Deprecated fork of old network stack source from github. Please use official library instead: https://mbed.org/users/mbed_official/code/EthernetInterface/

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers tcp_in.c Source File

tcp_in.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * Transmission Control Protocol, incoming traffic
00004  *
00005  * The input processing functions of the TCP layer.
00006  *
00007  * These functions are generally called in the order (ip_input() ->)
00008  * tcp_input() -> * tcp_process() -> tcp_receive() (-> application).
00009  * 
00010  */
00011 
00012 /*
00013  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
00014  * All rights reserved.
00015  *
00016  * Redistribution and use in source and binary forms, with or without modification,
00017  * are permitted provided that the following conditions are met:
00018  *
00019  * 1. Redistributions of source code must retain the above copyright notice,
00020  *    this list of conditions and the following disclaimer.
00021  * 2. Redistributions in binary form must reproduce the above copyright notice,
00022  *    this list of conditions and the following disclaimer in the documentation
00023  *    and/or other materials provided with the distribution.
00024  * 3. The name of the author may not be used to endorse or promote products
00025  *    derived from this software without specific prior written permission.
00026  *
00027  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00028  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00029  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00030  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00031  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00032  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00033  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00034  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00035  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00036  * OF SUCH DAMAGE.
00037  *
00038  * This file is part of the lwIP TCP/IP stack.
00039  *
00040  * Author: Adam Dunkels <adam@sics.se>
00041  *
00042  */
00043 
00044 #include "lwip/opt.h"
00045 
00046 #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
00047 
00048 #include "lwip/tcp_impl.h"
00049 #include "lwip/def.h"
00050 #include "lwip/ip_addr.h"
00051 #include "lwip/netif.h"
00052 #include "lwip/mem.h"
00053 #include "lwip/memp.h"
00054 #include "lwip/inet_chksum.h"
00055 #include "lwip/stats.h"
00056 #include "lwip/snmp.h"
00057 #include "arch/perf.h"
00058 
00059 /* These variables are global to all functions involved in the input
00060    processing of TCP segments. They are set by the tcp_input()
00061    function. */
00062 static struct tcp_seg inseg;
00063 static struct tcp_hdr *tcphdr;
00064 static struct ip_hdr *iphdr;
00065 static u32_t seqno, ackno;
00066 static u8_t flags;
00067 static u16_t tcplen;
00068 
00069 static u8_t recv_flags;
00070 static struct pbuf *recv_data;
00071 
00072 struct tcp_pcb *tcp_input_pcb;
00073 
00074 /* Forward declarations. */
00075 static err_t tcp_process(struct tcp_pcb *pcb);
00076 static void tcp_receive(struct tcp_pcb *pcb);
00077 static void tcp_parseopt(struct tcp_pcb *pcb);
00078 
00079 static err_t tcp_listen_input(struct tcp_pcb_listen *pcb);
00080 static err_t tcp_timewait_input(struct tcp_pcb *pcb);
00081 
00082 /**
00083  * The initial input processing of TCP. It verifies the TCP header, demultiplexes
00084  * the segment between the PCBs and passes it on to tcp_process(), which implements
00085  * the TCP finite state machine. This function is called by the IP layer (in
00086  * ip_input()).
00087  *
00088  * @param p received TCP segment to process (p->payload pointing to the IP header)
00089  * @param inp network interface on which this segment was received
00090  */
00091 void
00092 tcp_input(struct pbuf *p, struct netif *inp)
00093 {
00094   struct tcp_pcb *pcb, *prev;
00095   struct tcp_pcb_listen *lpcb;
00096 #if SO_REUSE
00097   struct tcp_pcb *lpcb_prev = NULL;
00098   struct tcp_pcb_listen *lpcb_any = NULL;
00099 #endif /* SO_REUSE */
00100   u8_t hdrlen;
00101   err_t err;
00102 
00103   PERF_START;
00104 
00105   TCP_STATS_INC(tcp.recv);
00106   snmp_inc_tcpinsegs();
00107 
00108   iphdr = (struct ip_hdr *)p->payload;
00109   tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);
00110 
00111 #if TCP_INPUT_DEBUG
00112   tcp_debug_print(tcphdr);
00113 #endif
00114 
00115   /* remove header from payload */
00116   if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) {
00117     /* drop short packets */
00118     LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len));
00119     TCP_STATS_INC(tcp.lenerr);
00120     TCP_STATS_INC(tcp.drop);
00121     snmp_inc_tcpinerrs();
00122     pbuf_free(p);
00123     return;
00124   }
00125 
00126   /* Don't even process incoming broadcasts/multicasts. */
00127   if (ip_addr_isbroadcast(&current_iphdr_dest, inp) ||
00128       ip_addr_ismulticast(&current_iphdr_dest)) {
00129     TCP_STATS_INC(tcp.proterr);
00130     TCP_STATS_INC(tcp.drop);
00131     snmp_inc_tcpinerrs();
00132     pbuf_free(p);
00133     return;
00134   }
00135 
00136 #if CHECKSUM_CHECK_TCP
00137   /* Verify TCP checksum. */
00138   if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
00139       IP_PROTO_TCP, p->tot_len) != 0) {
00140       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n",
00141         inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
00142       IP_PROTO_TCP, p->tot_len)));
00143 #if TCP_DEBUG
00144     tcp_debug_print(tcphdr);
00145 #endif /* TCP_DEBUG */
00146     TCP_STATS_INC(tcp.chkerr);
00147     TCP_STATS_INC(tcp.drop);
00148     snmp_inc_tcpinerrs();
00149     pbuf_free(p);
00150     return;
00151   }
00152 #endif
00153 
00154   /* Move the payload pointer in the pbuf so that it points to the
00155      TCP data instead of the TCP header. */
00156   hdrlen = TCPH_HDRLEN(tcphdr);
00157   if(pbuf_header(p, -(hdrlen * 4))){
00158     /* drop short packets */
00159     LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n"));
00160     TCP_STATS_INC(tcp.lenerr);
00161     TCP_STATS_INC(tcp.drop);
00162     snmp_inc_tcpinerrs();
00163     pbuf_free(p);
00164     return;
00165   }
00166 
00167   /* Convert fields in TCP header to host byte order. */
00168   tcphdr->src = ntohs(tcphdr->src);
00169   tcphdr->dest = ntohs(tcphdr->dest);
00170   seqno = tcphdr->seqno = ntohl(tcphdr->seqno);
00171   ackno = tcphdr->ackno = ntohl(tcphdr->ackno);
00172   tcphdr->wnd = ntohs(tcphdr->wnd);
00173 
00174   flags = TCPH_FLAGS(tcphdr);
00175   tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0);
00176 
00177   /* Demultiplex an incoming segment. First, we check if it is destined
00178      for an active connection. */
00179   prev = NULL;
00180 
00181   
00182   for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
00183     LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED);
00184     LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
00185     LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);
00186     if (pcb->remote_port == tcphdr->src &&
00187        pcb->local_port == tcphdr->dest &&
00188        ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src) &&
00189        ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest)) {
00190 
00191       /* Move this PCB to the front of the list so that subsequent
00192          lookups will be faster (we exploit locality in TCP segment
00193          arrivals). */
00194       LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb);
00195       if (prev != NULL) {
00196         prev->next = pcb->next;
00197         pcb->next = tcp_active_pcbs;
00198         tcp_active_pcbs = pcb;
00199       }
00200       LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb);
00201       break;
00202     }
00203     prev = pcb;
00204   }
00205 
00206   if (pcb == NULL) {
00207     /* If it did not go to an active connection, we check the connections
00208        in the TIME-WAIT state. */
00209     for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
00210       LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
00211       if (pcb->remote_port == tcphdr->src &&
00212          pcb->local_port == tcphdr->dest &&
00213          ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src) &&
00214          ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest)) {
00215         /* We don't really care enough to move this PCB to the front
00216            of the list since we are not very likely to receive that
00217            many segments for connections in TIME-WAIT. */
00218         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n"));
00219         tcp_timewait_input(pcb);
00220         pbuf_free(p);
00221         return;
00222       }
00223     }
00224 
00225     /* Finally, if we still did not get a match, we check all PCBs that
00226        are LISTENing for incoming connections. */
00227     prev = NULL;
00228     for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
00229       if (lpcb->local_port == tcphdr->dest) {
00230 #if SO_REUSE
00231         if (ip_addr_cmp(&(lpcb->local_ip), &current_iphdr_dest)) {
00232           /* found an exact match */
00233           break;
00234         } else if(ip_addr_isany(&(lpcb->local_ip))) {
00235           /* found an ANY-match */
00236           lpcb_any = lpcb;
00237           lpcb_prev = prev;
00238         }
00239 #else /* SO_REUSE */
00240         if (ip_addr_cmp(&(lpcb->local_ip), &current_iphdr_dest) ||
00241             ip_addr_isany(&(lpcb->local_ip))) {
00242           /* found a match */
00243           break;
00244         }
00245 #endif /* SO_REUSE */
00246       }
00247       prev = (struct tcp_pcb *)lpcb;
00248     }
00249 #if SO_REUSE
00250     /* first try specific local IP */
00251     if (lpcb == NULL) {
00252       /* only pass to ANY if no specific local IP has been found */
00253       lpcb = lpcb_any;
00254       prev = lpcb_prev;
00255     }
00256 #endif /* SO_REUSE */
00257     if (lpcb != NULL) {
00258       /* Move this PCB to the front of the list so that subsequent
00259          lookups will be faster (we exploit locality in TCP segment
00260          arrivals). */
00261       if (prev != NULL) {
00262         ((struct tcp_pcb_listen *)prev)->next = lpcb->next;
00263               /* our successor is the remainder of the listening list */
00264         lpcb->next = tcp_listen_pcbs.listen_pcbs;
00265               /* put this listening pcb at the head of the listening list */
00266         tcp_listen_pcbs.listen_pcbs = lpcb;
00267       }
00268     
00269       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));
00270       tcp_listen_input(lpcb);
00271       pbuf_free(p);
00272       return;
00273     }
00274   }
00275 
00276 #if TCP_INPUT_DEBUG
00277   LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags "));
00278   tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
00279   LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n"));
00280 #endif /* TCP_INPUT_DEBUG */
00281 
00282 
00283   if (pcb != NULL) {
00284     /* The incoming segment belongs to a connection. */
00285 #if TCP_INPUT_DEBUG
00286 #if TCP_DEBUG
00287     tcp_debug_print_state(pcb->state);
00288 #endif /* TCP_DEBUG */
00289 #endif /* TCP_INPUT_DEBUG */
00290 
00291     /* Set up a tcp_seg structure. */
00292     inseg.next = NULL;
00293     inseg.len = p->tot_len;
00294     inseg.p = p;
00295     inseg.tcphdr = tcphdr;
00296 
00297     recv_data = NULL;
00298     recv_flags = 0;
00299 
00300     /* If there is data which was previously "refused" by upper layer */
00301     if (pcb->refused_data != NULL) {
00302       /* Notify again application with data previously received. */
00303       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n"));
00304       TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
00305       if (err == ERR_OK) {
00306         pcb->refused_data = NULL;
00307       } else if ((err == ERR_ABRT) || (tcplen > 0)) {
00308         /* if err == ERR_ABRT, 'pcb' is already deallocated */
00309         /* Drop incoming packets because pcb is "full" (only if the incoming
00310            segment contains data). */
00311         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
00312         TCP_STATS_INC(tcp.drop);
00313         snmp_inc_tcpinerrs();
00314         pbuf_free(p);
00315         return;
00316       }
00317     }
00318     tcp_input_pcb = pcb;
00319     err = tcp_process(pcb);
00320     /* A return value of ERR_ABRT means that tcp_abort() was called
00321        and that the pcb has been freed. If so, we don't do anything. */
00322     if (err != ERR_ABRT) {
00323       if (recv_flags & TF_RESET) {
00324         /* TF_RESET means that the connection was reset by the other
00325            end. We then call the error callback to inform the
00326            application that the connection is dead before we
00327            deallocate the PCB. */
00328         TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST);
00329         tcp_pcb_remove(&tcp_active_pcbs, pcb);
00330         memp_free(MEMP_TCP_PCB, pcb);
00331       } else if (recv_flags & TF_CLOSED) {
00332         /* The connection has been closed and we will deallocate the
00333            PCB. */
00334         tcp_pcb_remove(&tcp_active_pcbs, pcb);
00335         memp_free(MEMP_TCP_PCB, pcb);
00336       } else {
00337         err = ERR_OK;
00338         /* If the application has registered a "sent" function to be
00339            called when new send buffer space is available, we call it
00340            now. */
00341         if (pcb->acked > 0) {
00342           TCP_EVENT_SENT(pcb, pcb->acked, err);
00343           if (err == ERR_ABRT) {
00344             goto aborted;
00345           }
00346         }
00347 
00348         if (recv_data != NULL) {
00349           LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL);
00350           if (pcb->flags & TF_RXCLOSED) {
00351             /* received data although already closed -> abort (send RST) to
00352                notify the remote host that not all data has been processed */
00353             pbuf_free(recv_data);
00354             tcp_abort(pcb);
00355             goto aborted;
00356           }
00357           if (flags & TCP_PSH) {
00358             recv_data->flags |= PBUF_FLAG_PUSH;
00359           }
00360 
00361           /* Notify application that data has been received. */
00362           TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);
00363           if (err == ERR_ABRT) {
00364             goto aborted;
00365           }
00366 
00367           /* If the upper layer can't receive this data, store it */
00368           if (err != ERR_OK) {
00369             pcb->refused_data = recv_data;
00370             LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n"));
00371           }
00372         }
00373 
00374         /* If a FIN segment was received, we call the callback
00375            function with a NULL buffer to indicate EOF. */
00376         if (recv_flags & TF_GOT_FIN) {
00377           /* correct rcv_wnd as the application won't call tcp_recved()
00378              for the FIN's seqno */
00379           if (pcb->rcv_wnd != TCP_WND) {
00380             pcb->rcv_wnd++;
00381           }
00382           TCP_EVENT_CLOSED(pcb, err);
00383           if (err == ERR_ABRT) {
00384             goto aborted;
00385           }
00386         }
00387 
00388         tcp_input_pcb = NULL;
00389         /* Try to send something out. */
00390         tcp_output(pcb);
00391 #if TCP_INPUT_DEBUG
00392 #if TCP_DEBUG
00393         tcp_debug_print_state(pcb->state);
00394 #endif /* TCP_DEBUG */
00395 #endif /* TCP_INPUT_DEBUG */
00396       }
00397     }
00398     /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()).
00399        Below this line, 'pcb' may not be dereferenced! */
00400 aborted:
00401     tcp_input_pcb = NULL;
00402     recv_data = NULL;
00403 
00404     /* give up our reference to inseg.p */
00405     if (inseg.p != NULL)
00406     {
00407       pbuf_free(inseg.p);
00408       inseg.p = NULL;
00409     }
00410   } else {
00411 
00412     /* If no matching PCB was found, send a TCP RST (reset) to the
00413        sender. */
00414     LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n"));
00415     if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {
00416       TCP_STATS_INC(tcp.proterr);
00417       TCP_STATS_INC(tcp.drop);
00418       tcp_rst(ackno, seqno + tcplen,
00419         ip_current_dest_addr(), ip_current_src_addr(),
00420         tcphdr->dest, tcphdr->src);
00421     }
00422     pbuf_free(p);
00423   }
00424 
00425   LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());
00426   PERF_STOP("tcp_input");
00427 }
00428 
00429 /**
00430  * Called by tcp_input() when a segment arrives for a listening
00431  * connection (from tcp_input()).
00432  *
00433  * @param pcb the tcp_pcb_listen for which a segment arrived
00434  * @return ERR_OK if the segment was processed
00435  *         another err_t on error
00436  *
00437  * @note the return value is not (yet?) used in tcp_input()
00438  * @note the segment which arrived is saved in global variables, therefore only the pcb
00439  *       involved is passed as a parameter to this function
00440  */
00441 static err_t
00442 tcp_listen_input(struct tcp_pcb_listen *pcb)
00443 {
00444   struct tcp_pcb *npcb;
00445   err_t rc;
00446 
00447   /* In the LISTEN state, we check for incoming SYN segments,
00448      creates a new PCB, and responds with a SYN|ACK. */
00449   if (flags & TCP_ACK) {
00450     /* For incoming segments with the ACK flag set, respond with a
00451        RST. */
00452     LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));
00453     tcp_rst(ackno + 1, seqno + tcplen,
00454       ip_current_dest_addr(), ip_current_src_addr(),
00455       tcphdr->dest, tcphdr->src);
00456   } else if (flags & TCP_SYN) {
00457     LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
00458 #if TCP_LISTEN_BACKLOG
00459     if (pcb->accepts_pending >= pcb->backlog) {
00460       LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest));
00461       return ERR_ABRT;
00462     }
00463 #endif /* TCP_LISTEN_BACKLOG */
00464     npcb = tcp_alloc(pcb->prio);
00465     /* If a new PCB could not be created (probably due to lack of memory),
00466        we don't do anything, but rely on the sender will retransmit the
00467        SYN at a time when we have more memory available. */
00468     if (npcb == NULL) {
00469       LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n"));
00470       TCP_STATS_INC(tcp.memerr);
00471       return ERR_MEM;
00472     }
00473 #if TCP_LISTEN_BACKLOG
00474     pcb->accepts_pending++;
00475 #endif /* TCP_LISTEN_BACKLOG */
00476     /* Set up the new PCB. */
00477     ip_addr_copy(npcb->local_ip, current_iphdr_dest);
00478     npcb->local_port = pcb->local_port;
00479     ip_addr_copy(npcb->remote_ip, current_iphdr_src);
00480     npcb->remote_port = tcphdr->src;
00481     npcb->state = SYN_RCVD;
00482     npcb->rcv_nxt = seqno + 1;
00483     npcb->rcv_ann_right_edge = npcb->rcv_nxt;
00484     npcb->snd_wnd = tcphdr->wnd;
00485     npcb->ssthresh = npcb->snd_wnd;
00486     npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
00487     npcb->callback_arg = pcb->callback_arg;
00488 #if LWIP_CALLBACK_API
00489     npcb->accept = pcb->accept;
00490 #endif /* LWIP_CALLBACK_API */
00491     /* inherit socket options */
00492     npcb->so_options = pcb->so_options & SOF_INHERITED;
00493     /* Register the new PCB so that we can begin receiving segments
00494        for it. */
00495     TCP_REG(&tcp_active_pcbs, npcb);
00496 
00497     /* Parse any options in the SYN. */
00498     tcp_parseopt(npcb);
00499 #if TCP_CALCULATE_EFF_SEND_MSS
00500     npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip));
00501 #endif /* TCP_CALCULATE_EFF_SEND_MSS */
00502 
00503     snmp_inc_tcppassiveopens();
00504 
00505     /* Send a SYN|ACK together with the MSS option. */
00506     rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK);
00507     if (rc != ERR_OK) {
00508       tcp_abandon(npcb, 0);
00509       return rc;
00510     }
00511     return tcp_output(npcb);
00512   }
00513   return ERR_OK;
00514 }
00515 
00516 /**
00517  * Called by tcp_input() when a segment arrives for a connection in
00518  * TIME_WAIT.
00519  *
00520  * @param pcb the tcp_pcb for which a segment arrived
00521  *
00522  * @note the segment which arrived is saved in global variables, therefore only the pcb
00523  *       involved is passed as a parameter to this function
00524  */
00525 static err_t
00526 tcp_timewait_input(struct tcp_pcb *pcb)
00527 {
00528   /* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */
00529   /* RFC 793 3.9 Event Processing - Segment Arrives:
00530    * - first check sequence number - we skip that one in TIME_WAIT (always
00531    *   acceptable since we only send ACKs)
00532    * - second check the RST bit (... return) */
00533   if (flags & TCP_RST)  {
00534     return ERR_OK;
00535   }
00536   /* - fourth, check the SYN bit, */
00537   if (flags & TCP_SYN) {
00538     /* If an incoming segment is not acceptable, an acknowledgment
00539        should be sent in reply */
00540     if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {
00541       /* If the SYN is in the window it is an error, send a reset */
00542       tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
00543         tcphdr->dest, tcphdr->src);
00544       return ERR_OK;
00545     }
00546   } else if (flags & TCP_FIN) {
00547     /* - eighth, check the FIN bit: Remain in the TIME-WAIT state.
00548          Restart the 2 MSL time-wait timeout.*/
00549     pcb->tmr = tcp_ticks;
00550   }
00551 
00552   if ((tcplen > 0))  {
00553     /* Acknowledge data, FIN or out-of-window SYN */
00554     pcb->flags |= TF_ACK_NOW;
00555     return tcp_output(pcb);
00556   }
00557   return ERR_OK;
00558 }
00559 
00560 /**
00561  * Implements the TCP state machine. Called by tcp_input. In some
00562  * states tcp_receive() is called to receive data. The tcp_seg
00563  * argument will be freed by the caller (tcp_input()) unless the
00564  * recv_data pointer in the pcb is set.
00565  *
00566  * @param pcb the tcp_pcb for which a segment arrived
00567  *
00568  * @note the segment which arrived is saved in global variables, therefore only the pcb
00569  *       involved is passed as a parameter to this function
00570  */
00571 static err_t
00572 tcp_process(struct tcp_pcb *pcb)
00573 {
00574   struct tcp_seg *rseg;
00575   u8_t acceptable = 0;
00576   err_t err;
00577 
00578   err = ERR_OK;
00579 
00580   /* Process incoming RST segments. */
00581   if (flags & TCP_RST) {
00582     /* First, determine if the reset is acceptable. */
00583     if (pcb->state == SYN_SENT) {
00584       if (ackno == pcb->snd_nxt) {
00585         acceptable = 1;
00586       }
00587     } else {
00588       if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, 
00589                           pcb->rcv_nxt+pcb->rcv_wnd)) {
00590         acceptable = 1;
00591       }
00592     }
00593 
00594     if (acceptable) {
00595       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));
00596       LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);
00597       recv_flags |= TF_RESET;
00598       pcb->flags &= ~TF_ACK_DELAY;
00599       return ERR_RST;
00600     } else {
00601       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
00602        seqno, pcb->rcv_nxt));
00603       LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
00604        seqno, pcb->rcv_nxt));
00605       return ERR_OK;
00606     }
00607   }
00608 
00609   if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) { 
00610     /* Cope with new connection attempt after remote end crashed */
00611     tcp_ack_now(pcb);
00612     return ERR_OK;
00613   }
00614   
00615   if ((pcb->flags & TF_RXCLOSED) == 0) {
00616     /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */
00617     pcb->tmr = tcp_ticks;
00618   }
00619   pcb->keep_cnt_sent = 0;
00620 
00621   tcp_parseopt(pcb);
00622 
00623   /* Do different things depending on the TCP state. */
00624   switch (pcb->state) {
00625   case SYN_SENT:
00626     LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,
00627      pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));
00628     /* received SYN ACK with expected sequence number? */
00629     if ((flags & TCP_ACK) && (flags & TCP_SYN)
00630         && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {
00631       pcb->snd_buf++;
00632       pcb->rcv_nxt = seqno + 1;
00633       pcb->rcv_ann_right_edge = pcb->rcv_nxt;
00634       pcb->lastack = ackno;
00635       pcb->snd_wnd = tcphdr->wnd;
00636       pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
00637       pcb->state = ESTABLISHED;
00638 
00639 #if TCP_CALCULATE_EFF_SEND_MSS
00640       pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));
00641 #endif /* TCP_CALCULATE_EFF_SEND_MSS */
00642 
00643       /* Set ssthresh again after changing pcb->mss (already set in tcp_connect
00644        * but for the default value of pcb->mss) */
00645       pcb->ssthresh = pcb->mss * 10;
00646 
00647       pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
00648       LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0));
00649       --pcb->snd_queuelen;
00650       LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));
00651       rseg = pcb->unacked;
00652       pcb->unacked = rseg->next;
00653 
00654       /* If there's nothing left to acknowledge, stop the retransmit
00655          timer, otherwise reset it to start again */
00656       if(pcb->unacked == NULL)
00657         pcb->rtime = -1;
00658       else {
00659         pcb->rtime = 0;
00660         pcb->nrtx = 0;
00661       }
00662 
00663       tcp_seg_free(rseg);
00664 
00665       /* Call the user specified function to call when sucessfully
00666        * connected. */
00667       TCP_EVENT_CONNECTED(pcb, ERR_OK, err);
00668       if (err == ERR_ABRT) {
00669         return ERR_ABRT;
00670       }
00671       tcp_ack_now(pcb);
00672     }
00673     /* received ACK? possibly a half-open connection */
00674     else if (flags & TCP_ACK) {
00675       /* send a RST to bring the other side in a non-synchronized state. */
00676       tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
00677         tcphdr->dest, tcphdr->src);
00678     }
00679     break;
00680   case SYN_RCVD:
00681     if (flags & TCP_ACK) {
00682       /* expected ACK number? */
00683       if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
00684         u16_t old_cwnd;
00685         pcb->state = ESTABLISHED;
00686         LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
00687 #if LWIP_CALLBACK_API
00688         LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);
00689 #endif
00690         /* Call the accept function. */
00691         TCP_EVENT_ACCEPT(pcb, ERR_OK, err);
00692         if (err != ERR_OK) {
00693           /* If the accept function returns with an error, we abort
00694            * the connection. */
00695           /* Already aborted? */
00696           if (err != ERR_ABRT) {
00697             tcp_abort(pcb);
00698           }
00699           return ERR_ABRT;
00700         }
00701         old_cwnd = pcb->cwnd;
00702         /* If there was any data contained within this ACK,
00703          * we'd better pass it on to the application as well. */
00704         tcp_receive(pcb);
00705 
00706         /* Prevent ACK for SYN to generate a sent event */
00707         if (pcb->acked != 0) {
00708           pcb->acked--;
00709         }
00710 
00711         pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
00712 
00713         if (recv_flags & TF_GOT_FIN) {
00714           tcp_ack_now(pcb);
00715           pcb->state = CLOSE_WAIT;
00716         }
00717       } else {
00718         /* incorrect ACK number, send RST */
00719         tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
00720                 tcphdr->dest, tcphdr->src);
00721       }
00722     } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {
00723       /* Looks like another copy of the SYN - retransmit our SYN-ACK */
00724       tcp_rexmit(pcb);
00725     }
00726     break;
00727   case CLOSE_WAIT:
00728     /* FALLTHROUGH */
00729   case ESTABLISHED:
00730     tcp_receive(pcb);
00731     if (recv_flags & TF_GOT_FIN) { /* passive close */
00732       tcp_ack_now(pcb);
00733       pcb->state = CLOSE_WAIT;
00734     }
00735     break;
00736   case FIN_WAIT_1:
00737     tcp_receive(pcb);
00738     if (recv_flags & TF_GOT_FIN) {
00739       if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
00740         LWIP_DEBUGF(TCP_DEBUG,
00741           ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
00742         tcp_ack_now(pcb);
00743         tcp_pcb_purge(pcb);
00744         TCP_RMV(&tcp_active_pcbs, pcb);
00745         pcb->state = TIME_WAIT;
00746         TCP_REG(&tcp_tw_pcbs, pcb);
00747       } else {
00748         tcp_ack_now(pcb);
00749         pcb->state = CLOSING;
00750       }
00751     } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
00752       pcb->state = FIN_WAIT_2;
00753     }
00754     break;
00755   case FIN_WAIT_2:
00756     tcp_receive(pcb);
00757     if (recv_flags & TF_GOT_FIN) {
00758       LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
00759       tcp_ack_now(pcb);
00760       tcp_pcb_purge(pcb);
00761       TCP_RMV(&tcp_active_pcbs, pcb);
00762       pcb->state = TIME_WAIT;
00763       TCP_REG(&tcp_tw_pcbs, pcb);
00764     }
00765     break;
00766   case CLOSING:
00767     tcp_receive(pcb);
00768     if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
00769       LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
00770       tcp_pcb_purge(pcb);
00771       TCP_RMV(&tcp_active_pcbs, pcb);
00772       pcb->state = TIME_WAIT;
00773       TCP_REG(&tcp_tw_pcbs, pcb);
00774     }
00775     break;
00776   case LAST_ACK:
00777     tcp_receive(pcb);
00778     if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
00779       LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
00780       /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
00781       recv_flags |= TF_CLOSED;
00782     }
00783     break;
00784   default:
00785     break;
00786   }
00787   return ERR_OK;
00788 }
00789 
00790 #if TCP_QUEUE_OOSEQ
00791 /**
00792  * Insert segment into the list (segments covered with new one will be deleted)
00793  *
00794  * Called from tcp_receive()
00795  */
00796 static void
00797 tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next)
00798 {
00799   struct tcp_seg *old_seg;
00800 
00801   if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
00802     /* received segment overlaps all following segments */
00803     tcp_segs_free(next);
00804     next = NULL;
00805   }
00806   else {
00807     /* delete some following segments
00808        oos queue may have segments with FIN flag */
00809     while (next &&
00810            TCP_SEQ_GEQ((seqno + cseg->len),
00811                       (next->tcphdr->seqno + next->len))) {
00812       /* cseg with FIN already processed */
00813       if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
00814         TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN);
00815       }
00816       old_seg = next;
00817       next = next->next;
00818       tcp_seg_free(old_seg);
00819     }
00820     if (next &&
00821         TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {
00822       /* We need to trim the incoming segment. */
00823       cseg->len = (u16_t)(next->tcphdr->seqno - seqno);
00824       pbuf_realloc(cseg->p, cseg->len);
00825     }
00826   }
00827   cseg->next = next;
00828 }
00829 #endif /* TCP_QUEUE_OOSEQ */
00830 
00831 /**
00832  * Called by tcp_process. Checks if the given segment is an ACK for outstanding
00833  * data, and if so frees the memory of the buffered data. Next, is places the
00834  * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment
00835  * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until
00836  * i it has been removed from the buffer.
00837  *
00838  * If the incoming segment constitutes an ACK for a segment that was used for RTT
00839  * estimation, the RTT is estimated here as well.
00840  *
00841  * Called from tcp_process().
00842  */
00843 static void
00844 tcp_receive(struct tcp_pcb *pcb)
00845 {
00846   struct tcp_seg *next;
00847 #if TCP_QUEUE_OOSEQ
00848   struct tcp_seg *prev, *cseg;
00849 #endif /* TCP_QUEUE_OOSEQ */
00850   struct pbuf *p;
00851   s32_t off;
00852   s16_t m;
00853   u32_t right_wnd_edge;
00854   u16_t new_tot_len;
00855   int found_dupack = 0;
00856 
00857   if (flags & TCP_ACK) {
00858     right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2;
00859 
00860     /* Update window. */
00861     if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||
00862        (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||
00863        (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {
00864       pcb->snd_wnd = tcphdr->wnd;
00865       pcb->snd_wl1 = seqno;
00866       pcb->snd_wl2 = ackno;
00867       if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) {
00868           pcb->persist_backoff = 0;
00869       }
00870       LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd));
00871 #if TCP_WND_DEBUG
00872     } else {
00873       if (pcb->snd_wnd != tcphdr->wnd) {
00874         LWIP_DEBUGF(TCP_WND_DEBUG, 
00875                     ("tcp_receive: no window update lastack %"U32_F" ackno %"
00876                      U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n",
00877                      pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));
00878       }
00879 #endif /* TCP_WND_DEBUG */
00880     }
00881 
00882     /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a
00883      * duplicate ack if:
00884      * 1) It doesn't ACK new data 
00885      * 2) length of received packet is zero (i.e. no payload) 
00886      * 3) the advertised window hasn't changed 
00887      * 4) There is outstanding unacknowledged data (retransmission timer running)
00888      * 5) The ACK is == biggest ACK sequence number so far seen (snd_una)
00889      * 
00890      * If it passes all five, should process as a dupack: 
00891      * a) dupacks < 3: do nothing 
00892      * b) dupacks == 3: fast retransmit 
00893      * c) dupacks > 3: increase cwnd 
00894      * 
00895      * If it only passes 1-3, should reset dupack counter (and add to
00896      * stats, which we don't do in lwIP)
00897      *
00898      * If it only passes 1, should reset dupack counter
00899      *
00900      */
00901 
00902     /* Clause 1 */
00903     if (TCP_SEQ_LEQ(ackno, pcb->lastack)) {
00904       pcb->acked = 0;
00905       /* Clause 2 */
00906       if (tcplen == 0) {
00907         /* Clause 3 */
00908         if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){
00909           /* Clause 4 */
00910           if (pcb->rtime >= 0) {
00911             /* Clause 5 */
00912             if (pcb->lastack == ackno) {
00913               found_dupack = 1;
00914               if (pcb->dupacks + 1 > pcb->dupacks)
00915                 ++pcb->dupacks;
00916               if (pcb->dupacks > 3) {
00917                 /* Inflate the congestion window, but not if it means that
00918                    the value overflows. */
00919                 if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
00920                   pcb->cwnd += pcb->mss;
00921                 }
00922               } else if (pcb->dupacks == 3) {
00923                 /* Do fast retransmit */
00924                 tcp_rexmit_fast(pcb);
00925               }
00926             }
00927           }
00928         }
00929       }
00930       /* If Clause (1) or more is true, but not a duplicate ack, reset
00931        * count of consecutive duplicate acks */
00932       if (!found_dupack) {
00933         pcb->dupacks = 0;
00934       }
00935     } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){
00936       /* We come here when the ACK acknowledges new data. */
00937 
00938       /* Reset the "IN Fast Retransmit" flag, since we are no longer
00939          in fast retransmit. Also reset the congestion window to the
00940          slow start threshold. */
00941       if (pcb->flags & TF_INFR) {
00942         pcb->flags &= ~TF_INFR;
00943         pcb->cwnd = pcb->ssthresh;
00944       }
00945 
00946       /* Reset the number of retransmissions. */
00947       pcb->nrtx = 0;
00948 
00949       /* Reset the retransmission time-out. */
00950       pcb->rto = (pcb->sa >> 3) + pcb->sv;
00951 
00952       /* Update the send buffer space. Diff between the two can never exceed 64K? */
00953       pcb->acked = (u16_t)(ackno - pcb->lastack);
00954 
00955       pcb->snd_buf += pcb->acked;
00956 
00957       /* Reset the fast retransmit variables. */
00958       pcb->dupacks = 0;
00959       pcb->lastack = ackno;
00960 
00961       /* Update the congestion control variables (cwnd and
00962          ssthresh). */
00963       if (pcb->state >= ESTABLISHED) {
00964         if (pcb->cwnd < pcb->ssthresh) {
00965           if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
00966             pcb->cwnd += pcb->mss;
00967           }
00968           LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd));
00969         } else {
00970           u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
00971           if (new_cwnd > pcb->cwnd) {
00972             pcb->cwnd = new_cwnd;
00973           }
00974           LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd));
00975         }
00976       }
00977       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n",
00978                                     ackno,
00979                                     pcb->unacked != NULL?
00980                                     ntohl(pcb->unacked->tcphdr->seqno): 0,
00981                                     pcb->unacked != NULL?
00982                                     ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));
00983 
00984       /* Remove segment from the unacknowledged list if the incoming
00985          ACK acknowlegdes them. */
00986       while (pcb->unacked != NULL &&
00987              TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +
00988                          TCP_TCPLEN(pcb->unacked), ackno)) {
00989         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n",
00990                                       ntohl(pcb->unacked->tcphdr->seqno),
00991                                       ntohl(pcb->unacked->tcphdr->seqno) +
00992                                       TCP_TCPLEN(pcb->unacked)));
00993 
00994         next = pcb->unacked;
00995         pcb->unacked = pcb->unacked->next;
00996 
00997         LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
00998         LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
00999         /* Prevent ACK for FIN to generate a sent event */
01000         if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
01001           pcb->acked--;
01002         }
01003 
01004         pcb->snd_queuelen -= pbuf_clen(next->p);
01005         tcp_seg_free(next);
01006 
01007         LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen));
01008         if (pcb->snd_queuelen != 0) {
01009           LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
01010                       pcb->unsent != NULL);
01011         }
01012       }
01013 
01014       /* If there's nothing left to acknowledge, stop the retransmit
01015          timer, otherwise reset it to start again */
01016       if(pcb->unacked == NULL)
01017         pcb->rtime = -1;
01018       else
01019         pcb->rtime = 0;
01020 
01021       pcb->polltmr = 0;
01022     } else {
01023       /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */
01024       pcb->acked = 0;
01025     }
01026 
01027     /* We go through the ->unsent list to see if any of the segments
01028        on the list are acknowledged by the ACK. This may seem
01029        strange since an "unsent" segment shouldn't be acked. The
01030        rationale is that lwIP puts all outstanding segments on the
01031        ->unsent list after a retransmission, so these segments may
01032        in fact have been sent once. */
01033     while (pcb->unsent != NULL &&
01034            TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + 
01035                            TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) {
01036       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",
01037                                     ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +
01038                                     TCP_TCPLEN(pcb->unsent)));
01039 
01040       next = pcb->unsent;
01041       pcb->unsent = pcb->unsent->next;
01042       LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
01043       LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
01044       /* Prevent ACK for FIN to generate a sent event */
01045       if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
01046         pcb->acked--;
01047       }
01048       pcb->snd_queuelen -= pbuf_clen(next->p);
01049       tcp_seg_free(next);
01050       LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen));
01051       if (pcb->snd_queuelen != 0) {
01052         LWIP_ASSERT("tcp_receive: valid queue length",
01053           pcb->unacked != NULL || pcb->unsent != NULL);
01054       }
01055     }
01056     /* End of ACK for new data processing. */
01057 
01058     LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n",
01059                                 pcb->rttest, pcb->rtseq, ackno));
01060 
01061     /* RTT estimation calculations. This is done by checking if the
01062        incoming segment acknowledges the segment we use to take a
01063        round-trip time measurement. */
01064     if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) {
01065       /* diff between this shouldn't exceed 32K since this are tcp timer ticks
01066          and a round-trip shouldn't be that long... */
01067       m = (s16_t)(tcp_ticks - pcb->rttest);
01068 
01069       LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n",
01070                                   m, m * TCP_SLOW_INTERVAL));
01071 
01072       /* This is taken directly from VJs original code in his paper */
01073       m = m - (pcb->sa >> 3);
01074       pcb->sa += m;
01075       if (m < 0) {
01076         m = -m;
01077       }
01078       m = m - (pcb->sv >> 2);
01079       pcb->sv += m;
01080       pcb->rto = (pcb->sa >> 3) + pcb->sv;
01081 
01082       LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n",
01083                                   pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));
01084 
01085       pcb->rttest = 0;
01086     }
01087   }
01088 
01089   /* If the incoming segment contains data, we must process it
01090      further. */
01091   if (tcplen > 0) {
01092     /* This code basically does three things:
01093 
01094     +) If the incoming segment contains data that is the next
01095     in-sequence data, this data is passed to the application. This
01096     might involve trimming the first edge of the data. The rcv_nxt
01097     variable and the advertised window are adjusted.
01098 
01099     +) If the incoming segment has data that is above the next
01100     sequence number expected (->rcv_nxt), the segment is placed on
01101     the ->ooseq queue. This is done by finding the appropriate
01102     place in the ->ooseq queue (which is ordered by sequence
01103     number) and trim the segment in both ends if needed. An
01104     immediate ACK is sent to indicate that we received an
01105     out-of-sequence segment.
01106 
01107     +) Finally, we check if the first segment on the ->ooseq queue
01108     now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If
01109     rcv_nxt > ooseq->seqno, we must trim the first edge of the
01110     segment on ->ooseq before we adjust rcv_nxt. The data in the
01111     segments that are now on sequence are chained onto the
01112     incoming segment so that we only need to call the application
01113     once.
01114     */
01115 
01116     /* First, we check if we must trim the first edge. We have to do
01117        this if the sequence number of the incoming segment is less
01118        than rcv_nxt, and the sequence number plus the length of the
01119        segment is larger than rcv_nxt. */
01120     /*    if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
01121           if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/
01122     if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){
01123       /* Trimming the first edge is done by pushing the payload
01124          pointer in the pbuf downwards. This is somewhat tricky since
01125          we do not want to discard the full contents of the pbuf up to
01126          the new starting point of the data since we have to keep the
01127          TCP header which is present in the first pbuf in the chain.
01128 
01129          What is done is really quite a nasty hack: the first pbuf in
01130          the pbuf chain is pointed to by inseg.p. Since we need to be
01131          able to deallocate the whole pbuf, we cannot change this
01132          inseg.p pointer to point to any of the later pbufs in the
01133          chain. Instead, we point the ->payload pointer in the first
01134          pbuf to data in one of the later pbufs. We also set the
01135          inseg.data pointer to point to the right place. This way, the
01136          ->p pointer will still point to the first pbuf, but the
01137          ->p->payload pointer will point to data in another pbuf.
01138 
01139          After we are done with adjusting the pbuf pointers we must
01140          adjust the ->data pointer in the seg and the segment
01141          length.*/
01142 
01143       off = pcb->rcv_nxt - seqno;
01144       p = inseg.p;
01145       LWIP_ASSERT("inseg.p != NULL", inseg.p);
01146       LWIP_ASSERT("insane offset!", (off < 0x7fff));
01147       if (inseg.p->len < off) {
01148         LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off));
01149         new_tot_len = (u16_t)(inseg.p->tot_len - off);
01150         while (p->len < off) {
01151           off -= p->len;
01152           /* KJM following line changed (with addition of new_tot_len var)
01153              to fix bug #9076
01154              inseg.p->tot_len -= p->len; */
01155           p->tot_len = new_tot_len;
01156           p->len = 0;
01157           p = p->next;
01158         }
01159         if(pbuf_header(p, (s16_t)-off)) {
01160           /* Do we need to cope with this failing?  Assert for now */
01161           LWIP_ASSERT("pbuf_header failed", 0);
01162         }
01163       } else {
01164         if(pbuf_header(inseg.p, (s16_t)-off)) {
01165           /* Do we need to cope with this failing?  Assert for now */
01166           LWIP_ASSERT("pbuf_header failed", 0);
01167         }
01168       }
01169       inseg.len -= (u16_t)(pcb->rcv_nxt - seqno);
01170       inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
01171     }
01172     else {
01173       if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
01174         /* the whole segment is < rcv_nxt */
01175         /* must be a duplicate of a packet that has already been correctly handled */
01176 
01177         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno));
01178         tcp_ack_now(pcb);
01179       }
01180     }
01181 
01182     /* The sequence number must be within the window (above rcv_nxt
01183        and below rcv_nxt + rcv_wnd) in order to be further
01184        processed. */
01185     if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, 
01186                         pcb->rcv_nxt + pcb->rcv_wnd - 1)){
01187       if (pcb->rcv_nxt == seqno) {
01188         /* The incoming segment is the next in sequence. We check if
01189            we have to trim the end of the segment and update rcv_nxt
01190            and pass the data to the application. */
01191         tcplen = TCP_TCPLEN(&inseg);
01192 
01193         if (tcplen > pcb->rcv_wnd) {
01194           LWIP_DEBUGF(TCP_INPUT_DEBUG, 
01195                       ("tcp_receive: other end overran receive window"
01196                        "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
01197                        seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
01198           if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
01199             /* Must remove the FIN from the header as we're trimming 
01200              * that byte of sequence-space from the packet */
01201             TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN);
01202           }
01203           /* Adjust length of segment to fit in the window. */
01204           inseg.len = pcb->rcv_wnd;
01205           if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
01206             inseg.len -= 1;
01207           }
01208           pbuf_realloc(inseg.p, inseg.len);
01209           tcplen = TCP_TCPLEN(&inseg);
01210           LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
01211                       (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
01212         }
01213 #if TCP_QUEUE_OOSEQ
01214         /* Received in-sequence data, adjust ooseq data if:
01215            - FIN has been received or
01216            - inseq overlaps with ooseq */
01217         if (pcb->ooseq != NULL) {
01218           if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
01219             LWIP_DEBUGF(TCP_INPUT_DEBUG, 
01220                         ("tcp_receive: received in-order FIN, binning ooseq queue\n"));
01221             /* Received in-order FIN means anything that was received
01222              * out of order must now have been received in-order, so
01223              * bin the ooseq queue */
01224             while (pcb->ooseq != NULL) {
01225               struct tcp_seg *old_ooseq = pcb->ooseq;
01226               pcb->ooseq = pcb->ooseq->next;
01227               tcp_seg_free(old_ooseq);
01228             }
01229           }
01230           else {
01231             next = pcb->ooseq;
01232             /* Remove all segments on ooseq that are covered by inseg already.
01233              * FIN is copied from ooseq to inseg if present. */
01234             while (next &&
01235                    TCP_SEQ_GEQ(seqno + tcplen,
01236                                next->tcphdr->seqno + next->len)) {
01237               /* inseg cannot have FIN here (already processed above) */
01238               if (TCPH_FLAGS(next->tcphdr) & TCP_FIN &&
01239                   (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) {
01240                 TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN);
01241                 tcplen = TCP_TCPLEN(&inseg);
01242               }
01243               prev = next;
01244               next = next->next;
01245               tcp_seg_free(prev);
01246             }
01247             /* Now trim right side of inseg if it overlaps with the first
01248              * segment on ooseq */
01249             if (next &&
01250                 TCP_SEQ_GT(seqno + tcplen,
01251                            next->tcphdr->seqno)) {
01252               /* inseg cannot have FIN here (already processed above) */
01253               inseg.len = (u16_t)(next->tcphdr->seqno - seqno);
01254               if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
01255                 inseg.len -= 1;
01256               }
01257               pbuf_realloc(inseg.p, inseg.len);
01258               tcplen = TCP_TCPLEN(&inseg);
01259               LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n",
01260                           (seqno + tcplen) == next->tcphdr->seqno);
01261             }
01262             pcb->ooseq = next;
01263           }
01264         }
01265 #endif /* TCP_QUEUE_OOSEQ */
01266 
01267         pcb->rcv_nxt = seqno + tcplen;
01268 
01269         /* Update the receiver's (our) window. */
01270         LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen);
01271         pcb->rcv_wnd -= tcplen;
01272 
01273         tcp_update_rcv_ann_wnd(pcb);
01274 
01275         /* If there is data in the segment, we make preparations to
01276            pass this up to the application. The ->recv_data variable
01277            is used for holding the pbuf that goes to the
01278            application. The code for reassembling out-of-sequence data
01279            chains its data on this pbuf as well.
01280 
01281            If the segment was a FIN, we set the TF_GOT_FIN flag that will
01282            be used to indicate to the application that the remote side has
01283            closed its end of the connection. */
01284         if (inseg.p->tot_len > 0) {
01285           recv_data = inseg.p;
01286           /* Since this pbuf now is the responsibility of the
01287              application, we delete our reference to it so that we won't
01288              (mistakingly) deallocate it. */
01289           inseg.p = NULL;
01290         }
01291         if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
01292           LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
01293           recv_flags |= TF_GOT_FIN;
01294         }
01295 
01296 #if TCP_QUEUE_OOSEQ
01297         /* We now check if we have segments on the ->ooseq queue that
01298            are now in sequence. */
01299         while (pcb->ooseq != NULL &&
01300                pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {
01301 
01302           cseg = pcb->ooseq;
01303           seqno = pcb->ooseq->tcphdr->seqno;
01304 
01305           pcb->rcv_nxt += TCP_TCPLEN(cseg);
01306           LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n",
01307                       pcb->rcv_wnd >= TCP_TCPLEN(cseg));
01308           pcb->rcv_wnd -= TCP_TCPLEN(cseg);
01309 
01310           tcp_update_rcv_ann_wnd(pcb);
01311 
01312           if (cseg->p->tot_len > 0) {
01313             /* Chain this pbuf onto the pbuf that we will pass to
01314                the application. */
01315             if (recv_data) {
01316               pbuf_cat(recv_data, cseg->p);
01317             } else {
01318               recv_data = cseg->p;
01319             }
01320             cseg->p = NULL;
01321           }
01322           if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
01323             LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
01324             recv_flags |= TF_GOT_FIN;
01325             if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */
01326               pcb->state = CLOSE_WAIT;
01327             } 
01328           }
01329 
01330           pcb->ooseq = cseg->next;
01331           tcp_seg_free(cseg);
01332         }
01333 #endif /* TCP_QUEUE_OOSEQ */
01334 
01335 
01336         /* Acknowledge the segment(s). */
01337         tcp_ack(pcb);
01338 
01339       } else {
01340         /* We get here if the incoming segment is out-of-sequence. */
01341         tcp_send_empty_ack(pcb);
01342 #if TCP_QUEUE_OOSEQ
01343         /* We queue the segment on the ->ooseq queue. */
01344         if (pcb->ooseq == NULL) {
01345           pcb->ooseq = tcp_seg_copy(&inseg);
01346         } else {
01347           /* If the queue is not empty, we walk through the queue and
01348              try to find a place where the sequence number of the
01349              incoming segment is between the sequence numbers of the
01350              previous and the next segment on the ->ooseq queue. That is
01351              the place where we put the incoming segment. If needed, we
01352              trim the second edges of the previous and the incoming
01353              segment so that it will fit into the sequence.
01354 
01355              If the incoming segment has the same sequence number as a
01356              segment on the ->ooseq queue, we discard the segment that
01357              contains less data. */
01358 
01359           prev = NULL;
01360           for(next = pcb->ooseq; next != NULL; next = next->next) {
01361             if (seqno == next->tcphdr->seqno) {
01362               /* The sequence number of the incoming segment is the
01363                  same as the sequence number of the segment on
01364                  ->ooseq. We check the lengths to see which one to
01365                  discard. */
01366               if (inseg.len > next->len) {
01367                 /* The incoming segment is larger than the old
01368                    segment. We replace some segments with the new
01369                    one. */
01370                 cseg = tcp_seg_copy(&inseg);
01371                 if (cseg != NULL) {
01372                   if (prev != NULL) {
01373                     prev->next = cseg;
01374                   } else {
01375                     pcb->ooseq = cseg;
01376                   }
01377                   tcp_oos_insert_segment(cseg, next);
01378                 }
01379                 break;
01380               } else {
01381                 /* Either the lenghts are the same or the incoming
01382                    segment was smaller than the old one; in either
01383                    case, we ditch the incoming segment. */
01384                 break;
01385               }
01386             } else {
01387               if (prev == NULL) {
01388                 if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {
01389                   /* The sequence number of the incoming segment is lower
01390                      than the sequence number of the first segment on the
01391                      queue. We put the incoming segment first on the
01392                      queue. */
01393                   cseg = tcp_seg_copy(&inseg);
01394                   if (cseg != NULL) {
01395                     pcb->ooseq = cseg;
01396                     tcp_oos_insert_segment(cseg, next);
01397                   }
01398                   break;
01399                 }
01400               } else {
01401                 /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
01402                   TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/
01403                 if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) {
01404                   /* The sequence number of the incoming segment is in
01405                      between the sequence numbers of the previous and
01406                      the next segment on ->ooseq. We trim trim the previous
01407                      segment, delete next segments that included in received segment
01408                      and trim received, if needed. */
01409                   cseg = tcp_seg_copy(&inseg);
01410                   if (cseg != NULL) {
01411                     if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
01412                       /* We need to trim the prev segment. */
01413                       prev->len = (u16_t)(seqno - prev->tcphdr->seqno);
01414                       pbuf_realloc(prev->p, prev->len);
01415                     }
01416                     prev->next = cseg;
01417                     tcp_oos_insert_segment(cseg, next);
01418                   }
01419                   break;
01420                 }
01421               }
01422               /* If the "next" segment is the last segment on the
01423                  ooseq queue, we add the incoming segment to the end
01424                  of the list. */
01425               if (next->next == NULL &&
01426                   TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {
01427                 if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
01428                   /* segment "next" already contains all data */
01429                   break;
01430                 }
01431                 next->next = tcp_seg_copy(&inseg);
01432                 if (next->next != NULL) {
01433                   if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
01434                     /* We need to trim the last segment. */
01435                     next->len = (u16_t)(seqno - next->tcphdr->seqno);
01436                     pbuf_realloc(next->p, next->len);
01437                   }
01438                   /* check if the remote side overruns our receive window */
01439                   if ((u32_t)tcplen + seqno > pcb->rcv_nxt + (u32_t)pcb->rcv_wnd) {
01440                     LWIP_DEBUGF(TCP_INPUT_DEBUG, 
01441                                 ("tcp_receive: other end overran receive window"
01442                                  "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
01443                                  seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
01444                     if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) {
01445                       /* Must remove the FIN from the header as we're trimming 
01446                        * that byte of sequence-space from the packet */
01447                       TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) &~ TCP_FIN);
01448                     }
01449                     /* Adjust length of segment to fit in the window. */
01450                     next->next->len = pcb->rcv_nxt + pcb->rcv_wnd - seqno;
01451                     pbuf_realloc(next->next->p, next->next->len);
01452                     tcplen = TCP_TCPLEN(next->next);
01453                     LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
01454                                 (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
01455                   }
01456                 }
01457                 break;
01458               }
01459             }
01460             prev = next;
01461           }
01462         }
01463 #endif /* TCP_QUEUE_OOSEQ */
01464 
01465       }
01466     } else {
01467       /* The incoming segment is not withing the window. */
01468       tcp_send_empty_ack(pcb);
01469     }
01470   } else {
01471     /* Segments with length 0 is taken care of here. Segments that
01472        fall out of the window are ACKed. */
01473     /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
01474       TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
01475     if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){
01476       tcp_ack_now(pcb);
01477     }
01478   }
01479 }
01480 
01481 /**
01482  * Parses the options contained in the incoming segment. 
01483  *
01484  * Called from tcp_listen_input() and tcp_process().
01485  * Currently, only the MSS option is supported!
01486  *
01487  * @param pcb the tcp_pcb for which a segment arrived
01488  */
01489 static void
01490 tcp_parseopt(struct tcp_pcb *pcb)
01491 {
01492   u16_t c, max_c;
01493   u16_t mss;
01494   u8_t *opts, opt;
01495 #if LWIP_TCP_TIMESTAMPS
01496   u32_t tsval;
01497 #endif
01498 
01499   opts = (u8_t *)tcphdr + TCP_HLEN;
01500 
01501   /* Parse the TCP MSS option, if present. */
01502   if(TCPH_HDRLEN(tcphdr) > 0x5) {
01503     max_c = (TCPH_HDRLEN(tcphdr) - 5) << 2;
01504     for (c = 0; c < max_c; ) {
01505       opt = opts[c];
01506       switch (opt) {
01507       case 0x00:
01508         /* End of options. */
01509         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n"));
01510         return;
01511       case 0x01:
01512         /* NOP option. */
01513         ++c;
01514         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n"));
01515         break;
01516       case 0x02:
01517         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n"));
01518         if (opts[c + 1] != 0x04 || c + 0x04 > max_c) {
01519           /* Bad length */
01520           LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
01521           return;
01522         }
01523         /* An MSS option with the right option length. */
01524         mss = (opts[c + 2] << 8) | opts[c + 3];
01525         /* Limit the mss to the configured TCP_MSS and prevent division by zero */
01526         pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss;
01527         /* Advance to next option */
01528         c += 0x04;
01529         break;
01530 #if LWIP_TCP_TIMESTAMPS
01531       case 0x08:
01532         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n"));
01533         if (opts[c + 1] != 0x0A || c + 0x0A > max_c) {
01534           /* Bad length */
01535           LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
01536           return;
01537         }
01538         /* TCP timestamp option with valid length */
01539         tsval = (opts[c+2]) | (opts[c+3] << 8) | 
01540           (opts[c+4] << 16) | (opts[c+5] << 24);
01541         if (flags & TCP_SYN) {
01542           pcb->ts_recent = ntohl(tsval);
01543           pcb->flags |= TF_TIMESTAMP;
01544         } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) {
01545           pcb->ts_recent = ntohl(tsval);
01546         }
01547         /* Advance to next option */
01548         c += 0x0A;
01549         break;
01550 #endif
01551       default:
01552         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n"));
01553         if (opts[c + 1] == 0) {
01554           LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
01555           /* If the length field is zero, the options are malformed
01556              and we don't process them further. */
01557           return;
01558         }
01559         /* All other options have a length field, so that we easily
01560            can skip past them. */
01561         c += opts[c + 1];
01562       }
01563     }
01564   }
01565 }
01566 
01567 #endif /* LWIP_TCP */