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

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