tcpsm.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2007 by egnite Software GmbH
00003  * Copyright (C) 2009 by egnite GmbH
00004  *
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted provided that the following conditions
00009  * are met:
00010  *
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. Neither the name of the copyright holders nor the names of
00017  *    contributors may be used to endorse or promote products derived
00018  *    from this software without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00021  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00024  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00027  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00028  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00029  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00030  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00031  * SUCH DAMAGE.
00032  *
00033  * For additional information see http://www.ethernut.de/
00034  *
00035  * -
00036  * Portions Copyright (C) 2000 David J. Hudson <dave@humbug.demon.co.uk>
00037  *
00038  * This file is distributed in the hope that it will be useful, but WITHOUT
00039  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00040  * FITNESS FOR A PARTICULAR PURPOSE.
00041  *
00042  * You can redistribute this file and/or modify it under the terms of the GNU
00043  * General Public License (GPL) as published by the Free Software Foundation;
00044  * either version 2 of the License, or (at your discretion) any later version.
00045  * See the accompanying file "copying-gpl.txt" for more details.
00046  *
00047  * As a special exception to the GPL, permission is granted for additional
00048  * uses of the text contained in this file.  See the accompanying file
00049  * "copying-liquorice.txt" for details.
00050  * -
00051  * Portions Copyright (c) 1983, 1993 by
00052  *  The Regents of the University of California.  All rights reserved.
00053  *
00054  * Redistribution and use in source and binary forms, with or without
00055  * modification, are permitted provided that the following conditions
00056  * are met:
00057  * 1. Redistributions of source code must retain the above copyright
00058  *    notice, this list of conditions and the following disclaimer.
00059  * 2. Redistributions in binary form must reproduce the above copyright
00060  *    notice, this list of conditions and the following disclaimer in the
00061  *    documentation and/or other materials provided with the distribution.
00062  * 3. Neither the name of the University nor the names of its contributors
00063  *    may be used to endorse or promote products derived from this software
00064  *    without specific prior written permission.
00065  *
00066  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00067  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00068  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00069  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00070  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00071  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00072  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00073  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00074  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00075  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00076  * SUCH DAMAGE.
00077  * -
00078  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
00079  *
00080  * Permission to use, copy, modify, and distribute this software for any
00081  * purpose with or without fee is hereby granted, provided that the above
00082  * copyright notice and this permission notice appear in all copies, and that
00083  * the name of Digital Equipment Corporation not be used in advertising or
00084  * publicity pertaining to distribution of the document or software without
00085  * specific, written prior permission.
00086  *
00087  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
00088  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
00089  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
00090  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
00091  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
00092  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
00093  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00094  * SOFTWARE.
00095  */
00096 
00097 /*
00098  * $Id: tcpsm.c 3170 2010-10-14 07:46:44Z hwmaier $
00099  */
00100 
00101 #include <cfg/os.h>
00102 #include <cfg/tcp.h>
00103 
00104 #include <sys/thread.h>
00105 #include <sys/heap.h>
00106 #include <sys/event.h>
00107 #include <sys/timer.h>
00108 
00109 #include <errno.h>
00110 #include <netinet/in.h>
00111 #include <netinet/ip.h>
00112 #include <net/route.h>
00113 #include <sys/socket.h>
00114 #include <netinet/tcputil.h>
00115 #include <netinet/tcp.h>
00116 
00117 #ifdef NUTDEBUG
00118 #include <net/netdebug.h>
00119 #endif
00120 
00121 #ifndef NUT_THREAD_TCPSMSTACK
00122 #if defined(__AVR__)
00123 #if defined(__GNUC__)
00124 /* avr-gcc size optimized code used 148 bytes. */
00125 #define NUT_THREAD_TCPSMSTACK   256
00126 #else
00127 /* icc-avr v7.19 used 312 bytes. */
00128 #define NUT_THREAD_TCPSMSTACK   512
00129 #endif
00130 #else
00131 /* arm-elf-gcc used 260 bytes with size optimized, 644 bytes with debug code. */
00132 #define NUT_THREAD_TCPSMSTACK   384
00133 #endif
00134 #endif
00135 
00136 #ifndef TCP_RETRIES_MAX
00137 #define TCP_RETRIES_MAX         7
00138 #endif
00139 
00140 extern TCPSOCKET *tcpSocketList;
00141 
00146 
00147 HANDLE tcp_in_rdy;
00148 NETBUF *volatile tcp_in_nbq;
00149 static uint16_t tcp_in_cnt;
00150 static HANDLE tcpThread = 0;
00151 
00152 #ifndef TCP_COLLECT_INADV
00153 #define TCP_COLLECT_INADV   8
00154 #endif
00155 
00156 #ifndef TCP_COLLECT_SLIMIT
00157 #define TCP_COLLECT_SLIMIT  256
00158 #endif
00159 
00160 #ifndef TCP_BACKLOG_MAX
00161 #define TCP_BACKLOG_MAX     8
00162 #endif
00163 
00164 #if TCP_BACKLOG_MAX
00165 #ifndef TCP_BACKLOG_TIME
00166 #define TCP_BACKLOG_TIME    5
00167 #endif
00168 static NETBUF *tcp_backlog[TCP_BACKLOG_MAX];
00169 static uint_fast8_t tcp_backlog_time[TCP_BACKLOG_MAX];
00170 #endif
00171 
00172 static size_t tcp_adv_cnt;
00173 static size_t tcp_adv_max = TCP_WINSIZE;
00174 
00175 static void NutTcpStateProcess(TCPSOCKET * sock, NETBUF * nb);
00176 
00177 /* ================================================================
00178  * Helper functions
00179  * ================================================================
00180  */
00181 
00182 #if TCP_BACKLOG_MAX
00183 static int NutTcpBacklogAdd(NETBUF *nb)
00184 {
00185     uint_fast8_t i;
00186     uint_fast8_t n = TCP_BACKLOG_MAX;
00187     IPHDR *ih = (IPHDR *) nb->nb_nw.vp;
00188     TCPHDR *th = (TCPHDR *) nb->nb_tp.vp;
00189 
00190     /* Process SYN segments only. */
00191     if ((th->th_flags & (TH_SYN | TH_ACK | TH_RST)) == TH_SYN) {
00192         for (i = 0; i < TCP_BACKLOG_MAX; i++) {
00193             if (tcp_backlog[i] == NULL) {
00194                 /* Remember the first free entry. */
00195                 if (n == TCP_BACKLOG_MAX) {
00196                     n = i;
00197                 }
00198             }
00199             else if (((IPHDR *) tcp_backlog[i]->nb_nw.vp)->ip_src == ih->ip_src &&
00200                     ((TCPHDR *) tcp_backlog[i]->nb_tp.vp)->th_sport == th->th_sport) {
00201                 /* Already received a SYN. Either the remote is too impatient
00202                 ** or we are too busy. Kill this entry and reject the SYN. */
00203                 NutNetBufFree(tcp_backlog[i]);
00204                 tcp_backlog[i] = NULL;
00205                 return -1;
00206             }
00207         }
00208         /* First SYN from the remote for this port.
00209         ** If there is a free entry left, then use it. */
00210         if (n != TCP_BACKLOG_MAX) {
00211             tcp_backlog[n] = nb;
00212             tcp_backlog_time[n] = 0;
00213             return 0;
00214         }
00215     }
00216     return -1;
00217 }
00218 
00219 static NETBUF *NutTcpBacklogCheck(uint16_t port)
00220 {
00221     NETBUF *nb;
00222     uint_fast8_t i;
00223     uint_fast8_t n = TCP_BACKLOG_MAX;
00224 
00225     for (i = 0; i < TCP_BACKLOG_MAX; i++) {
00226         if (tcp_backlog[i]) {
00227             if (((TCPHDR *) tcp_backlog[i]->nb_tp.vp)->th_dport == port) {
00228                 if (n == TCP_BACKLOG_MAX || tcp_backlog_time[i] > tcp_backlog_time[n]) {
00229                     n = i;
00230                 }
00231             }
00232         }
00233     }
00234     if (n == TCP_BACKLOG_MAX) {
00235         nb = NULL;
00236     } else {
00237         nb = tcp_backlog[n];
00238         tcp_backlog[n] = NULL;
00239     }
00240     return nb;
00241 }
00242 
00243 static NETBUF *NutTcpBacklogTimer(void)
00244 {
00245     NETBUF *nb;
00246     uint_fast8_t i;
00247     uint_fast8_t n = TCP_BACKLOG_MAX;
00248 
00249     for (i = 0; i < TCP_BACKLOG_MAX; i++) {
00250         if (tcp_backlog[i]) {
00251             if (tcp_backlog_time[i] < TCP_BACKLOG_TIME) {
00252                 tcp_backlog_time[i]++;
00253             } else {
00254                 n = i;
00255             }
00256         }
00257     }
00258     if (n == TCP_BACKLOG_MAX) {
00259         nb = NULL;
00260     } else {
00261         nb = tcp_backlog[n];
00262         tcp_backlog[n] = NULL;
00263     }
00264     return nb;
00265 }
00266 #endif /* TCP_BACKLOG_MAX */
00267 
00276 static void NutTcpInputOptions(TCPSOCKET * sock, NETBUF * nb)
00277 {
00278     uint8_t *cp;
00279     uint16_t s;
00280 
00281     /* any options there? */
00282     if (nb->nb_tp.sz <= sizeof (TCPHDR))
00283         return;
00284 
00285     /* loop through available options */
00286     for (cp = ((uint8_t*) nb->nb_tp.vp) + sizeof(TCPHDR); (*cp != TCPOPT_EOL)
00287        && (cp - (uint8_t *)nb->nb_tp.vp < (int)nb->nb_tp.sz); )
00288     {
00289         switch (*cp)
00290         {
00291             /* On NOP just proceed to next option */
00292             case TCPOPT_NOP:
00293                 cp++;
00294                 continue;
00295 
00296             /* Read MAXSEG option */
00297             case TCPOPT_MAXSEG:
00298                 s = ntohs(*((uint16_t*)&cp[2]));
00299                 if (s < sock->so_mss)
00300                     sock->so_mss = s;
00301                 cp += TCPOLEN_MAXSEG;
00302                 break;
00303             /* Ignore any other options */
00304             default:
00305                 cp += *(uint8_t*) (cp + 1);
00306                 break;
00307         }
00308     }
00309 }
00310 
00319 static void NutTcpProcessAppData(TCPSOCKET * sock, NETBUF * nb)
00320 {
00321     /*
00322      * Add the NETBUF to the socket's input buffer.
00323      */
00324     if (sock->so_rx_buf) {
00325         NETBUF *nbp = sock->so_rx_buf;
00326 
00327         while (nbp->nb_next)
00328             nbp = nbp->nb_next;
00329         nbp->nb_next = nb;
00330     } else
00331         sock->so_rx_buf = nb;
00332 
00333     /*
00334      * Update the number of bytes available in the socket's input buffer
00335      * and the sequence number we expect next.
00336      */
00337     sock->so_rx_cnt += nb->nb_ap.sz;
00338     sock->so_rx_nxt += nb->nb_ap.sz;
00339 
00340     /*
00341      * Reduce our TCP window size.
00342      */
00343     if (nb->nb_ap.sz >= sock->so_rx_win)
00344         sock->so_rx_win = 0;
00345     else
00346         sock->so_rx_win -= nb->nb_ap.sz;
00347 
00348     /*
00349      * Set the socket's ACK flag. This will enable ACK transmission in
00350      * the next outgoing segment. If no more NETBUFs are queued, we
00351      * force immediate transmission of the ACK.
00352      */
00353     sock->so_tx_flags |= SO_ACK;
00354     if (nb->nb_next)
00355         nb->nb_next = 0;
00356     else
00357         sock->so_tx_flags |= SO_FORCE;
00358 
00359     if (++sock->so_rx_apc > TCP_COLLECT_INADV) {
00360         NETBUF *nbq;
00361         int_fast8_t apc = sock->so_rx_apc;
00362         int cnt = sock->so_rx_cnt;
00363 
00364         for (nbq = sock->so_rx_buf; nbq; nbq = nbq->nb_next) {
00365             if (nbq->nb_ap.sz < TCP_COLLECT_SLIMIT) {
00366                 sock->so_rx_apc -= NutNetBufCollect(nbq, cnt);
00367                 break;
00368             }
00369             if (--apc < 8) {
00370                 break;
00371             }
00372             cnt -= nbq->nb_ap.sz;
00373         }
00374     }
00375     NutTcpOutput(sock, 0, 0);
00376 }
00377 
00378 /*
00379  * \param sock Socket descriptor.
00380  */
00381 static void NutTcpProcessSyn(TCPSOCKET * sock, IPHDR * ih, TCPHDR * th)
00382 {
00383     uint16_t mss;
00384     NUTDEVICE *dev;
00385     IFNET *nif;
00386 
00387     sock->so_local_addr = ih->ip_dst;
00388     sock->so_remote_port = th->th_sport;
00389     sock->so_remote_addr = ih->ip_src;
00390 
00391     sock->so_rx_nxt = sock->so_tx_wl1 = sock->so_rx_isn = ntohl(th->th_seq);
00392     sock->so_rx_nxt++;
00393     sock->so_tx_win = ntohs(th->th_win);
00394 
00395     /*
00396      * To avoid unnecessary fragmentation, limit the
00397      * maximum segment size to the maximum transfer
00398      * unit of our interface.
00399      */
00400     if ((dev = NutIpRouteQuery(ih->ip_src, 0)) != 0) {
00401         nif = dev->dev_icb;
00402         mss = nif->if_mtu - sizeof(IPHDR) - sizeof(TCPHDR);
00403         if (sock->so_mss == 0 || sock->so_mss > mss)
00404             sock->so_mss = mss;
00405 
00406         /* Limit output buffer size to mms */
00407         if (sock->so_devobsz > sock->so_mss)
00408             sock->so_devobsz = sock->so_mss;
00409     }
00410 }
00411 
00419 static int NutTcpProcessAck(TCPSOCKET * sock, TCPHDR * th, uint16_t length)
00420 {
00421     NETBUF *nb;
00422     uint32_t h_seq;
00423     uint32_t h_ack;
00424 
00425     /*
00426      * If remote acked something not yet send, reply immediately.
00427      */
00428     h_ack = ntohl(th->th_ack);
00429     if (SeqIsAfter(h_ack, sock->so_tx_nxt)) {
00430         sock->so_tx_flags |= SO_ACK | SO_FORCE;
00431         return 0;
00432     }
00433 
00434     /*
00435      * If the new sequence number or acknowledged sequence number
00436      * is above our last update, we adjust our transmit window.
00437      * Avoid dupe ACK processing on window updates.
00438      */
00439     if (h_ack == sock->so_tx_una) {
00440         h_seq = ntohl(th->th_seq);
00441         if (SeqIsAfter(h_seq, sock->so_tx_wl1) || (h_seq == sock->so_tx_wl1 && !SeqIsAfter(sock->so_tx_wl2, h_ack))) {
00442             sock->so_tx_win = ntohs(th->th_win);
00443             sock->so_tx_wl1 = h_seq;
00444             sock->so_tx_wl2 = h_ack;
00445         }
00446     }
00447 
00448     /*
00449      * Ignore old ACKs but wake up sleeping transmitter threads, because
00450      * the window size may have changed.
00451      */
00452     if (SeqIsAfter(sock->so_tx_una, h_ack)) {
00453         return 0;
00454     }
00455 
00456     /*
00457      * Process duplicate ACKs.
00458      */
00459     if (h_ack == sock->so_tx_una) {
00460         /*
00461          * Don't count, if nothing is waiting for ACK,
00462          * segment contains data or on SYN/FIN segments.
00463          */
00464         if (sock->so_tx_nbq && length == 0 && (th->th_flags & (TH_SYN | TH_FIN)) == 0) {
00465             /*
00466              * If dupe counter reaches it's limit, resend
00467              * the oldest unacknowledged netbuf.
00468              */
00469             if (++sock->so_tx_dup >= 3) {
00470                 sock->so_tx_dup = 0;
00471 #ifdef NUTDEBUG
00472                 if (__tcp_trf & NET_DBG_SOCKSTATE)
00473                     NutDumpTcpHeader(__tcp_trs, "RET", sock, sock->so_tx_nbq);
00474 #endif
00475                 /*
00476                  * Retransmit first unacked packet from queue.
00477                  * Actually we got much more trouble if this fails.
00478                  */
00479                 if (NutTcpStateRetranTimeout(sock))
00480                     return -1;
00481             }
00482         }
00483         return 0;
00484     }
00485 
00486     /*
00487      * We're here, so the ACK must have actually acked something
00488      */
00489     sock->so_tx_dup = 0;
00490     sock->so_tx_una = h_ack;
00491 
00492     /*
00493      * Bugfix contributed by Liu Limin: If the remote is slow and this
00494      * line is missing, then Ethernut will send a full data packet even
00495      * if the remote closed the window.
00496      */
00497     sock->so_tx_win = ntohs(th->th_win);
00498 
00499     /*
00500      * Do round trip time calculation.
00501      */
00502     if (sock->so_rtt_seq && SeqIsAfter(h_ack, sock->so_rtt_seq))
00503         NutTcpCalcRtt (sock);
00504     sock->so_rtt_seq = 0;
00505     /*
00506      * Remove all acknowledged netbufs.
00507      */
00508     while ((nb = sock->so_tx_nbq) != 0) {
00509         /* Calculate the sequence beyond this netbuf. */
00510         h_seq = ntohl(((TCPHDR *) (nb->nb_tp.vp))->th_seq) + nb->nb_ap.sz;
00511         if (((TCPHDR *) (nb->nb_tp.vp))->th_flags & (TH_SYN | TH_FIN)) {
00512             h_seq++;
00513         }
00514         //@@@printf ("[%04X]*: processack, check seq#: %lu\n", (u_short) sock, h_seq);
00515         if (SeqIsAfter(h_seq, h_ack)) {
00516             break;
00517         }
00518         sock->so_tx_nbq = nb->nb_next;
00519         NutNetBufFree(nb);
00520     }
00521 
00522     /*
00523      * Reset retransmit timer and wake up waiting transmissions.
00524      */
00525     if (sock->so_tx_nbq) {
00526         sock->so_retran_time = (uint16_t) NutGetMillis() | 1;
00527     } else {
00528         sock->so_retran_time = 0;
00529     }
00530     sock->so_retransmits = 0;
00531 
00532     return 0;
00533 }
00534 
00535 
00536 
00537 /* ================================================================
00538  * State changes.
00539  * ================================================================
00540  */
00549 static int NutTcpStateChange(TCPSOCKET * sock, uint8_t state)
00550 {
00551     int rc = 0;
00552     ureg_t txf = 0;
00553 
00554     switch (sock->so_state) {
00555         /* Handle the most common case first. */
00556     case TCPS_ESTABLISHED:
00557         switch (state) {
00558         case TCPS_FIN_WAIT_1:
00559             /*
00560              * Closed by application.
00561              */
00562             sock->so_tx_flags |= SO_FIN | SO_ACK;
00563             txf = 1;
00564 
00565 #ifdef RTLCONNECTHACK
00566             /*
00567              * Hack alert!
00568              * On the RTL8019AS we got a problem. Because of not handling
00569              * the CHRDY line, the controller drops outgoing packets when
00570              * a browser opens multiple connections concurrently, producing
00571              * several short incoming packets. Empirical test showed, that
00572              * a slight delay during connects and disconnects helped to
00573              * remarkably reduce this problem.
00574              */
00575             NutDelay(5);
00576 #endif
00577             break;
00578         case TCPS_CLOSE_WAIT:
00579             /*
00580              * FIN received.
00581              */
00582             sock->so_tx_flags |= SO_ACK | SO_FORCE;
00583             txf = 1;
00584             break;
00585         default:
00586             rc = -1;
00587             break;
00588         }
00589         break;
00590 
00591     case TCPS_LISTEN:
00592         /*
00593          * SYN received.
00594          */
00595         if (state == TCPS_SYN_RECEIVED) {
00596             sock->so_tx_flags |= SO_SYN | SO_ACK;
00597             txf = 1;
00598 #ifdef RTLCONNECTHACK
00599             /*
00600              * Hack alert!
00601              * On the RTL8019AS we got a problem. Because of not handling
00602              * the CHRDY line, the controller drops outgoing packets when
00603              * a browser opens multiple connections concurrently, producing
00604              * several short incoming packets. Empirical test showed, that
00605              * a slight delay during connects and disconnects helped to
00606              * remarkably reduce this problem.
00607              */
00608             NutDelay(5);
00609 #endif
00610         } else
00611             rc = -1;
00612         break;
00613 
00614     case TCPS_SYN_SENT:
00615         switch (state) {
00616         case TCPS_LISTEN:
00617             /*
00618              * RST received on passive socket.
00619              */
00620             break;
00621         case TCPS_SYN_RECEIVED:
00622             /*
00623              * SYN received.
00624              */
00625             sock->so_tx_flags |= SO_SYN | SO_ACK;
00626             txf = 1;
00627             break;
00628         case TCPS_ESTABLISHED:
00629             /*
00630              * SYNACK received.
00631              */
00632             sock->so_tx_flags |= SO_ACK | SO_FORCE;
00633             txf = 1;
00634             break;
00635         default:
00636             rc = -1;
00637             break;
00638         }
00639         break;
00640 
00641     case TCPS_SYN_RECEIVED:
00642         switch (state) {
00643         case TCPS_LISTEN:
00644             /*
00645              * RST received on passive socket.
00646              */
00647             break;
00648         case TCPS_ESTABLISHED:
00649             /*
00650              * ACK of SYN received.
00651              */
00652             break;
00653         case TCPS_FIN_WAIT_1:
00654             /*
00655              * Closed by application.
00656              */
00657             sock->so_tx_flags |= SO_FIN;
00658             txf = 1;
00659             break;
00660         case TCPS_CLOSE_WAIT:
00661             /*
00662              * FIN received.
00663              */
00664             sock->so_tx_flags |= SO_FIN | SO_ACK;
00665             txf = 1;
00666             break;
00667         default:
00668             rc = -1;
00669             break;
00670         }
00671         break;
00672 
00673     case TCPS_FIN_WAIT_1:
00674         switch (state) {
00675         case TCPS_FIN_WAIT_1:
00676         case TCPS_FIN_WAIT_2:
00677             /*
00678              * ACK of FIN received.
00679              */
00680             break;
00681         case TCPS_CLOSING:
00682             /*
00683              * FIN received.
00684              */
00685             sock->so_tx_flags |= SO_ACK | SO_FORCE;
00686             txf = 1;
00687             break;
00688         case TCPS_TIME_WAIT:
00689             /*
00690              * FIN and ACK of FIN received.
00691              */
00692             break;
00693         default:
00694             rc = -1;
00695             break;
00696         }
00697         break;
00698 
00699     case TCPS_FIN_WAIT_2:
00700         /*
00701          * FIN received.
00702          */
00703         if (state != TCPS_TIME_WAIT)
00704             rc = -1;
00705         sock->so_tx_flags |= SO_ACK | SO_FORCE;
00706         txf = 1;
00707         break;
00708 
00709     case TCPS_CLOSE_WAIT:
00710         /*
00711          * Closed by application.
00712          */
00713         if (state == TCPS_LAST_ACK) {
00714             sock->so_tx_flags |= SO_FIN | SO_ACK;
00715             txf = 1;
00716         } else
00717             rc = -1;
00718         break;
00719 
00720     case TCPS_CLOSING:
00721         /*
00722          * ACK of FIN received.
00723          */
00724         if (state != TCPS_TIME_WAIT)
00725             rc = -1;
00726         break;
00727 
00728     case TCPS_LAST_ACK:
00729         rc = -1;
00730         break;
00731 
00732     case TCPS_TIME_WAIT:
00733         rc = -1;
00734         break;
00735 
00736     case TCPS_CLOSED:
00737         switch (state) {
00738         case TCPS_LISTEN:
00739             /*
00740              * Passive open by application.
00741              */
00742             break;
00743         case TCPS_SYN_SENT:
00744             /*
00745              * Active open by application.
00746              */
00747             sock->so_tx_flags |= SO_SYN;
00748             txf = 1;
00749             break;
00750         default:
00751             rc = -1;
00752             break;
00753         }
00754         break;
00755     }
00756 #ifdef NUTDEBUG
00757     if (__tcp_trf & NET_DBG_SOCKSTATE) {
00758         fprintf(__tcp_trs, " %04x-", (unsigned int) sock);
00759         if (rc)
00760             NutDumpSockState(__tcp_trs, sock->so_state, "**ERR ", "**>");
00761         NutDumpSockState(__tcp_trs, state, "[>", "]");
00762     }
00763 #endif
00764 
00765     if (rc == 0) {
00766         sock->so_state = state;
00767         if (txf && NutTcpOutput(sock, 0, 0)) {
00768             if (state == TCPS_SYN_SENT) {
00769                 rc = -1;
00770                 sock->so_last_error = EHOSTDOWN;
00771                 NutEventPostAsync(&sock->so_ac_tq);
00772             }
00773         }
00774         if (state == TCPS_CLOSE_WAIT) {
00775             /*
00776              * Inform application.
00777              */
00778             NutEventBroadcast(&sock->so_rx_tq);
00779             NutEventBroadcast(&sock->so_pc_tq);
00780             NutEventBroadcast(&sock->so_ac_tq);
00781         }
00782     }
00783     return rc;
00784 }
00785 
00786 /* ================================================================
00787  * Application events.
00788  * ================================================================
00789  */
00798 int NutTcpStatePassiveOpenEvent(TCPSOCKET * sock)
00799 {
00800     if (sock->so_state != TCPS_CLOSED)
00801         return (sock->so_last_error = EISCONN);
00802 
00803     NutTcpStateChange(sock, TCPS_LISTEN);
00804 
00805 #if TCP_BACKLOG_MAX
00806     {
00807         /* If a SYN segment is already waiting in the backlog,
00808         ** then process it and return to the caller. */
00809         NETBUF *nb = NutTcpBacklogCheck(sock->so_local_port);
00810         if (nb) {
00811             NutTcpInputOptions(sock, nb);
00812             NutTcpStateProcess(sock, nb);
00813 
00814             return 0;
00815         }
00816     }
00817     if (NutEventWait(&sock->so_pc_tq, sock->so_read_to)) {
00818         sock->so_state = TCPS_CLOSED;
00819         return (sock->so_last_error = ETIMEDOUT);
00820     }
00821 #else
00822     /* For backward compatibility we simply block the application.
00823     ** If we do not have a backlog, then timing out would not make
00824     ** much sense anyway, because incoming connection attempts will
00825     ** be immediately rejected. */
00826     NutEventWait(&sock->so_pc_tq, 0);
00827 #endif /* TCP_BACKLOG_MAX */
00828 
00829     return 0;
00830 }
00831 
00842 int NutTcpStateActiveOpenEvent(TCPSOCKET * sock)
00843 {
00844     /*
00845      * Switch state to SYN_SENT. This will
00846      * transmit a SYN packet.
00847      */
00848     NutTcpStateChange(sock, TCPS_SYN_SENT);
00849 
00850     /*
00851      * Block application.
00852      */
00853      if(sock->so_state == TCPS_SYN_SENT)
00854         NutEventWait(&sock->so_ac_tq, 0);
00855 
00856     if (sock->so_state != TCPS_ESTABLISHED && sock->so_state != TCPS_CLOSE_WAIT)
00857         return -1;
00858 
00859     return 0;
00860 }
00861 
00874 int NutTcpStateCloseEvent(TCPSOCKET * sock)
00875 {
00876     if (sock == 0)
00877         return -1;
00878 
00879     NutThreadYield();
00880 
00881     switch (sock->so_state) {
00882     case TCPS_LISTEN:
00883     case TCPS_SYN_SENT:
00884     case TCPS_CLOSED:
00885         /*
00886          * No connection yet, immediately destroy the socket.
00887          */
00888         NutTcpDestroySocket(sock);
00889         break;
00890 
00891     case TCPS_SYN_RECEIVED:
00892     case TCPS_ESTABLISHED:
00893         /*
00894          * Send a FIN and wait for ACK or FIN.
00895          */
00896         //@@@printf ("[%04X]ESTABLISHED: going to FIN_WAIT_1\n", (u_short) sock);
00897         NutTcpStateChange(sock, TCPS_FIN_WAIT_1);
00898         break;
00899 
00900     case TCPS_CLOSE_WAIT:
00901         /*
00902          * RFC 793 is wrong.
00903          */
00904         //@@@printf("[%04X]CLOSE_WAIT: going to LAST_ACK\n", (u_short) sock);
00905         NutTcpStateChange(sock, TCPS_LAST_ACK);
00906         break;
00907 
00908     case TCPS_FIN_WAIT_1:
00909     case TCPS_FIN_WAIT_2:
00910     case TCPS_CLOSING:
00911     case TCPS_LAST_ACK:
00912     case TCPS_TIME_WAIT:
00913         sock->so_last_error = EALREADY;
00914         return -1;
00915 
00916     default:
00917         sock->so_last_error = ENOTCONN;
00918         return -1;
00919     }
00920     return 0;
00921 }
00922 
00929 int NutTcpStateWindowEvent(TCPSOCKET * sock)
00930 {
00931     if (sock == 0)
00932         return -1;
00933     sock->so_tx_flags |= SO_ACK | SO_FORCE;
00934     NutTcpOutput(sock, 0, 0);
00935 
00936     return 0;
00937 }
00938 
00939 /* ================================================================
00940  * Timeout events.
00941  * ================================================================
00942  */
00954 int NutTcpStateRetranTimeout(TCPSOCKET * sock)
00955 {
00956     NETBUF *so_tx_next;
00957     if (sock->so_retransmits++ > TCP_RETRIES_MAX)
00958     {
00959         /* Abort the socket */
00960         NutTcpAbortSocket(sock, ETIMEDOUT);
00961         return -1;
00962     } else {
00963 #ifdef NUTDEBUG
00964         if (__tcp_trf & NET_DBG_SOCKSTATE)
00965             NutDumpTcpHeader(__tcp_trs, "RET", sock, sock->so_tx_nbq);
00966 #endif
00967         /* We must save sock->so_tx_nbq->nb_next before calling NutIpOutput,
00968          * because in case of error the NETBUF is release by NutIpOutput and
00969          * not longer available.
00970          */
00971         so_tx_next = sock->so_tx_nbq->nb_next;
00972         if (NutIpOutput(IPPROTO_TCP, sock->so_remote_addr, sock->so_tx_nbq)) {
00973             /* Adjust packet queue */
00974             sock->so_tx_nbq = so_tx_next;
00975             /* Abort the socket */
00976             NutTcpAbortSocket(sock, ENETDOWN);
00977             return -1;
00978         } else {
00979             /* Restart the retransmission timer. */
00980             sock->so_retran_time = (uint16_t) NutGetMillis() | 1;
00981             return 0;
00982         }
00983     }
00984 }
00985 
00986 /* ================================================================
00987  * Segment arrival events.
00988  * ================================================================
00989  */
00990 
01000 static void NutTcpStateListen(TCPSOCKET * sock, uint8_t flags, TCPHDR * th, NETBUF * nb)
01001 {
01002     /*
01003      * Got a SYN segment. Store relevant data in our socket
01004      * structure and switch to TCPS_SYN_RECEIVED.
01005      */
01006     if ((flags & (TH_SYN | TH_ACK | TH_RST)) == TH_SYN) {
01007         NutTcpProcessSyn(sock, nb->nb_nw.vp, th);
01008         NutTcpStateChange(sock, TCPS_SYN_RECEIVED);
01009         NutNetBufFree(nb);
01010     } else
01011         NutTcpReject(nb);
01012 }
01013 
01014 
01023 static void NutTcpStateSynSent(TCPSOCKET * sock, uint8_t flags, TCPHDR * th, NETBUF * nb)
01024 {
01025     /*
01026      * Validate ACK, if set.
01027      */
01028     if (flags & TH_ACK) {
01029         if (!SeqIsBetween(ntohl(th->th_ack), sock->so_tx_isn + 1, sock->so_tx_nxt)) {
01030             NutTcpReject(nb);
01031             return;
01032         }
01033     }
01034 
01035     /*
01036      * Handle RST flag. If we were in the LISTEN state,
01037      * then we return to the LISTEN state, otherwise we
01038      * abort the connection and go to the CLOSED state.
01039      */
01040     if (flags & TH_RST) {
01041         if (flags & TH_ACK) {
01042             /*if (sock->so_pc_tq)
01043                 NutTcpStateChange(sock, TCPS_LISTEN);
01044             else */
01045                 NutTcpAbortSocket(sock, ECONNREFUSED);
01046         }
01047         NutNetBufFree(nb);
01048         return;
01049     }
01050 
01051     /*
01052      * Handle SYN flag. If we got a valid ACK too, then
01053      * our connection is established. Otherwise enter
01054      * SYNRCVD state.
01055      */
01056     if (flags & TH_SYN) {
01057         NutTcpProcessSyn(sock, nb->nb_nw.vp, th);
01058         if (flags & TH_ACK) {
01059             NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01060             NutTcpStateChange(sock, TCPS_ESTABLISHED);
01061             /* Wake up the actively connecting thread. */
01062             NutEventPost(&sock->so_ac_tq);
01063         } else {
01064             NutTcpStateChange(sock, TCPS_SYN_RECEIVED);
01065         }
01066     }
01067     NutNetBufFree(nb);
01068 }
01069 
01070 /*
01071  * \brief
01072  * Process incoming segments in SYN-RECEIVED state.
01073  *
01074  * Waiting for a confirming connection request
01075  * acknowledgment after having both received
01076  * and sent a connection request.
01077  *
01078  * \param sock Socket descriptor.
01079  * \param nb   Network buffer structure containing a TCP segment.
01080  */
01081 static void NutTcpStateSynReceived(TCPSOCKET * sock, uint8_t flags, TCPHDR * th, NETBUF * nb)
01082 {
01083     /*
01084      * If our previous ack receives a reset response,
01085      * then we fall back to the listening state.
01086      */
01087     if (flags & TH_RST) {
01088         if (sock->so_pc_tq)
01089             NutTcpStateChange(sock, TCPS_LISTEN);
01090         else
01091             NutTcpAbortSocket(sock, ECONNREFUSED);
01092         NutNetBufFree(nb);
01093         sock->so_retran_time = 0;
01094         NutTcpDiscardBuffers(sock);
01095         return;
01096     }
01097 
01098     /*
01099      * Reject SYNs.
01100      */
01101     if (flags & TH_SYN) {
01102         NutTcpReject(nb);
01103         return;
01104     }
01105 
01106     /*
01107      * Silently discard segments without ACK.
01108      */
01109     if ((flags & TH_ACK) == 0) {
01110         NutNetBufFree(nb);
01111         return;
01112     }
01113 
01114     /*
01115      * Reject out of window sequence.
01116      */
01117     if (!SeqIsBetween(ntohl(th->th_ack), sock->so_tx_una + 1, sock->so_tx_nxt)) {
01118         NutTcpReject(nb);
01119         return;
01120     }
01121 
01122     /* Acknowledge processing. */
01123     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01124 
01125     /*
01126      * Even SYN segments may contain application data, which will be stored
01127      * in the socket's input buffer. However, there is no need to post an
01128      * event to any thread waiting for data, because our connection is not
01129      * yet established.
01130      */
01131     if (nb->nb_ap.sz)
01132         NutTcpProcessAppData(sock, nb);
01133     else
01134         NutNetBufFree(nb);
01135 
01136     /*
01137      * Process state change.
01138      */
01139     if (flags & TH_FIN) {
01140         sock->so_rx_nxt++;
01141         NutTcpStateChange(sock, TCPS_CLOSE_WAIT);
01142     } else {
01143         NutTcpStateChange(sock, TCPS_ESTABLISHED);
01144         NutEventPost(&sock->so_pc_tq);
01145         NutEventPost(&sock->so_ac_tq);
01146     }
01147 }
01148 
01149 /*
01150  * \brief Process incoming segments from established connections.
01151  *
01152  * Received application data will be delivered to the application
01153  * until we receive a FIN segment.
01154  *
01155  * \param sock  Socket descriptor.
01156  * \param flags TCP flags.
01157  * \param th    Pointer to the TCP header within the NETBUF.
01158  * \param nb    Network buffer structure containing a TCP segment.
01159  *
01160  * \todo We may remove the unused counter of dropped segments, which
01161  *       were out of sequence.
01162  */
01163 static void NutTcpStateEstablished(TCPSOCKET * sock, uint8_t flags, TCPHDR * th, NETBUF * nb)
01164 {
01165     if (flags & TH_RST) {
01166         NutNetBufFree(nb);
01167         NutTcpAbortSocket(sock, ECONNRESET);
01168         return;
01169     }
01170 
01171     /*
01172      * Reject SYNs. Silently discard late SYNs
01173      * (Thanks to Mike Cornelius).
01174      */
01175     if (flags & TH_SYN) {
01176         if (ntohl(th->th_seq) != sock->so_rx_isn)
01177             NutTcpReject(nb);
01178         else
01179             NutNetBufFree(nb);
01180         return;
01181     }
01182 
01183     /*
01184      * Silently discard segments without ACK.
01185      */
01186     if ((flags & TH_ACK) == 0) {
01187         NutNetBufFree(nb);
01188         return;
01189     }
01190 
01191     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01192 
01193     /*
01194      * If the sequence number of the incoming segment is larger than
01195      * expected, we probably missed one or more previous segments. Let's
01196      * add this one to a linked list of segments received in advance and
01197      * hope that the missing data will arrive later.
01198      */
01199     if (SeqIsAfter(ntohl(th->th_seq),sock->so_rx_nxt)) {
01200         NETBUF *nbq;
01201         NETBUF **nbqp;
01202         TCPHDR *thq;
01203         uint32_t th_seq;
01204         uint32_t thq_seq;
01205 
01206         if (nb->nb_ap.sz) {
01207             /* Keep track of the number of bytes used by packets
01208             ** received in advance. Honor a global limit. */
01209             tcp_adv_cnt += nb->nb_dl.sz + sizeof(IPHDR) + sizeof (TCPHDR) + nb->nb_ap.sz;
01210             if (tcp_adv_cnt > tcp_adv_max) {
01211                 /* Limit reached, discard the packet. */
01212                 NutNetBufFree(nb);
01213                 tcp_adv_cnt -= nb->nb_dl.sz + sizeof(IPHDR) + sizeof (TCPHDR) + nb->nb_ap.sz;
01214             } else {
01215                 nbq = sock->so_rx_nbq;
01216                 nbqp = &sock->so_rx_nbq;
01217                 while (nbq) {
01218                     thq = (TCPHDR *) (nbq->nb_tp.vp);
01219                     th_seq = ntohl(th->th_seq);
01220                     thq_seq = ntohl(thq->th_seq);
01221                     if (SeqIsAfter(thq_seq, th_seq)) {
01222                         *nbqp = nb;
01223                         nb->nb_next = nbq;
01224                         break;
01225                     }
01226                     if (th_seq == thq_seq) {
01227                         NutNetBufFree(nb);
01228                         sock->so_tx_flags |= SO_ACK | SO_FORCE;
01229                         NutTcpOutput(sock, 0, 0);
01230                         return;
01231                     }
01232                     nbqp = &nbq->nb_next;
01233                     nbq = nbq->nb_next;
01234                 }
01235                 if (nbq == 0) {
01236                     *nbqp = nb;
01237                     nb->nb_next = 0;
01238                 }
01239             }
01240         } else
01241             NutNetBufFree(nb);
01242 
01243         sock->so_tx_flags |= SO_ACK | SO_FORCE;
01244         NutTcpOutput(sock, 0, 0);
01245         return;
01246     }
01247 
01248     /*
01249      * Acknowledge any sequence numbers not expected,
01250      * even if they do not contain any data. Keepalive
01251      * packets contain a sequence number one less
01252      * than the next data expected and they do not
01253      * contain any data.
01254      */
01255     if (ntohl(th->th_seq) != sock->so_rx_nxt) {
01256         sock->so_tx_flags |= SO_ACK | SO_FORCE;
01257         /* This seems to be unused. */
01258         sock->so_oos_drop++;
01259         NutNetBufFree(nb);
01260         NutTcpOutput(sock, 0, 0);
01261     }
01262 
01263     /*
01264      * The sequence number is exactly what we expected.
01265      */
01266     else if (nb->nb_ap.sz) {
01267         NutTcpProcessAppData(sock, nb);
01268         /*
01269          * Process segments we may have received in advance.
01270          */
01271         while ((nb = sock->so_rx_nbq) != 0) {
01272             th = (TCPHDR *) (nb->nb_tp.vp);
01273             if (SeqIsAfter(ntohl(th->th_seq), sock->so_rx_nxt))
01274                 break;
01275             sock->so_rx_nbq = nb->nb_next;
01276             /* Update the heap space used by packets
01277             ** received in advance. */
01278             tcp_adv_cnt -= nb->nb_dl.sz + sizeof(IPHDR) + sizeof (TCPHDR) + nb->nb_ap.sz;
01279             if (ntohl(th->th_seq) == sock->so_rx_nxt) {
01280                 NutTcpProcessAppData(sock, nb);
01281                 flags |= th->th_flags;
01282             } else
01283                 NutNetBufFree(nb);
01284         }
01285         /* Wake up a thread waiting for data. */
01286         NutEventPost(&sock->so_rx_tq);
01287     } else {
01288         NutNetBufFree(nb);
01289         //sock->so_tx_flags |= SO_ACK | SO_FORCE;
01290         //NutTcpOutput(sock, 0, 0);
01291     }
01292     if (flags & TH_FIN) {
01293         //@@@printf ("[%04X]ESTABLISHED: going to CLOSE_WAIT\n", (u_short) sock);
01294         sock->so_rx_nxt++;
01295         NutTcpStateChange(sock, TCPS_CLOSE_WAIT);
01296     }
01297 }
01298 
01299 /*
01300  * \brief Process incoming segments in FIN-WAIT1 state.
01301  *
01302  * Waiting for a connection termination request
01303  * from the remote, or an acknowledgment of the
01304  * connection termination request previously sent.
01305  *
01306  * The application already closed the socket.
01307  *
01308  * \param sock Socket descriptor.
01309  * \param nb   Network buffer structure containing a TCP segment.
01310  *
01311  * \todo The out of sync case seems to be ignored. Anyway, do we
01312  *       really need to process application data in this state?
01313  */
01314 static void NutTcpStateFinWait1(TCPSOCKET * sock, uint8_t flags, TCPHDR * th, NETBUF * nb)
01315 {
01316     //@@@printf ("[%04X]FIN_WAIT_1: incomming segment, IP %04X\n", (u_short) sock, ntohs(((IPHDR*)nb->nb_nw.vp)->ip_id));
01317     if (flags & TH_RST) {
01318         NutNetBufFree(nb);
01319         NutTcpDestroySocket(sock);
01320         return;
01321     }
01322 
01323     /*
01324      * Reject SYNs.
01325      */
01326     if (flags & TH_SYN) {
01327         NutTcpReject(nb);
01328         return;
01329     }
01330 
01331     /*
01332      * Silently discard segments without ACK.
01333      */
01334     if ((flags & TH_ACK) == 0) {
01335         NutNetBufFree(nb);
01336         return;
01337     }
01338 
01339     //@@@if (flags & TH_FIN) printf ("[%04X]FIN_WAIT_1: received FIN\n", (u_short) sock);
01340     //@@@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);
01341 
01342     //@@@printf ("[%04X]FIN_WAIT_1:  pre processack, nbq: %04X\n", (u_short) sock, (u_short) sock->so_tx_nbq);
01343     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01344     //@@@printf ("[%04X]FIN_WAIT_1: post processack, nbq: %04X\n", (u_short) sock, (u_short) sock->so_tx_nbq);
01345 
01346     /*
01347      * All segments had been acknowledged, including our FIN.
01348      */
01349     if (sock->so_tx_nxt == sock->so_tx_una) {
01350         //@@@printf ("[%04X]FIN_WAIT_1: going to FIN_WAIT_2\n", (u_short) sock);
01351         NutTcpStateChange(sock, TCPS_FIN_WAIT_2);
01352     }
01353 
01354     /*
01355      * Process application data and release the network buffer.
01356      * Is this really required?
01357      */
01358     if (nb->nb_ap.sz) {
01359         NutTcpProcessAppData(sock, nb);
01360         /* Wake up a thread waiting for data. */
01361         NutEventPost(&sock->so_rx_tq);
01362     }
01363     else
01364         NutNetBufFree(nb);
01365 
01366     if (flags & TH_FIN) {
01367         sock->so_rx_nxt++;
01368         /*
01369          * Our FIN has been acked.
01370          */
01371         sock->so_time_wait = 0;
01372         //@@@printf ("[%04X]FIN_WAIT_1: going to CLOSING\n", (u_short) sock);
01373         if (sock->so_state == TCPS_FIN_WAIT_2)
01374             NutTcpStateChange(sock, TCPS_TIME_WAIT);
01375         else
01376             NutTcpStateChange(sock, TCPS_CLOSING);
01377     }
01378 }
01379 
01380 /*
01381  * \brief Process incoming segments in FIN-WAIT2 state.
01382  *
01383  * Waiting for a connection termination request
01384  * from the remote.
01385  *
01386  * The application already closed the socket.
01387  *
01388  * \param sock Socket descriptor.
01389  * \param nb   Network buffer structure containing a TCP segment.
01390  *
01391  * \todo There's probably no need to process application data.
01392  */
01393 static void NutTcpStateFinWait2(TCPSOCKET * sock, uint8_t flags, TCPHDR * th, NETBUF * nb)
01394 {
01395     //@@@printf ("[%04X]FIN_WAIT_2: incomming segment, IP %04X\n", (u_short) sock, ntohs(((IPHDR*)nb->nb_nw.vp)->ip_id));
01396     if (flags & TH_RST) {
01397         NutNetBufFree(nb);
01398         NutTcpDestroySocket(sock);
01399         return;
01400     }
01401 
01402     /*
01403      * Reject SYNs.
01404      */
01405     if (flags & TH_SYN) {
01406         NutTcpReject(nb);
01407         return;
01408     }
01409 
01410     /*
01411      * Silently discard segments without ACK.
01412      */
01413     if ((flags & TH_ACK) == 0) {
01414         NutNetBufFree(nb);
01415         return;
01416     }
01417 
01418     //@@@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);
01419     /*
01420      * Process acknowledge and application data and release the
01421      * network buffer.
01422      */
01423     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01424 
01425     //@@@if (sock->so_tx_nbq) printf ("[%04X]FIN_WAIT_2: xmit buffer not empty!", (u_short) sock);
01426     /* Do we really need this? */
01427     if (nb->nb_ap.sz) {
01428         NutTcpProcessAppData(sock, nb);
01429         /* Wake up a thread waiting for data. */
01430         NutEventPost(&sock->so_rx_tq);
01431     }
01432     else
01433         NutNetBufFree(nb);
01434 
01435     if (flags & TH_FIN) {
01436         sock->so_rx_nxt++;
01437         sock->so_time_wait = 0;
01438         //@@@printf ("[%04X]FIN_WAIT_2: going to TIME_WAIT\n", (u_short) sock);
01439         NutTcpStateChange(sock, TCPS_TIME_WAIT);
01440     }
01441 }
01442 
01443 /*
01444  * \brief
01445  * Process incoming segments in CLOSE-WAIT state.
01446  *
01447  * Waiting for a connection termination request
01448  * from the local application.
01449  *
01450  * \param sock Socket descriptor.
01451  * \param nb   Network buffer structure containing a TCP segment.
01452  */
01453 static void NutTcpStateCloseWait(TCPSOCKET * sock, uint8_t flags, TCPHDR * th, NETBUF * nb)
01454 {
01455     //@@@printf ("[%04X]CLOSE_WAIT: incomming segment, IP %04X\n", (u_short) sock, ((IPHDR*)nb->nb_nw.vp)->ip_id);
01456     if (flags & TH_RST) {
01457         NutNetBufFree(nb);
01458         NutTcpAbortSocket(sock, ECONNRESET);
01459         return;
01460     }
01461 
01462     /*
01463      * Reject SYNs.
01464      */
01465     if (flags & TH_SYN) {
01466         NutTcpReject(nb);
01467         return;
01468     }
01469 
01470     /*
01471      * Silently discard segments without ACK.
01472      */
01473     if ((flags & TH_ACK) == 0) {
01474         NutNetBufFree(nb);
01475         return;
01476     }
01477 
01478     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01479 
01480     NutNetBufFree(nb);
01481 }
01482 
01483 /*
01484  * \brief
01485  * Process incoming segments in CLOSING state.
01486  *
01487  * Waiting for a connection termination request
01488  * acknowledgment from the remote.
01489  *
01490  * The application already closed the socket.
01491  *
01492  * \param sock Socket descriptor.
01493  * \param nb   Network buffer structure containing a TCP segment.
01494  */
01495 static void NutTcpStateClosing(TCPSOCKET * sock, uint8_t flags, TCPHDR * th, NETBUF * nb)
01496 {
01497     //@@@printf ("[%04X]CLOSING: Incomming segment\n", (u_short) sock);
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 
01522     /*
01523      * All segments had been acknowledged, including our FIN.
01524      */
01525     if (sock->so_tx_nxt == sock->so_tx_una) {
01526         sock->so_time_wait = 0;
01527         NutTcpStateChange(sock, TCPS_TIME_WAIT);
01528         //@@@printf ("[%04X]CLOSING: Going to TIME_WAIT\n", (u_short) sock);
01529     }
01530     //@@@else printf ("[%04X]CLOSING: NOT changing state\n", (u_short) sock);
01531 
01532     NutNetBufFree(nb);
01533 }
01534 
01549 static void NutTcpStateLastAck(TCPSOCKET * sock, uint8_t flags, TCPHDR * th, NETBUF * nb)
01550 {
01551     //@@@printf ("[%04X]LAST_ACK: incomming segment, IP %04X\n", (u_short) sock, ((IPHDR*)nb->nb_nw.vp)->ip_id);
01552     if (flags & TH_RST) {
01553         NutNetBufFree(nb);
01554         NutTcpDestroySocket(sock);
01555         return;
01556     }
01557 
01558     /*
01559      * Reject SYNs.
01560      */
01561     if (flags & TH_SYN) {
01562         NutTcpReject(nb);
01563         return;
01564     }
01565 
01566     /*
01567      * Silently discard segments without ACK.
01568      */
01569     if ((flags & TH_ACK) == 0) {
01570         NutNetBufFree(nb);
01571         return;
01572     }
01573 
01574     NutTcpProcessAck(sock, th, nb->nb_ap.sz);
01575     NutNetBufFree(nb);
01576 
01577     if (sock->so_tx_nxt == sock->so_tx_una)
01578         NutTcpDestroySocket(sock);
01579     //@@@else printf ("[%04X]LAST_ACK: no destroy sock\n", (u_short) sock);
01580 }
01581 
01592 static void NutTcpStateProcess(TCPSOCKET * sock, NETBUF * nb)
01593 {
01594     uint32_t tx_win;
01595     uint32_t tx_una;
01596     TCPHDR *th = (TCPHDR *) nb->nb_tp.vp;
01597     uint8_t flags = th->th_flags;
01598 
01599 #ifdef NUTDEBUG
01600     if (__tcp_trf & NET_DBG_SOCKSTATE) {
01601         fprintf(__tcp_trs, " %04x-", (unsigned int) sock);
01602         NutDumpSockState(__tcp_trs, sock->so_state, "[", ">]");
01603     }
01604 #endif
01605     switch (sock->so_state) {
01606         /* Handle the most common case first. */
01607     case TCPS_ESTABLISHED:
01608         tx_win = sock->so_tx_win;
01609         tx_una = sock->so_tx_una;
01610         NutTcpStateEstablished(sock, flags, th, nb);
01611         /* Wake up all threads waiting for transmit, if something interesting happened. */
01612         if(sock->so_state != TCPS_ESTABLISHED || /* Status changed. */
01613            sock->so_tx_win > tx_win ||           /* Windows changed. */
01614            sock->so_tx_una != tx_una) {          /* Unacknowledged data changed. */
01615             NutEventBroadcast(&sock->so_tx_tq);
01616         }
01617         break;
01618     case TCPS_LISTEN:
01619         NutTcpStateListen(sock, flags, th, nb);
01620         break;
01621     case TCPS_SYN_SENT:
01622         NutTcpStateSynSent(sock, flags, th, nb);
01623         break;
01624     case TCPS_SYN_RECEIVED:
01625         NutTcpStateSynReceived(sock, flags, th, nb);
01626         break;
01627     case TCPS_FIN_WAIT_1:
01628         NutTcpStateFinWait1(sock, flags, th, nb);
01629         break;
01630     case TCPS_FIN_WAIT_2:
01631         NutTcpStateFinWait2(sock, flags, th, nb);
01632         break;
01633     case TCPS_CLOSE_WAIT:
01634         NutTcpStateCloseWait(sock, flags, th, nb);
01635         break;
01636     case TCPS_CLOSING:
01637         NutTcpStateClosing(sock, flags, th, nb);
01638         break;
01639     case TCPS_LAST_ACK:
01640         NutTcpStateLastAck(sock, flags, th, nb);
01641         break;
01642     case TCPS_TIME_WAIT:
01643         /*
01644          * Ignore everything while in TIME_WAIT state.
01645          */
01646         NutNetBufFree(nb);
01647         break;
01648     case TCPS_CLOSED:
01649         /*
01650          * Reject everything while in CLOSED state.
01651          */
01652         NutTcpReject(nb);
01653         break;
01654     default:
01655         NutNetBufFree(nb);
01656         break;
01657     }
01658 }
01659 
01666 THREAD(NutTcpSm, arg)
01667 {
01668     NETBUF *nb;
01669     NETBUF *nbx;
01670     TCPHDR *th;
01671     IPHDR *ih;
01672     TCPSOCKET *sock;
01673     uint8_t tac = 0;
01674 
01675     /*
01676      * It won't help giving us a higher priority than the application
01677      * code. We depend on the speed of the reading application.
01678      */
01679     NutThreadSetPriority (32);
01680 
01681     for (;;) {
01682         if (++tac > 3 || NutEventWait(&tcp_in_rdy, 200)) {
01683             tac = 0;
01684 
01685 #if TCP_BACKLOG_MAX
01686             /* Process backlog timer.
01687             **
01688             ** Note, that the tac counter will spoil any exact timing.
01689             ** On the other hand, if we are very busy, it may not be that
01690             ** bad to kill early SYN segments soon. */
01691             nb = NutTcpBacklogTimer();
01692             if (nb) {
01693                 NutTcpReject(nb);
01694             }
01695 #endif /* TCP_BACKLOG_MAX */
01696 
01697             for (sock = tcpSocketList; sock; sock = sock->so_next) {
01698 
01699                 /*
01700                  * Send late acks.
01701                  */
01702                 if (sock->so_tx_flags & SO_ACK) {
01703                     sock->so_tx_flags |= SO_FORCE;
01704                     NutTcpOutput(sock, 0, 0);
01705                 }
01706 
01707                 /*
01708                  * Process retransmit timer.
01709                  */
01710                 if (sock->so_tx_nbq && sock->so_retran_time) {
01711                     if ((uint16_t)((uint16_t)NutGetMillis() - (sock->so_retran_time & ~1)) >= sock->so_rtto) {
01712                         NutTcpStateRetranTimeout(sock);
01713                     }
01714                 }
01715 
01716 
01717                 /*
01718                  * Destroy sockets after timeout in TIMEWAIT state.
01719                  */
01720                 if (sock->so_state == TCPS_TIME_WAIT || sock->so_state == TCPS_FIN_WAIT_2) {
01721                     if (sock->so_time_wait++ >= 9) {
01722                         NutTcpDestroySocket(sock);
01723                         break;
01724                     }
01725                 }
01726 
01727                 /*
01728                  * Recover from SYN flood attacks.
01729                  */
01730                 else if (sock->so_state == TCPS_SYN_RECEIVED) {
01731                     if (sock->so_time_wait++ >= 45) {
01732                         sock->so_state = TCPS_LISTEN;
01733                         sock->so_time_wait = 0;
01734                     }
01735                 }
01736             }
01737         } else {
01738             nb = tcp_in_nbq;
01739             tcp_in_nbq = 0;
01740             tcp_in_cnt = 0;
01741             while (nb) {
01742                 ih = (IPHDR *) nb->nb_nw.vp;
01743                 th = (TCPHDR *) nb->nb_tp.vp;
01744                 sock = NutTcpFindSocket(th->th_dport, th->th_sport, ih->ip_src);
01745 #ifdef NUTDEBUG
01746                 if (__tcp_trf & NET_DBG_SOCKSTATE)
01747                     NutDumpTcpHeader(__tcp_trs, " IN", sock, nb);
01748 #endif
01749                 nbx = nb->nb_next;
01750                 /* If a matching socket exists, process the NETBUF. */
01751                 if (sock) {
01752                     NutTcpInputOptions(sock, nb);
01753                     NutTcpStateProcess(sock, nb);
01754                 }
01755 #if TCP_BACKLOG_MAX
01756                 /* No matching socket, try to add it to the backlog. */
01757                 else if (NutTcpBacklogAdd(nb) == 0) {
01758                 }
01759 #endif
01760                 /* No matching socket and no backlog. Reject it. */
01761                 else {
01762                     NutTcpReject(nb);
01763                 }
01764                 nb = nbx;
01765             }
01766         }
01767     }
01768 }
01769 
01781 void NutTcpStateMachine(NETBUF * nb)
01782 {
01783     NETBUF *nbp;
01784     uint16_t size;
01785 
01786     nb->nb_next = 0;
01787 
01788     /*
01789      * Incoming TCP segments are rejected and released if no TCP
01790      * sockets have been opened. Not doing so would add them
01791      * to the queue and never release the NETBUF. Thanks to
01792      * Ralph Mason for this fix.
01793      */
01794     if (tcpThread == 0) {
01795         NutTcpReject(nb);
01796         return;
01797     }
01798 
01799     if ((nbp = tcp_in_nbq) == 0) {
01800         tcp_in_nbq = nb;
01801         NutEventPost(&tcp_in_rdy);
01802     } else {
01803         size = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz;
01804         if (tcp_in_cnt + size + 2048 < NutHeapAvailable()) {
01805             tcp_in_cnt += size;
01806             while (nbp->nb_next)
01807                 nbp = nbp->nb_next;
01808             nbp->nb_next = nb;
01809             NutEventPost(&tcp_in_rdy);
01810         } else
01811             NutNetBufFree(nb);
01812     }
01813 }
01814 
01823 int NutTcpInitStateMachine(void)
01824 {
01825     if (tcpThread == 0 && (tcpThread = NutThreadCreate("tcpsm", NutTcpSm, NULL,
01826         (NUT_THREAD_TCPSMSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD)) == 0)
01827         return -1;
01828     return 0;
01829 }
01830 
01844 int NutTcpAbortSocket(TCPSOCKET * sock, uint16_t last_error)
01845 {
01846     sock->so_last_error = last_error;
01847     sock->so_retran_time = 0;
01848     sock->so_time_wait = 0;
01849     /*
01850      * If NutTcpCloseSocket was already called, we have to change
01851      * to TCPS_TIME_WAIT state, otherwise the socket will not be destroyed.
01852      * For the other cases just go to TCPS_CLOSED.
01853      */
01854     if (sock->so_state >= TCPS_FIN_WAIT_1)      /* FIN_WAIT_1, FIN_WAIT_2, CLOSING, LAST_ACK, TIME_WAIT */
01855         sock->so_state = TCPS_TIME_WAIT;
01856     else
01857         sock->so_state = TCPS_CLOSED;
01858     NutTcpDiscardBuffers(sock);
01859     NutEventBroadcast(&sock->so_rx_tq);
01860     NutEventBroadcast(&sock->so_tx_tq);
01861     NutEventBroadcast(&sock->so_pc_tq);
01862     NutEventBroadcast(&sock->so_ac_tq);
01863     return 0;
01864 }
01865 

© 2000-2010 by contributors - visit http://www.ethernut.de/