ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

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

Generated on Sun May 27 2012 04:36:03 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.