Marcelo Rebonatto / lwip

Dependents:   EthernetInterface

Fork of lwip by mbed official

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