Used in Live Traffic Update Nokia LCD Display Project

Fork of NetServices by Segundo Equipo

Committer:
rrajan8
Date:
Wed Mar 06 19:07:23 2013 +0000
Revision:
8:92b57208ab99
Parent:
0:ac1725ba162c
This project utilizes mbed's networking features to display live traffic updates on the Nokia LCD using the MapQuest API's Traffic Web Service.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
segundo 0:ac1725ba162c 1 /**
segundo 0:ac1725ba162c 2 * @file
segundo 0:ac1725ba162c 3 * Transmission Control Protocol, incoming traffic
segundo 0:ac1725ba162c 4 *
segundo 0:ac1725ba162c 5 * The input processing functions of the TCP layer.
segundo 0:ac1725ba162c 6 *
segundo 0:ac1725ba162c 7 * These functions are generally called in the order (ip_input() ->)
segundo 0:ac1725ba162c 8 * tcp_input() -> * tcp_process() -> tcp_receive() (-> application).
segundo 0:ac1725ba162c 9 *
segundo 0:ac1725ba162c 10 */
segundo 0:ac1725ba162c 11
segundo 0:ac1725ba162c 12 /*
segundo 0:ac1725ba162c 13 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
segundo 0:ac1725ba162c 14 * All rights reserved.
segundo 0:ac1725ba162c 15 *
segundo 0:ac1725ba162c 16 * Redistribution and use in source and binary forms, with or without modification,
segundo 0:ac1725ba162c 17 * are permitted provided that the following conditions are met:
segundo 0:ac1725ba162c 18 *
segundo 0:ac1725ba162c 19 * 1. Redistributions of source code must retain the above copyright notice,
segundo 0:ac1725ba162c 20 * this list of conditions and the following disclaimer.
segundo 0:ac1725ba162c 21 * 2. Redistributions in binary form must reproduce the above copyright notice,
segundo 0:ac1725ba162c 22 * this list of conditions and the following disclaimer in the documentation
segundo 0:ac1725ba162c 23 * and/or other materials provided with the distribution.
segundo 0:ac1725ba162c 24 * 3. The name of the author may not be used to endorse or promote products
segundo 0:ac1725ba162c 25 * derived from this software without specific prior written permission.
segundo 0:ac1725ba162c 26 *
segundo 0:ac1725ba162c 27 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
segundo 0:ac1725ba162c 28 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
segundo 0:ac1725ba162c 29 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
segundo 0:ac1725ba162c 30 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
segundo 0:ac1725ba162c 31 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
segundo 0:ac1725ba162c 32 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
segundo 0:ac1725ba162c 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
segundo 0:ac1725ba162c 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
segundo 0:ac1725ba162c 35 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
segundo 0:ac1725ba162c 36 * OF SUCH DAMAGE.
segundo 0:ac1725ba162c 37 *
segundo 0:ac1725ba162c 38 * This file is part of the lwIP TCP/IP stack.
segundo 0:ac1725ba162c 39 *
segundo 0:ac1725ba162c 40 * Author: Adam Dunkels <adam@sics.se>
segundo 0:ac1725ba162c 41 *
segundo 0:ac1725ba162c 42 */
segundo 0:ac1725ba162c 43
segundo 0:ac1725ba162c 44 #include "lwip/opt.h"
segundo 0:ac1725ba162c 45
segundo 0:ac1725ba162c 46 #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
segundo 0:ac1725ba162c 47
segundo 0:ac1725ba162c 48 #include "lwip/tcp_impl.h"
segundo 0:ac1725ba162c 49 #include "lwip/def.h"
segundo 0:ac1725ba162c 50 #include "lwip/ip_addr.h"
segundo 0:ac1725ba162c 51 #include "lwip/netif.h"
segundo 0:ac1725ba162c 52 #include "lwip/mem.h"
segundo 0:ac1725ba162c 53 #include "lwip/memp.h"
segundo 0:ac1725ba162c 54 #include "lwip/inet_chksum.h"
segundo 0:ac1725ba162c 55 #include "lwip/stats.h"
segundo 0:ac1725ba162c 56 #include "lwip/snmp.h"
segundo 0:ac1725ba162c 57 #include "arch/perf.h"
segundo 0:ac1725ba162c 58
segundo 0:ac1725ba162c 59 /* These variables are global to all functions involved in the input
segundo 0:ac1725ba162c 60 processing of TCP segments. They are set by the tcp_input()
segundo 0:ac1725ba162c 61 function. */
segundo 0:ac1725ba162c 62 static struct tcp_seg inseg;
segundo 0:ac1725ba162c 63 static struct tcp_hdr *tcphdr;
segundo 0:ac1725ba162c 64 static struct ip_hdr *iphdr;
segundo 0:ac1725ba162c 65 static u32_t seqno, ackno;
segundo 0:ac1725ba162c 66 static u8_t flags;
segundo 0:ac1725ba162c 67 static u16_t tcplen;
segundo 0:ac1725ba162c 68
segundo 0:ac1725ba162c 69 static u8_t recv_flags;
segundo 0:ac1725ba162c 70 static struct pbuf *recv_data;
segundo 0:ac1725ba162c 71
segundo 0:ac1725ba162c 72 struct tcp_pcb *tcp_input_pcb;
segundo 0:ac1725ba162c 73
segundo 0:ac1725ba162c 74 /* Forward declarations. */
segundo 0:ac1725ba162c 75 static err_t tcp_process(struct tcp_pcb *pcb);
segundo 0:ac1725ba162c 76 static void tcp_receive(struct tcp_pcb *pcb);
segundo 0:ac1725ba162c 77 static void tcp_parseopt(struct tcp_pcb *pcb);
segundo 0:ac1725ba162c 78
segundo 0:ac1725ba162c 79 static err_t tcp_listen_input(struct tcp_pcb_listen *pcb);
segundo 0:ac1725ba162c 80 static err_t tcp_timewait_input(struct tcp_pcb *pcb);
segundo 0:ac1725ba162c 81
segundo 0:ac1725ba162c 82 /**
segundo 0:ac1725ba162c 83 * The initial input processing of TCP. It verifies the TCP header, demultiplexes
segundo 0:ac1725ba162c 84 * the segment between the PCBs and passes it on to tcp_process(), which implements
segundo 0:ac1725ba162c 85 * the TCP finite state machine. This function is called by the IP layer (in
segundo 0:ac1725ba162c 86 * ip_input()).
segundo 0:ac1725ba162c 87 *
segundo 0:ac1725ba162c 88 * @param p received TCP segment to process (p->payload pointing to the IP header)
segundo 0:ac1725ba162c 89 * @param inp network interface on which this segment was received
segundo 0:ac1725ba162c 90 */
segundo 0:ac1725ba162c 91 void
segundo 0:ac1725ba162c 92 tcp_input(struct pbuf *p, struct netif *inp)
segundo 0:ac1725ba162c 93 {
segundo 0:ac1725ba162c 94 struct tcp_pcb *pcb, *prev;
segundo 0:ac1725ba162c 95 struct tcp_pcb_listen *lpcb;
segundo 0:ac1725ba162c 96 #if SO_REUSE
segundo 0:ac1725ba162c 97 struct tcp_pcb *lpcb_prev = NULL;
segundo 0:ac1725ba162c 98 struct tcp_pcb_listen *lpcb_any = NULL;
segundo 0:ac1725ba162c 99 #endif /* SO_REUSE */
segundo 0:ac1725ba162c 100 u8_t hdrlen;
segundo 0:ac1725ba162c 101 err_t err;
segundo 0:ac1725ba162c 102
segundo 0:ac1725ba162c 103 PERF_START;
segundo 0:ac1725ba162c 104
segundo 0:ac1725ba162c 105 TCP_STATS_INC(tcp.recv);
segundo 0:ac1725ba162c 106 snmp_inc_tcpinsegs();
segundo 0:ac1725ba162c 107
segundo 0:ac1725ba162c 108 iphdr = (struct ip_hdr *)p->payload;
segundo 0:ac1725ba162c 109 tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);
segundo 0:ac1725ba162c 110
segundo 0:ac1725ba162c 111 #if TCP_INPUT_DEBUG
segundo 0:ac1725ba162c 112 tcp_debug_print(tcphdr);
segundo 0:ac1725ba162c 113 #endif
segundo 0:ac1725ba162c 114
segundo 0:ac1725ba162c 115 /* remove header from payload */
segundo 0:ac1725ba162c 116 if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) {
segundo 0:ac1725ba162c 117 /* drop short packets */
segundo 0:ac1725ba162c 118 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len));
segundo 0:ac1725ba162c 119 TCP_STATS_INC(tcp.lenerr);
segundo 0:ac1725ba162c 120 TCP_STATS_INC(tcp.drop);
segundo 0:ac1725ba162c 121 snmp_inc_tcpinerrs();
segundo 0:ac1725ba162c 122 pbuf_free(p);
segundo 0:ac1725ba162c 123 return;
segundo 0:ac1725ba162c 124 }
segundo 0:ac1725ba162c 125
segundo 0:ac1725ba162c 126 /* Don't even process incoming broadcasts/multicasts. */
segundo 0:ac1725ba162c 127 if (ip_addr_isbroadcast(&current_iphdr_dest, inp) ||
segundo 0:ac1725ba162c 128 ip_addr_ismulticast(&current_iphdr_dest)) {
segundo 0:ac1725ba162c 129 TCP_STATS_INC(tcp.proterr);
segundo 0:ac1725ba162c 130 TCP_STATS_INC(tcp.drop);
segundo 0:ac1725ba162c 131 snmp_inc_tcpinerrs();
segundo 0:ac1725ba162c 132 pbuf_free(p);
segundo 0:ac1725ba162c 133 return;
segundo 0:ac1725ba162c 134 }
segundo 0:ac1725ba162c 135
segundo 0:ac1725ba162c 136 #if CHECKSUM_CHECK_TCP
segundo 0:ac1725ba162c 137 /* Verify TCP checksum. */
segundo 0:ac1725ba162c 138 if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
segundo 0:ac1725ba162c 139 IP_PROTO_TCP, p->tot_len) != 0) {
segundo 0:ac1725ba162c 140 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n",
segundo 0:ac1725ba162c 141 inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
segundo 0:ac1725ba162c 142 IP_PROTO_TCP, p->tot_len)));
segundo 0:ac1725ba162c 143 #if TCP_DEBUG
segundo 0:ac1725ba162c 144 tcp_debug_print(tcphdr);
segundo 0:ac1725ba162c 145 #endif /* TCP_DEBUG */
segundo 0:ac1725ba162c 146 TCP_STATS_INC(tcp.chkerr);
segundo 0:ac1725ba162c 147 TCP_STATS_INC(tcp.drop);
segundo 0:ac1725ba162c 148 snmp_inc_tcpinerrs();
segundo 0:ac1725ba162c 149 pbuf_free(p);
segundo 0:ac1725ba162c 150 return;
segundo 0:ac1725ba162c 151 }
segundo 0:ac1725ba162c 152 #endif
segundo 0:ac1725ba162c 153
segundo 0:ac1725ba162c 154 /* Move the payload pointer in the pbuf so that it points to the
segundo 0:ac1725ba162c 155 TCP data instead of the TCP header. */
segundo 0:ac1725ba162c 156 hdrlen = TCPH_HDRLEN(tcphdr);
segundo 0:ac1725ba162c 157 if(pbuf_header(p, -(hdrlen * 4))){
segundo 0:ac1725ba162c 158 /* drop short packets */
segundo 0:ac1725ba162c 159 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n"));
segundo 0:ac1725ba162c 160 TCP_STATS_INC(tcp.lenerr);
segundo 0:ac1725ba162c 161 TCP_STATS_INC(tcp.drop);
segundo 0:ac1725ba162c 162 snmp_inc_tcpinerrs();
segundo 0:ac1725ba162c 163 pbuf_free(p);
segundo 0:ac1725ba162c 164 return;
segundo 0:ac1725ba162c 165 }
segundo 0:ac1725ba162c 166
segundo 0:ac1725ba162c 167 /* Convert fields in TCP header to host byte order. */
segundo 0:ac1725ba162c 168 tcphdr->src = ntohs(tcphdr->src);
segundo 0:ac1725ba162c 169 tcphdr->dest = ntohs(tcphdr->dest);
segundo 0:ac1725ba162c 170 seqno = tcphdr->seqno = ntohl(tcphdr->seqno);
segundo 0:ac1725ba162c 171 ackno = tcphdr->ackno = ntohl(tcphdr->ackno);
segundo 0:ac1725ba162c 172 tcphdr->wnd = ntohs(tcphdr->wnd);
segundo 0:ac1725ba162c 173
segundo 0:ac1725ba162c 174 flags = TCPH_FLAGS(tcphdr);
segundo 0:ac1725ba162c 175 tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0);
segundo 0:ac1725ba162c 176
segundo 0:ac1725ba162c 177 /* Demultiplex an incoming segment. First, we check if it is destined
segundo 0:ac1725ba162c 178 for an active connection. */
segundo 0:ac1725ba162c 179 prev = NULL;
segundo 0:ac1725ba162c 180
segundo 0:ac1725ba162c 181
segundo 0:ac1725ba162c 182 for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
segundo 0:ac1725ba162c 183 LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED);
segundo 0:ac1725ba162c 184 LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
segundo 0:ac1725ba162c 185 LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);
segundo 0:ac1725ba162c 186 if (pcb->remote_port == tcphdr->src &&
segundo 0:ac1725ba162c 187 pcb->local_port == tcphdr->dest &&
segundo 0:ac1725ba162c 188 ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src) &&
segundo 0:ac1725ba162c 189 ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest)) {
segundo 0:ac1725ba162c 190
segundo 0:ac1725ba162c 191 /* Move this PCB to the front of the list so that subsequent
segundo 0:ac1725ba162c 192 lookups will be faster (we exploit locality in TCP segment
segundo 0:ac1725ba162c 193 arrivals). */
segundo 0:ac1725ba162c 194 LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb);
segundo 0:ac1725ba162c 195 if (prev != NULL) {
segundo 0:ac1725ba162c 196 prev->next = pcb->next;
segundo 0:ac1725ba162c 197 pcb->next = tcp_active_pcbs;
segundo 0:ac1725ba162c 198 tcp_active_pcbs = pcb;
segundo 0:ac1725ba162c 199 }
segundo 0:ac1725ba162c 200 LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb);
segundo 0:ac1725ba162c 201 break;
segundo 0:ac1725ba162c 202 }
segundo 0:ac1725ba162c 203 prev = pcb;
segundo 0:ac1725ba162c 204 }
segundo 0:ac1725ba162c 205
segundo 0:ac1725ba162c 206 if (pcb == NULL) {
segundo 0:ac1725ba162c 207 /* If it did not go to an active connection, we check the connections
segundo 0:ac1725ba162c 208 in the TIME-WAIT state. */
segundo 0:ac1725ba162c 209 for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
segundo 0:ac1725ba162c 210 LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
segundo 0:ac1725ba162c 211 if (pcb->remote_port == tcphdr->src &&
segundo 0:ac1725ba162c 212 pcb->local_port == tcphdr->dest &&
segundo 0:ac1725ba162c 213 ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src) &&
segundo 0:ac1725ba162c 214 ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest)) {
segundo 0:ac1725ba162c 215 /* We don't really care enough to move this PCB to the front
segundo 0:ac1725ba162c 216 of the list since we are not very likely to receive that
segundo 0:ac1725ba162c 217 many segments for connections in TIME-WAIT. */
segundo 0:ac1725ba162c 218 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n"));
segundo 0:ac1725ba162c 219 tcp_timewait_input(pcb);
segundo 0:ac1725ba162c 220 pbuf_free(p);
segundo 0:ac1725ba162c 221 return;
segundo 0:ac1725ba162c 222 }
segundo 0:ac1725ba162c 223 }
segundo 0:ac1725ba162c 224
segundo 0:ac1725ba162c 225 /* Finally, if we still did not get a match, we check all PCBs that
segundo 0:ac1725ba162c 226 are LISTENing for incoming connections. */
segundo 0:ac1725ba162c 227 prev = NULL;
segundo 0:ac1725ba162c 228 for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
segundo 0:ac1725ba162c 229 if (lpcb->local_port == tcphdr->dest) {
segundo 0:ac1725ba162c 230 #if SO_REUSE
segundo 0:ac1725ba162c 231 if (ip_addr_cmp(&(lpcb->local_ip), &current_iphdr_dest)) {
segundo 0:ac1725ba162c 232 /* found an exact match */
segundo 0:ac1725ba162c 233 break;
segundo 0:ac1725ba162c 234 } else if(ip_addr_isany(&(lpcb->local_ip))) {
segundo 0:ac1725ba162c 235 /* found an ANY-match */
segundo 0:ac1725ba162c 236 lpcb_any = lpcb;
segundo 0:ac1725ba162c 237 lpcb_prev = prev;
segundo 0:ac1725ba162c 238 }
segundo 0:ac1725ba162c 239 #else /* SO_REUSE */
segundo 0:ac1725ba162c 240 if (ip_addr_cmp(&(lpcb->local_ip), &current_iphdr_dest) ||
segundo 0:ac1725ba162c 241 ip_addr_isany(&(lpcb->local_ip))) {
segundo 0:ac1725ba162c 242 /* found a match */
segundo 0:ac1725ba162c 243 break;
segundo 0:ac1725ba162c 244 }
segundo 0:ac1725ba162c 245 #endif /* SO_REUSE */
segundo 0:ac1725ba162c 246 }
segundo 0:ac1725ba162c 247 prev = (struct tcp_pcb *)lpcb;
segundo 0:ac1725ba162c 248 }
segundo 0:ac1725ba162c 249 #if SO_REUSE
segundo 0:ac1725ba162c 250 /* first try specific local IP */
segundo 0:ac1725ba162c 251 if (lpcb == NULL) {
segundo 0:ac1725ba162c 252 /* only pass to ANY if no specific local IP has been found */
segundo 0:ac1725ba162c 253 lpcb = lpcb_any;
segundo 0:ac1725ba162c 254 prev = lpcb_prev;
segundo 0:ac1725ba162c 255 }
segundo 0:ac1725ba162c 256 #endif /* SO_REUSE */
segundo 0:ac1725ba162c 257 if (lpcb != NULL) {
segundo 0:ac1725ba162c 258 /* Move this PCB to the front of the list so that subsequent
segundo 0:ac1725ba162c 259 lookups will be faster (we exploit locality in TCP segment
segundo 0:ac1725ba162c 260 arrivals). */
segundo 0:ac1725ba162c 261 if (prev != NULL) {
segundo 0:ac1725ba162c 262 ((struct tcp_pcb_listen *)prev)->next = lpcb->next;
segundo 0:ac1725ba162c 263 /* our successor is the remainder of the listening list */
segundo 0:ac1725ba162c 264 lpcb->next = tcp_listen_pcbs.listen_pcbs;
segundo 0:ac1725ba162c 265 /* put this listening pcb at the head of the listening list */
segundo 0:ac1725ba162c 266 tcp_listen_pcbs.listen_pcbs = lpcb;
segundo 0:ac1725ba162c 267 }
segundo 0:ac1725ba162c 268
segundo 0:ac1725ba162c 269 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));
segundo 0:ac1725ba162c 270 tcp_listen_input(lpcb);
segundo 0:ac1725ba162c 271 pbuf_free(p);
segundo 0:ac1725ba162c 272 return;
segundo 0:ac1725ba162c 273 }
segundo 0:ac1725ba162c 274 }
segundo 0:ac1725ba162c 275
segundo 0:ac1725ba162c 276 #if TCP_INPUT_DEBUG
segundo 0:ac1725ba162c 277 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags "));
segundo 0:ac1725ba162c 278 tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
segundo 0:ac1725ba162c 279 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n"));
segundo 0:ac1725ba162c 280 #endif /* TCP_INPUT_DEBUG */
segundo 0:ac1725ba162c 281
segundo 0:ac1725ba162c 282
segundo 0:ac1725ba162c 283 if (pcb != NULL) {
segundo 0:ac1725ba162c 284 /* The incoming segment belongs to a connection. */
segundo 0:ac1725ba162c 285 #if TCP_INPUT_DEBUG
segundo 0:ac1725ba162c 286 #if TCP_DEBUG
segundo 0:ac1725ba162c 287 tcp_debug_print_state(pcb->state);
segundo 0:ac1725ba162c 288 #endif /* TCP_DEBUG */
segundo 0:ac1725ba162c 289 #endif /* TCP_INPUT_DEBUG */
segundo 0:ac1725ba162c 290
segundo 0:ac1725ba162c 291 /* Set up a tcp_seg structure. */
segundo 0:ac1725ba162c 292 inseg.next = NULL;
segundo 0:ac1725ba162c 293 inseg.len = p->tot_len;
segundo 0:ac1725ba162c 294 inseg.dataptr = p->payload;
segundo 0:ac1725ba162c 295 inseg.p = p;
segundo 0:ac1725ba162c 296 inseg.tcphdr = tcphdr;
segundo 0:ac1725ba162c 297
segundo 0:ac1725ba162c 298 recv_data = NULL;
segundo 0:ac1725ba162c 299 recv_flags = 0;
segundo 0:ac1725ba162c 300
segundo 0:ac1725ba162c 301 /* If there is data which was previously "refused" by upper layer */
segundo 0:ac1725ba162c 302 if (pcb->refused_data != NULL) {
segundo 0:ac1725ba162c 303 /* Notify again application with data previously received. */
segundo 0:ac1725ba162c 304 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n"));
segundo 0:ac1725ba162c 305 TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
segundo 0:ac1725ba162c 306 if (err == ERR_OK) {
segundo 0:ac1725ba162c 307 pcb->refused_data = NULL;
segundo 0:ac1725ba162c 308 } else {
segundo 0:ac1725ba162c 309 /* if err == ERR_ABRT, 'pcb' is already deallocated */
segundo 0:ac1725ba162c 310 /* drop incoming packets, because pcb is "full" */
segundo 0:ac1725ba162c 311 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
segundo 0:ac1725ba162c 312 TCP_STATS_INC(tcp.drop);
segundo 0:ac1725ba162c 313 snmp_inc_tcpinerrs();
segundo 0:ac1725ba162c 314 pbuf_free(p);
segundo 0:ac1725ba162c 315 return;
segundo 0:ac1725ba162c 316 }
segundo 0:ac1725ba162c 317 }
segundo 0:ac1725ba162c 318 tcp_input_pcb = pcb;
segundo 0:ac1725ba162c 319 err = tcp_process(pcb);
segundo 0:ac1725ba162c 320 /* A return value of ERR_ABRT means that tcp_abort() was called
segundo 0:ac1725ba162c 321 and that the pcb has been freed. If so, we don't do anything. */
segundo 0:ac1725ba162c 322 if (err != ERR_ABRT) {
segundo 0:ac1725ba162c 323 if (recv_flags & TF_RESET) {
segundo 0:ac1725ba162c 324 /* TF_RESET means that the connection was reset by the other
segundo 0:ac1725ba162c 325 end. We then call the error callback to inform the
segundo 0:ac1725ba162c 326 application that the connection is dead before we
segundo 0:ac1725ba162c 327 deallocate the PCB. */
segundo 0:ac1725ba162c 328 TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST);
segundo 0:ac1725ba162c 329 tcp_pcb_remove(&tcp_active_pcbs, pcb);
segundo 0:ac1725ba162c 330 memp_free(MEMP_TCP_PCB, pcb);
segundo 0:ac1725ba162c 331 } else if (recv_flags & TF_CLOSED) {
segundo 0:ac1725ba162c 332 /* The connection has been closed and we will deallocate the
segundo 0:ac1725ba162c 333 PCB. */
segundo 0:ac1725ba162c 334 tcp_pcb_remove(&tcp_active_pcbs, pcb);
segundo 0:ac1725ba162c 335 memp_free(MEMP_TCP_PCB, pcb);
segundo 0:ac1725ba162c 336 } else {
segundo 0:ac1725ba162c 337 err = ERR_OK;
segundo 0:ac1725ba162c 338 /* If the application has registered a "sent" function to be
segundo 0:ac1725ba162c 339 called when new send buffer space is available, we call it
segundo 0:ac1725ba162c 340 now. */
segundo 0:ac1725ba162c 341 if (pcb->acked > 0) {
segundo 0:ac1725ba162c 342 TCP_EVENT_SENT(pcb, pcb->acked, err);
segundo 0:ac1725ba162c 343 if (err == ERR_ABRT) {
segundo 0:ac1725ba162c 344 goto aborted;
segundo 0:ac1725ba162c 345 }
segundo 0:ac1725ba162c 346 }
segundo 0:ac1725ba162c 347
segundo 0:ac1725ba162c 348 if (recv_data != NULL) {
segundo 0:ac1725ba162c 349 if (pcb->flags & TF_RXCLOSED) {
segundo 0:ac1725ba162c 350 /* received data although already closed -> abort (send RST) to
segundo 0:ac1725ba162c 351 notify the remote host that not all data has been processed */
segundo 0:ac1725ba162c 352 pbuf_free(recv_data);
segundo 0:ac1725ba162c 353 tcp_abort(pcb);
segundo 0:ac1725ba162c 354 goto aborted;
segundo 0:ac1725ba162c 355 }
segundo 0:ac1725ba162c 356 if (flags & TCP_PSH) {
segundo 0:ac1725ba162c 357 recv_data->flags |= PBUF_FLAG_PUSH;
segundo 0:ac1725ba162c 358 }
segundo 0:ac1725ba162c 359
segundo 0:ac1725ba162c 360 /* Notify application that data has been received. */
segundo 0:ac1725ba162c 361 TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);
segundo 0:ac1725ba162c 362 if (err == ERR_ABRT) {
segundo 0:ac1725ba162c 363 goto aborted;
segundo 0:ac1725ba162c 364 }
segundo 0:ac1725ba162c 365
segundo 0:ac1725ba162c 366 /* If the upper layer can't receive this data, store it */
segundo 0:ac1725ba162c 367 if (err != ERR_OK) {
segundo 0:ac1725ba162c 368 pcb->refused_data = recv_data;
segundo 0:ac1725ba162c 369 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n"));
segundo 0:ac1725ba162c 370 }
segundo 0:ac1725ba162c 371 }
segundo 0:ac1725ba162c 372
segundo 0:ac1725ba162c 373 /* If a FIN segment was received, we call the callback
segundo 0:ac1725ba162c 374 function with a NULL buffer to indicate EOF. */
segundo 0:ac1725ba162c 375 if (recv_flags & TF_GOT_FIN) {
segundo 0:ac1725ba162c 376 /* correct rcv_wnd as the application won't call tcp_recved()
segundo 0:ac1725ba162c 377 for the FIN's seqno */
segundo 0:ac1725ba162c 378 if (pcb->rcv_wnd != TCP_WND) {
segundo 0:ac1725ba162c 379 pcb->rcv_wnd++;
segundo 0:ac1725ba162c 380 }
segundo 0:ac1725ba162c 381 TCP_EVENT_CLOSED(pcb, err);
segundo 0:ac1725ba162c 382 if (err == ERR_ABRT) {
segundo 0:ac1725ba162c 383 goto aborted;
segundo 0:ac1725ba162c 384 }
segundo 0:ac1725ba162c 385 }
segundo 0:ac1725ba162c 386
segundo 0:ac1725ba162c 387 tcp_input_pcb = NULL;
segundo 0:ac1725ba162c 388 /* Try to send something out. */
segundo 0:ac1725ba162c 389 tcp_output(pcb);
segundo 0:ac1725ba162c 390 #if TCP_INPUT_DEBUG
segundo 0:ac1725ba162c 391 #if TCP_DEBUG
segundo 0:ac1725ba162c 392 tcp_debug_print_state(pcb->state);
segundo 0:ac1725ba162c 393 #endif /* TCP_DEBUG */
segundo 0:ac1725ba162c 394 #endif /* TCP_INPUT_DEBUG */
segundo 0:ac1725ba162c 395 }
segundo 0:ac1725ba162c 396 }
segundo 0:ac1725ba162c 397 /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()).
segundo 0:ac1725ba162c 398 Below this line, 'pcb' may not be dereferenced! */
segundo 0:ac1725ba162c 399 aborted:
segundo 0:ac1725ba162c 400 tcp_input_pcb = NULL;
segundo 0:ac1725ba162c 401 recv_data = NULL;
segundo 0:ac1725ba162c 402
segundo 0:ac1725ba162c 403 /* give up our reference to inseg.p */
segundo 0:ac1725ba162c 404 if (inseg.p != NULL)
segundo 0:ac1725ba162c 405 {
segundo 0:ac1725ba162c 406 pbuf_free(inseg.p);
segundo 0:ac1725ba162c 407 inseg.p = NULL;
segundo 0:ac1725ba162c 408 }
segundo 0:ac1725ba162c 409 } else {
segundo 0:ac1725ba162c 410
segundo 0:ac1725ba162c 411 /* If no matching PCB was found, send a TCP RST (reset) to the
segundo 0:ac1725ba162c 412 sender. */
segundo 0:ac1725ba162c 413 LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n"));
segundo 0:ac1725ba162c 414 if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {
segundo 0:ac1725ba162c 415 TCP_STATS_INC(tcp.proterr);
segundo 0:ac1725ba162c 416 TCP_STATS_INC(tcp.drop);
segundo 0:ac1725ba162c 417 tcp_rst(ackno, seqno + tcplen,
segundo 0:ac1725ba162c 418 ip_current_dest_addr(), ip_current_src_addr(),
segundo 0:ac1725ba162c 419 tcphdr->dest, tcphdr->src);
segundo 0:ac1725ba162c 420 }
segundo 0:ac1725ba162c 421 pbuf_free(p);
segundo 0:ac1725ba162c 422 }
segundo 0:ac1725ba162c 423
segundo 0:ac1725ba162c 424 LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());
segundo 0:ac1725ba162c 425 PERF_STOP("tcp_input");
segundo 0:ac1725ba162c 426 }
segundo 0:ac1725ba162c 427
segundo 0:ac1725ba162c 428 /**
segundo 0:ac1725ba162c 429 * Called by tcp_input() when a segment arrives for a listening
segundo 0:ac1725ba162c 430 * connection (from tcp_input()).
segundo 0:ac1725ba162c 431 *
segundo 0:ac1725ba162c 432 * @param pcb the tcp_pcb_listen for which a segment arrived
segundo 0:ac1725ba162c 433 * @return ERR_OK if the segment was processed
segundo 0:ac1725ba162c 434 * another err_t on error
segundo 0:ac1725ba162c 435 *
segundo 0:ac1725ba162c 436 * @note the return value is not (yet?) used in tcp_input()
segundo 0:ac1725ba162c 437 * @note the segment which arrived is saved in global variables, therefore only the pcb
segundo 0:ac1725ba162c 438 * involved is passed as a parameter to this function
segundo 0:ac1725ba162c 439 */
segundo 0:ac1725ba162c 440 static err_t
segundo 0:ac1725ba162c 441 tcp_listen_input(struct tcp_pcb_listen *pcb)
segundo 0:ac1725ba162c 442 {
segundo 0:ac1725ba162c 443 struct tcp_pcb *npcb;
segundo 0:ac1725ba162c 444 err_t rc;
segundo 0:ac1725ba162c 445
segundo 0:ac1725ba162c 446 /* In the LISTEN state, we check for incoming SYN segments,
segundo 0:ac1725ba162c 447 creates a new PCB, and responds with a SYN|ACK. */
segundo 0:ac1725ba162c 448 if (flags & TCP_ACK) {
segundo 0:ac1725ba162c 449 /* For incoming segments with the ACK flag set, respond with a
segundo 0:ac1725ba162c 450 RST. */
segundo 0:ac1725ba162c 451 LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));
segundo 0:ac1725ba162c 452 tcp_rst(ackno + 1, seqno + tcplen,
segundo 0:ac1725ba162c 453 ip_current_dest_addr(), ip_current_src_addr(),
segundo 0:ac1725ba162c 454 tcphdr->dest, tcphdr->src);
segundo 0:ac1725ba162c 455 } else if (flags & TCP_SYN) {
segundo 0:ac1725ba162c 456 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
segundo 0:ac1725ba162c 457 #if TCP_LISTEN_BACKLOG
segundo 0:ac1725ba162c 458 if (pcb->accepts_pending >= pcb->backlog) {
segundo 0:ac1725ba162c 459 LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest));
segundo 0:ac1725ba162c 460 return ERR_ABRT;
segundo 0:ac1725ba162c 461 }
segundo 0:ac1725ba162c 462 #endif /* TCP_LISTEN_BACKLOG */
segundo 0:ac1725ba162c 463 npcb = tcp_alloc(pcb->prio);
segundo 0:ac1725ba162c 464 /* If a new PCB could not be created (probably due to lack of memory),
segundo 0:ac1725ba162c 465 we don't do anything, but rely on the sender will retransmit the
segundo 0:ac1725ba162c 466 SYN at a time when we have more memory available. */
segundo 0:ac1725ba162c 467 if (npcb == NULL) {
segundo 0:ac1725ba162c 468 LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n"));
segundo 0:ac1725ba162c 469 TCP_STATS_INC(tcp.memerr);
segundo 0:ac1725ba162c 470 return ERR_MEM;
segundo 0:ac1725ba162c 471 }
segundo 0:ac1725ba162c 472 #if TCP_LISTEN_BACKLOG
segundo 0:ac1725ba162c 473 pcb->accepts_pending++;
segundo 0:ac1725ba162c 474 #endif /* TCP_LISTEN_BACKLOG */
segundo 0:ac1725ba162c 475 /* Set up the new PCB. */
segundo 0:ac1725ba162c 476 ip_addr_copy(npcb->local_ip, current_iphdr_dest);
segundo 0:ac1725ba162c 477 npcb->local_port = pcb->local_port;
segundo 0:ac1725ba162c 478 ip_addr_copy(npcb->remote_ip, current_iphdr_src);
segundo 0:ac1725ba162c 479 npcb->remote_port = tcphdr->src;
segundo 0:ac1725ba162c 480 npcb->state = SYN_RCVD;
segundo 0:ac1725ba162c 481 npcb->rcv_nxt = seqno + 1;
segundo 0:ac1725ba162c 482 npcb->rcv_ann_right_edge = npcb->rcv_nxt;
segundo 0:ac1725ba162c 483 npcb->snd_wnd = tcphdr->wnd;
segundo 0:ac1725ba162c 484 npcb->ssthresh = npcb->snd_wnd;
segundo 0:ac1725ba162c 485 npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
segundo 0:ac1725ba162c 486 npcb->callback_arg = pcb->callback_arg;
segundo 0:ac1725ba162c 487 #if LWIP_CALLBACK_API
segundo 0:ac1725ba162c 488 npcb->accept = pcb->accept;
segundo 0:ac1725ba162c 489 #endif /* LWIP_CALLBACK_API */
segundo 0:ac1725ba162c 490 /* inherit socket options */
segundo 0:ac1725ba162c 491 npcb->so_options = pcb->so_options & SOF_INHERITED;
segundo 0:ac1725ba162c 492 /* Register the new PCB so that we can begin receiving segments
segundo 0:ac1725ba162c 493 for it. */
segundo 0:ac1725ba162c 494 TCP_REG(&tcp_active_pcbs, npcb);
segundo 0:ac1725ba162c 495
segundo 0:ac1725ba162c 496 /* Parse any options in the SYN. */
segundo 0:ac1725ba162c 497 tcp_parseopt(npcb);
segundo 0:ac1725ba162c 498 #if TCP_CALCULATE_EFF_SEND_MSS
segundo 0:ac1725ba162c 499 npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip));
segundo 0:ac1725ba162c 500 #endif /* TCP_CALCULATE_EFF_SEND_MSS */
segundo 0:ac1725ba162c 501
segundo 0:ac1725ba162c 502 snmp_inc_tcppassiveopens();
segundo 0:ac1725ba162c 503
segundo 0:ac1725ba162c 504 /* Send a SYN|ACK together with the MSS option. */
segundo 0:ac1725ba162c 505 rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK);
segundo 0:ac1725ba162c 506 if (rc != ERR_OK) {
segundo 0:ac1725ba162c 507 tcp_abandon(npcb, 0);
segundo 0:ac1725ba162c 508 return rc;
segundo 0:ac1725ba162c 509 }
segundo 0:ac1725ba162c 510 return tcp_output(npcb);
segundo 0:ac1725ba162c 511 }
segundo 0:ac1725ba162c 512 return ERR_OK;
segundo 0:ac1725ba162c 513 }
segundo 0:ac1725ba162c 514
segundo 0:ac1725ba162c 515 /**
segundo 0:ac1725ba162c 516 * Called by tcp_input() when a segment arrives for a connection in
segundo 0:ac1725ba162c 517 * TIME_WAIT.
segundo 0:ac1725ba162c 518 *
segundo 0:ac1725ba162c 519 * @param pcb the tcp_pcb for which a segment arrived
segundo 0:ac1725ba162c 520 *
segundo 0:ac1725ba162c 521 * @note the segment which arrived is saved in global variables, therefore only the pcb
segundo 0:ac1725ba162c 522 * involved is passed as a parameter to this function
segundo 0:ac1725ba162c 523 */
segundo 0:ac1725ba162c 524 static err_t
segundo 0:ac1725ba162c 525 tcp_timewait_input(struct tcp_pcb *pcb)
segundo 0:ac1725ba162c 526 {
segundo 0:ac1725ba162c 527 /* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */
segundo 0:ac1725ba162c 528 /* RFC 793 3.9 Event Processing - Segment Arrives:
segundo 0:ac1725ba162c 529 * - first check sequence number - we skip that one in TIME_WAIT (always
segundo 0:ac1725ba162c 530 * acceptable since we only send ACKs)
segundo 0:ac1725ba162c 531 * - second check the RST bit (... return) */
segundo 0:ac1725ba162c 532 if (flags & TCP_RST) {
segundo 0:ac1725ba162c 533 return ERR_OK;
segundo 0:ac1725ba162c 534 }
segundo 0:ac1725ba162c 535 /* - fourth, check the SYN bit, */
segundo 0:ac1725ba162c 536 if (flags & TCP_SYN) {
segundo 0:ac1725ba162c 537 /* If an incoming segment is not acceptable, an acknowledgment
segundo 0:ac1725ba162c 538 should be sent in reply */
segundo 0:ac1725ba162c 539 if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {
segundo 0:ac1725ba162c 540 /* If the SYN is in the window it is an error, send a reset */
segundo 0:ac1725ba162c 541 tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
segundo 0:ac1725ba162c 542 tcphdr->dest, tcphdr->src);
segundo 0:ac1725ba162c 543 return ERR_OK;
segundo 0:ac1725ba162c 544 }
segundo 0:ac1725ba162c 545 } else if (flags & TCP_FIN) {
segundo 0:ac1725ba162c 546 /* - eighth, check the FIN bit: Remain in the TIME-WAIT state.
segundo 0:ac1725ba162c 547 Restart the 2 MSL time-wait timeout.*/
segundo 0:ac1725ba162c 548 pcb->tmr = tcp_ticks;
segundo 0:ac1725ba162c 549 }
segundo 0:ac1725ba162c 550
segundo 0:ac1725ba162c 551 if ((tcplen > 0)) {
segundo 0:ac1725ba162c 552 /* Acknowledge data, FIN or out-of-window SYN */
segundo 0:ac1725ba162c 553 pcb->flags |= TF_ACK_NOW;
segundo 0:ac1725ba162c 554 return tcp_output(pcb);
segundo 0:ac1725ba162c 555 }
segundo 0:ac1725ba162c 556 return ERR_OK;
segundo 0:ac1725ba162c 557 }
segundo 0:ac1725ba162c 558
segundo 0:ac1725ba162c 559 /**
segundo 0:ac1725ba162c 560 * Implements the TCP state machine. Called by tcp_input. In some
segundo 0:ac1725ba162c 561 * states tcp_receive() is called to receive data. The tcp_seg
segundo 0:ac1725ba162c 562 * argument will be freed by the caller (tcp_input()) unless the
segundo 0:ac1725ba162c 563 * recv_data pointer in the pcb is set.
segundo 0:ac1725ba162c 564 *
segundo 0:ac1725ba162c 565 * @param pcb the tcp_pcb for which a segment arrived
segundo 0:ac1725ba162c 566 *
segundo 0:ac1725ba162c 567 * @note the segment which arrived is saved in global variables, therefore only the pcb
segundo 0:ac1725ba162c 568 * involved is passed as a parameter to this function
segundo 0:ac1725ba162c 569 */
segundo 0:ac1725ba162c 570 static err_t
segundo 0:ac1725ba162c 571 tcp_process(struct tcp_pcb *pcb)
segundo 0:ac1725ba162c 572 {
segundo 0:ac1725ba162c 573 struct tcp_seg *rseg;
segundo 0:ac1725ba162c 574 u8_t acceptable = 0;
segundo 0:ac1725ba162c 575 err_t err;
segundo 0:ac1725ba162c 576
segundo 0:ac1725ba162c 577 err = ERR_OK;
segundo 0:ac1725ba162c 578
segundo 0:ac1725ba162c 579 /* Process incoming RST segments. */
segundo 0:ac1725ba162c 580 if (flags & TCP_RST) {
segundo 0:ac1725ba162c 581 /* First, determine if the reset is acceptable. */
segundo 0:ac1725ba162c 582 if (pcb->state == SYN_SENT) {
segundo 0:ac1725ba162c 583 if (ackno == pcb->snd_nxt) {
segundo 0:ac1725ba162c 584 acceptable = 1;
segundo 0:ac1725ba162c 585 }
segundo 0:ac1725ba162c 586 } else {
segundo 0:ac1725ba162c 587 if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
segundo 0:ac1725ba162c 588 pcb->rcv_nxt+pcb->rcv_wnd)) {
segundo 0:ac1725ba162c 589 acceptable = 1;
segundo 0:ac1725ba162c 590 }
segundo 0:ac1725ba162c 591 }
segundo 0:ac1725ba162c 592
segundo 0:ac1725ba162c 593 if (acceptable) {
segundo 0:ac1725ba162c 594 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));
segundo 0:ac1725ba162c 595 LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);
segundo 0:ac1725ba162c 596 recv_flags |= TF_RESET;
segundo 0:ac1725ba162c 597 pcb->flags &= ~TF_ACK_DELAY;
segundo 0:ac1725ba162c 598 return ERR_RST;
segundo 0:ac1725ba162c 599 } else {
segundo 0:ac1725ba162c 600 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
segundo 0:ac1725ba162c 601 seqno, pcb->rcv_nxt));
segundo 0:ac1725ba162c 602 LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
segundo 0:ac1725ba162c 603 seqno, pcb->rcv_nxt));
segundo 0:ac1725ba162c 604 return ERR_OK;
segundo 0:ac1725ba162c 605 }
segundo 0:ac1725ba162c 606 }
segundo 0:ac1725ba162c 607
segundo 0:ac1725ba162c 608 if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) {
segundo 0:ac1725ba162c 609 /* Cope with new connection attempt after remote end crashed */
segundo 0:ac1725ba162c 610 tcp_ack_now(pcb);
segundo 0:ac1725ba162c 611 return ERR_OK;
segundo 0:ac1725ba162c 612 }
segundo 0:ac1725ba162c 613
segundo 0:ac1725ba162c 614 if ((pcb->flags & TF_RXCLOSED) == 0) {
segundo 0:ac1725ba162c 615 /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */
segundo 0:ac1725ba162c 616 pcb->tmr = tcp_ticks;
segundo 0:ac1725ba162c 617 }
segundo 0:ac1725ba162c 618 pcb->keep_cnt_sent = 0;
segundo 0:ac1725ba162c 619
segundo 0:ac1725ba162c 620 tcp_parseopt(pcb);
segundo 0:ac1725ba162c 621
segundo 0:ac1725ba162c 622 /* Do different things depending on the TCP state. */
segundo 0:ac1725ba162c 623 switch (pcb->state) {
segundo 0:ac1725ba162c 624 case SYN_SENT:
segundo 0:ac1725ba162c 625 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,
segundo 0:ac1725ba162c 626 pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));
segundo 0:ac1725ba162c 627 /* received SYN ACK with expected sequence number? */
segundo 0:ac1725ba162c 628 if ((flags & TCP_ACK) && (flags & TCP_SYN)
segundo 0:ac1725ba162c 629 && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {
segundo 0:ac1725ba162c 630 pcb->snd_buf++;
segundo 0:ac1725ba162c 631 pcb->rcv_nxt = seqno + 1;
segundo 0:ac1725ba162c 632 pcb->rcv_ann_right_edge = pcb->rcv_nxt;
segundo 0:ac1725ba162c 633 pcb->lastack = ackno;
segundo 0:ac1725ba162c 634 pcb->snd_wnd = tcphdr->wnd;
segundo 0:ac1725ba162c 635 pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
segundo 0:ac1725ba162c 636 pcb->state = ESTABLISHED;
segundo 0:ac1725ba162c 637
segundo 0:ac1725ba162c 638 #if TCP_CALCULATE_EFF_SEND_MSS
segundo 0:ac1725ba162c 639 pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));
segundo 0:ac1725ba162c 640 #endif /* TCP_CALCULATE_EFF_SEND_MSS */
segundo 0:ac1725ba162c 641
segundo 0:ac1725ba162c 642 /* Set ssthresh again after changing pcb->mss (already set in tcp_connect
segundo 0:ac1725ba162c 643 * but for the default value of pcb->mss) */
segundo 0:ac1725ba162c 644 pcb->ssthresh = pcb->mss * 10;
segundo 0:ac1725ba162c 645
segundo 0:ac1725ba162c 646 pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
segundo 0:ac1725ba162c 647 LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0));
segundo 0:ac1725ba162c 648 --pcb->snd_queuelen;
segundo 0:ac1725ba162c 649 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));
segundo 0:ac1725ba162c 650 rseg = pcb->unacked;
segundo 0:ac1725ba162c 651 pcb->unacked = rseg->next;
segundo 0:ac1725ba162c 652
segundo 0:ac1725ba162c 653 /* If there's nothing left to acknowledge, stop the retransmit
segundo 0:ac1725ba162c 654 timer, otherwise reset it to start again */
segundo 0:ac1725ba162c 655 if(pcb->unacked == NULL)
segundo 0:ac1725ba162c 656 pcb->rtime = -1;
segundo 0:ac1725ba162c 657 else {
segundo 0:ac1725ba162c 658 pcb->rtime = 0;
segundo 0:ac1725ba162c 659 pcb->nrtx = 0;
segundo 0:ac1725ba162c 660 }
segundo 0:ac1725ba162c 661
segundo 0:ac1725ba162c 662 tcp_seg_free(rseg);
segundo 0:ac1725ba162c 663
segundo 0:ac1725ba162c 664 /* Call the user specified function to call when sucessfully
segundo 0:ac1725ba162c 665 * connected. */
segundo 0:ac1725ba162c 666 TCP_EVENT_CONNECTED(pcb, ERR_OK, err);
segundo 0:ac1725ba162c 667 if (err == ERR_ABRT) {
segundo 0:ac1725ba162c 668 return ERR_ABRT;
segundo 0:ac1725ba162c 669 }
segundo 0:ac1725ba162c 670 tcp_ack_now(pcb);
segundo 0:ac1725ba162c 671 }
segundo 0:ac1725ba162c 672 /* received ACK? possibly a half-open connection */
segundo 0:ac1725ba162c 673 else if (flags & TCP_ACK) {
segundo 0:ac1725ba162c 674 /* send a RST to bring the other side in a non-synchronized state. */
segundo 0:ac1725ba162c 675 tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
segundo 0:ac1725ba162c 676 tcphdr->dest, tcphdr->src);
segundo 0:ac1725ba162c 677 }
segundo 0:ac1725ba162c 678 break;
segundo 0:ac1725ba162c 679 case SYN_RCVD:
segundo 0:ac1725ba162c 680 if (flags & TCP_ACK) {
segundo 0:ac1725ba162c 681 /* expected ACK number? */
segundo 0:ac1725ba162c 682 if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
segundo 0:ac1725ba162c 683 u16_t old_cwnd;
segundo 0:ac1725ba162c 684 pcb->state = ESTABLISHED;
segundo 0:ac1725ba162c 685 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
segundo 0:ac1725ba162c 686 #if LWIP_CALLBACK_API
segundo 0:ac1725ba162c 687 LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);
segundo 0:ac1725ba162c 688 #endif
segundo 0:ac1725ba162c 689 /* Call the accept function. */
segundo 0:ac1725ba162c 690 TCP_EVENT_ACCEPT(pcb, ERR_OK, err);
segundo 0:ac1725ba162c 691 if (err != ERR_OK) {
segundo 0:ac1725ba162c 692 /* If the accept function returns with an error, we abort
segundo 0:ac1725ba162c 693 * the connection. */
segundo 0:ac1725ba162c 694 /* Already aborted? */
segundo 0:ac1725ba162c 695 if (err != ERR_ABRT) {
segundo 0:ac1725ba162c 696 tcp_abort(pcb);
segundo 0:ac1725ba162c 697 }
segundo 0:ac1725ba162c 698 return ERR_ABRT;
segundo 0:ac1725ba162c 699 }
segundo 0:ac1725ba162c 700 old_cwnd = pcb->cwnd;
segundo 0:ac1725ba162c 701 /* If there was any data contained within this ACK,
segundo 0:ac1725ba162c 702 * we'd better pass it on to the application as well. */
segundo 0:ac1725ba162c 703 tcp_receive(pcb);
segundo 0:ac1725ba162c 704
segundo 0:ac1725ba162c 705 /* Prevent ACK for SYN to generate a sent event */
segundo 0:ac1725ba162c 706 if (pcb->acked != 0) {
segundo 0:ac1725ba162c 707 pcb->acked--;
segundo 0:ac1725ba162c 708 }
segundo 0:ac1725ba162c 709
segundo 0:ac1725ba162c 710 pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
segundo 0:ac1725ba162c 711
segundo 0:ac1725ba162c 712 if (recv_flags & TF_GOT_FIN) {
segundo 0:ac1725ba162c 713 tcp_ack_now(pcb);
segundo 0:ac1725ba162c 714 pcb->state = CLOSE_WAIT;
segundo 0:ac1725ba162c 715 }
segundo 0:ac1725ba162c 716 } else {
segundo 0:ac1725ba162c 717 /* incorrect ACK number, send RST */
segundo 0:ac1725ba162c 718 tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
segundo 0:ac1725ba162c 719 tcphdr->dest, tcphdr->src);
segundo 0:ac1725ba162c 720 }
segundo 0:ac1725ba162c 721 } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {
segundo 0:ac1725ba162c 722 /* Looks like another copy of the SYN - retransmit our SYN-ACK */
segundo 0:ac1725ba162c 723 tcp_rexmit(pcb);
segundo 0:ac1725ba162c 724 }
segundo 0:ac1725ba162c 725 break;
segundo 0:ac1725ba162c 726 case CLOSE_WAIT:
segundo 0:ac1725ba162c 727 /* FALLTHROUGH */
segundo 0:ac1725ba162c 728 case ESTABLISHED:
segundo 0:ac1725ba162c 729 tcp_receive(pcb);
segundo 0:ac1725ba162c 730 if (recv_flags & TF_GOT_FIN) { /* passive close */
segundo 0:ac1725ba162c 731 tcp_ack_now(pcb);
segundo 0:ac1725ba162c 732 pcb->state = CLOSE_WAIT;
segundo 0:ac1725ba162c 733 }
segundo 0:ac1725ba162c 734 break;
segundo 0:ac1725ba162c 735 case FIN_WAIT_1:
segundo 0:ac1725ba162c 736 tcp_receive(pcb);
segundo 0:ac1725ba162c 737 if (recv_flags & TF_GOT_FIN) {
segundo 0:ac1725ba162c 738 if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
segundo 0:ac1725ba162c 739 LWIP_DEBUGF(TCP_DEBUG,
segundo 0:ac1725ba162c 740 ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
segundo 0:ac1725ba162c 741 tcp_ack_now(pcb);
segundo 0:ac1725ba162c 742 tcp_pcb_purge(pcb);
segundo 0:ac1725ba162c 743 TCP_RMV(&tcp_active_pcbs, pcb);
segundo 0:ac1725ba162c 744 pcb->state = TIME_WAIT;
segundo 0:ac1725ba162c 745 TCP_REG(&tcp_tw_pcbs, pcb);
segundo 0:ac1725ba162c 746 } else {
segundo 0:ac1725ba162c 747 tcp_ack_now(pcb);
segundo 0:ac1725ba162c 748 pcb->state = CLOSING;
segundo 0:ac1725ba162c 749 }
segundo 0:ac1725ba162c 750 } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
segundo 0:ac1725ba162c 751 pcb->state = FIN_WAIT_2;
segundo 0:ac1725ba162c 752 }
segundo 0:ac1725ba162c 753 break;
segundo 0:ac1725ba162c 754 case FIN_WAIT_2:
segundo 0:ac1725ba162c 755 tcp_receive(pcb);
segundo 0:ac1725ba162c 756 if (recv_flags & TF_GOT_FIN) {
segundo 0:ac1725ba162c 757 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
segundo 0:ac1725ba162c 758 tcp_ack_now(pcb);
segundo 0:ac1725ba162c 759 tcp_pcb_purge(pcb);
segundo 0:ac1725ba162c 760 TCP_RMV(&tcp_active_pcbs, pcb);
segundo 0:ac1725ba162c 761 pcb->state = TIME_WAIT;
segundo 0:ac1725ba162c 762 TCP_REG(&tcp_tw_pcbs, pcb);
segundo 0:ac1725ba162c 763 }
segundo 0:ac1725ba162c 764 break;
segundo 0:ac1725ba162c 765 case CLOSING:
segundo 0:ac1725ba162c 766 tcp_receive(pcb);
segundo 0:ac1725ba162c 767 if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
segundo 0:ac1725ba162c 768 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
segundo 0:ac1725ba162c 769 tcp_pcb_purge(pcb);
segundo 0:ac1725ba162c 770 TCP_RMV(&tcp_active_pcbs, pcb);
segundo 0:ac1725ba162c 771 pcb->state = TIME_WAIT;
segundo 0:ac1725ba162c 772 TCP_REG(&tcp_tw_pcbs, pcb);
segundo 0:ac1725ba162c 773 }
segundo 0:ac1725ba162c 774 break;
segundo 0:ac1725ba162c 775 case LAST_ACK:
segundo 0:ac1725ba162c 776 tcp_receive(pcb);
segundo 0:ac1725ba162c 777 if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
segundo 0:ac1725ba162c 778 LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
segundo 0:ac1725ba162c 779 /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
segundo 0:ac1725ba162c 780 recv_flags |= TF_CLOSED;
segundo 0:ac1725ba162c 781 }
segundo 0:ac1725ba162c 782 break;
segundo 0:ac1725ba162c 783 default:
segundo 0:ac1725ba162c 784 break;
segundo 0:ac1725ba162c 785 }
segundo 0:ac1725ba162c 786 return ERR_OK;
segundo 0:ac1725ba162c 787 }
segundo 0:ac1725ba162c 788
segundo 0:ac1725ba162c 789 #if TCP_QUEUE_OOSEQ
segundo 0:ac1725ba162c 790 /**
segundo 0:ac1725ba162c 791 * Insert segment into the list (segments covered with new one will be deleted)
segundo 0:ac1725ba162c 792 *
segundo 0:ac1725ba162c 793 * Called from tcp_receive()
segundo 0:ac1725ba162c 794 */
segundo 0:ac1725ba162c 795 static void
segundo 0:ac1725ba162c 796 tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next)
segundo 0:ac1725ba162c 797 {
segundo 0:ac1725ba162c 798 struct tcp_seg *old_seg;
segundo 0:ac1725ba162c 799
segundo 0:ac1725ba162c 800 if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
segundo 0:ac1725ba162c 801 /* received segment overlaps all following segments */
segundo 0:ac1725ba162c 802 tcp_segs_free(next);
segundo 0:ac1725ba162c 803 next = NULL;
segundo 0:ac1725ba162c 804 }
segundo 0:ac1725ba162c 805 else {
segundo 0:ac1725ba162c 806 /* delete some following segments
segundo 0:ac1725ba162c 807 oos queue may have segments with FIN flag */
segundo 0:ac1725ba162c 808 while (next &&
segundo 0:ac1725ba162c 809 TCP_SEQ_GEQ((seqno + cseg->len),
segundo 0:ac1725ba162c 810 (next->tcphdr->seqno + next->len))) {
segundo 0:ac1725ba162c 811 /* cseg with FIN already processed */
segundo 0:ac1725ba162c 812 if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
segundo 0:ac1725ba162c 813 TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN);
segundo 0:ac1725ba162c 814 }
segundo 0:ac1725ba162c 815 old_seg = next;
segundo 0:ac1725ba162c 816 next = next->next;
segundo 0:ac1725ba162c 817 tcp_seg_free(old_seg);
segundo 0:ac1725ba162c 818 }
segundo 0:ac1725ba162c 819 if (next &&
segundo 0:ac1725ba162c 820 TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {
segundo 0:ac1725ba162c 821 /* We need to trim the incoming segment. */
segundo 0:ac1725ba162c 822 cseg->len = (u16_t)(next->tcphdr->seqno - seqno);
segundo 0:ac1725ba162c 823 pbuf_realloc(cseg->p, cseg->len);
segundo 0:ac1725ba162c 824 }
segundo 0:ac1725ba162c 825 }
segundo 0:ac1725ba162c 826 cseg->next = next;
segundo 0:ac1725ba162c 827 }
segundo 0:ac1725ba162c 828 #endif /* TCP_QUEUE_OOSEQ */
segundo 0:ac1725ba162c 829
segundo 0:ac1725ba162c 830 /**
segundo 0:ac1725ba162c 831 * Called by tcp_process. Checks if the given segment is an ACK for outstanding
segundo 0:ac1725ba162c 832 * data, and if so frees the memory of the buffered data. Next, is places the
segundo 0:ac1725ba162c 833 * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment
segundo 0:ac1725ba162c 834 * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until
segundo 0:ac1725ba162c 835 * i it has been removed from the buffer.
segundo 0:ac1725ba162c 836 *
segundo 0:ac1725ba162c 837 * If the incoming segment constitutes an ACK for a segment that was used for RTT
segundo 0:ac1725ba162c 838 * estimation, the RTT is estimated here as well.
segundo 0:ac1725ba162c 839 *
segundo 0:ac1725ba162c 840 * Called from tcp_process().
segundo 0:ac1725ba162c 841 */
segundo 0:ac1725ba162c 842 static void
segundo 0:ac1725ba162c 843 tcp_receive(struct tcp_pcb *pcb)
segundo 0:ac1725ba162c 844 {
segundo 0:ac1725ba162c 845 struct tcp_seg *next;
segundo 0:ac1725ba162c 846 #if TCP_QUEUE_OOSEQ
segundo 0:ac1725ba162c 847 struct tcp_seg *prev, *cseg;
segundo 0:ac1725ba162c 848 #endif /* TCP_QUEUE_OOSEQ */
segundo 0:ac1725ba162c 849 struct pbuf *p;
segundo 0:ac1725ba162c 850 s32_t off;
segundo 0:ac1725ba162c 851 s16_t m;
segundo 0:ac1725ba162c 852 u32_t right_wnd_edge;
segundo 0:ac1725ba162c 853 u16_t new_tot_len;
segundo 0:ac1725ba162c 854 int found_dupack = 0;
segundo 0:ac1725ba162c 855
segundo 0:ac1725ba162c 856 if (flags & TCP_ACK) {
segundo 0:ac1725ba162c 857 right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2;
segundo 0:ac1725ba162c 858
segundo 0:ac1725ba162c 859 /* Update window. */
segundo 0:ac1725ba162c 860 if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||
segundo 0:ac1725ba162c 861 (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||
segundo 0:ac1725ba162c 862 (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {
segundo 0:ac1725ba162c 863 pcb->snd_wnd = tcphdr->wnd;
segundo 0:ac1725ba162c 864 pcb->snd_wl1 = seqno;
segundo 0:ac1725ba162c 865 pcb->snd_wl2 = ackno;
segundo 0:ac1725ba162c 866 if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) {
segundo 0:ac1725ba162c 867 pcb->persist_backoff = 0;
segundo 0:ac1725ba162c 868 }
segundo 0:ac1725ba162c 869 LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd));
segundo 0:ac1725ba162c 870 #if TCP_WND_DEBUG
segundo 0:ac1725ba162c 871 } else {
segundo 0:ac1725ba162c 872 if (pcb->snd_wnd != tcphdr->wnd) {
segundo 0:ac1725ba162c 873 LWIP_DEBUGF(TCP_WND_DEBUG,
segundo 0:ac1725ba162c 874 ("tcp_receive: no window update lastack %"U32_F" ackno %"
segundo 0:ac1725ba162c 875 U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n",
segundo 0:ac1725ba162c 876 pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));
segundo 0:ac1725ba162c 877 }
segundo 0:ac1725ba162c 878 #endif /* TCP_WND_DEBUG */
segundo 0:ac1725ba162c 879 }
segundo 0:ac1725ba162c 880
segundo 0:ac1725ba162c 881 /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a
segundo 0:ac1725ba162c 882 * duplicate ack if:
segundo 0:ac1725ba162c 883 * 1) It doesn't ACK new data
segundo 0:ac1725ba162c 884 * 2) length of received packet is zero (i.e. no payload)
segundo 0:ac1725ba162c 885 * 3) the advertised window hasn't changed
segundo 0:ac1725ba162c 886 * 4) There is outstanding unacknowledged data (retransmission timer running)
segundo 0:ac1725ba162c 887 * 5) The ACK is == biggest ACK sequence number so far seen (snd_una)
segundo 0:ac1725ba162c 888 *
segundo 0:ac1725ba162c 889 * If it passes all five, should process as a dupack:
segundo 0:ac1725ba162c 890 * a) dupacks < 3: do nothing
segundo 0:ac1725ba162c 891 * b) dupacks == 3: fast retransmit
segundo 0:ac1725ba162c 892 * c) dupacks > 3: increase cwnd
segundo 0:ac1725ba162c 893 *
segundo 0:ac1725ba162c 894 * If it only passes 1-3, should reset dupack counter (and add to
segundo 0:ac1725ba162c 895 * stats, which we don't do in lwIP)
segundo 0:ac1725ba162c 896 *
segundo 0:ac1725ba162c 897 * If it only passes 1, should reset dupack counter
segundo 0:ac1725ba162c 898 *
segundo 0:ac1725ba162c 899 */
segundo 0:ac1725ba162c 900
segundo 0:ac1725ba162c 901 /* Clause 1 */
segundo 0:ac1725ba162c 902 if (TCP_SEQ_LEQ(ackno, pcb->lastack)) {
segundo 0:ac1725ba162c 903 pcb->acked = 0;
segundo 0:ac1725ba162c 904 /* Clause 2 */
segundo 0:ac1725ba162c 905 if (tcplen == 0) {
segundo 0:ac1725ba162c 906 /* Clause 3 */
segundo 0:ac1725ba162c 907 if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){
segundo 0:ac1725ba162c 908 /* Clause 4 */
segundo 0:ac1725ba162c 909 if (pcb->rtime >= 0) {
segundo 0:ac1725ba162c 910 /* Clause 5 */
segundo 0:ac1725ba162c 911 if (pcb->lastack == ackno) {
segundo 0:ac1725ba162c 912 found_dupack = 1;
segundo 0:ac1725ba162c 913 if (pcb->dupacks + 1 > pcb->dupacks)
segundo 0:ac1725ba162c 914 ++pcb->dupacks;
segundo 0:ac1725ba162c 915 if (pcb->dupacks > 3) {
segundo 0:ac1725ba162c 916 /* Inflate the congestion window, but not if it means that
segundo 0:ac1725ba162c 917 the value overflows. */
segundo 0:ac1725ba162c 918 if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
segundo 0:ac1725ba162c 919 pcb->cwnd += pcb->mss;
segundo 0:ac1725ba162c 920 }
segundo 0:ac1725ba162c 921 } else if (pcb->dupacks == 3) {
segundo 0:ac1725ba162c 922 /* Do fast retransmit */
segundo 0:ac1725ba162c 923 tcp_rexmit_fast(pcb);
segundo 0:ac1725ba162c 924 }
segundo 0:ac1725ba162c 925 }
segundo 0:ac1725ba162c 926 }
segundo 0:ac1725ba162c 927 }
segundo 0:ac1725ba162c 928 }
segundo 0:ac1725ba162c 929 /* If Clause (1) or more is true, but not a duplicate ack, reset
segundo 0:ac1725ba162c 930 * count of consecutive duplicate acks */
segundo 0:ac1725ba162c 931 if (!found_dupack) {
segundo 0:ac1725ba162c 932 pcb->dupacks = 0;
segundo 0:ac1725ba162c 933 }
segundo 0:ac1725ba162c 934 } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){
segundo 0:ac1725ba162c 935 /* We come here when the ACK acknowledges new data. */
segundo 0:ac1725ba162c 936
segundo 0:ac1725ba162c 937 /* Reset the "IN Fast Retransmit" flag, since we are no longer
segundo 0:ac1725ba162c 938 in fast retransmit. Also reset the congestion window to the
segundo 0:ac1725ba162c 939 slow start threshold. */
segundo 0:ac1725ba162c 940 if (pcb->flags & TF_INFR) {
segundo 0:ac1725ba162c 941 pcb->flags &= ~TF_INFR;
segundo 0:ac1725ba162c 942 pcb->cwnd = pcb->ssthresh;
segundo 0:ac1725ba162c 943 }
segundo 0:ac1725ba162c 944
segundo 0:ac1725ba162c 945 /* Reset the number of retransmissions. */
segundo 0:ac1725ba162c 946 pcb->nrtx = 0;
segundo 0:ac1725ba162c 947
segundo 0:ac1725ba162c 948 /* Reset the retransmission time-out. */
segundo 0:ac1725ba162c 949 pcb->rto = (pcb->sa >> 3) + pcb->sv;
segundo 0:ac1725ba162c 950
segundo 0:ac1725ba162c 951 /* Update the send buffer space. Diff between the two can never exceed 64K? */
segundo 0:ac1725ba162c 952 pcb->acked = (u16_t)(ackno - pcb->lastack);
segundo 0:ac1725ba162c 953
segundo 0:ac1725ba162c 954 pcb->snd_buf += pcb->acked;
segundo 0:ac1725ba162c 955
segundo 0:ac1725ba162c 956 /* Reset the fast retransmit variables. */
segundo 0:ac1725ba162c 957 pcb->dupacks = 0;
segundo 0:ac1725ba162c 958 pcb->lastack = ackno;
segundo 0:ac1725ba162c 959
segundo 0:ac1725ba162c 960 /* Update the congestion control variables (cwnd and
segundo 0:ac1725ba162c 961 ssthresh). */
segundo 0:ac1725ba162c 962 if (pcb->state >= ESTABLISHED) {
segundo 0:ac1725ba162c 963 if (pcb->cwnd < pcb->ssthresh) {
segundo 0:ac1725ba162c 964 if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
segundo 0:ac1725ba162c 965 pcb->cwnd += pcb->mss;
segundo 0:ac1725ba162c 966 }
segundo 0:ac1725ba162c 967 LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd));
segundo 0:ac1725ba162c 968 } else {
segundo 0:ac1725ba162c 969 u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
segundo 0:ac1725ba162c 970 if (new_cwnd > pcb->cwnd) {
segundo 0:ac1725ba162c 971 pcb->cwnd = new_cwnd;
segundo 0:ac1725ba162c 972 }
segundo 0:ac1725ba162c 973 LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd));
segundo 0:ac1725ba162c 974 }
segundo 0:ac1725ba162c 975 }
segundo 0:ac1725ba162c 976 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n",
segundo 0:ac1725ba162c 977 ackno,
segundo 0:ac1725ba162c 978 pcb->unacked != NULL?
segundo 0:ac1725ba162c 979 ntohl(pcb->unacked->tcphdr->seqno): 0,
segundo 0:ac1725ba162c 980 pcb->unacked != NULL?
segundo 0:ac1725ba162c 981 ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));
segundo 0:ac1725ba162c 982
segundo 0:ac1725ba162c 983 /* Remove segment from the unacknowledged list if the incoming
segundo 0:ac1725ba162c 984 ACK acknowlegdes them. */
segundo 0:ac1725ba162c 985 while (pcb->unacked != NULL &&
segundo 0:ac1725ba162c 986 TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +
segundo 0:ac1725ba162c 987 TCP_TCPLEN(pcb->unacked), ackno)) {
segundo 0:ac1725ba162c 988 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n",
segundo 0:ac1725ba162c 989 ntohl(pcb->unacked->tcphdr->seqno),
segundo 0:ac1725ba162c 990 ntohl(pcb->unacked->tcphdr->seqno) +
segundo 0:ac1725ba162c 991 TCP_TCPLEN(pcb->unacked)));
segundo 0:ac1725ba162c 992
segundo 0:ac1725ba162c 993 next = pcb->unacked;
segundo 0:ac1725ba162c 994 pcb->unacked = pcb->unacked->next;
segundo 0:ac1725ba162c 995
segundo 0:ac1725ba162c 996 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
segundo 0:ac1725ba162c 997 LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
segundo 0:ac1725ba162c 998 /* Prevent ACK for FIN to generate a sent event */
segundo 0:ac1725ba162c 999 if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
segundo 0:ac1725ba162c 1000 pcb->acked--;
segundo 0:ac1725ba162c 1001 }
segundo 0:ac1725ba162c 1002
segundo 0:ac1725ba162c 1003 pcb->snd_queuelen -= pbuf_clen(next->p);
segundo 0:ac1725ba162c 1004 tcp_seg_free(next);
segundo 0:ac1725ba162c 1005
segundo 0:ac1725ba162c 1006 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen));
segundo 0:ac1725ba162c 1007 if (pcb->snd_queuelen != 0) {
segundo 0:ac1725ba162c 1008 LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
segundo 0:ac1725ba162c 1009 pcb->unsent != NULL);
segundo 0:ac1725ba162c 1010 }
segundo 0:ac1725ba162c 1011 }
segundo 0:ac1725ba162c 1012
segundo 0:ac1725ba162c 1013 /* If there's nothing left to acknowledge, stop the retransmit
segundo 0:ac1725ba162c 1014 timer, otherwise reset it to start again */
segundo 0:ac1725ba162c 1015 if(pcb->unacked == NULL)
segundo 0:ac1725ba162c 1016 pcb->rtime = -1;
segundo 0:ac1725ba162c 1017 else
segundo 0:ac1725ba162c 1018 pcb->rtime = 0;
segundo 0:ac1725ba162c 1019
segundo 0:ac1725ba162c 1020 pcb->polltmr = 0;
segundo 0:ac1725ba162c 1021 } else {
segundo 0:ac1725ba162c 1022 /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */
segundo 0:ac1725ba162c 1023 pcb->acked = 0;
segundo 0:ac1725ba162c 1024 }
segundo 0:ac1725ba162c 1025
segundo 0:ac1725ba162c 1026 /* We go through the ->unsent list to see if any of the segments
segundo 0:ac1725ba162c 1027 on the list are acknowledged by the ACK. This may seem
segundo 0:ac1725ba162c 1028 strange since an "unsent" segment shouldn't be acked. The
segundo 0:ac1725ba162c 1029 rationale is that lwIP puts all outstanding segments on the
segundo 0:ac1725ba162c 1030 ->unsent list after a retransmission, so these segments may
segundo 0:ac1725ba162c 1031 in fact have been sent once. */
segundo 0:ac1725ba162c 1032 while (pcb->unsent != NULL &&
segundo 0:ac1725ba162c 1033 TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) +
segundo 0:ac1725ba162c 1034 TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) {
segundo 0:ac1725ba162c 1035 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",
segundo 0:ac1725ba162c 1036 ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +
segundo 0:ac1725ba162c 1037 TCP_TCPLEN(pcb->unsent)));
segundo 0:ac1725ba162c 1038
segundo 0:ac1725ba162c 1039 next = pcb->unsent;
segundo 0:ac1725ba162c 1040 pcb->unsent = pcb->unsent->next;
segundo 0:ac1725ba162c 1041 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
segundo 0:ac1725ba162c 1042 LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
segundo 0:ac1725ba162c 1043 /* Prevent ACK for FIN to generate a sent event */
segundo 0:ac1725ba162c 1044 if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
segundo 0:ac1725ba162c 1045 pcb->acked--;
segundo 0:ac1725ba162c 1046 }
segundo 0:ac1725ba162c 1047 pcb->snd_queuelen -= pbuf_clen(next->p);
segundo 0:ac1725ba162c 1048 tcp_seg_free(next);
segundo 0:ac1725ba162c 1049 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen));
segundo 0:ac1725ba162c 1050 if (pcb->snd_queuelen != 0) {
segundo 0:ac1725ba162c 1051 LWIP_ASSERT("tcp_receive: valid queue length",
segundo 0:ac1725ba162c 1052 pcb->unacked != NULL || pcb->unsent != NULL);
segundo 0:ac1725ba162c 1053 }
segundo 0:ac1725ba162c 1054 }
segundo 0:ac1725ba162c 1055 /* End of ACK for new data processing. */
segundo 0:ac1725ba162c 1056
segundo 0:ac1725ba162c 1057 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n",
segundo 0:ac1725ba162c 1058 pcb->rttest, pcb->rtseq, ackno));
segundo 0:ac1725ba162c 1059
segundo 0:ac1725ba162c 1060 /* RTT estimation calculations. This is done by checking if the
segundo 0:ac1725ba162c 1061 incoming segment acknowledges the segment we use to take a
segundo 0:ac1725ba162c 1062 round-trip time measurement. */
segundo 0:ac1725ba162c 1063 if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) {
segundo 0:ac1725ba162c 1064 /* diff between this shouldn't exceed 32K since this are tcp timer ticks
segundo 0:ac1725ba162c 1065 and a round-trip shouldn't be that long... */
segundo 0:ac1725ba162c 1066 m = (s16_t)(tcp_ticks - pcb->rttest);
segundo 0:ac1725ba162c 1067
segundo 0:ac1725ba162c 1068 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n",
segundo 0:ac1725ba162c 1069 m, m * TCP_SLOW_INTERVAL));
segundo 0:ac1725ba162c 1070
segundo 0:ac1725ba162c 1071 /* This is taken directly from VJs original code in his paper */
segundo 0:ac1725ba162c 1072 m = m - (pcb->sa >> 3);
segundo 0:ac1725ba162c 1073 pcb->sa += m;
segundo 0:ac1725ba162c 1074 if (m < 0) {
segundo 0:ac1725ba162c 1075 m = -m;
segundo 0:ac1725ba162c 1076 }
segundo 0:ac1725ba162c 1077 m = m - (pcb->sv >> 2);
segundo 0:ac1725ba162c 1078 pcb->sv += m;
segundo 0:ac1725ba162c 1079 pcb->rto = (pcb->sa >> 3) + pcb->sv;
segundo 0:ac1725ba162c 1080
segundo 0:ac1725ba162c 1081 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n",
segundo 0:ac1725ba162c 1082 pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));
segundo 0:ac1725ba162c 1083
segundo 0:ac1725ba162c 1084 pcb->rttest = 0;
segundo 0:ac1725ba162c 1085 }
segundo 0:ac1725ba162c 1086 }
segundo 0:ac1725ba162c 1087
segundo 0:ac1725ba162c 1088 /* If the incoming segment contains data, we must process it
segundo 0:ac1725ba162c 1089 further. */
segundo 0:ac1725ba162c 1090 if (tcplen > 0) {
segundo 0:ac1725ba162c 1091 /* This code basically does three things:
segundo 0:ac1725ba162c 1092
segundo 0:ac1725ba162c 1093 +) If the incoming segment contains data that is the next
segundo 0:ac1725ba162c 1094 in-sequence data, this data is passed to the application. This
segundo 0:ac1725ba162c 1095 might involve trimming the first edge of the data. The rcv_nxt
segundo 0:ac1725ba162c 1096 variable and the advertised window are adjusted.
segundo 0:ac1725ba162c 1097
segundo 0:ac1725ba162c 1098 +) If the incoming segment has data that is above the next
segundo 0:ac1725ba162c 1099 sequence number expected (->rcv_nxt), the segment is placed on
segundo 0:ac1725ba162c 1100 the ->ooseq queue. This is done by finding the appropriate
segundo 0:ac1725ba162c 1101 place in the ->ooseq queue (which is ordered by sequence
segundo 0:ac1725ba162c 1102 number) and trim the segment in both ends if needed. An
segundo 0:ac1725ba162c 1103 immediate ACK is sent to indicate that we received an
segundo 0:ac1725ba162c 1104 out-of-sequence segment.
segundo 0:ac1725ba162c 1105
segundo 0:ac1725ba162c 1106 +) Finally, we check if the first segment on the ->ooseq queue
segundo 0:ac1725ba162c 1107 now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If
segundo 0:ac1725ba162c 1108 rcv_nxt > ooseq->seqno, we must trim the first edge of the
segundo 0:ac1725ba162c 1109 segment on ->ooseq before we adjust rcv_nxt. The data in the
segundo 0:ac1725ba162c 1110 segments that are now on sequence are chained onto the
segundo 0:ac1725ba162c 1111 incoming segment so that we only need to call the application
segundo 0:ac1725ba162c 1112 once.
segundo 0:ac1725ba162c 1113 */
segundo 0:ac1725ba162c 1114
segundo 0:ac1725ba162c 1115 /* First, we check if we must trim the first edge. We have to do
segundo 0:ac1725ba162c 1116 this if the sequence number of the incoming segment is less
segundo 0:ac1725ba162c 1117 than rcv_nxt, and the sequence number plus the length of the
segundo 0:ac1725ba162c 1118 segment is larger than rcv_nxt. */
segundo 0:ac1725ba162c 1119 /* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
segundo 0:ac1725ba162c 1120 if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/
segundo 0:ac1725ba162c 1121 if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){
segundo 0:ac1725ba162c 1122 /* Trimming the first edge is done by pushing the payload
segundo 0:ac1725ba162c 1123 pointer in the pbuf downwards. This is somewhat tricky since
segundo 0:ac1725ba162c 1124 we do not want to discard the full contents of the pbuf up to
segundo 0:ac1725ba162c 1125 the new starting point of the data since we have to keep the
segundo 0:ac1725ba162c 1126 TCP header which is present in the first pbuf in the chain.
segundo 0:ac1725ba162c 1127
segundo 0:ac1725ba162c 1128 What is done is really quite a nasty hack: the first pbuf in
segundo 0:ac1725ba162c 1129 the pbuf chain is pointed to by inseg.p. Since we need to be
segundo 0:ac1725ba162c 1130 able to deallocate the whole pbuf, we cannot change this
segundo 0:ac1725ba162c 1131 inseg.p pointer to point to any of the later pbufs in the
segundo 0:ac1725ba162c 1132 chain. Instead, we point the ->payload pointer in the first
segundo 0:ac1725ba162c 1133 pbuf to data in one of the later pbufs. We also set the
segundo 0:ac1725ba162c 1134 inseg.data pointer to point to the right place. This way, the
segundo 0:ac1725ba162c 1135 ->p pointer will still point to the first pbuf, but the
segundo 0:ac1725ba162c 1136 ->p->payload pointer will point to data in another pbuf.
segundo 0:ac1725ba162c 1137
segundo 0:ac1725ba162c 1138 After we are done with adjusting the pbuf pointers we must
segundo 0:ac1725ba162c 1139 adjust the ->data pointer in the seg and the segment
segundo 0:ac1725ba162c 1140 length.*/
segundo 0:ac1725ba162c 1141
segundo 0:ac1725ba162c 1142 off = pcb->rcv_nxt - seqno;
segundo 0:ac1725ba162c 1143 p = inseg.p;
segundo 0:ac1725ba162c 1144 LWIP_ASSERT("inseg.p != NULL", inseg.p);
segundo 0:ac1725ba162c 1145 LWIP_ASSERT("insane offset!", (off < 0x7fff));
segundo 0:ac1725ba162c 1146 if (inseg.p->len < off) {
segundo 0:ac1725ba162c 1147 LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off));
segundo 0:ac1725ba162c 1148 new_tot_len = (u16_t)(inseg.p->tot_len - off);
segundo 0:ac1725ba162c 1149 while (p->len < off) {
segundo 0:ac1725ba162c 1150 off -= p->len;
segundo 0:ac1725ba162c 1151 /* KJM following line changed (with addition of new_tot_len var)
segundo 0:ac1725ba162c 1152 to fix bug #9076
segundo 0:ac1725ba162c 1153 inseg.p->tot_len -= p->len; */
segundo 0:ac1725ba162c 1154 p->tot_len = new_tot_len;
segundo 0:ac1725ba162c 1155 p->len = 0;
segundo 0:ac1725ba162c 1156 p = p->next;
segundo 0:ac1725ba162c 1157 }
segundo 0:ac1725ba162c 1158 if(pbuf_header(p, (s16_t)-off)) {
segundo 0:ac1725ba162c 1159 /* Do we need to cope with this failing? Assert for now */
segundo 0:ac1725ba162c 1160 LWIP_ASSERT("pbuf_header failed", 0);
segundo 0:ac1725ba162c 1161 }
segundo 0:ac1725ba162c 1162 } else {
segundo 0:ac1725ba162c 1163 if(pbuf_header(inseg.p, (s16_t)-off)) {
segundo 0:ac1725ba162c 1164 /* Do we need to cope with this failing? Assert for now */
segundo 0:ac1725ba162c 1165 LWIP_ASSERT("pbuf_header failed", 0);
segundo 0:ac1725ba162c 1166 }
segundo 0:ac1725ba162c 1167 }
segundo 0:ac1725ba162c 1168 /* KJM following line changed to use p->payload rather than inseg->p->payload
segundo 0:ac1725ba162c 1169 to fix bug #9076 */
segundo 0:ac1725ba162c 1170 inseg.dataptr = p->payload;
segundo 0:ac1725ba162c 1171 inseg.len -= (u16_t)(pcb->rcv_nxt - seqno);
segundo 0:ac1725ba162c 1172 inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
segundo 0:ac1725ba162c 1173 }
segundo 0:ac1725ba162c 1174 else {
segundo 0:ac1725ba162c 1175 if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
segundo 0:ac1725ba162c 1176 /* the whole segment is < rcv_nxt */
segundo 0:ac1725ba162c 1177 /* must be a duplicate of a packet that has already been correctly handled */
segundo 0:ac1725ba162c 1178
segundo 0:ac1725ba162c 1179 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno));
segundo 0:ac1725ba162c 1180 tcp_ack_now(pcb);
segundo 0:ac1725ba162c 1181 }
segundo 0:ac1725ba162c 1182 }
segundo 0:ac1725ba162c 1183
segundo 0:ac1725ba162c 1184 /* The sequence number must be within the window (above rcv_nxt
segundo 0:ac1725ba162c 1185 and below rcv_nxt + rcv_wnd) in order to be further
segundo 0:ac1725ba162c 1186 processed. */
segundo 0:ac1725ba162c 1187 if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
segundo 0:ac1725ba162c 1188 pcb->rcv_nxt + pcb->rcv_wnd - 1)){
segundo 0:ac1725ba162c 1189 if (pcb->rcv_nxt == seqno) {
segundo 0:ac1725ba162c 1190 /* The incoming segment is the next in sequence. We check if
segundo 0:ac1725ba162c 1191 we have to trim the end of the segment and update rcv_nxt
segundo 0:ac1725ba162c 1192 and pass the data to the application. */
segundo 0:ac1725ba162c 1193 tcplen = TCP_TCPLEN(&inseg);
segundo 0:ac1725ba162c 1194
segundo 0:ac1725ba162c 1195 if (tcplen > pcb->rcv_wnd) {
segundo 0:ac1725ba162c 1196 LWIP_DEBUGF(TCP_INPUT_DEBUG,
segundo 0:ac1725ba162c 1197 ("tcp_receive: other end overran receive window"
segundo 0:ac1725ba162c 1198 "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
segundo 0:ac1725ba162c 1199 seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
segundo 0:ac1725ba162c 1200 if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
segundo 0:ac1725ba162c 1201 /* Must remove the FIN from the header as we're trimming
segundo 0:ac1725ba162c 1202 * that byte of sequence-space from the packet */
segundo 0:ac1725ba162c 1203 TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN);
segundo 0:ac1725ba162c 1204 }
segundo 0:ac1725ba162c 1205 /* Adjust length of segment to fit in the window. */
segundo 0:ac1725ba162c 1206 inseg.len = pcb->rcv_wnd;
segundo 0:ac1725ba162c 1207 if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
segundo 0:ac1725ba162c 1208 inseg.len -= 1;
segundo 0:ac1725ba162c 1209 }
segundo 0:ac1725ba162c 1210 pbuf_realloc(inseg.p, inseg.len);
segundo 0:ac1725ba162c 1211 tcplen = TCP_TCPLEN(&inseg);
segundo 0:ac1725ba162c 1212 LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
segundo 0:ac1725ba162c 1213 (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
segundo 0:ac1725ba162c 1214 }
segundo 0:ac1725ba162c 1215 #if TCP_QUEUE_OOSEQ
segundo 0:ac1725ba162c 1216 /* Received in-sequence data, adjust ooseq data if:
segundo 0:ac1725ba162c 1217 - FIN has been received or
segundo 0:ac1725ba162c 1218 - inseq overlaps with ooseq */
segundo 0:ac1725ba162c 1219 if (pcb->ooseq != NULL) {
segundo 0:ac1725ba162c 1220 if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
segundo 0:ac1725ba162c 1221 LWIP_DEBUGF(TCP_INPUT_DEBUG,
segundo 0:ac1725ba162c 1222 ("tcp_receive: received in-order FIN, binning ooseq queue\n"));
segundo 0:ac1725ba162c 1223 /* Received in-order FIN means anything that was received
segundo 0:ac1725ba162c 1224 * out of order must now have been received in-order, so
segundo 0:ac1725ba162c 1225 * bin the ooseq queue */
segundo 0:ac1725ba162c 1226 while (pcb->ooseq != NULL) {
segundo 0:ac1725ba162c 1227 struct tcp_seg *old_ooseq = pcb->ooseq;
segundo 0:ac1725ba162c 1228 pcb->ooseq = pcb->ooseq->next;
segundo 0:ac1725ba162c 1229 tcp_seg_free(old_ooseq);
segundo 0:ac1725ba162c 1230 }
segundo 0:ac1725ba162c 1231 }
segundo 0:ac1725ba162c 1232 else {
segundo 0:ac1725ba162c 1233 next = pcb->ooseq;
segundo 0:ac1725ba162c 1234 /* Remove all segments on ooseq that are covered by inseg already.
segundo 0:ac1725ba162c 1235 * FIN is copied from ooseq to inseg if present. */
segundo 0:ac1725ba162c 1236 while (next &&
segundo 0:ac1725ba162c 1237 TCP_SEQ_GEQ(seqno + tcplen,
segundo 0:ac1725ba162c 1238 next->tcphdr->seqno + next->len)) {
segundo 0:ac1725ba162c 1239 /* inseg cannot have FIN here (already processed above) */
segundo 0:ac1725ba162c 1240 if (TCPH_FLAGS(next->tcphdr) & TCP_FIN &&
segundo 0:ac1725ba162c 1241 (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) {
segundo 0:ac1725ba162c 1242 TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN);
segundo 0:ac1725ba162c 1243 tcplen = TCP_TCPLEN(&inseg);
segundo 0:ac1725ba162c 1244 }
segundo 0:ac1725ba162c 1245 prev = next;
segundo 0:ac1725ba162c 1246 next = next->next;
segundo 0:ac1725ba162c 1247 tcp_seg_free(prev);
segundo 0:ac1725ba162c 1248 }
segundo 0:ac1725ba162c 1249 /* Now trim right side of inseg if it overlaps with the first
segundo 0:ac1725ba162c 1250 * segment on ooseq */
segundo 0:ac1725ba162c 1251 if (next &&
segundo 0:ac1725ba162c 1252 TCP_SEQ_GT(seqno + tcplen,
segundo 0:ac1725ba162c 1253 next->tcphdr->seqno)) {
segundo 0:ac1725ba162c 1254 /* inseg cannot have FIN here (already processed above) */
segundo 0:ac1725ba162c 1255 inseg.len = (u16_t)(next->tcphdr->seqno - seqno);
segundo 0:ac1725ba162c 1256 if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
segundo 0:ac1725ba162c 1257 inseg.len -= 1;
segundo 0:ac1725ba162c 1258 }
segundo 0:ac1725ba162c 1259 pbuf_realloc(inseg.p, inseg.len);
segundo 0:ac1725ba162c 1260 tcplen = TCP_TCPLEN(&inseg);
segundo 0:ac1725ba162c 1261 LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n",
segundo 0:ac1725ba162c 1262 (seqno + tcplen) == next->tcphdr->seqno);
segundo 0:ac1725ba162c 1263 }
segundo 0:ac1725ba162c 1264 pcb->ooseq = next;
segundo 0:ac1725ba162c 1265 }
segundo 0:ac1725ba162c 1266 }
segundo 0:ac1725ba162c 1267 #endif /* TCP_QUEUE_OOSEQ */
segundo 0:ac1725ba162c 1268
segundo 0:ac1725ba162c 1269 pcb->rcv_nxt = seqno + tcplen;
segundo 0:ac1725ba162c 1270
segundo 0:ac1725ba162c 1271 /* Update the receiver's (our) window. */
segundo 0:ac1725ba162c 1272 LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen);
segundo 0:ac1725ba162c 1273 pcb->rcv_wnd -= tcplen;
segundo 0:ac1725ba162c 1274
segundo 0:ac1725ba162c 1275 tcp_update_rcv_ann_wnd(pcb);
segundo 0:ac1725ba162c 1276
segundo 0:ac1725ba162c 1277 /* If there is data in the segment, we make preparations to
segundo 0:ac1725ba162c 1278 pass this up to the application. The ->recv_data variable
segundo 0:ac1725ba162c 1279 is used for holding the pbuf that goes to the
segundo 0:ac1725ba162c 1280 application. The code for reassembling out-of-sequence data
segundo 0:ac1725ba162c 1281 chains its data on this pbuf as well.
segundo 0:ac1725ba162c 1282
segundo 0:ac1725ba162c 1283 If the segment was a FIN, we set the TF_GOT_FIN flag that will
segundo 0:ac1725ba162c 1284 be used to indicate to the application that the remote side has
segundo 0:ac1725ba162c 1285 closed its end of the connection. */
segundo 0:ac1725ba162c 1286 if (inseg.p->tot_len > 0) {
segundo 0:ac1725ba162c 1287 recv_data = inseg.p;
segundo 0:ac1725ba162c 1288 /* Since this pbuf now is the responsibility of the
segundo 0:ac1725ba162c 1289 application, we delete our reference to it so that we won't
segundo 0:ac1725ba162c 1290 (mistakingly) deallocate it. */
segundo 0:ac1725ba162c 1291 inseg.p = NULL;
segundo 0:ac1725ba162c 1292 }
segundo 0:ac1725ba162c 1293 if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
segundo 0:ac1725ba162c 1294 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
segundo 0:ac1725ba162c 1295 recv_flags |= TF_GOT_FIN;
segundo 0:ac1725ba162c 1296 }
segundo 0:ac1725ba162c 1297
segundo 0:ac1725ba162c 1298 #if TCP_QUEUE_OOSEQ
segundo 0:ac1725ba162c 1299 /* We now check if we have segments on the ->ooseq queue that
segundo 0:ac1725ba162c 1300 are now in sequence. */
segundo 0:ac1725ba162c 1301 while (pcb->ooseq != NULL &&
segundo 0:ac1725ba162c 1302 pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {
segundo 0:ac1725ba162c 1303
segundo 0:ac1725ba162c 1304 cseg = pcb->ooseq;
segundo 0:ac1725ba162c 1305 seqno = pcb->ooseq->tcphdr->seqno;
segundo 0:ac1725ba162c 1306
segundo 0:ac1725ba162c 1307 pcb->rcv_nxt += TCP_TCPLEN(cseg);
segundo 0:ac1725ba162c 1308 LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n",
segundo 0:ac1725ba162c 1309 pcb->rcv_wnd >= TCP_TCPLEN(cseg));
segundo 0:ac1725ba162c 1310 pcb->rcv_wnd -= TCP_TCPLEN(cseg);
segundo 0:ac1725ba162c 1311
segundo 0:ac1725ba162c 1312 tcp_update_rcv_ann_wnd(pcb);
segundo 0:ac1725ba162c 1313
segundo 0:ac1725ba162c 1314 if (cseg->p->tot_len > 0) {
segundo 0:ac1725ba162c 1315 /* Chain this pbuf onto the pbuf that we will pass to
segundo 0:ac1725ba162c 1316 the application. */
segundo 0:ac1725ba162c 1317 if (recv_data) {
segundo 0:ac1725ba162c 1318 pbuf_cat(recv_data, cseg->p);
segundo 0:ac1725ba162c 1319 } else {
segundo 0:ac1725ba162c 1320 recv_data = cseg->p;
segundo 0:ac1725ba162c 1321 }
segundo 0:ac1725ba162c 1322 cseg->p = NULL;
segundo 0:ac1725ba162c 1323 }
segundo 0:ac1725ba162c 1324 if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
segundo 0:ac1725ba162c 1325 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
segundo 0:ac1725ba162c 1326 recv_flags |= TF_GOT_FIN;
segundo 0:ac1725ba162c 1327 if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */
segundo 0:ac1725ba162c 1328 pcb->state = CLOSE_WAIT;
segundo 0:ac1725ba162c 1329 }
segundo 0:ac1725ba162c 1330 }
segundo 0:ac1725ba162c 1331
segundo 0:ac1725ba162c 1332 pcb->ooseq = cseg->next;
segundo 0:ac1725ba162c 1333 tcp_seg_free(cseg);
segundo 0:ac1725ba162c 1334 }
segundo 0:ac1725ba162c 1335 #endif /* TCP_QUEUE_OOSEQ */
segundo 0:ac1725ba162c 1336
segundo 0:ac1725ba162c 1337
segundo 0:ac1725ba162c 1338 /* Acknowledge the segment(s). */
segundo 0:ac1725ba162c 1339 tcp_ack(pcb);
segundo 0:ac1725ba162c 1340
segundo 0:ac1725ba162c 1341 } else {
segundo 0:ac1725ba162c 1342 /* We get here if the incoming segment is out-of-sequence. */
segundo 0:ac1725ba162c 1343 tcp_send_empty_ack(pcb);
segundo 0:ac1725ba162c 1344 #if TCP_QUEUE_OOSEQ
segundo 0:ac1725ba162c 1345 /* We queue the segment on the ->ooseq queue. */
segundo 0:ac1725ba162c 1346 if (pcb->ooseq == NULL) {
segundo 0:ac1725ba162c 1347 pcb->ooseq = tcp_seg_copy(&inseg);
segundo 0:ac1725ba162c 1348 } else {
segundo 0:ac1725ba162c 1349 /* If the queue is not empty, we walk through the queue and
segundo 0:ac1725ba162c 1350 try to find a place where the sequence number of the
segundo 0:ac1725ba162c 1351 incoming segment is between the sequence numbers of the
segundo 0:ac1725ba162c 1352 previous and the next segment on the ->ooseq queue. That is
segundo 0:ac1725ba162c 1353 the place where we put the incoming segment. If needed, we
segundo 0:ac1725ba162c 1354 trim the second edges of the previous and the incoming
segundo 0:ac1725ba162c 1355 segment so that it will fit into the sequence.
segundo 0:ac1725ba162c 1356
segundo 0:ac1725ba162c 1357 If the incoming segment has the same sequence number as a
segundo 0:ac1725ba162c 1358 segment on the ->ooseq queue, we discard the segment that
segundo 0:ac1725ba162c 1359 contains less data. */
segundo 0:ac1725ba162c 1360
segundo 0:ac1725ba162c 1361 prev = NULL;
segundo 0:ac1725ba162c 1362 for(next = pcb->ooseq; next != NULL; next = next->next) {
segundo 0:ac1725ba162c 1363 if (seqno == next->tcphdr->seqno) {
segundo 0:ac1725ba162c 1364 /* The sequence number of the incoming segment is the
segundo 0:ac1725ba162c 1365 same as the sequence number of the segment on
segundo 0:ac1725ba162c 1366 ->ooseq. We check the lengths to see which one to
segundo 0:ac1725ba162c 1367 discard. */
segundo 0:ac1725ba162c 1368 if (inseg.len > next->len) {
segundo 0:ac1725ba162c 1369 /* The incoming segment is larger than the old
segundo 0:ac1725ba162c 1370 segment. We replace some segments with the new
segundo 0:ac1725ba162c 1371 one. */
segundo 0:ac1725ba162c 1372 cseg = tcp_seg_copy(&inseg);
segundo 0:ac1725ba162c 1373 if (cseg != NULL) {
segundo 0:ac1725ba162c 1374 if (prev != NULL) {
segundo 0:ac1725ba162c 1375 prev->next = cseg;
segundo 0:ac1725ba162c 1376 } else {
segundo 0:ac1725ba162c 1377 pcb->ooseq = cseg;
segundo 0:ac1725ba162c 1378 }
segundo 0:ac1725ba162c 1379 tcp_oos_insert_segment(cseg, next);
segundo 0:ac1725ba162c 1380 }
segundo 0:ac1725ba162c 1381 break;
segundo 0:ac1725ba162c 1382 } else {
segundo 0:ac1725ba162c 1383 /* Either the lenghts are the same or the incoming
segundo 0:ac1725ba162c 1384 segment was smaller than the old one; in either
segundo 0:ac1725ba162c 1385 case, we ditch the incoming segment. */
segundo 0:ac1725ba162c 1386 break;
segundo 0:ac1725ba162c 1387 }
segundo 0:ac1725ba162c 1388 } else {
segundo 0:ac1725ba162c 1389 if (prev == NULL) {
segundo 0:ac1725ba162c 1390 if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {
segundo 0:ac1725ba162c 1391 /* The sequence number of the incoming segment is lower
segundo 0:ac1725ba162c 1392 than the sequence number of the first segment on the
segundo 0:ac1725ba162c 1393 queue. We put the incoming segment first on the
segundo 0:ac1725ba162c 1394 queue. */
segundo 0:ac1725ba162c 1395 cseg = tcp_seg_copy(&inseg);
segundo 0:ac1725ba162c 1396 if (cseg != NULL) {
segundo 0:ac1725ba162c 1397 pcb->ooseq = cseg;
segundo 0:ac1725ba162c 1398 tcp_oos_insert_segment(cseg, next);
segundo 0:ac1725ba162c 1399 }
segundo 0:ac1725ba162c 1400 break;
segundo 0:ac1725ba162c 1401 }
segundo 0:ac1725ba162c 1402 } else {
segundo 0:ac1725ba162c 1403 /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
segundo 0:ac1725ba162c 1404 TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/
segundo 0:ac1725ba162c 1405 if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) {
segundo 0:ac1725ba162c 1406 /* The sequence number of the incoming segment is in
segundo 0:ac1725ba162c 1407 between the sequence numbers of the previous and
segundo 0:ac1725ba162c 1408 the next segment on ->ooseq. We trim trim the previous
segundo 0:ac1725ba162c 1409 segment, delete next segments that included in received segment
segundo 0:ac1725ba162c 1410 and trim received, if needed. */
segundo 0:ac1725ba162c 1411 cseg = tcp_seg_copy(&inseg);
segundo 0:ac1725ba162c 1412 if (cseg != NULL) {
segundo 0:ac1725ba162c 1413 if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
segundo 0:ac1725ba162c 1414 /* We need to trim the prev segment. */
segundo 0:ac1725ba162c 1415 prev->len = (u16_t)(seqno - prev->tcphdr->seqno);
segundo 0:ac1725ba162c 1416 pbuf_realloc(prev->p, prev->len);
segundo 0:ac1725ba162c 1417 }
segundo 0:ac1725ba162c 1418 prev->next = cseg;
segundo 0:ac1725ba162c 1419 tcp_oos_insert_segment(cseg, next);
segundo 0:ac1725ba162c 1420 }
segundo 0:ac1725ba162c 1421 break;
segundo 0:ac1725ba162c 1422 }
segundo 0:ac1725ba162c 1423 }
segundo 0:ac1725ba162c 1424 /* If the "next" segment is the last segment on the
segundo 0:ac1725ba162c 1425 ooseq queue, we add the incoming segment to the end
segundo 0:ac1725ba162c 1426 of the list. */
segundo 0:ac1725ba162c 1427 if (next->next == NULL &&
segundo 0:ac1725ba162c 1428 TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {
segundo 0:ac1725ba162c 1429 if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
segundo 0:ac1725ba162c 1430 /* segment "next" already contains all data */
segundo 0:ac1725ba162c 1431 break;
segundo 0:ac1725ba162c 1432 }
segundo 0:ac1725ba162c 1433 next->next = tcp_seg_copy(&inseg);
segundo 0:ac1725ba162c 1434 if (next->next != NULL) {
segundo 0:ac1725ba162c 1435 if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
segundo 0:ac1725ba162c 1436 /* We need to trim the last segment. */
segundo 0:ac1725ba162c 1437 next->len = (u16_t)(seqno - next->tcphdr->seqno);
segundo 0:ac1725ba162c 1438 pbuf_realloc(next->p, next->len);
segundo 0:ac1725ba162c 1439 }
segundo 0:ac1725ba162c 1440 /* check if the remote side overruns our receive window */
segundo 0:ac1725ba162c 1441 if ((u32_t)tcplen + seqno > pcb->rcv_nxt + (u32_t)pcb->rcv_wnd) {
segundo 0:ac1725ba162c 1442 LWIP_DEBUGF(TCP_INPUT_DEBUG,
segundo 0:ac1725ba162c 1443 ("tcp_receive: other end overran receive window"
segundo 0:ac1725ba162c 1444 "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
segundo 0:ac1725ba162c 1445 seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
segundo 0:ac1725ba162c 1446 if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) {
segundo 0:ac1725ba162c 1447 /* Must remove the FIN from the header as we're trimming
segundo 0:ac1725ba162c 1448 * that byte of sequence-space from the packet */
segundo 0:ac1725ba162c 1449 TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) &~ TCP_FIN);
segundo 0:ac1725ba162c 1450 }
segundo 0:ac1725ba162c 1451 /* Adjust length of segment to fit in the window. */
segundo 0:ac1725ba162c 1452 next->next->len = pcb->rcv_nxt + pcb->rcv_wnd - seqno;
segundo 0:ac1725ba162c 1453 pbuf_realloc(next->next->p, next->next->len);
segundo 0:ac1725ba162c 1454 tcplen = TCP_TCPLEN(next->next);
segundo 0:ac1725ba162c 1455 LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
segundo 0:ac1725ba162c 1456 (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
segundo 0:ac1725ba162c 1457 }
segundo 0:ac1725ba162c 1458 }
segundo 0:ac1725ba162c 1459 break;
segundo 0:ac1725ba162c 1460 }
segundo 0:ac1725ba162c 1461 }
segundo 0:ac1725ba162c 1462 prev = next;
segundo 0:ac1725ba162c 1463 }
segundo 0:ac1725ba162c 1464 }
segundo 0:ac1725ba162c 1465 #endif /* TCP_QUEUE_OOSEQ */
segundo 0:ac1725ba162c 1466
segundo 0:ac1725ba162c 1467 }
segundo 0:ac1725ba162c 1468 } else {
segundo 0:ac1725ba162c 1469 /* The incoming segment is not withing the window. */
segundo 0:ac1725ba162c 1470 tcp_send_empty_ack(pcb);
segundo 0:ac1725ba162c 1471 }
segundo 0:ac1725ba162c 1472 } else {
segundo 0:ac1725ba162c 1473 /* Segments with length 0 is taken care of here. Segments that
segundo 0:ac1725ba162c 1474 fall out of the window are ACKed. */
segundo 0:ac1725ba162c 1475 /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
segundo 0:ac1725ba162c 1476 TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
segundo 0:ac1725ba162c 1477 if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){
segundo 0:ac1725ba162c 1478 tcp_ack_now(pcb);
segundo 0:ac1725ba162c 1479 }
segundo 0:ac1725ba162c 1480 }
segundo 0:ac1725ba162c 1481 }
segundo 0:ac1725ba162c 1482
segundo 0:ac1725ba162c 1483 /**
segundo 0:ac1725ba162c 1484 * Parses the options contained in the incoming segment.
segundo 0:ac1725ba162c 1485 *
segundo 0:ac1725ba162c 1486 * Called from tcp_listen_input() and tcp_process().
segundo 0:ac1725ba162c 1487 * Currently, only the MSS option is supported!
segundo 0:ac1725ba162c 1488 *
segundo 0:ac1725ba162c 1489 * @param pcb the tcp_pcb for which a segment arrived
segundo 0:ac1725ba162c 1490 */
segundo 0:ac1725ba162c 1491 static void
segundo 0:ac1725ba162c 1492 tcp_parseopt(struct tcp_pcb *pcb)
segundo 0:ac1725ba162c 1493 {
segundo 0:ac1725ba162c 1494 u16_t c, max_c;
segundo 0:ac1725ba162c 1495 u16_t mss;
segundo 0:ac1725ba162c 1496 u8_t *opts, opt;
segundo 0:ac1725ba162c 1497 #if LWIP_TCP_TIMESTAMPS
segundo 0:ac1725ba162c 1498 u32_t tsval;
segundo 0:ac1725ba162c 1499 #endif
segundo 0:ac1725ba162c 1500
segundo 0:ac1725ba162c 1501 opts = (u8_t *)tcphdr + TCP_HLEN;
segundo 0:ac1725ba162c 1502
segundo 0:ac1725ba162c 1503 /* Parse the TCP MSS option, if present. */
segundo 0:ac1725ba162c 1504 if(TCPH_HDRLEN(tcphdr) > 0x5) {
segundo 0:ac1725ba162c 1505 max_c = (TCPH_HDRLEN(tcphdr) - 5) << 2;
segundo 0:ac1725ba162c 1506 for (c = 0; c < max_c; ) {
segundo 0:ac1725ba162c 1507 opt = opts[c];
segundo 0:ac1725ba162c 1508 switch (opt) {
segundo 0:ac1725ba162c 1509 case 0x00:
segundo 0:ac1725ba162c 1510 /* End of options. */
segundo 0:ac1725ba162c 1511 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n"));
segundo 0:ac1725ba162c 1512 return;
segundo 0:ac1725ba162c 1513 case 0x01:
segundo 0:ac1725ba162c 1514 /* NOP option. */
segundo 0:ac1725ba162c 1515 ++c;
segundo 0:ac1725ba162c 1516 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n"));
segundo 0:ac1725ba162c 1517 break;
segundo 0:ac1725ba162c 1518 case 0x02:
segundo 0:ac1725ba162c 1519 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n"));
segundo 0:ac1725ba162c 1520 if (opts[c + 1] != 0x04 || c + 0x04 > max_c) {
segundo 0:ac1725ba162c 1521 /* Bad length */
segundo 0:ac1725ba162c 1522 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
segundo 0:ac1725ba162c 1523 return;
segundo 0:ac1725ba162c 1524 }
segundo 0:ac1725ba162c 1525 /* An MSS option with the right option length. */
segundo 0:ac1725ba162c 1526 mss = (opts[c + 2] << 8) | opts[c + 3];
segundo 0:ac1725ba162c 1527 /* Limit the mss to the configured TCP_MSS and prevent division by zero */
segundo 0:ac1725ba162c 1528 pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss;
segundo 0:ac1725ba162c 1529 /* Advance to next option */
segundo 0:ac1725ba162c 1530 c += 0x04;
segundo 0:ac1725ba162c 1531 break;
segundo 0:ac1725ba162c 1532 #if LWIP_TCP_TIMESTAMPS
segundo 0:ac1725ba162c 1533 case 0x08:
segundo 0:ac1725ba162c 1534 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n"));
segundo 0:ac1725ba162c 1535 if (opts[c + 1] != 0x0A || c + 0x0A > max_c) {
segundo 0:ac1725ba162c 1536 /* Bad length */
segundo 0:ac1725ba162c 1537 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
segundo 0:ac1725ba162c 1538 return;
segundo 0:ac1725ba162c 1539 }
segundo 0:ac1725ba162c 1540 /* TCP timestamp option with valid length */
segundo 0:ac1725ba162c 1541 tsval = (opts[c+2]) | (opts[c+3] << 8) |
segundo 0:ac1725ba162c 1542 (opts[c+4] << 16) | (opts[c+5] << 24);
segundo 0:ac1725ba162c 1543 if (flags & TCP_SYN) {
segundo 0:ac1725ba162c 1544 pcb->ts_recent = ntohl(tsval);
segundo 0:ac1725ba162c 1545 pcb->flags |= TF_TIMESTAMP;
segundo 0:ac1725ba162c 1546 } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) {
segundo 0:ac1725ba162c 1547 pcb->ts_recent = ntohl(tsval);
segundo 0:ac1725ba162c 1548 }
segundo 0:ac1725ba162c 1549 /* Advance to next option */
segundo 0:ac1725ba162c 1550 c += 0x0A;
segundo 0:ac1725ba162c 1551 break;
segundo 0:ac1725ba162c 1552 #endif
segundo 0:ac1725ba162c 1553 default:
segundo 0:ac1725ba162c 1554 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n"));
segundo 0:ac1725ba162c 1555 if (opts[c + 1] == 0) {
segundo 0:ac1725ba162c 1556 LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
segundo 0:ac1725ba162c 1557 /* If the length field is zero, the options are malformed
segundo 0:ac1725ba162c 1558 and we don't process them further. */
segundo 0:ac1725ba162c 1559 return;
segundo 0:ac1725ba162c 1560 }
segundo 0:ac1725ba162c 1561 /* All other options have a length field, so that we easily
segundo 0:ac1725ba162c 1562 can skip past them. */
segundo 0:ac1725ba162c 1563 c += opts[c + 1];
segundo 0:ac1725ba162c 1564 }
segundo 0:ac1725ba162c 1565 }
segundo 0:ac1725ba162c 1566 }
segundo 0:ac1725ba162c 1567 }
segundo 0:ac1725ba162c 1568
segundo 0:ac1725ba162c 1569 #endif /* LWIP_TCP */