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 static size_t tcp_adv_cnt;
00288 static size_t tcp_adv_max = TCP_WINSIZE;
00289 
00290 /* ================================================================
00291  * Helper functions
00292  * ================================================================
00293  */
00294 
00295 
00304 static void NutTcpInputOptions(TCPSOCKET * sock, NETBUF * nb)
00305 {
00306     uint8_t *cp;
00307     uint16_t s;
00308     
00309     /* any options there? */
00310     if (nb->nb_tp.sz <= sizeof (TCPHDR))
00311         return;
00312     
00313     /* loop through available options */
00314     for (cp = ((uint8_t*) nb->nb_tp.vp) + sizeof(TCPHDR); (*cp != TCPOPT_EOL) 
00315        && (cp - (uint8_t *)nb->nb_tp.vp < (int)nb->nb_tp.sz); )
00316     {
00317         switch (*cp)
00318         {
00319             /* On NOP just proceed to next option */
00320             case TCPOPT_NOP:
00321                 cp++;
00322                 continue;
00323                 
00324             /* Read MAXSEG option */
00325             case TCPOPT_MAXSEG:
00326                 s = ntohs(*((uint16_t*)&cp[2]));
00327                 if (s < sock->so_mss)
00328                     sock->so_mss = s;
00329                 cp += TCPOLEN_MAXSEG;
00330                 break;
00331             /* Ignore any other options */
00332             default:
00333                 cp += *(uint8_t*) (cp + 1);
00334                 break;
00335         }
00336     }
00337 }
00338 
00347 static void NutTcpProcessAppData(TCPSOCKET * sock, NETBUF * nb)
00348 {
00349     /*
00350      * Add the NETBUF to the socket's input buffer.
00351      */
00352     if (sock->so_rx_buf) {
00353         NETBUF *nbp = sock->so_rx_buf;
00354 
00355         while (nbp->nb_next)
00356             nbp = nbp->nb_next;
00357         nbp->nb_next = nb;
00358     } else
00359         sock->so_rx_buf = nb;
00360 
00361     /*
00362      * Update the number of bytes available in the socket's input buffer
00363      * and the sequence number we expect next.
00364      */
00365     sock->so_rx_cnt += nb->nb_ap.sz;
00366     sock->so_rx_nxt += nb->nb_ap.sz;
00367 
00368     /*
00369      * Reduce our TCP window size.
00370      */
00371     if (nb->nb_ap.sz >= sock->so_rx_win)
00372         sock->so_rx_win = 0;
00373     else
00374         sock->so_rx_win -= nb->nb_ap.sz;
00375 
00376     /*
00377      * Set the socket's ACK flag. This will enable ACK transmission in
00378      * the next outgoing segment. If no more NETBUFs are queued, we
00379      * force immediate transmission of the ACK.
00380      */
00381     sock->so_tx_flags |= SO_ACK;
00382     if (nb->nb_next)
00383         nb->nb_next = 0;
00384     else
00385         sock->so_tx_flags |= SO_FORCE;
00386 
00387     if (++sock->so_rx_apc > 8) {
00388         NETBUF *nbq;
00389         int_fast8_t apc = sock->so_rx_apc;
00390         int cnt = sock->so_rx_cnt;
00391 
00392         for (nbq = sock->so_rx_buf; nbq; nbq = nbq->nb_next) {
00393             if (nbq->nb_ap.sz < 256) {
00394                 sock->so_rx_apc -= NutNetBufCollect(nbq, cnt);
00395                 break;
00396             }
00397             if (--apc < 8) {
00398                 break;
00399             }
00400             cnt -= nbq->nb_ap.sz;
00401         }
00402     }
00403     NutTcpOutput(sock, 0, 0);
00404 }
00405 
00406 /*
00407  * \param sock Socket descriptor.
00408  */
00409 static void NutTcpProcessSyn(TCPSOCKET * sock, IPHDR * ih, TCPHDR * th)
00410 {
00411     uint16_t mss;
00412     NUTDEVICE *dev;
00413     IFNET *nif;
00414 
00415     sock->so_local_addr = ih->ip_dst;
00416     sock->so_remote_port = th->th_sport;
00417     sock->so_remote_addr = ih->ip_src;
00418 
00419     sock->so_rx_nxt = sock->so_tx_wl1 = sock->so_rx_isn = ntohl(th->th_seq);
00420     sock->so_rx_nxt++;
00421     sock->so_tx_win = ntohs(th->th_win);
00422 
00423     /*
00424      * To avoid unnecessary fragmentation, limit the
00425      * maximum segment size to the maximum transfer
00426      * unit of our interface.
00427      */
00428     if ((dev = NutIpRouteQuery(ih->ip_src, 0)) != 0) {
00429         nif = dev->dev_icb;
00430         mss = nif->if_mtu - sizeof(IPHDR) - sizeof(TCPHDR);
00431         if (sock->so_mss == 0 || sock->so_mss > mss)
00432             sock->so_mss = mss;
00433 
00434         /* Limit output buffer size to mms */
00435         if (sock->so_devobsz > sock->so_mss)
00436             sock->so_devobsz = sock->so_mss;
00437     }
00438 }
00439 
00447 static int NutTcpProcessAck(TCPSOCKET * sock, TCPHDR * th, uint16_t length)
00448 {
00449     NETBUF *nb;
00450     uint32_t h_seq;
00451     uint32_t h_ack;
00452 
00453     /*
00454      * If remote acked something not yet send, reply immediately.
00455      */
00456     h_ack = ntohl(th->th_ack);
00457     if (SeqIsAfter(h_ack, sock->so_tx_nxt)) {
00458         sock->so_tx_flags |= SO_ACK | SO_FORCE;
00459         return 0;
00460     }
00461 
00462     /*
00463      * If the new sequence number or acknowledged sequence number
00464      * is above our last update, we adjust our transmit window.
00465      * Avoid dupe ACK processing on window updates.
00466      */
00467     if (h_ack == sock->so_tx_una) {
00468         h_seq = ntohl(th->th_seq);
00469         if (SeqIsAfter(h_seq, sock->so_tx_wl1) || (h_seq == sock->so_tx_wl1 && !SeqIsAfter(sock->so_tx_wl2, h_ack))) {
00470             sock->so_tx_win = ntohs(th->th_win);
00471             sock->so_tx_wl1 = h_seq;
00472             sock->so_tx_wl2 = h_ack;
00473         }
00474     }
00475 
00476     /*
00477      * Ignore old ACKs but wake up sleeping transmitter threads, because
00478      * the window size may have changed.
00479      */
00480     if (SeqIsAfter(sock->so_tx_una, h_ack)) {
00481         return 0;
00482     }
00483 
00484     /*
00485      * Process duplicate ACKs.
00486      */
00487     if (h_ack == sock->so_tx_una) {
00488         /*
00489          * Don't count, if nothing is waiting for ACK,
00490          * segment contains data or on SYN/FIN segments.
00491          */
00492         if (sock->so_tx_nbq && length == 0 && (th->th_flags & (TH_SYN | TH_FIN)) == 0) {
00493             /*
00494              * If dupe counter reaches it's limit, resend
00495              * the oldest unacknowledged netbuf.
00496              */
00497             if (++sock->so_tx_dup >= 3) {
00498                 sock->so_tx_dup = 0;
00499 #ifdef NUTDEBUG
00500                 if (__tcp_trf)
00501                     NutDumpTcpHeader(__tcp_trs, "RET", sock, sock->so_tx_nbq);
00502 #endif
00503                 /*
00504                  * Retransmit first unacked packet from queue.
00505                  * Actually we got much more trouble if this fails.
00506                  */
00507                 if (NutTcpStateRetranTimeout(sock))
00508                     return -1;
00509             }
00510         }
00511         return 0;
00512     }
00513 
00514     /*
00515      * We're here, so the ACK must have actually acked something
00516      */
00517     sock->so_tx_dup = 0;
00518     sock->so_tx_una = h_ack;
00519 
00520     /*
00521      * Bugfix contributed by Liu Limin: If the remote is slow and this
00522      * line is missing, then Ethernut will send a full data packet even
00523      * if the remote closed the window.
00524      */
00525     sock->so_tx_win = ntohs(th->th_win);
00526 
00527     /* 
00528      * Do round trip time calculation.
00529      */
00530     if (sock->so_rtt_seq && SeqIsAfter(h_ack, sock->so_rtt_seq))
00531         NutTcpCalcRtt (sock);
00532     sock->so_rtt_seq = 0;
00533     /*
00534      * Remove all acknowledged netbufs.
00535      */
00536     while ((nb = sock->so_tx_nbq) != 0) {
00537         /* Calculate the sequence beyond this netbuf. */
00538         h_seq = ntohl(((TCPHDR *) (nb->nb_tp.vp))->th_seq) + nb->nb_ap.sz;
00539         if (((TCPHDR *) (nb->nb_tp.vp))->th_flags & (TH_SYN | TH_FIN)) {
00540             h_seq++;
00541         }
00542         //@@@printf ("[%04X]*: processack, check seq#: %lu\n", (u_short) sock, h_seq);
00543         if (SeqIsAfter(h_seq, h_ack)) {
00544             break;
00545         }
00546         sock->so_tx_nbq = nb->nb_next;
00547         NutNetBufFree(nb);
00548     }
00549 
00550     /*
00551      * Reset retransmit timer and wake up waiting transmissions.
00552      */
00553     if (sock->so_tx_nbq) {
00554         sock->so_retran_time = (uint16_t) NutGetMillis() | 1;
00555     } else {
00556         sock->so_retran_time = 0;
00557     }
00558     sock->so_retransmits = 0;
00559 
00560     return 0;
00561 }
00562 
00563 
00564 
00565 /* ================================================================
00566  * State changes.
00567  * ================================================================
00568  */
00577 static int NutTcpStateChange(TCPSOCKET * sock, uint8_t state)
00578 {
00579     int rc = 0;
00580     ureg_t txf = 0;
00581 
00582     switch (sock->so_state) {
00583         /* Handle the most common case first. */
00584     case TCPS_ESTABLISHED:
00585         switch (state) {
00586         case TCPS_FIN_WAIT_1:
00587             /*
00588              * Closed by application.
00589              */
00590             sock->so_tx_flags |= SO_FIN | SO_ACK;
00591             txf = 1;
00592 
00593 #ifdef RTLCONNECTHACK
00594             /*
00595              * Hack alert!
00596              * On the RTL8019AS we got a problem. Because of not handling
00597              * the CHRDY line, the controller drops outgoing packets when
00598              * a browser opens multiple connections concurrently, producing
00599              * several short incoming packets. Empirical test showed, that
00600              * a slight delay during connects and disconnects helped to
00601              * remarkably reduce this problem.
00602              */
00603             NutDelay(5);
00604 #endif
00605             break;
00606         case TCPS_CLOSE_WAIT:
00607             /*
00608              * FIN received.
00609              */
00610             sock->so_tx_flags |= SO_ACK | SO_FORCE;
00611             txf = 1;
00612             break;
00613         default:
00614             rc = -1;
00615             break;
00616         }
00617         break;
00618 
00619     case TCPS_LISTEN:
00620         /*
00621          * SYN received.
00622          */
00623         if (state == TCPS_SYN_RECEIVED) {
00624             sock->so_tx_flags |= SO_SYN | SO_ACK;
00625             txf = 1;
00626 #ifdef RTLCONNECTHACK
00627             /*
00628              * Hack alert!
00629              * On the RTL8019AS we got a problem. Because of not handling
00630              * the CHRDY line, the controller drops outgoing packets when
00631              * a browser opens multiple connections concurrently, producing
00632              * several short incoming packets. Empirical test showed, that
00633              * a slight delay during connects and disconnects helped to
00634              * remarkably reduce this problem.
00635              */
00636             NutDelay(5);
00637 #endif
00638         } else
00639             rc = -1;
00640         break;
00641 
00642     case TCPS_SYN_SENT:
00643         switch (state) {
00644         case TCPS_LISTEN:
00645             /*
00646              * RST received on passive socket.
00647              */
00648             break;
00649         case TCPS_SYN_RECEIVED:
00650             /*
00651              * SYN received.
00652              */
00653             sock->so_tx_flags |= SO_SYN | SO_ACK;
00654             txf = 1;
00655             break;
00656         case TCPS_ESTABLISHED:
00657             /*
00658              * SYNACK received.
00659              */
00660             sock->so_tx_flags |= SO_ACK | SO_FORCE;
00661             txf = 1;
00662             break;
00663         default:
00664             rc = -1;
00665             break;
00666         }
00667         break;
00668 
00669     case TCPS_SYN_RECEIVED:
00670         switch (state) {
00671         case TCPS_LISTEN:
00672             /*
00673              * RST received on passive socket.
00674              */
00675             break;
00676         case TCPS_ESTABLISHED:
00677             /*
00678              * ACK of SYN received.
00679              */
00680             break;
00681         case TCPS_FIN_WAIT_1:
00682             /*
00683              * Closed by application.
00684              */
00685             sock->so_tx_flags |= SO_FIN;
00686             txf = 1;
00687             break;
00688         case TCPS_CLOSE_WAIT:
00689             /*
00690              * FIN received.
00691              */
00692             sock->so_tx_flags |= SO_FIN | SO_ACK;
00693             txf = 1;
00694             break;
00695         default:
00696             rc = -1;
00697             break;
00698         }
00699         break;
00700 
00701     case TCPS_FIN_WAIT_1:
00702         switch (state) {
00703         case TCPS_FIN_WAIT_1:
00704         case TCPS_FIN_WAIT_2:
00705             /*
00706              * ACK of FIN received.
00707              */
00708             break;
00709         case TCPS_CLOSING:
00710             /*
00711              * FIN received.
00712              */
00713             sock->so_tx_flags |= SO_ACK | SO_FORCE;
00714             txf = 1;
00715             break;
00716         case TCPS_TIME_WAIT:
00717             /*
00718              * FIN and ACK of FIN received.
00719              */
00720             break;
00721         default:
00722             rc = -1;
00723             break;
00724         }
00725         break;
00726 
00727     case TCPS_FIN_WAIT_2:
00728         /*
00729          * FIN received.
00730          */
00731         if (state != TCPS_TIME_WAIT)
00732             rc = -1;
00733         sock->so_tx_flags |= SO_ACK | SO_FORCE;
00734         txf = 1;
00735         break;
00736 
00737     case TCPS_CLOSE_WAIT:
00738         /*
00739          * Closed by application.
00740          */
00741         if (state == TCPS_LAST_ACK) {
00742             sock->so_tx_flags |= SO_FIN | SO_ACK;
00743             txf = 1;
00744         } else
00745             rc = -1;
00746         break;
00747 
00748     case TCPS_CLOSING:
00749         /*
00750          * ACK of FIN received.
00751          */
00752         if (state != TCPS_TIME_WAIT)
00753             rc = -1;
00754         break;
00755 
00756     case TCPS_LAST_ACK:
00757         rc = -1;
00758         break;
00759 
00760     case TCPS_TIME_WAIT:
00761         rc = -1;
00762         break;
00763 
00764     case TCPS_CLOSED:
00765         switch (state) {
00766         case TCPS_LISTEN:
00767             /*
00768              * Passive open by application.
00769              */
00770             break;
00771         case TCPS_SYN_SENT:
00772             /*
00773              * Active open by application.
00774              */
00775             sock->so_tx_flags |= SO_SYN;
00776             txf = 1;
00777             break;
00778         default:
00779             rc = -1;
00780             break;
00781         }
00782         break;
00783     }
00784 #ifdef NUTDEBUG
00785     if (__tcp_trf) {
00786         fprintf(__tcp_trs, " %04x-", (unsigned int) sock);
00787         if (rc)
00788             NutDumpSockState(__tcp_trs, sock->so_state, "**ERR ", "**>");
00789         NutDumpSockState(__tcp_trs, state, "[>", "]");
00790     }
00791 #endif
00792 
00793     if (rc == 0) {
00794         sock->so_state = state;
00795         if (txf && NutTcpOutput(sock, 0, 0)) {
00796             if (state == TCPS_SYN_SENT) {
00797                 rc = -1;
00798                 sock->so_last_error = EHOSTDOWN;
00799                 NutEventPostAsync(&sock->so_ac_tq);
00800             }
00801         }
00802         if (state == TCPS_CLOSE_WAIT) {
00803             /*
00804              * Inform application.
00805              */
00806             NutEventBroadcast(&sock->so_rx_tq);
00807             NutEventBroadcast(&sock->so_pc_tq);
00808             NutEventBroadcast(&sock->so_ac_tq);
00809         }
00810     }
00811     return rc;
00812 }
00813 
00814 /* ================================================================
00815  * Application events.
00816  * ================================================================
00817  */
00826 int NutTcpStatePassiveOpenEvent(TCPSOCKET * sock)
00827 {
00828     if (sock->so_state != TCPS_CLOSED)
00829         return (sock->so_last_error = EISCONN);
00830 
00831     NutTcpStateChange(sock, TCPS_LISTEN);
00832 
00833     /*
00834      * Block application.
00835      */
00836     NutEventWait(&sock->so_pc_tq, 0);
00837 
00838     return 0;
00839 }
00840 
00851 int NutTcpStateActiveOpenEvent(TCPSOCKET * sock)
00852 {
00853     /*
00854      * Switch state to SYN_SENT. This will
00855      * transmit a SYN packet.
00856      */
00857     NutTcpStateChange(sock, TCPS_SYN_SENT);
00858 
00859     /*
00860      * Block application.
00861      */
00862      if(sock->so_state == TCPS_SYN_SENT)
00863         NutEventWait(&sock->so_ac_tq, 0);
00864 
00865     if (sock->so_state != TCPS_ESTABLISHED && sock->so_state != TCPS_CLOSE_WAIT)
00866         return -1;
00867 
00868     return 0;
00869 }
00870 
00883 int NutTcpStateCloseEvent(TCPSOCKET * sock)
00884 {
00885     if (sock == 0)
00886         return -1;
00887 
00888     NutThreadYield();
00889 
00890     switch (sock->so_state) {
00891     case TCPS_LISTEN:
00892     case TCPS_SYN_SENT:
00893     case TCPS_CLOSED:
00894         /*
00895          * No connection yet, immediately destroy the socket.
00896          */
00897         NutTcpDestroySocket(sock);
00898         break;
00899 
00900     case TCPS_SYN_RECEIVED:
00901     case TCPS_ESTABLISHED:
00902         /*
00903          * Send a FIN and wait for ACK or FIN.
00904          */
00905         //@@@printf ("[%04X]ESTABLISHED: going to FIN_WAIT_1\n", (u_short) sock);
00906         NutTcpStateChange(sock, TCPS_FIN_WAIT_1);
00907         break;
00908 
00909     case TCPS_CLOSE_WAIT:
00910         /* 
00911          * RFC 793 is wrong. 
00912          */
00913         //@@@printf("[%04X]CLOSE_WAIT: going to LAST_ACK\n", (u_short) sock);
00914         NutTcpStateChange(sock, TCPS_LAST_ACK);
00915         break;
00916 
00917     case TCPS_FIN_WAIT_1:
00918     case TCPS_FIN_WAIT_2:
00919     case TCPS_CLOSING:
00920     case TCPS_LAST_ACK:
00921     case TCPS_TIME_WAIT:
00922         sock->so_last_error = EALREADY;
00923         return -1;
00924 
00925     default:
00926         sock->so_last_error = ENOTCONN;
00927         return -1;
00928     }
00929     return 0;
00930 }
00931 
00938 int NutTcpStateWindowEvent(TCPSOCKET * sock)
00939 {
00940     if (sock == 0)
00941         return -1;
00942     sock->so_tx_flags |= SO_ACK | SO_FORCE;
00943     NutTcpOutput(sock, 0, 0);
00944 
00945     return 0;
00946 }
00947 
00948 /* ================================================================
00949  * Timeout events.
00950  * ================================================================
00951  */
00963 int NutTcpStateRetranTimeout(TCPSOCKET * sock)
00964 {
00965     NETBUF *so_tx_next;
00966     if (sock->so_retransmits++ > TCP_RETRIES_MAX)
00967     {
00968         /* Abort the socket */
00969         NutTcpAbortSocket(sock, ETIMEDOUT);
00970         return -1;
00971     } else {
00972 #ifdef NUTDEBUG
00973         if (__tcp_trf)
00974             NutDumpTcpHeader(__tcp_trs, "RET", sock, sock->so_tx_nbq);
00975 #endif
00976         /* We must save sock->so_tx_nbq->nb_next before calling NutIpOutput,
00977          * because in case of error the NETBUF is release by NutIpOutput and
00978          * not longer available.
00979          */
00980         so_tx_next = sock->so_tx_nbq->nb_next;
00981         if (NutIpOutput(IPPROTO_TCP, sock->so_remote_addr, sock->so_tx_nbq)) {
00982             /* Adjust packet queue */
00983             sock->so_tx_nbq = so_tx_next;
00984             /* Abort the socket */
00985             NutTcpAbortSocket(sock, ENETDOWN);
00986             return -1;
00987         } else {
00988             /* Restart the retransmission timer. */
00989             sock->so_retran_time = (uint16_t) NutGetMillis() | 1;
00990             return 0;
00991         }
00992     }
00993 }
00994 
00995 /* ================================================================
00996  * Segment arrival events.
00997  * ================================================================
00998  */
00999 
01009 static void NutTcpStateListen(TCPSOCKET * sock, uint8_t flags, TCPHDR * th, NETBUF * nb)
01010 {
01011     /*
01012      * Got a SYN segment. Store relevant data in our socket
01013      * structure and switch to TCPS_SYN_RECEIVED.
01014      */
01015     if ((flags & (TH_SYN | TH_ACK | TH_RST)) == TH_SYN) {
01016         NutTcpProcessSyn(sock, nb->nb_nw.vp, th);
01017         NutTcpStateChange(sock, TCPS_SYN_RECEIVED);
01018         NutNetBufFree(nb);
01019     } else
01020         NutTcpReject(nb);
01021 }
01022 
01023 
01032 static void NutTcpStateSynSent(TCPSOCKET * sock, uint8_t flags, TCPHDR * th, NETBUF * nb)
01033 {
01034     /*
01035      * Validate ACK, if set.
01036      */
01037     if (flags & TH_ACK) {
01038         if (!SeqIsBetween(ntohl(th->th_ack), sock->so_tx_isn + 1, sock->so_tx_nxt)) {
01039             NutTcpReject(nb);
01040             return;
01041         }
01042     }
01043 
01044     /*
01045      * Handle RST flag. If we were in the LISTEN state,
01046      * then we return to the LISTEN state, otherwise we
01047      * abort the connection and go to the CLOSED state.
01048      */
01049     if (flags & TH_RST) {
01050         if (flags & TH_ACK) {
01051             /*if (sock->so_pc_tq)
01052                 NutTcpStateChange(sock, TCPS_LISTEN);
01053             else */
01054                 NutTcpAbortSocket(sock, ECONNREFUSED);
01055         }
01056         NutNetBufFree(nb);
01057         return;
01058     }
01059 
01060     /*
01061      * Handle SYN flag. If we got a valid ACK too, then
01062      * our connection is established. Otherwise enter
01063      * SYNRCVD state.
01064      */
01065     if (flags & TH_SYN) {
01066         NutTcpProcessSyn(sock, nb->nb_nw.vp, th);
01067         if (flags & TH_ACK) {
01068             NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01069             NutTcpStateChange(sock, TCPS_ESTABLISHED);
01070             /* Wake up the actively connecting thread. */
01071             NutEventPost(&sock->so_ac_tq);
01072         } else {
01073             NutTcpStateChange(sock, TCPS_SYN_RECEIVED);
01074         }
01075     }
01076     NutNetBufFree(nb);
01077 }
01078 
01079 /*
01080  * \brief
01081  * Process incoming segments in SYN-RECEIVED state.
01082  *
01083  * Waiting for a confirming connection request
01084  * acknowledgment after having both received
01085  * and sent a connection request.
01086  *
01087  * \param sock Socket descriptor.
01088  * \param nb   Network buffer structure containing a TCP segment.
01089  */
01090 static void NutTcpStateSynReceived(TCPSOCKET * sock, uint8_t flags, TCPHDR * th, NETBUF * nb)
01091 {
01092     /*
01093      * If our previous ack receives a reset response,
01094      * then we fall back to the listening state.
01095      */
01096     if (flags & TH_RST) {
01097         if (sock->so_pc_tq)
01098             NutTcpStateChange(sock, TCPS_LISTEN);
01099         else 
01100             NutTcpAbortSocket(sock, ECONNREFUSED);
01101         NutNetBufFree(nb);
01102         sock->so_retran_time = 0;
01103         NutTcpDiscardBuffers(sock);
01104         return;
01105     }
01106 
01107     /*
01108      * Reject SYNs.
01109      */
01110     if (flags & TH_SYN) {
01111         NutTcpReject(nb);
01112         return;
01113     }
01114 
01115     /*
01116      * Silently discard segments without ACK.
01117      */
01118     if ((flags & TH_ACK) == 0) {
01119         NutNetBufFree(nb);
01120         return;
01121     }
01122 
01123     /*
01124      * Reject out of window sequence.
01125      */
01126     if (!SeqIsBetween(ntohl(th->th_ack), sock->so_tx_una + 1, sock->so_tx_nxt)) {
01127         NutTcpReject(nb);
01128         return;
01129     }
01130 
01131     /* Acknowledge processing. */
01132     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01133 
01134     /*
01135      * Even SYN segments may contain application data, which will be stored
01136      * in the socket's input buffer. However, there is no need to post an
01137      * event to any thread waiting for data, because our connection is not 
01138      * yet established.
01139      */
01140     if (nb->nb_ap.sz)
01141         NutTcpProcessAppData(sock, nb);
01142     else
01143         NutNetBufFree(nb);
01144 
01145     /*
01146      * Process state change.
01147      */
01148     if (flags & TH_FIN) {
01149         sock->so_rx_nxt++;
01150         NutTcpStateChange(sock, TCPS_CLOSE_WAIT);
01151     } else {
01152         NutTcpStateChange(sock, TCPS_ESTABLISHED);
01153         NutEventPost(&sock->so_pc_tq);
01154         NutEventPost(&sock->so_ac_tq);
01155     }
01156 }
01157 
01158 /*
01159  * \brief Process incoming segments from established connections.
01160  *
01161  * Received application data will be delivered to the application
01162  * until we receive a FIN segment.
01163  *
01164  * \param sock  Socket descriptor.
01165  * \param flags TCP flags.
01166  * \param th    Pointer to the TCP header within the NETBUF.
01167  * \param nb    Network buffer structure containing a TCP segment.
01168  *
01169  * \todo We may remove the unused counter of dropped segments, which
01170  *       were out of sequence.
01171  */
01172 static void NutTcpStateEstablished(TCPSOCKET * sock, uint8_t flags, TCPHDR * th, NETBUF * nb)
01173 {
01174     if (flags & TH_RST) {
01175         NutNetBufFree(nb);
01176         NutTcpAbortSocket(sock, ECONNRESET);
01177         return;
01178     }
01179 
01180     /*
01181      * Reject SYNs. Silently discard late SYNs
01182      * (Thanks to Mike Cornelius).
01183      */
01184     if (flags & TH_SYN) {
01185         if (ntohl(th->th_seq) != sock->so_rx_isn)
01186             NutTcpReject(nb);
01187         else
01188             NutNetBufFree(nb);
01189         return;
01190     }
01191 
01192     /*
01193      * Silently discard segments without ACK.
01194      */
01195     if ((flags & TH_ACK) == 0) {
01196         NutNetBufFree(nb);
01197         return;
01198     }
01199 
01200     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01201 
01202     /*
01203      * If the sequence number of the incoming segment is larger than 
01204      * expected, we probably missed one or more previous segments. Let's 
01205      * add this one to a linked list of segments received in advance and 
01206      * hope that the missing data will arrive later.
01207      */
01208     if (SeqIsAfter(ntohl(th->th_seq),sock->so_rx_nxt)) {
01209         NETBUF *nbq;
01210         NETBUF **nbqp;
01211         TCPHDR *thq;
01212         uint32_t th_seq;
01213         uint32_t thq_seq;
01214 
01215         if (nb->nb_ap.sz) {
01216             /* Keep track of the number of bytes used by packets
01217             ** received in advance. Honor a global limit. */
01218             tcp_adv_cnt += nb->nb_dl.sz + sizeof(IPHDR) + sizeof (TCPHDR) + nb->nb_ap.sz;
01219             if (tcp_adv_cnt > tcp_adv_max) {
01220                 /* Limit reached, discard the packet. */
01221                 NutNetBufFree(nb);
01222                 tcp_adv_cnt -= nb->nb_dl.sz + sizeof(IPHDR) + sizeof (TCPHDR) + nb->nb_ap.sz;
01223             } else {
01224                 nbq = sock->so_rx_nbq;
01225                 nbqp = &sock->so_rx_nbq;
01226                 while (nbq) {
01227                     thq = (TCPHDR *) (nbq->nb_tp.vp);
01228                     th_seq = ntohl(th->th_seq);
01229                     thq_seq = ntohl(thq->th_seq);
01230                     if (SeqIsAfter(thq_seq, th_seq)) {
01231                         *nbqp = nb;
01232                         nb->nb_next = nbq;
01233                         break;
01234                     }
01235                     if (th_seq == thq_seq) {
01236                         NutNetBufFree(nb);
01237                         sock->so_tx_flags |= SO_ACK | SO_FORCE;
01238                         NutTcpOutput(sock, 0, 0);
01239                         return;
01240                     }
01241                     nbqp = &nbq->nb_next;
01242                     nbq = nbq->nb_next;
01243                 }
01244                 if (nbq == 0) {
01245                     *nbqp = nb;
01246                     nb->nb_next = 0;
01247                 }
01248             }
01249         } else
01250             NutNetBufFree(nb);
01251 
01252         sock->so_tx_flags |= SO_ACK | SO_FORCE;
01253         NutTcpOutput(sock, 0, 0);
01254         return;
01255     }
01256 
01257     /*
01258      * Acknowledge any sequence numbers not expected, 
01259      * even if they do not contain any data. Keepalive
01260      * packets contain a sequence number one less
01261      * than the next data expected and they do not 
01262      * contain any data.
01263      */
01264     if (ntohl(th->th_seq) != sock->so_rx_nxt) {
01265         sock->so_tx_flags |= SO_ACK | SO_FORCE;
01266         /* This seems to be unused. */
01267         sock->so_oos_drop++;
01268         NutNetBufFree(nb);
01269         NutTcpOutput(sock, 0, 0);
01270     } 
01271 
01272     /*
01273      * The sequence number is exactly what we expected.
01274      */
01275     else if (nb->nb_ap.sz) {
01276         NutTcpProcessAppData(sock, nb);
01277         /*
01278          * Process segments we may have received in advance.
01279          */
01280         while ((nb = sock->so_rx_nbq) != 0) {
01281             th = (TCPHDR *) (nb->nb_tp.vp);
01282             if (SeqIsAfter(ntohl(th->th_seq), sock->so_rx_nxt))
01283                 break;
01284             sock->so_rx_nbq = nb->nb_next;
01285             /* Update the heap space used by packets 
01286             ** received in advance. */
01287             tcp_adv_cnt -= nb->nb_dl.sz + sizeof(IPHDR) + sizeof (TCPHDR) + nb->nb_ap.sz;
01288             if (ntohl(th->th_seq) == sock->so_rx_nxt) {
01289                 NutTcpProcessAppData(sock, nb);
01290                 flags |= th->th_flags;
01291             } else
01292                 NutNetBufFree(nb);
01293         }
01294         /* Wake up a thread waiting for data. */
01295         NutEventPost(&sock->so_rx_tq);
01296     } else {
01297         NutNetBufFree(nb);
01298         //sock->so_tx_flags |= SO_ACK | SO_FORCE;
01299         //NutTcpOutput(sock, 0, 0);
01300     }
01301     if (flags & TH_FIN) {
01302         //@@@printf ("[%04X]ESTABLISHED: going to CLOSE_WAIT\n", (u_short) sock);
01303         sock->so_rx_nxt++;
01304         NutTcpStateChange(sock, TCPS_CLOSE_WAIT);
01305     }
01306 }
01307 
01308 /*
01309  * \brief Process incoming segments in FIN-WAIT1 state.
01310  *
01311  * Waiting for a connection termination request
01312  * from the remote, or an acknowledgment of the
01313  * connection termination request previously sent.
01314  *
01315  * The application already closed the socket.
01316  *
01317  * \param sock Socket descriptor.
01318  * \param nb   Network buffer structure containing a TCP segment.
01319  *
01320  * \todo The out of sync case seems to be ignored. Anyway, do we
01321  *       really need to process application data in this state?
01322  */
01323 static void NutTcpStateFinWait1(TCPSOCKET * sock, uint8_t flags, TCPHDR * th, NETBUF * nb)
01324 {
01325     //@@@printf ("[%04X]FIN_WAIT_1: incomming segment, IP %04X\n", (u_short) sock, ntohs(((IPHDR*)nb->nb_nw.vp)->ip_id));
01326     if (flags & TH_RST) {
01327         NutNetBufFree(nb);
01328         NutTcpDestroySocket(sock);
01329         return;
01330     }
01331 
01332     /*
01333      * Reject SYNs.
01334      */
01335     if (flags & TH_SYN) {
01336         NutTcpReject(nb);
01337         return;
01338     }
01339 
01340     /*
01341      * Silently discard segments without ACK.
01342      */
01343     if ((flags & TH_ACK) == 0) {
01344         NutNetBufFree(nb);
01345         return;
01346     }
01347 
01348     //@@@if (flags & TH_FIN) printf ("[%04X]FIN_WAIT_1: received FIN\n", (u_short) sock);
01349     //@@@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);
01350     
01351     //@@@printf ("[%04X]FIN_WAIT_1:  pre processack, nbq: %04X\n", (u_short) sock, (u_short) sock->so_tx_nbq);
01352     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01353     //@@@printf ("[%04X]FIN_WAIT_1: post processack, nbq: %04X\n", (u_short) sock, (u_short) sock->so_tx_nbq);
01354 
01355     /*
01356      * All segments had been acknowledged, including our FIN.
01357      */
01358     if (sock->so_tx_nxt == sock->so_tx_una) {
01359         //@@@printf ("[%04X]FIN_WAIT_1: going to FIN_WAIT_2\n", (u_short) sock);
01360         NutTcpStateChange(sock, TCPS_FIN_WAIT_2);
01361     }
01362 
01363     /*
01364      * Process application data and release the network buffer.
01365      * Is this really required?
01366      */
01367     if (nb->nb_ap.sz) {
01368         NutTcpProcessAppData(sock, nb);
01369         /* Wake up a thread waiting for data. */
01370         NutEventPost(&sock->so_rx_tq);
01371     }
01372     else
01373         NutNetBufFree(nb);
01374 
01375     if (flags & TH_FIN) {
01376         sock->so_rx_nxt++;
01377         /* 
01378          * Our FIN has been acked.
01379          */
01380         sock->so_time_wait = 0;
01381         //@@@printf ("[%04X]FIN_WAIT_1: going to CLOSING\n", (u_short) sock);
01382         if (sock->so_state == TCPS_FIN_WAIT_2)
01383             NutTcpStateChange(sock, TCPS_TIME_WAIT);
01384         else
01385             NutTcpStateChange(sock, TCPS_CLOSING);
01386     }
01387 }
01388 
01389 /*
01390  * \brief Process incoming segments in FIN-WAIT2 state.
01391  *
01392  * Waiting for a connection termination request
01393  * from the remote.
01394  *
01395  * The application already closed the socket.
01396  *
01397  * \param sock Socket descriptor.
01398  * \param nb   Network buffer structure containing a TCP segment.
01399  *
01400  * \todo There's probably no need to process application data.
01401  */
01402 static void NutTcpStateFinWait2(TCPSOCKET * sock, uint8_t flags, TCPHDR * th, NETBUF * nb)
01403 {
01404     //@@@printf ("[%04X]FIN_WAIT_2: incomming segment, IP %04X\n", (u_short) sock, ntohs(((IPHDR*)nb->nb_nw.vp)->ip_id));
01405     if (flags & TH_RST) {
01406         NutNetBufFree(nb);
01407         NutTcpDestroySocket(sock);
01408         return;
01409     }
01410 
01411     /*
01412      * Reject SYNs.
01413      */
01414     if (flags & TH_SYN) {
01415         NutTcpReject(nb);
01416         return;
01417     }
01418 
01419     /*
01420      * Silently discard segments without ACK.
01421      */
01422     if ((flags & TH_ACK) == 0) {
01423         NutNetBufFree(nb);
01424         return;
01425     }
01426 
01427     //@@@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);
01428     /*
01429      * Process acknowledge and application data and release the 
01430      * network buffer.
01431      */
01432     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01433 
01434     //@@@if (sock->so_tx_nbq) printf ("[%04X]FIN_WAIT_2: xmit buffer not empty!", (u_short) sock);
01435     /* Do we really need this? */
01436     if (nb->nb_ap.sz) {
01437         NutTcpProcessAppData(sock, nb);
01438         /* Wake up a thread waiting for data. */
01439         NutEventPost(&sock->so_rx_tq);
01440     }
01441     else
01442         NutNetBufFree(nb);
01443 
01444     if (flags & TH_FIN) {
01445         sock->so_rx_nxt++;
01446         sock->so_time_wait = 0;
01447         //@@@printf ("[%04X]FIN_WAIT_2: going to TIME_WAIT\n", (u_short) sock);
01448         NutTcpStateChange(sock, TCPS_TIME_WAIT);
01449     }
01450 }
01451 
01452 /*
01453  * \brief
01454  * Process incoming segments in CLOSE-WAIT state.
01455  *
01456  * Waiting for a connection termination request
01457  * from the local application.
01458  *
01459  * \param sock Socket descriptor.
01460  * \param nb   Network buffer structure containing a TCP segment.
01461  */
01462 static void NutTcpStateCloseWait(TCPSOCKET * sock, uint8_t flags, TCPHDR * th, NETBUF * nb)
01463 {
01464     //@@@printf ("[%04X]CLOSE_WAIT: incomming segment, IP %04X\n", (u_short) sock, ((IPHDR*)nb->nb_nw.vp)->ip_id);
01465     if (flags & TH_RST) {
01466         NutNetBufFree(nb);
01467         NutTcpAbortSocket(sock, ECONNRESET);
01468         return;
01469     }
01470 
01471     /*
01472      * Reject SYNs.
01473      */
01474     if (flags & TH_SYN) {
01475         NutTcpReject(nb);
01476         return;
01477     }
01478 
01479     /*
01480      * Silently discard segments without ACK.
01481      */
01482     if ((flags & TH_ACK) == 0) {
01483         NutNetBufFree(nb);
01484         return;
01485     }
01486 
01487     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01488 
01489     NutNetBufFree(nb);
01490 }
01491 
01492 /*
01493  * \brief
01494  * Process incoming segments in CLOSING state.
01495  *
01496  * Waiting for a connection termination request
01497  * acknowledgment from the remote.
01498  *
01499  * The application already closed the socket.
01500  *
01501  * \param sock Socket descriptor.
01502  * \param nb   Network buffer structure containing a TCP segment.
01503  */
01504 static void NutTcpStateClosing(TCPSOCKET * sock, uint8_t flags, TCPHDR * th, NETBUF * nb)
01505 {
01506     //@@@printf ("[%04X]CLOSING: Incomming segment\n", (u_short) sock);
01507     if (flags & TH_RST) {
01508         NutNetBufFree(nb);
01509         NutTcpDestroySocket(sock);
01510         return;
01511     }
01512 
01513     /*
01514      * Reject SYNs.
01515      */
01516     if (flags & TH_SYN) {
01517         NutTcpReject(nb);
01518         return;
01519     }
01520 
01521     /*
01522      * Silently discard segments without ACK.
01523      */
01524     if ((flags & TH_ACK) == 0) {
01525         NutNetBufFree(nb);
01526         return;
01527     }
01528 
01529     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01530 
01531     /*
01532      * All segments had been acknowledged, including our FIN.
01533      */
01534     if (sock->so_tx_nxt == sock->so_tx_una) {
01535         sock->so_time_wait = 0;
01536         NutTcpStateChange(sock, TCPS_TIME_WAIT);
01537         //@@@printf ("[%04X]CLOSING: Going to TIME_WAIT\n", (u_short) sock);
01538     }
01539     //@@@else printf ("[%04X]CLOSING: NOT changing state\n", (u_short) sock);
01540 
01541     NutNetBufFree(nb);
01542 }
01543 
01558 static void NutTcpStateLastAck(TCPSOCKET * sock, uint8_t flags, TCPHDR * th, NETBUF * nb)
01559 {
01560     //@@@printf ("[%04X]LAST_ACK: incomming segment, IP %04X\n", (u_short) sock, ((IPHDR*)nb->nb_nw.vp)->ip_id);
01561     if (flags & TH_RST) {
01562         NutNetBufFree(nb);
01563         NutTcpDestroySocket(sock);
01564         return;
01565     }
01566 
01567     /*
01568      * Reject SYNs.
01569      */
01570     if (flags & TH_SYN) {
01571         NutTcpReject(nb);
01572         return;
01573     }
01574 
01575     /*
01576      * Silently discard segments without ACK.
01577      */
01578     if ((flags & TH_ACK) == 0) {
01579         NutNetBufFree(nb);
01580         return;
01581     }
01582 
01583     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01584     NutNetBufFree(nb);
01585 
01586     if (sock->so_tx_nxt == sock->so_tx_una) 
01587         NutTcpDestroySocket(sock);
01588     //@@@else printf ("[%04X]LAST_ACK: no destroy sock\n", (u_short) sock);
01589 }
01590 
01601 static void NutTcpStateProcess(TCPSOCKET * sock, NETBUF * nb)
01602 {
01603     uint32_t tx_win;
01604     uint32_t tx_una;
01605     TCPHDR *th = (TCPHDR *) nb->nb_tp.vp;
01606     uint8_t flags = th->th_flags;
01607 
01608 #ifdef NUTDEBUG
01609     if (__tcp_trf) {
01610         fprintf(__tcp_trs, " %04x-", (unsigned int) sock);
01611         NutDumpSockState(__tcp_trs, sock->so_state, "[", ">]");
01612     }
01613 #endif
01614     switch (sock->so_state) {
01615         /* Handle the most common case first. */
01616     case TCPS_ESTABLISHED:
01617         tx_win = sock->so_tx_win;
01618         tx_una = sock->so_tx_una;
01619         NutTcpStateEstablished(sock, flags, th, nb);
01620         /* Wake up all threads waiting for transmit, if something interesting happened. */
01621         if(sock->so_state != TCPS_ESTABLISHED || /* Status changed. */
01622            sock->so_tx_win > tx_win ||           /* Windows changed. */
01623            sock->so_tx_una != tx_una) {          /* Unacknowledged data changed. */
01624             NutEventBroadcast(&sock->so_tx_tq);
01625         }
01626         break;
01627     case TCPS_LISTEN:
01628         NutTcpStateListen(sock, flags, th, nb);
01629         break;
01630     case TCPS_SYN_SENT:
01631         NutTcpStateSynSent(sock, flags, th, nb);
01632         break;
01633     case TCPS_SYN_RECEIVED:
01634         NutTcpStateSynReceived(sock, flags, th, nb);
01635         break;
01636     case TCPS_FIN_WAIT_1:
01637         NutTcpStateFinWait1(sock, flags, th, nb);
01638         break;
01639     case TCPS_FIN_WAIT_2:
01640         NutTcpStateFinWait2(sock, flags, th, nb);
01641         break;
01642     case TCPS_CLOSE_WAIT:
01643         NutTcpStateCloseWait(sock, flags, th, nb);
01644         break;
01645     case TCPS_CLOSING:
01646         NutTcpStateClosing(sock, flags, th, nb);
01647         break;
01648     case TCPS_LAST_ACK:
01649         NutTcpStateLastAck(sock, flags, th, nb);
01650         break;
01651     case TCPS_TIME_WAIT:
01652         /*
01653          * Ignore everything while in TIME_WAIT state.
01654          */
01655         NutNetBufFree(nb);
01656         break;
01657     case TCPS_CLOSED:
01658         /*
01659          * Reject everything while in CLOSED state.
01660          */
01661         NutTcpReject(nb);
01662         break;
01663     default:
01664         NutNetBufFree(nb);
01665         break;
01666     }
01667 }
01668 
01675 THREAD(NutTcpSm, arg)
01676 {
01677     NETBUF *nb;
01678     NETBUF *nbx;
01679     TCPHDR *th;
01680     IPHDR *ih;
01681     TCPSOCKET *sock;
01682     uint8_t tac = 0;
01683 
01684     /*
01685      * It won't help giving us a higher priority than the application
01686      * code. We depend on the speed of the reading application.
01687      */
01688     NutThreadSetPriority (32);
01689     
01690     for (;;) {
01691         if (++tac > 3 || NutEventWait(&tcp_in_rdy, 200)) {
01692             tac = 0;
01693             for (sock = tcpSocketList; sock; sock = sock->so_next) {
01694 
01695                 /*
01696                  * Send late acks.
01697                  */
01698                 if (sock->so_tx_flags & SO_ACK) {
01699                     sock->so_tx_flags |= SO_FORCE;
01700                     NutTcpOutput(sock, 0, 0);
01701                 }
01702 
01703                 /*
01704                  * Process retransmit timer.
01705                  */
01706                 if (sock->so_tx_nbq && sock->so_retran_time) {
01707                     if ((uint16_t)((uint16_t)NutGetMillis() - (sock->so_retran_time & ~1)) >= sock->so_rtto) {
01708                         NutTcpStateRetranTimeout(sock);
01709                     }
01710                 }
01711 
01712                 /*
01713                  * Destroy sockets after timeout in TIMEWAIT state.
01714                  */
01715                 if (sock->so_state == TCPS_TIME_WAIT || sock->so_state == TCPS_FIN_WAIT_2) {
01716                     if (sock->so_time_wait++ >= 9) {
01717                         NutTcpDestroySocket(sock);
01718                         break;
01719                     }
01720                 }
01721 
01722                 /*
01723                  * Recover from SYN flood attacks.
01724                  */
01725                 else if (sock->so_state == TCPS_SYN_RECEIVED) {
01726                     if (sock->so_time_wait++ >= 45) {
01727                         sock->so_state = TCPS_LISTEN;
01728                         sock->so_time_wait = 0;
01729                     }
01730                 }
01731             }
01732         } else {
01733             nb = tcp_in_nbq;
01734             tcp_in_nbq = 0;
01735             tcp_in_cnt = 0;
01736             while (nb) {
01737                 ih = (IPHDR *) nb->nb_nw.vp;
01738                 th = (TCPHDR *) nb->nb_tp.vp;
01739                 sock = NutTcpFindSocket(th->th_dport, th->th_sport, ih->ip_src);
01740 #ifdef NUTDEBUG
01741                 if (__tcp_trf)
01742                     NutDumpTcpHeader(__tcp_trs, " IN", sock, nb);
01743 #endif
01744                 nbx = nb->nb_next;
01745                 if (sock) {
01746                     NutTcpInputOptions(sock, nb);
01747                     NutTcpStateProcess(sock, nb);
01748                 }
01749 
01750                 /*
01751                  * Reject the segment, if no matching socket was found.
01752                  */
01753                 else
01754                     NutTcpReject(nb);
01755                 nb = nbx;
01756             }
01757         }
01758     }
01759 }
01760 
01772 void NutTcpStateMachine(NETBUF * nb)
01773 {
01774     NETBUF *nbp;
01775     uint16_t size;
01776 
01777     nb->nb_next = 0;
01778 
01779     /*
01780      * Incoming TCP segments are rejected and released if no TCP
01781      * sockets have been opened. Not doing so would add them
01782      * to the queue and never release the NETBUF. Thanks to
01783      * Ralph Mason for this fix.
01784      */
01785     if (tcpThread == 0) {
01786         NutTcpReject(nb);
01787         return;
01788     }
01789 
01790     if ((nbp = tcp_in_nbq) == 0) {
01791         tcp_in_nbq = nb;
01792         NutEventPost(&tcp_in_rdy);
01793     } else {
01794         size = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz;
01795         if (tcp_in_cnt + size + 2048 < NutHeapAvailable()) {
01796             tcp_in_cnt += size;
01797             while (nbp->nb_next)
01798                 nbp = nbp->nb_next;
01799             nbp->nb_next = nb;
01800             NutEventPost(&tcp_in_rdy);
01801         } else
01802             NutNetBufFree(nb);
01803     }
01804 }
01805 
01814 int NutTcpInitStateMachine(void)
01815 {
01816     if (tcpThread == 0 && (tcpThread = NutThreadCreate("tcpsm", NutTcpSm, NULL, 
01817         (NUT_THREAD_TCPSMSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD)) == 0)
01818         return -1;
01819     return 0;
01820 }
01821 
01835 int NutTcpAbortSocket(TCPSOCKET * sock, uint16_t last_error)
01836 {
01837     sock->so_last_error = last_error;
01838     sock->so_retran_time = 0;
01839     sock->so_time_wait = 0;
01840     /*
01841      * If NutTcpCloseSocket was already called, we have to change
01842      * to TCPS_TIME_WAIT state, otherwise the socket will not be destroyed.
01843      * For the other cases just go to TCPS_CLOSED.
01844      */
01845     if (sock->so_state >= TCPS_FIN_WAIT_1)      /* FIN_WAIT_1, FIN_WAIT_2, CLOSING, LAST_ACK, TIME_WAIT */
01846         sock->so_state = TCPS_TIME_WAIT;
01847     else
01848         sock->so_state = TCPS_CLOSED;
01849     NutTcpDiscardBuffers(sock);
01850     NutEventBroadcast(&sock->so_rx_tq);
01851     NutEventBroadcast(&sock->so_tx_tq);
01852     NutEventBroadcast(&sock->so_pc_tq);
01853     NutEventBroadcast(&sock->so_ac_tq);
01854     return 0;
01855 }
01856 

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