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.25  2008/07/27 11:43:22  haraldkipp
00097  * Configurable TCP retransmissions.
00098  *
00099  * Revision 1.24  2008/04/06 13:29:01  haraldkipp
00100  * In unreliable or high traffic networks connections may suddenly freeze.
00101  * The problem is, that during overflows (happening every 65s) the
00102  * retransmission timer may be loaded with 0, which in turn disables all
00103  * outstanding retransmission. Applied fix contributed by Henrik Maier.
00104  *
00105  * Revision 1.23  2007/02/15 15:59:59  haraldkipp
00106  * Serious bug in the TCP state machine froze socket connection on 32-bit
00107  * platforms.
00108  *
00109  * Revision 1.22  2006/10/05 17:25:41  haraldkipp
00110  * Avoid possible alignment errors. Fixes bug #1567748.
00111  *
00112  * Revision 1.21  2006/05/15 12:49:12  haraldkipp
00113  * ICCAVR doesn't accept void pointer calculation.
00114  *
00115  * Revision 1.20  2006/03/21 21:22:19  drsung
00116  * Enhancement made to TCP state machine. Now TCP options
00117  * are read from peer and at least the maximum segment size is stored.
00118  *
00119  * Revision 1.19  2005/04/30 16:42:42  chaac
00120  * Fixed bug in handling of NUTDEBUG. Added include for cfg/os.h. If NUTDEBUG
00121  * is defined in NutConf, it will make effect where it is used.
00122  *
00123  * Revision 1.18  2005/04/05 17:44:57  haraldkipp
00124  * Made stack space configurable.
00125  *
00126  * Revision 1.17  2005/03/30 15:17:58  mrjones4u
00127  * 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.
00128  *
00129  * Revision 1.16  2005/02/04 17:17:49  haraldkipp
00130  * Unused include files removed.
00131  *
00132  * Revision 1.15  2005/01/21 16:49:46  freckle
00133  * Seperated calls to NutEventPostAsync between Threads and IRQs
00134  *
00135  * Revision 1.14  2005/01/03 08:43:29  haraldkipp
00136  * Replaced unprotected calls to NutEventPostAsync() by late calls to NutEventPost().
00137  * This should fix the infrequent system halts/resets. The event to the transmitter
00138  * waiting queue will be broadcasted on relevant state changes.
00139  *
00140  * Revision 1.13  2004/07/30 19:54:46  drsung
00141  * Some code of TCP stack redesigned. Round trip time calculation is now
00142  * supported. Fixed several bugs in TCP state machine. Now TCP connections
00143  * should be more reliable under heavy traffic or poor physical connections.
00144  *
00145  * Revision 1.12  2004/04/15 11:08:21  haraldkipp
00146  * Bugfix: Sequence number had not been incremented on FIN segments.
00147  * Added Realtek hack to reduce concurrent connection problems.
00148  * Rely on TCP output to set the retransmission timer.
00149  *
00150  * Revision 1.11  2004/02/28 20:14:38  drsung
00151  * Merge from nut-3_4-release b/c of bugfixes.
00152  *
00153  * Revision 1.9.2.1  2004/02/28 20:02:23  drsung
00154  * Bugfix in several tcp state functions. Swapped around the check
00155  * for ACK and SYN flag. Because initial SYN packets don't have
00156  * an ACK flag, recevied SYN packets were never rejected.
00157  * Thanks to Damian Slee, who discovered that.
00158  *
00159  * Revision 1.9  2004/01/25 11:50:03  drsung
00160  * setting correct error code on timeout while NutTcpConnect.
00161  *
00162  * Revision 1.8  2004/01/25 11:29:48  drsung
00163  * bugfix for connection establishing.
00164  *
00165  * Revision 1.7  2004/01/14 19:35:19  drsung
00166  * New TCP output buffer handling and fixed not starting retransmission timer for NutTcpConnect.
00167  *
00168  * Revision 1.6  2003/11/28 19:49:58  haraldkipp
00169  * TCP connections suddenly drop during transmission.
00170  * Bug in retransmission timer fixed.
00171  *
00172  * Revision 1.5  2003/11/04 17:57:35  haraldkipp
00173  * Bugfix: Race condition left socket in close-wait state
00174  *
00175  * Revision 1.4  2003/11/03 16:48:02  haraldkipp
00176  * Use the system timer for retransmission timouts
00177  *
00178  * Revision 1.3  2003/08/14 15:10:31  haraldkipp
00179  * Two bugfixes: 1. NutTcpAccept fails if caller got higher priority.
00180  * 2. Incoming TCP NETBUFs will never be released if TCP is not used by
00181  * the application.
00182  *
00183  * Revision 1.2  2003/07/13 19:22:23  haraldkipp
00184  * TCP transfer speed increased by changing the character receive buffer
00185  * in TCPSOCKET to a NETBUF queue. (More confusing diff lines by using
00186  * indent, sorry.)
00187  *
00188  * Revision 1.1.1.1  2003/05/09 14:41:42  haraldkipp
00189  * Initial using 3.2.1
00190  *
00191  * Revision 1.20  2003/05/06 18:20:02  harald
00192  * Stack size reduced
00193  *
00194  * Revision 1.19  2003/04/01 18:36:11  harald
00195  * Added forced ACK response on same sequence
00196  *
00197  * Revision 1.18  2003/03/31 12:29:45  harald
00198  * Check NEBUF allocation
00199  *
00200  * Revision 1.17  2003/02/04 18:14:57  harald
00201  * Version 3 released
00202  *
00203  * Revision 1.16  2003/01/14 16:51:29  harald
00204  * Handle possible deadlock in the TCP state machine in low memory situations.
00205  * Fixed: TCP might fail to process incoming packets on slow connections.
00206  *
00207  * Revision 1.15  2002/09/15 17:05:41  harald
00208  * Silently ignore late SYNs.
00209  * Detect host down in local networks during connect.
00210  * Avoid re-sending packets too soon.
00211  *
00212  * Revision 1.14  2002/09/03 17:42:20  harald
00213  * Buffer sequences received in advance
00214  *
00215  * Revision 1.13  2002/08/16 17:54:56  harald
00216  * Count out of sequence drops
00217  *
00218  * Revision 1.12  2002/06/26 17:29:36  harald
00219  * First pre-release with 2.4 stack
00220  *
00221  */
00222 
00223 #include <cfg/os.h>
00224 #include <cfg/tcp.h>
00225 
00226 #include <sys/thread.h>
00227 #include <sys/heap.h>
00228 #include <sys/event.h>
00229 #include <sys/timer.h>
00230 
00231 #include <net/errno.h>
00232 #include <netinet/in.h>
00233 #include <netinet/ip.h>
00234 #include <net/route.h>
00235 #include <sys/socket.h>
00236 #include <netinet/tcputil.h>
00237 #include <netinet/tcp.h>
00238 
00239 #ifdef NUTDEBUG
00240 #include <net/netdebug.h>
00241 #endif
00242 
00243 #ifndef NUT_THREAD_TCPSMSTACK
00244 #define NUT_THREAD_TCPSMSTACK   512
00245 #endif
00246 
00247 #ifndef TCP_RETRIES_MAX
00248 #define TCP_RETRIES_MAX         7
00249 #endif
00250 
00251 extern TCPSOCKET *tcpSocketList;
00252 
00257 
00258 HANDLE tcp_in_rdy;
00259 NETBUF *volatile tcp_in_nbq;
00260 static u_short tcp_in_cnt;
00261 static HANDLE tcpThread = 0;
00262 
00263 /* ================================================================
00264  * Helper functions
00265  * ================================================================
00266  */
00267 
00276 static void NutTcpInputOptions(TCPSOCKET * sock, NETBUF * nb)
00277 {
00278     u_char *cp;
00279     u_short s;
00280     
00281     /* any options there? */
00282     if (nb->nb_tp.sz <= sizeof (TCPHDR))
00283         return;
00284     
00285     /* loop through available options */
00286     for (cp = ((u_char*) nb->nb_tp.vp) + sizeof(TCPHDR); (*cp != TCPOPT_EOL) 
00287        && (cp - (u_char *)nb->nb_tp.vp < (int)nb->nb_tp.sz); )
00288     {
00289         switch (*cp)
00290         {
00291             /* On NOP just proceed to next option */
00292             case TCPOPT_NOP:
00293                 cp++;
00294                 continue;
00295                 
00296             /* Read MAXSEG option */
00297             case TCPOPT_MAXSEG:
00298                 s = ntohs(((u_short)cp[2] << 8) | cp[3]);
00299                 if (s < sock->so_mss)
00300                     sock->so_mss = s;
00301                 cp += TCPOLEN_MAXSEG;
00302                 break;
00303             /* Ignore any other options */
00304             default:
00305                 cp += *(u_char*) (cp + 1);
00306                 break;
00307         }
00308     }
00309 }
00310 
00319 static void NutTcpProcessAppData(TCPSOCKET * sock, NETBUF * nb)
00320 {
00321     /*
00322      * Add the NETBUF to the socket's input buffer.
00323      */
00324     if (sock->so_rx_buf) {
00325         NETBUF *nbp = sock->so_rx_buf;
00326 
00327         while (nbp->nb_next)
00328             nbp = nbp->nb_next;
00329         nbp->nb_next = nb;
00330     } else
00331         sock->so_rx_buf = nb;
00332 
00333     /*
00334      * Update the number of bytes available in the socket's input buffer
00335      * and the sequence number we expect next.
00336      */
00337     sock->so_rx_cnt += nb->nb_ap.sz;
00338     sock->so_rx_nxt += nb->nb_ap.sz;
00339 
00340     /*
00341      * Reduce our TCP window size.
00342      */
00343     if (nb->nb_ap.sz >= sock->so_rx_win)
00344         sock->so_rx_win = 0;
00345     else
00346         sock->so_rx_win -= nb->nb_ap.sz;
00347 
00348     /*
00349      * Set the socket's ACK flag. This will enable ACK transmission in
00350      * the next outgoing segment. If no more NETBUFs are queued, we
00351      * force immediate transmission of the ACK.
00352      */
00353     sock->so_tx_flags |= SO_ACK;
00354     if (nb->nb_next)
00355         nb->nb_next = 0;
00356     else
00357         sock->so_tx_flags |= SO_FORCE;
00358 
00359     NutTcpOutput(sock, 0, 0);
00360 }
00361 
00362 /*
00363  * \param sock Socket descriptor.
00364  */
00365 static void NutTcpProcessSyn(TCPSOCKET * sock, IPHDR * ih, TCPHDR * th)
00366 {
00367     u_short mss;
00368     NUTDEVICE *dev;
00369     IFNET *nif;
00370 
00371     sock->so_local_addr = ih->ip_dst;
00372     sock->so_remote_port = th->th_sport;
00373     sock->so_remote_addr = ih->ip_src;
00374 
00375     sock->so_rx_nxt = sock->so_tx_wl1 = sock->so_rx_isn = ntohl(th->th_seq);
00376     sock->so_rx_nxt++;
00377     sock->so_tx_win = ntohs(th->th_win);
00378 
00379     /*
00380      * To avoid unnecessary fragmentation, limit the
00381      * maximum segment size to the maximum transfer
00382      * unit of our interface.
00383      */
00384     if ((dev = NutIpRouteQuery(ih->ip_src, 0)) != 0) {
00385         nif = dev->dev_icb;
00386         mss = nif->if_mtu - sizeof(IPHDR) - sizeof(TCPHDR);
00387         if (sock->so_mss == 0 || sock->so_mss > mss)
00388             sock->so_mss = mss;
00389 
00390         /* Limit output buffer size to mms */
00391         if (sock->so_devobsz > sock->so_mss)
00392             sock->so_devobsz = sock->so_mss;
00393     }
00394 }
00395 
00403 static int NutTcpProcessAck(TCPSOCKET * sock, TCPHDR * th, u_short length)
00404 {
00405     NETBUF *nb;
00406     u_long h_seq;
00407     u_long h_ack;
00408 
00409     /*
00410      * If remote acked something not yet send, reply immediately.
00411      */
00412     h_ack = ntohl(th->th_ack);
00413     if (h_ack > sock->so_tx_nxt) {
00414         sock->so_tx_flags |= SO_ACK | SO_FORCE;
00415         return 0;
00416     }
00417 
00418     /*
00419      * If the new sequence number or acknowledged sequence number
00420      * is above our last update, we adjust our transmit window.
00421      * Avoid dupe ACK processing on window updates.
00422      */
00423     if (h_ack == sock->so_tx_una) {
00424         h_seq = ntohl(th->th_seq);
00425         if (h_seq > sock->so_tx_wl1 || (h_seq == sock->so_tx_wl1 && h_ack >= sock->so_tx_wl2)) {
00426             sock->so_tx_win = ntohs(th->th_win);
00427             sock->so_tx_wl1 = h_seq;
00428             sock->so_tx_wl2 = h_ack;
00429         }
00430     }
00431 
00432     /*
00433      * Ignore old ACKs but wake up sleeping transmitter threads, because
00434      * the window size may have changed.
00435      */
00436     if (h_ack < sock->so_tx_una) {
00437         return 0;
00438     }
00439 
00440     /*
00441      * Process duplicate ACKs.
00442      */
00443     if (h_ack == sock->so_tx_una) {
00444         /*
00445          * Don't count, if nothing is waiting for ACK,
00446          * segment contains data or on SYN/FIN segments.
00447          */
00448         if (sock->so_tx_nbq && length == 0 && (th->th_flags & (TH_SYN | TH_FIN)) == 0) {
00449             /*
00450              * If dupe counter reaches it's limit, resend
00451              * the oldest unacknowledged netbuf.
00452              */
00453             if (++sock->so_tx_dup >= 3) {
00454                 sock->so_tx_dup = 0;
00455 #ifdef NUTDEBUG
00456                 if (__tcp_trf)
00457                     NutDumpTcpHeader(__tcp_trs, "RET", sock, sock->so_tx_nbq);
00458 #endif
00459                 /*
00460                  * Retransmit first unacked packet from queue.
00461                  * Actually we got much more trouble if this fails.
00462                  */
00463                 if (NutTcpStateRetranTimeout(sock))
00464                     return -1;
00465             }
00466         }
00467         return 0;
00468     }
00469 
00470     /*
00471      * We're here, so the ACK must have actually acked something
00472      */
00473     sock->so_tx_dup = 0;
00474     sock->so_tx_una = h_ack;
00475 
00476     /*
00477      * Bugfix contributed by Liu Limin: If the remote is slow and this
00478      * line is missing, then Ethernut will send a full data packet even
00479      * if the remote closed the window.
00480      */
00481     sock->so_tx_win = ntohs(th->th_win);
00482 
00483     /* 
00484      * Do round trip time calculation.
00485      */
00486     if (sock->so_rtt_seq && sock->so_rtt_seq < h_ack)
00487         NutTcpCalcRtt (sock);
00488     sock->so_rtt_seq = 0;
00489     /*
00490      * Remove all acknowledged netbufs.
00491      */
00492     while ((nb = sock->so_tx_nbq) != 0) {
00493         /* Calculate the sequence beyond this netbuf. */
00494         h_seq = ntohl(((TCPHDR *) (nb->nb_tp.vp))->th_seq) + nb->nb_ap.sz;
00495         if (((TCPHDR *) (nb->nb_tp.vp))->th_flags & (TH_SYN | TH_FIN)) {
00496             h_seq++;
00497         }
00498         //@@@printf ("[%04X]*: processack, check seq#: %lu\n", (u_short) sock, h_seq);
00499         if (h_seq > h_ack) {
00500             break;
00501         }
00502         sock->so_tx_nbq = nb->nb_next;
00503         NutNetBufFree(nb);
00504     }
00505 
00506     /*
00507      * Reset retransmit timer and wake up waiting transmissions.
00508      */
00509     if (sock->so_tx_nbq) {
00510         sock->so_retran_time = (u_short) NutGetMillis() | 1;
00511     } else {
00512         sock->so_retran_time = 0;
00513     }
00514     sock->so_retransmits = 0;
00515 
00516     return 0;
00517 }
00518 
00519 
00520 
00521 /* ================================================================
00522  * State changes.
00523  * ================================================================
00524  */
00533 static int NutTcpStateChange(TCPSOCKET * sock, u_char state)
00534 {
00535     int rc = 0;
00536     ureg_t txf = 0;
00537 
00538     switch (sock->so_state) {
00539         /* Handle the most common case first. */
00540     case TCPS_ESTABLISHED:
00541         switch (state) {
00542         case TCPS_FIN_WAIT_1:
00543             /*
00544              * Closed by application.
00545              */
00546             sock->so_tx_flags |= SO_FIN | SO_ACK;
00547             txf = 1;
00548 
00549 #ifdef RTLCONNECTHACK
00550             /*
00551              * Hack alert!
00552              * On the RTL8019AS we got a problem. Because of not handling
00553              * the CHRDY line, the controller drops outgoing packets when
00554              * a browser opens multiple connections concurrently, producing
00555              * several short incoming packets. Empirical test showed, that
00556              * a slight delay during connects and disconnects helped to
00557              * remarkably reduce this problem.
00558              */
00559             NutDelay(5);
00560 #endif
00561             break;
00562         case TCPS_CLOSE_WAIT:
00563             /*
00564              * FIN received.
00565              */
00566             sock->so_tx_flags |= SO_ACK | SO_FORCE;
00567             txf = 1;
00568             break;
00569         default:
00570             rc = -1;
00571             break;
00572         }
00573         break;
00574 
00575     case TCPS_LISTEN:
00576         /*
00577          * SYN received.
00578          */
00579         if (state == TCPS_SYN_RECEIVED) {
00580             sock->so_tx_flags |= SO_SYN | SO_ACK;
00581             txf = 1;
00582 #ifdef RTLCONNECTHACK
00583             /*
00584              * Hack alert!
00585              * On the RTL8019AS we got a problem. Because of not handling
00586              * the CHRDY line, the controller drops outgoing packets when
00587              * a browser opens multiple connections concurrently, producing
00588              * several short incoming packets. Empirical test showed, that
00589              * a slight delay during connects and disconnects helped to
00590              * remarkably reduce this problem.
00591              */
00592             NutDelay(5);
00593 #endif
00594         } else
00595             rc = -1;
00596         break;
00597 
00598     case TCPS_SYN_SENT:
00599         switch (state) {
00600         case TCPS_LISTEN:
00601             /*
00602              * RST received on passive socket.
00603              */
00604             break;
00605         case TCPS_SYN_RECEIVED:
00606             /*
00607              * SYN received.
00608              */
00609             sock->so_tx_flags |= SO_SYN | SO_ACK;
00610             txf = 1;
00611             break;
00612         case TCPS_ESTABLISHED:
00613             /*
00614              * SYNACK received.
00615              */
00616             sock->so_tx_flags |= SO_ACK | SO_FORCE;
00617             txf = 1;
00618             break;
00619         default:
00620             rc = -1;
00621             break;
00622         }
00623         break;
00624 
00625     case TCPS_SYN_RECEIVED:
00626         switch (state) {
00627         case TCPS_LISTEN:
00628             /*
00629              * RST received on passive socket.
00630              */
00631             break;
00632         case TCPS_ESTABLISHED:
00633             /*
00634              * ACK of SYN received.
00635              */
00636             break;
00637         case TCPS_FIN_WAIT_1:
00638             /*
00639              * Closed by application.
00640              */
00641             sock->so_tx_flags |= SO_FIN;
00642             txf = 1;
00643             break;
00644         case TCPS_CLOSE_WAIT:
00645             /*
00646              * FIN received.
00647              */
00648             sock->so_tx_flags |= SO_FIN | SO_ACK;
00649             txf = 1;
00650             break;
00651         default:
00652             rc = -1;
00653             break;
00654         }
00655         break;
00656 
00657     case TCPS_FIN_WAIT_1:
00658         switch (state) {
00659         case TCPS_FIN_WAIT_1:
00660         case TCPS_FIN_WAIT_2:
00661             /*
00662              * ACK of FIN received.
00663              */
00664             break;
00665         case TCPS_CLOSING:
00666             /*
00667              * FIN received.
00668              */
00669             sock->so_tx_flags |= SO_ACK | SO_FORCE;
00670             txf = 1;
00671             break;
00672         case TCPS_TIME_WAIT:
00673             /*
00674              * FIN and ACK of FIN received.
00675              */
00676             break;
00677         default:
00678             rc = -1;
00679             break;
00680         }
00681         break;
00682 
00683     case TCPS_FIN_WAIT_2:
00684         /*
00685          * FIN received.
00686          */
00687         if (state != TCPS_TIME_WAIT)
00688             rc = -1;
00689         sock->so_tx_flags |= SO_ACK | SO_FORCE;
00690         txf = 1;
00691         break;
00692 
00693     case TCPS_CLOSE_WAIT:
00694         /*
00695          * Closed by application.
00696          */
00697         if (state == TCPS_LAST_ACK) {
00698             sock->so_tx_flags |= SO_FIN | SO_ACK;
00699             txf = 1;
00700         } else
00701             rc = -1;
00702         break;
00703 
00704     case TCPS_CLOSING:
00705         /*
00706          * ACK of FIN received.
00707          */
00708         if (state != TCPS_TIME_WAIT)
00709             rc = -1;
00710         break;
00711 
00712     case TCPS_LAST_ACK:
00713         rc = -1;
00714         break;
00715 
00716     case TCPS_TIME_WAIT:
00717         rc = -1;
00718         break;
00719 
00720     case TCPS_CLOSED:
00721         switch (state) {
00722         case TCPS_LISTEN:
00723             /*
00724              * Passive open by application.
00725              */
00726             break;
00727         case TCPS_SYN_SENT:
00728             /*
00729              * Active open by application.
00730              */
00731             sock->so_tx_flags |= SO_SYN;
00732             txf = 1;
00733             break;
00734         default:
00735             rc = -1;
00736             break;
00737         }
00738         break;
00739     }
00740 #ifdef NUTDEBUG
00741     if (__tcp_trf) {
00742         fprintf(__tcp_trs, " %04x-", (u_int) sock);
00743         if (rc)
00744             NutDumpSockState(__tcp_trs, sock->so_state, "**ERR ", "**>");
00745         NutDumpSockState(__tcp_trs, state, "[>", "]");
00746     }
00747 #endif
00748 
00749     if (rc == 0) {
00750         sock->so_state = state;
00751         if (txf && NutTcpOutput(sock, 0, 0)) {
00752             if (state == TCPS_SYN_SENT) {
00753                 rc = -1;
00754                 sock->so_last_error = EHOSTDOWN;
00755                 NutEventPostAsync(&sock->so_ac_tq);
00756             }
00757         }
00758         if (state == TCPS_CLOSE_WAIT) {
00759             /*
00760              * Inform application.
00761              */
00762             NutEventBroadcast(&sock->so_rx_tq);
00763             NutEventBroadcast(&sock->so_pc_tq);
00764             NutEventBroadcast(&sock->so_ac_tq);
00765         }
00766     }
00767     return rc;
00768 }
00769 
00770 /* ================================================================
00771  * Application events.
00772  * ================================================================
00773  */
00782 int NutTcpStatePassiveOpenEvent(TCPSOCKET * sock)
00783 {
00784     if (sock->so_state != TCPS_CLOSED)
00785         return (sock->so_last_error = EISCONN);
00786 
00787     NutTcpStateChange(sock, TCPS_LISTEN);
00788 
00789     /*
00790      * Block application.
00791      */
00792     NutEventWait(&sock->so_pc_tq, 0);
00793 
00794     return 0;
00795 }
00796 
00807 int NutTcpStateActiveOpenEvent(TCPSOCKET * sock)
00808 {
00809     /*
00810      * Switch state to SYN_SENT. This will
00811      * transmit a SYN packet.
00812      */
00813     NutTcpStateChange(sock, TCPS_SYN_SENT);
00814 
00815     /*
00816      * Block application.
00817      */
00818      if(sock->so_state == TCPS_SYN_SENT)
00819         NutEventWait(&sock->so_ac_tq, 0);
00820 
00821     if (sock->so_state != TCPS_ESTABLISHED)
00822         return -1;
00823 
00824     return 0;
00825 }
00826 
00839 int NutTcpStateCloseEvent(TCPSOCKET * sock)
00840 {
00841     if (sock == 0)
00842         return -1;
00843 
00844     NutThreadYield();
00845 
00846     switch (sock->so_state) {
00847     case TCPS_LISTEN:
00848     case TCPS_SYN_SENT:
00849     case TCPS_CLOSED:
00850         /*
00851          * No connection yet, immediately destroy the socket.
00852          */
00853         NutTcpDestroySocket(sock);
00854         break;
00855 
00856     case TCPS_SYN_RECEIVED:
00857     case TCPS_ESTABLISHED:
00858         /*
00859          * Send a FIN and wait for ACK or FIN.
00860          */
00861         //@@@printf ("[%04X]ESTABLISHED: going to FIN_WAIT_1\n", (u_short) sock);
00862         NutTcpStateChange(sock, TCPS_FIN_WAIT_1);
00863         break;
00864 
00865     case TCPS_CLOSE_WAIT:
00866         /* 
00867          * RFC 793 is wrong. 
00868          */
00869         //@@@printf("[%04X]CLOSE_WAIT: going to LAST_ACK\n", (u_short) sock);
00870         NutTcpStateChange(sock, TCPS_LAST_ACK);
00871         break;
00872 
00873     case TCPS_FIN_WAIT_1:
00874     case TCPS_FIN_WAIT_2:
00875     case TCPS_CLOSING:
00876     case TCPS_LAST_ACK:
00877     case TCPS_TIME_WAIT:
00878         sock->so_last_error = EALREADY;
00879         return -1;
00880 
00881     default:
00882         sock->so_last_error = ENOTCONN;
00883         return -1;
00884     }
00885     return 0;
00886 }
00887 
00894 int NutTcpStateWindowEvent(TCPSOCKET * sock)
00895 {
00896     if (sock == 0)
00897         return -1;
00898     sock->so_tx_flags |= SO_ACK | SO_FORCE;
00899     NutTcpOutput(sock, 0, 0);
00900 
00901     return 0;
00902 }
00903 
00904 /* ================================================================
00905  * Timeout events.
00906  * ================================================================
00907  */
00919 int NutTcpStateRetranTimeout(TCPSOCKET * sock)
00920 {
00921     NETBUF *so_tx_next;
00922     if (sock->so_retransmits++ > TCP_RETRIES_MAX)
00923     {
00924         /* Abort the socket */
00925         NutTcpAbortSocket(sock, ETIMEDOUT);
00926         return -1;
00927     } else {
00928 #ifdef NUTDEBUG
00929         if (__tcp_trf)
00930             NutDumpTcpHeader(__tcp_trs, "RET", sock, sock->so_tx_nbq);
00931 #endif
00932         /* We must save sock->so_tx_nbq->nb_next before calling NutIpOutput,
00933          * because in case of error the NETBUF is release by NutIpOutput and
00934          * not longer available.
00935          */
00936         so_tx_next = sock->so_tx_nbq->nb_next;
00937         if (NutIpOutput(IPPROTO_TCP, sock->so_remote_addr, sock->so_tx_nbq)) {
00938             /* Adjust packet queue */
00939             sock->so_tx_nbq = so_tx_next;
00940             /* Abort the socket */
00941             NutTcpAbortSocket(sock, ENETDOWN);
00942             return -1;
00943         } else {
00944             /* Restart the retransmission timer. */
00945             sock->so_retran_time = (u_short) NutGetMillis() | 1;
00946             return 0;
00947         }
00948     }
00949 }
00950 
00951 /* ================================================================
00952  * Segment arrival events.
00953  * ================================================================
00954  */
00955 
00965 static void NutTcpStateListen(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
00966 {
00967     /*
00968      * Got a SYN segment. Store relevant data in our socket
00969      * structure and switch to TCPS_SYN_RECEIVED.
00970      */
00971     if ((flags & (TH_SYN | TH_ACK | TH_RST)) == TH_SYN) {
00972         NutTcpProcessSyn(sock, nb->nb_nw.vp, th);
00973         NutTcpStateChange(sock, TCPS_SYN_RECEIVED);
00974         NutNetBufFree(nb);
00975     } else
00976         NutTcpReject(nb);
00977 }
00978 
00979 
00988 static void NutTcpStateSynSent(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
00989 {
00990     /*
00991      * Validate ACK, if set.
00992      */
00993     if (flags & TH_ACK) {
00994         if (!IsInLimits(ntohl(th->th_ack), sock->so_tx_isn + 1, sock->so_tx_nxt)) {
00995             NutTcpReject(nb);
00996             return;
00997         }
00998     }
00999 
01000     /*
01001      * Handle RST flag. If we were in the LISTEN state,
01002      * then we return to the LISTEN state, otherwise we
01003      * abort the connection and go to the CLOSED state.
01004      */
01005     if (flags & TH_RST) {
01006         if (flags & TH_ACK) {
01007             /*if (sock->so_pc_tq)
01008                 NutTcpStateChange(sock, TCPS_LISTEN);
01009             else */
01010                 NutTcpAbortSocket(sock, ECONNREFUSED);
01011         }
01012         NutNetBufFree(nb);
01013         return;
01014     }
01015 
01016     /*
01017      * Handle SYN flag. If we got a valid ACK too, then
01018      * our connection is established. Otherwise enter
01019      * SYNRCVD state.
01020      */
01021     if (flags & TH_SYN) {
01022         NutTcpProcessSyn(sock, nb->nb_nw.vp, th);
01023         if (flags & TH_ACK) {
01024             NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01025             NutTcpStateChange(sock, TCPS_ESTABLISHED);
01026             /* Wake up the actively connecting thread. */
01027             NutEventPost(&sock->so_ac_tq);
01028         } else {
01029             NutTcpStateChange(sock, TCPS_SYN_RECEIVED);
01030         }
01031     }
01032     NutNetBufFree(nb);
01033 }
01034 
01035 /*
01036  * \brief
01037  * Process incoming segments in SYN-RECEIVED state.
01038  *
01039  * Waiting for a confirming connection request
01040  * acknowledgment after having both received
01041  * and sent a connection request.
01042  *
01043  * \param sock Socket descriptor.
01044  * \param nb   Network buffer structure containing a TCP segment.
01045  */
01046 static void NutTcpStateSynReceived(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
01047 {
01048     /*
01049      * If our previous ack receives a reset response,
01050      * then we fall back to the listening state.
01051      */
01052     if (flags & TH_RST) {
01053         if (sock->so_pc_tq)
01054             NutTcpStateChange(sock, TCPS_LISTEN);
01055         else 
01056             NutTcpAbortSocket(sock, ECONNREFUSED);
01057         NutNetBufFree(nb);
01058         sock->so_retran_time = 0;
01059         NutTcpDiscardBuffers(sock);
01060         return;
01061     }
01062 
01063     /*
01064      * Reject SYNs.
01065      */
01066     if (flags & TH_SYN) {
01067         NutTcpReject(nb);
01068         return;
01069     }
01070 
01071     /*
01072      * Silently discard segments without ACK.
01073      */
01074     if ((flags & TH_ACK) == 0) {
01075         NutNetBufFree(nb);
01076         return;
01077     }
01078 
01079     /*
01080      * Reject out of window sequence.
01081      */
01082     if (!IsInLimits(ntohl(th->th_ack), sock->so_tx_una + 1, sock->so_tx_nxt)) {
01083         NutTcpReject(nb);
01084         return;
01085     }
01086 
01087     /* Acknowledge processing. */
01088     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01089 
01090     /*
01091      * Even SYN segments may contain application data, which will be stored
01092      * in the socket's input buffer. However, there is no need to post an
01093      * event to any thread waiting for data, because our connection is not 
01094      * yet established.
01095      */
01096     if (nb->nb_ap.sz)
01097         NutTcpProcessAppData(sock, nb);
01098     else
01099         NutNetBufFree(nb);
01100 
01101     /*
01102      * Process state change.
01103      */
01104     if (flags & TH_FIN) {
01105         sock->so_rx_nxt++;
01106         NutTcpStateChange(sock, TCPS_CLOSE_WAIT);
01107     } else {
01108         NutTcpStateChange(sock, TCPS_ESTABLISHED);
01109         NutEventPost(&sock->so_pc_tq);
01110         NutEventPost(&sock->so_ac_tq);
01111     }
01112 }
01113 
01114 /*
01115  * \brief Process incoming segments from established connections.
01116  *
01117  * Received application data will be delivered to the application
01118  * until we receive a FIN segment.
01119  *
01120  * \param sock  Socket descriptor.
01121  * \param flags TCP flags.
01122  * \param th    Pointer to the TCP header within the NETBUF.
01123  * \param nb    Network buffer structure containing a TCP segment.
01124  *
01125  * \todo We may remove the unused counter of dropped segments, which
01126  *       were out of sequence.
01127  */
01128 static void NutTcpStateEstablished(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
01129 {
01130     if (flags & TH_RST) {
01131         NutNetBufFree(nb);
01132         NutTcpAbortSocket(sock, ECONNRESET);
01133         return;
01134     }
01135 
01136     /*
01137      * Reject SYNs. Silently discard late SYNs
01138      * (Thanks to Mike Cornelius).
01139      */
01140     if (flags & TH_SYN) {
01141         if (htonl(th->th_seq) != sock->so_rx_isn)
01142             NutTcpReject(nb);
01143         else
01144             NutNetBufFree(nb);
01145         return;
01146     }
01147 
01148     /*
01149      * Silently discard segments without ACK.
01150      */
01151     if ((flags & TH_ACK) == 0) {
01152         NutNetBufFree(nb);
01153         return;
01154     }
01155 
01156     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01157 
01158     /*
01159      * If the sequence number of the incoming segment is larger than 
01160      * expected, we probably missed one or more previous segments. Let's 
01161      * add this one to a linked list of segments received in advance and 
01162      * hope that the missing data will arrive later.
01163      */
01164     if (htonl(th->th_seq) > sock->so_rx_nxt) {
01165         NETBUF *nbq;
01166         NETBUF **nbqp;
01167         TCPHDR *thq;
01168         u_long th_seq;
01169         u_long thq_seq;
01170 
01171         if (nb->nb_ap.sz) {
01172             nbq = sock->so_rx_nbq;
01173             nbqp = &sock->so_rx_nbq;
01174             while (nbq) {
01175                 thq = (TCPHDR *) (nbq->nb_tp.vp);
01176                 th_seq = htonl(th->th_seq);
01177                 thq_seq = htonl(thq->th_seq);
01178                 if (th_seq < thq_seq) {
01179                     *nbqp = nb;
01180                     nb->nb_next = nbq;
01181                     break;
01182                 }
01183                 if (th_seq == thq_seq) {
01184                     NutNetBufFree(nb);
01185                     sock->so_tx_flags |= SO_ACK | SO_FORCE;
01186                     NutTcpOutput(sock, 0, 0);
01187                     return;
01188                 }
01189                 nbqp = &nbq->nb_next;
01190                 nbq = nbq->nb_next;
01191             }
01192             if (nbq == 0) {
01193                 *nbqp = nb;
01194                 nb->nb_next = 0;
01195             }
01196         } else
01197             NutNetBufFree(nb);
01198 
01199         sock->so_tx_flags |= SO_ACK | SO_FORCE;
01200         NutTcpOutput(sock, 0, 0);
01201         return;
01202     }
01203 
01204     /*
01205      * Acknowledge any sequence numbers not expected, 
01206      * even if they do not contain any data. Keepalive
01207      * packets contain a sequence number one less
01208      * than the next data expected and they do not 
01209      * contain any data.
01210      */
01211     if (htonl(th->th_seq) != sock->so_rx_nxt) {
01212         sock->so_tx_flags |= SO_ACK | SO_FORCE;
01213         /* This seems to be unused. */
01214         sock->so_oos_drop++;
01215         NutNetBufFree(nb);
01216         NutTcpOutput(sock, 0, 0);
01217     } 
01218 
01219     /*
01220      * The sequence number is exactly what we expected.
01221      */
01222     else if (nb->nb_ap.sz) {
01223         NutTcpProcessAppData(sock, nb);
01224         /*
01225          * Process segments we may have received in advance.
01226          */
01227         while ((nb = sock->so_rx_nbq) != 0) {
01228             th = (TCPHDR *) (nb->nb_tp.vp);
01229             if (htonl(th->th_seq) > sock->so_rx_nxt)
01230                 break;
01231             sock->so_rx_nbq = nb->nb_next;
01232             if (htonl(th->th_seq) == sock->so_rx_nxt) {
01233                 NutTcpProcessAppData(sock, nb);
01234                 flags |= th->th_flags;
01235             } else
01236                 NutNetBufFree(nb);
01237         }
01238         /* Wake up a thread waiting for data. */
01239         NutEventPost(&sock->so_rx_tq);
01240     } else {
01241         NutNetBufFree(nb);
01242         //sock->so_tx_flags |= SO_ACK | SO_FORCE;
01243         //NutTcpOutput(sock, 0, 0);
01244     }
01245     if (flags & TH_FIN) {
01246         //@@@printf ("[%04X]ESTABLISHED: going to CLOSE_WAIT\n", (u_short) sock);
01247         sock->so_rx_nxt++;
01248         NutTcpStateChange(sock, TCPS_CLOSE_WAIT);
01249     }
01250 }
01251 
01252 /*
01253  * \brief Process incoming segments in FIN-WAIT1 state.
01254  *
01255  * Waiting for a connection termination request
01256  * from the remote, or an acknowledgment of the
01257  * connection termination request previously sent.
01258  *
01259  * The application already closed the socket.
01260  *
01261  * \param sock Socket descriptor.
01262  * \param nb   Network buffer structure containing a TCP segment.
01263  *
01264  * \todo The out of sync case seems to be ignored. Anyway, do we
01265  *       really need to process application data in this state?
01266  */
01267 static void NutTcpStateFinWait1(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
01268 {
01269     //@@@printf ("[%04X]FIN_WAIT_1: incomming segment, IP %04X\n", (u_short) sock, ntohs(((IPHDR*)nb->nb_nw.vp)->ip_id));
01270     if (flags & TH_RST) {
01271         NutNetBufFree(nb);
01272         NutTcpDestroySocket(sock);
01273         return;
01274     }
01275 
01276     /*
01277      * Reject SYNs.
01278      */
01279     if (flags & TH_SYN) {
01280         NutTcpReject(nb);
01281         return;
01282     }
01283 
01284     /*
01285      * Silently discard segments without ACK.
01286      */
01287     if ((flags & TH_ACK) == 0) {
01288         NutNetBufFree(nb);
01289         return;
01290     }
01291 
01292     //@@@if (flags & TH_FIN) printf ("[%04X]FIN_WAIT_1: received FIN\n", (u_short) sock);
01293     //@@@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);
01294     
01295     //@@@printf ("[%04X]FIN_WAIT_1:  pre processack, nbq: %04X\n", (u_short) sock, (u_short) sock->so_tx_nbq);
01296     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01297     //@@@printf ("[%04X]FIN_WAIT_1: post processack, nbq: %04X\n", (u_short) sock, (u_short) sock->so_tx_nbq);
01298 
01299     /*
01300      * All segments had been acknowledged, including our FIN.
01301      */
01302     if (sock->so_tx_nxt == sock->so_tx_una) {
01303         //@@@printf ("[%04X]FIN_WAIT_1: going to FIN_WAIT_2\n", (u_short) sock);
01304         NutTcpStateChange(sock, TCPS_FIN_WAIT_2);
01305     }
01306 
01307     /*
01308      * Process application data and release the network buffer.
01309      * Is this really required?
01310      */
01311     if (nb->nb_ap.sz) {
01312         NutTcpProcessAppData(sock, nb);
01313         /* Wake up a thread waiting for data. */
01314         NutEventPost(&sock->so_rx_tq);
01315     }
01316     else
01317         NutNetBufFree(nb);
01318 
01319     if (flags & TH_FIN) {
01320         sock->so_rx_nxt++;
01321         /* 
01322          * Our FIN has been acked.
01323          */
01324         sock->so_time_wait = 0;
01325         //@@@printf ("[%04X]FIN_WAIT_1: going to CLOSING\n", (u_short) sock);
01326         if (sock->so_state == TCPS_FIN_WAIT_2)
01327             NutTcpStateChange(sock, TCPS_TIME_WAIT);
01328         else
01329             NutTcpStateChange(sock, TCPS_CLOSING);
01330     }
01331 }
01332 
01333 /*
01334  * \brief Process incoming segments in FIN-WAIT2 state.
01335  *
01336  * Waiting for a connection termination request
01337  * from the remote.
01338  *
01339  * The application already closed the socket.
01340  *
01341  * \param sock Socket descriptor.
01342  * \param nb   Network buffer structure containing a TCP segment.
01343  *
01344  * \todo There's probably no need to process application data.
01345  */
01346 static void NutTcpStateFinWait2(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
01347 {
01348     //@@@printf ("[%04X]FIN_WAIT_2: incomming segment, IP %04X\n", (u_short) sock, ntohs(((IPHDR*)nb->nb_nw.vp)->ip_id));
01349     if (flags & TH_RST) {
01350         NutNetBufFree(nb);
01351         NutTcpDestroySocket(sock);
01352         return;
01353     }
01354 
01355     /*
01356      * Reject SYNs.
01357      */
01358     if (flags & TH_SYN) {
01359         NutTcpReject(nb);
01360         return;
01361     }
01362 
01363     /*
01364      * Silently discard segments without ACK.
01365      */
01366     if ((flags & TH_ACK) == 0) {
01367         NutNetBufFree(nb);
01368         return;
01369     }
01370 
01371     //@@@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);
01372     /*
01373      * Process acknowledge and application data and release the 
01374      * network buffer.
01375      */
01376     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01377 
01378     //@@@if (sock->so_tx_nbq) printf ("[%04X]FIN_WAIT_2: xmit buffer not empty!", (u_short) sock);
01379     /* Do we really need this? */
01380     if (nb->nb_ap.sz) {
01381         NutTcpProcessAppData(sock, nb);
01382         /* Wake up a thread waiting for data. */
01383         NutEventPost(&sock->so_rx_tq);
01384     }
01385     else
01386         NutNetBufFree(nb);
01387 
01388     if (flags & TH_FIN) {
01389         sock->so_rx_nxt++;
01390         sock->so_time_wait = 0;
01391         //@@@printf ("[%04X]FIN_WAIT_2: going to TIME_WAIT\n", (u_short) sock);
01392         NutTcpStateChange(sock, TCPS_TIME_WAIT);
01393     }
01394 }
01395 
01396 /*
01397  * \brief
01398  * Process incoming segments in CLOSE-WAIT state.
01399  *
01400  * Waiting for a connection termination request
01401  * from the local application.
01402  *
01403  * \param sock Socket descriptor.
01404  * \param nb   Network buffer structure containing a TCP segment.
01405  */
01406 static void NutTcpStateCloseWait(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
01407 {
01408     //@@@printf ("[%04X]CLOSE_WAIT: incomming segment, IP %04X\n", (u_short) sock, ((IPHDR*)nb->nb_nw.vp)->ip_id);
01409     if (flags & TH_RST) {
01410         NutNetBufFree(nb);
01411         NutTcpAbortSocket(sock, ECONNRESET);
01412         return;
01413     }
01414 
01415     /*
01416      * Reject SYNs.
01417      */
01418     if (flags & TH_SYN) {
01419         NutTcpReject(nb);
01420         return;
01421     }
01422 
01423     /*
01424      * Silently discard segments without ACK.
01425      */
01426     if ((flags & TH_ACK) == 0) {
01427         NutNetBufFree(nb);
01428         return;
01429     }
01430 
01431     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01432 
01433     NutNetBufFree(nb);
01434 }
01435 
01436 /*
01437  * \brief
01438  * Process incoming segments in CLOSING state.
01439  *
01440  * Waiting for a connection termination request
01441  * acknowledgment from the remote.
01442  *
01443  * The application already closed the socket.
01444  *
01445  * \param sock Socket descriptor.
01446  * \param nb   Network buffer structure containing a TCP segment.
01447  */
01448 static void NutTcpStateClosing(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
01449 {
01450     //@@@printf ("[%04X]CLOSING: Incomming segment\n", (u_short) sock);
01451     if (flags & TH_RST) {
01452         NutNetBufFree(nb);
01453         NutTcpDestroySocket(sock);
01454         return;
01455     }
01456 
01457     /*
01458      * Reject SYNs.
01459      */
01460     if (flags & TH_SYN) {
01461         NutTcpReject(nb);
01462         return;
01463     }
01464 
01465     /*
01466      * Silently discard segments without ACK.
01467      */
01468     if ((flags & TH_ACK) == 0) {
01469         NutNetBufFree(nb);
01470         return;
01471     }
01472 
01473     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01474 
01475     /*
01476      * All segments had been acknowledged, including our FIN.
01477      */
01478     if (sock->so_tx_nxt == sock->so_tx_una) {
01479         sock->so_time_wait = 0;
01480         NutTcpStateChange(sock, TCPS_TIME_WAIT);
01481         //@@@printf ("[%04X]CLOSING: Going to TIME_WAIT\n", (u_short) sock);
01482     }
01483     //@@@else printf ("[%04X]CLOSING: NOT changing state\n", (u_short) sock);
01484 
01485     NutNetBufFree(nb);
01486 }
01487 
01502 static void NutTcpStateLastAck(TCPSOCKET * sock, u_char flags, TCPHDR * th, NETBUF * nb)
01503 {
01504     //@@@printf ("[%04X]LAST_ACK: incomming segment, IP %04X\n", (u_short) sock, ((IPHDR*)nb->nb_nw.vp)->ip_id);
01505     if (flags & TH_RST) {
01506         NutNetBufFree(nb);
01507         NutTcpDestroySocket(sock);
01508         return;
01509     }
01510 
01511     /*
01512      * Reject SYNs.
01513      */
01514     if (flags & TH_SYN) {
01515         NutTcpReject(nb);
01516         return;
01517     }
01518 
01519     /*
01520      * Silently discard segments without ACK.
01521      */
01522     if ((flags & TH_ACK) == 0) {
01523         NutNetBufFree(nb);
01524         return;
01525     }
01526 
01527     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01528     NutNetBufFree(nb);
01529 
01530     if (sock->so_tx_nxt == sock->so_tx_una) 
01531         NutTcpDestroySocket(sock);
01532     //@@@else printf ("[%04X]LAST_ACK: no destroy sock\n", (u_short) sock);
01533 }
01534 
01545 static void NutTcpStateProcess(TCPSOCKET * sock, NETBUF * nb)
01546 {
01547     u_long tx_win;
01548     u_long tx_una;
01549     TCPHDR *th = (TCPHDR *) nb->nb_tp.vp;
01550     u_char flags = th->th_flags;
01551 
01552 #ifdef NUTDEBUG
01553     if (__tcp_trf) {
01554         fprintf(__tcp_trs, " %04x-", (u_int) sock);
01555         NutDumpSockState(__tcp_trs, sock->so_state, "[", ">]");
01556     }
01557 #endif
01558     switch (sock->so_state) {
01559         /* Handle the most common case first. */
01560     case TCPS_ESTABLISHED:
01561         tx_win = sock->so_tx_win;
01562         tx_una = sock->so_tx_una;
01563         NutTcpStateEstablished(sock, flags, th, nb);
01564         /* Wake up all threads waiting for transmit, if something interesting happened. */
01565         if(sock->so_state != TCPS_ESTABLISHED || /* Status changed. */
01566            sock->so_tx_win > tx_win ||           /* Windows changed. */
01567            sock->so_tx_una > tx_una) {           /* Unacknowledged data changed. */
01568             NutEventBroadcast(&sock->so_tx_tq);
01569         }
01570         break;
01571     case TCPS_LISTEN:
01572         NutTcpStateListen(sock, flags, th, nb);
01573         break;
01574     case TCPS_SYN_SENT:
01575         NutTcpStateSynSent(sock, flags, th, nb);
01576         break;
01577     case TCPS_SYN_RECEIVED:
01578         NutTcpStateSynReceived(sock, flags, th, nb);
01579         break;
01580     case TCPS_FIN_WAIT_1:
01581         NutTcpStateFinWait1(sock, flags, th, nb);
01582         break;
01583     case TCPS_FIN_WAIT_2:
01584         NutTcpStateFinWait2(sock, flags, th, nb);
01585         break;
01586     case TCPS_CLOSE_WAIT:
01587         NutTcpStateCloseWait(sock, flags, th, nb);
01588         break;
01589     case TCPS_CLOSING:
01590         NutTcpStateClosing(sock, flags, th, nb);
01591         break;
01592     case TCPS_LAST_ACK:
01593         NutTcpStateLastAck(sock, flags, th, nb);
01594         break;
01595     case TCPS_TIME_WAIT:
01596         /*
01597          * Ignore everything while in TIME_WAIT state.
01598          */
01599         NutNetBufFree(nb);
01600         break;
01601     case TCPS_CLOSED:
01602         /*
01603          * Reject everything while in CLOSED state.
01604          */
01605         NutTcpReject(nb);
01606         break;
01607     default:
01608         NutNetBufFree(nb);
01609         break;
01610     }
01611 }
01612 
01619 THREAD(NutTcpSm, arg)
01620 {
01621     NETBUF *nb;
01622     NETBUF *nbx;
01623     TCPHDR *th;
01624     IPHDR *ih;
01625     TCPSOCKET *sock;
01626     u_char tac = 0;
01627 
01628     /*
01629      * It won't help giving us a higher priority than the application
01630      * code. We depend on the speed of the reading application.
01631      */
01632     NutThreadSetPriority (32);
01633     
01634     for (;;) {
01635         if (++tac > 3 || NutEventWait(&tcp_in_rdy, 200)) {
01636             tac = 0;
01637             for (sock = tcpSocketList; sock; sock = sock->so_next) {
01638 
01639                 /*
01640                  * Send late acks.
01641                  */
01642                 if (sock->so_tx_flags & SO_ACK) {
01643                     sock->so_tx_flags |= SO_FORCE;
01644                     NutTcpOutput(sock, 0, 0);
01645                 }
01646 
01647                 /*
01648                  * Process retransmit timer.
01649                  */
01650                 if (sock->so_tx_nbq && sock->so_retran_time) {
01651                     if ((u_short)((u_short)NutGetMillis() - sock->so_retran_time) > sock->so_rtto) {
01652                         NutTcpStateRetranTimeout(sock);
01653                     }
01654                 }
01655 
01656                 /*
01657                  * Destroy sockets after timeout in TIMEWAIT state.
01658                  */
01659                 if (sock->so_state == TCPS_TIME_WAIT || sock->so_state == TCPS_FIN_WAIT_2) {
01660                     if (sock->so_time_wait++ >= 9) {
01661                         NutTcpDestroySocket(sock);
01662                         break;
01663                     }
01664                 }
01665 
01666                 /*
01667                  * Recover from SYN flood attacks.
01668                  */
01669                 else if (sock->so_state == TCPS_SYN_RECEIVED) {
01670                     if (sock->so_time_wait++ >= 45) {
01671                         sock->so_state = TCPS_LISTEN;
01672                         sock->so_time_wait = 0;
01673                     }
01674                 }
01675             }
01676         } else {
01677             nb = tcp_in_nbq;
01678             tcp_in_nbq = 0;
01679             tcp_in_cnt = 0;
01680             while (nb) {
01681                 ih = (IPHDR *) nb->nb_nw.vp;
01682                 th = (TCPHDR *) nb->nb_tp.vp;
01683                 sock = NutTcpFindSocket(th->th_dport, th->th_sport, ih->ip_src);
01684 #ifdef NUTDEBUG
01685                 if (__tcp_trf)
01686                     NutDumpTcpHeader(__tcp_trs, " IN", sock, nb);
01687 #endif
01688                 nbx = nb->nb_next;
01689                 if (sock) {
01690                     NutTcpInputOptions(sock, nb);
01691                     NutTcpStateProcess(sock, nb);
01692                 }
01693 
01694                 /*
01695                  * Reject the segment, if no matching socket was found.
01696                  */
01697                 else
01698                     NutTcpReject(nb);
01699                 nb = nbx;
01700             }
01701         }
01702     }
01703 }
01704 
01716 void NutTcpStateMachine(NETBUF * nb)
01717 {
01718     NETBUF *nbp;
01719     u_short size;
01720 
01721     nb->nb_next = 0;
01722 
01723     /*
01724      * Incoming TCP segments are rejected and released if no TCP
01725      * sockets have been opened. Not doing so would add them
01726      * to the queue and never release the NETBUF. Thanks to
01727      * Ralph Mason for this fix.
01728      */
01729     if (tcpThread == 0) {
01730         NutTcpReject(nb);
01731         return;
01732     }
01733 
01734     if ((nbp = tcp_in_nbq) == 0) {
01735         tcp_in_nbq = nb;
01736         NutEventPost(&tcp_in_rdy);
01737     } else {
01738         size = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz;
01739         if (tcp_in_cnt + size + 2048 < NutHeapAvailable()) {
01740             tcp_in_cnt += size;
01741             while (nbp->nb_next)
01742                 nbp = nbp->nb_next;
01743             nbp->nb_next = nb;
01744             NutEventPost(&tcp_in_rdy);
01745         } else
01746             NutNetBufFree(nb);
01747     }
01748 }
01749 
01758 int NutTcpInitStateMachine(void)
01759 {
01760     if (tcpThread == 0 && (tcpThread = NutThreadCreate("tcpsm", NutTcpSm, NULL, NUT_THREAD_TCPSMSTACK)) == 0)
01761         return -1;
01762     return 0;
01763 }
01764 
01778 int NutTcpAbortSocket(TCPSOCKET * sock, u_short last_error)
01779 {
01780     sock->so_last_error = last_error;
01781     sock->so_retran_time = 0;
01782     sock->so_time_wait = 0;
01783     /*
01784      * If NutTcpCloseSocket was already called, we have to change
01785      * to TCPS_TIME_WAIT state, otherwise the socket will not be destroyed.
01786      * For the other cases just go to TCPS_CLOSED.
01787      */
01788     if (sock->so_state >= TCPS_FIN_WAIT_1)      /* FIN_WAIT_1, FIN_WAIT_2, CLOSING, LAST_ACK, TIME_WAIT */
01789         sock->so_state = TCPS_TIME_WAIT;
01790     else
01791         sock->so_state = TCPS_CLOSED;
01792     NutTcpDiscardBuffers(sock);
01793     NutEventBroadcast(&sock->so_rx_tq);
01794     NutEventBroadcast(&sock->so_tx_tq);
01795     NutEventBroadcast(&sock->so_pc_tq);
01796     NutEventBroadcast(&sock->so_ac_tq);
01797     return 0;
01798 }
01799 

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