BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /** |
2 | * @file |
||
3 | * Transmission Control Protocol for IP |
||
4 | * See also @ref tcp_raw |
||
5 | * |
||
6 | * @defgroup tcp_raw TCP |
||
7 | * @ingroup callbackstyle_api |
||
8 | * Transmission Control Protocol for IP\n |
||
9 | * @see @ref raw_api and @ref netconn |
||
10 | * |
||
11 | * Common functions for the TCP implementation, such as functinos |
||
12 | * for manipulating the data structures and the TCP timer functions. TCP functions |
||
13 | * related to input and output is found in tcp_in.c and tcp_out.c respectively.\n |
||
14 | */ |
||
15 | |||
16 | /* |
||
17 | * Copyright (c) 2001-2004 Swedish Institute of Computer Science. |
||
18 | * All rights reserved. |
||
19 | * |
||
20 | * Redistribution and use in source and binary forms, with or without modification, |
||
21 | * are permitted provided that the following conditions are met: |
||
22 | * |
||
23 | * 1. Redistributions of source code must retain the above copyright notice, |
||
24 | * this list of conditions and the following disclaimer. |
||
25 | * 2. Redistributions in binary form must reproduce the above copyright notice, |
||
26 | * this list of conditions and the following disclaimer in the documentation |
||
27 | * and/or other materials provided with the distribution. |
||
28 | * 3. The name of the author may not be used to endorse or promote products |
||
29 | * derived from this software without specific prior written permission. |
||
30 | * |
||
31 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
||
32 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
||
33 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||
34 | * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||
35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
||
36 | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
||
37 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||
38 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
||
39 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY |
||
40 | * OF SUCH DAMAGE. |
||
41 | * |
||
42 | * This file is part of the lwIP TCP/IP stack. |
||
43 | * |
||
44 | * Author: Adam Dunkels <adam@sics.se> |
||
45 | * |
||
46 | */ |
||
47 | |||
48 | #include "lwip/opt.h" |
||
49 | |||
50 | #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ |
||
51 | |||
52 | #include "lwip/def.h" |
||
53 | #include "lwip/mem.h" |
||
54 | #include "lwip/memp.h" |
||
55 | #include "lwip/tcp.h" |
||
56 | #include "lwip/priv/tcp_priv.h" |
||
57 | #include "lwip/debug.h" |
||
58 | #include "lwip/stats.h" |
||
59 | #include "lwip/ip6.h" |
||
60 | #include "lwip/ip6_addr.h" |
||
61 | #include "lwip/nd6.h" |
||
62 | |||
63 | #include <string.h> |
||
64 | |||
65 | #ifdef LWIP_HOOK_FILENAME |
||
66 | #include LWIP_HOOK_FILENAME |
||
67 | #endif |
||
68 | |||
69 | #ifndef TCP_LOCAL_PORT_RANGE_START |
||
70 | /* From http://www.iana.org/assignments/port-numbers: |
||
71 | "The Dynamic and/or Private Ports are those from 49152 through 65535" */ |
||
72 | #define TCP_LOCAL_PORT_RANGE_START 0xc000 |
||
73 | #define TCP_LOCAL_PORT_RANGE_END 0xffff |
||
74 | #define TCP_ENSURE_LOCAL_PORT_RANGE(port) ((u16_t)(((port) & (u16_t)~TCP_LOCAL_PORT_RANGE_START) + TCP_LOCAL_PORT_RANGE_START)) |
||
75 | #endif |
||
76 | |||
77 | #if LWIP_TCP_KEEPALIVE |
||
78 | #define TCP_KEEP_DUR(pcb) ((pcb)->keep_cnt * (pcb)->keep_intvl) |
||
79 | #define TCP_KEEP_INTVL(pcb) ((pcb)->keep_intvl) |
||
80 | #else /* LWIP_TCP_KEEPALIVE */ |
||
81 | #define TCP_KEEP_DUR(pcb) TCP_MAXIDLE |
||
82 | #define TCP_KEEP_INTVL(pcb) TCP_KEEPINTVL_DEFAULT |
||
83 | #endif /* LWIP_TCP_KEEPALIVE */ |
||
84 | |||
85 | /* As initial send MSS, we use TCP_MSS but limit it to 536. */ |
||
86 | #if TCP_MSS > 536 |
||
87 | #define INITIAL_MSS 536 |
||
88 | #else |
||
89 | #define INITIAL_MSS TCP_MSS |
||
90 | #endif |
||
91 | |||
92 | static const char *const tcp_state_str[] = { |
||
93 | "CLOSED", |
||
94 | "LISTEN", |
||
95 | "SYN_SENT", |
||
96 | "SYN_RCVD", |
||
97 | "ESTABLISHED", |
||
98 | "FIN_WAIT_1", |
||
99 | "FIN_WAIT_2", |
||
100 | "CLOSE_WAIT", |
||
101 | "CLOSING", |
||
102 | "LAST_ACK", |
||
103 | "TIME_WAIT" |
||
104 | }; |
||
105 | |||
106 | /* last local TCP port */ |
||
107 | static u16_t tcp_port = TCP_LOCAL_PORT_RANGE_START; |
||
108 | |||
109 | /* Incremented every coarse grained timer shot (typically every 500 ms). */ |
||
110 | u32_t tcp_ticks; |
||
111 | static const u8_t tcp_backoff[13] = |
||
112 | { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; |
||
113 | /* Times per slowtmr hits */ |
||
114 | static const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 }; |
||
115 | |||
116 | /* The TCP PCB lists. */ |
||
117 | |||
118 | /** List of all TCP PCBs bound but not yet (connected || listening) */ |
||
119 | struct tcp_pcb *tcp_bound_pcbs; |
||
120 | /** List of all TCP PCBs in LISTEN state */ |
||
121 | union tcp_listen_pcbs_t tcp_listen_pcbs; |
||
122 | /** List of all TCP PCBs that are in a state in which |
||
123 | * they accept or send data. */ |
||
124 | struct tcp_pcb *tcp_active_pcbs; |
||
125 | /** List of all TCP PCBs in TIME-WAIT state */ |
||
126 | struct tcp_pcb *tcp_tw_pcbs; |
||
127 | |||
128 | /** An array with all (non-temporary) PCB lists, mainly used for smaller code size */ |
||
129 | struct tcp_pcb **const tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs, |
||
130 | &tcp_active_pcbs, &tcp_tw_pcbs |
||
131 | }; |
||
132 | |||
133 | u8_t tcp_active_pcbs_changed; |
||
134 | |||
135 | /** Timer counter to handle calling slow-timer from tcp_tmr() */ |
||
136 | static u8_t tcp_timer; |
||
137 | static u8_t tcp_timer_ctr; |
||
138 | static u16_t tcp_new_port(void); |
||
139 | |||
140 | static err_t tcp_close_shutdown_fin(struct tcp_pcb *pcb); |
||
141 | |||
142 | /** |
||
143 | * Initialize this module. |
||
144 | */ |
||
145 | void |
||
146 | tcp_init(void) |
||
147 | { |
||
148 | #ifdef LWIP_RAND |
||
149 | tcp_port = TCP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); |
||
150 | #endif /* LWIP_RAND */ |
||
151 | } |
||
152 | |||
153 | /** |
||
154 | * Called periodically to dispatch TCP timers. |
||
155 | */ |
||
156 | void |
||
157 | tcp_tmr(void) |
||
158 | { |
||
159 | /* Call tcp_fasttmr() every 250 ms */ |
||
160 | tcp_fasttmr(); |
||
161 | |||
162 | if (++tcp_timer & 1) { |
||
163 | /* Call tcp_slowtmr() every 500 ms, i.e., every other timer |
||
164 | tcp_tmr() is called. */ |
||
165 | tcp_slowtmr(); |
||
166 | } |
||
167 | } |
||
168 | |||
169 | #if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG |
||
170 | /** Called when a listen pcb is closed. Iterates one pcb list and removes the |
||
171 | * closed listener pcb from pcb->listener if matching. |
||
172 | */ |
||
173 | static void |
||
174 | tcp_remove_listener(struct tcp_pcb *list, struct tcp_pcb_listen *lpcb) |
||
175 | { |
||
176 | struct tcp_pcb *pcb; |
||
177 | for (pcb = list; pcb != NULL; pcb = pcb->next) { |
||
178 | if (pcb->listener == lpcb) { |
||
179 | pcb->listener = NULL; |
||
180 | } |
||
181 | } |
||
182 | } |
||
183 | #endif |
||
184 | |||
185 | /** Called when a listen pcb is closed. Iterates all pcb lists and removes the |
||
186 | * closed listener pcb from pcb->listener if matching. |
||
187 | */ |
||
188 | static void |
||
189 | tcp_listen_closed(struct tcp_pcb *pcb) |
||
190 | { |
||
191 | #if LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG |
||
192 | size_t i; |
||
193 | LWIP_ASSERT("pcb != NULL", pcb != NULL); |
||
194 | LWIP_ASSERT("pcb->state == LISTEN", pcb->state == LISTEN); |
||
195 | for (i = 1; i < LWIP_ARRAYSIZE(tcp_pcb_lists); i++) { |
||
196 | tcp_remove_listener(*tcp_pcb_lists[i], (struct tcp_pcb_listen *)pcb); |
||
197 | } |
||
198 | #endif |
||
199 | LWIP_UNUSED_ARG(pcb); |
||
200 | } |
||
201 | |||
202 | #if TCP_LISTEN_BACKLOG |
||
203 | /** @ingroup tcp_raw |
||
204 | * Delay accepting a connection in respect to the listen backlog: |
||
205 | * the number of outstanding connections is increased until |
||
206 | * tcp_backlog_accepted() is called. |
||
207 | * |
||
208 | * ATTENTION: the caller is responsible for calling tcp_backlog_accepted() |
||
209 | * or else the backlog feature will get out of sync! |
||
210 | * |
||
211 | * @param pcb the connection pcb which is not fully accepted yet |
||
212 | */ |
||
213 | void |
||
214 | tcp_backlog_delayed(struct tcp_pcb *pcb) |
||
215 | { |
||
216 | LWIP_ASSERT("pcb != NULL", pcb != NULL); |
||
217 | if ((pcb->flags & TF_BACKLOGPEND) == 0) { |
||
218 | if (pcb->listener != NULL) { |
||
219 | pcb->listener->accepts_pending++; |
||
220 | LWIP_ASSERT("accepts_pending != 0", pcb->listener->accepts_pending != 0); |
||
221 | tcp_set_flags(pcb, TF_BACKLOGPEND); |
||
222 | } |
||
223 | } |
||
224 | } |
||
225 | |||
226 | /** @ingroup tcp_raw |
||
227 | * A delayed-accept a connection is accepted (or closed/aborted): decreases |
||
228 | * the number of outstanding connections after calling tcp_backlog_delayed(). |
||
229 | * |
||
230 | * ATTENTION: the caller is responsible for calling tcp_backlog_accepted() |
||
231 | * or else the backlog feature will get out of sync! |
||
232 | * |
||
233 | * @param pcb the connection pcb which is now fully accepted (or closed/aborted) |
||
234 | */ |
||
235 | void |
||
236 | tcp_backlog_accepted(struct tcp_pcb *pcb) |
||
237 | { |
||
238 | LWIP_ASSERT("pcb != NULL", pcb != NULL); |
||
239 | if ((pcb->flags & TF_BACKLOGPEND) != 0) { |
||
240 | if (pcb->listener != NULL) { |
||
241 | LWIP_ASSERT("accepts_pending != 0", pcb->listener->accepts_pending != 0); |
||
242 | pcb->listener->accepts_pending--; |
||
243 | tcp_clear_flags(pcb, TF_BACKLOGPEND); |
||
244 | } |
||
245 | } |
||
246 | } |
||
247 | #endif /* TCP_LISTEN_BACKLOG */ |
||
248 | |||
249 | /** |
||
250 | * Closes the TX side of a connection held by the PCB. |
||
251 | * For tcp_close(), a RST is sent if the application didn't receive all data |
||
252 | * (tcp_recved() not called for all data passed to recv callback). |
||
253 | * |
||
254 | * Listening pcbs are freed and may not be referenced any more. |
||
255 | * Connection pcbs are freed if not yet connected and may not be referenced |
||
256 | * any more. If a connection is established (at least SYN received or in |
||
257 | * a closing state), the connection is closed, and put in a closing state. |
||
258 | * The pcb is then automatically freed in tcp_slowtmr(). It is therefore |
||
259 | * unsafe to reference it. |
||
260 | * |
||
261 | * @param pcb the tcp_pcb to close |
||
262 | * @return ERR_OK if connection has been closed |
||
263 | * another err_t if closing failed and pcb is not freed |
||
264 | */ |
||
265 | static err_t |
||
266 | tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) |
||
267 | { |
||
268 | if (rst_on_unacked_data && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) { |
||
269 | if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND_MAX(pcb))) { |
||
270 | /* Not all data received by application, send RST to tell the remote |
||
271 | side about this. */ |
||
272 | LWIP_ASSERT("pcb->flags & TF_RXCLOSED", pcb->flags & TF_RXCLOSED); |
||
273 | |||
274 | /* don't call tcp_abort here: we must not deallocate the pcb since |
||
275 | that might not be expected when calling tcp_close */ |
||
276 | tcp_rst(pcb, pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, |
||
277 | pcb->local_port, pcb->remote_port); |
||
278 | |||
279 | tcp_pcb_purge(pcb); |
||
280 | TCP_RMV_ACTIVE(pcb); |
||
281 | if (pcb->state == ESTABLISHED) { |
||
282 | /* move to TIME_WAIT since we close actively */ |
||
283 | pcb->state = TIME_WAIT; |
||
284 | TCP_REG(&tcp_tw_pcbs, pcb); |
||
285 | } else { |
||
286 | /* CLOSE_WAIT: deallocate the pcb since we already sent a RST for it */ |
||
287 | if (tcp_input_pcb == pcb) { |
||
288 | /* prevent using a deallocated pcb: free it from tcp_input later */ |
||
289 | tcp_trigger_input_pcb_close(); |
||
290 | } else { |
||
291 | memp_free(MEMP_TCP_PCB, pcb); |
||
292 | } |
||
293 | } |
||
294 | return ERR_OK; |
||
295 | } |
||
296 | } |
||
297 | |||
298 | /* - states which free the pcb are handled here, |
||
299 | - states which send FIN and change state are handled in tcp_close_shutdown_fin() */ |
||
300 | switch (pcb->state) { |
||
301 | case CLOSED: |
||
302 | /* Closing a pcb in the CLOSED state might seem erroneous, |
||
303 | * however, it is in this state once allocated and as yet unused |
||
304 | * and the user needs some way to free it should the need arise. |
||
305 | * Calling tcp_close() with a pcb that has already been closed, (i.e. twice) |
||
306 | * or for a pcb that has been used and then entered the CLOSED state |
||
307 | * is erroneous, but this should never happen as the pcb has in those cases |
||
308 | * been freed, and so any remaining handles are bogus. */ |
||
309 | if (pcb->local_port != 0 || pcb->bound_to_netif) { |
||
310 | TCP_RMV(&tcp_bound_pcbs, pcb); |
||
311 | } |
||
312 | memp_free(MEMP_TCP_PCB, pcb); |
||
313 | break; |
||
314 | case LISTEN: |
||
315 | tcp_listen_closed(pcb); |
||
316 | tcp_pcb_remove(&tcp_listen_pcbs.pcbs, pcb); |
||
317 | memp_free(MEMP_TCP_PCB_LISTEN, pcb); |
||
318 | break; |
||
319 | case SYN_SENT: |
||
320 | TCP_PCB_REMOVE_ACTIVE(pcb); |
||
321 | memp_free(MEMP_TCP_PCB, pcb); |
||
322 | MIB2_STATS_INC(mib2.tcpattemptfails); |
||
323 | break; |
||
324 | default: |
||
325 | return tcp_close_shutdown_fin(pcb); |
||
326 | } |
||
327 | return ERR_OK; |
||
328 | } |
||
329 | |||
330 | static err_t |
||
331 | tcp_close_shutdown_fin(struct tcp_pcb *pcb) |
||
332 | { |
||
333 | err_t err; |
||
334 | LWIP_ASSERT("pcb != NULL", pcb != NULL); |
||
335 | |||
336 | switch (pcb->state) { |
||
337 | case SYN_RCVD: |
||
338 | err = tcp_send_fin(pcb); |
||
339 | if (err == ERR_OK) { |
||
340 | tcp_backlog_accepted(pcb); |
||
341 | MIB2_STATS_INC(mib2.tcpattemptfails); |
||
342 | pcb->state = FIN_WAIT_1; |
||
343 | } |
||
344 | break; |
||
345 | case ESTABLISHED: |
||
346 | err = tcp_send_fin(pcb); |
||
347 | if (err == ERR_OK) { |
||
348 | MIB2_STATS_INC(mib2.tcpestabresets); |
||
349 | pcb->state = FIN_WAIT_1; |
||
350 | } |
||
351 | break; |
||
352 | case CLOSE_WAIT: |
||
353 | err = tcp_send_fin(pcb); |
||
354 | if (err == ERR_OK) { |
||
355 | MIB2_STATS_INC(mib2.tcpestabresets); |
||
356 | pcb->state = LAST_ACK; |
||
357 | } |
||
358 | break; |
||
359 | default: |
||
360 | /* Has already been closed, do nothing. */ |
||
361 | return ERR_OK; |
||
362 | } |
||
363 | |||
364 | if (err == ERR_OK) { |
||
365 | /* To ensure all data has been sent when tcp_close returns, we have |
||
366 | to make sure tcp_output doesn't fail. |
||
367 | Since we don't really have to ensure all data has been sent when tcp_close |
||
368 | returns (unsent data is sent from tcp timer functions, also), we don't care |
||
369 | for the return value of tcp_output for now. */ |
||
370 | tcp_output(pcb); |
||
371 | } else if (err == ERR_MEM) { |
||
372 | /* Mark this pcb for closing. Closing is retried from tcp_tmr. */ |
||
373 | tcp_set_flags(pcb, TF_CLOSEPEND); |
||
374 | /* We have to return ERR_OK from here to indicate to the callers that this |
||
375 | pcb should not be used any more as it will be freed soon via tcp_tmr. |
||
376 | This is OK here since sending FIN does not guarantee a time frime for |
||
377 | actually freeing the pcb, either (it is left in closure states for |
||
378 | remote ACK or timeout) */ |
||
379 | return ERR_OK; |
||
380 | } |
||
381 | return err; |
||
382 | } |
||
383 | |||
384 | /** |
||
385 | * @ingroup tcp_raw |
||
386 | * Closes the connection held by the PCB. |
||
387 | * |
||
388 | * Listening pcbs are freed and may not be referenced any more. |
||
389 | * Connection pcbs are freed if not yet connected and may not be referenced |
||
390 | * any more. If a connection is established (at least SYN received or in |
||
391 | * a closing state), the connection is closed, and put in a closing state. |
||
392 | * The pcb is then automatically freed in tcp_slowtmr(). It is therefore |
||
393 | * unsafe to reference it (unless an error is returned). |
||
394 | * |
||
395 | * @param pcb the tcp_pcb to close |
||
396 | * @return ERR_OK if connection has been closed |
||
397 | * another err_t if closing failed and pcb is not freed |
||
398 | */ |
||
399 | err_t |
||
400 | tcp_close(struct tcp_pcb *pcb) |
||
401 | { |
||
402 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in ")); |
||
403 | tcp_debug_print_state(pcb->state); |
||
404 | |||
405 | if (pcb->state != LISTEN) { |
||
406 | /* Set a flag not to receive any more data... */ |
||
407 | tcp_set_flags(pcb, TF_RXCLOSED); |
||
408 | } |
||
409 | /* ... and close */ |
||
410 | return tcp_close_shutdown(pcb, 1); |
||
411 | } |
||
412 | |||
413 | /** |
||
414 | * @ingroup tcp_raw |
||
415 | * Causes all or part of a full-duplex connection of this PCB to be shut down. |
||
416 | * This doesn't deallocate the PCB unless shutting down both sides! |
||
417 | * Shutting down both sides is the same as calling tcp_close, so if it succeds |
||
418 | * (i.e. returns ER_OK), the PCB must not be referenced any more! |
||
419 | * |
||
420 | * @param pcb PCB to shutdown |
||
421 | * @param shut_rx shut down receive side if this is != 0 |
||
422 | * @param shut_tx shut down send side if this is != 0 |
||
423 | * @return ERR_OK if shutdown succeeded (or the PCB has already been shut down) |
||
424 | * another err_t on error. |
||
425 | */ |
||
426 | err_t |
||
427 | tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx) |
||
428 | { |
||
429 | if (pcb->state == LISTEN) { |
||
430 | return ERR_CONN; |
||
431 | } |
||
432 | if (shut_rx) { |
||
433 | /* shut down the receive side: set a flag not to receive any more data... */ |
||
434 | tcp_set_flags(pcb, TF_RXCLOSED); |
||
435 | if (shut_tx) { |
||
436 | /* shutting down the tx AND rx side is the same as closing for the raw API */ |
||
437 | return tcp_close_shutdown(pcb, 1); |
||
438 | } |
||
439 | /* ... and free buffered data */ |
||
440 | if (pcb->refused_data != NULL) { |
||
441 | pbuf_free(pcb->refused_data); |
||
442 | pcb->refused_data = NULL; |
||
443 | } |
||
444 | } |
||
445 | if (shut_tx) { |
||
446 | /* This can't happen twice since if it succeeds, the pcb's state is changed. |
||
447 | Only close in these states as the others directly deallocate the PCB */ |
||
448 | switch (pcb->state) { |
||
449 | case SYN_RCVD: |
||
450 | case ESTABLISHED: |
||
451 | case CLOSE_WAIT: |
||
452 | return tcp_close_shutdown(pcb, (u8_t)shut_rx); |
||
453 | default: |
||
454 | /* Not (yet?) connected, cannot shutdown the TX side as that would bring us |
||
455 | into CLOSED state, where the PCB is deallocated. */ |
||
456 | return ERR_CONN; |
||
457 | } |
||
458 | } |
||
459 | return ERR_OK; |
||
460 | } |
||
461 | |||
462 | /** |
||
463 | * Abandons a connection and optionally sends a RST to the remote |
||
464 | * host. Deletes the local protocol control block. This is done when |
||
465 | * a connection is killed because of shortage of memory. |
||
466 | * |
||
467 | * @param pcb the tcp_pcb to abort |
||
468 | * @param reset boolean to indicate whether a reset should be sent |
||
469 | */ |
||
470 | void |
||
471 | tcp_abandon(struct tcp_pcb *pcb, int reset) |
||
472 | { |
||
473 | u32_t seqno, ackno; |
||
474 | #if LWIP_CALLBACK_API |
||
475 | tcp_err_fn errf; |
||
476 | #endif /* LWIP_CALLBACK_API */ |
||
477 | void *errf_arg; |
||
478 | |||
479 | /* pcb->state LISTEN not allowed here */ |
||
480 | LWIP_ASSERT("don't call tcp_abort/tcp_abandon for listen-pcbs", |
||
481 | pcb->state != LISTEN); |
||
482 | /* Figure out on which TCP PCB list we are, and remove us. If we |
||
483 | are in an active state, call the receive function associated with |
||
484 | the PCB with a NULL argument, and send an RST to the remote end. */ |
||
485 | if (pcb->state == TIME_WAIT) { |
||
486 | tcp_pcb_remove(&tcp_tw_pcbs, pcb); |
||
487 | memp_free(MEMP_TCP_PCB, pcb); |
||
488 | } else { |
||
489 | int send_rst = 0; |
||
490 | u16_t local_port = 0; |
||
491 | enum tcp_state last_state; |
||
492 | seqno = pcb->snd_nxt; |
||
493 | ackno = pcb->rcv_nxt; |
||
494 | #if LWIP_CALLBACK_API |
||
495 | errf = pcb->errf; |
||
496 | #endif /* LWIP_CALLBACK_API */ |
||
497 | errf_arg = pcb->callback_arg; |
||
498 | if (pcb->state == CLOSED) { |
||
499 | if (pcb->local_port != 0) { |
||
500 | /* bound, not yet opened */ |
||
501 | TCP_RMV(&tcp_bound_pcbs, pcb); |
||
502 | } |
||
503 | } else { |
||
504 | send_rst = reset; |
||
505 | local_port = pcb->local_port; |
||
506 | TCP_PCB_REMOVE_ACTIVE(pcb); |
||
507 | } |
||
508 | if (pcb->unacked != NULL) { |
||
509 | tcp_segs_free(pcb->unacked); |
||
510 | } |
||
511 | if (pcb->unsent != NULL) { |
||
512 | tcp_segs_free(pcb->unsent); |
||
513 | } |
||
514 | #if TCP_QUEUE_OOSEQ |
||
515 | if (pcb->ooseq != NULL) { |
||
516 | tcp_segs_free(pcb->ooseq); |
||
517 | } |
||
518 | #endif /* TCP_QUEUE_OOSEQ */ |
||
519 | tcp_backlog_accepted(pcb); |
||
520 | if (send_rst) { |
||
521 | LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n")); |
||
522 | tcp_rst(pcb, seqno, ackno, &pcb->local_ip, &pcb->remote_ip, local_port, pcb->remote_port); |
||
523 | } |
||
524 | last_state = pcb->state; |
||
525 | memp_free(MEMP_TCP_PCB, pcb); |
||
526 | TCP_EVENT_ERR(last_state, errf, errf_arg, ERR_ABRT); |
||
527 | } |
||
528 | } |
||
529 | |||
530 | /** |
||
531 | * @ingroup tcp_raw |
||
532 | * Aborts the connection by sending a RST (reset) segment to the remote |
||
533 | * host. The pcb is deallocated. This function never fails. |
||
534 | * |
||
535 | * ATTENTION: When calling this from one of the TCP callbacks, make |
||
536 | * sure you always return ERR_ABRT (and never return ERR_ABRT otherwise |
||
537 | * or you will risk accessing deallocated memory or memory leaks! |
||
538 | * |
||
539 | * @param pcb the tcp pcb to abort |
||
540 | */ |
||
541 | void |
||
542 | tcp_abort(struct tcp_pcb *pcb) |
||
543 | { |
||
544 | tcp_abandon(pcb, 1); |
||
545 | } |
||
546 | |||
547 | /** |
||
548 | * @ingroup tcp_raw |
||
549 | * Binds the connection to a local port number and IP address. If the |
||
550 | * IP address is not given (i.e., ipaddr == NULL), the IP address of |
||
551 | * the outgoing network interface is used instead. |
||
552 | * |
||
553 | * @param pcb the tcp_pcb to bind (no check is done whether this pcb is |
||
554 | * already bound!) |
||
555 | * @param ipaddr the local ip address to bind to (use IPx_ADDR_ANY to bind |
||
556 | * to any local address |
||
557 | * @param port the local port to bind to |
||
558 | * @return ERR_USE if the port is already in use |
||
559 | * ERR_VAL if bind failed because the PCB is not in a valid state |
||
560 | * ERR_OK if bound |
||
561 | */ |
||
562 | err_t |
||
563 | tcp_bind(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) |
||
564 | { |
||
565 | int i; |
||
566 | int max_pcb_list = NUM_TCP_PCB_LISTS; |
||
567 | struct tcp_pcb *cpcb; |
||
568 | #if LWIP_IPV6 && LWIP_IPV6_SCOPES |
||
569 | ip_addr_t zoned_ipaddr; |
||
570 | #endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ |
||
571 | |||
572 | #if LWIP_IPV4 |
||
573 | /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ |
||
574 | if (ipaddr == NULL) { |
||
575 | ipaddr = IP4_ADDR_ANY; |
||
576 | } |
||
577 | #endif /* LWIP_IPV4 */ |
||
578 | |||
579 | /* still need to check for ipaddr == NULL in IPv6 only case */ |
||
580 | if ((pcb == NULL) || (ipaddr == NULL)) { |
||
581 | return ERR_VAL; |
||
582 | } |
||
583 | |||
584 | LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_VAL); |
||
585 | |||
586 | #if SO_REUSE |
||
587 | /* Unless the REUSEADDR flag is set, |
||
588 | we have to check the pcbs in TIME-WAIT state, also. |
||
589 | We do not dump TIME_WAIT pcb's; they can still be matched by incoming |
||
590 | packets using both local and remote IP addresses and ports to distinguish. |
||
591 | */ |
||
592 | if (ip_get_option(pcb, SOF_REUSEADDR)) { |
||
593 | max_pcb_list = NUM_TCP_PCB_LISTS_NO_TIME_WAIT; |
||
594 | } |
||
595 | #endif /* SO_REUSE */ |
||
596 | |||
597 | #if LWIP_IPV6 && LWIP_IPV6_SCOPES |
||
598 | /* If the given IP address should have a zone but doesn't, assign one now. |
||
599 | * This is legacy support: scope-aware callers should always provide properly |
||
600 | * zoned source addresses. Do the zone selection before the address-in-use |
||
601 | * check below; as such we have to make a temporary copy of the address. */ |
||
602 | if (IP_IS_V6(ipaddr) && ip6_addr_lacks_zone(ip_2_ip6(ipaddr), IP6_UNICAST)) { |
||
603 | ip_addr_copy(zoned_ipaddr, *ipaddr); |
||
604 | ip6_addr_select_zone(ip_2_ip6(&zoned_ipaddr), ip_2_ip6(&zoned_ipaddr)); |
||
605 | ipaddr = &zoned_ipaddr; |
||
606 | } |
||
607 | #endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ |
||
608 | |||
609 | if (port == 0) { |
||
610 | port = tcp_new_port(); |
||
611 | if (port == 0) { |
||
612 | return ERR_BUF; |
||
613 | } |
||
614 | } else { |
||
615 | /* Check if the address already is in use (on all lists) */ |
||
616 | for (i = 0; i < max_pcb_list; i++) { |
||
617 | for (cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { |
||
618 | if (cpcb->local_port == port) { |
||
619 | #if SO_REUSE |
||
620 | /* Omit checking for the same port if both pcbs have REUSEADDR set. |
||
621 | For SO_REUSEADDR, the duplicate-check for a 5-tuple is done in |
||
622 | tcp_connect. */ |
||
623 | if (!ip_get_option(pcb, SOF_REUSEADDR) || |
||
624 | !ip_get_option(cpcb, SOF_REUSEADDR)) |
||
625 | #endif /* SO_REUSE */ |
||
626 | { |
||
627 | /* @todo: check accept_any_ip_version */ |
||
628 | if ((IP_IS_V6(ipaddr) == IP_IS_V6_VAL(cpcb->local_ip)) && |
||
629 | (ip_addr_isany(&cpcb->local_ip) || |
||
630 | ip_addr_isany(ipaddr) || |
||
631 | ip_addr_cmp(&cpcb->local_ip, ipaddr))) { |
||
632 | return ERR_USE; |
||
633 | } |
||
634 | } |
||
635 | } |
||
636 | } |
||
637 | } |
||
638 | } |
||
639 | |||
640 | pcb->bound_to_netif = 0; |
||
641 | if (!ip_addr_isany(ipaddr)) { |
||
642 | ip_addr_set(&pcb->local_ip, ipaddr); |
||
643 | } |
||
644 | pcb->local_port = port; |
||
645 | TCP_REG(&tcp_bound_pcbs, pcb); |
||
646 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port)); |
||
647 | return ERR_OK; |
||
648 | } |
||
649 | |||
650 | err_t |
||
651 | tcp_bind_to_netif(struct tcp_pcb *pcb, const char ifname[3]) |
||
652 | { |
||
653 | int i; |
||
654 | struct tcp_pcb *cpcb; |
||
655 | |||
656 | LWIP_ERROR("tcp_bind_to_netif: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_VAL); |
||
657 | |||
658 | /* Check if the interface is already in use (in tcp_listen_pcbs and tcp_bound_pcbs) */ |
||
659 | for (i = 0; i < 2; i++) { |
||
660 | for (cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { |
||
661 | if (cpcb->bound_to_netif && |
||
662 | !memcmp(cpcb->local_netif, ifname, sizeof(cpcb->local_netif)) && ( |
||
663 | IP_IS_ANY_TYPE_VAL(pcb->local_ip) || IP_IS_ANY_TYPE_VAL(cpcb->local_ip) || |
||
664 | IP_GET_TYPE(&pcb->local_ip) == IP_GET_TYPE(&cpcb->local_ip))) { |
||
665 | return ERR_USE; |
||
666 | } |
||
667 | } |
||
668 | } |
||
669 | |||
670 | pcb->bound_to_netif = 1; |
||
671 | if (!IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { |
||
672 | ip_addr_set_any(IP_IS_V6(&pcb->local_ip), &pcb->local_ip); |
||
673 | } |
||
674 | pcb->local_port = 0; |
||
675 | memcpy(pcb->local_netif, ifname, sizeof(pcb->local_netif)); |
||
676 | TCP_REG(&tcp_bound_pcbs, pcb); |
||
677 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind_to_netif: bind to interface %c%c%c\n", ifname[0], ifname[1], ifname[2])); |
||
678 | // should call tcp_bind_netif() to set pcb->netif_idx |
||
679 | return ERR_OK; |
||
680 | } |
||
681 | |||
682 | /** |
||
683 | * @ingroup tcp_raw |
||
684 | * Binds the connection to a netif and IP address. |
||
685 | * After calling this function, all packets received via this PCB |
||
686 | * are guaranteed to have come in via the specified netif, and all |
||
687 | * outgoing packets will go out via the specified netif. |
||
688 | * |
||
689 | * @param pcb the tcp_pcb to bind. |
||
690 | * @param netif the netif to bind to. Can be NULL. |
||
691 | */ |
||
692 | void |
||
693 | tcp_bind_netif(struct tcp_pcb *pcb, const struct netif *netif) |
||
694 | { |
||
695 | if (netif != NULL) { |
||
696 | pcb->netif_idx = netif_get_index(netif); |
||
697 | } else { |
||
698 | pcb->netif_idx = NETIF_NO_INDEX; |
||
699 | } |
||
700 | } |
||
701 | |||
702 | #if LWIP_CALLBACK_API |
||
703 | /** |
||
704 | * Default accept callback if no accept callback is specified by the user. |
||
705 | */ |
||
706 | static err_t |
||
707 | tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err) |
||
708 | { |
||
709 | LWIP_UNUSED_ARG(arg); |
||
710 | LWIP_UNUSED_ARG(err); |
||
711 | |||
712 | tcp_abort(pcb); |
||
713 | |||
714 | return ERR_ABRT; |
||
715 | } |
||
716 | #endif /* LWIP_CALLBACK_API */ |
||
717 | |||
718 | /** |
||
719 | * @ingroup tcp_raw |
||
720 | * Set the state of the connection to be LISTEN, which means that it |
||
721 | * is able to accept incoming connections. The protocol control block |
||
722 | * is reallocated in order to consume less memory. Setting the |
||
723 | * connection to LISTEN is an irreversible process. |
||
724 | * |
||
725 | * @param pcb the original tcp_pcb |
||
726 | * @param backlog the incoming connections queue limit |
||
727 | * @return tcp_pcb used for listening, consumes less memory. |
||
728 | * |
||
729 | * @note The original tcp_pcb is freed. This function therefore has to be |
||
730 | * called like this: |
||
731 | * tpcb = tcp_listen_with_backlog(tpcb, backlog); |
||
732 | */ |
||
733 | struct tcp_pcb * |
||
734 | tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) |
||
735 | { |
||
736 | return tcp_listen_with_backlog_and_err(pcb, backlog, NULL); |
||
737 | } |
||
738 | |||
739 | /** |
||
740 | * @ingroup tcp_raw |
||
741 | * Set the state of the connection to be LISTEN, which means that it |
||
742 | * is able to accept incoming connections. The protocol control block |
||
743 | * is reallocated in order to consume less memory. Setting the |
||
744 | * connection to LISTEN is an irreversible process. |
||
745 | * |
||
746 | * @param pcb the original tcp_pcb |
||
747 | * @param backlog the incoming connections queue limit |
||
748 | * @param err when NULL is returned, this contains the error reason |
||
749 | * @return tcp_pcb used for listening, consumes less memory. |
||
750 | * |
||
751 | * @note The original tcp_pcb is freed. This function therefore has to be |
||
752 | * called like this: |
||
753 | * tpcb = tcp_listen_with_backlog_and_err(tpcb, backlog, &err); |
||
754 | */ |
||
755 | struct tcp_pcb * |
||
756 | tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) |
||
757 | { |
||
758 | struct tcp_pcb_listen *lpcb = NULL; |
||
759 | err_t res; |
||
760 | |||
761 | LWIP_UNUSED_ARG(backlog); |
||
762 | LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, res = ERR_CLSD; goto done); |
||
763 | |||
764 | /* already listening? */ |
||
765 | if (pcb->state == LISTEN) { |
||
766 | lpcb = (struct tcp_pcb_listen *)pcb; |
||
767 | res = ERR_ALREADY; |
||
768 | goto done; |
||
769 | } |
||
770 | #if SO_REUSE |
||
771 | if (ip_get_option(pcb, SOF_REUSEADDR) && !pcb->have_local_netif) { |
||
772 | /* Since SOF_REUSEADDR allows reusing a local address before the pcb's usage |
||
773 | is declared (listen-/connection-pcb), we have to make sure now that |
||
774 | this port is only used once for every local IP. */ |
||
775 | for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { |
||
776 | if ((lpcb->local_port == pcb->local_port) && |
||
777 | ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) { |
||
778 | /* this address/port is already used */ |
||
779 | lpcb = NULL; |
||
780 | res = ERR_USE; |
||
781 | goto done; |
||
782 | } |
||
783 | } |
||
784 | } |
||
785 | #endif /* SO_REUSE */ |
||
786 | lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN); |
||
787 | if (lpcb == NULL) { |
||
788 | res = ERR_MEM; |
||
789 | goto done; |
||
790 | } |
||
791 | lpcb->callback_arg = pcb->callback_arg; |
||
792 | lpcb->bound_to_netif = pcb->bound_to_netif; |
||
793 | lpcb->local_port = pcb->local_port; |
||
794 | memcpy(lpcb->local_netif, pcb->local_netif, sizeof(pcb->local_netif)); |
||
795 | lpcb->state = LISTEN; |
||
796 | lpcb->prio = pcb->prio; |
||
797 | lpcb->so_options = pcb->so_options; |
||
798 | lpcb->netif_idx = NETIF_NO_INDEX; |
||
799 | lpcb->ttl = pcb->ttl; |
||
800 | lpcb->tos = pcb->tos; |
||
801 | #if LWIP_IPV4 && LWIP_IPV6 |
||
802 | IP_SET_TYPE_VAL(lpcb->remote_ip, pcb->local_ip.type); |
||
803 | #endif /* LWIP_IPV4 && LWIP_IPV6 */ |
||
804 | ip_addr_copy(lpcb->local_ip, pcb->local_ip); |
||
805 | if (pcb->local_port != 0 || pcb->bound_to_netif) { |
||
806 | TCP_RMV(&tcp_bound_pcbs, pcb); |
||
807 | } |
||
808 | memp_free(MEMP_TCP_PCB, pcb); |
||
809 | #if LWIP_CALLBACK_API |
||
810 | lpcb->accept = tcp_accept_null; |
||
811 | #endif /* LWIP_CALLBACK_API */ |
||
812 | #if TCP_LISTEN_BACKLOG |
||
813 | lpcb->accepts_pending = 0; |
||
814 | tcp_backlog_set(lpcb, backlog); |
||
815 | #endif /* TCP_LISTEN_BACKLOG */ |
||
816 | TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb); |
||
817 | res = ERR_OK; |
||
818 | done: |
||
819 | if (err != NULL) { |
||
820 | *err = res; |
||
821 | } |
||
822 | return (struct tcp_pcb *)lpcb; |
||
823 | } |
||
824 | |||
825 | /** |
||
826 | * Update the state that tracks the available window space to advertise. |
||
827 | * |
||
828 | * Returns how much extra window would be advertised if we sent an |
||
829 | * update now. |
||
830 | */ |
||
831 | u32_t |
||
832 | tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb) |
||
833 | { |
||
834 | u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd; |
||
835 | |||
836 | if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + LWIP_MIN((TCP_WND / 2), pcb->mss))) { |
||
837 | /* we can advertise more window */ |
||
838 | pcb->rcv_ann_wnd = pcb->rcv_wnd; |
||
839 | return new_right_edge - pcb->rcv_ann_right_edge; |
||
840 | } else { |
||
841 | if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) { |
||
842 | /* Can happen due to other end sending out of advertised window, |
||
843 | * but within actual available (but not yet advertised) window */ |
||
844 | pcb->rcv_ann_wnd = 0; |
||
845 | } else { |
||
846 | /* keep the right edge of window constant */ |
||
847 | u32_t new_rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt; |
||
848 | #if !LWIP_WND_SCALE |
||
849 | LWIP_ASSERT("new_rcv_ann_wnd <= 0xffff", new_rcv_ann_wnd <= 0xffff); |
||
850 | #endif |
||
851 | pcb->rcv_ann_wnd = (tcpwnd_size_t)new_rcv_ann_wnd; |
||
852 | } |
||
853 | return 0; |
||
854 | } |
||
855 | } |
||
856 | |||
857 | /** |
||
858 | * @ingroup tcp_raw |
||
859 | * This function should be called by the application when it has |
||
860 | * processed the data. The purpose is to advertise a larger window |
||
861 | * when the data has been processed. |
||
862 | * |
||
863 | * @param pcb the tcp_pcb for which data is read |
||
864 | * @param len the amount of bytes that have been read by the application |
||
865 | */ |
||
866 | void |
||
867 | tcp_recved(struct tcp_pcb *pcb, u16_t len) |
||
868 | { |
||
869 | u32_t wnd_inflation; |
||
870 | |||
871 | /* pcb->state LISTEN not allowed here */ |
||
872 | LWIP_ASSERT("don't call tcp_recved for listen-pcbs", |
||
873 | pcb->state != LISTEN); |
||
874 | |||
875 | pcb->rcv_wnd = (tcpwnd_size_t)(pcb->rcv_wnd + len); |
||
876 | if (pcb->rcv_wnd > TCP_WND_MAX(pcb)) { |
||
877 | pcb->rcv_wnd = TCP_WND_MAX(pcb); |
||
878 | } else if (pcb->rcv_wnd == 0) { |
||
879 | /* rcv_wnd overflowed */ |
||
880 | if ((pcb->state == CLOSE_WAIT) || (pcb->state == LAST_ACK)) { |
||
881 | /* In passive close, we allow this, since the FIN bit is added to rcv_wnd |
||
882 | by the stack itself, since it is not mandatory for an application |
||
883 | to call tcp_recved() for the FIN bit, but e.g. the netconn API does so. */ |
||
884 | pcb->rcv_wnd = TCP_WND_MAX(pcb); |
||
885 | } else { |
||
886 | LWIP_ASSERT("tcp_recved: len wrapped rcv_wnd\n", 0); |
||
887 | } |
||
888 | } |
||
889 | |||
890 | wnd_inflation = tcp_update_rcv_ann_wnd(pcb); |
||
891 | |||
892 | /* If the change in the right edge of window is significant (default |
||
893 | * watermark is TCP_WND/4), then send an explicit update now. |
||
894 | * Otherwise wait for a packet to be sent in the normal course of |
||
895 | * events (or more window to be available later) */ |
||
896 | if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) { |
||
897 | tcp_ack_now(pcb); |
||
898 | tcp_output(pcb); |
||
899 | } |
||
900 | |||
901 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: received %"U16_F" bytes, wnd %"TCPWNDSIZE_F" (%"TCPWNDSIZE_F").\n", |
||
902 | len, pcb->rcv_wnd, (u16_t)(TCP_WND_MAX(pcb) - pcb->rcv_wnd))); |
||
903 | } |
||
904 | |||
905 | /** |
||
906 | * Allocate a new local TCP port. |
||
907 | * |
||
908 | * @return a new (free) local TCP port number |
||
909 | */ |
||
910 | static u16_t |
||
911 | tcp_new_port(void) |
||
912 | { |
||
913 | u8_t i; |
||
914 | u16_t n = 0; |
||
915 | struct tcp_pcb *pcb; |
||
916 | |||
917 | again: |
||
918 | tcp_port++; |
||
919 | if (tcp_port == TCP_LOCAL_PORT_RANGE_END) { |
||
920 | tcp_port = TCP_LOCAL_PORT_RANGE_START; |
||
921 | } |
||
922 | /* Check all PCB lists. */ |
||
923 | for (i = 0; i < NUM_TCP_PCB_LISTS; i++) { |
||
924 | for (pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) { |
||
925 | if (pcb->local_port == tcp_port) { |
||
926 | n++; |
||
927 | if (n > (TCP_LOCAL_PORT_RANGE_END - TCP_LOCAL_PORT_RANGE_START)) { |
||
928 | return 0; |
||
929 | } |
||
930 | goto again; |
||
931 | } |
||
932 | } |
||
933 | } |
||
934 | return tcp_port; |
||
935 | } |
||
936 | |||
937 | /** |
||
938 | * @ingroup tcp_raw |
||
939 | * Connects to another host. The function given as the "connected" |
||
940 | * argument will be called when the connection has been established. |
||
941 | * |
||
942 | * @param pcb the tcp_pcb used to establish the connection |
||
943 | * @param ipaddr the remote ip address to connect to |
||
944 | * @param port the remote tcp port to connect to |
||
945 | * @param connected callback function to call when connected (on error, |
||
946 | the err calback will be called) |
||
947 | * @return ERR_VAL if invalid arguments are given |
||
948 | * ERR_OK if connect request has been sent |
||
949 | * other err_t values if connect request couldn't be sent |
||
950 | */ |
||
951 | err_t |
||
952 | tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, |
||
953 | tcp_connected_fn connected) |
||
954 | { |
||
955 | struct netif *netif = NULL; |
||
956 | err_t ret; |
||
957 | u32_t iss; |
||
958 | u16_t old_local_port; |
||
959 | |||
960 | if ((pcb == NULL) || (ipaddr == NULL)) { |
||
961 | return ERR_VAL; |
||
962 | } |
||
963 | |||
964 | LWIP_ERROR("tcp_connect: can only connect from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); |
||
965 | LWIP_ERROR("tcp_connect: cannot connect pcb bound to netif", !pcb->bound_to_netif, return ERR_VAL); |
||
966 | |||
967 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); |
||
968 | ip_addr_set(&pcb->remote_ip, ipaddr); |
||
969 | pcb->remote_port = port; |
||
970 | |||
971 | if (pcb->netif_idx != NETIF_NO_INDEX) { |
||
972 | netif = netif_get_by_index(pcb->netif_idx); |
||
973 | } else { |
||
974 | /* check if we have a route to the remote host */ |
||
975 | netif = ip_route(&pcb->local_ip, &pcb->remote_ip); |
||
976 | } |
||
977 | if (netif == NULL) { |
||
978 | /* Don't even try to send a SYN packet if we have no route since that will fail. */ |
||
979 | return ERR_RTE; |
||
980 | } |
||
981 | |||
982 | /* check if local IP has been assigned to pcb, if not, get one */ |
||
983 | if (ip_addr_isany(&pcb->local_ip)) { |
||
984 | const ip_addr_t *local_ip = ip_netif_get_local_ip(netif, ipaddr); |
||
985 | if (local_ip == NULL) { |
||
986 | return ERR_RTE; |
||
987 | } |
||
988 | ip_addr_copy(pcb->local_ip, *local_ip); |
||
989 | } |
||
990 | |||
991 | #if LWIP_IPV6 && LWIP_IPV6_SCOPES |
||
992 | /* If the given IP address should have a zone but doesn't, assign one now. |
||
993 | * Given that we already have the target netif, this is easy and cheap. */ |
||
994 | if (IP_IS_V6(&pcb->remote_ip) && |
||
995 | ip6_addr_lacks_zone(ip_2_ip6(&pcb->remote_ip), IP6_UNICAST)) { |
||
996 | ip6_addr_assign_zone(ip_2_ip6(&pcb->remote_ip), IP6_UNICAST, netif); |
||
997 | } |
||
998 | #endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ |
||
999 | |||
1000 | old_local_port = pcb->local_port; |
||
1001 | if (pcb->local_port == 0) { |
||
1002 | pcb->local_port = tcp_new_port(); |
||
1003 | if (pcb->local_port == 0) { |
||
1004 | return ERR_BUF; |
||
1005 | } |
||
1006 | } else { |
||
1007 | #if SO_REUSE |
||
1008 | if (ip_get_option(pcb, SOF_REUSEADDR)) { |
||
1009 | /* Since SOF_REUSEADDR allows reusing a local address, we have to make sure |
||
1010 | now that the 5-tuple is unique. */ |
||
1011 | struct tcp_pcb *cpcb; |
||
1012 | int i; |
||
1013 | /* Don't check listen- and bound-PCBs, check active- and TIME-WAIT PCBs. */ |
||
1014 | for (i = 2; i < NUM_TCP_PCB_LISTS; i++) { |
||
1015 | for (cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { |
||
1016 | if ((cpcb->local_port == pcb->local_port) && |
||
1017 | (cpcb->remote_port == port) && |
||
1018 | ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) && |
||
1019 | ip_addr_cmp(&cpcb->remote_ip, ipaddr)) { |
||
1020 | /* linux returns EISCONN here, but ERR_USE should be OK for us */ |
||
1021 | return ERR_USE; |
||
1022 | } |
||
1023 | } |
||
1024 | } |
||
1025 | } |
||
1026 | #endif /* SO_REUSE */ |
||
1027 | } |
||
1028 | |||
1029 | iss = tcp_next_iss(pcb); |
||
1030 | pcb->rcv_nxt = 0; |
||
1031 | pcb->snd_nxt = iss; |
||
1032 | pcb->lastack = iss - 1; |
||
1033 | pcb->snd_wl2 = iss - 1; |
||
1034 | pcb->snd_lbb = iss - 1; |
||
1035 | /* Start with a window that does not need scaling. When window scaling is |
||
1036 | enabled and used, the window is enlarged when both sides agree on scaling. */ |
||
1037 | pcb->rcv_wnd = pcb->rcv_ann_wnd = TCPWND_MIN16(TCP_WND); |
||
1038 | pcb->rcv_ann_right_edge = pcb->rcv_nxt; |
||
1039 | pcb->snd_wnd = TCP_WND; |
||
1040 | /* As initial send MSS, we use TCP_MSS but limit it to 536. |
||
1041 | The send MSS is updated when an MSS option is received. */ |
||
1042 | pcb->mss = INITIAL_MSS; |
||
1043 | #if TCP_CALCULATE_EFF_SEND_MSS |
||
1044 | pcb->mss = tcp_eff_send_mss_netif(pcb->mss, netif, &pcb->remote_ip); |
||
1045 | #endif /* TCP_CALCULATE_EFF_SEND_MSS */ |
||
1046 | pcb->cwnd = 1; |
||
1047 | #if LWIP_CALLBACK_API |
||
1048 | pcb->connected = connected; |
||
1049 | #else /* LWIP_CALLBACK_API */ |
||
1050 | LWIP_UNUSED_ARG(connected); |
||
1051 | #endif /* LWIP_CALLBACK_API */ |
||
1052 | |||
1053 | /* Send a SYN together with the MSS option. */ |
||
1054 | ret = tcp_enqueue_flags(pcb, TCP_SYN); |
||
1055 | if (ret == ERR_OK) { |
||
1056 | /* SYN segment was enqueued, changed the pcbs state now */ |
||
1057 | pcb->state = SYN_SENT; |
||
1058 | if (old_local_port != 0) { |
||
1059 | TCP_RMV(&tcp_bound_pcbs, pcb); |
||
1060 | } |
||
1061 | TCP_REG_ACTIVE(pcb); |
||
1062 | MIB2_STATS_INC(mib2.tcpactiveopens); |
||
1063 | |||
1064 | tcp_output(pcb); |
||
1065 | } |
||
1066 | return ret; |
||
1067 | } |
||
1068 | |||
1069 | /** |
||
1070 | * Called every 500 ms and implements the retransmission timer and the timer that |
||
1071 | * removes PCBs that have been in TIME-WAIT for enough time. It also increments |
||
1072 | * various timers such as the inactivity timer in each PCB. |
||
1073 | * |
||
1074 | * Automatically called from tcp_tmr(). |
||
1075 | */ |
||
1076 | void |
||
1077 | tcp_slowtmr(void) |
||
1078 | { |
||
1079 | struct tcp_pcb *pcb, *prev; |
||
1080 | tcpwnd_size_t eff_wnd; |
||
1081 | u8_t pcb_remove; /* flag if a PCB should be removed */ |
||
1082 | u8_t pcb_reset; /* flag if a RST should be sent when removing */ |
||
1083 | err_t err; |
||
1084 | |||
1085 | err = ERR_OK; |
||
1086 | |||
1087 | ++tcp_ticks; |
||
1088 | ++tcp_timer_ctr; |
||
1089 | |||
1090 | tcp_slowtmr_start: |
||
1091 | /* Steps through all of the active PCBs. */ |
||
1092 | prev = NULL; |
||
1093 | pcb = tcp_active_pcbs; |
||
1094 | if (pcb == NULL) { |
||
1095 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n")); |
||
1096 | } |
||
1097 | while (pcb != NULL) { |
||
1098 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n")); |
||
1099 | LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED); |
||
1100 | LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN); |
||
1101 | LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT); |
||
1102 | if (pcb->last_timer == tcp_timer_ctr) { |
||
1103 | /* skip this pcb, we have already processed it */ |
||
1104 | pcb = pcb->next; |
||
1105 | continue; |
||
1106 | } |
||
1107 | pcb->last_timer = tcp_timer_ctr; |
||
1108 | |||
1109 | pcb_remove = 0; |
||
1110 | pcb_reset = 0; |
||
1111 | |||
1112 | if (pcb->state == SYN_SENT && pcb->nrtx >= TCP_SYNMAXRTX) { |
||
1113 | ++pcb_remove; |
||
1114 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n")); |
||
1115 | } else if (pcb->nrtx >= TCP_MAXRTX) { |
||
1116 | ++pcb_remove; |
||
1117 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n")); |
||
1118 | } else { |
||
1119 | if (pcb->persist_backoff > 0) { |
||
1120 | LWIP_ASSERT("tcp_slowtimr: persist ticking with in-flight data", pcb->unacked == NULL); |
||
1121 | LWIP_ASSERT("tcp_slowtimr: persist ticking with empty send buffer", pcb->unsent != NULL); |
||
1122 | if (pcb->persist_probe >= TCP_MAXRTX) { |
||
1123 | ++pcb_remove; /* max probes reached */ |
||
1124 | } else { |
||
1125 | u8_t backoff_cnt = tcp_persist_backoff[pcb->persist_backoff - 1]; |
||
1126 | if (pcb->persist_cnt < backoff_cnt) { |
||
1127 | pcb->persist_cnt++; |
||
1128 | } |
||
1129 | if (pcb->persist_cnt >= backoff_cnt) { |
||
1130 | int next_slot = 1; /* increment timer to next slot */ |
||
1131 | /* If snd_wnd is zero, send 1 byte probes */ |
||
1132 | if (pcb->snd_wnd == 0) { |
||
1133 | if (tcp_zero_window_probe(pcb) != ERR_OK) { |
||
1134 | next_slot = 0; /* try probe again with current slot */ |
||
1135 | } |
||
1136 | /* snd_wnd not fully closed, split unsent head and fill window */ |
||
1137 | } else { |
||
1138 | if (tcp_split_unsent_seg(pcb, (u16_t)pcb->snd_wnd) == ERR_OK) { |
||
1139 | if (tcp_output(pcb) == ERR_OK) { |
||
1140 | /* sending will cancel persist timer, else retry with current slot */ |
||
1141 | next_slot = 0; |
||
1142 | } |
||
1143 | } |
||
1144 | } |
||
1145 | if (next_slot) { |
||
1146 | pcb->persist_cnt = 0; |
||
1147 | if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) { |
||
1148 | pcb->persist_backoff++; |
||
1149 | } |
||
1150 | } |
||
1151 | } |
||
1152 | } |
||
1153 | } else { |
||
1154 | /* Increase the retransmission timer if it is running */ |
||
1155 | if (pcb->rtime >= 0) { |
||
1156 | ++pcb->rtime; |
||
1157 | } |
||
1158 | |||
1159 | if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) { |
||
1160 | /* Time for a retransmission. */ |
||
1161 | LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F |
||
1162 | " pcb->rto %"S16_F"\n", |
||
1163 | pcb->rtime, pcb->rto)); |
||
1164 | if (tcp_rexmit_rto_prepare(pcb) == ERR_OK) { |
||
1165 | /* Double retransmission time-out unless we are trying to |
||
1166 | * connect to somebody (i.e., we are in SYN_SENT). */ |
||
1167 | if (pcb->state != SYN_SENT) { |
||
1168 | u8_t backoff_idx = LWIP_MIN(pcb->nrtx, sizeof(tcp_backoff) - 1); |
||
1169 | int calc_rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[backoff_idx]; |
||
1170 | pcb->rto = (s16_t)LWIP_MIN(calc_rto, 0x7FFF); |
||
1171 | } |
||
1172 | |||
1173 | /* Reset the retransmission timer. */ |
||
1174 | pcb->rtime = 0; |
||
1175 | |||
1176 | /* Reduce congestion window and ssthresh. */ |
||
1177 | eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd); |
||
1178 | pcb->ssthresh = eff_wnd >> 1; |
||
1179 | if (pcb->ssthresh < (tcpwnd_size_t)(pcb->mss << 1)) { |
||
1180 | pcb->ssthresh = (tcpwnd_size_t)(pcb->mss << 1); |
||
1181 | } |
||
1182 | pcb->cwnd = pcb->mss; |
||
1183 | LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"TCPWNDSIZE_F |
||
1184 | " ssthresh %"TCPWNDSIZE_F"\n", |
||
1185 | pcb->cwnd, pcb->ssthresh)); |
||
1186 | pcb->bytes_acked = 0; |
||
1187 | |||
1188 | /* The following needs to be called AFTER cwnd is set to one |
||
1189 | mss - STJ */ |
||
1190 | tcp_rexmit_rto_commit(pcb); |
||
1191 | } |
||
1192 | } |
||
1193 | } |
||
1194 | } |
||
1195 | /* Check if this PCB has stayed too long in FIN-WAIT-2 */ |
||
1196 | if (pcb->state == FIN_WAIT_2) { |
||
1197 | /* If this PCB is in FIN_WAIT_2 because of SHUT_WR don't let it time out. */ |
||
1198 | if (pcb->flags & TF_RXCLOSED) { |
||
1199 | /* PCB was fully closed (either through close() or SHUT_RDWR): |
||
1200 | normal FIN-WAIT timeout handling. */ |
||
1201 | if ((u32_t)(tcp_ticks - pcb->tmr) > |
||
1202 | TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) { |
||
1203 | ++pcb_remove; |
||
1204 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n")); |
||
1205 | } |
||
1206 | } |
||
1207 | } |
||
1208 | |||
1209 | /* Check if KEEPALIVE should be sent */ |
||
1210 | if (ip_get_option(pcb, SOF_KEEPALIVE) && |
||
1211 | ((pcb->state == ESTABLISHED) || |
||
1212 | (pcb->state == CLOSE_WAIT))) { |
||
1213 | if ((u32_t)(tcp_ticks - pcb->tmr) > |
||
1214 | (pcb->keep_idle + TCP_KEEP_DUR(pcb)) / TCP_SLOW_INTERVAL) { |
||
1215 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to ")); |
||
1216 | ip_addr_debug_print_val(TCP_DEBUG, pcb->remote_ip); |
||
1217 | LWIP_DEBUGF(TCP_DEBUG, ("\n")); |
||
1218 | |||
1219 | ++pcb_remove; |
||
1220 | ++pcb_reset; |
||
1221 | } else if ((u32_t)(tcp_ticks - pcb->tmr) > |
||
1222 | (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEP_INTVL(pcb)) |
||
1223 | / TCP_SLOW_INTERVAL) { |
||
1224 | err = tcp_keepalive(pcb); |
||
1225 | if (err == ERR_OK) { |
||
1226 | pcb->keep_cnt_sent++; |
||
1227 | } |
||
1228 | } |
||
1229 | } |
||
1230 | |||
1231 | /* If this PCB has queued out of sequence data, but has been |
||
1232 | inactive for too long, will drop the data (it will eventually |
||
1233 | be retransmitted). */ |
||
1234 | #if TCP_QUEUE_OOSEQ |
||
1235 | if (pcb->ooseq != NULL && |
||
1236 | (tcp_ticks - pcb->tmr >= (u32_t)pcb->rto * TCP_OOSEQ_TIMEOUT)) { |
||
1237 | LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n")); |
||
1238 | tcp_free_ooseq(pcb); |
||
1239 | } |
||
1240 | #endif /* TCP_QUEUE_OOSEQ */ |
||
1241 | |||
1242 | /* Check if this PCB has stayed too long in SYN-RCVD */ |
||
1243 | if (pcb->state == SYN_RCVD) { |
||
1244 | if ((u32_t)(tcp_ticks - pcb->tmr) > |
||
1245 | TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) { |
||
1246 | ++pcb_remove; |
||
1247 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n")); |
||
1248 | } |
||
1249 | } |
||
1250 | |||
1251 | /* Check if this PCB has stayed too long in LAST-ACK */ |
||
1252 | if (pcb->state == LAST_ACK) { |
||
1253 | if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { |
||
1254 | ++pcb_remove; |
||
1255 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n")); |
||
1256 | } |
||
1257 | } |
||
1258 | |||
1259 | /* If the PCB should be removed, do it. */ |
||
1260 | if (pcb_remove) { |
||
1261 | struct tcp_pcb *pcb2; |
||
1262 | #if LWIP_CALLBACK_API |
||
1263 | tcp_err_fn err_fn = pcb->errf; |
||
1264 | #endif /* LWIP_CALLBACK_API */ |
||
1265 | void *err_arg; |
||
1266 | enum tcp_state last_state; |
||
1267 | tcp_pcb_purge(pcb); |
||
1268 | /* Remove PCB from tcp_active_pcbs list. */ |
||
1269 | if (prev != NULL) { |
||
1270 | LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs); |
||
1271 | prev->next = pcb->next; |
||
1272 | } else { |
||
1273 | /* This PCB was the first. */ |
||
1274 | LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb); |
||
1275 | tcp_active_pcbs = pcb->next; |
||
1276 | } |
||
1277 | |||
1278 | if (pcb_reset) { |
||
1279 | tcp_rst(pcb, pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, |
||
1280 | pcb->local_port, pcb->remote_port); |
||
1281 | } |
||
1282 | |||
1283 | err_arg = pcb->callback_arg; |
||
1284 | last_state = pcb->state; |
||
1285 | pcb2 = pcb; |
||
1286 | pcb = pcb->next; |
||
1287 | memp_free(MEMP_TCP_PCB, pcb2); |
||
1288 | |||
1289 | tcp_active_pcbs_changed = 0; |
||
1290 | TCP_EVENT_ERR(last_state, err_fn, err_arg, ERR_ABRT); |
||
1291 | if (tcp_active_pcbs_changed) { |
||
1292 | goto tcp_slowtmr_start; |
||
1293 | } |
||
1294 | } else { |
||
1295 | /* get the 'next' element now and work with 'prev' below (in case of abort) */ |
||
1296 | prev = pcb; |
||
1297 | pcb = pcb->next; |
||
1298 | |||
1299 | /* We check if we should poll the connection. */ |
||
1300 | ++prev->polltmr; |
||
1301 | if (prev->polltmr >= prev->pollinterval) { |
||
1302 | prev->polltmr = 0; |
||
1303 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n")); |
||
1304 | tcp_active_pcbs_changed = 0; |
||
1305 | TCP_EVENT_POLL(prev, err); |
||
1306 | if (tcp_active_pcbs_changed) { |
||
1307 | goto tcp_slowtmr_start; |
||
1308 | } |
||
1309 | /* if err == ERR_ABRT, 'prev' is already deallocated */ |
||
1310 | if (err == ERR_OK) { |
||
1311 | tcp_output(prev); |
||
1312 | } |
||
1313 | } |
||
1314 | } |
||
1315 | } |
||
1316 | |||
1317 | |||
1318 | /* Steps through all of the TIME-WAIT PCBs. */ |
||
1319 | prev = NULL; |
||
1320 | pcb = tcp_tw_pcbs; |
||
1321 | while (pcb != NULL) { |
||
1322 | LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); |
||
1323 | pcb_remove = 0; |
||
1324 | |||
1325 | /* Check if this PCB has stayed long enough in TIME-WAIT */ |
||
1326 | if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { |
||
1327 | ++pcb_remove; |
||
1328 | } |
||
1329 | |||
1330 | /* If the PCB should be removed, do it. */ |
||
1331 | if (pcb_remove) { |
||
1332 | struct tcp_pcb *pcb2; |
||
1333 | tcp_pcb_purge(pcb); |
||
1334 | /* Remove PCB from tcp_tw_pcbs list. */ |
||
1335 | if (prev != NULL) { |
||
1336 | LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs); |
||
1337 | prev->next = pcb->next; |
||
1338 | } else { |
||
1339 | /* This PCB was the first. */ |
||
1340 | LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb); |
||
1341 | tcp_tw_pcbs = pcb->next; |
||
1342 | } |
||
1343 | pcb2 = pcb; |
||
1344 | pcb = pcb->next; |
||
1345 | memp_free(MEMP_TCP_PCB, pcb2); |
||
1346 | } else { |
||
1347 | prev = pcb; |
||
1348 | pcb = pcb->next; |
||
1349 | } |
||
1350 | } |
||
1351 | } |
||
1352 | |||
1353 | /** |
||
1354 | * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously |
||
1355 | * "refused" by upper layer (application) and sends delayed ACKs or pending FINs. |
||
1356 | * |
||
1357 | * Automatically called from tcp_tmr(). |
||
1358 | */ |
||
1359 | void |
||
1360 | tcp_fasttmr(void) |
||
1361 | { |
||
1362 | struct tcp_pcb *pcb; |
||
1363 | |||
1364 | ++tcp_timer_ctr; |
||
1365 | |||
1366 | tcp_fasttmr_start: |
||
1367 | pcb = tcp_active_pcbs; |
||
1368 | |||
1369 | while (pcb != NULL) { |
||
1370 | if (pcb->last_timer != tcp_timer_ctr) { |
||
1371 | struct tcp_pcb *next; |
||
1372 | pcb->last_timer = tcp_timer_ctr; |
||
1373 | /* send delayed ACKs */ |
||
1374 | if (pcb->flags & TF_ACK_DELAY) { |
||
1375 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); |
||
1376 | tcp_ack_now(pcb); |
||
1377 | tcp_output(pcb); |
||
1378 | tcp_clear_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW); |
||
1379 | } |
||
1380 | /* send pending FIN */ |
||
1381 | if (pcb->flags & TF_CLOSEPEND) { |
||
1382 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: pending FIN\n")); |
||
1383 | tcp_clear_flags(pcb, TF_CLOSEPEND); |
||
1384 | tcp_close_shutdown_fin(pcb); |
||
1385 | } |
||
1386 | |||
1387 | next = pcb->next; |
||
1388 | |||
1389 | /* If there is data which was previously "refused" by upper layer */ |
||
1390 | if (pcb->refused_data != NULL) { |
||
1391 | tcp_active_pcbs_changed = 0; |
||
1392 | tcp_process_refused_data(pcb); |
||
1393 | if (tcp_active_pcbs_changed) { |
||
1394 | /* application callback has changed the pcb list: restart the loop */ |
||
1395 | goto tcp_fasttmr_start; |
||
1396 | } |
||
1397 | } |
||
1398 | pcb = next; |
||
1399 | } else { |
||
1400 | pcb = pcb->next; |
||
1401 | } |
||
1402 | } |
||
1403 | } |
||
1404 | |||
1405 | /** Call tcp_output for all active pcbs that have TF_NAGLEMEMERR set */ |
||
1406 | void |
||
1407 | tcp_txnow(void) |
||
1408 | { |
||
1409 | struct tcp_pcb *pcb; |
||
1410 | |||
1411 | for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { |
||
1412 | if (pcb->flags & TF_NAGLEMEMERR) { |
||
1413 | tcp_output(pcb); |
||
1414 | } |
||
1415 | } |
||
1416 | } |
||
1417 | |||
1418 | /** Pass pcb->refused_data to the recv callback */ |
||
1419 | err_t |
||
1420 | tcp_process_refused_data(struct tcp_pcb *pcb) |
||
1421 | { |
||
1422 | #if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE |
||
1423 | struct pbuf *rest; |
||
1424 | while (pcb->refused_data != NULL) |
||
1425 | #endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ |
||
1426 | { |
||
1427 | err_t err; |
||
1428 | u8_t refused_flags = pcb->refused_data->flags; |
||
1429 | /* set pcb->refused_data to NULL in case the callback frees it and then |
||
1430 | closes the pcb */ |
||
1431 | struct pbuf *refused_data = pcb->refused_data; |
||
1432 | #if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE |
||
1433 | pbuf_split_64k(refused_data, &rest); |
||
1434 | pcb->refused_data = rest; |
||
1435 | #else /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ |
||
1436 | pcb->refused_data = NULL; |
||
1437 | #endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ |
||
1438 | /* Notify again application with data previously received. */ |
||
1439 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n")); |
||
1440 | TCP_EVENT_RECV(pcb, refused_data, ERR_OK, err); |
||
1441 | if (err == ERR_OK) { |
||
1442 | /* did refused_data include a FIN? */ |
||
1443 | if ((refused_flags & PBUF_FLAG_TCP_FIN) |
||
1444 | #if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE |
||
1445 | && (rest == NULL) |
||
1446 | #endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ |
||
1447 | ) { |
||
1448 | /* correct rcv_wnd as the application won't call tcp_recved() |
||
1449 | for the FIN's seqno */ |
||
1450 | if (pcb->rcv_wnd != TCP_WND_MAX(pcb)) { |
||
1451 | pcb->rcv_wnd++; |
||
1452 | } |
||
1453 | TCP_EVENT_CLOSED(pcb, err); |
||
1454 | if (err == ERR_ABRT) { |
||
1455 | return ERR_ABRT; |
||
1456 | } |
||
1457 | } |
||
1458 | } else if (err == ERR_ABRT) { |
||
1459 | /* if err == ERR_ABRT, 'pcb' is already deallocated */ |
||
1460 | /* Drop incoming packets because pcb is "full" (only if the incoming |
||
1461 | segment contains data). */ |
||
1462 | LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n")); |
||
1463 | return ERR_ABRT; |
||
1464 | } else { |
||
1465 | /* data is still refused, pbuf is still valid (go on for ACK-only packets) */ |
||
1466 | #if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE |
||
1467 | if (rest != NULL) { |
||
1468 | pbuf_cat(refused_data, rest); |
||
1469 | } |
||
1470 | #endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ |
||
1471 | pcb->refused_data = refused_data; |
||
1472 | return ERR_INPROGRESS; |
||
1473 | } |
||
1474 | } |
||
1475 | return ERR_OK; |
||
1476 | } |
||
1477 | |||
1478 | /** |
||
1479 | * Deallocates a list of TCP segments (tcp_seg structures). |
||
1480 | * |
||
1481 | * @param seg tcp_seg list of TCP segments to free |
||
1482 | */ |
||
1483 | void |
||
1484 | tcp_segs_free(struct tcp_seg *seg) |
||
1485 | { |
||
1486 | while (seg != NULL) { |
||
1487 | struct tcp_seg *next = seg->next; |
||
1488 | tcp_seg_free(seg); |
||
1489 | seg = next; |
||
1490 | } |
||
1491 | } |
||
1492 | |||
1493 | /** |
||
1494 | * Frees a TCP segment (tcp_seg structure). |
||
1495 | * |
||
1496 | * @param seg single tcp_seg to free |
||
1497 | */ |
||
1498 | void |
||
1499 | tcp_seg_free(struct tcp_seg *seg) |
||
1500 | { |
||
1501 | if (seg != NULL) { |
||
1502 | if (seg->p != NULL) { |
||
1503 | pbuf_free(seg->p); |
||
1504 | #if TCP_DEBUG |
||
1505 | seg->p = NULL; |
||
1506 | #endif /* TCP_DEBUG */ |
||
1507 | } |
||
1508 | memp_free(MEMP_TCP_SEG, seg); |
||
1509 | } |
||
1510 | } |
||
1511 | |||
1512 | /** |
||
1513 | * @ingroup tcp |
||
1514 | * Sets the priority of a connection. |
||
1515 | * |
||
1516 | * @param pcb the tcp_pcb to manipulate |
||
1517 | * @param prio new priority |
||
1518 | */ |
||
1519 | void |
||
1520 | tcp_setprio(struct tcp_pcb *pcb, u8_t prio) |
||
1521 | { |
||
1522 | pcb->prio = prio; |
||
1523 | } |
||
1524 | |||
1525 | #if TCP_QUEUE_OOSEQ |
||
1526 | /** |
||
1527 | * Returns a copy of the given TCP segment. |
||
1528 | * The pbuf and data are not copied, only the pointers |
||
1529 | * |
||
1530 | * @param seg the old tcp_seg |
||
1531 | * @return a copy of seg |
||
1532 | */ |
||
1533 | struct tcp_seg * |
||
1534 | tcp_seg_copy(struct tcp_seg *seg) |
||
1535 | { |
||
1536 | struct tcp_seg *cseg; |
||
1537 | |||
1538 | cseg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG); |
||
1539 | if (cseg == NULL) { |
||
1540 | return NULL; |
||
1541 | } |
||
1542 | SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); |
||
1543 | pbuf_ref(cseg->p); |
||
1544 | return cseg; |
||
1545 | } |
||
1546 | #endif /* TCP_QUEUE_OOSEQ */ |
||
1547 | |||
1548 | #if LWIP_CALLBACK_API |
||
1549 | /** |
||
1550 | * Default receive callback that is called if the user didn't register |
||
1551 | * a recv callback for the pcb. |
||
1552 | */ |
||
1553 | err_t |
||
1554 | tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) |
||
1555 | { |
||
1556 | LWIP_UNUSED_ARG(arg); |
||
1557 | if (p != NULL) { |
||
1558 | tcp_recved(pcb, p->tot_len); |
||
1559 | pbuf_free(p); |
||
1560 | } else if (err == ERR_OK) { |
||
1561 | return tcp_close(pcb); |
||
1562 | } |
||
1563 | return ERR_OK; |
||
1564 | } |
||
1565 | #endif /* LWIP_CALLBACK_API */ |
||
1566 | |||
1567 | /** |
||
1568 | * Kills the oldest active connection that has the same or lower priority than |
||
1569 | * 'prio'. |
||
1570 | * |
||
1571 | * @param prio minimum priority |
||
1572 | */ |
||
1573 | static void |
||
1574 | tcp_kill_prio(u8_t prio) |
||
1575 | { |
||
1576 | struct tcp_pcb *pcb, *inactive; |
||
1577 | u32_t inactivity; |
||
1578 | u8_t mprio; |
||
1579 | |||
1580 | mprio = LWIP_MIN(TCP_PRIO_MAX, prio); |
||
1581 | |||
1582 | /* We kill the oldest active connection that has lower priority than prio. */ |
||
1583 | inactivity = 0; |
||
1584 | inactive = NULL; |
||
1585 | for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { |
||
1586 | if (pcb->prio <= mprio && |
||
1587 | (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { |
||
1588 | inactivity = tcp_ticks - pcb->tmr; |
||
1589 | inactive = pcb; |
||
1590 | mprio = pcb->prio; |
||
1591 | } |
||
1592 | } |
||
1593 | if (inactive != NULL) { |
||
1594 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n", |
||
1595 | (void *)inactive, inactivity)); |
||
1596 | tcp_abort(inactive); |
||
1597 | } |
||
1598 | } |
||
1599 | |||
1600 | /** |
||
1601 | * Kills the oldest connection that is in specific state. |
||
1602 | * Called from tcp_alloc() for LAST_ACK and CLOSING if no more connections are available. |
||
1603 | */ |
||
1604 | static void |
||
1605 | tcp_kill_state(enum tcp_state state) |
||
1606 | { |
||
1607 | struct tcp_pcb *pcb, *inactive; |
||
1608 | u32_t inactivity; |
||
1609 | |||
1610 | LWIP_ASSERT("invalid state", (state == CLOSING) || (state == LAST_ACK)); |
||
1611 | |||
1612 | inactivity = 0; |
||
1613 | inactive = NULL; |
||
1614 | /* Go through the list of active pcbs and get the oldest pcb that is in state |
||
1615 | CLOSING/LAST_ACK. */ |
||
1616 | for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { |
||
1617 | if (pcb->state == state) { |
||
1618 | if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { |
||
1619 | inactivity = tcp_ticks - pcb->tmr; |
||
1620 | inactive = pcb; |
||
1621 | } |
||
1622 | } |
||
1623 | } |
||
1624 | if (inactive != NULL) { |
||
1625 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_closing: killing oldest %s PCB %p (%"S32_F")\n", |
||
1626 | tcp_state_str[state], (void *)inactive, inactivity)); |
||
1627 | /* Don't send a RST, since no data is lost. */ |
||
1628 | tcp_abandon(inactive, 0); |
||
1629 | } |
||
1630 | } |
||
1631 | |||
1632 | /** |
||
1633 | * Kills the oldest connection that is in TIME_WAIT state. |
||
1634 | * Called from tcp_alloc() if no more connections are available. |
||
1635 | */ |
||
1636 | static void |
||
1637 | tcp_kill_timewait(void) |
||
1638 | { |
||
1639 | struct tcp_pcb *pcb, *inactive; |
||
1640 | u32_t inactivity; |
||
1641 | |||
1642 | inactivity = 0; |
||
1643 | inactive = NULL; |
||
1644 | /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */ |
||
1645 | for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { |
||
1646 | if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { |
||
1647 | inactivity = tcp_ticks - pcb->tmr; |
||
1648 | inactive = pcb; |
||
1649 | } |
||
1650 | } |
||
1651 | if (inactive != NULL) { |
||
1652 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n", |
||
1653 | (void *)inactive, inactivity)); |
||
1654 | tcp_abort(inactive); |
||
1655 | } |
||
1656 | } |
||
1657 | |||
1658 | /** |
||
1659 | * Allocate a new tcp_pcb structure. |
||
1660 | * |
||
1661 | * @param prio priority for the new pcb |
||
1662 | * @return a new tcp_pcb that initially is in state CLOSED |
||
1663 | */ |
||
1664 | struct tcp_pcb * |
||
1665 | tcp_alloc(u8_t prio) |
||
1666 | { |
||
1667 | struct tcp_pcb *pcb; |
||
1668 | |||
1669 | pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); |
||
1670 | if (pcb == NULL) { |
||
1671 | /* Try killing oldest connection in TIME-WAIT. */ |
||
1672 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n")); |
||
1673 | tcp_kill_timewait(); |
||
1674 | /* Try to allocate a tcp_pcb again. */ |
||
1675 | pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); |
||
1676 | if (pcb == NULL) { |
||
1677 | /* Try killing oldest connection in LAST-ACK (these wouldn't go to TIME-WAIT). */ |
||
1678 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest LAST-ACK connection\n")); |
||
1679 | tcp_kill_state(LAST_ACK); |
||
1680 | /* Try to allocate a tcp_pcb again. */ |
||
1681 | pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); |
||
1682 | if (pcb == NULL) { |
||
1683 | /* Try killing oldest connection in CLOSING. */ |
||
1684 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest CLOSING connection\n")); |
||
1685 | tcp_kill_state(CLOSING); |
||
1686 | /* Try to allocate a tcp_pcb again. */ |
||
1687 | pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); |
||
1688 | if (pcb == NULL) { |
||
1689 | /* Try killing active connections with lower priority than the new one. */ |
||
1690 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing connection with prio lower than %d\n", prio)); |
||
1691 | tcp_kill_prio(prio); |
||
1692 | /* Try to allocate a tcp_pcb again. */ |
||
1693 | pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); |
||
1694 | if (pcb != NULL) { |
||
1695 | /* adjust err stats: memp_malloc failed multiple times before */ |
||
1696 | MEMP_STATS_DEC(err, MEMP_TCP_PCB); |
||
1697 | } |
||
1698 | } |
||
1699 | if (pcb != NULL) { |
||
1700 | /* adjust err stats: memp_malloc failed multiple times before */ |
||
1701 | MEMP_STATS_DEC(err, MEMP_TCP_PCB); |
||
1702 | } |
||
1703 | } |
||
1704 | if (pcb != NULL) { |
||
1705 | /* adjust err stats: memp_malloc failed multiple times before */ |
||
1706 | MEMP_STATS_DEC(err, MEMP_TCP_PCB); |
||
1707 | } |
||
1708 | } |
||
1709 | if (pcb != NULL) { |
||
1710 | /* adjust err stats: memp_malloc failed above */ |
||
1711 | MEMP_STATS_DEC(err, MEMP_TCP_PCB); |
||
1712 | } |
||
1713 | } |
||
1714 | if (pcb != NULL) { |
||
1715 | /* zero out the whole pcb, so there is no need to initialize members to zero */ |
||
1716 | memset(pcb, 0, sizeof(struct tcp_pcb)); |
||
1717 | pcb->prio = prio; |
||
1718 | pcb->snd_buf = TCP_SND_BUF; |
||
1719 | /* Start with a window that does not need scaling. When window scaling is |
||
1720 | enabled and used, the window is enlarged when both sides agree on scaling. */ |
||
1721 | pcb->rcv_wnd = pcb->rcv_ann_wnd = TCPWND_MIN16(TCP_WND); |
||
1722 | pcb->ttl = TCP_TTL; |
||
1723 | /* As initial send MSS, we use TCP_MSS but limit it to 536. |
||
1724 | The send MSS is updated when an MSS option is received. */ |
||
1725 | pcb->mss = INITIAL_MSS; |
||
1726 | pcb->rto = 3000 / TCP_SLOW_INTERVAL; |
||
1727 | pcb->sv = 3000 / TCP_SLOW_INTERVAL; |
||
1728 | pcb->rtime = -1; |
||
1729 | pcb->cwnd = 1; |
||
1730 | pcb->tmr = tcp_ticks; |
||
1731 | pcb->last_timer = tcp_timer_ctr; |
||
1732 | |||
1733 | /* RFC 5681 recommends setting ssthresh abritrarily high and gives an example |
||
1734 | of using the largest advertised receive window. We've seen complications with |
||
1735 | receiving TCPs that use window scaling and/or window auto-tuning where the |
||
1736 | initial advertised window is very small and then grows rapidly once the |
||
1737 | connection is established. To avoid these complications, we set ssthresh to the |
||
1738 | largest effective cwnd (amount of in-flight data) that the sender can have. */ |
||
1739 | pcb->ssthresh = TCP_SND_BUF; |
||
1740 | |||
1741 | #if LWIP_CALLBACK_API |
||
1742 | pcb->recv = tcp_recv_null; |
||
1743 | #endif /* LWIP_CALLBACK_API */ |
||
1744 | |||
1745 | /* Init KEEPALIVE timer */ |
||
1746 | pcb->keep_idle = TCP_KEEPIDLE_DEFAULT; |
||
1747 | |||
1748 | #if LWIP_TCP_KEEPALIVE |
||
1749 | pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT; |
||
1750 | pcb->keep_cnt = TCP_KEEPCNT_DEFAULT; |
||
1751 | #endif /* LWIP_TCP_KEEPALIVE */ |
||
1752 | } |
||
1753 | return pcb; |
||
1754 | } |
||
1755 | |||
1756 | /** |
||
1757 | * @ingroup tcp_raw |
||
1758 | * Creates a new TCP protocol control block but doesn't place it on |
||
1759 | * any of the TCP PCB lists. |
||
1760 | * The pcb is not put on any list until binding using tcp_bind(). |
||
1761 | * |
||
1762 | * @internal: Maybe there should be a idle TCP PCB list where these |
||
1763 | * PCBs are put on. Port reservation using tcp_bind() is implemented but |
||
1764 | * allocated pcbs that are not bound can't be killed automatically if wanting |
||
1765 | * to allocate a pcb with higher prio (@see tcp_kill_prio()) |
||
1766 | * |
||
1767 | * @return a new tcp_pcb that initially is in state CLOSED |
||
1768 | */ |
||
1769 | struct tcp_pcb * |
||
1770 | tcp_new(void) |
||
1771 | { |
||
1772 | return tcp_alloc(TCP_PRIO_NORMAL); |
||
1773 | } |
||
1774 | |||
1775 | /** |
||
1776 | * @ingroup tcp_raw |
||
1777 | * Creates a new TCP protocol control block but doesn't |
||
1778 | * place it on any of the TCP PCB lists. |
||
1779 | * The pcb is not put on any list until binding using tcp_bind(). |
||
1780 | * |
||
1781 | * @param type IP address type, see @ref lwip_ip_addr_type definitions. |
||
1782 | * If you want to listen to IPv4 and IPv6 (dual-stack) connections, |
||
1783 | * supply @ref IPADDR_TYPE_ANY as argument and bind to @ref IP_ANY_TYPE. |
||
1784 | * @return a new tcp_pcb that initially is in state CLOSED |
||
1785 | */ |
||
1786 | struct tcp_pcb * |
||
1787 | tcp_new_ip_type(u8_t type) |
||
1788 | { |
||
1789 | struct tcp_pcb *pcb; |
||
1790 | pcb = tcp_alloc(TCP_PRIO_NORMAL); |
||
1791 | #if LWIP_IPV4 && LWIP_IPV6 |
||
1792 | if (pcb != NULL) { |
||
1793 | IP_SET_TYPE_VAL(pcb->local_ip, type); |
||
1794 | IP_SET_TYPE_VAL(pcb->remote_ip, type); |
||
1795 | } |
||
1796 | #else |
||
1797 | LWIP_UNUSED_ARG(type); |
||
1798 | #endif /* LWIP_IPV4 && LWIP_IPV6 */ |
||
1799 | return pcb; |
||
1800 | } |
||
1801 | |||
1802 | /** |
||
1803 | * @ingroup tcp_raw |
||
1804 | * Used to specify the argument that should be passed callback |
||
1805 | * functions. |
||
1806 | * |
||
1807 | * @param pcb tcp_pcb to set the callback argument |
||
1808 | * @param arg void pointer argument to pass to callback functions |
||
1809 | */ |
||
1810 | void |
||
1811 | tcp_arg(struct tcp_pcb *pcb, void *arg) |
||
1812 | { |
||
1813 | /* This function is allowed to be called for both listen pcbs and |
||
1814 | connection pcbs. */ |
||
1815 | if (pcb != NULL) { |
||
1816 | pcb->callback_arg = arg; |
||
1817 | } |
||
1818 | } |
||
1819 | #if LWIP_CALLBACK_API |
||
1820 | |||
1821 | /** |
||
1822 | * @ingroup tcp_raw |
||
1823 | * Used to specify the function that should be called when a TCP |
||
1824 | * connection receives data. |
||
1825 | * |
||
1826 | * @param pcb tcp_pcb to set the recv callback |
||
1827 | * @param recv callback function to call for this pcb when data is received |
||
1828 | */ |
||
1829 | void |
||
1830 | tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv) |
||
1831 | { |
||
1832 | if (pcb != NULL) { |
||
1833 | LWIP_ASSERT("invalid socket state for recv callback", pcb->state != LISTEN); |
||
1834 | pcb->recv = recv; |
||
1835 | } |
||
1836 | } |
||
1837 | |||
1838 | /** |
||
1839 | * @ingroup tcp_raw |
||
1840 | * Used to specify the function that should be called when TCP data |
||
1841 | * has been successfully delivered to the remote host. |
||
1842 | * |
||
1843 | * @param pcb tcp_pcb to set the sent callback |
||
1844 | * @param sent callback function to call for this pcb when data is successfully sent |
||
1845 | */ |
||
1846 | void |
||
1847 | tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent) |
||
1848 | { |
||
1849 | if (pcb != NULL) { |
||
1850 | LWIP_ASSERT("invalid socket state for sent callback", pcb->state != LISTEN); |
||
1851 | pcb->sent = sent; |
||
1852 | } |
||
1853 | } |
||
1854 | |||
1855 | /** |
||
1856 | * @ingroup tcp_raw |
||
1857 | * Used to specify the function that should be called when a fatal error |
||
1858 | * has occurred on the connection. |
||
1859 | * |
||
1860 | * @note The corresponding pcb is already freed when this callback is called! |
||
1861 | * |
||
1862 | * @param pcb tcp_pcb to set the err callback |
||
1863 | * @param err callback function to call for this pcb when a fatal error |
||
1864 | * has occurred on the connection |
||
1865 | */ |
||
1866 | void |
||
1867 | tcp_err(struct tcp_pcb *pcb, tcp_err_fn err) |
||
1868 | { |
||
1869 | if (pcb != NULL) { |
||
1870 | LWIP_ASSERT("invalid socket state for err callback", pcb->state != LISTEN); |
||
1871 | pcb->errf = err; |
||
1872 | } |
||
1873 | } |
||
1874 | |||
1875 | /** |
||
1876 | * @ingroup tcp_raw |
||
1877 | * Used for specifying the function that should be called when a |
||
1878 | * LISTENing connection has been connected to another host. |
||
1879 | * |
||
1880 | * @param pcb tcp_pcb to set the accept callback |
||
1881 | * @param accept callback function to call for this pcb when LISTENing |
||
1882 | * connection has been connected to another host |
||
1883 | */ |
||
1884 | void |
||
1885 | tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept) |
||
1886 | { |
||
1887 | if ((pcb != NULL) && (pcb->state == LISTEN)) { |
||
1888 | struct tcp_pcb_listen *lpcb = (struct tcp_pcb_listen *)pcb; |
||
1889 | lpcb->accept = accept; |
||
1890 | } |
||
1891 | } |
||
1892 | #endif /* LWIP_CALLBACK_API */ |
||
1893 | |||
1894 | |||
1895 | /** |
||
1896 | * @ingroup tcp_raw |
||
1897 | * Used to specify the function that should be called periodically |
||
1898 | * from TCP. The interval is specified in terms of the TCP coarse |
||
1899 | * timer interval, which is called twice a second. |
||
1900 | * |
||
1901 | */ |
||
1902 | void |
||
1903 | tcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval) |
||
1904 | { |
||
1905 | LWIP_ASSERT("invalid socket state for poll", pcb->state != LISTEN); |
||
1906 | #if LWIP_CALLBACK_API |
||
1907 | pcb->poll = poll; |
||
1908 | #else /* LWIP_CALLBACK_API */ |
||
1909 | LWIP_UNUSED_ARG(poll); |
||
1910 | #endif /* LWIP_CALLBACK_API */ |
||
1911 | pcb->pollinterval = interval; |
||
1912 | } |
||
1913 | |||
1914 | /** |
||
1915 | * Purges a TCP PCB. Removes any buffered data and frees the buffer memory |
||
1916 | * (pcb->ooseq, pcb->unsent and pcb->unacked are freed). |
||
1917 | * |
||
1918 | * @param pcb tcp_pcb to purge. The pcb itself is not deallocated! |
||
1919 | */ |
||
1920 | void |
||
1921 | tcp_pcb_purge(struct tcp_pcb *pcb) |
||
1922 | { |
||
1923 | if (pcb->state != CLOSED && |
||
1924 | pcb->state != TIME_WAIT && |
||
1925 | pcb->state != LISTEN) { |
||
1926 | |||
1927 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n")); |
||
1928 | |||
1929 | tcp_backlog_accepted(pcb); |
||
1930 | |||
1931 | if (pcb->refused_data != NULL) { |
||
1932 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n")); |
||
1933 | pbuf_free(pcb->refused_data); |
||
1934 | pcb->refused_data = NULL; |
||
1935 | } |
||
1936 | if (pcb->unsent != NULL) { |
||
1937 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n")); |
||
1938 | } |
||
1939 | if (pcb->unacked != NULL) { |
||
1940 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n")); |
||
1941 | } |
||
1942 | #if TCP_QUEUE_OOSEQ |
||
1943 | if (pcb->ooseq != NULL) { |
||
1944 | LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n")); |
||
1945 | tcp_free_ooseq(pcb); |
||
1946 | } |
||
1947 | #endif /* TCP_QUEUE_OOSEQ */ |
||
1948 | |||
1949 | /* Stop the retransmission timer as it will expect data on unacked |
||
1950 | queue if it fires */ |
||
1951 | pcb->rtime = -1; |
||
1952 | |||
1953 | tcp_segs_free(pcb->unsent); |
||
1954 | tcp_segs_free(pcb->unacked); |
||
1955 | pcb->unacked = pcb->unsent = NULL; |
||
1956 | #if TCP_OVERSIZE |
||
1957 | pcb->unsent_oversize = 0; |
||
1958 | #endif /* TCP_OVERSIZE */ |
||
1959 | } |
||
1960 | } |
||
1961 | |||
1962 | /** |
||
1963 | * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first. |
||
1964 | * |
||
1965 | * @param pcblist PCB list to purge. |
||
1966 | * @param pcb tcp_pcb to purge. The pcb itself is NOT deallocated! |
||
1967 | */ |
||
1968 | void |
||
1969 | tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) |
||
1970 | { |
||
1971 | TCP_RMV(pcblist, pcb); |
||
1972 | |||
1973 | tcp_pcb_purge(pcb); |
||
1974 | |||
1975 | /* if there is an outstanding delayed ACKs, send it */ |
||
1976 | if ((pcb->state != TIME_WAIT) && |
||
1977 | (pcb->state != LISTEN) && |
||
1978 | (pcb->flags & TF_ACK_DELAY)) { |
||
1979 | tcp_ack_now(pcb); |
||
1980 | tcp_output(pcb); |
||
1981 | } |
||
1982 | |||
1983 | if (pcb->state != LISTEN) { |
||
1984 | LWIP_ASSERT("unsent segments leaking", pcb->unsent == NULL); |
||
1985 | LWIP_ASSERT("unacked segments leaking", pcb->unacked == NULL); |
||
1986 | #if TCP_QUEUE_OOSEQ |
||
1987 | LWIP_ASSERT("ooseq segments leaking", pcb->ooseq == NULL); |
||
1988 | #endif /* TCP_QUEUE_OOSEQ */ |
||
1989 | } |
||
1990 | |||
1991 | pcb->state = CLOSED; |
||
1992 | /* reset the local port to prevent the pcb from being 'bound' */ |
||
1993 | pcb->local_port = 0; |
||
1994 | |||
1995 | LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane()); |
||
1996 | } |
||
1997 | |||
1998 | /** |
||
1999 | * Calculates a new initial sequence number for new connections. |
||
2000 | * |
||
2001 | * @return u32_t pseudo random sequence number |
||
2002 | */ |
||
2003 | u32_t |
||
2004 | tcp_next_iss(struct tcp_pcb *pcb) |
||
2005 | { |
||
2006 | #ifdef LWIP_HOOK_TCP_ISN |
||
2007 | return LWIP_HOOK_TCP_ISN(&pcb->local_ip, pcb->local_port, &pcb->remote_ip, pcb->remote_port); |
||
2008 | #else /* LWIP_HOOK_TCP_ISN */ |
||
2009 | static u32_t iss = 6510; |
||
2010 | |||
2011 | LWIP_UNUSED_ARG(pcb); |
||
2012 | |||
2013 | iss += tcp_ticks; /* XXX */ |
||
2014 | return iss; |
||
2015 | #endif /* LWIP_HOOK_TCP_ISN */ |
||
2016 | } |
||
2017 | |||
2018 | #if TCP_CALCULATE_EFF_SEND_MSS |
||
2019 | /** |
||
2020 | * Calculates the effective send mss that can be used for a specific IP address |
||
2021 | * by calculating the minimum of TCP_MSS and the mtu (if set) of the target |
||
2022 | * netif (if not NULL). |
||
2023 | */ |
||
2024 | u16_t |
||
2025 | tcp_eff_send_mss_netif(u16_t sendmss, struct netif *outif, const ip_addr_t *dest) |
||
2026 | { |
||
2027 | u16_t mss_s; |
||
2028 | u16_t mtu; |
||
2029 | |||
2030 | LWIP_UNUSED_ARG(dest); /* in case IPv6 is disabled */ |
||
2031 | |||
2032 | #if LWIP_IPV6 |
||
2033 | #if LWIP_IPV4 |
||
2034 | if (IP_IS_V6(dest)) |
||
2035 | #endif /* LWIP_IPV4 */ |
||
2036 | { |
||
2037 | /* First look in destination cache, to see if there is a Path MTU. */ |
||
2038 | mtu = nd6_get_destination_mtu(ip_2_ip6(dest), outif); |
||
2039 | } |
||
2040 | #if LWIP_IPV4 |
||
2041 | else |
||
2042 | #endif /* LWIP_IPV4 */ |
||
2043 | #endif /* LWIP_IPV6 */ |
||
2044 | #if LWIP_IPV4 |
||
2045 | { |
||
2046 | if (outif == NULL) { |
||
2047 | return sendmss; |
||
2048 | } |
||
2049 | mtu = outif->mtu; |
||
2050 | } |
||
2051 | #endif /* LWIP_IPV4 */ |
||
2052 | |||
2053 | if (mtu != 0) { |
||
2054 | u16_t offset; |
||
2055 | #if LWIP_IPV6 |
||
2056 | #if LWIP_IPV4 |
||
2057 | if (IP_IS_V6(dest)) |
||
2058 | #endif /* LWIP_IPV4 */ |
||
2059 | { |
||
2060 | offset = IP6_HLEN + TCP_HLEN; |
||
2061 | } |
||
2062 | #if LWIP_IPV4 |
||
2063 | else |
||
2064 | #endif /* LWIP_IPV4 */ |
||
2065 | #endif /* LWIP_IPV6 */ |
||
2066 | #if LWIP_IPV4 |
||
2067 | { |
||
2068 | offset = IP_HLEN + TCP_HLEN; |
||
2069 | } |
||
2070 | #endif /* LWIP_IPV4 */ |
||
2071 | mss_s = (mtu > offset) ? (u16_t)(mtu - offset) : 0; |
||
2072 | /* RFC 1122, chap 4.2.2.6: |
||
2073 | * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize |
||
2074 | * We correct for TCP options in tcp_write(), and don't support IP options. |
||
2075 | */ |
||
2076 | sendmss = LWIP_MIN(sendmss, mss_s); |
||
2077 | } |
||
2078 | return sendmss; |
||
2079 | } |
||
2080 | #endif /* TCP_CALCULATE_EFF_SEND_MSS */ |
||
2081 | |||
2082 | /** Helper function for tcp_netif_ip_addr_changed() that iterates a pcb list */ |
||
2083 | static void |
||
2084 | tcp_netif_ip_addr_changed_pcblist(const ip_addr_t *old_addr, struct tcp_pcb *pcb_list) |
||
2085 | { |
||
2086 | struct tcp_pcb *pcb; |
||
2087 | pcb = pcb_list; |
||
2088 | while (pcb != NULL) { |
||
2089 | /* PCB bound to current local interface address? */ |
||
2090 | if (ip_addr_cmp(&pcb->local_ip, old_addr) |
||
2091 | #if LWIP_AUTOIP |
||
2092 | /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */ |
||
2093 | && (!IP_IS_V4_VAL(pcb->local_ip) || !ip4_addr_islinklocal(ip_2_ip4(&pcb->local_ip))) |
||
2094 | #endif /* LWIP_AUTOIP */ |
||
2095 | ) { |
||
2096 | /* this connection must be aborted */ |
||
2097 | struct tcp_pcb *next = pcb->next; |
||
2098 | LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb)); |
||
2099 | tcp_abort(pcb); |
||
2100 | pcb = next; |
||
2101 | } else { |
||
2102 | pcb = pcb->next; |
||
2103 | } |
||
2104 | } |
||
2105 | } |
||
2106 | |||
2107 | /** This function is called from netif.c when address is changed or netif is removed |
||
2108 | * |
||
2109 | * @param old_addr IP address of the netif before change |
||
2110 | * @param new_addr IP address of the netif after change or NULL if netif has been removed |
||
2111 | */ |
||
2112 | void |
||
2113 | tcp_netif_ip_addr_changed(const ip_addr_t *old_addr, const ip_addr_t *new_addr) |
||
2114 | { |
||
2115 | struct tcp_pcb_listen *lpcb, *next; |
||
2116 | |||
2117 | if (!ip_addr_isany(old_addr)) { |
||
2118 | tcp_netif_ip_addr_changed_pcblist(old_addr, tcp_active_pcbs); |
||
2119 | tcp_netif_ip_addr_changed_pcblist(old_addr, tcp_bound_pcbs); |
||
2120 | |||
2121 | if (!ip_addr_isany(new_addr)) { |
||
2122 | /* PCB bound to current local interface address? */ |
||
2123 | for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = next) { |
||
2124 | next = lpcb->next; |
||
2125 | /* PCB bound to current local interface address? */ |
||
2126 | if (ip_addr_cmp(&lpcb->local_ip, old_addr)) { |
||
2127 | /* The PCB is listening to the old ipaddr and |
||
2128 | * is set to listen to the new one instead */ |
||
2129 | ip_addr_copy(lpcb->local_ip, *new_addr); |
||
2130 | } |
||
2131 | } |
||
2132 | } |
||
2133 | } |
||
2134 | } |
||
2135 | |||
2136 | const char * |
||
2137 | tcp_debug_state_str(enum tcp_state s) |
||
2138 | { |
||
2139 | return tcp_state_str[s]; |
||
2140 | } |
||
2141 | |||
2142 | err_t |
||
2143 | tcp_tcp_get_tcp_addrinfo(struct tcp_pcb *pcb, int local, ip_addr_t *addr, u16_t *port) |
||
2144 | { |
||
2145 | if (pcb) { |
||
2146 | if (local) { |
||
2147 | if (addr) { |
||
2148 | *addr = pcb->local_ip; |
||
2149 | } |
||
2150 | if (port) { |
||
2151 | *port = pcb->local_port; |
||
2152 | } |
||
2153 | } else { |
||
2154 | if (addr) { |
||
2155 | *addr = pcb->remote_ip; |
||
2156 | } |
||
2157 | if (port) { |
||
2158 | *port = pcb->remote_port; |
||
2159 | } |
||
2160 | } |
||
2161 | return ERR_OK; |
||
2162 | } |
||
2163 | return ERR_VAL; |
||
2164 | } |
||
2165 | |||
2166 | #if TCP_QUEUE_OOSEQ |
||
2167 | /* Free all ooseq pbufs (and possibly reset SACK state) */ |
||
2168 | void |
||
2169 | tcp_free_ooseq(struct tcp_pcb *pcb) |
||
2170 | { |
||
2171 | if (pcb->ooseq) { |
||
2172 | tcp_segs_free(pcb->ooseq); |
||
2173 | pcb->ooseq = NULL; |
||
2174 | #if LWIP_TCP_SACK_OUT |
||
2175 | memset(pcb->rcv_sacks, 0, sizeof(pcb->rcv_sacks)); |
||
2176 | #endif /* LWIP_TCP_SACK_OUT */ |
||
2177 | } |
||
2178 | } |
||
2179 | #endif /* TCP_QUEUE_OOSEQ */ |
||
2180 | |||
2181 | #if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG |
||
2182 | /** |
||
2183 | * Print a tcp header for debugging purposes. |
||
2184 | * |
||
2185 | * @param tcphdr pointer to a struct tcp_hdr |
||
2186 | */ |
||
2187 | void |
||
2188 | tcp_debug_print(struct tcp_hdr *tcphdr) |
||
2189 | { |
||
2190 | LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n")); |
||
2191 | LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); |
||
2192 | LWIP_DEBUGF(TCP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", |
||
2193 | lwip_ntohs(tcphdr->src), lwip_ntohs(tcphdr->dest))); |
||
2194 | LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); |
||
2195 | LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (seq no)\n", |
||
2196 | lwip_ntohl(tcphdr->seqno))); |
||
2197 | LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); |
||
2198 | LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (ack no)\n", |
||
2199 | lwip_ntohl(tcphdr->ackno))); |
||
2200 | LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); |
||
2201 | LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" | |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"| %5"U16_F" | (hdrlen, flags (", |
||
2202 | TCPH_HDRLEN(tcphdr), |
||
2203 | (u16_t)(TCPH_FLAGS(tcphdr) >> 5 & 1), |
||
2204 | (u16_t)(TCPH_FLAGS(tcphdr) >> 4 & 1), |
||
2205 | (u16_t)(TCPH_FLAGS(tcphdr) >> 3 & 1), |
||
2206 | (u16_t)(TCPH_FLAGS(tcphdr) >> 2 & 1), |
||
2207 | (u16_t)(TCPH_FLAGS(tcphdr) >> 1 & 1), |
||
2208 | (u16_t)(TCPH_FLAGS(tcphdr) & 1), |
||
2209 | lwip_ntohs(tcphdr->wnd))); |
||
2210 | tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); |
||
2211 | LWIP_DEBUGF(TCP_DEBUG, ("), win)\n")); |
||
2212 | LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); |
||
2213 | LWIP_DEBUGF(TCP_DEBUG, ("| 0x%04"X16_F" | %5"U16_F" | (chksum, urgp)\n", |
||
2214 | lwip_ntohs(tcphdr->chksum), lwip_ntohs(tcphdr->urgp))); |
||
2215 | LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); |
||
2216 | } |
||
2217 | |||
2218 | /** |
||
2219 | * Print a tcp state for debugging purposes. |
||
2220 | * |
||
2221 | * @param s enum tcp_state to print |
||
2222 | */ |
||
2223 | void |
||
2224 | tcp_debug_print_state(enum tcp_state s) |
||
2225 | { |
||
2226 | LWIP_DEBUGF(TCP_DEBUG, ("State: %s\n", tcp_state_str[s])); |
||
2227 | } |
||
2228 | |||
2229 | /** |
||
2230 | * Print tcp flags for debugging purposes. |
||
2231 | * |
||
2232 | * @param flags tcp flags, all active flags are printed |
||
2233 | */ |
||
2234 | void |
||
2235 | tcp_debug_print_flags(u8_t flags) |
||
2236 | { |
||
2237 | if (flags & TCP_FIN) { |
||
2238 | LWIP_DEBUGF(TCP_DEBUG, ("FIN ")); |
||
2239 | } |
||
2240 | if (flags & TCP_SYN) { |
||
2241 | LWIP_DEBUGF(TCP_DEBUG, ("SYN ")); |
||
2242 | } |
||
2243 | if (flags & TCP_RST) { |
||
2244 | LWIP_DEBUGF(TCP_DEBUG, ("RST ")); |
||
2245 | } |
||
2246 | if (flags & TCP_PSH) { |
||
2247 | LWIP_DEBUGF(TCP_DEBUG, ("PSH ")); |
||
2248 | } |
||
2249 | if (flags & TCP_ACK) { |
||
2250 | LWIP_DEBUGF(TCP_DEBUG, ("ACK ")); |
||
2251 | } |
||
2252 | if (flags & TCP_URG) { |
||
2253 | LWIP_DEBUGF(TCP_DEBUG, ("URG ")); |
||
2254 | } |
||
2255 | if (flags & TCP_ECE) { |
||
2256 | LWIP_DEBUGF(TCP_DEBUG, ("ECE ")); |
||
2257 | } |
||
2258 | if (flags & TCP_CWR) { |
||
2259 | LWIP_DEBUGF(TCP_DEBUG, ("CWR ")); |
||
2260 | } |
||
2261 | LWIP_DEBUGF(TCP_DEBUG, ("\n")); |
||
2262 | } |
||
2263 | |||
2264 | /** |
||
2265 | * Print all tcp_pcbs in every list for debugging purposes. |
||
2266 | */ |
||
2267 | void |
||
2268 | tcp_debug_print_pcbs(void) |
||
2269 | { |
||
2270 | struct tcp_pcb *pcb; |
||
2271 | struct tcp_pcb_listen *pcbl; |
||
2272 | |||
2273 | LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n")); |
||
2274 | for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { |
||
2275 | LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", |
||
2276 | pcb->local_port, pcb->remote_port, |
||
2277 | pcb->snd_nxt, pcb->rcv_nxt)); |
||
2278 | tcp_debug_print_state(pcb->state); |
||
2279 | } |
||
2280 | |||
2281 | LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n")); |
||
2282 | for (pcbl = tcp_listen_pcbs.listen_pcbs; pcbl != NULL; pcbl = pcbl->next) { |
||
2283 | LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F" ", pcbl->local_port)); |
||
2284 | tcp_debug_print_state(pcbl->state); |
||
2285 | } |
||
2286 | |||
2287 | LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n")); |
||
2288 | for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { |
||
2289 | LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", |
||
2290 | pcb->local_port, pcb->remote_port, |
||
2291 | pcb->snd_nxt, pcb->rcv_nxt)); |
||
2292 | tcp_debug_print_state(pcb->state); |
||
2293 | } |
||
2294 | } |
||
2295 | |||
2296 | /** |
||
2297 | * Check state consistency of the tcp_pcb lists. |
||
2298 | */ |
||
2299 | s16_t |
||
2300 | tcp_pcbs_sane(void) |
||
2301 | { |
||
2302 | struct tcp_pcb *pcb; |
||
2303 | for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { |
||
2304 | LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED); |
||
2305 | LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN); |
||
2306 | LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); |
||
2307 | } |
||
2308 | for (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { |
||
2309 | LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); |
||
2310 | } |
||
2311 | return 1; |
||
2312 | } |
||
2313 | #endif /* TCP_DEBUG */ |
||
2314 | |||
2315 | #endif /* LWIP_TCP */ |