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