tcpsm.c

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

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