1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
4 * TCP Protocol File: net_tcp.c
6 * This file contains a very simple TCP. The basic goals of this
7 * tcp are to be "good enough for firmware." We try to be
8 * correct in our protocol implementation, but not very fancy.
9 * In particular, we don't deal with out-of-order segments,
10 * we don't hesitate to copy data more then necessary, etc.
11 * We strive to implement important protocol features
12 * like slow start, nagle, etc., but even these things are
13 * subsetted and simplified as much as possible.
15 * Current "todo" list:
17 * good testing of retransmissions,
18 * round-trip delay calculations
19 * Process received TCP options, particularly segment size
20 * Ignore urgent data (remove from datastream)
22 * Author: Mitch Lichtenberg (mpl@broadcom.com)
24 *********************************************************************
26 * Copyright 2000,2001,2002,2003
27 * Broadcom Corporation. All rights reserved.
29 * This software is furnished under license and may be used and
30 * copied only in accordance with the following terms and
31 * conditions. Subject to these conditions, you may download,
32 * copy, install, use, modify and distribute modified or unmodified
33 * copies of this software in source and/or binary form. No title
34 * or ownership is transferred hereby.
36 * 1) Any source code used, modified or distributed must reproduce
37 * and retain this copyright notice and list of conditions
38 * as they appear in the source file.
40 * 2) No right is granted to use any trade name, trademark, or
41 * logo of Broadcom Corporation. The "Broadcom Corporation"
42 * name may not be used to endorse or promote products derived
43 * from this software without the prior written permission of
44 * Broadcom Corporation.
46 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
47 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
48 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
49 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
50 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
51 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
52 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
53 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
54 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
55 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
56 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
57 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
58 * THE POSSIBILITY OF SUCH DAMAGE.
59 ********************************************************************* */
62 #include "lib_types.h"
63 #include "lib_string.h"
64 #include "lib_queue.h"
65 #include "lib_malloc.h"
66 #include "lib_printf.h"
69 #include "net_ether.h"
72 #include "net_ip_internal.h"
74 #include "cfe_timer.h"
76 #include "cfe_error.h"
78 #include "net_tcpbuf.h"
79 #include "net_tcp_internal.h"
82 /* *********************************************************************
84 ********************************************************************* */
88 /* *********************************************************************
90 ********************************************************************* */
93 void *ti_ref
; /* ref data for IP layer */
94 ip_info_t
*ti_ipinfo
; /* IP layer handle */
95 cfe_timer_t ti_fasttimer
; /* 200ms timer */
96 queue_t ti_tcblist
; /* list of known TCBs */
97 int ti_onqueue
; /* number of TCBs on queue */
98 uint32_t ti_iss
; /* initial sequence number */
99 tcb_t
*ti_ports
[TCP_MAX_PORTS
]; /* table of active sockets */
102 /* *********************************************************************
103 * Forward Declarations
104 ********************************************************************* */
106 static void _tcp_protosend(tcp_info_t
*ti
,tcb_t
*tcb
);
107 static int _tcp_rx_callback(void *ref
,ebuf_t
*buf
,uint8_t *destaddr
,uint8_t *srcaddr
);
108 static void _tcp_output(tcp_info_t
*ti
,tcb_t
*tcb
);
109 static void _tcp_aborttcb(tcp_info_t
*ti
,tcb_t
*tcb
);
110 static void _tcp_closetcb(tcp_info_t
*ti
,tcb_t
*tcb
);
111 static tcb_t
*_tcp_find_lclport(tcp_info_t
*ti
,uint16_t port
);
112 static void _tcp_freetcb(tcp_info_t
*ti
,tcb_t
*tcb
);
113 static void _tcp_sendctlmsg(tcp_info_t
*ti
,tcb_t
*tcb
,uint16_t flags
,int timeout
);
116 /* *********************************************************************
118 ********************************************************************* */
121 #define _tcp_setstate(tcb,state) (tcb)->tcb_state = (state); \
122 printf("tcp state = " #state "\n");
123 #define DEBUGMSG(x) printf x
125 #define _tcp_setstate(tcb,state) (tcb)->tcb_state = (state);
129 #define _tcp_preparectlmsg(tcb,flags) (tcb)->tcb_txflags = (flags) ; \
130 (tcb)->tcb_flags |= TCB_FLG_SENDMSG;
132 #define _tcp_canceltimers(tcb) \
133 TIMER_CLEAR((tcb)->tcb_timer_retx); \
134 TIMER_CLEAR((tcb)->tcb_timer_keep); \
135 TIMER_CLEAR((tcb)->tcb_timer_2msl); \
136 TIMER_CLEAR((tcb)->tcb_timer_pers);
139 /* *********************************************************************
141 ********************************************************************* */
144 int _tcp_dumpflags
= 1;
146 int _tcp_dumpflags
= 0;
149 /* *********************************************************************
152 * Initialize the TCP module. We set up our data structures
153 * and register ourselves with the IP layer.
156 * ipi - IP information
157 * ref - will be passed back to IP as needed
160 * tcp_info_t structure, or NULL if problems
161 ********************************************************************* */
163 tcp_info_t
*_tcp_init(ip_info_t
*ipi
,void *ref
)
168 ti
= (tcp_info_t
*) KMALLOC(sizeof(tcp_info_t
),0);
169 if (!ti
) return NULL
;
175 * Start the "fast" timer
178 TIMER_SET(ti
->ti_fasttimer
,TCP_FAST_TIMER
);
181 * Initialize the TCB list
184 q_init(&(ti
->ti_tcblist
));
186 for (idx
= 0; idx
< TCP_MAX_PORTS
; idx
++) {
187 ti
->ti_ports
[idx
] = NULL
;
193 * Set up the initial sequence number
196 extern int32_t _getticks(void); /* return value of CP0 COUNT */
197 ti
->ti_iss
= (uint32_t) _getticks();
200 * Register our protocol with IP
203 _ip_register(ipi
,IPPROTO_TCP
,_tcp_rx_callback
,ti
);
209 /* *********************************************************************
212 * De-initialize the TCP layer, unregistering from the IP layer.
215 * info - our tcp_info_t, from _tcp_init()
219 ********************************************************************* */
221 void _tcp_uninit(tcp_info_t
*info
)
226 * Destroy all allocated TCBs, forcefully.
229 while (!q_isempty(&(info
->ti_tcblist
))) {
230 tcb
= (tcb_t
*) q_getfirst(&(info
->ti_tcblist
));
231 /* tcp_freetcb removes tcb from the queue */
232 _tcp_freetcb(info
,tcb
);
239 _ip_deregister(info
->ti_ipinfo
,IPPROTO_TCP
);
242 * Free up the info structure
249 /* *********************************************************************
250 * _tcp_freetcb(ti,tcb)
252 * Called when the TIME_WAIT timer expires, we use this to
253 * free up the TCB for good.
256 * ti - tcp information
261 ********************************************************************* */
263 static void _tcp_freetcb(tcp_info_t
*ti
,tcb_t
*tcb
)
269 if (tcb
->tcb_socknum
>= 0) ti
->ti_ports
[tcb
->tcb_socknum
] = NULL
;
270 tcb
->tcb_socknum
= -1;
277 q_dequeue(&(tcb
->tcb_qb
));
280 * Free buffers (could probably be done in tcb_destroy)
283 tmb_free(&(tcb
->tcb_txbuf
));
284 tmb_free(&(tcb
->tcb_rxbuf
));
294 /* *********************************************************************
297 * Create a new tcp socket (a new tcb structure is allocated
298 * and entered into the socket table)
301 * info - tcp information
304 * new socket number, or <0 if an error occured
305 ********************************************************************* */
307 int _tcp_socket(tcp_info_t
*info
)
313 * Find an empty slot.
316 for (idx
= 0; idx
< TCP_MAX_PORTS
; idx
++) {
317 if (!info
->ti_ports
[idx
]) break;
320 if (idx
== TCP_MAX_PORTS
) {
321 return CFE_ERR_NOHANDLES
;
325 * See if we can create another TCB
328 if (info
->ti_onqueue
>= TCP_MAX_TCBS
) return CFE_ERR_NOMEM
;
331 * Allocate data structures
334 tcb
= KMALLOC(sizeof(tcb_t
),0);
335 if (!tcb
) return CFE_ERR_NOMEM
;
337 memset(tcb
,0,sizeof(tcb_t
));
339 if (tmb_alloc(&tcb
->tcb_txbuf
,TCP_BUF_SIZE
) < 0) goto error
;
340 if (tmb_alloc(&tcb
->tcb_rxbuf
,TCP_BUF_SIZE
) < 0) goto error
;
346 * Default socket flags
349 tcb
->tcb_sockflags
= TCPFLG_NBIO
;
352 * Set up initial state. Find an empty port number.
353 * note that the way we do this is pretty gruesome, but it will
354 * work for our small TCP, where the number of TCBs outstanding
355 * will be very small compared to the port number space.
357 * Try to look up the port number we want - if we find it, increment
358 * it and try again until we find an unused one.
359 * Stay away from ports 0..1023.
362 _tcp_setstate(tcb
,TCPSTATE_CLOSED
);
363 tcb
->tcb_lclport
= (uint16_t) (((uint16_t) cfe_ticks
) + 1024);
365 while (_tcp_find_lclport(info
,tcb
->tcb_lclport
) != NULL
) {
367 if (tcb
->tcb_lclport
== 0) tcb
->tcb_lclport
= 1024;
371 * Remember this socket in the table
374 info
->ti_ports
[idx
] = tcb
;
375 tcb
->tcb_socknum
= idx
;
378 q_enqueue(&(info
->ti_tcblist
),&(tcb
->tcb_qb
));
383 tmb_free(&(tcb
->tcb_txbuf
));
384 tmb_free(&(tcb
->tcb_rxbuf
));
386 return CFE_ERR_NOMEM
;
390 /* *********************************************************************
391 * _tcp_connect(ti,s,dest,port)
393 * Connect a socket to a remote port.
396 * ti - TCP information
397 * s - socket number, allocated via _tcp_create
398 * dest - destination IP address
399 * port - destination port number
404 ********************************************************************* */
406 int _tcp_connect(tcp_info_t
*ti
,int s
,uint8_t *dest
,uint16_t port
)
410 tcb
= ti
->ti_ports
[s
];
411 if (!tcb
) return CFE_ERR_INV_PARAM
;
413 memcpy(tcb
->tcb_peeraddr
,dest
,IP_ADDR_LEN
);
414 tcb
->tcb_peerport
= port
;
416 tcb
->tcb_rcvnext
= 0;
419 tcb
->tcb_sendnext
= ti
->ti_iss
;
420 tcb
->tcb_sendunack
= ti
->ti_iss
;
421 tcb
->tcb_sendwindow
= 0;
423 tmb_init(&tcb
->tcb_txbuf
);
424 tmb_init(&tcb
->tcb_rxbuf
);
426 TIMER_SET(tcb
->tcb_timer_keep
,TCP_KEEPALIVE_TIMER
);
427 _tcp_setstate(tcb
,TCPSTATE_SYN_SENT
);
429 _tcp_sendctlmsg(ti
,tcb
,TCPFLG_SYN
,TCP_RETX_TIMER
);
435 /* *********************************************************************
438 * Disconnect a TCP socket nicely. Sends a FIN packet to get
439 * us into the disconnect state.
442 * ti - tcp information
448 ********************************************************************* */
450 int _tcp_close(tcp_info_t
*ti
,int s
)
454 tcb
= ti
->ti_ports
[s
];
455 if (!tcb
) return CFE_ERR_INV_PARAM
;
458 * Reclaim this socket number for future use
461 ti
->ti_ports
[s
] = NULL
;
462 tcb
->tcb_socknum
= -1;
465 * Decide what action to take based on current state
468 switch (tcb
->tcb_state
) {
469 case TCPSTATE_SYN_RECEIVED
:
470 case TCPSTATE_ESTABLISHED
:
471 _tcp_setstate(tcb
,TCPSTATE_FINWAIT_1
);
472 _tcp_sendctlmsg(ti
,tcb
,TCPFLG_ACK
| TCPFLG_FIN
,TCP_RETX_TIMER
);
475 case TCPSTATE_CLOSED
:
476 case TCPSTATE_LISTEN
:
477 case TCPSTATE_SYN_SENT
:
479 * Disconnect during our attempt, or from some
480 * idle state that does not require sending anything.
483 _tcp_closetcb(ti
,tcb
);
484 _tcp_freetcb(ti
,tcb
);
487 case TCPSTATE_CLOSE_WAIT
:
488 _tcp_setstate(tcb
,TCPSTATE_LAST_ACK
);
489 _tcp_sendctlmsg(ti
,tcb
,TCPFLG_ACK
| TCPFLG_FIN
,TCP_RETX_TIMER
);
492 case TCPSTATE_TIME_WAIT
:
493 case TCPSTATE_FINWAIT_1
:
494 case TCPSTATE_FINWAIT_2
:
495 case TCPSTATE_CLOSING
:
496 case TCPSTATE_LAST_ACK
:
506 /* *********************************************************************
507 * _tcp_aborttcb(ti,tcb)
509 * Forcefully terminate a TCP connection. Sends an RST packet
510 * to nuke the other end. The socket is forced into the CLOSED
514 * ti - tcp information
519 ********************************************************************* */
521 static void _tcp_aborttcb(tcp_info_t
*ti
,tcb_t
*tcb
)
523 DEBUGMSG(("tcp_abort from state %d\n",tcb
->tcb_state
));
526 * Decide what action to take based on current state
527 * If we're in SYN_SENT, RECEIVED, ESTABLISHED, FINWAIT_1,
528 * FINWAIT_2, CLOSING, LAST_ACK, or CLOSE_WAIT we've sent
529 * some traffic on this TCB, so send an RST to kill off
533 if (TCPSTATE_IN_SET(tcb
->tcb_state
,M_TCPSTATE_ABORTSTATES
)) {
534 /* Send RST with no timeout, don't retransmit it. */
535 _tcp_canceltimers(tcb
);
536 _tcp_sendctlmsg(ti
,tcb
,TCPFLG_ACK
| TCPFLG_RST
,0);
540 * No matter what, it's now CLOSED.
543 _tcp_closetcb(ti
,tcb
);
548 /* *********************************************************************
549 * _tcp_closetcb(ti,tcb)
551 * Close a TCB, switching the state to "closed" and resetting
552 * internal variables. The TCB is *not* freed.
555 * ti - tcp information
560 ********************************************************************* */
562 static void _tcp_closetcb(tcp_info_t
*ti
,tcb_t
*tcb
)
565 * Set state to "closed" and reset timers
568 _tcp_setstate(tcb
,TCPSTATE_CLOSED
);
570 _tcp_canceltimers(tcb
);
573 * Reinitialize the buffers to waste the stored send data and
574 * clear out any receive data
577 tmb_init(&tcb
->tcb_txbuf
);
578 tmb_init(&tcb
->tcb_rxbuf
);
581 /* *********************************************************************
582 * _tcp_send(ti,s,buf,len)
584 * Queue some data to be transmitted via a TCP socket
587 * ti - TCP information
589 * buf - buffer of data to send
590 * len - size of buffer to send
593 * number of bytes queued
594 * <0 if an error occured
595 ********************************************************************* */
597 int _tcp_send(tcp_info_t
*ti
,int s
,uint8_t *buf
,int len
)
603 tcb
= ti
->ti_ports
[s
];
604 if (!tcb
) return CFE_ERR_INV_PARAM
;
607 * State must be ESTABLISHED or CLOSE_WAIT. CLOSE_WAIT
608 * means we've received a fin, but we can still send in
609 * the outbound direction.
612 if (!TCPSTATE_IN_SET(tcb
->tcb_state
,M_TCPSTATE_SEND_OK
)) {
613 return CFE_ERR_NOTCONN
;
617 * Copy the user data into the transmit buffer.
620 curlen
= tmb_curlen(&(tcb
->tcb_txbuf
));
621 retlen
= tmb_copyin(&(tcb
->tcb_txbuf
),buf
,len
,TRUE
);
624 * Cause some output on the device.
628 * Nagle: Call _tcp_output only if there is no outstanding
629 * unacknowledged data. The way our transmit buffer
630 * works, it only holds unacknowledged data, so this
631 * test is easy. It isn't really 100% correct to
632 * do it this way, but the effect is the same; we will
633 * not transmit tinygrams.
636 if ((curlen
== 0) || (tcb
->tcb_sockflags
& TCPFLG_NODELAY
)) {
643 /* *********************************************************************
644 * _tcp_recv(ti,s,buf,len)
646 * Get buffered receive data from the TCP socket
649 * ti - tcp information
651 * buf - pointer to receive buffer area
652 * len - size of receive buffer area
655 * number of bytes received
656 * <0 if an error occured
657 * ==0 if no data available (or tcp session is closed)
658 ********************************************************************* */
660 int _tcp_recv(tcp_info_t
*ti
,int s
,uint8_t *buf
,int len
)
665 tcb
= ti
->ti_ports
[s
];
666 if (!tcb
) return CFE_ERR_INV_PARAM
;
668 if (!TCPSTATE_IN_SET(tcb
->tcb_state
,M_TCPSTATE_RECV_OK
)) {
669 return CFE_ERR_NOTCONN
;
672 retlen
= tmb_copyout(&(tcb
->tcb_rxbuf
),buf
,len
,TRUE
);
675 * If we've drained all of the data out of the buffer
676 * send an ack. This isn't ideal, but it will
677 * prevent us from keeping the window closed.
680 // if (retlen && (tmb_curlen(&(tcb->tcb_rxbuf)) == 0)) {
681 // _tcp_preparectlmsg(tcb,TCPFLG_ACK);
682 // _tcp_protosend(ti,tcb);
683 // tcb->tcb_flags &= ~TCB_FLG_DLYACK;
690 /* *********************************************************************
691 * _tcp_bind(ti,s,port)
693 * "bind" a TCP socket to a particular port - this sets the
694 * outbound local (source) port number.
697 * ti - tcp information
704 ********************************************************************* */
706 int _tcp_bind(tcp_info_t
*ti
,int s
,uint16_t port
)
710 tcb
= ti
->ti_ports
[s
];
711 if (!tcb
) return CFE_ERR_INV_PARAM
;
714 if (_tcp_find_lclport(ti
,port
)) return CFE_ERR_ADDRINUSE
;
716 tcb
->tcb_lclport
= port
;
721 /* *********************************************************************
722 * _tcp_setflags(ti,s,flags)
724 * Set per-socket flags.
727 * ti - tcp information
729 * flags - flags to set
734 ********************************************************************* */
736 int _tcp_setflags(tcp_info_t
*ti
,int s
,unsigned int flags
)
740 tcb
= ti
->ti_ports
[s
];
741 if (!tcb
) return CFE_ERR_INV_PARAM
;
743 tcb
->tcb_sockflags
= flags
;
748 /* *********************************************************************
749 * _tcp_getflags(ti,s,flags)
751 * Get per-socket flags.
754 * ti - tcp information
756 * flags - pointer to int to receive flags
761 ********************************************************************* */
763 int _tcp_getflags(tcp_info_t
*ti
,int s
,unsigned int *flags
)
767 tcb
= ti
->ti_ports
[s
];
768 if (!tcb
) return CFE_ERR_INV_PARAM
;
770 *flags
= tcb
->tcb_sockflags
;
776 /* *********************************************************************
777 * _tcp_peeraddr(ti,s,addr,port)
779 * Return the address of the computer on the other end of this
783 * ti - tcp information
785 * addr - receives IP address of remote
791 ********************************************************************* */
793 int _tcp_peeraddr(tcp_info_t
*ti
,int s
,uint8_t *addr
,uint16_t *port
)
797 tcb
= ti
->ti_ports
[s
];
798 if (!tcb
) return CFE_ERR_INV_PARAM
;
801 * Test for any of the states where we believe the peeraddr in the tcb
805 if (!TCPSTATE_IN_SET(tcb
->tcb_state
,M_TCPSTATE_PEERADDR_OK
)) {
806 return CFE_ERR_NOTCONN
;
809 if (addr
) memcpy(addr
,tcb
->tcb_peeraddr
,IP_ADDR_LEN
);
810 if (port
) *port
= tcb
->tcb_peerport
;
815 /* *********************************************************************
816 * _tcp_listen(ti,s,port)
818 * Set a socket for listening mode, allowing inbound connections
822 * ti - tcp information
824 * port - port number to listen for (implicit tcp_bind)
829 ********************************************************************* */
831 int _tcp_listen(tcp_info_t
*ti
,int s
,uint16_t port
)
837 * See if another TCB is listening to this port
840 for (qb
= ti
->ti_tcblist
.q_next
; qb
!= &(ti
->ti_tcblist
); qb
= qb
->q_next
) {
843 if ((tcb
->tcb_lclport
== port
) &&
844 (tcb
->tcb_state
== TCPSTATE_LISTEN
) &&
845 (tcb
->tcb_peerport
== 0)) return CFE_ERR_ADDRINUSE
;
850 * Otherwise, we're good to go.
853 tcb
= ti
->ti_ports
[s
];
854 if (!tcb
) return CFE_ERR_INV_PARAM
;
856 tcb
->tcb_lclport
= port
;
857 _tcp_setstate(tcb
,TCPSTATE_LISTEN
);
859 tcb
->tcb_sendnext
= 0;
860 tcb
->tcb_sendunack
= 0;
861 tcb
->tcb_sendwindow
= 0;
862 _tcp_canceltimers(tcb
);
864 tcb
->tcb_rcvnext
= 0;
867 tmb_init(&tcb
->tcb_txbuf
);
868 tmb_init(&tcb
->tcb_rxbuf
);
870 tcb
->tcb_txflags
= 0;
875 /* *********************************************************************
876 * _tcp_status(ti,s,connflag,rxready,rxeof)
878 * Get status information about the TCP session
881 * ti - tcp information
883 * connflag - points to an int to receive connection status
884 * (1=connected,0=not connected)
885 * rxready - number of bytes in receive queue
886 * rxeof - returns 1 if we've been FINed.
891 ********************************************************************* */
893 int _tcp_status(tcp_info_t
*ti
,int s
,int *connflag
,int *rxready
,int *rxeof
)
898 tcb
= ti
->ti_ports
[s
];
899 if (!tcb
) return CFE_ERR_INV_PARAM
;
901 rxlen
= tmb_curlen(&(tcb
->tcb_rxbuf
));
904 * We consider the connection "connected" if it's established
905 * or it's in CLOSE_WAIT (FIN received) but we have not drained
906 * all of the receive data.
908 * Otherwise: If it's not in one of the connection establishment states,
909 * it's not connected.
913 if ((tcb
->tcb_state
== TCPSTATE_ESTABLISHED
) ||
914 ((rxlen
!= 0) && (tcb
->tcb_state
== TCPSTATE_CLOSE_WAIT
))) {
915 *connflag
= TCPSTATUS_CONNECTED
;
917 else if (TCPSTATE_IN_SET(tcb
->tcb_state
,M_TCPSTATE_CONNINPROGRESS
)) {
918 *connflag
= TCPSTATUS_CONNECTING
;
921 *connflag
= TCPSTATUS_NOTCONN
;
931 if ((tcb
->tcb_state
== TCPSTATE_CLOSE_WAIT
) ||
932 (tcb
->tcb_state
== TCPSTATE_LAST_ACK
)) {
940 /* *********************************************************************
941 * _tcp_debug(ti,s,arg)
943 * Perform debug functions on a socket
946 * ti - tcp information
953 ********************************************************************* */
955 int _tcp_debug(tcp_info_t
*ti
,int s
,int arg
)
959 tcb
= ti
->ti_ports
[s
];
960 if (!tcb
) return CFE_ERR_INV_PARAM
;
962 printf("State=%d SendNext=%u SendUnack=%u ",
963 tcb
->tcb_state
,tcb
->tcb_sendnext
,tcb
->tcb_sendunack
);
964 printf("SendWin=%d Ack=%u Rxlen=%d\n",
966 tcb
->tcb_rcvack
,tmb_curlen(&(tcb
->tcb_rxbuf
)));
973 /* *********************************************************************
974 * _tcp_dumppktstate(label,flags,ack,seq,len)
979 * label - printed before packet state
980 * flags - transmit flags for packet
981 * ack,seq,len - from the packet
985 ********************************************************************* */
986 static void _tcp_dumppktstate(char *label
,uint16_t flags
,
987 uint32_t ack
,uint32_t seq
,int len
)
989 printf("%s: ",label
);
990 if (flags
& TCPFLG_FIN
) printf("FIN ");
991 if (flags
& TCPFLG_SYN
) printf("SYN ");
992 if (flags
& TCPFLG_RST
) printf("RST ");
993 if (flags
& TCPFLG_PSH
) printf("PSH ");
994 if (flags
& TCPFLG_ACK
) printf("ACK ");
995 if (flags
& TCPFLG_URG
) printf("URG ");
996 printf("Ack=%u Seq=%u Data=%d\n",ack
,seq
,len
);
1001 /* *********************************************************************
1002 * _tcp_output(ti,tcb)
1004 * Try to perform some output on this TCB. If there is
1005 * data to send and we can transmit it (i.e., the remote's
1006 * receive window will allow it), segment the data from the
1007 * buffer and transmit it, updating local state variables.
1010 * ti - tcp information
1011 * tcb - the tcb to send data on
1015 ********************************************************************* */
1017 static void _tcp_output(tcp_info_t
*ti
,tcb_t
*tcb
)
1027 uint8_t pseudoheader
[12];
1034 * sendmax is (one plus) the highest sequence number we have
1037 * windowmax is (one plus) the highest sequence number in the
1040 * cwndmax is (one plus) the highest sequence number in the
1041 * congestion window.
1044 sendmax
= tcb
->tcb_sendunack
+ tmb_curlen(&(tcb
->tcb_txbuf
));
1045 windowmax
= tcb
->tcb_sendunack
+ tcb
->tcb_sendwindow
;
1046 cwndmax
= tcb
->tcb_sendunack
+ 5*1400;
1049 * We'll send up to 'sendmax', 'cwndmax', or 'windowmax' bytes, whichever
1050 * is sooner. Set 'sendmax' to the earliest sequence number.
1053 if (TCPSEQ_GT(sendmax
,windowmax
)) sendmax
= windowmax
;
1054 if (TCPSEQ_GT(sendmax
,cwndmax
)) sendmax
= cwndmax
;
1057 * The (receive) window is whatever it takes to fill the buffer.
1060 window
= tmb_remlen(&(tcb
->tcb_rxbuf
));
1061 if (window
> 65000) window
= 65000;
1064 * Spit out packets until "sendnext" either catches up
1065 * or exceeds the remote window
1068 while (TCPSEQ_LT(tcb
->tcb_sendnext
,sendmax
)) {
1071 * This is the offset into the transmit buffer to start with.
1072 * Offset 0 in the transmit buffer corresponds to "send unack"
1073 * received acks move this pointer.
1076 offset
= tcb
->tcb_sendnext
- tcb
->tcb_sendunack
;
1079 * Allocate a buffer and remember the pointer to where
1080 * the header starts.
1083 b
= _ip_alloc(ti
->ti_ipinfo
);
1086 tcphdr
= ebuf_ptr(b
) + ebuf_length(b
);
1088 flags
= TCPFLG_ACK
| TCPHDRFLG(TCP_HDR_LENGTH
);
1089 hdrlen
= TCP_HDR_LENGTH
;
1092 * Fill in the fields according to the RFC.
1095 tcb
->tcb_rcvack
= tcb
->tcb_rcvnext
; /* Update our "most recent ack" */
1097 ebuf_append_u16_be(b
,tcb
->tcb_lclport
); /* Local and remote ports */
1098 ebuf_append_u16_be(b
,tcb
->tcb_peerport
);
1099 ebuf_append_u32_be(b
,tcb
->tcb_sendnext
); /* sequence and ack numbers */
1100 ebuf_append_u32_be(b
,tcb
->tcb_rcvack
);
1101 ebuf_append_u16_be(b
,flags
); /* Flags */
1102 ebuf_append_u16_be(b
,window
); /* Window size */
1103 cksumptr
= ebuf_ptr(b
) + ebuf_length(b
);
1104 ebuf_append_u16_be(b
,0); /* dummy checksum for calculation */
1105 ebuf_append_u16_be(b
,0); /* Urgent Pointer (not used) */
1108 * Append the data, copying pieces out of the transmit buffer
1109 * without adjusting its pointers.
1112 tcplen
= tmb_copyout2(&(tcb
->tcb_txbuf
),
1113 b
->eb_ptr
+ b
->eb_length
,
1117 b
->eb_length
+= tcplen
;
1120 if (_tcp_dumpflags
) _tcp_dumppktstate("TX_DATA",flags
,
1122 tcb
->tcb_rcvack
,tcplen
);
1126 * Adjust the "send next" sequence number to account for what
1127 * we're about to send.
1130 tcb
->tcb_sendnext
+= tcplen
;
1134 * Build the pseudoheader, which is part of the checksum calculation
1137 _ip_getaddr(ti
->ti_ipinfo
,&pseudoheader
[0]);
1138 memcpy(&pseudoheader
[4],tcb
->tcb_peeraddr
,IP_ADDR_LEN
);
1139 pseudoheader
[8] = 0;
1140 pseudoheader
[9] = IPPROTO_TCP
;
1141 pseudoheader
[10] = ((tcplen
+hdrlen
) >> 8) & 0xFF;
1142 pseudoheader
[11] = ((tcplen
+hdrlen
) & 0xFF);
1145 * Checksum the packet and insert the checksum into the header
1148 cksum
= ip_chksum(0,pseudoheader
,sizeof(pseudoheader
));
1149 cksum
= ip_chksum(cksum
,tcphdr
,tcplen
+ hdrlen
);
1151 cksumptr
[0] = (cksum
>> 8) & 0xFF;
1152 cksumptr
[1] = (cksum
& 0xFF);
1155 * Transmit the packet. The layer below us will free it.
1158 _ip_send(ti
->ti_ipinfo
,b
,tcb
->tcb_peeraddr
,IPPROTO_TCP
);
1161 * Set the timer that we'll use to wait for an acknowledgement.
1162 * If this timer goes off, we'll rewind "sendnext" back to
1163 * "sendunack" and transmit stuff again.
1166 TIMER_SET(tcb
->tcb_timer_retx
,TCP_RETX_TIMER
);
1169 * We just sent an ack, so cancel the delayed ack timer.
1172 tcb
->tcb_flags
&= ~TCB_FLG_DLYACK
;
1178 /* *********************************************************************
1179 * _tcp_protosend(ti,tcb)
1181 * Transmit "protocol messages" on the tcb. This is used for
1182 * sending SYN, FIN, ACK, and other control packets.
1185 * ti - tcp infomration
1186 * tcb - tcb we're interested in
1190 ********************************************************************* */
1192 static void _tcp_protosend(tcp_info_t
*ti
,tcb_t
*tcb
)
1202 uint8_t pseudoheader
[12];
1205 * Allocate a buffer and remember the pointer to where
1206 * the header starts.
1209 b
= _ip_alloc(ti
->ti_ipinfo
);
1212 tcphdr
= ebuf_ptr(b
) + ebuf_length(b
);
1215 * We're going to send something, so we can clear the flag.
1216 * Also clear the delay-ack flag since everything's an ack.
1219 tcb
->tcb_flags
&= ~(TCB_FLG_SENDMSG
| TCB_FLG_DLYACK
);
1222 * Build the TCP header
1225 /* The flags are the current flags + the header length */
1226 if (tcb
->tcb_txflags
& TCPFLG_SYN
) {
1227 flags
= tcb
->tcb_txflags
| (TCPHDRFLG(TCP_HDR_LENGTH
+ 4));
1228 hdrlen
= TCP_HDR_LENGTH
+ 4;
1231 flags
= tcb
->tcb_txflags
| (TCPHDRFLG(TCP_HDR_LENGTH
));
1232 hdrlen
= TCP_HDR_LENGTH
;
1237 if (_tcp_dumpflags
) _tcp_dumppktstate("TX_CTL",flags
,
1243 * The (receive) window is whatever it takes to fill the buffer.
1246 window
= tmb_remlen(&(tcb
->tcb_rxbuf
));
1247 if (window
> 65000) window
= 65000;
1250 * Fill in the fields according to the RFC.
1253 tcb
->tcb_rcvack
= tcb
->tcb_rcvnext
; /* update last tx ack */
1255 ebuf_append_u16_be(b
,tcb
->tcb_lclport
); /* Local and remote ports */
1256 ebuf_append_u16_be(b
,tcb
->tcb_peerport
);
1257 ebuf_append_u32_be(b
,tcb
->tcb_sendnext
); /* sequence and ack numbers */
1258 ebuf_append_u32_be(b
,tcb
->tcb_rcvack
);
1259 ebuf_append_u16_be(b
,flags
); /* Flags */
1260 ebuf_append_u16_be(b
,window
); /* Window size */
1261 cksumptr
= ebuf_ptr(b
) + ebuf_length(b
);
1262 ebuf_append_u16_be(b
,0); /* dummy checksum for calculation */
1263 ebuf_append_u16_be(b
,0); /* Urgent Pointer (not used) */
1266 * Append TCP options on SYN packet
1269 if (flags
& TCPFLG_SYN
) {
1270 ebuf_append_u16_be(b
,TCP_MAX_SEG_OPT
);
1271 ebuf_append_u16_be(b
,TCP_MAX_SEG_SIZE
);
1274 tcplen
= 0; /* don't transmit data here */
1277 if (flags
& (TCPFLG_SYN
| TCPFLG_FIN
)) tcb
->tcb_sendnext
++;
1280 * Build the pseudoheader, which is part of the checksum calculation
1283 _ip_getaddr(ti
->ti_ipinfo
,&pseudoheader
[0]);
1284 memcpy(&pseudoheader
[4],tcb
->tcb_peeraddr
,IP_ADDR_LEN
);
1285 pseudoheader
[8] = 0;
1286 pseudoheader
[9] = IPPROTO_TCP
;
1287 pseudoheader
[10] = ((tcplen
+hdrlen
) >> 8) & 0xFF;
1288 pseudoheader
[11] = ((tcplen
+hdrlen
) & 0xFF);
1291 * Checksum the packet and insert the checksum into the header
1294 cksum
= ip_chksum(0,pseudoheader
,sizeof(pseudoheader
));
1295 cksum
= ip_chksum(cksum
,tcphdr
,tcplen
+ hdrlen
);
1297 cksumptr
[0] = (cksum
>> 8) & 0xFF;
1298 cksumptr
[1] = (cksum
& 0xFF);
1301 * Transmit the packet. The layer below us will free it.
1304 _ip_send(ti
->ti_ipinfo
,b
,tcb
->tcb_peeraddr
,IPPROTO_TCP
);
1307 /* *********************************************************************
1308 * _tcp_sendreset(ti,dstipaddr,ack,srcport,dstport)
1310 * Transmit "protocol messages" on the tcb. This is used for
1311 * sending SYN, FIN, ACK, and other control packets.
1314 * ti - tcp infomration
1315 * tcb - tcb we're interested in
1319 ********************************************************************* */
1321 static void _tcp_sendreset(tcp_info_t
*ti
,uint8_t *dstipaddr
,uint32_t ack
,
1322 uint16_t srcport
,uint16_t dstport
)
1324 tcb_t tcb
; /* fake TCB so we can use _tcp_protosend */
1326 memset(&tcb
,0,sizeof(tcb
));
1327 memcpy(tcb
.tcb_peeraddr
,dstipaddr
,IP_ADDR_LEN
);
1328 tcb
.tcb_peerport
= dstport
;
1329 tcb
.tcb_lclport
= srcport
;
1330 tcb
.tcb_txflags
= TCPFLG_RST
|TCPFLG_ACK
;
1331 tcb
.tcb_rcvnext
= ack
;
1333 _tcp_protosend(ti
,&tcb
);
1337 /* *********************************************************************
1338 * _tcp_sendctlmsg(ti,tcb,flags,timeout)
1340 * Set up for and transmit a control message. This is usually
1341 * called on a state transition where we need to send a control
1342 * message like a SYN or FIN, with a timeout. We reset the
1343 * retry counter, set the retransmit timer, and fire off the message
1347 * ti - tcp information
1348 * tcb - the tcb for this TCP session
1349 * flags - packet flags (TCPFLG_xxx)
1350 * timeout - timeout value , in ticks
1354 ********************************************************************* */
1356 static void _tcp_sendctlmsg(tcp_info_t
*ti
,tcb_t
*tcb
,uint16_t flags
,int timeout
)
1358 tcb
->tcb_txflags
= flags
;
1359 tcb
->tcb_retrycnt
= 0;
1363 TIMER_SET(tcb
->tcb_timer_retx
,timeout
);
1366 TIMER_CLEAR(tcb
->tcb_timer_retx
);
1370 _tcp_protosend(ti
,tcb
);
1374 /* *********************************************************************
1375 * _tcp_find_lclport(ti,port)
1377 * Find the specified local port - mostly to see if it is
1381 * ti - tcp information
1385 * tcb owning this port, or NULL if none found
1386 ********************************************************************* */
1387 static tcb_t
*_tcp_find_lclport(tcp_info_t
*ti
,uint16_t port
)
1392 for (qb
= ti
->ti_tcblist
.q_next
; qb
!= &(ti
->ti_tcblist
); qb
= qb
->q_next
) {
1395 if (tcb
->tcb_lclport
== port
) return tcb
;
1403 /* *********************************************************************
1404 * _tcp_find_tcb(ti,srcport,dstport,saddr)
1406 * Locate the TCB in the active TCBs. This is used to match
1407 * an inbound TCP packet to a TCB.
1410 * ti - tcp information
1411 * srcport,dstport - source and dest ports from TCP header
1412 * saddr - source IP address of sending host
1415 * tcb pointer or NULL if no TCB was found
1416 ********************************************************************* */
1418 static tcb_t
*_tcp_find_tcb(tcp_info_t
*ti
,uint16_t srcport
,uint16_t dstport
,uint8_t *saddr
)
1423 for (qb
= ti
->ti_tcblist
.q_next
; qb
!= &(ti
->ti_tcblist
); qb
= qb
->q_next
) {
1426 /* Try active TCBs */
1427 if ((tcb
->tcb_peerport
!= 0) &&
1428 (tcb
->tcb_lclport
== dstport
) &&
1429 (tcb
->tcb_peerport
== srcport
) &&
1430 (memcmp(saddr
,tcb
->tcb_peeraddr
,IP_ADDR_LEN
) == 0)) break;
1433 /* Found it on our active list. */
1434 if (qb
!= &(ti
->ti_tcblist
)) return tcb
;
1436 /* no dice, try listening ports */
1437 for (qb
= ti
->ti_tcblist
.q_next
; qb
!= &(ti
->ti_tcblist
); qb
= qb
->q_next
) {
1440 /* Try active TCBs */
1441 if ((tcb
->tcb_peerport
== 0) &&
1442 (tcb
->tcb_lclport
== dstport
)) break;
1445 /* Found it on our passive list. */
1446 if (qb
!= &(ti
->ti_tcblist
)) return tcb
;
1451 /* *********************************************************************
1452 * _tcp_procack(ti,tcb,ack,flags)
1454 * Process a received acknowledgement.
1457 * ti - tcp information
1458 * tcb - tcb for this tcb session
1459 * ack - acknum from received packet
1460 * flags - flags from received packet
1464 ********************************************************************* */
1466 static void _tcp_procack(tcp_info_t
*ti
,tcb_t
*tcb
,uint32_t ack
,uint16_t flags
)
1471 /* This is the number of unacknowledged bytes we have */
1472 unacklen
= tmb_curlen(&(tcb
->tcb_txbuf
));
1474 switch (tcb
->tcb_state
) {
1476 case TCPSTATE_ESTABLISHED
:
1478 * The ack is valid if it's in the range of
1479 * unacknowledged data we're holding onto.
1481 * sendunack < ack <= (sendunack+datalen)
1483 * Do the first comparison as "<=" instead of just "<"
1484 * so we can catch duplicate acks.
1487 if (!(TCPSEQ_LEQ(tcb
->tcb_sendunack
,ack
) &&
1488 TCPSEQ_LEQ(ack
,(tcb
->tcb_sendunack
+unacklen
)))) {
1489 DEBUGMSG(("Ack is out of range: %u\n",ack
));
1494 * Compute the # of bytes spanned by this ack
1497 ackamt
= TCPSEQ_DIFF(ack
,tcb
->tcb_sendunack
);
1500 * If we actually acked something, adjust the tx buffer
1501 * to remove the bytes covered by the ack, then update
1502 * the 'next' sequence number so we'll start there next
1507 tmb_adjust(&tcb
->tcb_txbuf
,ackamt
);
1508 tcb
->tcb_txflags
= TCPFLG_ACK
;
1509 tcb
->tcb_sendunack
= ack
;
1510 tcb
->tcb_dup_ackcnt
= 0; /* not a duplicate */
1513 tcb
->tcb_dup_ackcnt
++;
1514 //DEBUGMSG(("Duplicate ack received\n"));
1518 * If we're all caught up, we can cancel the
1519 * retransmit timer. Otherwise, try to do
1520 * some output on the interface. This will
1521 * reset the retransmit timer if we did anything.
1524 if (tmb_curlen(&(tcb
->tcb_txbuf
)) != 0) {
1525 tcb
->tcb_flags
|= TCB_FLG_OUTPUT
;
1528 TIMER_CLEAR(tcb
->tcb_timer_retx
);
1533 case TCPSTATE_FINWAIT_1
:
1534 ackamt
= TCPSEQ_DIFF(ack
,tcb
->tcb_sendunack
);
1536 tcb
->tcb_sendunack
= ack
;
1537 if (flags
& TCPFLG_FIN
) {
1538 _tcp_setstate(tcb
,TCPSTATE_TIME_WAIT
);
1539 _tcp_canceltimers(tcb
);
1540 _tcp_preparectlmsg(tcb
,TCPFLG_ACK
);
1541 TIMER_SET(tcb
->tcb_timer_2msl
,TCP_TIMEWAIT_TIMER
);
1544 _tcp_setstate(tcb
,TCPSTATE_FINWAIT_2
);
1552 /* *********************************************************************
1553 * _tcp_procdata(ti,tcb,seqnum,flags,buf)
1555 * Process data in a received TCP packet - we'll put the
1556 * data into the receive ring buffer, process the seqnum
1557 * field, and prepare to send an ack.
1560 * ti - tcp information
1561 * tcb - tcb describing TCP session
1562 * seqnum,flags - from the header of the received TCP packet
1563 * buf - ebuf contianing data
1567 ********************************************************************* */
1569 static void _tcp_procdata(tcp_info_t
*ti
,tcb_t
*tcb
,uint32_t seqnum
,
1570 uint16_t flags
,ebuf_t
*buf
)
1576 uint32_t endrxwindow
;
1580 * Figure out how much we're going to take. This should not
1581 * exceed our buffer size because we advertised a window
1582 * only big enough to fill our buffer.
1585 bp
= ebuf_ptr(buf
); /* pointer to TCP data */
1586 datalen
= ebuf_remlen(buf
); /* Size of TCP data */
1589 * If there's no data in the buffer, we can skip the data-related
1590 * stuff and check for a possible FIN.
1596 * Figure out if the data fits within the window. We don't deal
1597 * with out-of-order segments, so the test is relatively
1598 * simple: The received segment must contain (or match)
1599 * the sequence number from "rcvnext" to the end of the receive
1602 * Therefore: seqnum <= rcvnext < seqnum+datalen
1605 rxwin
= tmb_remlen(&(tcb
->tcb_rxbuf
)); /* receive window size */
1606 endseqnum
= (seqnum
+ datalen
); /* seq # of end of segment */
1607 endrxwindow
= tcb
->tcb_rcvack
+ rxwin
; /* end of receive window */
1610 * The segment might include data outside the receive window
1611 * (it's not supposed to, but it can). Crop the 'endseqnum'
1612 * value at the rx window if necessary. Keep the earlier seqnum.
1615 // if (TCPSEQ_LT(endrxwindow,endseqnum)) {
1616 // endseqnum = endrxwindow;
1620 * Test to see if the data is in sequence.
1623 rwin
= (TCPSEQ_LEQ(seqnum
,tcb
->tcb_rcvnext
) &&
1624 TCPSEQ_LT(tcb
->tcb_rcvnext
,endseqnum
));
1627 DEBUGMSG(("Dropping out-of-order packet %u %u %u\n",seqnum
,
1628 tcb
->tcb_rcvnext
,endseqnum
));
1633 * The actual amount of new data is the distance from
1634 * the "rcvnext" pointer to the end sequence number.
1635 * typically this will be the entire packet, but we
1636 * handle the case of receiving a partial duplicate segment.
1637 * Do this by shortening the data length we're going to
1638 * copy and adjusting the buffer pointer to point past the
1639 * duplicate data. Normally this won't do anything.
1642 reallen
= endseqnum
- tcb
->tcb_rcvnext
;
1643 bp
+= (tcb
->tcb_rcvnext
- seqnum
);
1645 if (reallen
!= datalen
) {
1646 DEBUGMSG(("newdata(%d) does not match real length(%d)\n",reallen
,datalen
));
1652 * Copy the data into the receive buffer. In the
1653 * unlikely event that it doesn't fit, update the
1654 * length so we'll only ack what we took.
1657 reallen
= tmb_copyin(&(tcb
->tcb_rxbuf
),bp
,reallen
,TRUE
);
1659 tcb
->tcb_rcvnext
+= reallen
;
1662 * Set the delayed-ack flag. If it's already set,
1663 * then we've already received some data without acking
1664 * it, so send the ack now, to encourage us to
1665 * ack every other segment at least.
1668 if (tcb
->tcb_flags
& TCB_FLG_DLYACK
) {
1669 _tcp_preparectlmsg(tcb
,TCPFLG_ACK
);
1672 tcb
->tcb_flags
|= TCB_FLG_DLYACK
;
1678 * Handle the case of data in a FIN packet.
1681 if (flags
& TCPFLG_FIN
) {
1683 tcb
->tcb_rcvnext
++; /* Consume the FIN */
1685 DEBUGMSG(("FIN rcvd in %d ack %u\n",tcb
->tcb_state
,tcb
->tcb_rcvnext
));
1687 switch (tcb
->tcb_state
) {
1688 case TCPSTATE_ESTABLISHED
:
1691 * If a FIN is received in the ESTABLISHED state,
1695 tcb
->tcb_flags
&= ~TCB_FLG_DLYACK
;
1696 _tcp_setstate(tcb
,TCPSTATE_CLOSE_WAIT
);
1697 _tcp_sendctlmsg(ti
,tcb
,TCPFLG_ACK
,-1);
1700 case TCPSTATE_FINWAIT_1
:
1703 * Two choices: Either we got a FIN or a FIN ACK.
1704 * In either case, send an ack. The difference
1705 * is what state we end up in.
1708 if (flags
& TCPFLG_ACK
) {
1709 /* Received: FIN ACK - go directly to TIME_WAIT */
1710 _tcp_canceltimers(tcb
);
1711 _tcp_preparectlmsg(tcb
,TCPFLG_ACK
);
1712 _tcp_setstate(tcb
,TCPSTATE_TIME_WAIT
);
1713 TIMER_SET(tcb
->tcb_timer_2msl
,TCP_TIMEWAIT_TIMER
);
1716 /* Received: FIN - simultaneous close, go to CLOSING */
1717 _tcp_setstate(tcb
,TCPSTATE_CLOSING
);
1718 _tcp_preparectlmsg(tcb
,TCPFLG_ACK
);
1722 case TCPSTATE_FINWAIT_2
:
1725 * Received a FIN in FINWAIT_2 - just transmit
1726 * an ack and go to TIME_WAIT.
1729 _tcp_canceltimers(tcb
);
1730 _tcp_preparectlmsg(tcb
,TCPFLG_ACK
);
1731 _tcp_setstate(tcb
,TCPSTATE_TIME_WAIT
);
1732 TIMER_SET(tcb
->tcb_timer_2msl
,TCP_TIMEWAIT_TIMER
);
1739 /* *********************************************************************
1740 * _tcp_rx_callback(ref,buf,destaddr,srcaddr)
1742 * The IP layer calls this routine when a TCP packet is received.
1743 * We dispatch the packet to appropriate handlers from here.
1746 * ref - our tcp information (held by the ip stack for us)
1747 * buf - the ebuf that we received
1748 * destaddr,srcaddr - destination and source IP addresses
1751 * ETH_DROP or ETH_KEEP, depending if we keep the packet or not
1752 ********************************************************************* */
1754 static int _tcp_rx_callback(void *ref
,ebuf_t
*buf
,uint8_t *destaddr
,uint8_t *srcaddr
)
1756 uint8_t pseudoheader
[12];
1768 tcp_info_t
*ti
= (tcp_info_t
*) ref
;
1771 * get a pointer to the TCP header
1774 tcplen
= ebuf_length(buf
);
1775 tcphdr
= ebuf_ptr(buf
);
1778 * construct the pseudoheader for the cksum calculation
1781 memcpy(&pseudoheader
[0],srcaddr
,IP_ADDR_LEN
);
1782 memcpy(&pseudoheader
[4],destaddr
,IP_ADDR_LEN
);
1783 pseudoheader
[8] = 0;
1784 pseudoheader
[9] = IPPROTO_TCP
;
1785 pseudoheader
[10] = (tcplen
>> 8) & 0xFF;
1786 pseudoheader
[11] = (tcplen
& 0xFF);
1788 origcksum
= ((uint16_t) tcphdr
[16] << 8) | (uint16_t) tcphdr
[17];
1789 tcphdr
[16] = tcphdr
[17] = 0;
1791 calccksum
= ip_chksum(0,pseudoheader
,sizeof(pseudoheader
));
1792 calccksum
= ip_chksum(calccksum
,tcphdr
,tcplen
);
1793 calccksum
= ~calccksum
;
1795 if (calccksum
!= origcksum
) {
1799 /* Read the other TCP header fields from the packet */
1801 ebuf_get_u16_be(buf
,srcport
);
1802 ebuf_get_u16_be(buf
,dstport
);
1803 ebuf_get_u32_be(buf
,seqnum
);
1804 ebuf_get_u32_be(buf
,acknum
);
1805 ebuf_get_u16_be(buf
,flags
);
1806 ebuf_get_u16_be(buf
,window
);
1807 ebuf_skip(buf
,4); /* skip checksum and urgent pointer */
1809 /* Skip options in header */
1810 if (TCPHDRSIZE(flags
) < TCP_HDR_LENGTH
) {
1813 ebuf_skip(buf
,(TCPHDRSIZE(flags
) - TCP_HDR_LENGTH
));
1816 tcb
= _tcp_find_tcb(ti
,srcport
,dstport
,srcaddr
);
1818 DEBUGMSG(("Invalid TCB from %I, srcport=%u dstport=%u\n",srcaddr
,srcport
,dstport
));
1819 _tcp_sendreset(ti
,srcaddr
,seqnum
+1,dstport
,srcport
);
1820 return ETH_DROP
; /* drop packet if no matching port */
1824 * Any activity on a TCB is enough to reset the keepalive timer
1827 if (TCPSTATE_IN_SET(tcb
->tcb_state
,M_TCPSTATE_RESETKEEPALIVE
)) {
1828 TIMER_SET(tcb
->tcb_timer_keep
,TCP_KEEPALIVE_TIMER
);
1836 if (_tcp_dumpflags
) _tcp_dumppktstate("Received",flags
,
1837 acknum
,seqnum
,ebuf_length(buf
));
1841 * If someone tries to reset us, just kill off the port.
1842 * (except: if we were in SYN_RECEIVED, go back to LISTEN)
1845 if (flags
& TCPFLG_RST
) {
1846 if (tcb
->tcb_state
== TCPSTATE_SYN_RECEIVED
) {
1847 _tcp_setstate(tcb
,TCPSTATE_LISTEN
);
1850 _tcp_closetcb(ti
,tcb
);
1856 * Remember the window we got.
1859 tcb
->tcb_sendwindow
= window
;
1862 * What we do here depends on the current connection state
1863 * Most of this is just from the connection state diagram we've
1864 * all see way too often.
1867 switch ( tcb
->tcb_state
) {
1869 case TCPSTATE_LISTEN
:
1870 if (flags
& TCPFLG_SYN
) {
1871 tcb
->tcb_rcvnext
= seqnum
+ 1;
1872 tcb
->tcb_peerport
= srcport
;
1873 memcpy(tcb
->tcb_peeraddr
,srcaddr
,IP_ADDR_LEN
);
1874 TIMER_SET(tcb
->tcb_timer_keep
,TCP_KEEPALIVE_TIMER
);
1875 _tcp_setstate(tcb
,TCPSTATE_SYN_RECEIVED
);
1876 _tcp_sendctlmsg(ti
,tcb
,TCPFLG_SYN
| TCPFLG_ACK
,TCP_RETX_TIMER
);
1878 return ETH_DROP
; /* we ignore everything else */
1881 case TCPSTATE_SYN_SENT
:
1884 * The only packets we pay attention to in SYN_SENT
1885 * are packets with SYN flags.
1887 if (flags
& TCPFLG_SYN
) {
1890 * Two choices: Either we got a SYN ACK (normal)
1891 * or just a SYN (simultaneous open, rare)
1894 if ((flags
& TCPFLG_ACK
) &&
1895 (acknum
== (tcb
->tcb_sendunack
+ 1))) {
1897 * If we received a SYN ACK and the acknum
1898 * matches our SYN's seqnum + 1, we want
1899 * to transition from SYN_SENT to ESTABLISHED.
1901 TIMER_SET(tcb
->tcb_timer_keep
,TCP_KEEPALIVE_TIMER
);
1902 _tcp_setstate(tcb
,TCPSTATE_ESTABLISHED
);
1903 tcb
->tcb_sendunack
= acknum
;
1904 tcb
->tcb_sendnext
= tcb
->tcb_sendunack
;
1905 tcb
->tcb_rcvnext
= seqnum
+ 1;
1907 * Send an ack, but don't bother with the timer.
1908 * If the remote does not get our ack, it will
1909 * retransmit the SYN ACK and we'll ack it from
1910 * the "ESTABLISHED" state.
1911 * Actually, is that really true?
1913 _tcp_sendctlmsg(ti
,tcb
,TCPFLG_ACK
,0);
1916 DEBUGMSG(("Simultaneous open: SYN received in SYN_SENT state\n"));
1917 tcb
->tcb_rcvnext
++; /* consume the SYN */
1918 _tcp_setstate(tcb
,TCPSTATE_SYN_RECEIVED
);
1919 _tcp_sendctlmsg(ti
,tcb
,TCPFLG_SYN
|TCPFLG_ACK
,TCP_RETX_TIMER
);
1926 case TCPSTATE_SYN_RECEIVED
:
1928 * If we've received a SYN and someone sends us a SYN,
1929 * and the sequence numbers don't match,
1930 * send back a SYN ACK. (this doesn't sound right,
1931 * does it? It's sort of what we do from LISTEN)
1934 if (flags
& TCPFLG_SYN
) {
1935 _tcp_sendctlmsg(ti
,tcb
,TCPFLG_SYN
| TCPFLG_ACK
,TCP_RETX_TIMER
);
1939 * If we got an ack and the acknum is correct,
1940 * switch the state to 'ESTABLISHED' and cancel
1941 * the timer. We're ready to rock.
1944 if ((flags
& TCPFLG_ACK
) &&
1945 (acknum
== (tcb
->tcb_sendunack
+ 1))) {
1946 _tcp_sendctlmsg(ti
,tcb
,TCPFLG_ACK
,0);
1947 tcb
->tcb_sendunack
= acknum
;
1948 tcb
->tcb_sendnext
= tcb
->tcb_sendunack
;
1949 TIMER_SET(tcb
->tcb_timer_keep
,TCP_KEEPALIVE_TIMER
);
1950 _tcp_setstate(tcb
,TCPSTATE_ESTABLISHED
);
1956 case TCPSTATE_ESTABLISHED
:
1957 case TCPSTATE_FINWAIT_1
:
1958 case TCPSTATE_FINWAIT_2
:
1961 * ESTABLISHED, FINWAIT_1, and FINWAIT_2 can all
1962 * carry data. Process the data here. If the
1963 * segment also contains a FIN, these routines
1967 if (flags
& TCPFLG_ACK
) {
1968 _tcp_procack(ti
,tcb
,acknum
,flags
);
1970 _tcp_procdata(ti
,tcb
,seqnum
,flags
,buf
);
1973 case TCPSTATE_CLOSING
:
1974 if (acknum
== (tcb
->tcb_sendunack
+ 1)) {
1975 _tcp_setstate(tcb
,TCPSTATE_TIME_WAIT
);
1976 _tcp_canceltimers(tcb
);
1977 TIMER_SET(tcb
->tcb_timer_2msl
,TCP_TIMEWAIT_TIMER
);
1981 case TCPSTATE_LAST_ACK
:
1982 if (acknum
== (tcb
->tcb_sendunack
+ 1)) {
1983 /* Ack matches, just close the TCB here. */
1984 _tcp_closetcb(ti
,tcb
);
1986 _tcp_freetcb(ti
,tcb
);
1989 _tcp_sendctlmsg(ti
,tcb
,TCPFLG_ACK
| TCPFLG_FIN
,TCP_RETX_TIMER
);
1993 case TCPSTATE_TIME_WAIT
:
1994 if (!(flags
& TCPFLG_RST
)) {
1995 tcb
->tcb_txflags
= TCPFLG_ACK
;
1996 TIMER_SET(tcb
->tcb_timer_2msl
,TCP_TIMEWAIT_TIMER
);
1997 _tcp_protosend(ti
,tcb
);
2003 * If we're expected to transmit something, do it now.
2006 if (tcb
->tcb_flags
& TCB_FLG_OUTPUT
) {
2007 _tcp_output(ti
,tcb
);
2008 tcb
->tcb_flags
&= ~(TCB_FLG_OUTPUT
| TCB_FLG_SENDMSG
);
2011 if (tcb
->tcb_flags
& TCB_FLG_SENDMSG
) {
2012 _tcp_protosend(ti
,tcb
);
2015 /* We always make a copy of the data, so drop the packet. */
2019 /* *********************************************************************
2022 * Handle "fast timeout" for active TCP sockets.
2025 * ti - tcp_info structure
2029 ********************************************************************* */
2030 static void _tcp_fasttimo(tcp_info_t
*ti
)
2036 * First, reset the timer so we'll end up here
2037 * again in another 200ms
2040 TIMER_SET(ti
->ti_fasttimer
,TCP_FAST_TIMER
); /* 200ms */
2043 * Now, walk down the list of TCBs and handle
2047 for (qb
= ti
->ti_tcblist
.q_next
; qb
!= &(ti
->ti_tcblist
); qb
= qb
->q_next
) {
2049 if (tcb
->tcb_flags
& TCB_FLG_DLYACK
) {
2050 tcb
->tcb_flags
&= ~TCB_FLG_DLYACK
;
2051 _tcp_sendctlmsg(ti
,tcb
,TCPFLG_ACK
,-1);
2056 * While we're here, increment TCP's initial sequence number.
2057 * BSD suggests 128000 every second, so we'll add 25600 every 200ms.
2060 ti
->ti_iss
+= 25600;
2065 /* *********************************************************************
2068 * CFE calls this routine periodically to allow us to check
2069 * and update timers, etc.
2072 * arg - our tcp information (held by the timer module for us)
2076 ********************************************************************* */
2078 void _tcp_poll(void *arg
)
2082 tcp_info_t
*ti
= (tcp_info_t
*) arg
;
2085 * Handle the "fast" timer. We do this every 200ms
2088 if (TIMER_EXPIRED(ti
->ti_fasttimer
)) {
2090 /* timer will be reset by the _tcp_fasttimo routine */
2094 * Check the TCBs for the "slow" timers.
2097 for (qb
= ti
->ti_tcblist
.q_next
; qb
!= &(ti
->ti_tcblist
); qb
= qb
->q_next
) {
2101 if (TIMER_EXPIRED(tcb
->tcb_timer_retx
)) {
2102 TIMER_CLEAR(tcb
->tcb_timer_retx
); /* unless it is reset */
2104 DEBUGMSG(("Retransmit timer expired, retrycnt=%d\n",tcb
->tcb_retrycnt
));
2106 switch (tcb
->tcb_state
) {
2107 case TCPSTATE_ESTABLISHED
:
2109 * wind the send seqnum back to the last unacknowledged data,
2110 * and send it out again.
2112 TIMER_SET(tcb
->tcb_timer_retx
,TCP_RETX_TIMER
);
2113 tcb
->tcb_retrycnt
++;
2114 tcb
->tcb_sendnext
= tcb
->tcb_sendunack
;
2115 _tcp_output(ti
,tcb
);
2118 case TCPSTATE_SYN_SENT
:
2119 TIMER_SET(tcb
->tcb_timer_retx
,(TCP_RETX_TIMER
<< tcb
->tcb_retrycnt
));
2120 tcb
->tcb_retrycnt
++;
2121 tcb
->tcb_sendnext
= tcb
->tcb_sendunack
;
2122 _tcp_protosend(ti
,tcb
);
2129 * Check the keepalive timer. This is used during connection
2130 * attempts to time out the connection, and _can_ be used for
2131 * keepalives during established sessions.
2133 * Our TCP does not bother with keepalive messages.
2136 if (TIMER_EXPIRED(tcb
->tcb_timer_keep
)) {
2137 TIMER_CLEAR(tcb
->tcb_timer_keep
); /* unless it is reset */
2138 DEBUGMSG(("Keepalive timer expired in state %d\n",tcb
->tcb_state
));
2139 if (TCPSTATE_IN_SET(tcb
->tcb_state
,M_TCPSTATE_CONNINPROGRESS
)) {
2140 DEBUGMSG(("Canceling pending connection\n"));
2141 _tcp_aborttcb(ti
,tcb
);
2146 * Check the 2MSL timer. This is used in the TIME_WAIT state
2147 * to return the tcb to the free list after the time wait
2151 if (TIMER_EXPIRED(tcb
->tcb_timer_2msl
)) {
2152 TIMER_CLEAR(tcb
->tcb_timer_2msl
); /* will not be reset */
2153 DEBUGMSG(("2MSL timer expired in state %d\n",tcb
->tcb_state
));
2154 if (tcb
->tcb_state
== TCPSTATE_TIME_WAIT
) {
2155 DEBUGMSG(("Freeing TCB\n"));
2156 _tcp_closetcb(ti
,tcb
);
2157 _tcp_freetcb(ti
,tcb
);