A version of LWIP, provided for backwards compatibility.

Dependents:   AA_DemoBoard DemoBoard HelloServerDemo DemoBoard_RangeIndicator ... more

Committer:
root@mbed.org
Date:
Tue May 08 15:32:10 2012 +0100
Revision:
0:5e1631496985
initial commit

Who changed what in which revision?

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