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

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