ZG2100 Network interface source

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.dataptr = p->payload;
00295     inseg.p = p;
00296     inseg.tcphdr = tcphdr;
00297 
00298     recv_data = NULL;
00299     recv_flags = 0;
00300 
00301     /* If there is data which was previously "refused" by upper layer */
00302     if (pcb->refused_data != NULL) {
00303       /* Notify again application with data previously received. */
00304       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n"));
00305       TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
00306       if (err == ERR_OK) {
00307         pcb->refused_data = NULL;
00308       } else {
00309         /* if err == ERR_ABRT, 'pcb' is already deallocated */
00310         /* drop incoming packets, because pcb is "full" */
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           if (pcb->flags & TF_RXCLOSED) {
00350             /* received data although already closed -> abort (send RST) to
00351                notify the remote host that not all data has been processed */
00352             pbuf_free(recv_data);
00353             tcp_abort(pcb);
00354             goto aborted;
00355           }
00356           if (flags & TCP_PSH) {
00357             recv_data->flags |= PBUF_FLAG_PUSH;
00358           }
00359 
00360           /* Notify application that data has been received. */
00361           TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);
00362           if (err == ERR_ABRT) {
00363             goto aborted;
00364           }
00365 
00366           /* If the upper layer can't receive this data, store it */
00367           if (err != ERR_OK) {
00368             pcb->refused_data = recv_data;
00369             LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n"));
00370           }
00371         }
00372 
00373         /* If a FIN segment was received, we call the callback
00374            function with a NULL buffer to indicate EOF. */
00375         if (recv_flags & TF_GOT_FIN) {
00376           /* correct rcv_wnd as the application won't call tcp_recved()
00377              for the FIN's seqno */
00378           if (pcb->rcv_wnd != TCP_WND) {
00379             pcb->rcv_wnd++;
00380           }
00381           TCP_EVENT_CLOSED(pcb, err);
00382           if (err == ERR_ABRT) {
00383             goto aborted;
00384           }
00385         }
00386 
00387         tcp_input_pcb = NULL;
00388         /* Try to send something out. */
00389         tcp_output(pcb);
00390 #if TCP_INPUT_DEBUG
00391 #if TCP_DEBUG
00392         tcp_debug_print_state(pcb->state);
00393 #endif /* TCP_DEBUG */
00394 #endif /* TCP_INPUT_DEBUG */
00395       }
00396     }
00397     /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()).
00398        Below this line, 'pcb' may not be dereferenced! */
00399 aborted:
00400     tcp_input_pcb = NULL;
00401     recv_data = NULL;
00402 
00403     /* give up our reference to inseg.p */
00404     if (inseg.p != NULL)
00405     {
00406       pbuf_free(inseg.p);
00407       inseg.p = NULL;
00408     }
00409   } else {
00410 
00411     /* If no matching PCB was found, send a TCP RST (reset) to the
00412        sender. */
00413     LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n"));
00414     if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {
00415       TCP_STATS_INC(tcp.proterr);
00416       TCP_STATS_INC(tcp.drop);
00417       tcp_rst(ackno, seqno + tcplen,
00418         ip_current_dest_addr(), ip_current_src_addr(),
00419         tcphdr->dest, tcphdr->src);
00420     }
00421     pbuf_free(p);
00422   }
00423 
00424   LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());
00425   PERF_STOP("tcp_input");
00426 }
00427 
00428 /**
00429  * Called by tcp_input() when a segment arrives for a listening
00430  * connection (from tcp_input()).
00431  *
00432  * @param pcb the tcp_pcb_listen for which a segment arrived
00433  * @return ERR_OK if the segment was processed
00434  *         another err_t on error
00435  *
00436  * @note the return value is not (yet?) used in tcp_input()
00437  * @note the segment which arrived is saved in global variables, therefore only the pcb
00438  *       involved is passed as a parameter to this function
00439  */
00440 static err_t
00441 tcp_listen_input(struct tcp_pcb_listen *pcb)
00442 {
00443   struct tcp_pcb *npcb;
00444   err_t rc;
00445 
00446   /* In the LISTEN state, we check for incoming SYN segments,
00447      creates a new PCB, and responds with a SYN|ACK. */
00448   if (flags & TCP_ACK) {
00449     /* For incoming segments with the ACK flag set, respond with a
00450        RST. */
00451     LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));
00452     tcp_rst(ackno + 1, seqno + tcplen,
00453       ip_current_dest_addr(), ip_current_src_addr(),
00454       tcphdr->dest, tcphdr->src);
00455   } else if (flags & TCP_SYN) {
00456     LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
00457 #if TCP_LISTEN_BACKLOG
00458     if (pcb->accepts_pending >= pcb->backlog) {
00459       LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest));
00460       return ERR_ABRT;
00461     }
00462 #endif /* TCP_LISTEN_BACKLOG */
00463     npcb = tcp_alloc(pcb->prio);
00464     /* If a new PCB could not be created (probably due to lack of memory),
00465        we don't do anything, but rely on the sender will retransmit the
00466        SYN at a time when we have more memory available. */
00467     if (npcb == NULL) {
00468       LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n"));
00469       TCP_STATS_INC(tcp.memerr);
00470       return ERR_MEM;
00471     }
00472 #if TCP_LISTEN_BACKLOG
00473     pcb->accepts_pending++;
00474 #endif /* TCP_LISTEN_BACKLOG */
00475     /* Set up the new PCB. */
00476     ip_addr_copy(npcb->local_ip, current_iphdr_dest);
00477     npcb->local_port = pcb->local_port;
00478     ip_addr_copy(npcb->remote_ip, current_iphdr_src);
00479     npcb->remote_port = tcphdr->src;
00480     npcb->state = SYN_RCVD;
00481     npcb->rcv_nxt = seqno + 1;
00482     npcb->rcv_ann_right_edge = npcb->rcv_nxt;
00483     npcb->snd_wnd = tcphdr->wnd;
00484     npcb->ssthresh = npcb->snd_wnd;
00485     npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
00486     npcb->callback_arg = pcb->callback_arg;
00487 #if LWIP_CALLBACK_API
00488     npcb->accept = pcb->accept;
00489 #endif /* LWIP_CALLBACK_API */
00490     /* inherit socket options */
00491     npcb->so_options = pcb->so_options & SOF_INHERITED;
00492     /* Register the new PCB so that we can begin receiving segments
00493        for it. */
00494     TCP_REG(&tcp_active_pcbs, npcb);
00495 
00496     /* Parse any options in the SYN. */
00497     tcp_parseopt(npcb);
00498 #if TCP_CALCULATE_EFF_SEND_MSS
00499     npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip));
00500 #endif /* TCP_CALCULATE_EFF_SEND_MSS */
00501 
00502     snmp_inc_tcppassiveopens();
00503 
00504     /* Send a SYN|ACK together with the MSS option. */
00505     rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK);
00506     if (rc != ERR_OK) {
00507       tcp_abandon(npcb, 0);
00508       return rc;
00509     }
00510     return tcp_output(npcb);
00511   }
00512   return ERR_OK;
00513 }
00514 
00515 /**
00516  * Called by tcp_input() when a segment arrives for a connection in
00517  * TIME_WAIT.
00518  *
00519  * @param pcb the tcp_pcb for which a segment arrived
00520  *
00521  * @note the segment which arrived is saved in global variables, therefore only the pcb
00522  *       involved is passed as a parameter to this function
00523  */
00524 static err_t
00525 tcp_timewait_input(struct tcp_pcb *pcb)
00526 {
00527   /* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */
00528   /* RFC 793 3.9 Event Processing - Segment Arrives:
00529    * - first check sequence number - we skip that one in TIME_WAIT (always
00530    *   acceptable since we only send ACKs)
00531    * - second check the RST bit (... return) */
00532   if (flags & TCP_RST)  {
00533     return ERR_OK;
00534   }
00535   /* - fourth, check the SYN bit, */
00536   if (flags & TCP_SYN) {
00537     /* If an incoming segment is not acceptable, an acknowledgment
00538        should be sent in reply */
00539     if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {
00540       /* If the SYN is in the window it is an error, send a reset */
00541       tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
00542         tcphdr->dest, tcphdr->src);
00543       return ERR_OK;
00544     }
00545   } else if (flags & TCP_FIN) {
00546     /* - eighth, check the FIN bit: Remain in the TIME-WAIT state.
00547          Restart the 2 MSL time-wait timeout.*/
00548     pcb->tmr = tcp_ticks;
00549   }
00550 
00551   if ((tcplen > 0))  {
00552     /* Acknowledge data, FIN or out-of-window SYN */
00553     pcb->flags |= TF_ACK_NOW;
00554     return tcp_output(pcb);
00555   }
00556   return ERR_OK;
00557 }
00558 
00559 /**
00560  * Implements the TCP state machine. Called by tcp_input. In some
00561  * states tcp_receive() is called to receive data. The tcp_seg
00562  * argument will be freed by the caller (tcp_input()) unless the
00563  * recv_data pointer in the pcb is set.
00564  *
00565  * @param pcb the tcp_pcb for which a segment arrived
00566  *
00567  * @note the segment which arrived is saved in global variables, therefore only the pcb
00568  *       involved is passed as a parameter to this function
00569  */
00570 static err_t
00571 tcp_process(struct tcp_pcb *pcb)
00572 {
00573   struct tcp_seg *rseg;
00574   u8_t acceptable = 0;
00575   err_t err;
00576 
00577   err = ERR_OK;
00578 
00579   /* Process incoming RST segments. */
00580   if (flags & TCP_RST) {
00581     /* First, determine if the reset is acceptable. */
00582     if (pcb->state == SYN_SENT) {
00583       if (ackno == pcb->snd_nxt) {
00584         acceptable = 1;
00585       }
00586     } else {
00587       if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, 
00588                           pcb->rcv_nxt+pcb->rcv_wnd)) {
00589         acceptable = 1;
00590       }
00591     }
00592 
00593     if (acceptable) {
00594       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));
00595       LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);
00596       recv_flags |= TF_RESET;
00597       pcb->flags &= ~TF_ACK_DELAY;
00598       return ERR_RST;
00599     } else {
00600       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
00601        seqno, pcb->rcv_nxt));
00602       LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
00603        seqno, pcb->rcv_nxt));
00604       return ERR_OK;
00605     }
00606   }
00607 
00608   if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) { 
00609     /* Cope with new connection attempt after remote end crashed */
00610     tcp_ack_now(pcb);
00611     return ERR_OK;
00612   }
00613   
00614   if ((pcb->flags & TF_RXCLOSED) == 0) {
00615     /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */
00616     pcb->tmr = tcp_ticks;
00617   }
00618   pcb->keep_cnt_sent = 0;
00619 
00620   tcp_parseopt(pcb);
00621 
00622   /* Do different things depending on the TCP state. */
00623   switch (pcb->state) {
00624   case SYN_SENT:
00625     LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,
00626      pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));
00627     /* received SYN ACK with expected sequence number? */
00628     if ((flags & TCP_ACK) && (flags & TCP_SYN)
00629         && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {
00630       pcb->snd_buf++;
00631       pcb->rcv_nxt = seqno + 1;
00632       pcb->rcv_ann_right_edge = pcb->rcv_nxt;
00633       pcb->lastack = ackno;
00634       pcb->snd_wnd = tcphdr->wnd;
00635       pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
00636       pcb->state = ESTABLISHED;
00637 
00638 #if TCP_CALCULATE_EFF_SEND_MSS
00639       pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));
00640 #endif /* TCP_CALCULATE_EFF_SEND_MSS */
00641 
00642       /* Set ssthresh again after changing pcb->mss (already set in tcp_connect
00643        * but for the default value of pcb->mss) */
00644       pcb->ssthresh = pcb->mss * 10;
00645 
00646       pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
00647       LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0));
00648       --pcb->snd_queuelen;
00649       LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));
00650       rseg = pcb->unacked;
00651       pcb->unacked = rseg->next;
00652 
00653       /* If there's nothing left to acknowledge, stop the retransmit
00654          timer, otherwise reset it to start again */
00655       if(pcb->unacked == NULL)
00656         pcb->rtime = -1;
00657       else {
00658         pcb->rtime = 0;
00659         pcb->nrtx = 0;
00660       }
00661 
00662       tcp_seg_free(rseg);
00663 
00664       /* Call the user specified function to call when sucessfully
00665        * connected. */
00666       TCP_EVENT_CONNECTED(pcb, ERR_OK, err);
00667       if (err == ERR_ABRT) {
00668         return ERR_ABRT;
00669       }
00670       tcp_ack_now(pcb);
00671     }
00672     /* received ACK? possibly a half-open connection */
00673     else if (flags & TCP_ACK) {
00674       /* send a RST to bring the other side in a non-synchronized state. */
00675       tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
00676         tcphdr->dest, tcphdr->src);
00677     }
00678     break;
00679   case SYN_RCVD:
00680     if (flags & TCP_ACK) {
00681       /* expected ACK number? */
00682       if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
00683         u16_t old_cwnd;
00684         pcb->state = ESTABLISHED;
00685         LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
00686 #if LWIP_CALLBACK_API
00687         LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);
00688 #endif
00689         /* Call the accept function. */
00690         TCP_EVENT_ACCEPT(pcb, ERR_OK, err);
00691         if (err != ERR_OK) {
00692           /* If the accept function returns with an error, we abort
00693            * the connection. */
00694           /* Already aborted? */
00695           if (err != ERR_ABRT) {
00696             tcp_abort(pcb);
00697           }
00698           return ERR_ABRT;
00699         }
00700         old_cwnd = pcb->cwnd;
00701         /* If there was any data contained within this ACK,
00702          * we'd better pass it on to the application as well. */
00703         tcp_receive(pcb);
00704 
00705         /* Prevent ACK for SYN to generate a sent event */
00706         if (pcb->acked != 0) {
00707           pcb->acked--;
00708         }
00709 
00710         pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
00711 
00712         if (recv_flags & TF_GOT_FIN) {
00713           tcp_ack_now(pcb);
00714           pcb->state = CLOSE_WAIT;
00715         }
00716       } else {
00717         /* incorrect ACK number, send RST */
00718         tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
00719                 tcphdr->dest, tcphdr->src);
00720       }
00721     } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {
00722       /* Looks like another copy of the SYN - retransmit our SYN-ACK */
00723       tcp_rexmit(pcb);
00724     }
00725     break;
00726   case CLOSE_WAIT:
00727     /* FALLTHROUGH */
00728   case ESTABLISHED:
00729     tcp_receive(pcb);
00730     if (recv_flags & TF_GOT_FIN) { /* passive close */
00731       tcp_ack_now(pcb);
00732       pcb->state = CLOSE_WAIT;
00733     }
00734     break;
00735   case FIN_WAIT_1:
00736     tcp_receive(pcb);
00737     if (recv_flags & TF_GOT_FIN) {
00738       if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
00739         LWIP_DEBUGF(TCP_DEBUG,
00740           ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
00741         tcp_ack_now(pcb);
00742         tcp_pcb_purge(pcb);
00743         TCP_RMV(&tcp_active_pcbs, pcb);
00744         pcb->state = TIME_WAIT;
00745         TCP_REG(&tcp_tw_pcbs, pcb);
00746       } else {
00747         tcp_ack_now(pcb);
00748         pcb->state = CLOSING;
00749       }
00750     } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
00751       pcb->state = FIN_WAIT_2;
00752     }
00753     break;
00754   case FIN_WAIT_2:
00755     tcp_receive(pcb);
00756     if (recv_flags & TF_GOT_FIN) {
00757       LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
00758       tcp_ack_now(pcb);
00759       tcp_pcb_purge(pcb);
00760       TCP_RMV(&tcp_active_pcbs, pcb);
00761       pcb->state = TIME_WAIT;
00762       TCP_REG(&tcp_tw_pcbs, pcb);
00763     }
00764     break;
00765   case CLOSING:
00766     tcp_receive(pcb);
00767     if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
00768       LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
00769       tcp_pcb_purge(pcb);
00770       TCP_RMV(&tcp_active_pcbs, pcb);
00771       pcb->state = TIME_WAIT;
00772       TCP_REG(&tcp_tw_pcbs, pcb);
00773     }
00774     break;
00775   case LAST_ACK:
00776     tcp_receive(pcb);
00777     if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
00778       LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
00779       /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
00780       recv_flags |= TF_CLOSED;
00781     }
00782     break;
00783   default:
00784     break;
00785   }
00786   return ERR_OK;
00787 }
00788 
00789 #if TCP_QUEUE_OOSEQ
00790 /**
00791  * Insert segment into the list (segments covered with new one will be deleted)
00792  *
00793  * Called from tcp_receive()
00794  */
00795 static void
00796 tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next)
00797 {
00798   struct tcp_seg *old_seg;
00799 
00800   if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
00801     /* received segment overlaps all following segments */
00802     tcp_segs_free(next);
00803     next = NULL;
00804   }
00805   else {
00806     /* delete some following segments
00807        oos queue may have segments with FIN flag */
00808     while (next &&
00809            TCP_SEQ_GEQ((seqno + cseg->len),
00810                       (next->tcphdr->seqno + next->len))) {
00811       /* cseg with FIN already processed */
00812       if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
00813         TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN);
00814       }
00815       old_seg = next;
00816       next = next->next;
00817       tcp_seg_free(old_seg);
00818     }
00819     if (next &&
00820         TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {
00821       /* We need to trim the incoming segment. */
00822       cseg->len = (u16_t)(next->tcphdr->seqno - seqno);
00823       pbuf_realloc(cseg->p, cseg->len);
00824     }
00825   }
00826   cseg->next = next;
00827 }
00828 #endif /* TCP_QUEUE_OOSEQ */
00829 
00830 /**
00831  * Called by tcp_process. Checks if the given segment is an ACK for outstanding
00832  * data, and if so frees the memory of the buffered data. Next, is places the
00833  * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment
00834  * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until
00835  * i it has been removed from the buffer.
00836  *
00837  * If the incoming segment constitutes an ACK for a segment that was used for RTT
00838  * estimation, the RTT is estimated here as well.
00839  *
00840  * Called from tcp_process().
00841  */
00842 static void
00843 tcp_receive(struct tcp_pcb *pcb)
00844 {
00845   struct tcp_seg *next;
00846 #if TCP_QUEUE_OOSEQ
00847   struct tcp_seg *prev, *cseg;
00848 #endif /* TCP_QUEUE_OOSEQ */
00849   struct pbuf *p;
00850   s32_t off;
00851   s16_t m;
00852   u32_t right_wnd_edge;
00853   u16_t new_tot_len;
00854   int found_dupack = 0;
00855 
00856   if (flags & TCP_ACK) {
00857     right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2;
00858 
00859     /* Update window. */
00860     if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||
00861        (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||
00862        (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {
00863       pcb->snd_wnd = tcphdr->wnd;
00864       pcb->snd_wl1 = seqno;
00865       pcb->snd_wl2 = ackno;
00866       if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) {
00867           pcb->persist_backoff = 0;
00868       }
00869       LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd));
00870 #if TCP_WND_DEBUG
00871     } else {
00872       if (pcb->snd_wnd != tcphdr->wnd) {
00873         LWIP_DEBUGF(TCP_WND_DEBUG, 
00874                     ("tcp_receive: no window update lastack %"U32_F" ackno %"
00875                      U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n",
00876                      pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));
00877       }
00878 #endif /* TCP_WND_DEBUG */
00879     }
00880 
00881     /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a
00882      * duplicate ack if:
00883      * 1) It doesn't ACK new data 
00884      * 2) length of received packet is zero (i.e. no payload) 
00885      * 3) the advertised window hasn't changed 
00886      * 4) There is outstanding unacknowledged data (retransmission timer running)
00887      * 5) The ACK is == biggest ACK sequence number so far seen (snd_una)
00888      * 
00889      * If it passes all five, should process as a dupack: 
00890      * a) dupacks < 3: do nothing 
00891      * b) dupacks == 3: fast retransmit 
00892      * c) dupacks > 3: increase cwnd 
00893      * 
00894      * If it only passes 1-3, should reset dupack counter (and add to
00895      * stats, which we don't do in lwIP)
00896      *
00897      * If it only passes 1, should reset dupack counter
00898      *
00899      */
00900 
00901     /* Clause 1 */
00902     if (TCP_SEQ_LEQ(ackno, pcb->lastack)) {
00903       pcb->acked = 0;
00904       /* Clause 2 */
00905       if (tcplen == 0) {
00906         /* Clause 3 */
00907         if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){
00908           /* Clause 4 */
00909           if (pcb->rtime >= 0) {
00910             /* Clause 5 */
00911             if (pcb->lastack == ackno) {
00912               found_dupack = 1;
00913               if (pcb->dupacks + 1 > pcb->dupacks)
00914                 ++pcb->dupacks;
00915               if (pcb->dupacks > 3) {
00916                 /* Inflate the congestion window, but not if it means that
00917                    the value overflows. */
00918                 if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
00919                   pcb->cwnd += pcb->mss;
00920                 }
00921               } else if (pcb->dupacks == 3) {
00922                 /* Do fast retransmit */
00923                 tcp_rexmit_fast(pcb);
00924               }
00925             }
00926           }
00927         }
00928       }
00929       /* If Clause (1) or more is true, but not a duplicate ack, reset
00930        * count of consecutive duplicate acks */
00931       if (!found_dupack) {
00932         pcb->dupacks = 0;
00933       }
00934     } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){
00935       /* We come here when the ACK acknowledges new data. */
00936 
00937       /* Reset the "IN Fast Retransmit" flag, since we are no longer
00938          in fast retransmit. Also reset the congestion window to the
00939          slow start threshold. */
00940       if (pcb->flags & TF_INFR) {
00941         pcb->flags &= ~TF_INFR;
00942         pcb->cwnd = pcb->ssthresh;
00943       }
00944 
00945       /* Reset the number of retransmissions. */
00946       pcb->nrtx = 0;
00947 
00948       /* Reset the retransmission time-out. */
00949       pcb->rto = (pcb->sa >> 3) + pcb->sv;
00950 
00951       /* Update the send buffer space. Diff between the two can never exceed 64K? */
00952       pcb->acked = (u16_t)(ackno - pcb->lastack);
00953 
00954       pcb->snd_buf += pcb->acked;
00955 
00956       /* Reset the fast retransmit variables. */
00957       pcb->dupacks = 0;
00958       pcb->lastack = ackno;
00959 
00960       /* Update the congestion control variables (cwnd and
00961          ssthresh). */
00962       if (pcb->state >= ESTABLISHED) {
00963         if (pcb->cwnd < pcb->ssthresh) {
00964           if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
00965             pcb->cwnd += pcb->mss;
00966           }
00967           LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd));
00968         } else {
00969           u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
00970           if (new_cwnd > pcb->cwnd) {
00971             pcb->cwnd = new_cwnd;
00972           }
00973           LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd));
00974         }
00975       }
00976       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n",
00977                                     ackno,
00978                                     pcb->unacked != NULL?
00979                                     ntohl(pcb->unacked->tcphdr->seqno): 0,
00980                                     pcb->unacked != NULL?
00981                                     ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));
00982 
00983       /* Remove segment from the unacknowledged list if the incoming
00984          ACK acknowlegdes them. */
00985       while (pcb->unacked != NULL &&
00986              TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +
00987                          TCP_TCPLEN(pcb->unacked), ackno)) {
00988         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n",
00989                                       ntohl(pcb->unacked->tcphdr->seqno),
00990                                       ntohl(pcb->unacked->tcphdr->seqno) +
00991                                       TCP_TCPLEN(pcb->unacked)));
00992 
00993         next = pcb->unacked;
00994         pcb->unacked = pcb->unacked->next;
00995 
00996         LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
00997         LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
00998         /* Prevent ACK for FIN to generate a sent event */
00999         if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
01000           pcb->acked--;
01001         }
01002 
01003         pcb->snd_queuelen -= pbuf_clen(next->p);
01004         tcp_seg_free(next);
01005 
01006         LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen));
01007         if (pcb->snd_queuelen != 0) {
01008           LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
01009                       pcb->unsent != NULL);
01010         }
01011       }
01012 
01013       /* If there's nothing left to acknowledge, stop the retransmit
01014          timer, otherwise reset it to start again */
01015       if(pcb->unacked == NULL)
01016         pcb->rtime = -1;
01017       else
01018         pcb->rtime = 0;
01019 
01020       pcb->polltmr = 0;
01021     } else {
01022       /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */
01023       pcb->acked = 0;
01024     }
01025 
01026     /* We go through the ->unsent list to see if any of the segments
01027        on the list are acknowledged by the ACK. This may seem
01028        strange since an "unsent" segment shouldn't be acked. The
01029        rationale is that lwIP puts all outstanding segments on the
01030        ->unsent list after a retransmission, so these segments may
01031        in fact have been sent once. */
01032     while (pcb->unsent != NULL &&
01033            TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + 
01034                            TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) {
01035       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",
01036                                     ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +
01037                                     TCP_TCPLEN(pcb->unsent)));
01038 
01039       next = pcb->unsent;
01040       pcb->unsent = pcb->unsent->next;
01041       LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
01042       LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
01043       /* Prevent ACK for FIN to generate a sent event */
01044       if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
01045         pcb->acked--;
01046       }
01047       pcb->snd_queuelen -= pbuf_clen(next->p);
01048       tcp_seg_free(next);
01049       LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen));
01050       if (pcb->snd_queuelen != 0) {
01051         LWIP_ASSERT("tcp_receive: valid queue length",
01052           pcb->unacked != NULL || pcb->unsent != NULL);
01053       }
01054     }
01055     /* End of ACK for new data processing. */
01056 
01057     LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n",
01058                                 pcb->rttest, pcb->rtseq, ackno));
01059 
01060     /* RTT estimation calculations. This is done by checking if the
01061        incoming segment acknowledges the segment we use to take a
01062        round-trip time measurement. */
01063     if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) {
01064       /* diff between this shouldn't exceed 32K since this are tcp timer ticks
01065          and a round-trip shouldn't be that long... */
01066       m = (s16_t)(tcp_ticks - pcb->rttest);
01067 
01068       LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n",
01069                                   m, m * TCP_SLOW_INTERVAL));
01070 
01071       /* This is taken directly from VJs original code in his paper */
01072       m = m - (pcb->sa >> 3);
01073       pcb->sa += m;
01074       if (m < 0) {
01075         m = -m;
01076       }
01077       m = m - (pcb->sv >> 2);
01078       pcb->sv += m;
01079       pcb->rto = (pcb->sa >> 3) + pcb->sv;
01080 
01081       LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n",
01082                                   pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));
01083 
01084       pcb->rttest = 0;
01085     }
01086   }
01087 
01088   /* If the incoming segment contains data, we must process it
01089      further. */
01090   if (tcplen > 0) {
01091     /* This code basically does three things:
01092 
01093     +) If the incoming segment contains data that is the next
01094     in-sequence data, this data is passed to the application. This
01095     might involve trimming the first edge of the data. The rcv_nxt
01096     variable and the advertised window are adjusted.
01097 
01098     +) If the incoming segment has data that is above the next
01099     sequence number expected (->rcv_nxt), the segment is placed on
01100     the ->ooseq queue. This is done by finding the appropriate
01101     place in the ->ooseq queue (which is ordered by sequence
01102     number) and trim the segment in both ends if needed. An
01103     immediate ACK is sent to indicate that we received an
01104     out-of-sequence segment.
01105 
01106     +) Finally, we check if the first segment on the ->ooseq queue
01107     now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If
01108     rcv_nxt > ooseq->seqno, we must trim the first edge of the
01109     segment on ->ooseq before we adjust rcv_nxt. The data in the
01110     segments that are now on sequence are chained onto the
01111     incoming segment so that we only need to call the application
01112     once.
01113     */
01114 
01115     /* First, we check if we must trim the first edge. We have to do
01116        this if the sequence number of the incoming segment is less
01117        than rcv_nxt, and the sequence number plus the length of the
01118        segment is larger than rcv_nxt. */
01119     /*    if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
01120           if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/
01121     if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){
01122       /* Trimming the first edge is done by pushing the payload
01123          pointer in the pbuf downwards. This is somewhat tricky since
01124          we do not want to discard the full contents of the pbuf up to
01125          the new starting point of the data since we have to keep the
01126          TCP header which is present in the first pbuf in the chain.
01127 
01128          What is done is really quite a nasty hack: the first pbuf in
01129          the pbuf chain is pointed to by inseg.p. Since we need to be
01130          able to deallocate the whole pbuf, we cannot change this
01131          inseg.p pointer to point to any of the later pbufs in the
01132          chain. Instead, we point the ->payload pointer in the first
01133          pbuf to data in one of the later pbufs. We also set the
01134          inseg.data pointer to point to the right place. This way, the
01135          ->p pointer will still point to the first pbuf, but the
01136          ->p->payload pointer will point to data in another pbuf.
01137 
01138          After we are done with adjusting the pbuf pointers we must
01139          adjust the ->data pointer in the seg and the segment
01140          length.*/
01141 
01142       off = pcb->rcv_nxt - seqno;
01143       p = inseg.p;
01144       LWIP_ASSERT("inseg.p != NULL", inseg.p);
01145       LWIP_ASSERT("insane offset!", (off < 0x7fff));
01146       if (inseg.p->len < off) {
01147         LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off));
01148         new_tot_len = (u16_t)(inseg.p->tot_len - off);
01149         while (p->len < off) {
01150           off -= p->len;
01151           /* KJM following line changed (with addition of new_tot_len var)
01152              to fix bug #9076
01153              inseg.p->tot_len -= p->len; */
01154           p->tot_len = new_tot_len;
01155           p->len = 0;
01156           p = p->next;
01157         }
01158         if(pbuf_header(p, (s16_t)-off)) {
01159           /* Do we need to cope with this failing?  Assert for now */
01160           LWIP_ASSERT("pbuf_header failed", 0);
01161         }
01162       } else {
01163         if(pbuf_header(inseg.p, (s16_t)-off)) {
01164           /* Do we need to cope with this failing?  Assert for now */
01165           LWIP_ASSERT("pbuf_header failed", 0);
01166         }
01167       }
01168       /* KJM following line changed to use p->payload rather than inseg->p->payload
01169          to fix bug #9076 */
01170       inseg.dataptr = p->payload;
01171       inseg.len -= (u16_t)(pcb->rcv_nxt - seqno);
01172       inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
01173     }
01174     else {
01175       if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
01176         /* the whole segment is < rcv_nxt */
01177         /* must be a duplicate of a packet that has already been correctly handled */
01178 
01179         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno));
01180         tcp_ack_now(pcb);
01181       }
01182     }
01183 
01184     /* The sequence number must be within the window (above rcv_nxt
01185        and below rcv_nxt + rcv_wnd) in order to be further
01186        processed. */
01187     if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, 
01188                         pcb->rcv_nxt + pcb->rcv_wnd - 1)){
01189       if (pcb->rcv_nxt == seqno) {
01190         /* The incoming segment is the next in sequence. We check if
01191            we have to trim the end of the segment and update rcv_nxt
01192            and pass the data to the application. */
01193         tcplen = TCP_TCPLEN(&inseg);
01194 
01195         if (tcplen > pcb->rcv_wnd) {
01196           LWIP_DEBUGF(TCP_INPUT_DEBUG, 
01197                       ("tcp_receive: other end overran receive window"
01198                        "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
01199                        seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
01200           if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
01201             /* Must remove the FIN from the header as we're trimming 
01202              * that byte of sequence-space from the packet */
01203             TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN);
01204           }
01205           /* Adjust length of segment to fit in the window. */
01206           inseg.len = pcb->rcv_wnd;
01207           if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
01208             inseg.len -= 1;
01209           }
01210           pbuf_realloc(inseg.p, inseg.len);
01211           tcplen = TCP_TCPLEN(&inseg);
01212           LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
01213                       (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
01214         }
01215 #if TCP_QUEUE_OOSEQ
01216         /* Received in-sequence data, adjust ooseq data if:
01217            - FIN has been received or
01218            - inseq overlaps with ooseq */
01219         if (pcb->ooseq != NULL) {
01220           if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
01221             LWIP_DEBUGF(TCP_INPUT_DEBUG, 
01222                         ("tcp_receive: received in-order FIN, binning ooseq queue\n"));
01223             /* Received in-order FIN means anything that was received
01224              * out of order must now have been received in-order, so
01225              * bin the ooseq queue */
01226             while (pcb->ooseq != NULL) {
01227               struct tcp_seg *old_ooseq = pcb->ooseq;
01228               pcb->ooseq = pcb->ooseq->next;
01229               tcp_seg_free(old_ooseq);
01230             }
01231           }
01232           else {
01233             next = pcb->ooseq;
01234             /* Remove all segments on ooseq that are covered by inseg already.
01235              * FIN is copied from ooseq to inseg if present. */
01236             while (next &&
01237                    TCP_SEQ_GEQ(seqno + tcplen,
01238                                next->tcphdr->seqno + next->len)) {
01239               /* inseg cannot have FIN here (already processed above) */
01240               if (TCPH_FLAGS(next->tcphdr) & TCP_FIN &&
01241                   (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) {
01242                 TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN);
01243                 tcplen = TCP_TCPLEN(&inseg);
01244               }
01245               prev = next;
01246               next = next->next;
01247               tcp_seg_free(prev);
01248             }
01249             /* Now trim right side of inseg if it overlaps with the first
01250              * segment on ooseq */
01251             if (next &&
01252                 TCP_SEQ_GT(seqno + tcplen,
01253                            next->tcphdr->seqno)) {
01254               /* inseg cannot have FIN here (already processed above) */
01255               inseg.len = (u16_t)(next->tcphdr->seqno - seqno);
01256               if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
01257                 inseg.len -= 1;
01258               }
01259               pbuf_realloc(inseg.p, inseg.len);
01260               tcplen = TCP_TCPLEN(&inseg);
01261               LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n",
01262                           (seqno + tcplen) == next->tcphdr->seqno);
01263             }
01264             pcb->ooseq = next;
01265           }
01266         }
01267 #endif /* TCP_QUEUE_OOSEQ */
01268 
01269         pcb->rcv_nxt = seqno + tcplen;
01270 
01271         /* Update the receiver's (our) window. */
01272         LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen);
01273         pcb->rcv_wnd -= tcplen;
01274 
01275         tcp_update_rcv_ann_wnd(pcb);
01276 
01277         /* If there is data in the segment, we make preparations to
01278            pass this up to the application. The ->recv_data variable
01279            is used for holding the pbuf that goes to the
01280            application. The code for reassembling out-of-sequence data
01281            chains its data on this pbuf as well.
01282 
01283            If the segment was a FIN, we set the TF_GOT_FIN flag that will
01284            be used to indicate to the application that the remote side has
01285            closed its end of the connection. */
01286         if (inseg.p->tot_len > 0) {
01287           recv_data = inseg.p;
01288           /* Since this pbuf now is the responsibility of the
01289              application, we delete our reference to it so that we won't
01290              (mistakingly) deallocate it. */
01291           inseg.p = NULL;
01292         }
01293         if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
01294           LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
01295           recv_flags |= TF_GOT_FIN;
01296         }
01297 
01298 #if TCP_QUEUE_OOSEQ
01299         /* We now check if we have segments on the ->ooseq queue that
01300            are now in sequence. */
01301         while (pcb->ooseq != NULL &&
01302                pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {
01303 
01304           cseg = pcb->ooseq;
01305           seqno = pcb->ooseq->tcphdr->seqno;
01306 
01307           pcb->rcv_nxt += TCP_TCPLEN(cseg);
01308           LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n",
01309                       pcb->rcv_wnd >= TCP_TCPLEN(cseg));
01310           pcb->rcv_wnd -= TCP_TCPLEN(cseg);
01311 
01312           tcp_update_rcv_ann_wnd(pcb);
01313 
01314           if (cseg->p->tot_len > 0) {
01315             /* Chain this pbuf onto the pbuf that we will pass to
01316                the application. */
01317             if (recv_data) {
01318               pbuf_cat(recv_data, cseg->p);
01319             } else {
01320               recv_data = cseg->p;
01321             }
01322             cseg->p = NULL;
01323           }
01324           if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
01325             LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
01326             recv_flags |= TF_GOT_FIN;
01327             if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */
01328               pcb->state = CLOSE_WAIT;
01329             } 
01330           }
01331 
01332           pcb->ooseq = cseg->next;
01333           tcp_seg_free(cseg);
01334         }
01335 #endif /* TCP_QUEUE_OOSEQ */
01336 
01337 
01338         /* Acknowledge the segment(s). */
01339         tcp_ack(pcb);
01340 
01341       } else {
01342         /* We get here if the incoming segment is out-of-sequence. */
01343         tcp_send_empty_ack(pcb);
01344 #if TCP_QUEUE_OOSEQ
01345         /* We queue the segment on the ->ooseq queue. */
01346         if (pcb->ooseq == NULL) {
01347           pcb->ooseq = tcp_seg_copy(&inseg);
01348         } else {
01349           /* If the queue is not empty, we walk through the queue and
01350              try to find a place where the sequence number of the
01351              incoming segment is between the sequence numbers of the
01352              previous and the next segment on the ->ooseq queue. That is
01353              the place where we put the incoming segment. If needed, we
01354              trim the second edges of the previous and the incoming
01355              segment so that it will fit into the sequence.
01356 
01357              If the incoming segment has the same sequence number as a
01358              segment on the ->ooseq queue, we discard the segment that
01359              contains less data. */
01360 
01361           prev = NULL;
01362           for(next = pcb->ooseq; next != NULL; next = next->next) {
01363             if (seqno == next->tcphdr->seqno) {
01364               /* The sequence number of the incoming segment is the
01365                  same as the sequence number of the segment on
01366                  ->ooseq. We check the lengths to see which one to
01367                  discard. */
01368               if (inseg.len > next->len) {
01369                 /* The incoming segment is larger than the old
01370                    segment. We replace some segments with the new
01371                    one. */
01372                 cseg = tcp_seg_copy(&inseg);
01373                 if (cseg != NULL) {
01374                   if (prev != NULL) {
01375                     prev->next = cseg;
01376                   } else {
01377                     pcb->ooseq = cseg;
01378                   }
01379                   tcp_oos_insert_segment(cseg, next);
01380                 }
01381                 break;
01382               } else {
01383                 /* Either the lenghts are the same or the incoming
01384                    segment was smaller than the old one; in either
01385                    case, we ditch the incoming segment. */
01386                 break;
01387               }
01388             } else {
01389               if (prev == NULL) {
01390                 if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {
01391                   /* The sequence number of the incoming segment is lower
01392                      than the sequence number of the first segment on the
01393                      queue. We put the incoming segment first on the
01394                      queue. */
01395                   cseg = tcp_seg_copy(&inseg);
01396                   if (cseg != NULL) {
01397                     pcb->ooseq = cseg;
01398                     tcp_oos_insert_segment(cseg, next);
01399                   }
01400                   break;
01401                 }
01402               } else {
01403                 /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
01404                   TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/
01405                 if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) {
01406                   /* The sequence number of the incoming segment is in
01407                      between the sequence numbers of the previous and
01408                      the next segment on ->ooseq. We trim trim the previous
01409                      segment, delete next segments that included in received segment
01410                      and trim received, if needed. */
01411                   cseg = tcp_seg_copy(&inseg);
01412                   if (cseg != NULL) {
01413                     if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
01414                       /* We need to trim the prev segment. */
01415                       prev->len = (u16_t)(seqno - prev->tcphdr->seqno);
01416                       pbuf_realloc(prev->p, prev->len);
01417                     }
01418                     prev->next = cseg;
01419                     tcp_oos_insert_segment(cseg, next);
01420                   }
01421                   break;
01422                 }
01423               }
01424               /* If the "next" segment is the last segment on the
01425                  ooseq queue, we add the incoming segment to the end
01426                  of the list. */
01427               if (next->next == NULL &&
01428                   TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {
01429                 if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
01430                   /* segment "next" already contains all data */
01431                   break;
01432                 }
01433                 next->next = tcp_seg_copy(&inseg);
01434                 if (next->next != NULL) {
01435                   if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
01436                     /* We need to trim the last segment. */
01437                     next->len = (u16_t)(seqno - next->tcphdr->seqno);
01438                     pbuf_realloc(next->p, next->len);
01439                   }
01440                   /* check if the remote side overruns our receive window */
01441                   if ((u32_t)tcplen + seqno > pcb->rcv_nxt + (u32_t)pcb->rcv_wnd) {
01442                     LWIP_DEBUGF(TCP_INPUT_DEBUG, 
01443                                 ("tcp_receive: other end overran receive window"
01444                                  "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
01445                                  seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
01446                     if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) {
01447                       /* Must remove the FIN from the header as we're trimming 
01448                        * that byte of sequence-space from the packet */
01449                       TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) &~ TCP_FIN);
01450                     }
01451                     /* Adjust length of segment to fit in the window. */
01452                     next->next->len = pcb->rcv_nxt + pcb->rcv_wnd - seqno;
01453                     pbuf_realloc(next->next->p, next->next->len);
01454                     tcplen = TCP_TCPLEN(next->next);
01455                     LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
01456                                 (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
01457                   }
01458                 }
01459                 break;
01460               }
01461             }
01462             prev = next;
01463           }
01464         }
01465 #endif /* TCP_QUEUE_OOSEQ */
01466 
01467       }
01468     } else {
01469       /* The incoming segment is not withing the window. */
01470       tcp_send_empty_ack(pcb);
01471     }
01472   } else {
01473     /* Segments with length 0 is taken care of here. Segments that
01474        fall out of the window are ACKed. */
01475     /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
01476       TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
01477     if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){
01478       tcp_ack_now(pcb);
01479     }
01480   }
01481 }
01482 
01483 /**
01484  * Parses the options contained in the incoming segment. 
01485  *
01486  * Called from tcp_listen_input() and tcp_process().
01487  * Currently, only the MSS option is supported!
01488  *
01489  * @param pcb the tcp_pcb for which a segment arrived
01490  */
01491 static void
01492 tcp_parseopt(struct tcp_pcb *pcb)
01493 {
01494   u16_t c, max_c;
01495   u16_t mss;
01496   u8_t *opts, opt;
01497 #if LWIP_TCP_TIMESTAMPS
01498   u32_t tsval;
01499 #endif
01500 
01501   opts = (u8_t *)tcphdr + TCP_HLEN;
01502 
01503   /* Parse the TCP MSS option, if present. */
01504   if(TCPH_HDRLEN(tcphdr) > 0x5) {
01505     max_c = (TCPH_HDRLEN(tcphdr) - 5) << 2;
01506     for (c = 0; c < max_c; ) {
01507       opt = opts[c];
01508       switch (opt) {
01509       case 0x00:
01510         /* End of options. */
01511         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n"));
01512         return;
01513       case 0x01:
01514         /* NOP option. */
01515         ++c;
01516         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n"));
01517         break;
01518       case 0x02:
01519         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n"));
01520         if (opts[c + 1] != 0x04 || c + 0x04 > max_c) {
01521           /* Bad length */
01522           LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
01523           return;
01524         }
01525         /* An MSS option with the right option length. */
01526         mss = (opts[c + 2] << 8) | opts[c + 3];
01527         /* Limit the mss to the configured TCP_MSS and prevent division by zero */
01528         pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss;
01529         /* Advance to next option */
01530         c += 0x04;
01531         break;
01532 #if LWIP_TCP_TIMESTAMPS
01533       case 0x08:
01534         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n"));
01535         if (opts[c + 1] != 0x0A || c + 0x0A > max_c) {
01536           /* Bad length */
01537           LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
01538           return;
01539         }
01540         /* TCP timestamp option with valid length */
01541         tsval = (opts[c+2]) | (opts[c+3] << 8) | 
01542           (opts[c+4] << 16) | (opts[c+5] << 24);
01543         if (flags & TCP_SYN) {
01544           pcb->ts_recent = ntohl(tsval);
01545           pcb->flags |= TF_TIMESTAMP;
01546         } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) {
01547           pcb->ts_recent = ntohl(tsval);
01548         }
01549         /* Advance to next option */
01550         c += 0x0A;
01551         break;
01552 #endif
01553       default:
01554         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n"));
01555         if (opts[c + 1] == 0) {
01556           LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
01557           /* If the length field is zero, the options are malformed
01558              and we don't process them further. */
01559           return;
01560         }
01561         /* All other options have a length field, so that we easily
01562            can skip past them. */
01563         c += opts[c + 1];
01564       }
01565     }
01566   }
01567 }
01568 
01569 #endif /* LWIP_TCP */