lwip-1.4.1 (partial)

Dependents:   IGLOO_board

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