tcpsm.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2007 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  * -
00033  * Portions Copyright (C) 2000 David J. Hudson <dave@humbug.demon.co.uk>
00034  *
00035  * This file is distributed in the hope that it will be useful, but WITHOUT
00036  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00037  * FITNESS FOR A PARTICULAR PURPOSE.
00038  *
00039  * You can redistribute this file and/or modify it under the terms of the GNU
00040  * General Public License (GPL) as published by the Free Software Foundation;
00041  * either version 2 of the License, or (at your discretion) any later version.
00042  * See the accompanying file "copying-gpl.txt" for more details.
00043  *
00044  * As a special exception to the GPL, permission is granted for additional
00045  * uses of the text contained in this file.  See the accompanying file
00046  * "copying-liquorice.txt" for details.
00047  * -
00048  * Portions Copyright (c) 1983, 1993 by
00049  *  The Regents of the University of California.  All rights reserved.
00050  *
00051  * Redistribution and use in source and binary forms, with or without
00052  * modification, are permitted provided that the following conditions
00053  * are met:
00054  * 1. Redistributions of source code must retain the above copyright
00055  *    notice, this list of conditions and the following disclaimer.
00056  * 2. Redistributions in binary form must reproduce the above copyright
00057  *    notice, this list of conditions and the following disclaimer in the
00058  *    documentation and/or other materials provided with the distribution.
00059  * 3. Neither the name of the University nor the names of its contributors
00060  *    may be used to endorse or promote products derived from this software
00061  *    without specific prior written permission.
00062  *
00063  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00064  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00065  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00066  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00067  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00068  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00069  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00070  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00071  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00072  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00073  * SUCH DAMAGE.
00074  * -
00075  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
00076  *
00077  * Permission to use, copy, modify, and distribute this software for any
00078  * purpose with or without fee is hereby granted, provided that the above
00079  * copyright notice and this permission notice appear in all copies, and that
00080  * the name of Digital Equipment Corporation not be used in advertising or
00081  * publicity pertaining to distribution of the document or software without
00082  * specific, written prior permission.
00083  * 
00084  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
00085  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
00086  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
00087  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
00088  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
00089  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
00090  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00091  * SOFTWARE.
00092  */
00093 
00094 /*
00095  * $Log: tcpsm.c,v $
00096  * Revision 1.23  2007/02/15 15:59:59  haraldkipp
00097  * Serious bug in the TCP state machine froze socket connection on 32-bit
00098  * platforms.
00099  *
00100  * Revision 1.22  2006/10/05 17:25:41  haraldkipp
00101  * Avoid possible alignment errors. Fixes bug #1567748.
00102  *
00103  * Revision 1.21  2006/05/15 12:49:12  haraldkipp
00104  * ICCAVR doesn't accept void pointer calculation.
00105  *
00106  * Revision 1.20  2006/03/21 21:22:19  drsung
00107  * Enhancement made to TCP state machine. Now TCP options
00108  * are read from peer and at least the maximum segment size is stored.
00109  *
00110  * Revision 1.19  2005/04/30 16:42:42  chaac
00111  * Fixed bug in handling of NUTDEBUG. Added include for cfg/os.h. If NUTDEBUG
00112  * is defined in NutConf, it will make effect where it is used.
00113  *
00114  * Revision 1.18  2005/04/05 17:44:57  haraldkipp
00115  * Made stack space configurable.
00116  *
00117  * Revision 1.17  2005/03/30 15:17:58  mrjones4u
00118  * Defussed race condition in NutTcpStateActiveOpenEvent where the NutEventWait would be called after sock->so_ac_tq had been signaled and therefore the calling thread will hang due to usage of NutEventBroadcast which will not ‘store’ the signaled state. This condition can e.g. occur when attempting connection an unconnected target port on an active host. The returning RST would be processed and signaled before the NutEventWait is called.
00119  *
00120  * Revision 1.16  2005/02/04 17:17:49  haraldkipp
00121  * Unused include files removed.
00122  *
00123  * Revision 1.15  2005/01/21 16:49:46  freckle
00124  * Seperated calls to NutEventPostAsync between Threads and IRQs
00125  *
00126  * Revision 1.14  2005/01/03 08:43:29  haraldkipp
00127  * Replaced unprotected calls to NutEventPostAsync() by late calls to NutEventPost().
00128  * This should fix the infrequent system halts/resets. The event to the transmitter
00129  * waiting queue will be broadcasted on relevant state changes.
00130  *
00131  * Revision 1.13  2004/07/30 19:54:46  drsung
00132  * Some code of TCP stack redesigned. Round trip time calculation is now
00133  * supported. Fixed several bugs in TCP state machine. Now TCP connections
00134  * should be more reliable under heavy traffic or poor physical connections.
00135  *
00136  * Revision 1.12  2004/04/15 11:08:21  haraldkipp
00137  * Bugfix: Sequence number had not been incremented on FIN segments.
00138  * Added Realtek hack to reduce concurrent connection problems.
00139  * Rely on TCP output to set the retransmission timer.
00140  *
00141  * Revision 1.11  2004/02/28 20:14:38  drsung
00142  * Merge from nut-3_4-release b/c of bugfixes.
00143  *
00144  * Revision 1.9.2.1  2004/02/28 20:02:23  drsung
00145  * Bugfix in several tcp state functions. Swapped around the check
00146  * for ACK and SYN flag. Because initial SYN packets don't have
00147  * an ACK flag, recevied SYN packets were never rejected.
00148  * Thanks to Damian Slee, who discovered that.
00149  *
00150  * Revision 1.9  2004/01/25 11:50:03  drsung
00151  * setting correct error code on timeout while NutTcpConnect.
00152  *
00153  * Revision 1.8  2004/01/25 11:29:48  drsung
00154  * bugfix for connection establishing.
00155  *
00156  * Revision 1.7  2004/01/14 19:35:19  drsung
00157  * New TCP output buffer handling and fixed not starting retransmission timer for NutTcpConnect.
00158  *
00159  * Revision 1.6  2003/11/28 19:49:58  haraldkipp
00160  * TCP connections suddenly drop during transmission.
00161  * Bug in retransmission timer fixed.
00162  *
00163  * Revision 1.5  2003/11/04 17:57:35  haraldkipp
00164  * Bugfix: Race condition left socket in close-wait state
00165  *
00166  * Revision 1.4  2003/11/03 16:48:02  haraldkipp
00167  * Use the system timer for retransmission timouts
00168  *
00169  * Revision 1.3  2003/08/14 15:10:31  haraldkipp
00170  * Two bugfixes: 1. NutTcpAccept fails if caller got higher priority.
00171  * 2. Incoming TCP NETBUFs will never be released if TCP is not used by
00172  * the application.
00173  *
00174  * Revision 1.2  2003/07/13 19:22:23  haraldkipp
00175  * TCP transfer speed increased by changing the character receive buffer
00176  * in TCPSOCKET to a NETBUF queue. (More confusing diff lines by using
00177  * indent, sorry.)
00178  *
00179  * Revision 1.1.1.1  2003/05/09 14:41:42  haraldkipp
00180  * Initial using 3.2.1
00181  *
00182  * Revision 1.20  2003/05/06 18:20:02  harald
00183  * Stack size reduced
00184  *
00185  * Revision 1.19  2003/04/01 18:36:11  harald
00186  * Added forced ACK response on same sequence
00187  *
00188  * Revision 1.18  2003/03/31 12:29:45  harald
00189  * Check NEBUF allocation
00190  *
00191  * Revision 1.17  2003/02/04 18:14:57  harald
00192  * Version 3 released
00193  *
00194  * Revision 1.16  2003/01/14 16:51:29  harald
00195  * Handle possible deadlock in the TCP state machine in low memory situations.
00196  * Fixed: TCP might fail to process incoming packets on slow connections.
00197  *
00198  * Revision 1.15  2002/09/15 17:05:41  harald
00199  * Silently ignore late SYNs.
00200  * Detect host down in local networks during connect.
00201  * Avoid re-sending packets too soon.
00202  *
00203  * Revision 1.14  2002/09/03 17:42:20  harald
00204  * Buffer sequences received in advance
00205  *
00206  * Revision 1.13  2002/08/16 17:54:56  harald
00207  * Count out of sequence drops
00208  *
00209  * Revision 1.12  2002/06/26 17:29:36  harald
00210  * First pre-release with 2.4 stack
00211  *
00212  */
00213 
00214 #include <cfg/os.h>
00215 #include <cfg/tcp.h>
00216 
00217 #include <sys/thread.h>
00218 #include <sys/heap.h>
00219 #include <sys/event.h>
00220 #include <sys/timer.h>
00221 
00222 #include <net/errno.h>
00223 #include <netinet/in.h>
00224 #include <netinet/ip.h>
00225 #include <net/route.h>
00226 #include <sys/socket.h>
00227 #include <netinet/tcputil.h>
00228 #include <netinet/tcp.h>
00229 
00230 #ifdef NUTDEBUG
00231 #include <net/netdebug.h>
00232 #endif
00233 
00234 #ifndef NUT_THREAD_TCPSMSTACK
00235 #define NUT_THREAD_TCPSMSTACK   512
00236 #endif
00237 
00238 extern TCPSOCKET *tcpSocketList;
00239 
00244 
00245 HANDLE tcp_in_rdy;
00246 NETBUF *volatile tcp_in_nbq;
00247 static u_short tcp_in_cnt;
00248 static HANDLE tcpThread = 0;
00249 
00250 /* ================================================================
00251  * Helper functions
00252  * ================================================================
00253  */
00254 
00263 static void NutTcpInputOptions(TCPSOCKET * sock, NETBUF * nb)
00264 {
00265     u_char *cp;
00266     u_short s;
00267     
00268     /* any options there? */
00269     if (nb->nb_tp.sz <= sizeof (TCPHDR))
00270         return;
00271     
00272     /* loop through available options */
00273     for (cp = ((u_char*) nb->nb_tp.vp) + sizeof(TCPHDR); (*cp != TCPOPT_EOL) 
00274        && (cp - (u_char *)nb->nb_tp.vp < (int)nb->nb_tp.sz); )
00275     {
00276         switch (*cp)
00277         {
00278             /* On NOP just proceed to next option */
00279             case TCPOPT_NOP:
00280                 cp++;
00281                 continue;
00282                 
00283             /* Read MAXSEG option */
00284             case TCPOPT_MAXSEG:
00285                 s = ntohs(((u_short)cp[2] << 8) | cp[3]);
00286                 if (s < sock->so_mss)
00287                     sock->so_mss = s;
00288                 cp += TCPOLEN_MAXSEG;
00289                 break;
00290             /* Ignore any other options */
00291             default:
00292                 cp += *(u_char*) (cp + 1);
00293                 break;
00294         }
00295     }
00296 }
00297 
00306 static void NutTcpProcessAppData(TCPSOCKET * sock, NETBUF * nb)
00307 {
00308     /*
00309      * Add the NETBUF to the socket's input buffer.
00310      */
00311     if (sock->so_rx_buf) {
00312         NETBUF *nbp = sock->so_rx_buf;
00313 
00314         while (nbp->nb_next)
00315             nbp = nbp->nb_next;
00316         nbp->nb_next = nb;
00317     } else
00318         sock->so_rx_buf = nb;
00319 
00320     /*
00321      * Update the number of bytes available in the socket's input buffer
00322      * and the sequence number we expect next.
00323      */
00324     sock->so_rx_cnt += nb->nb_ap.sz;
00325     sock->so_rx_nxt += nb->nb_ap.sz;
00326 
00327     /*
00328      * Reduce our TCP window size.
00329      */
00330     if (nb->nb_ap.sz >= sock->so_rx_win)
00331         sock->so_rx_win = 0;
00332     else
00333         sock->so_rx_win -= nb->nb_ap.sz;
00334 
00335     /*
00336      * Set the socket's ACK flag. This will enable ACK transmission in
00337      * the next outgoing segment. If no more NETBUFs are queued, we
00338      * force immediate transmission of the ACK.
00339      */
00340     sock->so_tx_flags |= SO_ACK;
00341     if (nb->nb_next)
00342         nb->nb_next = 0;
00343     else
00344         sock->so_tx_flags |= SO_FORCE;
00345 
00346     NutTcpOutput(sock, 0, 0);
00347 }
00348 
00349 /*
00350  * \param sock Socket descriptor.
00351  */
00352 static void NutTcpProcessSyn(TCPSOCKET * sock, IPHDR * ih, TCPHDR * th)
00353 {
00354     u_short mss;
00355     NUTDEVICE *dev;
00356     IFNET *nif;
00357 
00358     sock->so_local_addr = ih->ip_dst;
00359     sock->so_remote_port = th->th_sport;
00360     sock->so_remote_addr = ih->ip_src;
00361 
00362     sock->so_rx_nxt = sock->so_tx_wl1 = sock->so_rx_isn = ntohl(th->th_seq);
00363     sock->so_rx_nxt++;
00364     sock->so_tx_win = ntohs(th->th_win);
00365 
00366     /*
00367      * To avoid unnecessary fragmentation, limit the
00368      * maximum segment size to the maximum transfer
00369      * unit of our interface.
00370      */
00371     if ((dev = NutIpRouteQuery(ih->ip_src, 0)) != 0) {
00372         nif = dev->dev_icb;
00373         mss = nif->if_mtu - sizeof(IPHDR) - sizeof(TCPHDR);
00374         if (sock->so_mss == 0 || sock->so_mss > mss)
00375             sock->so_mss = mss;
00376 
00377         /* Limit output buffer size to mms */
00378         if (sock->so_devobsz > sock->so_mss)
00379             sock->so_devobsz = sock->so_mss;
00380     }
00381 }
00382 
00390 static int NutTcpProcessAck(TCPSOCKET * sock, TCPHDR * th, u_short length)
00391 {
00392     NETBUF *nb;
00393     u_long h_seq;
00394     u_long h_ack;
00395 
00396     /*
00397      * If remote acked something not yet send, reply immediately.
00398      */
00399     h_ack = ntohl(th->th_ack);
00400     if (h_ack > sock->so_tx_nxt) {
00401         sock->so_tx_flags |= SO_ACK | SO_FORCE;
00402         return 0;
00403     }
00404 
00405     /*
00406      * If the new sequence number or acknowledged sequence number
00407      * is above our last update, we adjust our transmit window.
00408      * Avoid dupe ACK processing on window updates.
00409      */
00410     if (h_ack == sock->so_tx_una) {
00411         h_seq = ntohl(th->th_seq);
00412         if (h_seq > sock->so_tx_wl1 || (h_seq == sock->so_tx_wl1 && h_ack >= sock->so_tx_wl2)) {
00413             sock->so_tx_win = ntohs(th->th_win);
00414             sock->so_tx_wl1 = h_seq;
00415             sock->so_tx_wl2 = h_ack;
00416         }
00417     }
00418 
00419     /*
00420      * Ignore old ACKs but wake up sleeping transmitter threads, because
00421      * the window size may have changed.
00422      */
00423     if (h_ack < sock->so_tx_una) {
00424         return 0;
00425     }
00426 
00427     /*
00428      * Process duplicate ACKs.
00429      */
00430     if (h_ack == sock->so_tx_una) {
00431         /*
00432          * Don't count, if nothing is waiting for ACK,
00433          * segment contains data or on SYN/FIN segments.
00434          */
00435         if (sock->so_tx_nbq && length == 0 && (th->th_flags & (TH_SYN | TH_FIN)) == 0) {
00436             /*
00437              * If dupe counter reaches it's limit, resend
00438              * the oldest unacknowledged netbuf.
00439              */
00440             if (++sock->so_tx_dup >= 3) {
00441                 sock->so_tx_dup = 0;
00442 #ifdef NUTDEBUG
00443                 if (__tcp_trf)
00444                     NutDumpTcpHeader(__tcp_trs, "RET", sock, sock->so_tx_nbq);
00445 #endif
00446                 /*
00447                  * Retransmit first unacked packet from queue.
00448                  * Actually we got much more trouble if this fails.
00449                  */
00450                 if (NutTcpStateRetranTimeout(sock))
00451                     return -1;
00452             }
00453         }
00454         return 0;
00455     }
00456 
00457     /*
00458      * We're here, so the ACK must have actually acked something
00459      */
00460     sock->so_tx_dup = 0;
00461     sock->so_tx_una = h_ack;
00462 
00463     /*
00464      * Bugfix contributed by Liu Limin: If the remote is slow and this
00465      * line is missing, then Ethernut will send a full data packet even
00466      * if the remote closed the window.
00467      */
00468     sock->so_tx_win = ntohs(th->th_win);
00469 
00470     /* 
00471      * Do round trip time calculation.
00472      */
00473     if (sock->so_rtt_seq && sock->so_rtt_seq < h_ack)
00474         NutTcpCalcRtt (sock);
00475     sock->so_rtt_seq = 0;
00476     /*
00477      * Remove all acknowledged netbufs.
00478      */
00479     while ((nb = sock->so_tx_nbq) != 0) {
00480         /* Calculate the sequence beyond this netbuf. */
00481         h_seq = ntohl(((TCPHDR *) (nb->nb_tp.vp))->th_seq) + nb->nb_ap.sz;
00482         if (((TCPHDR *) (nb->nb_tp.vp))->th_flags & (TH_SYN | TH_FIN)) {
00483             h_seq++;
00484         }
00485         //@@@printf ("[%04X]*: processack, check seq#: %lu\n", (u_short) sock, h_seq);
00486         if (h_seq > h_ack) {
00487             break;
00488         }
00489         sock->so_tx_nbq = nb->nb_next;
00490         NutNetBufFree(nb);
00491     }
00492 
00493     /*
00494      * Reset retransmit timer and wake up waiting transmissions.
00495      */
00496     if (sock->so_tx_nbq) {
00497         sock->so_retran_time = (u_short) NutGetMillis();
00498     } else {
00499         sock->so_retran_time = 0;
00500     }
00501     sock->so_retransmits = 0;
00502 
00503     return 0;
00504 }
00505 
00506 
00507 
00508 /* ================================================================
00509  * State changes.
00510  * ================================================================
00511  */
00520 static int NutTcpStateChange(TCPSOCKET * sock, u_char state)
00521 {
00522     int rc = 0;
00523     ureg_t txf = 0;
00524 
00525     switch (sock->so_state) {
00526         /* Handle the most common case first. */
00527     case TCPS_ESTABLISHED:
00528         switch (state) {
00529         case TCPS_FIN_WAIT_1:
00530             /*
00531              * Closed by application.
00532              */
00533             sock->so_tx_flags |= SO_FIN | SO_ACK;
00534             txf = 1;
00535 
00536 #ifdef RTLCONNECTHACK
00537             /*
00538              * Hack alert!
00539              * On the RTL8019AS we got a problem. Because of not handling
00540              * the CHRDY line, the controller drops outgoing packets when
00541              * a browser opens multiple connections concurrently, producing
00542              * several short incoming packets. Empirical test showed, that
00543              * a slight delay during connects and disconnects helped to
00544              * remarkably reduce this problem.
00545              */
00546             NutDelay(5);
00547 #endif
00548             break;
00549         case TCPS_CLOSE_WAIT:
00550             /*
00551              * FIN received.
00552              */
00553             sock->so_tx_flags |= SO_ACK | SO_FORCE;
00554             txf = 1;
00555             break;
00556         default:
00557             rc = -1;
00558             break;
00559         }
00560         break;
00561 
00562     case TCPS_LISTEN:
00563         /*
00564          * SYN received.
00565          */
00566         if (state == TCPS_SYN_RECEIVED) {
00567             sock->so_tx_flags |= SO_SYN | SO_ACK;
00568             txf = 1;
00569 #ifdef RTLCONNECTHACK
00570             /*
00571              * Hack alert!
00572              * On the RTL8019AS we got a problem. Because of not handling
00573              * the CHRDY line, the controller drops outgoing packets when
00574              * a browser opens multiple connections concurrently, producing
00575              * several short incoming packets. Empirical test showed, that
00576              * a slight delay during connects and disconnects helped to
00577              * remarkably reduce this problem.
00578              */
00579             NutDelay(5);
00580 #endif
00581         } else
00582             rc = -1;
00583         break;
00584 
00585     case TCPS_SYN_SENT:
00586         switch (state) {
00587         case TCPS_LISTEN:
00588             /*
00589              * RST received on passive socket.
00590              */
00591             break;
00592         case TCPS_SYN_RECEIVED:
00593             /*
00594              * SYN received.
00595              */
00596             sock->so_tx_flags |= SO_SYN | SO_ACK;
00597             txf = 1;
00598             break;
00599         case TCPS_ESTABLISHED:
00600             /*
00601              * SYNACK received.
00602              */
00603             sock->so_tx_flags |= SO_ACK | SO_FORCE;
00604             txf = 1;
00605             break;
00606         default:
00607             rc = -1;
00608             break;
00609         }
00610         break;
00611 
00612     case TCPS_SYN_RECEIVED:
00613         switch (state) {
00614         case TCPS_LISTEN:
00615             /*
00616              * RST received on passive socket.
00617              */
00618             break;
00619         case TCPS_ESTABLISHED:
00620             /*
00621              * ACK of SYN received.
00622              */
00623             break;
00624         case TCPS_FIN_WAIT_1:
00625             /*
00626              * Closed by application.
00627              */
00628             sock->so_tx_flags |= SO_FIN;
00629             txf = 1;
00630             break;
00631         case TCPS_CLOSE_WAIT:
00632             /*
00633              * FIN received.
00634              */
00635             sock->so_tx_flags |= SO_FIN | SO_ACK;
00636             txf = 1;
00637             break;
00638         default:
00639             rc = -1;
00640             break;
00641         }
00642         break;
00643 
00644     case TCPS_FIN_WAIT_1:
00645         switch (state) {
00646         case TCPS_FIN_WAIT_1:
00647         case TCPS_FIN_WAIT_2:
00648             /*
00649              * ACK of FIN received.
00650              */
00651             break;
00652         case TCPS_CLOSING:
00653             /*
00654              * FIN received.
00655              */
00656             sock->so_tx_flags |= SO_ACK | SO_FORCE;
00657             txf = 1;
00658             break;
00659         case TCPS_TIME_WAIT:
00660             /*
00661              * FIN and ACK of FIN received.
00662              */
00663             break;
00664         default:
00665             rc = -1;
00666             break;
00667         }
00668         break;
00669 
00670     case TCPS_FIN_WAIT_2:
00671         /*
00672          * FIN received.
00673          */
00674         if (state != TCPS_TIME_WAIT)
00675             rc = -1;
00676         sock->so_tx_flags |= SO_ACK | SO_FORCE;
00677         txf = 1;
00678         break;
00679 
00680     case TCPS_CLOSE_WAIT:
00681         /*
00682          * Closed by application.
00683          */
00684         if (state == TCPS_LAST_ACK) {
00685             sock->so_tx_flags |= SO_FIN | SO_ACK;
00686             txf = 1;
00687         } else
00688             rc = -1;
00689         break;
00690 
00691     case TCPS_CLOSING:
00692         /*
00693          * ACK of FIN received.
00694          */
00695         if (state != TCPS_TIME_WAIT)
00696             rc = -1;
00697         break;
00698 
00699     case TCPS_LAST_ACK:
00700         rc = -1;
00701         break;
00702 
00703     case TCPS_TIME_WAIT:
00704         rc = -1;
00705         break;
00706 
00707     case TCPS_CLOSED:
00708         switch (state) {
00709         case TCPS_LISTEN:
00710             /*
00711              * Passive open by application.
00712              */
00713             break;
00714         case TCPS_SYN_SENT:
00715             /*
00716              * Active open by application.
00717              */
00718             sock->so_tx_flags |= SO_SYN;
00719             txf = 1;
00720             break;
00721         default:
00722             rc = -1;
00723             break;
00724         }
00725         break;
00726     }
00727 #ifdef NUTDEBUG
00728     if (__tcp_trf) {
00729         fprintf(__tcp_trs, " %04x-", (u_int) sock);
00730         if (rc)
00731             NutDumpSockState(__tcp_trs, sock->so_state, "**ERR ", "**>");
00732         NutDumpSockState(__tcp_trs, state, "[>", "]");
00733     }
00734 #endif
00735 
00736     if (rc == 0) {
00737         sock->so_state = state;
00738         if (txf && NutTcpOutput(sock, 0, 0)) {
00739             if (state == TCPS_SYN_SENT) {
00740                 rc = -1;
00741                 sock->so_last_error = EHOSTDOWN;
00742                 NutEventPostAsync(&sock->so_ac_tq);
00743             }
00744         }
00745         if (state == TCPS_CLOSE_WAIT) {
00746             /*
00747              * Inform application.
00748              */
00749             NutEventBroadcast(&sock->so_rx_tq);
00750             NutEventBroadcast(&sock->so_pc_tq);
00751             NutEventBroadcast(&sock->so_ac_tq);
00752         }
00753     }
00754     return rc;
00755 }
00756 
00757 /* ================================================================
00758  * Application events.
00759  * ================================================================
00760  */
00769 int NutTcpStatePassiveOpenEvent(TCPSOCKET * sock)
00770 {
00771     if (sock->so_state != TCPS_CLOSED)
00772         return (sock->so_last_error = EISCONN);
00773 
00774     NutTcpStateChange(sock, TCPS_LISTEN);
00775 
00776     /*
00777      * Block application.
00778      */
00779     NutEventWait(&sock->so_pc_tq, 0);
00780 
00781     return 0;
00782 }
00783 
00794 int NutTcpStateActiveOpenEvent(TCPSOCKET * sock)
00795 {
00796     /*
00797      * Switch state to SYN_SENT. This will
00798      * transmit a SYN packet.
00799      */
00800     NutTcpStateChange(sock, TCPS_SYN_SENT);
00801 
00802     /*
00803      * Block application.
00804      */
00805      if(sock->so_state == TCPS_SYN_SENT)
00806         NutEventWait(&sock->so_ac_tq, 0);
00807 
00808     if (sock->so_state != TCPS_ESTABLISHED)
00809         return -1;
00810 
00811     return 0;
00812 }
00813 
00826 int NutTcpStateCloseEvent(TCPSOCKET * sock)
00827 {
00828     if (sock == 0)
00829         return -1;
00830 
00831     NutThreadYield();
00832 
00833     switch (sock->so_state) {
00834     case TCPS_LISTEN:
00835     case TCPS_SYN_SENT:
00836     case TCPS_CLOSED:
00837         /*
00838          * No connection yet, immediately destroy the socket.
00839          */
00840         NutTcpDestroySocket(sock);
00841         break;
00842 
00843     case TCPS_SYN_RECEIVED:
00844     case TCPS_ESTABLISHED:
00845         /*
00846          * Send a FIN and wait for ACK or FIN.
00847          */
00848         //@@@printf ("[%04X]ESTABLISHED: going to FIN_WAIT_1\n", (u_short) sock);
00849         NutTcpStateChange(sock, TCPS_FIN_WAIT_1);
00850         break;
00851 
00852     case TCPS_CLOSE_WAIT:
00853         /* 
00854          * RFC 793 is wrong. 
00855          */
00856         //@@@printf("[%04X]CLOSE_WAIT: going to LAST_ACK\n", (u_short) sock);
00857         NutTcpStateChange(sock, TCPS_LAST_ACK);
00858         break;
00859 
00860     case TCPS_FIN_WAIT_1:
00861     case TCPS_FIN_WAIT_2:
00862     case TCPS_CLOSING:
00863     case TCPS_LAST_ACK:
00864     case TCPS_TIME_WAIT:
00865         sock->so_last_error = EALREADY;
00866         return -1;
00867 
00868     default:
00869         sock->so_last_error = ENOTCONN;
00870         return -1;
00871     }
00872     return 0;
00873 }
00874 
00881 int NutTcpStateWindowEvent(TCPSOCKET * sock)
00882 {
00883     if (sock == 0)
00884         return -1;
00885     sock->so_tx_flags |= SO_ACK | SO_FORCE;
00886     NutTcpOutput(sock, 0, 0);
00887 
00888     return 0;
00889 }
00890 
00891 /* ================================================================
00892  * Timeout events.
00893  * ================================================================
00894  */
00906 int NutTcpStateRetranTimeout(TCPSOCKET * sock)
00907 {
00908     NETBUF *so_tx_next;
00909     if (sock->so_retransmits++ > 7)
00910     {
00911         /* Abort the socket */
00912         NutTcpAbortSocket(sock, ETIMEDOUT);
00913         return -1;
00914     } else {
00915 #ifdef NUTDEBUG
00916         if (__tcp_trf)
00917             NutDumpTcpHeader(__tcp_trs, "RET", sock, sock->so_tx_nbq);
00918 #endif
00919         /* We must save sock->so_tx_nbq->nb_next before calling NutIpOutput,
00920          * because in case of error the NETBUF is release by NutIpOutput and
00921          * not longer available.
00922          */
00923         so_tx_next = sock->so_tx_nbq->nb_next;
00924         if (NutIpOutput(IPPROTO_TCP, sock->so_remote_addr, sock->so_tx_nbq)) {
00925             /* Adjust packet queue */
00926             sock->so_tx_nbq = so_tx_next;
00927             /* Abort the socket */
00928             NutTcpAbortSocket(sock, ENETDOWN);
00929             return -1;
00930         } else {
00931             /* Restart the retransmission timer. */
00932             sock->so_retran_time = (u_short) NutGetMillis();
00933             return 0;
00934         }
00935     }
00936 }
00937 
00938 /* ================================================================
00939  * Segment arrival events.
00940  * ================================================================
00941  */
00942 
00952 static void NutTcpStateListen(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
00953 {
00954     /*
00955      * Got a SYN segment. Store relevant data in our socket
00956      * structure and switch to TCPS_SYN_RECEIVED.
00957      */
00958     if ((flags & (TH_SYN | TH_ACK | TH_RST)) == TH_SYN) {
00959         NutTcpProcessSyn(sock, nb->nb_nw.vp, th);
00960         NutTcpStateChange(sock, TCPS_SYN_RECEIVED);
00961         NutNetBufFree(nb);
00962     } else
00963         NutTcpReject(nb);
00964 }
00965 
00966 
00975 static void NutTcpStateSynSent(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
00976 {
00977     /*
00978      * Validate ACK, if set.
00979      */
00980     if (flags & TH_ACK) {
00981         if (!IsInLimits(ntohl(th->th_ack), sock->so_tx_isn + 1, sock->so_tx_nxt)) {
00982             NutTcpReject(nb);
00983             return;
00984         }
00985     }
00986 
00987     /*
00988      * Handle RST flag. If we were in the LISTEN state,
00989      * then we return to the LISTEN state, otherwise we
00990      * abort the connection and go to the CLOSED state.
00991      */
00992     if (flags & TH_RST) {
00993         if (flags & TH_ACK) {
00994             /*if (sock->so_pc_tq)
00995                 NutTcpStateChange(sock, TCPS_LISTEN);
00996             else */
00997                 NutTcpAbortSocket(sock, ECONNREFUSED);
00998         }
00999         NutNetBufFree(nb);
01000         return;
01001     }
01002 
01003     /*
01004      * Handle SYN flag. If we got a valid ACK too, then
01005      * our connection is established. Otherwise enter
01006      * SYNRCVD state.
01007      */
01008     if (flags & TH_SYN) {
01009         NutTcpProcessSyn(sock, nb->nb_nw.vp, th);
01010         if (flags & TH_ACK) {
01011             NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01012             NutTcpStateChange(sock, TCPS_ESTABLISHED);
01013             /* Wake up the actively connecting thread. */
01014             NutEventPost(&sock->so_ac_tq);
01015         } else {
01016             NutTcpStateChange(sock, TCPS_SYN_RECEIVED);
01017         }
01018     }
01019     NutNetBufFree(nb);
01020 }
01021 
01022 /*
01023  * \brief
01024  * Process incoming segments in SYN-RECEIVED state.
01025  *
01026  * Waiting for a confirming connection request
01027  * acknowledgment after having both received
01028  * and sent a connection request.
01029  *
01030  * \param sock Socket descriptor.
01031  * \param nb   Network buffer structure containing a TCP segment.
01032  */
01033 static void NutTcpStateSynReceived(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
01034 {
01035     /*
01036      * If our previous ack receives a reset response,
01037      * then we fall back to the listening state.
01038      */
01039     if (flags & TH_RST) {
01040         if (sock->so_pc_tq)
01041             NutTcpStateChange(sock, TCPS_LISTEN);
01042         else 
01043             NutTcpAbortSocket(sock, ECONNREFUSED);
01044         NutNetBufFree(nb);
01045         sock->so_retran_time = 0;
01046         NutTcpDiscardBuffers(sock);
01047         return;
01048     }
01049 
01050     /*
01051      * Reject SYNs.
01052      */
01053     if (flags & TH_SYN) {
01054         NutTcpReject(nb);
01055         return;
01056     }
01057 
01058     /*
01059      * Silently discard segments without ACK.
01060      */
01061     if ((flags & TH_ACK) == 0) {
01062         NutNetBufFree(nb);
01063         return;
01064     }
01065 
01066     /*
01067      * Reject out of window sequence.
01068      */
01069     if (!IsInLimits(ntohl(th->th_ack), sock->so_tx_una + 1, sock->so_tx_nxt)) {
01070         NutTcpReject(nb);
01071         return;
01072     }
01073 
01074     /* Acknowledge processing. */
01075     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01076 
01077     /*
01078      * Even SYN segments may contain application data, which will be stored
01079      * in the socket's input buffer. However, there is no need to post an
01080      * event to any thread waiting for data, because our connection is not 
01081      * yet established.
01082      */
01083     if (nb->nb_ap.sz)
01084         NutTcpProcessAppData(sock, nb);
01085     else
01086         NutNetBufFree(nb);
01087 
01088     /*
01089      * Process state change.
01090      */
01091     if (flags & TH_FIN) {
01092         sock->so_rx_nxt++;
01093         NutTcpStateChange(sock, TCPS_CLOSE_WAIT);
01094     } else {
01095         NutTcpStateChange(sock, TCPS_ESTABLISHED);
01096         NutEventPost(&sock->so_pc_tq);
01097         NutEventPost(&sock->so_ac_tq);
01098     }
01099 }
01100 
01101 /*
01102  * \brief Process incoming segments from established connections.
01103  *
01104  * Received application data will be delivered to the application
01105  * until we receive a FIN segment.
01106  *
01107  * \param sock  Socket descriptor.
01108  * \param flags TCP flags.
01109  * \param th    Pointer to the TCP header within the NETBUF.
01110  * \param nb    Network buffer structure containing a TCP segment.
01111  *
01112  * \todo We may remove the unused counter of dropped segments, which
01113  *       were out of sequence.
01114  */
01115 static void NutTcpStateEstablished(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
01116 {
01117     if (flags & TH_RST) {
01118         NutNetBufFree(nb);
01119         NutTcpAbortSocket(sock, ECONNRESET);
01120         return;
01121     }
01122 
01123     /*
01124      * Reject SYNs. Silently discard late SYNs
01125      * (Thanks to Mike Cornelius).
01126      */
01127     if (flags & TH_SYN) {
01128         if (htonl(th->th_seq) != sock->so_rx_isn)
01129             NutTcpReject(nb);
01130         else
01131             NutNetBufFree(nb);
01132         return;
01133     }
01134 
01135     /*
01136      * Silently discard segments without ACK.
01137      */
01138     if ((flags & TH_ACK) == 0) {
01139         NutNetBufFree(nb);
01140         return;
01141     }
01142 
01143     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01144 
01145     /*
01146      * If the sequence number of the incoming segment is larger than 
01147      * expected, we probably missed one or more previous segments. Let's 
01148      * add this one to a linked list of segments received in advance and 
01149      * hope that the missing data will arrive later.
01150      */
01151     if (htonl(th->th_seq) > sock->so_rx_nxt) {
01152         NETBUF *nbq;
01153         NETBUF **nbqp;
01154         TCPHDR *thq;
01155         u_long th_seq;
01156         u_long thq_seq;
01157 
01158         if (nb->nb_ap.sz) {
01159             nbq = sock->so_rx_nbq;
01160             nbqp = &sock->so_rx_nbq;
01161             while (nbq) {
01162                 thq = (TCPHDR *) (nbq->nb_tp.vp);
01163                 th_seq = htonl(th->th_seq);
01164                 thq_seq = htonl(thq->th_seq);
01165                 if (th_seq < thq_seq) {
01166                     *nbqp = nb;
01167                     nb->nb_next = nbq;
01168                     break;
01169                 }
01170                 if (th_seq == thq_seq) {
01171                     NutNetBufFree(nb);
01172                     sock->so_tx_flags |= SO_ACK | SO_FORCE;
01173                     NutTcpOutput(sock, 0, 0);
01174                     return;
01175                 }
01176                 nbqp = &nbq->nb_next;
01177                 nbq = nbq->nb_next;
01178             }
01179             if (nbq == 0) {
01180                 *nbqp = nb;
01181                 nb->nb_next = 0;
01182             }
01183         } else
01184             NutNetBufFree(nb);
01185 
01186         sock->so_tx_flags |= SO_ACK | SO_FORCE;
01187         NutTcpOutput(sock, 0, 0);
01188         return;
01189     }
01190 
01191     /*
01192      * Acknowledge any sequence numbers not expected, 
01193      * even if they do not contain any data. Keepalive
01194      * packets contain a sequence number one less
01195      * than the next data expected and they do not 
01196      * contain any data.
01197      */
01198     if (htonl(th->th_seq) != sock->so_rx_nxt) {
01199         sock->so_tx_flags |= SO_ACK | SO_FORCE;
01200         /* This seems to be unused. */
01201         sock->so_oos_drop++;
01202         NutNetBufFree(nb);
01203         NutTcpOutput(sock, 0, 0);
01204     } 
01205 
01206     /*
01207      * The sequence number is exactly what we expected.
01208      */
01209     else if (nb->nb_ap.sz) {
01210         NutTcpProcessAppData(sock, nb);
01211         /*
01212          * Process segments we may have received in advance.
01213          */
01214         while ((nb = sock->so_rx_nbq) != 0) {
01215             th = (TCPHDR *) (nb->nb_tp.vp);
01216             if (htonl(th->th_seq) > sock->so_rx_nxt)
01217                 break;
01218             sock->so_rx_nbq = nb->nb_next;
01219             if (htonl(th->th_seq) == sock->so_rx_nxt) {
01220                 NutTcpProcessAppData(sock, nb);
01221                 flags |= th->th_flags;
01222             } else
01223                 NutNetBufFree(nb);
01224         }
01225         /* Wake up a thread waiting for data. */
01226         NutEventPost(&sock->so_rx_tq);
01227     } else {
01228         NutNetBufFree(nb);
01229         //sock->so_tx_flags |= SO_ACK | SO_FORCE;
01230         //NutTcpOutput(sock, 0, 0);
01231     }
01232     if (flags & TH_FIN) {
01233         //@@@printf ("[%04X]ESTABLISHED: going to CLOSE_WAIT\n", (u_short) sock);
01234         sock->so_rx_nxt++;
01235         NutTcpStateChange(sock, TCPS_CLOSE_WAIT);
01236     }
01237 }
01238 
01239 /*
01240  * \brief Process incoming segments in FIN-WAIT1 state.
01241  *
01242  * Waiting for a connection termination request
01243  * from the remote, or an acknowledgment of the
01244  * connection termination request previously sent.
01245  *
01246  * The application already closed the socket.
01247  *
01248  * \param sock Socket descriptor.
01249  * \param nb   Network buffer structure containing a TCP segment.
01250  *
01251  * \todo The out of sync case seems to be ignored. Anyway, do we
01252  *       really need to process application data in this state?
01253  */
01254 static void NutTcpStateFinWait1(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
01255 {
01256     //@@@printf ("[%04X]FIN_WAIT_1: incomming segment, IP %04X\n", (u_short) sock, ntohs(((IPHDR*)nb->nb_nw.vp)->ip_id));
01257     if (flags & TH_RST) {
01258         NutNetBufFree(nb);
01259         NutTcpDestroySocket(sock);
01260         return;
01261     }
01262 
01263     /*
01264      * Reject SYNs.
01265      */
01266     if (flags & TH_SYN) {
01267         NutTcpReject(nb);
01268         return;
01269     }
01270 
01271     /*
01272      * Silently discard segments without ACK.
01273      */
01274     if ((flags & TH_ACK) == 0) {
01275         NutNetBufFree(nb);
01276         return;
01277     }
01278 
01279     //@@@if (flags & TH_FIN) printf ("[%04X]FIN_WAIT_1: received FIN\n", (u_short) sock);
01280     //@@@printf ("[%04X]FIN_WAIT_1: received ACK: %lu, unack: %lu, next: %lu\n", (u_short) sock, ntohl(th->th_ack), sock->so_tx_una, sock->so_tx_nxt);
01281     
01282     //@@@printf ("[%04X]FIN_WAIT_1:  pre processack, nbq: %04X\n", (u_short) sock, (u_short) sock->so_tx_nbq);
01283     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01284     //@@@printf ("[%04X]FIN_WAIT_1: post processack, nbq: %04X\n", (u_short) sock, (u_short) sock->so_tx_nbq);
01285 
01286     /*
01287      * All segments had been acknowledged, including our FIN.
01288      */
01289     if (sock->so_tx_nxt == sock->so_tx_una) {
01290         //@@@printf ("[%04X]FIN_WAIT_1: going to FIN_WAIT_2\n", (u_short) sock);
01291         NutTcpStateChange(sock, TCPS_FIN_WAIT_2);
01292     }
01293 
01294     /*
01295      * Process application data and release the network buffer.
01296      * Is this really required?
01297      */
01298     if (nb->nb_ap.sz) {
01299         NutTcpProcessAppData(sock, nb);
01300         /* Wake up a thread waiting for data. */
01301         NutEventPost(&sock->so_rx_tq);
01302     }
01303     else
01304         NutNetBufFree(nb);
01305 
01306     if (flags & TH_FIN) {
01307         sock->so_rx_nxt++;
01308         /* 
01309          * Our FIN has been acked.
01310          */
01311         sock->so_time_wait = 0;
01312         //@@@printf ("[%04X]FIN_WAIT_1: going to CLOSING\n", (u_short) sock);
01313         if (sock->so_state == TCPS_FIN_WAIT_2)
01314             NutTcpStateChange(sock, TCPS_TIME_WAIT);
01315         else
01316             NutTcpStateChange(sock, TCPS_CLOSING);
01317     }
01318 }
01319 
01320 /*
01321  * \brief Process incoming segments in FIN-WAIT2 state.
01322  *
01323  * Waiting for a connection termination request
01324  * from the remote.
01325  *
01326  * The application already closed the socket.
01327  *
01328  * \param sock Socket descriptor.
01329  * \param nb   Network buffer structure containing a TCP segment.
01330  *
01331  * \todo There's probably no need to process application data.
01332  */
01333 static void NutTcpStateFinWait2(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
01334 {
01335     //@@@printf ("[%04X]FIN_WAIT_2: incomming segment, IP %04X\n", (u_short) sock, ntohs(((IPHDR*)nb->nb_nw.vp)->ip_id));
01336     if (flags & TH_RST) {
01337         NutNetBufFree(nb);
01338         NutTcpDestroySocket(sock);
01339         return;
01340     }
01341 
01342     /*
01343      * Reject SYNs.
01344      */
01345     if (flags & TH_SYN) {
01346         NutTcpReject(nb);
01347         return;
01348     }
01349 
01350     /*
01351      * Silently discard segments without ACK.
01352      */
01353     if ((flags & TH_ACK) == 0) {
01354         NutNetBufFree(nb);
01355         return;
01356     }
01357 
01358     //@@@printf ("[%04X]FIN_WAIT_2: received ACK: %lu, unack: %lu, next: %lu\n", (u_short) sock, ntohl(th->th_ack), sock->so_tx_una, sock->so_tx_nxt);
01359     /*
01360      * Process acknowledge and application data and release the 
01361      * network buffer.
01362      */
01363     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01364 
01365     //@@@if (sock->so_tx_nbq) printf ("[%04X]FIN_WAIT_2: xmit buffer not empty!", (u_short) sock);
01366     /* Do we really need this? */
01367     if (nb->nb_ap.sz) {
01368         NutTcpProcessAppData(sock, nb);
01369         /* Wake up a thread waiting for data. */
01370         NutEventPost(&sock->so_rx_tq);
01371     }
01372     else
01373         NutNetBufFree(nb);
01374 
01375     if (flags & TH_FIN) {
01376         sock->so_rx_nxt++;
01377         sock->so_time_wait = 0;
01378         //@@@printf ("[%04X]FIN_WAIT_2: going to TIME_WAIT\n", (u_short) sock);
01379         NutTcpStateChange(sock, TCPS_TIME_WAIT);
01380     }
01381 }
01382 
01383 /*
01384  * \brief
01385  * Process incoming segments in CLOSE-WAIT state.
01386  *
01387  * Waiting for a connection termination request
01388  * from the local application.
01389  *
01390  * \param sock Socket descriptor.
01391  * \param nb   Network buffer structure containing a TCP segment.
01392  */
01393 static void NutTcpStateCloseWait(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
01394 {
01395     //@@@printf ("[%04X]CLOSE_WAIT: incomming segment, IP %04X\n", (u_short) sock, ((IPHDR*)nb->nb_nw.vp)->ip_id);
01396     if (flags & TH_RST) {
01397         NutNetBufFree(nb);
01398         NutTcpAbortSocket(sock, ECONNRESET);
01399         return;
01400     }
01401 
01402     /*
01403      * Reject SYNs.
01404      */
01405     if (flags & TH_SYN) {
01406         NutTcpReject(nb);
01407         return;
01408     }
01409 
01410     /*
01411      * Silently discard segments without ACK.
01412      */
01413     if ((flags & TH_ACK) == 0) {
01414         NutNetBufFree(nb);
01415         return;
01416     }
01417 
01418     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01419 
01420     NutNetBufFree(nb);
01421 }
01422 
01423 /*
01424  * \brief
01425  * Process incoming segments in CLOSING state.
01426  *
01427  * Waiting for a connection termination request
01428  * acknowledgment from the remote.
01429  *
01430  * The application already closed the socket.
01431  *
01432  * \param sock Socket descriptor.
01433  * \param nb   Network buffer structure containing a TCP segment.
01434  */
01435 static void NutTcpStateClosing(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
01436 {
01437     //@@@printf ("[%04X]CLOSING: Incomming segment\n", (u_short) sock);
01438     if (flags & TH_RST) {
01439         NutNetBufFree(nb);
01440         NutTcpDestroySocket(sock);
01441         return;
01442     }
01443 
01444     /*
01445      * Reject SYNs.
01446      */
01447     if (flags & TH_SYN) {
01448         NutTcpReject(nb);
01449         return;
01450     }
01451 
01452     /*
01453      * Silently discard segments without ACK.
01454      */
01455     if ((flags & TH_ACK) == 0) {
01456         NutNetBufFree(nb);
01457         return;
01458     }
01459 
01460     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01461 
01462     /*
01463      * All segments had been acknowledged, including our FIN.
01464      */
01465     if (sock->so_tx_nxt == sock->so_tx_una) {
01466         sock->so_time_wait = 0;
01467         NutTcpStateChange(sock, TCPS_TIME_WAIT);
01468         //@@@printf ("[%04X]CLOSING: Going to TIME_WAIT\n", (u_short) sock);
01469     }
01470     //@@@else printf ("[%04X]CLOSING: NOT changing state\n", (u_short) sock);
01471 
01472     NutNetBufFree(nb);
01473 }
01474 
01489 static void NutTcpStateLastAck(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
01490 {
01491     //@@@printf ("[%04X]LAST_ACK: incomming segment, IP %04X\n", (u_short) sock, ((IPHDR*)nb->nb_nw.vp)->ip_id);
01492     if (flags & TH_RST) {
01493         NutNetBufFree(nb);
01494         NutTcpDestroySocket(sock);
01495         return;
01496     }
01497 
01498     /*
01499      * Reject SYNs.
01500      */
01501     if (flags & TH_SYN) {
01502         NutTcpReject(nb);
01503         return;
01504     }
01505 
01506     /*
01507      * Silently discard segments without ACK.
01508      */
01509     if ((flags & TH_ACK) == 0) {
01510         NutNetBufFree(nb);
01511         return;
01512     }
01513 
01514     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01515     NutNetBufFree(nb);
01516 
01517     if (sock->so_tx_nxt == sock->so_tx_una) 
01518         NutTcpDestroySocket(sock);
01519     //@@@else printf ("[%04X]LAST_ACK: no destroy sock\n", (u_short) sock);
01520 }
01521 
01532 static void NutTcpStateProcess(TCPSOCKET * sock, NETBUF * nb)
01533 {
01534     u_long tx_win;
01535     u_long tx_una;
01536     TCPHDR *th = (TCPHDR *) nb->nb_tp.vp;
01537     u_char flags = th->th_flags;
01538 
01539 #ifdef NUTDEBUG
01540     if (__tcp_trf) {
01541         fprintf(__tcp_trs, " %04x-", (u_int) sock);
01542         NutDumpSockState(__tcp_trs, sock->so_state, "[", ">]");
01543     }
01544 #endif
01545     switch (sock->so_state) {
01546         /* Handle the most common case first. */
01547     case TCPS_ESTABLISHED:
01548         tx_win = sock->so_tx_win;
01549         tx_una = sock->so_tx_una;
01550         NutTcpStateEstablished(sock, flags, th, nb);
01551         /* Wake up all threads waiting for transmit, if something interesting happened. */
01552         if(sock->so_state != TCPS_ESTABLISHED || /* Status changed. */
01553            sock->so_tx_win > tx_win ||           /* Windows changed. */
01554            sock->so_tx_una > tx_una) {           /* Unacknowledged data changed. */
01555             NutEventBroadcast(&sock->so_tx_tq);
01556         }
01557         break;
01558     case TCPS_LISTEN:
01559         NutTcpStateListen(sock, flags, th, nb);
01560         break;
01561     case TCPS_SYN_SENT:
01562         NutTcpStateSynSent(sock, flags, th, nb);
01563         break;
01564     case TCPS_SYN_RECEIVED:
01565         NutTcpStateSynReceived(sock, flags, th, nb);
01566         break;
01567     case TCPS_FIN_WAIT_1:
01568         NutTcpStateFinWait1(sock, flags, th, nb);
01569         break;
01570     case TCPS_FIN_WAIT_2:
01571         NutTcpStateFinWait2(sock, flags, th, nb);
01572         break;
01573     case TCPS_CLOSE_WAIT:
01574         NutTcpStateCloseWait(sock, flags, th, nb);
01575         break;
01576     case TCPS_CLOSING:
01577         NutTcpStateClosing(sock, flags, th, nb);
01578         break;
01579     case TCPS_LAST_ACK:
01580         NutTcpStateLastAck(sock, flags, th, nb);
01581         break;
01582     case TCPS_TIME_WAIT:
01583         /*
01584          * Ignore everything while in TIME_WAIT state.
01585          */
01586         NutNetBufFree(nb);
01587         break;
01588     case TCPS_CLOSED:
01589         /*
01590          * Reject everything while in CLOSED state.
01591          */
01592         NutTcpReject(nb);
01593         break;
01594     default:
01595         NutNetBufFree(nb);
01596         break;
01597     }
01598 }
01599 
01606 THREAD(NutTcpSm, arg)
01607 {
01608     NETBUF *nb;
01609     NETBUF *nbx;
01610     TCPHDR *th;
01611     IPHDR *ih;
01612     TCPSOCKET *sock;
01613     u_char tac = 0;
01614 
01615     /*
01616      * It won't help giving us a higher priority than the application
01617      * code. We depend on the speed of the reading application.
01618      */
01619     NutThreadSetPriority (32);
01620     
01621     for (;;) {
01622         if (++tac > 3 || NutEventWait(&tcp_in_rdy, 200)) {
01623             tac = 0;
01624             for (sock = tcpSocketList; sock; sock = sock->so_next) {
01625 
01626                 /*
01627                  * Send late acks.
01628                  */
01629                 if (sock->so_tx_flags & SO_ACK) {
01630                     sock->so_tx_flags |= SO_FORCE;
01631                     NutTcpOutput(sock, 0, 0);
01632                 }
01633 
01634                 /*
01635                  * Process retransmit timer.
01636                  */
01637                 if (sock->so_tx_nbq && sock->so_retran_time) {
01638                     if ((u_short)((u_short)NutGetMillis() - sock->so_retran_time) > sock->so_rtto) {
01639                         NutTcpStateRetranTimeout(sock);
01640                     }
01641                 }
01642 
01643                 /*
01644                  * Destroy sockets after timeout in TIMEWAIT state.
01645                  */
01646                 if (sock->so_state == TCPS_TIME_WAIT || sock->so_state == TCPS_FIN_WAIT_2) {
01647                     if (sock->so_time_wait++ >= 9) {
01648                         NutTcpDestroySocket(sock);
01649                         break;
01650                     }
01651                 }
01652 
01653                 /*
01654                  * Recover from SYN flood attacks.
01655                  */
01656                 else if (sock->so_state == TCPS_SYN_RECEIVED) {
01657                     if (sock->so_time_wait++ >= 45) {
01658                         sock->so_state = TCPS_LISTEN;
01659                         sock->so_time_wait = 0;
01660                     }
01661                 }
01662             }
01663         } else {
01664             nb = tcp_in_nbq;
01665             tcp_in_nbq = 0;
01666             tcp_in_cnt = 0;
01667             while (nb) {
01668                 ih = (IPHDR *) nb->nb_nw.vp;
01669                 th = (TCPHDR *) nb->nb_tp.vp;
01670                 sock = NutTcpFindSocket(th->th_dport, th->th_sport, ih->ip_src);
01671 #ifdef NUTDEBUG
01672                 if (__tcp_trf)
01673                     NutDumpTcpHeader(__tcp_trs, " IN", sock, nb);
01674 #endif
01675                 nbx = nb->nb_next;
01676                 if (sock) {
01677                     NutTcpInputOptions(sock, nb);
01678                     NutTcpStateProcess(sock, nb);
01679                 }
01680 
01681                 /*
01682                  * Reject the segment, if no matching socket was found.
01683                  */
01684                 else
01685                     NutTcpReject(nb);
01686                 nb = nbx;
01687             }
01688         }
01689     }
01690 }
01691 
01703 void NutTcpStateMachine(NETBUF * nb)
01704 {
01705     NETBUF *nbp;
01706     u_short size;
01707 
01708     nb->nb_next = 0;
01709 
01710     /*
01711      * Incoming TCP segments are rejected and released if no TCP
01712      * sockets have been opened. Not doing so would add them
01713      * to the queue and never release the NETBUF. Thanks to
01714      * Ralph Mason for this fix.
01715      */
01716     if (tcpThread == 0) {
01717         NutTcpReject(nb);
01718         return;
01719     }
01720 
01721     if ((nbp = tcp_in_nbq) == 0) {
01722         tcp_in_nbq = nb;
01723         NutEventPost(&tcp_in_rdy);
01724     } else {
01725         size = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz;
01726         if (tcp_in_cnt + size + 2048 < NutHeapAvailable()) {
01727             tcp_in_cnt += size;
01728             while (nbp->nb_next)
01729                 nbp = nbp->nb_next;
01730             nbp->nb_next = nb;
01731             NutEventPost(&tcp_in_rdy);
01732         } else
01733             NutNetBufFree(nb);
01734     }
01735 }
01736 
01745 int NutTcpInitStateMachine(void)
01746 {
01747     if (tcpThread == 0 && (tcpThread = NutThreadCreate("tcpsm", NutTcpSm, NULL, NUT_THREAD_TCPSMSTACK)) == 0)
01748         return -1;
01749     return 0;
01750 }
01751 
01765 int NutTcpAbortSocket(TCPSOCKET * sock, u_short last_error)
01766 {
01767     sock->so_last_error = last_error;
01768     sock->so_retran_time = 0;
01769     sock->so_time_wait = 0;
01770     /*
01771      * If NutTcpCloseSocket was already called, we have to change
01772      * to TCPS_TIME_WAIT state, otherwise the socket will not be destroyed.
01773      * For the other cases just go to TCPS_CLOSED.
01774      */
01775     if (sock->so_state >= TCPS_FIN_WAIT_1)      /* FIN_WAIT_1, FIN_WAIT_2, CLOSING, LAST_ACK, TIME_WAIT */
01776         sock->so_state = TCPS_TIME_WAIT;
01777     else
01778         sock->so_state = TCPS_CLOSED;
01779     NutTcpDiscardBuffers(sock);
01780     NutEventBroadcast(&sock->so_rx_tq);
01781     NutEventBroadcast(&sock->so_tx_tq);
01782     NutEventBroadcast(&sock->so_pc_tq);
01783     NutEventBroadcast(&sock->so_ac_tq);
01784     return 0;
01785 }
01786 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/