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