BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /** |
2 | * @file |
||
3 | * Transmission Control Protocol, incoming traffic |
||
4 | * |
||
5 | * The input processing functions of the TCP layer. |
||
6 | * |
||
7 | * These functions are generally called in the order (ip_input() ->) |
||
8 | * tcp_input() -> * tcp_process() -> tcp_receive() (-> application). |
||
9 | * |
||
10 | */ |
||
11 | |||
12 | /* |
||
13 | * Copyright (c) 2001-2004 Swedish Institute of Computer Science. |
||
14 | * All rights reserved. |
||
15 | * |
||
16 | * Redistribution and use in source and binary forms, with or without modification, |
||
17 | * are permitted provided that the following conditions are met: |
||
18 | * |
||
19 | * 1. Redistributions of source code must retain the above copyright notice, |
||
20 | * this list of conditions and the following disclaimer. |
||
21 | * 2. Redistributions in binary form must reproduce the above copyright notice, |
||
22 | * this list of conditions and the following disclaimer in the documentation |
||
23 | * and/or other materials provided with the distribution. |
||
24 | * 3. The name of the author may not be used to endorse or promote products |
||
25 | * derived from this software without specific prior written permission. |
||
26 | * |
||
27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
||
28 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
||
29 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||
30 | * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||
31 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
||
32 | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
||
33 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||
34 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
||
35 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY |
||
36 | * OF SUCH DAMAGE. |
||
37 | * |
||
38 | * This file is part of the lwIP TCP/IP stack. |
||
39 | * |
||
40 | * Author: Adam Dunkels <adam@sics.se> |
||
41 | * |
||
42 | */ |
||
43 | |||
44 | #include "lwip/opt.h" |
||
45 | |||
46 | #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ |
||
47 | |||
48 | #include "lwip/priv/tcp_priv.h" |
||
49 | #include "lwip/def.h" |
||
50 | #include "lwip/ip_addr.h" |
||
51 | #include "lwip/netif.h" |
||
52 | #include "lwip/mem.h" |
||
53 | #include "lwip/memp.h" |
||
54 | #include "lwip/inet_chksum.h" |
||
55 | #include "lwip/stats.h" |
||
56 | #include "lwip/ip6.h" |
||
57 | #include "lwip/ip6_addr.h" |
||
58 | #if LWIP_ND6_TCP_REACHABILITY_HINTS |
||
59 | #include "lwip/nd6.h" |
||
60 | #endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ |
||
61 | |||
62 | #include <string.h> |
||
63 | |||
64 | /** Initial CWND calculation as defined RFC 2581 */ |
||
65 | #define LWIP_TCP_CALC_INITIAL_CWND(mss) ((tcpwnd_size_t)LWIP_MIN((4U * (mss)), LWIP_MAX((2U * (mss)), 4380U))) |
||
66 | |||
67 | /* These variables are global to all functions involved in the input |
||
68 | processing of TCP segments. They are set by the tcp_input() |
||
69 | function. */ |
||
70 | static struct tcp_seg inseg; |
||
71 | static struct tcp_hdr *tcphdr; |
||
72 | static u16_t tcphdr_optlen; |
||
73 | static u16_t tcphdr_opt1len; |
||
74 | static u8_t *tcphdr_opt2; |
||
75 | static u16_t tcp_optidx; |
||
76 | static u32_t seqno, ackno; |
||
77 | static tcpwnd_size_t recv_acked; |
||
78 | static u16_t tcplen; |
||
79 | static u8_t flags; |
||
80 | |||
81 | static u8_t recv_flags; |
||
82 | static struct pbuf *recv_data; |
||
83 | |||
84 | struct tcp_pcb *tcp_input_pcb; |
||
85 | |||
86 | /* Forward declarations. */ |
||
87 | static err_t tcp_process(struct tcp_pcb *pcb); |
||
88 | static void tcp_receive(struct tcp_pcb *pcb); |
||
89 | static void tcp_parseopt(struct tcp_pcb *pcb); |
||
90 | |||
91 | static void tcp_listen_input(struct tcp_pcb_listen *pcb); |
||
92 | static void tcp_timewait_input(struct tcp_pcb *pcb); |
||
93 | |||
94 | static int tcp_input_delayed_close(struct tcp_pcb *pcb); |
||
95 | |||
96 | #if LWIP_TCP_SACK_OUT |
||
97 | static void tcp_add_sack(struct tcp_pcb *pcb, u32_t left, u32_t right); |
||
98 | static void tcp_remove_sacks_lt(struct tcp_pcb *pcb, u32_t seq); |
||
99 | #if defined(TCP_OOSEQ_BYTES_LIMIT) || defined(TCP_OOSEQ_PBUFS_LIMIT) |
||
100 | static void tcp_remove_sacks_gt(struct tcp_pcb *pcb, u32_t seq); |
||
101 | #endif /* TCP_OOSEQ_BYTES_LIMIT || TCP_OOSEQ_PBUFS_LIMIT */ |
||
102 | #endif /* LWIP_TCP_SACK_OUT */ |
||
103 | |||
104 | /** |
||
105 | * The initial input processing of TCP. It verifies the TCP header, demultiplexes |
||
106 | * the segment between the PCBs and passes it on to tcp_process(), which implements |
||
107 | * the TCP finite state machine. This function is called by the IP layer (in |
||
108 | * ip_input()). |
||
109 | * |
||
110 | * @param p received TCP segment to process (p->payload pointing to the TCP header) |
||
111 | * @param inp network interface on which this segment was received |
||
112 | */ |
||
113 | void |
||
114 | tcp_input(struct pbuf *p, struct netif *inp) |
||
115 | { |
||
116 | struct tcp_pcb *pcb, *prev; |
||
117 | struct tcp_pcb_listen *lpcb; |
||
118 | #if SO_REUSE |
||
119 | struct tcp_pcb *lpcb_prev = NULL; |
||
120 | struct tcp_pcb_listen *lpcb_any = NULL; |
||
121 | #endif /* SO_REUSE */ |
||
122 | u8_t hdrlen_bytes; |
||
123 | err_t err; |
||
124 | |||
125 | LWIP_UNUSED_ARG(inp); |
||
126 | |||
127 | PERF_START; |
||
128 | |||
129 | TCP_STATS_INC(tcp.recv); |
||
130 | MIB2_STATS_INC(mib2.tcpinsegs); |
||
131 | |||
132 | tcphdr = (struct tcp_hdr *)p->payload; |
||
133 | |||
134 | #if TCP_INPUT_DEBUG |
||
135 | tcp_debug_print(tcphdr); |
||
136 | #endif |
||
137 | |||
138 | /* Check that TCP header fits in payload */ |
||
139 | if (p->len < TCP_HLEN) { |
||
140 | /* drop short packets */ |
||
141 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len)); |
||
142 | TCP_STATS_INC(tcp.lenerr); |
||
143 | goto dropped; |
||
144 | } |
||
145 | |||
146 | /* Don't even process incoming broadcasts/multicasts. */ |
||
147 | if (ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()) || |
||
148 | ip_addr_ismulticast(ip_current_dest_addr())) { |
||
149 | TCP_STATS_INC(tcp.proterr); |
||
150 | goto dropped; |
||
151 | } |
||
152 | |||
153 | #if CHECKSUM_CHECK_TCP |
||
154 | IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_TCP) { |
||
155 | /* Verify TCP checksum. */ |
||
156 | u16_t chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, |
||
157 | ip_current_src_addr(), ip_current_dest_addr()); |
||
158 | if (chksum != 0) { |
||
159 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n", |
||
160 | chksum)); |
||
161 | tcp_debug_print(tcphdr); |
||
162 | TCP_STATS_INC(tcp.chkerr); |
||
163 | goto dropped; |
||
164 | } |
||
165 | } |
||
166 | #endif /* CHECKSUM_CHECK_TCP */ |
||
167 | |||
168 | /* sanity-check header length */ |
||
169 | hdrlen_bytes = TCPH_HDRLEN_BYTES(tcphdr); |
||
170 | if ((hdrlen_bytes < TCP_HLEN) || (hdrlen_bytes > p->tot_len)) { |
||
171 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: invalid header length (%"U16_F")\n", (u16_t)hdrlen_bytes)); |
||
172 | TCP_STATS_INC(tcp.lenerr); |
||
173 | goto dropped; |
||
174 | } |
||
175 | |||
176 | /* Move the payload pointer in the pbuf so that it points to the |
||
177 | TCP data instead of the TCP header. */ |
||
178 | tcphdr_optlen = (u16_t)(hdrlen_bytes - TCP_HLEN); |
||
179 | tcphdr_opt2 = NULL; |
||
180 | if (p->len >= hdrlen_bytes) { |
||
181 | /* all options are in the first pbuf */ |
||
182 | tcphdr_opt1len = tcphdr_optlen; |
||
183 | pbuf_remove_header(p, hdrlen_bytes); /* cannot fail */ |
||
184 | } else { |
||
185 | u16_t opt2len; |
||
186 | /* TCP header fits into first pbuf, options don't - data is in the next pbuf */ |
||
187 | /* there must be a next pbuf, due to hdrlen_bytes sanity check above */ |
||
188 | LWIP_ASSERT("p->next != NULL", p->next != NULL); |
||
189 | |||
190 | /* advance over the TCP header (cannot fail) */ |
||
191 | pbuf_remove_header(p, TCP_HLEN); |
||
192 | |||
193 | /* determine how long the first and second parts of the options are */ |
||
194 | tcphdr_opt1len = p->len; |
||
195 | opt2len = (u16_t)(tcphdr_optlen - tcphdr_opt1len); |
||
196 | |||
197 | /* options continue in the next pbuf: set p to zero length and hide the |
||
198 | options in the next pbuf (adjusting p->tot_len) */ |
||
199 | pbuf_remove_header(p, tcphdr_opt1len); |
||
200 | |||
201 | /* check that the options fit in the second pbuf */ |
||
202 | if (opt2len > p->next->len) { |
||
203 | /* drop short packets */ |
||
204 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: options overflow second pbuf (%"U16_F" bytes)\n", p->next->len)); |
||
205 | TCP_STATS_INC(tcp.lenerr); |
||
206 | goto dropped; |
||
207 | } |
||
208 | |||
209 | /* remember the pointer to the second part of the options */ |
||
210 | tcphdr_opt2 = (u8_t *)p->next->payload; |
||
211 | |||
212 | /* advance p->next to point after the options, and manually |
||
213 | adjust p->tot_len to keep it consistent with the changed p->next */ |
||
214 | pbuf_remove_header(p->next, opt2len); |
||
215 | p->tot_len = (u16_t)(p->tot_len - opt2len); |
||
216 | |||
217 | LWIP_ASSERT("p->len == 0", p->len == 0); |
||
218 | LWIP_ASSERT("p->tot_len == p->next->tot_len", p->tot_len == p->next->tot_len); |
||
219 | } |
||
220 | |||
221 | /* Convert fields in TCP header to host byte order. */ |
||
222 | tcphdr->src = lwip_ntohs(tcphdr->src); |
||
223 | tcphdr->dest = lwip_ntohs(tcphdr->dest); |
||
224 | seqno = tcphdr->seqno = lwip_ntohl(tcphdr->seqno); |
||
225 | ackno = tcphdr->ackno = lwip_ntohl(tcphdr->ackno); |
||
226 | tcphdr->wnd = lwip_ntohs(tcphdr->wnd); |
||
227 | |||
228 | flags = TCPH_FLAGS(tcphdr); |
||
229 | tcplen = p->tot_len; |
||
230 | if (flags & (TCP_FIN | TCP_SYN)) { |
||
231 | tcplen++; |
||
232 | if (tcplen < p->tot_len) { |
||
233 | /* u16_t overflow, cannot handle this */ |
||
234 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: length u16_t overflow, cannot handle this\n")); |
||
235 | TCP_STATS_INC(tcp.lenerr); |
||
236 | goto dropped; |
||
237 | } |
||
238 | } |
||
239 | |||
240 | /* Demultiplex an incoming segment. First, we check if it is destined |
||
241 | for an active connection. */ |
||
242 | prev = NULL; |
||
243 | |||
244 | for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { |
||
245 | LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED); |
||
246 | LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); |
||
247 | LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); |
||
248 | |||
249 | /* check if PCB is bound to specific netif */ |
||
250 | if ((pcb->netif_idx != NETIF_NO_INDEX) && |
||
251 | (pcb->netif_idx != netif_get_index(ip_data.current_input_netif))) { |
||
252 | prev = pcb; |
||
253 | continue; |
||
254 | } |
||
255 | |||
256 | if (pcb->remote_port == tcphdr->src && |
||
257 | pcb->local_port == tcphdr->dest && |
||
258 | ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()) && |
||
259 | ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { |
||
260 | /* Move this PCB to the front of the list so that subsequent |
||
261 | lookups will be faster (we exploit locality in TCP segment |
||
262 | arrivals). */ |
||
263 | LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb); |
||
264 | if (prev != NULL) { |
||
265 | prev->next = pcb->next; |
||
266 | pcb->next = tcp_active_pcbs; |
||
267 | tcp_active_pcbs = pcb; |
||
268 | } else { |
||
269 | TCP_STATS_INC(tcp.cachehit); |
||
270 | } |
||
271 | LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb); |
||
272 | break; |
||
273 | } |
||
274 | prev = pcb; |
||
275 | } |
||
276 | |||
277 | if (pcb == NULL) { |
||
278 | /* If it did not go to an active connection, we check the connections |
||
279 | in the TIME-WAIT state. */ |
||
280 | for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { |
||
281 | LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); |
||
282 | |||
283 | /* check if PCB is bound to specific netif */ |
||
284 | if ((pcb->netif_idx != NETIF_NO_INDEX) && |
||
285 | (pcb->netif_idx != netif_get_index(ip_data.current_input_netif))) { |
||
286 | continue; |
||
287 | } |
||
288 | |||
289 | if (pcb->remote_port == tcphdr->src && |
||
290 | pcb->local_port == tcphdr->dest && |
||
291 | ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()) && |
||
292 | ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { |
||
293 | /* We don't really care enough to move this PCB to the front |
||
294 | of the list since we are not very likely to receive that |
||
295 | many segments for connections in TIME-WAIT. */ |
||
296 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n")); |
||
297 | tcp_timewait_input(pcb); |
||
298 | pbuf_free(p); |
||
299 | return; |
||
300 | } |
||
301 | } |
||
302 | |||
303 | /* Finally, if we still did not get a match, we check all PCBs that |
||
304 | are LISTENing for incoming connections. */ |
||
305 | prev = NULL; |
||
306 | struct tcp_pcb_listen *netif_pcb = NULL; |
||
307 | struct tcp_pcb *netif_pcb_prev = NULL; |
||
308 | for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { |
||
309 | /* check if PCB is bound to specific netif */ |
||
310 | if ((lpcb->netif_idx != NETIF_NO_INDEX) && |
||
311 | (lpcb->netif_idx != netif_get_index(ip_data.current_input_netif))) { |
||
312 | prev = (struct tcp_pcb *)lpcb; |
||
313 | continue; |
||
314 | } |
||
315 | |||
316 | if (lpcb->bound_to_netif) { |
||
317 | if (IP_ADDR_PCB_VERSION_MATCH(lpcb, ip_current_dest_addr()) && |
||
318 | netif_is_named(inp, lpcb->local_netif)) { |
||
319 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_input: found lpcb->bound_to_netif, set netif_pcb(_prev)\n")); |
||
320 | netif_pcb = lpcb; |
||
321 | netif_pcb_prev = prev; |
||
322 | } |
||
323 | } |
||
324 | else if (lpcb->local_port == tcphdr->dest) { |
||
325 | if (IP_IS_ANY_TYPE_VAL(lpcb->local_ip)) { |
||
326 | /* found an ANY TYPE (IPv4/IPv6) match */ |
||
327 | #if SO_REUSE |
||
328 | lpcb_any = lpcb; |
||
329 | lpcb_prev = prev; |
||
330 | #else /* SO_REUSE */ |
||
331 | break; |
||
332 | #endif /* SO_REUSE */ |
||
333 | } else if (IP_ADDR_PCB_VERSION_MATCH_EXACT(lpcb, ip_current_dest_addr())) { |
||
334 | if (ip_addr_cmp(&lpcb->local_ip, ip_current_dest_addr())) { |
||
335 | /* found an exact match */ |
||
336 | break; |
||
337 | } else if (ip_addr_isany(&lpcb->local_ip)) { |
||
338 | /* found an ANY-match */ |
||
339 | #if SO_REUSE |
||
340 | lpcb_any = lpcb; |
||
341 | lpcb_prev = prev; |
||
342 | #else /* SO_REUSE */ |
||
343 | break; |
||
344 | #endif /* SO_REUSE */ |
||
345 | } |
||
346 | } |
||
347 | } |
||
348 | prev = (struct tcp_pcb *)lpcb; |
||
349 | } |
||
350 | #if SO_REUSE |
||
351 | /* first try specific local IP */ |
||
352 | if (lpcb == NULL) { |
||
353 | /* only pass to ANY if no specific local IP has been found */ |
||
354 | lpcb = lpcb_any; |
||
355 | prev = lpcb_prev; |
||
356 | } |
||
357 | #endif /* SO_REUSE */ |
||
358 | if (lpcb == NULL && netif_pcb) { |
||
359 | lpcb = netif_pcb; |
||
360 | prev = netif_pcb_prev; |
||
361 | } |
||
362 | if (lpcb != NULL) { |
||
363 | /* Move this PCB to the front of the list so that subsequent |
||
364 | lookups will be faster (we exploit locality in TCP segment |
||
365 | arrivals). */ |
||
366 | if (prev != NULL) { |
||
367 | ((struct tcp_pcb_listen *)prev)->next = lpcb->next; |
||
368 | /* our successor is the remainder of the listening list */ |
||
369 | lpcb->next = tcp_listen_pcbs.listen_pcbs; |
||
370 | /* put this listening pcb at the head of the listening list */ |
||
371 | tcp_listen_pcbs.listen_pcbs = lpcb; |
||
372 | } else { |
||
373 | TCP_STATS_INC(tcp.cachehit); |
||
374 | } |
||
375 | |||
376 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n")); |
||
377 | tcp_listen_input(lpcb); |
||
378 | pbuf_free(p); |
||
379 | return; |
||
380 | } |
||
381 | } |
||
382 | |||
383 | #if TCP_INPUT_DEBUG |
||
384 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags ")); |
||
385 | tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); |
||
386 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n")); |
||
387 | #endif /* TCP_INPUT_DEBUG */ |
||
388 | |||
389 | |||
390 | if (pcb != NULL) { |
||
391 | /* The incoming segment belongs to a connection. */ |
||
392 | #if TCP_INPUT_DEBUG |
||
393 | tcp_debug_print_state(pcb->state); |
||
394 | #endif /* TCP_INPUT_DEBUG */ |
||
395 | |||
396 | /* Set up a tcp_seg structure. */ |
||
397 | inseg.next = NULL; |
||
398 | inseg.len = p->tot_len; |
||
399 | inseg.p = p; |
||
400 | inseg.tcphdr = tcphdr; |
||
401 | |||
402 | recv_data = NULL; |
||
403 | recv_flags = 0; |
||
404 | recv_acked = 0; |
||
405 | |||
406 | if (flags & TCP_PSH) { |
||
407 | p->flags |= PBUF_FLAG_PUSH; |
||
408 | } |
||
409 | |||
410 | /* If there is data which was previously "refused" by upper layer */ |
||
411 | if (pcb->refused_data != NULL) { |
||
412 | if ((tcp_process_refused_data(pcb) == ERR_ABRT) || |
||
413 | ((pcb->refused_data != NULL) && (tcplen > 0))) { |
||
414 | /* pcb has been aborted or refused data is still refused and the new |
||
415 | segment contains data */ |
||
416 | if (pcb->rcv_ann_wnd == 0) { |
||
417 | /* this is a zero-window probe, we respond to it with current RCV.NXT |
||
418 | and drop the data segment */ |
||
419 | tcp_send_empty_ack(pcb); |
||
420 | } |
||
421 | TCP_STATS_INC(tcp.drop); |
||
422 | MIB2_STATS_INC(mib2.tcpinerrs); |
||
423 | goto aborted; |
||
424 | } |
||
425 | } |
||
426 | tcp_input_pcb = pcb; |
||
427 | err = tcp_process(pcb); |
||
428 | /* A return value of ERR_ABRT means that tcp_abort() was called |
||
429 | and that the pcb has been freed. If so, we don't do anything. */ |
||
430 | if (err != ERR_ABRT) { |
||
431 | if (recv_flags & TF_RESET) { |
||
432 | /* TF_RESET means that the connection was reset by the other |
||
433 | end. We then call the error callback to inform the |
||
434 | application that the connection is dead before we |
||
435 | deallocate the PCB. */ |
||
436 | TCP_EVENT_ERR(pcb->state, pcb->errf, pcb->callback_arg, ERR_RST); |
||
437 | tcp_pcb_remove(&tcp_active_pcbs, pcb); |
||
438 | memp_free(MEMP_TCP_PCB, pcb); |
||
439 | } else { |
||
440 | err = ERR_OK; |
||
441 | /* If the application has registered a "sent" function to be |
||
442 | called when new send buffer space is available, we call it |
||
443 | now. */ |
||
444 | if (recv_acked > 0) { |
||
445 | u16_t acked16; |
||
446 | #if LWIP_WND_SCALE |
||
447 | /* recv_acked is u32_t but the sent callback only takes a u16_t, |
||
448 | so we might have to call it multiple times. */ |
||
449 | u32_t acked = recv_acked; |
||
450 | while (acked > 0) { |
||
451 | acked16 = (u16_t)LWIP_MIN(acked, 0xffffu); |
||
452 | acked -= acked16; |
||
453 | #else |
||
454 | { |
||
455 | acked16 = recv_acked; |
||
456 | #endif |
||
457 | TCP_EVENT_SENT(pcb, (u16_t)acked16, err); |
||
458 | if (err == ERR_ABRT) { |
||
459 | goto aborted; |
||
460 | } |
||
461 | } |
||
462 | recv_acked = 0; |
||
463 | } |
||
464 | if (tcp_input_delayed_close(pcb)) { |
||
465 | goto aborted; |
||
466 | } |
||
467 | #if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE |
||
468 | while (recv_data != NULL) { |
||
469 | struct pbuf *rest = NULL; |
||
470 | pbuf_split_64k(recv_data, &rest); |
||
471 | #else /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ |
||
472 | if (recv_data != NULL) { |
||
473 | #endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ |
||
474 | |||
475 | LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL); |
||
476 | if (pcb->flags & TF_RXCLOSED) { |
||
477 | /* received data although already closed -> abort (send RST) to |
||
478 | notify the remote host that not all data has been processed */ |
||
479 | pbuf_free(recv_data); |
||
480 | #if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE |
||
481 | if (rest != NULL) { |
||
482 | pbuf_free(rest); |
||
483 | } |
||
484 | #endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ |
||
485 | tcp_abort(pcb); |
||
486 | goto aborted; |
||
487 | } |
||
488 | |||
489 | /* Notify application that data has been received. */ |
||
490 | TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err); |
||
491 | if (err == ERR_ABRT) { |
||
492 | #if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE |
||
493 | if (rest != NULL) { |
||
494 | pbuf_free(rest); |
||
495 | } |
||
496 | #endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ |
||
497 | goto aborted; |
||
498 | } |
||
499 | |||
500 | /* If the upper layer can't receive this data, store it */ |
||
501 | if (err != ERR_OK) { |
||
502 | #if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE |
||
503 | if (rest != NULL) { |
||
504 | pbuf_cat(recv_data, rest); |
||
505 | } |
||
506 | #endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ |
||
507 | pcb->refused_data = recv_data; |
||
508 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n")); |
||
509 | #if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE |
||
510 | break; |
||
511 | } else { |
||
512 | /* Upper layer received the data, go on with the rest if > 64K */ |
||
513 | recv_data = rest; |
||
514 | #endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ |
||
515 | } |
||
516 | } |
||
517 | |||
518 | /* If a FIN segment was received, we call the callback |
||
519 | function with a NULL buffer to indicate EOF. */ |
||
520 | if (recv_flags & TF_GOT_FIN) { |
||
521 | if (pcb->refused_data != NULL) { |
||
522 | /* Delay this if we have refused data. */ |
||
523 | pcb->refused_data->flags |= PBUF_FLAG_TCP_FIN; |
||
524 | } else { |
||
525 | /* correct rcv_wnd as the application won't call tcp_recved() |
||
526 | for the FIN's seqno */ |
||
527 | if (pcb->rcv_wnd != TCP_WND_MAX(pcb)) { |
||
528 | pcb->rcv_wnd++; |
||
529 | } |
||
530 | TCP_EVENT_CLOSED(pcb, err); |
||
531 | if (err == ERR_ABRT) { |
||
532 | goto aborted; |
||
533 | } |
||
534 | } |
||
535 | } |
||
536 | |||
537 | tcp_input_pcb = NULL; |
||
538 | if (tcp_input_delayed_close(pcb)) { |
||
539 | goto aborted; |
||
540 | } |
||
541 | /* Try to send something out. */ |
||
542 | tcp_output(pcb); |
||
543 | #if TCP_INPUT_DEBUG |
||
544 | #if TCP_DEBUG |
||
545 | tcp_debug_print_state(pcb->state); |
||
546 | #endif /* TCP_DEBUG */ |
||
547 | #endif /* TCP_INPUT_DEBUG */ |
||
548 | } |
||
549 | } |
||
550 | /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()). |
||
551 | Below this line, 'pcb' may not be dereferenced! */ |
||
552 | aborted: |
||
553 | tcp_input_pcb = NULL; |
||
554 | recv_data = NULL; |
||
555 | |||
556 | /* give up our reference to inseg.p */ |
||
557 | if (inseg.p != NULL) { |
||
558 | pbuf_free(inseg.p); |
||
559 | inseg.p = NULL; |
||
560 | } |
||
561 | } else { |
||
562 | /* If no matching PCB was found, send a TCP RST (reset) to the |
||
563 | sender. */ |
||
564 | LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n")); |
||
565 | if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) { |
||
566 | TCP_STATS_INC(tcp.proterr); |
||
567 | TCP_STATS_INC(tcp.drop); |
||
568 | tcp_rst(NULL, ackno, seqno + tcplen, ip_current_dest_addr(), |
||
569 | ip_current_src_addr(), tcphdr->dest, tcphdr->src); |
||
570 | } |
||
571 | pbuf_free(p); |
||
572 | } |
||
573 | |||
574 | LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane()); |
||
575 | PERF_STOP("tcp_input"); |
||
576 | return; |
||
577 | dropped: |
||
578 | TCP_STATS_INC(tcp.drop); |
||
579 | MIB2_STATS_INC(mib2.tcpinerrs); |
||
580 | pbuf_free(p); |
||
581 | } |
||
582 | |||
583 | /** Called from tcp_input to check for TF_CLOSED flag. This results in closing |
||
584 | * and deallocating a pcb at the correct place to ensure noone references it |
||
585 | * any more. |
||
586 | * @returns 1 if the pcb has been closed and deallocated, 0 otherwise |
||
587 | */ |
||
588 | static int |
||
589 | tcp_input_delayed_close(struct tcp_pcb *pcb) |
||
590 | { |
||
591 | if (recv_flags & TF_CLOSED) { |
||
592 | /* The connection has been closed and we will deallocate the |
||
593 | PCB. */ |
||
594 | if (!(pcb->flags & TF_RXCLOSED)) { |
||
595 | /* Connection closed although the application has only shut down the |
||
596 | tx side: call the PCB's err callback and indicate the closure to |
||
597 | ensure the application doesn't continue using the PCB. */ |
||
598 | TCP_EVENT_ERR(pcb->state, pcb->errf, pcb->callback_arg, ERR_CLSD); |
||
599 | } |
||
600 | tcp_pcb_remove(&tcp_active_pcbs, pcb); |
||
601 | memp_free(MEMP_TCP_PCB, pcb); |
||
602 | return 1; |
||
603 | } |
||
604 | return 0; |
||
605 | } |
||
606 | |||
607 | /** |
||
608 | * Called by tcp_input() when a segment arrives for a listening |
||
609 | * connection (from tcp_input()). |
||
610 | * |
||
611 | * @param pcb the tcp_pcb_listen for which a segment arrived |
||
612 | * |
||
613 | * @note the segment which arrived is saved in global variables, therefore only the pcb |
||
614 | * involved is passed as a parameter to this function |
||
615 | */ |
||
616 | static void |
||
617 | tcp_listen_input(struct tcp_pcb_listen *pcb) |
||
618 | { |
||
619 | struct tcp_pcb *npcb; |
||
620 | u32_t iss; |
||
621 | err_t rc; |
||
622 | |||
623 | if (flags & TCP_RST) { |
||
624 | /* An incoming RST should be ignored. Return. */ |
||
625 | return; |
||
626 | } |
||
627 | |||
628 | /* In the LISTEN state, we check for incoming SYN segments, |
||
629 | creates a new PCB, and responds with a SYN|ACK. */ |
||
630 | if (flags & TCP_ACK) { |
||
631 | /* For incoming segments with the ACK flag set, respond with a |
||
632 | RST. */ |
||
633 | LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); |
||
634 | tcp_rst((const struct tcp_pcb *)pcb, ackno, seqno + tcplen, ip_current_dest_addr(), |
||
635 | ip_current_src_addr(), tcphdr->dest, tcphdr->src); |
||
636 | } else if (flags & TCP_SYN) { |
||
637 | LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); |
||
638 | #if TCP_LISTEN_BACKLOG |
||
639 | if (pcb->accepts_pending >= pcb->backlog) { |
||
640 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest)); |
||
641 | return; |
||
642 | } |
||
643 | #endif /* TCP_LISTEN_BACKLOG */ |
||
644 | npcb = tcp_alloc(pcb->prio); |
||
645 | /* If a new PCB could not be created (probably due to lack of memory), |
||
646 | we don't do anything, but rely on the sender will retransmit the |
||
647 | SYN at a time when we have more memory available. */ |
||
648 | if (npcb == NULL) { |
||
649 | err_t err; |
||
650 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n")); |
||
651 | TCP_STATS_INC(tcp.memerr); |
||
652 | TCP_EVENT_ACCEPT(pcb, NULL, pcb->callback_arg, ERR_MEM, err); |
||
653 | LWIP_UNUSED_ARG(err); /* err not useful here */ |
||
654 | return; |
||
655 | } |
||
656 | #if TCP_LISTEN_BACKLOG |
||
657 | pcb->accepts_pending++; |
||
658 | tcp_set_flags(npcb, TF_BACKLOGPEND); |
||
659 | #endif /* TCP_LISTEN_BACKLOG */ |
||
660 | /* Set up the new PCB. */ |
||
661 | ip_addr_copy(npcb->local_ip, *ip_current_dest_addr()); |
||
662 | ip_addr_copy(npcb->remote_ip, *ip_current_src_addr()); |
||
663 | /* npcb->bound_to_netif is 0 regardless of lpcb */ |
||
664 | npcb->local_port = tcphdr->dest; |
||
665 | npcb->remote_port = tcphdr->src; |
||
666 | npcb->state = SYN_RCVD; |
||
667 | npcb->rcv_nxt = seqno + 1; |
||
668 | npcb->rcv_ann_right_edge = npcb->rcv_nxt; |
||
669 | iss = tcp_next_iss(npcb); |
||
670 | npcb->snd_wl2 = iss; |
||
671 | npcb->snd_nxt = iss; |
||
672 | npcb->lastack = iss; |
||
673 | npcb->snd_lbb = iss; |
||
674 | npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */ |
||
675 | npcb->callback_arg = pcb->callback_arg; |
||
676 | #if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG |
||
677 | npcb->listener = pcb; |
||
678 | #endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */ |
||
679 | /* inherit socket options */ |
||
680 | npcb->so_options = pcb->so_options & SOF_INHERITED; |
||
681 | npcb->netif_idx = pcb->netif_idx; |
||
682 | /* Register the new PCB so that we can begin receiving segments |
||
683 | for it. */ |
||
684 | TCP_REG_ACTIVE(npcb); |
||
685 | |||
686 | /* Parse any options in the SYN. */ |
||
687 | tcp_parseopt(npcb); |
||
688 | npcb->snd_wnd = tcphdr->wnd; |
||
689 | npcb->snd_wnd_max = npcb->snd_wnd; |
||
690 | |||
691 | #if TCP_CALCULATE_EFF_SEND_MSS |
||
692 | npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip, &npcb->remote_ip); |
||
693 | #endif /* TCP_CALCULATE_EFF_SEND_MSS */ |
||
694 | |||
695 | MIB2_STATS_INC(mib2.tcppassiveopens); |
||
696 | |||
697 | /* Send a SYN|ACK together with the MSS option. */ |
||
698 | rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK); |
||
699 | if (rc != ERR_OK) { |
||
700 | tcp_abandon(npcb, 0); |
||
701 | return; |
||
702 | } |
||
703 | tcp_output(npcb); |
||
704 | } |
||
705 | return; |
||
706 | } |
||
707 | |||
708 | /** |
||
709 | * Called by tcp_input() when a segment arrives for a connection in |
||
710 | * TIME_WAIT. |
||
711 | * |
||
712 | * @param pcb the tcp_pcb for which a segment arrived |
||
713 | * |
||
714 | * @note the segment which arrived is saved in global variables, therefore only the pcb |
||
715 | * involved is passed as a parameter to this function |
||
716 | */ |
||
717 | static void |
||
718 | tcp_timewait_input(struct tcp_pcb *pcb) |
||
719 | { |
||
720 | /* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */ |
||
721 | /* RFC 793 3.9 Event Processing - Segment Arrives: |
||
722 | * - first check sequence number - we skip that one in TIME_WAIT (always |
||
723 | * acceptable since we only send ACKs) |
||
724 | * - second check the RST bit (... return) */ |
||
725 | if (flags & TCP_RST) { |
||
726 | return; |
||
727 | } |
||
728 | /* - fourth, check the SYN bit, */ |
||
729 | if (flags & TCP_SYN) { |
||
730 | /* If an incoming segment is not acceptable, an acknowledgment |
||
731 | should be sent in reply */ |
||
732 | if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd)) { |
||
733 | /* If the SYN is in the window it is an error, send a reset */ |
||
734 | tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), |
||
735 | ip_current_src_addr(), tcphdr->dest, tcphdr->src); |
||
736 | return; |
||
737 | } |
||
738 | } else if (flags & TCP_FIN) { |
||
739 | /* - eighth, check the FIN bit: Remain in the TIME-WAIT state. |
||
740 | Restart the 2 MSL time-wait timeout.*/ |
||
741 | pcb->tmr = tcp_ticks; |
||
742 | } |
||
743 | |||
744 | if ((tcplen > 0)) { |
||
745 | /* Acknowledge data, FIN or out-of-window SYN */ |
||
746 | tcp_ack_now(pcb); |
||
747 | tcp_output(pcb); |
||
748 | } |
||
749 | return; |
||
750 | } |
||
751 | |||
752 | /** |
||
753 | * Implements the TCP state machine. Called by tcp_input. In some |
||
754 | * states tcp_receive() is called to receive data. The tcp_seg |
||
755 | * argument will be freed by the caller (tcp_input()) unless the |
||
756 | * recv_data pointer in the pcb is set. |
||
757 | * |
||
758 | * @param pcb the tcp_pcb for which a segment arrived |
||
759 | * |
||
760 | * @note the segment which arrived is saved in global variables, therefore only the pcb |
||
761 | * involved is passed as a parameter to this function |
||
762 | */ |
||
763 | static err_t |
||
764 | tcp_process(struct tcp_pcb *pcb) |
||
765 | { |
||
766 | struct tcp_seg *rseg; |
||
767 | u8_t acceptable = 0; |
||
768 | err_t err; |
||
769 | |||
770 | err = ERR_OK; |
||
771 | |||
772 | /* Process incoming RST segments. */ |
||
773 | if (flags & TCP_RST) { |
||
774 | /* First, determine if the reset is acceptable. */ |
||
775 | if (pcb->state == SYN_SENT) { |
||
776 | /* "In the SYN-SENT state (a RST received in response to an initial SYN), |
||
777 | the RST is acceptable if the ACK field acknowledges the SYN." */ |
||
778 | if (ackno == pcb->snd_nxt) { |
||
779 | acceptable = 1; |
||
780 | } |
||
781 | } else { |
||
782 | /* "In all states except SYN-SENT, all reset (RST) segments are validated |
||
783 | by checking their SEQ-fields." */ |
||
784 | if (seqno == pcb->rcv_nxt) { |
||
785 | acceptable = 1; |
||
786 | } else if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, |
||
787 | pcb->rcv_nxt + pcb->rcv_wnd)) { |
||
788 | /* If the sequence number is inside the window, we send a challenge ACK |
||
789 | and wait for a re-send with matching sequence number. |
||
790 | This follows RFC 5961 section 3.2 and addresses CVE-2004-0230 |
||
791 | (RST spoofing attack), which is present in RFC 793 RST handling. */ |
||
792 | tcp_ack_now(pcb); |
||
793 | } |
||
794 | } |
||
795 | |||
796 | if (acceptable) { |
||
797 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n")); |
||
798 | LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED); |
||
799 | recv_flags |= TF_RESET; |
||
800 | tcp_clear_flags(pcb, TF_ACK_DELAY); |
||
801 | return ERR_RST; |
||
802 | } else { |
||
803 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", |
||
804 | seqno, pcb->rcv_nxt)); |
||
805 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", |
||
806 | seqno, pcb->rcv_nxt)); |
||
807 | return ERR_OK; |
||
808 | } |
||
809 | } |
||
810 | |||
811 | if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) { |
||
812 | /* Cope with new connection attempt after remote end crashed */ |
||
813 | tcp_ack_now(pcb); |
||
814 | return ERR_OK; |
||
815 | } |
||
816 | |||
817 | if ((pcb->flags & TF_RXCLOSED) == 0) { |
||
818 | /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */ |
||
819 | pcb->tmr = tcp_ticks; |
||
820 | } |
||
821 | pcb->keep_cnt_sent = 0; |
||
822 | pcb->persist_probe = 0; |
||
823 | |||
824 | tcp_parseopt(pcb); |
||
825 | |||
826 | /* Do different things depending on the TCP state. */ |
||
827 | switch (pcb->state) { |
||
828 | case SYN_SENT: |
||
829 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno, |
||
830 | pcb->snd_nxt, lwip_ntohl(pcb->unacked->tcphdr->seqno))); |
||
831 | /* received SYN ACK with expected sequence number? */ |
||
832 | if ((flags & TCP_ACK) && (flags & TCP_SYN) |
||
833 | && (ackno == pcb->lastack + 1)) { |
||
834 | pcb->rcv_nxt = seqno + 1; |
||
835 | pcb->rcv_ann_right_edge = pcb->rcv_nxt; |
||
836 | pcb->lastack = ackno; |
||
837 | pcb->snd_wnd = tcphdr->wnd; |
||
838 | pcb->snd_wnd_max = pcb->snd_wnd; |
||
839 | pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */ |
||
840 | pcb->state = ESTABLISHED; |
||
841 | |||
842 | #if TCP_CALCULATE_EFF_SEND_MSS |
||
843 | pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip); |
||
844 | #endif /* TCP_CALCULATE_EFF_SEND_MSS */ |
||
845 | |||
846 | pcb->cwnd = LWIP_TCP_CALC_INITIAL_CWND(pcb->mss); |
||
847 | LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_process (SENT): cwnd %"TCPWNDSIZE_F |
||
848 | " ssthresh %"TCPWNDSIZE_F"\n", |
||
849 | pcb->cwnd, pcb->ssthresh)); |
||
850 | LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0)); |
||
851 | --pcb->snd_queuelen; |
||
852 | LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"TCPWNDSIZE_F"\n", (tcpwnd_size_t)pcb->snd_queuelen)); |
||
853 | rseg = pcb->unacked; |
||
854 | if (rseg == NULL) { |
||
855 | /* might happen if tcp_output fails in tcp_rexmit_rto() |
||
856 | in which case the segment is on the unsent list */ |
||
857 | rseg = pcb->unsent; |
||
858 | LWIP_ASSERT("no segment to free", rseg != NULL); |
||
859 | pcb->unsent = rseg->next; |
||
860 | } else { |
||
861 | pcb->unacked = rseg->next; |
||
862 | } |
||
863 | tcp_seg_free(rseg); |
||
864 | |||
865 | /* If there's nothing left to acknowledge, stop the retransmit |
||
866 | timer, otherwise reset it to start again */ |
||
867 | if (pcb->unacked == NULL) { |
||
868 | pcb->rtime = -1; |
||
869 | } else { |
||
870 | pcb->rtime = 0; |
||
871 | pcb->nrtx = 0; |
||
872 | } |
||
873 | |||
874 | /* Call the user specified function to call when successfully |
||
875 | * connected. */ |
||
876 | TCP_EVENT_CONNECTED(pcb, ERR_OK, err); |
||
877 | if (err == ERR_ABRT) { |
||
878 | return ERR_ABRT; |
||
879 | } |
||
880 | tcp_ack_now(pcb); |
||
881 | } |
||
882 | /* received ACK? possibly a half-open connection */ |
||
883 | else if (flags & TCP_ACK) { |
||
884 | /* send a RST to bring the other side in a non-synchronized state. */ |
||
885 | tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), |
||
886 | ip_current_src_addr(), tcphdr->dest, tcphdr->src); |
||
887 | /* Resend SYN immediately (don't wait for rto timeout) to establish |
||
888 | connection faster, but do not send more SYNs than we otherwise would |
||
889 | have, or we might get caught in a loop on loopback interfaces. */ |
||
890 | if (pcb->nrtx < TCP_SYNMAXRTX) { |
||
891 | pcb->rtime = 0; |
||
892 | tcp_rexmit_rto(pcb); |
||
893 | } |
||
894 | } |
||
895 | break; |
||
896 | case SYN_RCVD: |
||
897 | if (flags & TCP_ACK) { |
||
898 | /* expected ACK number? */ |
||
899 | if (TCP_SEQ_BETWEEN(ackno, pcb->lastack + 1, pcb->snd_nxt)) { |
||
900 | pcb->state = ESTABLISHED; |
||
901 | LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); |
||
902 | #if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG |
||
903 | if (pcb->listener == NULL) { |
||
904 | /* listen pcb might be closed by now */ |
||
905 | err = ERR_VAL; |
||
906 | } else |
||
907 | #endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */ |
||
908 | { |
||
909 | #if LWIP_CALLBACK_API |
||
910 | LWIP_ASSERT("pcb->listener->accept != NULL", pcb->listener->accept != NULL); |
||
911 | #endif |
||
912 | tcp_backlog_accepted(pcb); |
||
913 | /* Call the accept function. */ |
||
914 | TCP_EVENT_ACCEPT(pcb->listener, pcb, pcb->callback_arg, ERR_OK, err); |
||
915 | } |
||
916 | if (err != ERR_OK) { |
||
917 | /* If the accept function returns with an error, we abort |
||
918 | * the connection. */ |
||
919 | /* Already aborted? */ |
||
920 | if (err != ERR_ABRT) { |
||
921 | tcp_abort(pcb); |
||
922 | } |
||
923 | return ERR_ABRT; |
||
924 | } |
||
925 | /* If there was any data contained within this ACK, |
||
926 | * we'd better pass it on to the application as well. */ |
||
927 | tcp_receive(pcb); |
||
928 | |||
929 | /* Prevent ACK for SYN to generate a sent event */ |
||
930 | if (recv_acked != 0) { |
||
931 | recv_acked--; |
||
932 | } |
||
933 | |||
934 | pcb->cwnd = LWIP_TCP_CALC_INITIAL_CWND(pcb->mss); |
||
935 | LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_process (SYN_RCVD): cwnd %"TCPWNDSIZE_F |
||
936 | " ssthresh %"TCPWNDSIZE_F"\n", |
||
937 | pcb->cwnd, pcb->ssthresh)); |
||
938 | |||
939 | if (recv_flags & TF_GOT_FIN) { |
||
940 | tcp_ack_now(pcb); |
||
941 | pcb->state = CLOSE_WAIT; |
||
942 | } |
||
943 | } else { |
||
944 | /* incorrect ACK number, send RST */ |
||
945 | tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(), |
||
946 | ip_current_src_addr(), tcphdr->dest, tcphdr->src); |
||
947 | } |
||
948 | } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { |
||
949 | /* Looks like another copy of the SYN - retransmit our SYN-ACK */ |
||
950 | tcp_rexmit(pcb); |
||
951 | } |
||
952 | break; |
||
953 | case CLOSE_WAIT: |
||
954 | /* FALLTHROUGH */ |
||
955 | case ESTABLISHED: |
||
956 | tcp_receive(pcb); |
||
957 | if (recv_flags & TF_GOT_FIN) { /* passive close */ |
||
958 | tcp_ack_now(pcb); |
||
959 | pcb->state = CLOSE_WAIT; |
||
960 | } |
||
961 | break; |
||
962 | case FIN_WAIT_1: |
||
963 | tcp_receive(pcb); |
||
964 | if (recv_flags & TF_GOT_FIN) { |
||
965 | if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt) && |
||
966 | pcb->unsent == NULL) { |
||
967 | LWIP_DEBUGF(TCP_DEBUG, |
||
968 | ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); |
||
969 | tcp_ack_now(pcb); |
||
970 | tcp_pcb_purge(pcb); |
||
971 | TCP_RMV_ACTIVE(pcb); |
||
972 | pcb->state = TIME_WAIT; |
||
973 | TCP_REG(&tcp_tw_pcbs, pcb); |
||
974 | } else { |
||
975 | tcp_ack_now(pcb); |
||
976 | pcb->state = CLOSING; |
||
977 | } |
||
978 | } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt) && |
||
979 | pcb->unsent == NULL) { |
||
980 | pcb->state = FIN_WAIT_2; |
||
981 | } |
||
982 | break; |
||
983 | case FIN_WAIT_2: |
||
984 | tcp_receive(pcb); |
||
985 | if (recv_flags & TF_GOT_FIN) { |
||
986 | LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); |
||
987 | tcp_ack_now(pcb); |
||
988 | tcp_pcb_purge(pcb); |
||
989 | TCP_RMV_ACTIVE(pcb); |
||
990 | pcb->state = TIME_WAIT; |
||
991 | TCP_REG(&tcp_tw_pcbs, pcb); |
||
992 | } |
||
993 | break; |
||
994 | case CLOSING: |
||
995 | tcp_receive(pcb); |
||
996 | if ((flags & TCP_ACK) && ackno == pcb->snd_nxt && pcb->unsent == NULL) { |
||
997 | LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); |
||
998 | tcp_pcb_purge(pcb); |
||
999 | TCP_RMV_ACTIVE(pcb); |
||
1000 | pcb->state = TIME_WAIT; |
||
1001 | TCP_REG(&tcp_tw_pcbs, pcb); |
||
1002 | } |
||
1003 | break; |
||
1004 | case LAST_ACK: |
||
1005 | tcp_receive(pcb); |
||
1006 | if ((flags & TCP_ACK) && ackno == pcb->snd_nxt && pcb->unsent == NULL) { |
||
1007 | LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); |
||
1008 | /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */ |
||
1009 | recv_flags |= TF_CLOSED; |
||
1010 | } |
||
1011 | break; |
||
1012 | default: |
||
1013 | break; |
||
1014 | } |
||
1015 | return ERR_OK; |
||
1016 | } |
||
1017 | |||
1018 | #if TCP_QUEUE_OOSEQ |
||
1019 | /** |
||
1020 | * Insert segment into the list (segments covered with new one will be deleted) |
||
1021 | * |
||
1022 | * Called from tcp_receive() |
||
1023 | */ |
||
1024 | static void |
||
1025 | tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next) |
||
1026 | { |
||
1027 | struct tcp_seg *old_seg; |
||
1028 | |||
1029 | if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { |
||
1030 | /* received segment overlaps all following segments */ |
||
1031 | tcp_segs_free(next); |
||
1032 | next = NULL; |
||
1033 | } else { |
||
1034 | /* delete some following segments |
||
1035 | oos queue may have segments with FIN flag */ |
||
1036 | while (next && |
||
1037 | TCP_SEQ_GEQ((seqno + cseg->len), |
||
1038 | (next->tcphdr->seqno + next->len))) { |
||
1039 | /* cseg with FIN already processed */ |
||
1040 | if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { |
||
1041 | TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN); |
||
1042 | } |
||
1043 | old_seg = next; |
||
1044 | next = next->next; |
||
1045 | tcp_seg_free(old_seg); |
||
1046 | } |
||
1047 | if (next && |
||
1048 | TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) { |
||
1049 | /* We need to trim the incoming segment. */ |
||
1050 | cseg->len = (u16_t)(next->tcphdr->seqno - seqno); |
||
1051 | pbuf_realloc(cseg->p, cseg->len); |
||
1052 | } |
||
1053 | } |
||
1054 | cseg->next = next; |
||
1055 | } |
||
1056 | #endif /* TCP_QUEUE_OOSEQ */ |
||
1057 | |||
1058 | /** Remove segments from a list if the incoming ACK acknowledges them */ |
||
1059 | static struct tcp_seg * |
||
1060 | tcp_free_acked_segments(struct tcp_pcb *pcb, struct tcp_seg *seg_list, const char *dbg_list_name, |
||
1061 | struct tcp_seg *dbg_other_seg_list) |
||
1062 | { |
||
1063 | struct tcp_seg *next; |
||
1064 | u16_t clen; |
||
1065 | |||
1066 | LWIP_UNUSED_ARG(dbg_list_name); |
||
1067 | LWIP_UNUSED_ARG(dbg_other_seg_list); |
||
1068 | |||
1069 | while (seg_list != NULL && |
||
1070 | TCP_SEQ_LEQ(lwip_ntohl(seg_list->tcphdr->seqno) + |
||
1071 | TCP_TCPLEN(seg_list), ackno)) { |
||
1072 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->%s\n", |
||
1073 | lwip_ntohl(seg_list->tcphdr->seqno), |
||
1074 | lwip_ntohl(seg_list->tcphdr->seqno) + TCP_TCPLEN(seg_list), |
||
1075 | dbg_list_name)); |
||
1076 | |||
1077 | next = seg_list; |
||
1078 | seg_list = seg_list->next; |
||
1079 | |||
1080 | clen = pbuf_clen(next->p); |
||
1081 | LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"TCPWNDSIZE_F" ... ", |
||
1082 | (tcpwnd_size_t)pcb->snd_queuelen)); |
||
1083 | LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= clen)); |
||
1084 | |||
1085 | pcb->snd_queuelen = (u16_t)(pcb->snd_queuelen - clen); |
||
1086 | recv_acked = (tcpwnd_size_t)(recv_acked + next->len); |
||
1087 | tcp_seg_free(next); |
||
1088 | |||
1089 | LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"TCPWNDSIZE_F" (after freeing %s)\n", |
||
1090 | (tcpwnd_size_t)pcb->snd_queuelen, |
||
1091 | dbg_list_name)); |
||
1092 | if (pcb->snd_queuelen != 0) { |
||
1093 | LWIP_ASSERT("tcp_receive: valid queue length", |
||
1094 | seg_list != NULL || dbg_other_seg_list != NULL); |
||
1095 | } |
||
1096 | } |
||
1097 | return seg_list; |
||
1098 | } |
||
1099 | |||
1100 | /** |
||
1101 | * Called by tcp_process. Checks if the given segment is an ACK for outstanding |
||
1102 | * data, and if so frees the memory of the buffered data. Next, it places the |
||
1103 | * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment |
||
1104 | * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until |
||
1105 | * it has been removed from the buffer. |
||
1106 | * |
||
1107 | * If the incoming segment constitutes an ACK for a segment that was used for RTT |
||
1108 | * estimation, the RTT is estimated here as well. |
||
1109 | * |
||
1110 | * Called from tcp_process(). |
||
1111 | */ |
||
1112 | static void |
||
1113 | tcp_receive(struct tcp_pcb *pcb) |
||
1114 | { |
||
1115 | s16_t m; |
||
1116 | u32_t right_wnd_edge; |
||
1117 | int found_dupack = 0; |
||
1118 | |||
1119 | LWIP_ASSERT("tcp_receive: wrong state", pcb->state >= ESTABLISHED); |
||
1120 | |||
1121 | if (flags & TCP_ACK) { |
||
1122 | right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2; |
||
1123 | |||
1124 | /* Update window. */ |
||
1125 | if (TCP_SEQ_LT(pcb->snd_wl1, seqno) || |
||
1126 | (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) || |
||
1127 | (pcb->snd_wl2 == ackno && (u32_t)SND_WND_SCALE(pcb, tcphdr->wnd) > pcb->snd_wnd)) { |
||
1128 | pcb->snd_wnd = SND_WND_SCALE(pcb, tcphdr->wnd); |
||
1129 | /* keep track of the biggest window announced by the remote host to calculate |
||
1130 | the maximum segment size */ |
||
1131 | if (pcb->snd_wnd_max < pcb->snd_wnd) { |
||
1132 | pcb->snd_wnd_max = pcb->snd_wnd; |
||
1133 | } |
||
1134 | pcb->snd_wl1 = seqno; |
||
1135 | pcb->snd_wl2 = ackno; |
||
1136 | LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"TCPWNDSIZE_F"\n", pcb->snd_wnd)); |
||
1137 | #if TCP_WND_DEBUG |
||
1138 | } else { |
||
1139 | if (pcb->snd_wnd != (tcpwnd_size_t)SND_WND_SCALE(pcb, tcphdr->wnd)) { |
||
1140 | LWIP_DEBUGF(TCP_WND_DEBUG, |
||
1141 | ("tcp_receive: no window update lastack %"U32_F" ackno %" |
||
1142 | U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n", |
||
1143 | pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2)); |
||
1144 | } |
||
1145 | #endif /* TCP_WND_DEBUG */ |
||
1146 | } |
||
1147 | |||
1148 | /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a |
||
1149 | * duplicate ack if: |
||
1150 | * 1) It doesn't ACK new data |
||
1151 | * 2) length of received packet is zero (i.e. no payload) |
||
1152 | * 3) the advertised window hasn't changed |
||
1153 | * 4) There is outstanding unacknowledged data (retransmission timer running) |
||
1154 | * 5) The ACK is == biggest ACK sequence number so far seen (snd_una) |
||
1155 | * |
||
1156 | * If it passes all five, should process as a dupack: |
||
1157 | * a) dupacks < 3: do nothing |
||
1158 | * b) dupacks == 3: fast retransmit |
||
1159 | * c) dupacks > 3: increase cwnd |
||
1160 | * |
||
1161 | * If it only passes 1-3, should reset dupack counter (and add to |
||
1162 | * stats, which we don't do in lwIP) |
||
1163 | * |
||
1164 | * If it only passes 1, should reset dupack counter |
||
1165 | * |
||
1166 | */ |
||
1167 | |||
1168 | /* Clause 1 */ |
||
1169 | if (TCP_SEQ_LEQ(ackno, pcb->lastack)) { |
||
1170 | /* Clause 2 */ |
||
1171 | if (tcplen == 0) { |
||
1172 | /* Clause 3 */ |
||
1173 | if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge) { |
||
1174 | /* Clause 4 */ |
||
1175 | if (pcb->rtime >= 0) { |
||
1176 | /* Clause 5 */ |
||
1177 | if (pcb->lastack == ackno) { |
||
1178 | found_dupack = 1; |
||
1179 | if ((u8_t)(pcb->dupacks + 1) > pcb->dupacks) { |
||
1180 | ++pcb->dupacks; |
||
1181 | } |
||
1182 | if (pcb->dupacks > 3) { |
||
1183 | /* Inflate the congestion window */ |
||
1184 | TCP_WND_INC(pcb->cwnd, pcb->mss); |
||
1185 | } |
||
1186 | if (pcb->dupacks >= 3) { |
||
1187 | /* Do fast retransmit (checked via TF_INFR, not via dupacks count) */ |
||
1188 | tcp_rexmit_fast(pcb); |
||
1189 | } |
||
1190 | } |
||
1191 | } |
||
1192 | } |
||
1193 | } |
||
1194 | /* If Clause (1) or more is true, but not a duplicate ack, reset |
||
1195 | * count of consecutive duplicate acks */ |
||
1196 | if (!found_dupack) { |
||
1197 | pcb->dupacks = 0; |
||
1198 | } |
||
1199 | } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack + 1, pcb->snd_nxt)) { |
||
1200 | /* We come here when the ACK acknowledges new data. */ |
||
1201 | tcpwnd_size_t acked; |
||
1202 | |||
1203 | /* Reset the "IN Fast Retransmit" flag, since we are no longer |
||
1204 | in fast retransmit. Also reset the congestion window to the |
||
1205 | slow start threshold. */ |
||
1206 | if (pcb->flags & TF_INFR) { |
||
1207 | tcp_clear_flags(pcb, TF_INFR); |
||
1208 | pcb->cwnd = pcb->ssthresh; |
||
1209 | pcb->bytes_acked = 0; |
||
1210 | } |
||
1211 | |||
1212 | /* Reset the number of retransmissions. */ |
||
1213 | pcb->nrtx = 0; |
||
1214 | |||
1215 | /* Reset the retransmission time-out. */ |
||
1216 | pcb->rto = (s16_t)((pcb->sa >> 3) + pcb->sv); |
||
1217 | |||
1218 | /* Record how much data this ACK acks */ |
||
1219 | acked = (tcpwnd_size_t)(ackno - pcb->lastack); |
||
1220 | |||
1221 | /* Reset the fast retransmit variables. */ |
||
1222 | pcb->dupacks = 0; |
||
1223 | pcb->lastack = ackno; |
||
1224 | |||
1225 | /* Update the congestion control variables (cwnd and |
||
1226 | ssthresh). */ |
||
1227 | if (pcb->state >= ESTABLISHED) { |
||
1228 | if (pcb->cwnd < pcb->ssthresh) { |
||
1229 | tcpwnd_size_t increase; |
||
1230 | /* limit to 1 SMSS segment during period following RTO */ |
||
1231 | u8_t num_seg = (pcb->flags & TF_RTO) ? 1 : 2; |
||
1232 | /* RFC 3465, section 2.2 Slow Start */ |
||
1233 | increase = LWIP_MIN(acked, (tcpwnd_size_t)(num_seg * pcb->mss)); |
||
1234 | TCP_WND_INC(pcb->cwnd, increase); |
||
1235 | LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"TCPWNDSIZE_F"\n", pcb->cwnd)); |
||
1236 | } else { |
||
1237 | /* RFC 3465, section 2.1 Congestion Avoidance */ |
||
1238 | TCP_WND_INC(pcb->bytes_acked, acked); |
||
1239 | if (pcb->bytes_acked >= pcb->cwnd) { |
||
1240 | pcb->bytes_acked = (tcpwnd_size_t)(pcb->bytes_acked - pcb->cwnd); |
||
1241 | TCP_WND_INC(pcb->cwnd, pcb->mss); |
||
1242 | } |
||
1243 | LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"TCPWNDSIZE_F"\n", pcb->cwnd)); |
||
1244 | } |
||
1245 | } |
||
1246 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n", |
||
1247 | ackno, |
||
1248 | pcb->unacked != NULL ? |
||
1249 | lwip_ntohl(pcb->unacked->tcphdr->seqno) : 0, |
||
1250 | pcb->unacked != NULL ? |
||
1251 | lwip_ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked) : 0)); |
||
1252 | |||
1253 | /* Remove segment from the unacknowledged list if the incoming |
||
1254 | ACK acknowledges them. */ |
||
1255 | pcb->unacked = tcp_free_acked_segments(pcb, pcb->unacked, "unacked", pcb->unsent); |
||
1256 | /* We go through the ->unsent list to see if any of the segments |
||
1257 | on the list are acknowledged by the ACK. This may seem |
||
1258 | strange since an "unsent" segment shouldn't be acked. The |
||
1259 | rationale is that lwIP puts all outstanding segments on the |
||
1260 | ->unsent list after a retransmission, so these segments may |
||
1261 | in fact have been sent once. */ |
||
1262 | pcb->unsent = tcp_free_acked_segments(pcb, pcb->unsent, "unsent", pcb->unacked); |
||
1263 | |||
1264 | /* If there's nothing left to acknowledge, stop the retransmit |
||
1265 | timer, otherwise reset it to start again */ |
||
1266 | if (pcb->unacked == NULL) { |
||
1267 | pcb->rtime = -1; |
||
1268 | } else { |
||
1269 | pcb->rtime = 0; |
||
1270 | } |
||
1271 | |||
1272 | pcb->polltmr = 0; |
||
1273 | |||
1274 | #if TCP_OVERSIZE |
||
1275 | if (pcb->unsent == NULL) { |
||
1276 | pcb->unsent_oversize = 0; |
||
1277 | } |
||
1278 | #endif /* TCP_OVERSIZE */ |
||
1279 | |||
1280 | #if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS |
||
1281 | if (ip_current_is_v6()) { |
||
1282 | /* Inform neighbor reachability of forward progress. */ |
||
1283 | nd6_reachability_hint(ip6_current_src_addr()); |
||
1284 | } |
||
1285 | #endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/ |
||
1286 | |||
1287 | pcb->snd_buf = (tcpwnd_size_t)(pcb->snd_buf + recv_acked); |
||
1288 | /* check if this ACK ends our retransmission of in-flight data */ |
||
1289 | if (pcb->flags & TF_RTO) { |
||
1290 | /* RTO is done if |
||
1291 | 1) both queues are empty or |
||
1292 | 2) unacked is empty and unsent head contains data not part of RTO or |
||
1293 | 3) unacked head contains data not part of RTO */ |
||
1294 | if (pcb->unacked == NULL) { |
||
1295 | if ((pcb->unsent == NULL) || |
||
1296 | (TCP_SEQ_LEQ(pcb->rto_end, lwip_ntohl(pcb->unsent->tcphdr->seqno)))) { |
||
1297 | tcp_clear_flags(pcb, TF_RTO); |
||
1298 | } |
||
1299 | } else if (TCP_SEQ_LEQ(pcb->rto_end, lwip_ntohl(pcb->unacked->tcphdr->seqno))) { |
||
1300 | tcp_clear_flags(pcb, TF_RTO); |
||
1301 | } |
||
1302 | } |
||
1303 | /* End of ACK for new data processing. */ |
||
1304 | } else { |
||
1305 | /* Out of sequence ACK, didn't really ack anything */ |
||
1306 | tcp_send_empty_ack(pcb); |
||
1307 | } |
||
1308 | |||
1309 | LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n", |
||
1310 | pcb->rttest, pcb->rtseq, ackno)); |
||
1311 | |||
1312 | /* RTT estimation calculations. This is done by checking if the |
||
1313 | incoming segment acknowledges the segment we use to take a |
||
1314 | round-trip time measurement. */ |
||
1315 | if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) { |
||
1316 | /* diff between this shouldn't exceed 32K since this are tcp timer ticks |
||
1317 | and a round-trip shouldn't be that long... */ |
||
1318 | m = (s16_t)(tcp_ticks - pcb->rttest); |
||
1319 | |||
1320 | LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n", |
||
1321 | m, (u16_t)(m * TCP_SLOW_INTERVAL))); |
||
1322 | |||
1323 | /* This is taken directly from VJs original code in his paper */ |
||
1324 | m = (s16_t)(m - (pcb->sa >> 3)); |
||
1325 | pcb->sa = (s16_t)(pcb->sa + m); |
||
1326 | if (m < 0) { |
||
1327 | m = (s16_t) - m; |
||
1328 | } |
||
1329 | m = (s16_t)(m - (pcb->sv >> 2)); |
||
1330 | pcb->sv = (s16_t)(pcb->sv + m); |
||
1331 | pcb->rto = (s16_t)((pcb->sa >> 3) + pcb->sv); |
||
1332 | |||
1333 | LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n", |
||
1334 | pcb->rto, (u16_t)(pcb->rto * TCP_SLOW_INTERVAL))); |
||
1335 | |||
1336 | pcb->rttest = 0; |
||
1337 | } |
||
1338 | } |
||
1339 | |||
1340 | /* If the incoming segment contains data, we must process it |
||
1341 | further unless the pcb already received a FIN. |
||
1342 | (RFC 793, chapter 3.9, "SEGMENT ARRIVES" in states CLOSE-WAIT, CLOSING, |
||
1343 | LAST-ACK and TIME-WAIT: "Ignore the segment text.") */ |
||
1344 | if ((tcplen > 0) && (pcb->state < CLOSE_WAIT)) { |
||
1345 | /* This code basically does three things: |
||
1346 | |||
1347 | +) If the incoming segment contains data that is the next |
||
1348 | in-sequence data, this data is passed to the application. This |
||
1349 | might involve trimming the first edge of the data. The rcv_nxt |
||
1350 | variable and the advertised window are adjusted. |
||
1351 | |||
1352 | +) If the incoming segment has data that is above the next |
||
1353 | sequence number expected (->rcv_nxt), the segment is placed on |
||
1354 | the ->ooseq queue. This is done by finding the appropriate |
||
1355 | place in the ->ooseq queue (which is ordered by sequence |
||
1356 | number) and trim the segment in both ends if needed. An |
||
1357 | immediate ACK is sent to indicate that we received an |
||
1358 | out-of-sequence segment. |
||
1359 | |||
1360 | +) Finally, we check if the first segment on the ->ooseq queue |
||
1361 | now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If |
||
1362 | rcv_nxt > ooseq->seqno, we must trim the first edge of the |
||
1363 | segment on ->ooseq before we adjust rcv_nxt. The data in the |
||
1364 | segments that are now on sequence are chained onto the |
||
1365 | incoming segment so that we only need to call the application |
||
1366 | once. |
||
1367 | */ |
||
1368 | |||
1369 | /* First, we check if we must trim the first edge. We have to do |
||
1370 | this if the sequence number of the incoming segment is less |
||
1371 | than rcv_nxt, and the sequence number plus the length of the |
||
1372 | segment is larger than rcv_nxt. */ |
||
1373 | /* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)) { |
||
1374 | if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/ |
||
1375 | if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)) { |
||
1376 | /* Trimming the first edge is done by pushing the payload |
||
1377 | pointer in the pbuf downwards. This is somewhat tricky since |
||
1378 | we do not want to discard the full contents of the pbuf up to |
||
1379 | the new starting point of the data since we have to keep the |
||
1380 | TCP header which is present in the first pbuf in the chain. |
||
1381 | |||
1382 | What is done is really quite a nasty hack: the first pbuf in |
||
1383 | the pbuf chain is pointed to by inseg.p. Since we need to be |
||
1384 | able to deallocate the whole pbuf, we cannot change this |
||
1385 | inseg.p pointer to point to any of the later pbufs in the |
||
1386 | chain. Instead, we point the ->payload pointer in the first |
||
1387 | pbuf to data in one of the later pbufs. We also set the |
||
1388 | inseg.data pointer to point to the right place. This way, the |
||
1389 | ->p pointer will still point to the first pbuf, but the |
||
1390 | ->p->payload pointer will point to data in another pbuf. |
||
1391 | |||
1392 | After we are done with adjusting the pbuf pointers we must |
||
1393 | adjust the ->data pointer in the seg and the segment |
||
1394 | length.*/ |
||
1395 | |||
1396 | struct pbuf *p = inseg.p; |
||
1397 | u32_t off32 = pcb->rcv_nxt - seqno; |
||
1398 | u16_t new_tot_len, off; |
||
1399 | LWIP_ASSERT("inseg.p != NULL", inseg.p); |
||
1400 | LWIP_ASSERT("insane offset!", (off32 < 0xffff)); |
||
1401 | off = (u16_t)off32; |
||
1402 | LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off)); |
||
1403 | inseg.len -= off; |
||
1404 | new_tot_len = (u16_t)(inseg.p->tot_len - off); |
||
1405 | while (p->len < off) { |
||
1406 | off -= p->len; |
||
1407 | /* all pbufs up to and including this one have len==0, so tot_len is equal */ |
||
1408 | p->tot_len = new_tot_len; |
||
1409 | p->len = 0; |
||
1410 | p = p->next; |
||
1411 | } |
||
1412 | /* cannot fail... */ |
||
1413 | pbuf_remove_header(p, off); |
||
1414 | inseg.tcphdr->seqno = seqno = pcb->rcv_nxt; |
||
1415 | } else { |
||
1416 | if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)) { |
||
1417 | /* the whole segment is < rcv_nxt */ |
||
1418 | /* must be a duplicate of a packet that has already been correctly handled */ |
||
1419 | |||
1420 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno)); |
||
1421 | tcp_ack_now(pcb); |
||
1422 | } |
||
1423 | } |
||
1424 | |||
1425 | /* The sequence number must be within the window (above rcv_nxt |
||
1426 | and below rcv_nxt + rcv_wnd) in order to be further |
||
1427 | processed. */ |
||
1428 | if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, |
||
1429 | pcb->rcv_nxt + pcb->rcv_wnd - 1)) { |
||
1430 | if (pcb->rcv_nxt == seqno) { |
||
1431 | /* The incoming segment is the next in sequence. We check if |
||
1432 | we have to trim the end of the segment and update rcv_nxt |
||
1433 | and pass the data to the application. */ |
||
1434 | tcplen = TCP_TCPLEN(&inseg); |
||
1435 | |||
1436 | if (tcplen > pcb->rcv_wnd) { |
||
1437 | LWIP_DEBUGF(TCP_INPUT_DEBUG, |
||
1438 | ("tcp_receive: other end overran receive window" |
||
1439 | "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", |
||
1440 | seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); |
||
1441 | if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { |
||
1442 | /* Must remove the FIN from the header as we're trimming |
||
1443 | * that byte of sequence-space from the packet */ |
||
1444 | TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) & ~(unsigned int)TCP_FIN); |
||
1445 | } |
||
1446 | /* Adjust length of segment to fit in the window. */ |
||
1447 | TCPWND_CHECK16(pcb->rcv_wnd); |
||
1448 | inseg.len = (u16_t)pcb->rcv_wnd; |
||
1449 | if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { |
||
1450 | inseg.len -= 1; |
||
1451 | } |
||
1452 | pbuf_realloc(inseg.p, inseg.len); |
||
1453 | tcplen = TCP_TCPLEN(&inseg); |
||
1454 | LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", |
||
1455 | (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); |
||
1456 | } |
||
1457 | #if TCP_QUEUE_OOSEQ |
||
1458 | /* Received in-sequence data, adjust ooseq data if: |
||
1459 | - FIN has been received or |
||
1460 | - inseq overlaps with ooseq */ |
||
1461 | if (pcb->ooseq != NULL) { |
||
1462 | if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { |
||
1463 | LWIP_DEBUGF(TCP_INPUT_DEBUG, |
||
1464 | ("tcp_receive: received in-order FIN, binning ooseq queue\n")); |
||
1465 | /* Received in-order FIN means anything that was received |
||
1466 | * out of order must now have been received in-order, so |
||
1467 | * bin the ooseq queue */ |
||
1468 | while (pcb->ooseq != NULL) { |
||
1469 | struct tcp_seg *old_ooseq = pcb->ooseq; |
||
1470 | pcb->ooseq = pcb->ooseq->next; |
||
1471 | tcp_seg_free(old_ooseq); |
||
1472 | } |
||
1473 | } else { |
||
1474 | struct tcp_seg *next = pcb->ooseq; |
||
1475 | /* Remove all segments on ooseq that are covered by inseg already. |
||
1476 | * FIN is copied from ooseq to inseg if present. */ |
||
1477 | while (next && |
||
1478 | TCP_SEQ_GEQ(seqno + tcplen, |
||
1479 | next->tcphdr->seqno + next->len)) { |
||
1480 | struct tcp_seg *tmp; |
||
1481 | /* inseg cannot have FIN here (already processed above) */ |
||
1482 | if ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0 && |
||
1483 | (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) { |
||
1484 | TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN); |
||
1485 | tcplen = TCP_TCPLEN(&inseg); |
||
1486 | } |
||
1487 | tmp = next; |
||
1488 | next = next->next; |
||
1489 | tcp_seg_free(tmp); |
||
1490 | } |
||
1491 | /* Now trim right side of inseg if it overlaps with the first |
||
1492 | * segment on ooseq */ |
||
1493 | if (next && |
||
1494 | TCP_SEQ_GT(seqno + tcplen, |
||
1495 | next->tcphdr->seqno)) { |
||
1496 | /* inseg cannot have FIN here (already processed above) */ |
||
1497 | inseg.len = (u16_t)(next->tcphdr->seqno - seqno); |
||
1498 | if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { |
||
1499 | inseg.len -= 1; |
||
1500 | } |
||
1501 | pbuf_realloc(inseg.p, inseg.len); |
||
1502 | tcplen = TCP_TCPLEN(&inseg); |
||
1503 | LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n", |
||
1504 | (seqno + tcplen) == next->tcphdr->seqno); |
||
1505 | } |
||
1506 | pcb->ooseq = next; |
||
1507 | } |
||
1508 | } |
||
1509 | #endif /* TCP_QUEUE_OOSEQ */ |
||
1510 | |||
1511 | pcb->rcv_nxt = seqno + tcplen; |
||
1512 | |||
1513 | /* Update the receiver's (our) window. */ |
||
1514 | LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen); |
||
1515 | pcb->rcv_wnd -= tcplen; |
||
1516 | |||
1517 | tcp_update_rcv_ann_wnd(pcb); |
||
1518 | |||
1519 | /* If there is data in the segment, we make preparations to |
||
1520 | pass this up to the application. The ->recv_data variable |
||
1521 | is used for holding the pbuf that goes to the |
||
1522 | application. The code for reassembling out-of-sequence data |
||
1523 | chains its data on this pbuf as well. |
||
1524 | |||
1525 | If the segment was a FIN, we set the TF_GOT_FIN flag that will |
||
1526 | be used to indicate to the application that the remote side has |
||
1527 | closed its end of the connection. */ |
||
1528 | if (inseg.p->tot_len > 0) { |
||
1529 | recv_data = inseg.p; |
||
1530 | /* Since this pbuf now is the responsibility of the |
||
1531 | application, we delete our reference to it so that we won't |
||
1532 | (mistakingly) deallocate it. */ |
||
1533 | inseg.p = NULL; |
||
1534 | } |
||
1535 | if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { |
||
1536 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n")); |
||
1537 | recv_flags |= TF_GOT_FIN; |
||
1538 | } |
||
1539 | |||
1540 | #if TCP_QUEUE_OOSEQ |
||
1541 | /* We now check if we have segments on the ->ooseq queue that |
||
1542 | are now in sequence. */ |
||
1543 | while (pcb->ooseq != NULL && |
||
1544 | pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) { |
||
1545 | |||
1546 | struct tcp_seg *cseg = pcb->ooseq; |
||
1547 | seqno = pcb->ooseq->tcphdr->seqno; |
||
1548 | |||
1549 | pcb->rcv_nxt += TCP_TCPLEN(cseg); |
||
1550 | LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n", |
||
1551 | pcb->rcv_wnd >= TCP_TCPLEN(cseg)); |
||
1552 | pcb->rcv_wnd -= TCP_TCPLEN(cseg); |
||
1553 | |||
1554 | tcp_update_rcv_ann_wnd(pcb); |
||
1555 | |||
1556 | if (cseg->p->tot_len > 0) { |
||
1557 | /* Chain this pbuf onto the pbuf that we will pass to |
||
1558 | the application. */ |
||
1559 | /* With window scaling, this can overflow recv_data->tot_len, but |
||
1560 | that's not a problem since we explicitly fix that before passing |
||
1561 | recv_data to the application. */ |
||
1562 | if (recv_data) { |
||
1563 | pbuf_cat(recv_data, cseg->p); |
||
1564 | } else { |
||
1565 | recv_data = cseg->p; |
||
1566 | } |
||
1567 | cseg->p = NULL; |
||
1568 | } |
||
1569 | if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { |
||
1570 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n")); |
||
1571 | recv_flags |= TF_GOT_FIN; |
||
1572 | if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */ |
||
1573 | pcb->state = CLOSE_WAIT; |
||
1574 | } |
||
1575 | } |
||
1576 | |||
1577 | pcb->ooseq = cseg->next; |
||
1578 | tcp_seg_free(cseg); |
||
1579 | } |
||
1580 | #if LWIP_TCP_SACK_OUT |
||
1581 | if (pcb->flags & TF_SACK) { |
||
1582 | if (pcb->ooseq != NULL) { |
||
1583 | /* Some segments may have been removed from ooseq, let's remove all SACKs that |
||
1584 | describe anything before the new beginning of that list. */ |
||
1585 | tcp_remove_sacks_lt(pcb, pcb->ooseq->tcphdr->seqno); |
||
1586 | } else if (LWIP_TCP_SACK_VALID(pcb, 0)) { |
||
1587 | /* ooseq has been cleared. Nothing to SACK */ |
||
1588 | memset(pcb->rcv_sacks, 0, sizeof(pcb->rcv_sacks)); |
||
1589 | } |
||
1590 | } |
||
1591 | #endif /* LWIP_TCP_SACK_OUT */ |
||
1592 | #endif /* TCP_QUEUE_OOSEQ */ |
||
1593 | |||
1594 | |||
1595 | /* Acknowledge the segment(s). */ |
||
1596 | tcp_ack(pcb); |
||
1597 | |||
1598 | #if LWIP_TCP_SACK_OUT |
||
1599 | if (LWIP_TCP_SACK_VALID(pcb, 0)) { |
||
1600 | /* Normally the ACK for the data received could be piggy-backed on a data packet, |
||
1601 | but lwIP currently does not support including SACKs in data packets. So we force |
||
1602 | it to respond with an empty ACK packet (only if there is at least one SACK to be sent). |
||
1603 | NOTE: tcp_send_empty_ack() on success clears the ACK flags (set by tcp_ack()) */ |
||
1604 | tcp_send_empty_ack(pcb); |
||
1605 | } |
||
1606 | #endif /* LWIP_TCP_SACK_OUT */ |
||
1607 | |||
1608 | #if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS |
||
1609 | if (ip_current_is_v6()) { |
||
1610 | /* Inform neighbor reachability of forward progress. */ |
||
1611 | nd6_reachability_hint(ip6_current_src_addr()); |
||
1612 | } |
||
1613 | #endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/ |
||
1614 | |||
1615 | } else { |
||
1616 | /* We get here if the incoming segment is out-of-sequence. */ |
||
1617 | |||
1618 | #if TCP_QUEUE_OOSEQ |
||
1619 | /* We queue the segment on the ->ooseq queue. */ |
||
1620 | if (pcb->ooseq == NULL) { |
||
1621 | pcb->ooseq = tcp_seg_copy(&inseg); |
||
1622 | #if LWIP_TCP_SACK_OUT |
||
1623 | if (pcb->flags & TF_SACK) { |
||
1624 | /* All the SACKs should be invalid, so we can simply store the most recent one: */ |
||
1625 | pcb->rcv_sacks[0].left = seqno; |
||
1626 | pcb->rcv_sacks[0].right = seqno + inseg.len; |
||
1627 | } |
||
1628 | #endif /* LWIP_TCP_SACK_OUT */ |
||
1629 | } else { |
||
1630 | /* If the queue is not empty, we walk through the queue and |
||
1631 | try to find a place where the sequence number of the |
||
1632 | incoming segment is between the sequence numbers of the |
||
1633 | previous and the next segment on the ->ooseq queue. That is |
||
1634 | the place where we put the incoming segment. If needed, we |
||
1635 | trim the second edges of the previous and the incoming |
||
1636 | segment so that it will fit into the sequence. |
||
1637 | |||
1638 | If the incoming segment has the same sequence number as a |
||
1639 | segment on the ->ooseq queue, we discard the segment that |
||
1640 | contains less data. */ |
||
1641 | |||
1642 | #if LWIP_TCP_SACK_OUT |
||
1643 | /* This is the left edge of the lowest possible SACK range. |
||
1644 | It may start before the newly received segment (possibly adjusted below). */ |
||
1645 | u32_t sackbeg = TCP_SEQ_LT(seqno, pcb->ooseq->tcphdr->seqno) ? seqno : pcb->ooseq->tcphdr->seqno; |
||
1646 | #endif /* LWIP_TCP_SACK_OUT */ |
||
1647 | struct tcp_seg *next, *prev = NULL; |
||
1648 | for (next = pcb->ooseq; next != NULL; next = next->next) { |
||
1649 | if (seqno == next->tcphdr->seqno) { |
||
1650 | /* The sequence number of the incoming segment is the |
||
1651 | same as the sequence number of the segment on |
||
1652 | ->ooseq. We check the lengths to see which one to |
||
1653 | discard. */ |
||
1654 | if (inseg.len > next->len) { |
||
1655 | /* The incoming segment is larger than the old |
||
1656 | segment. We replace some segments with the new |
||
1657 | one. */ |
||
1658 | struct tcp_seg *cseg = tcp_seg_copy(&inseg); |
||
1659 | if (cseg != NULL) { |
||
1660 | if (prev != NULL) { |
||
1661 | prev->next = cseg; |
||
1662 | } else { |
||
1663 | pcb->ooseq = cseg; |
||
1664 | } |
||
1665 | tcp_oos_insert_segment(cseg, next); |
||
1666 | } |
||
1667 | break; |
||
1668 | } else { |
||
1669 | /* Either the lengths are the same or the incoming |
||
1670 | segment was smaller than the old one; in either |
||
1671 | case, we ditch the incoming segment. */ |
||
1672 | break; |
||
1673 | } |
||
1674 | } else { |
||
1675 | if (prev == NULL) { |
||
1676 | if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) { |
||
1677 | /* The sequence number of the incoming segment is lower |
||
1678 | than the sequence number of the first segment on the |
||
1679 | queue. We put the incoming segment first on the |
||
1680 | queue. */ |
||
1681 | struct tcp_seg *cseg = tcp_seg_copy(&inseg); |
||
1682 | if (cseg != NULL) { |
||
1683 | pcb->ooseq = cseg; |
||
1684 | tcp_oos_insert_segment(cseg, next); |
||
1685 | } |
||
1686 | break; |
||
1687 | } |
||
1688 | } else { |
||
1689 | /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) && |
||
1690 | TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/ |
||
1691 | if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno + 1, next->tcphdr->seqno - 1)) { |
||
1692 | /* The sequence number of the incoming segment is in |
||
1693 | between the sequence numbers of the previous and |
||
1694 | the next segment on ->ooseq. We trim trim the previous |
||
1695 | segment, delete next segments that included in received segment |
||
1696 | and trim received, if needed. */ |
||
1697 | struct tcp_seg *cseg = tcp_seg_copy(&inseg); |
||
1698 | if (cseg != NULL) { |
||
1699 | if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) { |
||
1700 | /* We need to trim the prev segment. */ |
||
1701 | prev->len = (u16_t)(seqno - prev->tcphdr->seqno); |
||
1702 | pbuf_realloc(prev->p, prev->len); |
||
1703 | } |
||
1704 | prev->next = cseg; |
||
1705 | tcp_oos_insert_segment(cseg, next); |
||
1706 | } |
||
1707 | break; |
||
1708 | } |
||
1709 | } |
||
1710 | |||
1711 | #if LWIP_TCP_SACK_OUT |
||
1712 | /* The new segment goes after the 'next' one. If there is a "hole" in sequence numbers |
||
1713 | between 'prev' and the beginning of 'next', we want to move sackbeg. */ |
||
1714 | if (prev != NULL && prev->tcphdr->seqno + prev->len != next->tcphdr->seqno) { |
||
1715 | sackbeg = next->tcphdr->seqno; |
||
1716 | } |
||
1717 | #endif /* LWIP_TCP_SACK_OUT */ |
||
1718 | |||
1719 | /* We don't use 'prev' below, so let's set it to current 'next'. |
||
1720 | This way even if we break the loop below, 'prev' will be pointing |
||
1721 | at the segment right in front of the newly added one. */ |
||
1722 | prev = next; |
||
1723 | |||
1724 | /* If the "next" segment is the last segment on the |
||
1725 | ooseq queue, we add the incoming segment to the end |
||
1726 | of the list. */ |
||
1727 | if (next->next == NULL && |
||
1728 | TCP_SEQ_GT(seqno, next->tcphdr->seqno)) { |
||
1729 | if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { |
||
1730 | /* segment "next" already contains all data */ |
||
1731 | break; |
||
1732 | } |
||
1733 | next->next = tcp_seg_copy(&inseg); |
||
1734 | if (next->next != NULL) { |
||
1735 | if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) { |
||
1736 | /* We need to trim the last segment. */ |
||
1737 | next->len = (u16_t)(seqno - next->tcphdr->seqno); |
||
1738 | pbuf_realloc(next->p, next->len); |
||
1739 | } |
||
1740 | /* check if the remote side overruns our receive window */ |
||
1741 | if (TCP_SEQ_GT((u32_t)tcplen + seqno, pcb->rcv_nxt + (u32_t)pcb->rcv_wnd)) { |
||
1742 | LWIP_DEBUGF(TCP_INPUT_DEBUG, |
||
1743 | ("tcp_receive: other end overran receive window" |
||
1744 | "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", |
||
1745 | seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); |
||
1746 | if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) { |
||
1747 | /* Must remove the FIN from the header as we're trimming |
||
1748 | * that byte of sequence-space from the packet */ |
||
1749 | TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) & ~TCP_FIN); |
||
1750 | } |
||
1751 | /* Adjust length of segment to fit in the window. */ |
||
1752 | next->next->len = (u16_t)(pcb->rcv_nxt + pcb->rcv_wnd - seqno); |
||
1753 | pbuf_realloc(next->next->p, next->next->len); |
||
1754 | tcplen = TCP_TCPLEN(next->next); |
||
1755 | LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", |
||
1756 | (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); |
||
1757 | } |
||
1758 | } |
||
1759 | break; |
||
1760 | } |
||
1761 | } |
||
1762 | } |
||
1763 | |||
1764 | #if LWIP_TCP_SACK_OUT |
||
1765 | if (pcb->flags & TF_SACK) { |
||
1766 | if (prev == NULL) { |
||
1767 | /* The new segment is at the beginning. sackbeg should already be set properly. |
||
1768 | We need to find the right edge. */ |
||
1769 | next = pcb->ooseq; |
||
1770 | } else if (prev->next != NULL) { |
||
1771 | /* The new segment was added after 'prev'. If there is a "hole" between 'prev' and 'prev->next', |
||
1772 | we need to move sackbeg. After that we should find the right edge. */ |
||
1773 | next = prev->next; |
||
1774 | if (prev->tcphdr->seqno + prev->len != next->tcphdr->seqno) { |
||
1775 | sackbeg = next->tcphdr->seqno; |
||
1776 | } |
||
1777 | } else { |
||
1778 | next = NULL; |
||
1779 | } |
||
1780 | if (next != NULL) { |
||
1781 | u32_t sackend = next->tcphdr->seqno; |
||
1782 | for ( ; (next != NULL) && (sackend == next->tcphdr->seqno); next = next->next) { |
||
1783 | sackend += next->len; |
||
1784 | } |
||
1785 | tcp_add_sack(pcb, sackbeg, sackend); |
||
1786 | } |
||
1787 | } |
||
1788 | #endif /* LWIP_TCP_SACK_OUT */ |
||
1789 | } |
||
1790 | #if defined(TCP_OOSEQ_BYTES_LIMIT) || defined(TCP_OOSEQ_PBUFS_LIMIT) |
||
1791 | { |
||
1792 | /* Check that the data on ooseq doesn't exceed one of the limits |
||
1793 | and throw away everything above that limit. */ |
||
1794 | #ifdef TCP_OOSEQ_BYTES_LIMIT |
||
1795 | const u32_t ooseq_max_blen = TCP_OOSEQ_BYTES_LIMIT(pcb); |
||
1796 | u32_t ooseq_blen = 0; |
||
1797 | #endif |
||
1798 | #ifdef TCP_OOSEQ_PBUFS_LIMIT |
||
1799 | const u16_t ooseq_max_qlen = TCP_OOSEQ_PBUFS_LIMIT(pcb); |
||
1800 | u16_t ooseq_qlen = 0; |
||
1801 | #endif |
||
1802 | struct tcp_seg *next, *prev = NULL; |
||
1803 | for (next = pcb->ooseq; next != NULL; prev = next, next = next->next) { |
||
1804 | struct pbuf *p = next->p; |
||
1805 | int stop_here = 0; |
||
1806 | #ifdef TCP_OOSEQ_BYTES_LIMIT |
||
1807 | ooseq_blen += p->tot_len; |
||
1808 | if (ooseq_blen > ooseq_max_blen) { |
||
1809 | stop_here = 1; |
||
1810 | } |
||
1811 | #endif |
||
1812 | #ifdef TCP_OOSEQ_PBUFS_LIMIT |
||
1813 | ooseq_qlen += pbuf_clen(p); |
||
1814 | if (ooseq_qlen > ooseq_max_qlen) { |
||
1815 | stop_here = 1; |
||
1816 | } |
||
1817 | #endif |
||
1818 | if (stop_here) { |
||
1819 | #if LWIP_TCP_SACK_OUT |
||
1820 | if (pcb->flags & TF_SACK) { |
||
1821 | /* Let's remove all SACKs from next's seqno up. */ |
||
1822 | tcp_remove_sacks_gt(pcb, next->tcphdr->seqno); |
||
1823 | } |
||
1824 | #endif /* LWIP_TCP_SACK_OUT */ |
||
1825 | /* too much ooseq data, dump this and everything after it */ |
||
1826 | tcp_segs_free(next); |
||
1827 | if (prev == NULL) { |
||
1828 | /* first ooseq segment is too much, dump the whole queue */ |
||
1829 | pcb->ooseq = NULL; |
||
1830 | } else { |
||
1831 | /* just dump 'next' and everything after it */ |
||
1832 | prev->next = NULL; |
||
1833 | } |
||
1834 | break; |
||
1835 | } |
||
1836 | } |
||
1837 | } |
||
1838 | #endif /* TCP_OOSEQ_BYTES_LIMIT || TCP_OOSEQ_PBUFS_LIMIT */ |
||
1839 | #endif /* TCP_QUEUE_OOSEQ */ |
||
1840 | |||
1841 | /* We send the ACK packet after we've (potentially) dealt with SACKs, |
||
1842 | so they can be included in the acknowledgment. */ |
||
1843 | tcp_send_empty_ack(pcb); |
||
1844 | } |
||
1845 | } else { |
||
1846 | /* The incoming segment is not within the window. */ |
||
1847 | tcp_send_empty_ack(pcb); |
||
1848 | } |
||
1849 | } else { |
||
1850 | /* Segments with length 0 is taken care of here. Segments that |
||
1851 | fall out of the window are ACKed. */ |
||
1852 | if (!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd - 1)) { |
||
1853 | tcp_ack_now(pcb); |
||
1854 | } |
||
1855 | } |
||
1856 | } |
||
1857 | |||
1858 | static u8_t |
||
1859 | tcp_get_next_optbyte(void) |
||
1860 | { |
||
1861 | u16_t optidx = tcp_optidx++; |
||
1862 | if ((tcphdr_opt2 == NULL) || (optidx < tcphdr_opt1len)) { |
||
1863 | u8_t *opts = (u8_t *)tcphdr + TCP_HLEN; |
||
1864 | return opts[optidx]; |
||
1865 | } else { |
||
1866 | u8_t idx = (u8_t)(optidx - tcphdr_opt1len); |
||
1867 | return tcphdr_opt2[idx]; |
||
1868 | } |
||
1869 | } |
||
1870 | |||
1871 | /** |
||
1872 | * Parses the options contained in the incoming segment. |
||
1873 | * |
||
1874 | * Called from tcp_listen_input() and tcp_process(). |
||
1875 | * Currently, only the MSS option is supported! |
||
1876 | * |
||
1877 | * @param pcb the tcp_pcb for which a segment arrived |
||
1878 | */ |
||
1879 | static void |
||
1880 | tcp_parseopt(struct tcp_pcb *pcb) |
||
1881 | { |
||
1882 | u8_t data; |
||
1883 | u16_t mss; |
||
1884 | #if LWIP_TCP_TIMESTAMPS |
||
1885 | u32_t tsval; |
||
1886 | #endif |
||
1887 | |||
1888 | /* Parse the TCP MSS option, if present. */ |
||
1889 | if (tcphdr_optlen != 0) { |
||
1890 | for (tcp_optidx = 0; tcp_optidx < tcphdr_optlen; ) { |
||
1891 | u8_t opt = tcp_get_next_optbyte(); |
||
1892 | switch (opt) { |
||
1893 | case LWIP_TCP_OPT_EOL: |
||
1894 | /* End of options. */ |
||
1895 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n")); |
||
1896 | return; |
||
1897 | case LWIP_TCP_OPT_NOP: |
||
1898 | /* NOP option. */ |
||
1899 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n")); |
||
1900 | break; |
||
1901 | case LWIP_TCP_OPT_MSS: |
||
1902 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n")); |
||
1903 | if (tcp_get_next_optbyte() != LWIP_TCP_OPT_LEN_MSS || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_MSS) > tcphdr_optlen) { |
||
1904 | /* Bad length */ |
||
1905 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); |
||
1906 | return; |
||
1907 | } |
||
1908 | /* An MSS option with the right option length. */ |
||
1909 | mss = (u16_t)(tcp_get_next_optbyte() << 8); |
||
1910 | mss |= tcp_get_next_optbyte(); |
||
1911 | /* Limit the mss to the configured TCP_MSS and prevent division by zero */ |
||
1912 | pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss; |
||
1913 | break; |
||
1914 | #if LWIP_WND_SCALE |
||
1915 | case LWIP_TCP_OPT_WS: |
||
1916 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: WND_SCALE\n")); |
||
1917 | if (tcp_get_next_optbyte() != LWIP_TCP_OPT_LEN_WS || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_WS) > tcphdr_optlen) { |
||
1918 | /* Bad length */ |
||
1919 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); |
||
1920 | return; |
||
1921 | } |
||
1922 | /* An WND_SCALE option with the right option length. */ |
||
1923 | data = tcp_get_next_optbyte(); |
||
1924 | /* If syn was received with wnd scale option, |
||
1925 | activate wnd scale opt, but only if this is not a retransmission */ |
||
1926 | if ((flags & TCP_SYN) && !(pcb->flags & TF_WND_SCALE)) { |
||
1927 | pcb->snd_scale = data; |
||
1928 | if (pcb->snd_scale > 14U) { |
||
1929 | pcb->snd_scale = 14U; |
||
1930 | } |
||
1931 | pcb->rcv_scale = TCP_RCV_SCALE; |
||
1932 | tcp_set_flags(pcb, TF_WND_SCALE); |
||
1933 | /* window scaling is enabled, we can use the full receive window */ |
||
1934 | LWIP_ASSERT("window not at default value", pcb->rcv_wnd == TCPWND_MIN16(TCP_WND)); |
||
1935 | LWIP_ASSERT("window not at default value", pcb->rcv_ann_wnd == TCPWND_MIN16(TCP_WND)); |
||
1936 | pcb->rcv_wnd = pcb->rcv_ann_wnd = TCP_WND; |
||
1937 | } |
||
1938 | break; |
||
1939 | #endif /* LWIP_WND_SCALE */ |
||
1940 | #if LWIP_TCP_TIMESTAMPS |
||
1941 | case LWIP_TCP_OPT_TS: |
||
1942 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n")); |
||
1943 | if (tcp_get_next_optbyte() != LWIP_TCP_OPT_LEN_TS || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_TS) > tcphdr_optlen) { |
||
1944 | /* Bad length */ |
||
1945 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); |
||
1946 | return; |
||
1947 | } |
||
1948 | /* TCP timestamp option with valid length */ |
||
1949 | tsval = tcp_get_next_optbyte(); |
||
1950 | tsval |= (tcp_get_next_optbyte() << 8); |
||
1951 | tsval |= (tcp_get_next_optbyte() << 16); |
||
1952 | tsval |= (tcp_get_next_optbyte() << 24); |
||
1953 | if (flags & TCP_SYN) { |
||
1954 | pcb->ts_recent = lwip_ntohl(tsval); |
||
1955 | /* Enable sending timestamps in every segment now that we know |
||
1956 | the remote host supports it. */ |
||
1957 | tcp_set_flags(pcb, TF_TIMESTAMP); |
||
1958 | } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno + tcplen)) { |
||
1959 | pcb->ts_recent = lwip_ntohl(tsval); |
||
1960 | } |
||
1961 | /* Advance to next option (6 bytes already read) */ |
||
1962 | tcp_optidx += LWIP_TCP_OPT_LEN_TS - 6; |
||
1963 | break; |
||
1964 | #endif /* LWIP_TCP_TIMESTAMPS */ |
||
1965 | #if LWIP_TCP_SACK_OUT |
||
1966 | case LWIP_TCP_OPT_SACK_PERM: |
||
1967 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: SACK_PERM\n")); |
||
1968 | if (tcp_get_next_optbyte() != LWIP_TCP_OPT_LEN_SACK_PERM || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_SACK_PERM) > tcphdr_optlen) { |
||
1969 | /* Bad length */ |
||
1970 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); |
||
1971 | return; |
||
1972 | } |
||
1973 | /* TCP SACK_PERM option with valid length */ |
||
1974 | if (flags & TCP_SYN) { |
||
1975 | /* We only set it if we receive it in a SYN (or SYN+ACK) packet */ |
||
1976 | tcp_set_flags(pcb, TF_SACK); |
||
1977 | } |
||
1978 | break; |
||
1979 | #endif /* LWIP_TCP_SACK_OUT */ |
||
1980 | default: |
||
1981 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n")); |
||
1982 | data = tcp_get_next_optbyte(); |
||
1983 | if (data < 2) { |
||
1984 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); |
||
1985 | /* If the length field is zero, the options are malformed |
||
1986 | and we don't process them further. */ |
||
1987 | return; |
||
1988 | } |
||
1989 | /* All other options have a length field, so that we easily |
||
1990 | can skip past them. */ |
||
1991 | tcp_optidx += data - 2; |
||
1992 | } |
||
1993 | } |
||
1994 | } |
||
1995 | } |
||
1996 | |||
1997 | void |
||
1998 | tcp_trigger_input_pcb_close(void) |
||
1999 | { |
||
2000 | recv_flags |= TF_CLOSED; |
||
2001 | } |
||
2002 | |||
2003 | #if LWIP_TCP_SACK_OUT |
||
2004 | /** |
||
2005 | * Called by tcp_receive() to add new SACK entry. |
||
2006 | * |
||
2007 | * The new SACK entry will be placed at the beginning of rcv_sacks[], as the newest one. |
||
2008 | * Existing SACK entries will be "pushed back", to preserve their order. |
||
2009 | * This is the behavior described in RFC 2018, section 4. |
||
2010 | * |
||
2011 | * @param pcb the tcp_pcb for which a segment arrived |
||
2012 | * @param left the left side of the SACK (the first sequence number) |
||
2013 | * @param right the right side of the SACK (the first sequence number past this SACK) |
||
2014 | */ |
||
2015 | static void |
||
2016 | tcp_add_sack(struct tcp_pcb *pcb, u32_t left, u32_t right) |
||
2017 | { |
||
2018 | u8_t i; |
||
2019 | u8_t unused_idx; |
||
2020 | |||
2021 | if ((pcb->flags & TF_SACK) == 0 || !TCP_SEQ_LT(left, right)) { |
||
2022 | return; |
||
2023 | } |
||
2024 | |||
2025 | /* First, let's remove all SACKs that are no longer needed (because they overlap with the newest one), |
||
2026 | while moving all other SACKs forward. |
||
2027 | We run this loop for all entries, until we find the first invalid one. |
||
2028 | There is no point checking after that. */ |
||
2029 | for (i = unused_idx = 0; (i < LWIP_TCP_MAX_SACK_NUM) && LWIP_TCP_SACK_VALID(pcb, i); ++i) { |
||
2030 | /* We only want to use SACK at [i] if it doesn't overlap with left:right range. |
||
2031 | It does not overlap if its right side is before the newly added SACK, |
||
2032 | or if its left side is after the newly added SACK. |
||
2033 | NOTE: The equality should not really happen, but it doesn't hurt. */ |
||
2034 | if (TCP_SEQ_LEQ(pcb->rcv_sacks[i].right, left) || TCP_SEQ_LEQ(right, pcb->rcv_sacks[i].left)) { |
||
2035 | if (unused_idx != i) { |
||
2036 | /* We don't need to copy if it's already in the right spot */ |
||
2037 | pcb->rcv_sacks[unused_idx] = pcb->rcv_sacks[i]; |
||
2038 | } |
||
2039 | ++unused_idx; |
||
2040 | } |
||
2041 | } |
||
2042 | |||
2043 | /* Now 'unused_idx' is the index of the first invalid SACK entry, |
||
2044 | anywhere between 0 (no valid entries) and LWIP_TCP_MAX_SACK_NUM (all entries are valid). |
||
2045 | We want to clear this and all following SACKs. |
||
2046 | However, we will be adding another one in the front (and shifting everything else back). |
||
2047 | So let's just iterate from the back, and set each entry to the one to the left if it's valid, |
||
2048 | or to 0 if it is not. */ |
||
2049 | for (i = LWIP_TCP_MAX_SACK_NUM - 1; i > 0; --i) { |
||
2050 | /* [i] is the index we are setting, and the value should be at index [i-1], |
||
2051 | or 0 if that index is unused (>= unused_idx). */ |
||
2052 | if (i - 1 >= unused_idx) { |
||
2053 | /* [i-1] is unused. Let's clear [i]. */ |
||
2054 | pcb->rcv_sacks[i].left = pcb->rcv_sacks[i].right = 0; |
||
2055 | } else { |
||
2056 | pcb->rcv_sacks[i] = pcb->rcv_sacks[i - 1]; |
||
2057 | } |
||
2058 | } |
||
2059 | |||
2060 | /* And now we can store the newest SACK */ |
||
2061 | pcb->rcv_sacks[0].left = left; |
||
2062 | pcb->rcv_sacks[0].right = right; |
||
2063 | } |
||
2064 | |||
2065 | /** |
||
2066 | * Called to remove a range of SACKs. |
||
2067 | * |
||
2068 | * SACK entries will be removed or adjusted to not acknowledge any sequence |
||
2069 | * numbers that are less than 'seq' passed. It not only invalidates entries, |
||
2070 | * but also moves all entries that are still valid to the beginning. |
||
2071 | * |
||
2072 | * @param pcb the tcp_pcb to modify |
||
2073 | * @param seq the lowest sequence number to keep in SACK entries |
||
2074 | */ |
||
2075 | static void |
||
2076 | tcp_remove_sacks_lt(struct tcp_pcb *pcb, u32_t seq) |
||
2077 | { |
||
2078 | u8_t i; |
||
2079 | u8_t unused_idx; |
||
2080 | |||
2081 | /* We run this loop for all entries, until we find the first invalid one. |
||
2082 | There is no point checking after that. */ |
||
2083 | for (i = unused_idx = 0; (i < LWIP_TCP_MAX_SACK_NUM) && LWIP_TCP_SACK_VALID(pcb, i); ++i) { |
||
2084 | /* We only want to use SACK at index [i] if its right side is > 'seq'. */ |
||
2085 | if (TCP_SEQ_GT(pcb->rcv_sacks[i].right, seq)) { |
||
2086 | if (unused_idx != i) { |
||
2087 | /* We only copy it if it's not in the right spot already. */ |
||
2088 | pcb->rcv_sacks[unused_idx] = pcb->rcv_sacks[i]; |
||
2089 | } |
||
2090 | /* NOTE: It is possible that its left side is < 'seq', in which case we should adjust it. */ |
||
2091 | if (TCP_SEQ_LT(pcb->rcv_sacks[unused_idx].left, seq)) { |
||
2092 | pcb->rcv_sacks[unused_idx].left = seq; |
||
2093 | } |
||
2094 | ++unused_idx; |
||
2095 | } |
||
2096 | } |
||
2097 | |||
2098 | /* We also need to invalidate everything from 'unused_idx' till the end */ |
||
2099 | for (i = unused_idx; i < LWIP_TCP_MAX_SACK_NUM; ++i) { |
||
2100 | pcb->rcv_sacks[i].left = pcb->rcv_sacks[i].right = 0; |
||
2101 | } |
||
2102 | } |
||
2103 | |||
2104 | #if defined(TCP_OOSEQ_BYTES_LIMIT) || defined(TCP_OOSEQ_PBUFS_LIMIT) |
||
2105 | /** |
||
2106 | * Called to remove a range of SACKs. |
||
2107 | * |
||
2108 | * SACK entries will be removed or adjusted to not acknowledge any sequence |
||
2109 | * numbers that are greater than (or equal to) 'seq' passed. It not only invalidates entries, |
||
2110 | * but also moves all entries that are still valid to the beginning. |
||
2111 | * |
||
2112 | * @param pcb the tcp_pcb to modify |
||
2113 | * @param seq the highest sequence number to keep in SACK entries |
||
2114 | */ |
||
2115 | static void |
||
2116 | tcp_remove_sacks_gt(struct tcp_pcb *pcb, u32_t seq) |
||
2117 | { |
||
2118 | u8_t i; |
||
2119 | u8_t unused_idx; |
||
2120 | |||
2121 | /* We run this loop for all entries, until we find the first invalid one. |
||
2122 | There is no point checking after that. */ |
||
2123 | for (i = unused_idx = 0; (i < LWIP_TCP_MAX_SACK_NUM) && LWIP_TCP_SACK_VALID(pcb, i); ++i) { |
||
2124 | /* We only want to use SACK at index [i] if its left side is < 'seq'. */ |
||
2125 | if (TCP_SEQ_LT(pcb->rcv_sacks[i].left, seq)) { |
||
2126 | if (unused_idx != i) { |
||
2127 | /* We only copy it if it's not in the right spot already. */ |
||
2128 | pcb->rcv_sacks[unused_idx] = pcb->rcv_sacks[i]; |
||
2129 | } |
||
2130 | /* NOTE: It is possible that its right side is > 'seq', in which case we should adjust it. */ |
||
2131 | if (TCP_SEQ_GT(pcb->rcv_sacks[unused_idx].right, seq)) { |
||
2132 | pcb->rcv_sacks[unused_idx].right = seq; |
||
2133 | } |
||
2134 | ++unused_idx; |
||
2135 | } |
||
2136 | } |
||
2137 | |||
2138 | /* We also need to invalidate everything from 'unused_idx' till the end */ |
||
2139 | for (i = unused_idx; i < LWIP_TCP_MAX_SACK_NUM; ++i) { |
||
2140 | pcb->rcv_sacks[i].left = pcb->rcv_sacks[i].right = 0; |
||
2141 | } |
||
2142 | } |
||
2143 | #endif /* TCP_OOSEQ_BYTES_LIMIT || TCP_OOSEQ_PBUFS_LIMIT */ |
||
2144 | |||
2145 | #endif /* LWIP_TCP_SACK_OUT */ |
||
2146 | |||
2147 | #endif /* LWIP_TCP */ |