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

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