RT-AC66 3.0.0.4.374.130 core
[tomato.git] / release / src-rt-6.x / cfe / cfe / net / net_tcp.c
blob0c69298d3cff09c0defbbcf1cf4fdc382e10a3f9
1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
3 *
4 * TCP Protocol File: net_tcp.c
5 *
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:
16 * slow start
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"
68 #include "net_ebuf.h"
69 #include "net_ether.h"
71 #include "net_ip.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"
80 #include "net_tcp.h"
82 /* *********************************************************************
83 * Config
84 ********************************************************************* */
86 //#define _TCP_DEBUG_
88 /* *********************************************************************
89 * Structures
90 ********************************************************************* */
92 struct tcp_info_s {
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 /* *********************************************************************
117 * Macros
118 ********************************************************************* */
120 #ifdef _TCP_DEBUG_
121 #define _tcp_setstate(tcb,state) (tcb)->tcb_state = (state); \
122 printf("tcp state = " #state "\n");
123 #define DEBUGMSG(x) printf x
124 #else
125 #define _tcp_setstate(tcb,state) (tcb)->tcb_state = (state);
126 #define DEBUGMSG(x)
127 #endif
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 /* *********************************************************************
140 * Globals
141 ********************************************************************* */
143 #ifdef _TCP_DEBUG_
144 int _tcp_dumpflags = 1;
145 #else
146 int _tcp_dumpflags = 0;
147 #endif
149 /* *********************************************************************
150 * _tcp_init(ipi,ref)
152 * Initialize the TCP module. We set up our data structures
153 * and register ourselves with the IP layer.
155 * Input parameters:
156 * ipi - IP information
157 * ref - will be passed back to IP as needed
159 * Return value:
160 * tcp_info_t structure, or NULL if problems
161 ********************************************************************* */
163 tcp_info_t *_tcp_init(ip_info_t *ipi,void *ref)
165 tcp_info_t *ti;
166 int idx;
168 ti = (tcp_info_t *) KMALLOC(sizeof(tcp_info_t),0);
169 if (!ti) return NULL;
171 ti->ti_ref = ref;
172 ti->ti_ipinfo = ipi;
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;
190 ti->ti_onqueue = 0;
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);
205 return ti;
209 /* *********************************************************************
210 * _tcp_uninit(info)
212 * De-initialize the TCP layer, unregistering from the IP layer.
214 * Input parameters:
215 * info - our tcp_info_t, from _tcp_init()
217 * Return value:
218 * nothing
219 ********************************************************************* */
221 void _tcp_uninit(tcp_info_t *info)
223 tcb_t *tcb;
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);
236 * Deregister with IP
239 _ip_deregister(info->ti_ipinfo,IPPROTO_TCP);
242 * Free up the info structure
245 KFREE(info);
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.
255 * Input parameters:
256 * ti - tcp information
257 * tcb - tcb to free
259 * Return value:
260 * nothing
261 ********************************************************************* */
263 static void _tcp_freetcb(tcp_info_t *ti,tcb_t *tcb)
266 * Undo socket number
269 if (tcb->tcb_socknum >= 0) ti->ti_ports[tcb->tcb_socknum] = NULL;
270 tcb->tcb_socknum = -1;
273 * Remove from queue
276 ti->ti_onqueue--;
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));
287 * Free the TCB
290 KFREE(tcb);
294 /* *********************************************************************
295 * _tcp_socket(info)
297 * Create a new tcp socket (a new tcb structure is allocated
298 * and entered into the socket table)
300 * Input parameters:
301 * info - tcp information
303 * Return value:
304 * new socket number, or <0 if an error occured
305 ********************************************************************* */
307 int _tcp_socket(tcp_info_t *info)
309 int idx;
310 tcb_t *tcb;
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;
343 tcb->tcb_mtu = 1400;
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) {
366 tcb->tcb_lclport++;
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;
377 info->ti_onqueue++;
378 q_enqueue(&(info->ti_tcblist),&(tcb->tcb_qb));
380 return idx;
382 error:
383 tmb_free(&(tcb->tcb_txbuf));
384 tmb_free(&(tcb->tcb_rxbuf));
385 KFREE(tcb);
386 return CFE_ERR_NOMEM;
390 /* *********************************************************************
391 * _tcp_connect(ti,s,dest,port)
393 * Connect a socket to a remote port.
395 * Input parameters:
396 * ti - TCP information
397 * s - socket number, allocated via _tcp_create
398 * dest - destination IP address
399 * port - destination port number
401 * Return value:
402 * 0 if ok
403 * else error code
404 ********************************************************************* */
406 int _tcp_connect(tcp_info_t *ti,int s,uint8_t *dest,uint16_t port)
408 tcb_t *tcb;
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;
417 tcb->tcb_rcvack = 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);
431 return 0;
435 /* *********************************************************************
436 * _tcp_close(ti,s)
438 * Disconnect a TCP socket nicely. Sends a FIN packet to get
439 * us into the disconnect state.
441 * Input parameters:
442 * ti - tcp information
443 * s - socket number
445 * Return value:
446 * 0 if ok
447 * else error code
448 ********************************************************************* */
450 int _tcp_close(tcp_info_t *ti,int s)
452 tcb_t *tcb;
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);
473 break;
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.
481 * Go back to CLOSED.
483 _tcp_closetcb(ti,tcb);
484 _tcp_freetcb(ti,tcb);
485 break;
487 case TCPSTATE_CLOSE_WAIT:
488 _tcp_setstate(tcb,TCPSTATE_LAST_ACK);
489 _tcp_sendctlmsg(ti,tcb,TCPFLG_ACK | TCPFLG_FIN,TCP_RETX_TIMER);
490 break;
492 case TCPSTATE_TIME_WAIT:
493 case TCPSTATE_FINWAIT_1:
494 case TCPSTATE_FINWAIT_2:
495 case TCPSTATE_CLOSING:
496 case TCPSTATE_LAST_ACK:
497 default:
498 break;
501 return 0;
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
511 * state.
513 * Input parameters:
514 * ti - tcp information
515 * tcb -tcb to abort
517 * Return value:
518 * nothing
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
530 * the remote TCB.
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.
554 * Input parameters:
555 * ti - tcp information
556 * tcb - tcb to close
558 * Return value:
559 * nothing
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);
569 tcb->tcb_flags = 0;
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
586 * Input parameters:
587 * ti - TCP information
588 * s - socket number
589 * buf - buffer of data to send
590 * len - size of buffer to send
592 * Return value:
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)
599 tcb_t *tcb;
600 int retlen;
601 int curlen;
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)) {
637 _tcp_output(ti,tcb);
640 return retlen;
643 /* *********************************************************************
644 * _tcp_recv(ti,s,buf,len)
646 * Get buffered receive data from the TCP socket
648 * Input parameters:
649 * ti - tcp information
650 * s - socket number
651 * buf - pointer to receive buffer area
652 * len - size of receive buffer area
654 * Return value:
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)
662 tcb_t *tcb;
663 int retlen;
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;
684 // }
686 return retlen;
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.
696 * Input parameters:
697 * ti - tcp information
698 * s - socket number
699 * port - port number
701 * Return value:
702 * 0 if ok
703 * else error code
704 ********************************************************************* */
706 int _tcp_bind(tcp_info_t *ti,int s,uint16_t port)
708 tcb_t *tcb;
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;
718 return 0;
721 /* *********************************************************************
722 * _tcp_setflags(ti,s,flags)
724 * Set per-socket flags.
726 * Input parameters:
727 * ti - tcp information
728 * s - socket number
729 * flags - flags to set
731 * Return value:
732 * 0 if ok
733 * else error code
734 ********************************************************************* */
736 int _tcp_setflags(tcp_info_t *ti,int s,unsigned int flags)
738 tcb_t *tcb;
740 tcb = ti->ti_ports[s];
741 if (!tcb) return CFE_ERR_INV_PARAM;
743 tcb->tcb_sockflags = flags;
745 return 0;
748 /* *********************************************************************
749 * _tcp_getflags(ti,s,flags)
751 * Get per-socket flags.
753 * Input parameters:
754 * ti - tcp information
755 * s - socket number
756 * flags - pointer to int to receive flags
758 * Return value:
759 * 0 if ok
760 * else error code
761 ********************************************************************* */
763 int _tcp_getflags(tcp_info_t *ti,int s,unsigned int *flags)
765 tcb_t *tcb;
767 tcb = ti->ti_ports[s];
768 if (!tcb) return CFE_ERR_INV_PARAM;
770 *flags = tcb->tcb_sockflags;
772 return 0;
776 /* *********************************************************************
777 * _tcp_peeraddr(ti,s,addr,port)
779 * Return the address of the computer on the other end of this
780 * connection.
782 * Input parameters:
783 * ti - tcp information
784 * s - socket number
785 * addr - receives IP address of remote
786 * port - port number
788 * Return value:
789 * 0 if ok
790 * else error code
791 ********************************************************************* */
793 int _tcp_peeraddr(tcp_info_t *ti,int s,uint8_t *addr,uint16_t *port)
795 tcb_t *tcb;
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
802 * is valid.
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;
812 return 0;
815 /* *********************************************************************
816 * _tcp_listen(ti,s,port)
818 * Set a socket for listening mode, allowing inbound connections
819 * to occur.
821 * Input parameters:
822 * ti - tcp information
823 * s - socket nunber
824 * port - port number to listen for (implicit tcp_bind)
826 * Return value:
827 * 0 if ok
828 * else error code
829 ********************************************************************* */
831 int _tcp_listen(tcp_info_t *ti,int s,uint16_t port)
833 tcb_t *tcb;
834 queue_t *qb;
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) {
841 tcb = (tcb_t *) qb;
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;
865 tcb->tcb_rcvack = 0;
867 tmb_init(&tcb->tcb_txbuf);
868 tmb_init(&tcb->tcb_rxbuf);
870 tcb->tcb_txflags = 0;
872 return 0;
875 /* *********************************************************************
876 * _tcp_status(ti,s,connflag,rxready,rxeof)
878 * Get status information about the TCP session
880 * Input parameters:
881 * ti - tcp information
882 * s - socket nunber
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.
888 * Return value:
889 * 0 if ok
890 * else error code
891 ********************************************************************* */
893 int _tcp_status(tcp_info_t *ti,int s,int *connflag,int *rxready,int *rxeof)
895 tcb_t *tcb;
896 int rxlen;
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.
912 if (connflag) {
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;
920 else {
921 *connflag = TCPSTATUS_NOTCONN;
925 if (rxready) {
926 *rxready = rxlen;
929 if (rxeof) {
930 *rxeof = 0;
931 if ((tcb->tcb_state == TCPSTATE_CLOSE_WAIT) ||
932 (tcb->tcb_state == TCPSTATE_LAST_ACK)) {
933 *rxeof = 1;
937 return 0;
940 /* *********************************************************************
941 * _tcp_debug(ti,s,arg)
943 * Perform debug functions on a socket
945 * Input parameters:
946 * ti - tcp information
947 * s - socket number
948 * arg - argument
950 * Return value:
951 * 0 if ok
952 * else error code
953 ********************************************************************* */
955 int _tcp_debug(tcp_info_t *ti,int s,int arg)
957 tcb_t *tcb;
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",
965 tcb->tcb_sendwindow,
966 tcb->tcb_rcvack,tmb_curlen(&(tcb->tcb_rxbuf)));
968 return 0;
972 #ifdef _TCP_DEBUG_
973 /* *********************************************************************
974 * _tcp_dumppktstate(label,flags,ack,seq,len)
976 * A debug function.
978 * Input parameters:
979 * label - printed before packet state
980 * flags - transmit flags for packet
981 * ack,seq,len - from the packet
983 * Return value:
984 * nothing
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);
998 #endif
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.
1009 * Input parameters:
1010 * ti - tcp information
1011 * tcb - the tcb to send data on
1013 * Return value:
1014 * nothing
1015 ********************************************************************* */
1017 static void _tcp_output(tcp_info_t *ti,tcb_t *tcb)
1019 ebuf_t *b;
1020 int tcplen;
1021 int window;
1022 uint16_t flags;
1023 uint8_t *cksumptr;
1024 uint8_t *tcphdr;
1025 uint16_t cksum;
1026 int hdrlen;
1027 uint8_t pseudoheader[12];
1028 int offset;
1029 uint32_t sendmax;
1030 uint32_t windowmax;
1031 uint32_t cwndmax;
1034 * sendmax is (one plus) the highest sequence number we have
1035 * data for.
1037 * windowmax is (one plus) the highest sequence number in the
1038 * send window.
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);
1084 if (!b) break;
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,
1114 offset,
1115 tcb->tcb_mtu);
1117 b->eb_length += tcplen;
1119 #ifdef _TCP_DEBUG_
1120 if (_tcp_dumpflags) _tcp_dumppktstate("TX_DATA",flags,
1121 tcb->tcb_sendnext,
1122 tcb->tcb_rcvack,tcplen);
1123 #endif
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);
1150 cksum = ~cksum;
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.
1184 * Input parameters:
1185 * ti - tcp infomration
1186 * tcb - tcb we're interested in
1188 * Return value:
1189 * nothing
1190 ********************************************************************* */
1192 static void _tcp_protosend(tcp_info_t *ti,tcb_t *tcb)
1194 ebuf_t *b;
1195 int tcplen;
1196 int window;
1197 uint16_t flags;
1198 uint8_t *cksumptr;
1199 uint8_t *tcphdr;
1200 uint16_t cksum;
1201 int hdrlen;
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);
1210 if (!b) return;
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;
1230 else {
1231 flags = tcb->tcb_txflags | (TCPHDRFLG(TCP_HDR_LENGTH));
1232 hdrlen = TCP_HDR_LENGTH;
1236 #ifdef _TCP_DEBUG_
1237 if (_tcp_dumpflags) _tcp_dumppktstate("TX_CTL",flags,
1238 tcb->tcb_sendnext,
1239 tcb->tcb_rcvack,0);
1240 #endif
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);
1296 cksum = ~cksum;
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.
1313 * Input parameters:
1314 * ti - tcp infomration
1315 * tcb - tcb we're interested in
1317 * Return value:
1318 * nothing
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
1344 * right here.
1346 * Input parameters:
1347 * ti - tcp information
1348 * tcb - the tcb for this TCP session
1349 * flags - packet flags (TCPFLG_xxx)
1350 * timeout - timeout value , in ticks
1352 * Return value:
1353 * nothing
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;
1361 if (timeout >= 0) {
1362 if (timeout) {
1363 TIMER_SET(tcb->tcb_timer_retx,timeout);
1365 else {
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
1378 * already in use.
1380 * Input parameters:
1381 * ti - tcp information
1382 * port - local port
1384 * Return value:
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)
1389 tcb_t *tcb = NULL;
1390 queue_t *qb;
1392 for (qb = ti->ti_tcblist.q_next; qb != &(ti->ti_tcblist); qb = qb->q_next) {
1393 tcb = (tcb_t *) qb;
1395 if (tcb->tcb_lclport == port) return tcb;
1399 return NULL;
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.
1409 * Input parameters:
1410 * ti - tcp information
1411 * srcport,dstport - source and dest ports from TCP header
1412 * saddr - source IP address of sending host
1414 * Return value:
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)
1420 tcb_t *tcb = NULL;
1421 queue_t *qb;
1423 for (qb = ti->ti_tcblist.q_next; qb != &(ti->ti_tcblist); qb = qb->q_next) {
1424 tcb = (tcb_t *) qb;
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) {
1438 tcb = (tcb_t *) qb;
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;
1448 return NULL;
1451 /* *********************************************************************
1452 * _tcp_procack(ti,tcb,ack,flags)
1454 * Process a received acknowledgement.
1456 * Input parameters:
1457 * ti - tcp information
1458 * tcb - tcb for this tcb session
1459 * ack - acknum from received packet
1460 * flags - flags from received packet
1462 * Return value:
1463 * nothing
1464 ********************************************************************* */
1466 static void _tcp_procack(tcp_info_t *ti,tcb_t *tcb,uint32_t ack,uint16_t flags)
1468 int ackamt;
1469 int unacklen;
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));
1490 return;
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
1503 * time.
1506 if (ackamt > 0) {
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 */
1512 else {
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;
1527 else {
1528 TIMER_CLEAR(tcb->tcb_timer_retx);
1531 break;
1533 case TCPSTATE_FINWAIT_1:
1534 ackamt = TCPSEQ_DIFF(ack,tcb->tcb_sendunack);
1535 if (ackamt == 1) {
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);
1543 else {
1544 _tcp_setstate(tcb,TCPSTATE_FINWAIT_2);
1547 break;
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.
1559 * Input parameters:
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
1565 * Return value:
1566 * nothing
1567 ********************************************************************* */
1569 static void _tcp_procdata(tcp_info_t *ti,tcb_t *tcb,uint32_t seqnum,
1570 uint16_t flags,ebuf_t *buf)
1572 int datalen;
1573 uint8_t *bp;
1574 int rxwin,rwin;
1575 uint32_t endseqnum;
1576 uint32_t endrxwindow;
1577 int reallen;
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.
1593 if (datalen != 0) {
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
1600 * window.
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;
1617 // }
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));
1626 if (!rwin) {
1627 DEBUGMSG(("Dropping out-of-order packet %u %u %u\n",seqnum,
1628 tcb->tcb_rcvnext,endseqnum));
1629 return;
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));
1649 if (reallen > 0) {
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);
1671 else {
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,
1692 * go to CLOSE_WAIT.
1695 tcb->tcb_flags &= ~TCB_FLG_DLYACK;
1696 _tcp_setstate(tcb,TCPSTATE_CLOSE_WAIT);
1697 _tcp_sendctlmsg(ti,tcb,TCPFLG_ACK,-1);
1698 break;
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);
1715 else {
1716 /* Received: FIN - simultaneous close, go to CLOSING */
1717 _tcp_setstate(tcb,TCPSTATE_CLOSING);
1718 _tcp_preparectlmsg(tcb,TCPFLG_ACK);
1720 break;
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);
1733 break;
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.
1745 * Input parameters:
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
1750 * Return value:
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];
1757 int tcplen;
1758 uint16_t calccksum;
1759 uint16_t origcksum;
1760 uint8_t *tcphdr;
1761 uint16_t srcport;
1762 uint16_t dstport;
1763 uint32_t seqnum;
1764 uint32_t acknum;
1765 uint16_t window;
1766 uint16_t flags;
1767 tcb_t *tcb;
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) {
1796 return ETH_DROP;
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) {
1811 return ETH_DROP;
1813 ebuf_skip(buf,(TCPHDRSIZE(flags) - TCP_HDR_LENGTH));
1816 tcb = _tcp_find_tcb(ti,srcport,dstport,srcaddr);
1817 if (!tcb) {
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);
1832 * Some debugging
1835 #ifdef _TCP_DEBUG_
1836 if (_tcp_dumpflags) _tcp_dumppktstate("Received",flags,
1837 acknum,seqnum,ebuf_length(buf));
1838 #endif
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);
1849 else {
1850 _tcp_closetcb(ti,tcb);
1852 return ETH_DROP;
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 */
1879 break;
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);
1915 else {
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);
1923 return ETH_DROP;
1924 break;
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);
1953 return ETH_DROP;
1954 break;
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
1964 * will handle that.
1967 if (flags & TCPFLG_ACK) {
1968 _tcp_procack(ti,tcb,acknum,flags);
1970 _tcp_procdata(ti,tcb,seqnum,flags,buf);
1971 break;
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);
1979 break;
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);
1985 /* and free it. */
1986 _tcp_freetcb(ti,tcb);
1988 else {
1989 _tcp_sendctlmsg(ti,tcb,TCPFLG_ACK | TCPFLG_FIN,TCP_RETX_TIMER);
1991 break;
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);
1999 break;
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. */
2016 return ETH_DROP;
2019 /* *********************************************************************
2020 * _tcp_fasttimo(ti)
2022 * Handle "fast timeout" for active TCP sockets.
2024 * Input parameters:
2025 * ti - tcp_info structure
2027 * Return value:
2028 * nothing
2029 ********************************************************************* */
2030 static void _tcp_fasttimo(tcp_info_t *ti)
2032 tcb_t *tcb;
2033 queue_t *qb;
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
2044 * all the timers.
2047 for (qb = ti->ti_tcblist.q_next; qb != &(ti->ti_tcblist); qb = qb->q_next) {
2048 tcb = (tcb_t *) qb;
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 /* *********************************************************************
2066 * _tcp_poll(arg)
2068 * CFE calls this routine periodically to allow us to check
2069 * and update timers, etc.
2071 * Input parameters:
2072 * arg - our tcp information (held by the timer module for us)
2074 * Return value:
2075 * nothing
2076 ********************************************************************* */
2078 void _tcp_poll(void *arg)
2080 tcb_t *tcb;
2081 queue_t *qb;
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)) {
2089 _tcp_fasttimo(ti);
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) {
2098 tcb = (tcb_t *) qb;
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);
2116 break;
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);
2123 break;
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
2148 * period elapses.
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);