]> git.sur5r.net Git - freertos/blob - Demo/Common/ethernet/lwIP/core/tcp.c
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@82 1d2547de-c912-0410-9cb9...
[freertos] / Demo / Common / ethernet / lwIP / core / tcp.c
1 /**\r
2  * @file\r
3  *\r
4  * Transmission Control Protocol for IP\r
5  *\r
6  * This file contains common functions for the TCP implementation, such as functinos\r
7  * for manipulating the data structures and the TCP timer functions. TCP functions\r
8  * related to input and output is found in tcp_in.c and tcp_out.c respectively.\r
9  *\r
10  */\r
11 \r
12 /*\r
13  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
14  * All rights reserved. \r
15  * \r
16  * Redistribution and use in source and binary forms, with or without modification, \r
17  * are permitted provided that the following conditions are met:\r
18  *\r
19  * 1. Redistributions of source code must retain the above copyright notice,\r
20  *    this list of conditions and the following disclaimer.\r
21  * 2. Redistributions in binary form must reproduce the above copyright notice,\r
22  *    this list of conditions and the following disclaimer in the documentation\r
23  *    and/or other materials provided with the distribution.\r
24  * 3. The name of the author may not be used to endorse or promote products\r
25  *    derived from this software without specific prior written permission. \r
26  *\r
27  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
28  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
29  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
30  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
31  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
32  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
35  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
36  * OF SUCH DAMAGE.\r
37  *\r
38  * This file is part of the lwIP TCP/IP stack.\r
39  * \r
40  * Author: Adam Dunkels <adam@sics.se>\r
41  *\r
42  */\r
43 \r
44 #include <string.h>\r
45 \r
46 #include "lwip/opt.h"\r
47 #include "lwip/def.h"\r
48 #include "lwip/mem.h"\r
49 #include "lwip/memp.h"\r
50 #include "lwip/snmp.h"\r
51 \r
52 #include "lwip/tcp.h"\r
53 #if LWIP_TCP\r
54 \r
55 /* Incremented every coarse grained timer shot (typically every 500 ms). */\r
56 u32_t tcp_ticks;\r
57 const u8_t tcp_backoff[13] =\r
58     { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};\r
59 \r
60 /* The TCP PCB lists. */\r
61 \r
62 /** List of all TCP PCBs in LISTEN state */\r
63 union tcp_listen_pcbs_t tcp_listen_pcbs;\r
64 /** List of all TCP PCBs that are in a state in which\r
65  * they accept or send data. */\r
66 struct tcp_pcb *tcp_active_pcbs;  \r
67 /** List of all TCP PCBs in TIME-WAIT state */\r
68 struct tcp_pcb *tcp_tw_pcbs;\r
69 \r
70 struct tcp_pcb *tcp_tmp_pcb;\r
71 \r
72 static u8_t tcp_timer;\r
73 static u16_t tcp_new_port(void);\r
74 \r
75 /**\r
76  * Initializes the TCP layer.\r
77  */\r
78 void\r
79 tcp_init(void)\r
80 {\r
81   /* Clear globals. */\r
82   tcp_listen_pcbs.listen_pcbs = NULL;\r
83   tcp_active_pcbs = NULL;\r
84   tcp_tw_pcbs = NULL;\r
85   tcp_tmp_pcb = NULL;\r
86   \r
87   /* initialize timer */\r
88   tcp_ticks = 0;\r
89   tcp_timer = 0;\r
90   \r
91 }\r
92 \r
93 /**\r
94  * Called periodically to dispatch TCP timers.\r
95  *\r
96  */\r
97 void\r
98 tcp_tmr(void)\r
99 {\r
100   /* Call tcp_fasttmr() every 250 ms */\r
101   tcp_fasttmr();\r
102 \r
103   if (++tcp_timer & 1) {\r
104     /* Call tcp_tmr() every 500 ms, i.e., every other timer\r
105        tcp_tmr() is called. */\r
106     tcp_slowtmr();\r
107   }\r
108 }\r
109 \r
110 /**\r
111  * Closes the connection held by the PCB.\r
112  *\r
113  */\r
114 err_t\r
115 tcp_close(struct tcp_pcb *pcb)\r
116 {\r
117   err_t err;\r
118 \r
119 #if TCP_DEBUG\r
120   LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in "));\r
121   tcp_debug_print_state(pcb->state);\r
122 #endif /* TCP_DEBUG */\r
123 \r
124   switch (pcb->state) {\r
125   case CLOSED:\r
126     /* Closing a pcb in the CLOSED state might seem erroneous,\r
127      * however, it is in this state once allocated and as yet unused\r
128      * and the user needs some way to free it should the need arise.\r
129      * Calling tcp_close() with a pcb that has already been closed, (i.e. twice)\r
130      * or for a pcb that has been used and then entered the CLOSED state \r
131      * is erroneous, but this should never happen as the pcb has in those cases\r
132      * been freed, and so any remaining handles are bogus. */\r
133     err = ERR_OK;\r
134     memp_free(MEMP_TCP_PCB, pcb);\r
135     pcb = NULL;\r
136     break;\r
137   case LISTEN:\r
138     err = ERR_OK;\r
139     tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb);\r
140     memp_free(MEMP_TCP_PCB_LISTEN, pcb);\r
141     pcb = NULL;\r
142     break;\r
143   case SYN_SENT:\r
144     err = ERR_OK;\r
145     tcp_pcb_remove(&tcp_active_pcbs, pcb);\r
146     memp_free(MEMP_TCP_PCB, pcb);\r
147     pcb = NULL;\r
148     snmp_inc_tcpattemptfails();\r
149     break;\r
150   case SYN_RCVD:\r
151     err = tcp_send_ctrl(pcb, TCP_FIN);\r
152     if (err == ERR_OK) {\r
153       snmp_inc_tcpattemptfails();\r
154       pcb->state = FIN_WAIT_1;\r
155     }\r
156     break;\r
157   case ESTABLISHED:\r
158     err = tcp_send_ctrl(pcb, TCP_FIN);\r
159     if (err == ERR_OK) {\r
160       snmp_inc_tcpestabresets();\r
161       pcb->state = FIN_WAIT_1;\r
162     }\r
163     break;\r
164   case CLOSE_WAIT:\r
165     err = tcp_send_ctrl(pcb, TCP_FIN);\r
166     if (err == ERR_OK) {\r
167       snmp_inc_tcpestabresets();\r
168       pcb->state = LAST_ACK;\r
169     }\r
170     break;\r
171   default:\r
172     /* Has already been closed, do nothing. */\r
173     err = ERR_OK;\r
174     pcb = NULL;\r
175     break;\r
176   }\r
177 \r
178   if (pcb != NULL && err == ERR_OK) {\r
179     err = tcp_output(pcb);\r
180   }\r
181   return err;\r
182 }\r
183 \r
184 /**\r
185  * Aborts a connection by sending a RST to the remote host and deletes\r
186  * the local protocol control block. This is done when a connection is\r
187  * killed because of shortage of memory.\r
188  *\r
189  */\r
190 void\r
191 tcp_abort(struct tcp_pcb *pcb)\r
192 {\r
193   u32_t seqno, ackno;\r
194   u16_t remote_port, local_port;\r
195   struct ip_addr remote_ip, local_ip;\r
196 #if LWIP_CALLBACK_API  \r
197   void (* errf)(void *arg, err_t err);\r
198 #endif /* LWIP_CALLBACK_API */\r
199   void *errf_arg;\r
200 \r
201   \r
202   /* Figure out on which TCP PCB list we are, and remove us. If we\r
203      are in an active state, call the receive function associated with\r
204      the PCB with a NULL argument, and send an RST to the remote end. */\r
205   if (pcb->state == TIME_WAIT) {\r
206     tcp_pcb_remove(&tcp_tw_pcbs, pcb);\r
207     memp_free(MEMP_TCP_PCB, pcb);\r
208   } else {\r
209     seqno = pcb->snd_nxt;\r
210     ackno = pcb->rcv_nxt;\r
211     ip_addr_set(&local_ip, &(pcb->local_ip));\r
212     ip_addr_set(&remote_ip, &(pcb->remote_ip));\r
213     local_port = pcb->local_port;\r
214     remote_port = pcb->remote_port;\r
215 #if LWIP_CALLBACK_API\r
216     errf = pcb->errf;\r
217 #endif /* LWIP_CALLBACK_API */\r
218     errf_arg = pcb->callback_arg;\r
219     tcp_pcb_remove(&tcp_active_pcbs, pcb);\r
220     if (pcb->unacked != NULL) {\r
221       tcp_segs_free(pcb->unacked);\r
222     }\r
223     if (pcb->unsent != NULL) {\r
224       tcp_segs_free(pcb->unsent);\r
225     }\r
226 #if TCP_QUEUE_OOSEQ    \r
227     if (pcb->ooseq != NULL) {\r
228       tcp_segs_free(pcb->ooseq);\r
229     }\r
230 #endif /* TCP_QUEUE_OOSEQ */\r
231     memp_free(MEMP_TCP_PCB, pcb);\r
232     TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);\r
233     LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abort: sending RST\n"));\r
234     tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);\r
235   }\r
236 }\r
237 \r
238 /**\r
239  * Binds the connection to a local portnumber and IP address. If the\r
240  * IP address is not given (i.e., ipaddr == NULL), the IP address of\r
241  * the outgoing network interface is used instead.\r
242  *\r
243  */\r
244 \r
245 err_t\r
246 tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)\r
247 {\r
248   struct tcp_pcb *cpcb;\r
249 \r
250   if (port == 0) {\r
251     port = tcp_new_port();\r
252   }\r
253   /* Check if the address already is in use. */\r
254   for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs;\r
255       cpcb != NULL; cpcb = cpcb->next) {\r
256     if (cpcb->local_port == port) {\r
257       if (ip_addr_isany(&(cpcb->local_ip)) ||\r
258         ip_addr_isany(ipaddr) ||\r
259         ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {\r
260           return ERR_USE;\r
261       }\r
262     }\r
263   }\r
264   for(cpcb = tcp_active_pcbs;\r
265       cpcb != NULL; cpcb = cpcb->next) {\r
266     if (cpcb->local_port == port) {\r
267       if (ip_addr_isany(&(cpcb->local_ip)) ||\r
268    ip_addr_isany(ipaddr) ||\r
269    ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {\r
270   return ERR_USE;\r
271       }\r
272     }\r
273   }\r
274 \r
275   if (!ip_addr_isany(ipaddr)) {\r
276     pcb->local_ip = *ipaddr;\r
277   }\r
278   pcb->local_port = port;\r
279   LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port));\r
280   return ERR_OK;\r
281 }\r
282 #if LWIP_CALLBACK_API\r
283 static err_t\r
284 tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err)\r
285 {\r
286   (void)arg;\r
287   (void)pcb;\r
288   (void)err;\r
289 \r
290   return ERR_ABRT;\r
291 }\r
292 #endif /* LWIP_CALLBACK_API */\r
293 \r
294 /**\r
295  * Set the state of the connection to be LISTEN, which means that it\r
296  * is able to accept incoming connections. The protocol control block\r
297  * is reallocated in order to consume less memory. Setting the\r
298  * connection to LISTEN is an irreversible process.\r
299  *\r
300  */\r
301 struct tcp_pcb *\r
302 tcp_listen(struct tcp_pcb *pcb)\r
303 {\r
304   struct tcp_pcb_listen *lpcb;\r
305 \r
306   /* already listening? */\r
307   if (pcb->state == LISTEN) {\r
308     return pcb;\r
309   }\r
310   lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN);\r
311   if (lpcb == NULL) {\r
312     return NULL;\r
313   }\r
314   lpcb->callback_arg = pcb->callback_arg;\r
315   lpcb->local_port = pcb->local_port;\r
316   lpcb->state = LISTEN;\r
317   lpcb->so_options = pcb->so_options;\r
318   lpcb->so_options |= SOF_ACCEPTCONN;\r
319   lpcb->ttl = pcb->ttl;\r
320   lpcb->tos = pcb->tos;\r
321   ip_addr_set(&lpcb->local_ip, &pcb->local_ip);\r
322   memp_free(MEMP_TCP_PCB, pcb);\r
323 #if LWIP_CALLBACK_API\r
324   lpcb->accept = tcp_accept_null;\r
325 #endif /* LWIP_CALLBACK_API */\r
326   TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb);\r
327   return (struct tcp_pcb *)lpcb;\r
328 }\r
329 \r
330 /**\r
331  * This function should be called by the application when it has\r
332  * processed the data. The purpose is to advertise a larger window\r
333  * when the data has been processed.\r
334  *\r
335  */\r
336 void\r
337 tcp_recved(struct tcp_pcb *pcb, u16_t len)\r
338 {\r
339   if ((u32_t)pcb->rcv_wnd + len > TCP_WND) {\r
340     pcb->rcv_wnd = TCP_WND;\r
341   } else {\r
342     pcb->rcv_wnd += len;\r
343   }\r
344   if (!(pcb->flags & TF_ACK_DELAY) &&\r
345      !(pcb->flags & TF_ACK_NOW)) {\r
346     /*\r
347      * We send an ACK here (if one is not already pending, hence\r
348      * the above tests) as tcp_recved() implies that the application\r
349      * has processed some data, and so we can open the receiver's\r
350      * window to allow more to be transmitted.  This could result in\r
351      * two ACKs being sent for each received packet in some limited cases\r
352      * (where the application is only receiving data, and is slow to\r
353      * process it) but it is necessary to guarantee that the sender can\r
354      * continue to transmit.\r
355      */\r
356     tcp_ack(pcb);\r
357   } \r
358   else if (pcb->flags & TF_ACK_DELAY && pcb->rcv_wnd >= TCP_WND/2) {\r
359     /* If we can send a window update such that there is a full\r
360      * segment available in the window, do so now.  This is sort of\r
361      * nagle-like in its goals, and tries to hit a compromise between\r
362      * sending acks each time the window is updated, and only sending\r
363      * window updates when a timer expires.  The "threshold" used\r
364      * above (currently TCP_WND/2) can be tuned to be more or less\r
365      * aggressive  */\r
366     tcp_ack_now(pcb);\r
367   }\r
368 \r
369   LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n",\r
370          len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd));\r
371 }\r
372 \r
373 /**\r
374  * A nastly hack featuring 'goto' statements that allocates a\r
375  * new TCP local port.\r
376  */\r
377 static u16_t\r
378 tcp_new_port(void)\r
379 {\r
380   struct tcp_pcb *pcb;\r
381 #ifndef TCP_LOCAL_PORT_RANGE_START\r
382 #define TCP_LOCAL_PORT_RANGE_START 4096\r
383 #define TCP_LOCAL_PORT_RANGE_END   0x7fff\r
384 #endif\r
385   static u16_t port = TCP_LOCAL_PORT_RANGE_START;\r
386   \r
387  again:\r
388   if (++port > TCP_LOCAL_PORT_RANGE_END) {\r
389     port = TCP_LOCAL_PORT_RANGE_START;\r
390   }\r
391   \r
392   for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\r
393     if (pcb->local_port == port) {\r
394       goto again;\r
395     }\r
396   }\r
397   for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {\r
398     if (pcb->local_port == port) {\r
399       goto again;\r
400     }\r
401   }\r
402   for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {\r
403     if (pcb->local_port == port) {\r
404       goto again;\r
405     }\r
406   }\r
407   return port;\r
408 }\r
409 \r
410 /**\r
411  * Connects to another host. The function given as the "connected"\r
412  * argument will be called when the connection has been established.\r
413  *\r
414  */\r
415 err_t\r
416 tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,\r
417       err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err))\r
418 {\r
419   u32_t optdata;\r
420   err_t ret;\r
421   u32_t iss;\r
422 \r
423   LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port));\r
424   if (ipaddr != NULL) {\r
425     pcb->remote_ip = *ipaddr;\r
426   } else {\r
427     return ERR_VAL;\r
428   }\r
429   pcb->remote_port = port;\r
430   if (pcb->local_port == 0) {\r
431     pcb->local_port = tcp_new_port();\r
432   }\r
433   iss = tcp_next_iss();\r
434   pcb->rcv_nxt = 0;\r
435   pcb->snd_nxt = iss;\r
436   pcb->lastack = iss - 1;\r
437   pcb->snd_lbb = iss - 1;\r
438   pcb->rcv_wnd = TCP_WND;\r
439   pcb->snd_wnd = TCP_WND;\r
440   pcb->mss = TCP_MSS;\r
441   pcb->cwnd = 1;\r
442   pcb->ssthresh = pcb->mss * 10;\r
443   pcb->state = SYN_SENT;\r
444 #if LWIP_CALLBACK_API  \r
445   pcb->connected = connected;\r
446 #endif /* LWIP_CALLBACK_API */  \r
447   TCP_REG(&tcp_active_pcbs, pcb);\r
448 \r
449   snmp_inc_tcpactiveopens();\r
450   \r
451   /* Build an MSS option */\r
452   optdata = htonl(((u32_t)2 << 24) | \r
453       ((u32_t)4 << 16) | \r
454       (((u32_t)pcb->mss / 256) << 8) |\r
455       (pcb->mss & 255));\r
456 \r
457   ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, (u8_t *)&optdata, 4);\r
458   if (ret == ERR_OK) { \r
459     tcp_output(pcb);\r
460   }\r
461   return ret;\r
462\r
463 \r
464 /**\r
465  * Called every 500 ms and implements the retransmission timer and the timer that\r
466  * removes PCBs that have been in TIME-WAIT for enough time. It also increments\r
467  * various timers such as the inactivity timer in each PCB.\r
468  */\r
469 void\r
470 tcp_slowtmr(void)\r
471 {\r
472   struct tcp_pcb *pcb, *pcb2, *prev;\r
473   u32_t eff_wnd;\r
474   u8_t pcb_remove;      /* flag if a PCB should be removed */\r
475   err_t err;\r
476 \r
477   err = ERR_OK;\r
478 \r
479   ++tcp_ticks;\r
480 \r
481   /* Steps through all of the active PCBs. */\r
482   prev = NULL;\r
483   pcb = tcp_active_pcbs;\r
484   if (pcb == NULL) {\r
485     LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n"));\r
486   }\r
487   while (pcb != NULL) {\r
488     LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n"));\r
489     LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED);\r
490     LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN);\r
491     LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT);\r
492 \r
493     pcb_remove = 0;\r
494 \r
495     if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) {\r
496       ++pcb_remove;\r
497       LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n"));\r
498     }\r
499     else if (pcb->nrtx == TCP_MAXRTX) {\r
500       ++pcb_remove;\r
501       LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n"));\r
502     } else {\r
503       ++pcb->rtime;\r
504       if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {\r
505 \r
506         /* Time for a retransmission. */\r
507         LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"U16_F" pcb->rto %"U16_F"\n",\r
508           pcb->rtime, pcb->rto));\r
509 \r
510         /* Double retransmission time-out unless we are trying to\r
511          * connect to somebody (i.e., we are in SYN_SENT). */\r
512         if (pcb->state != SYN_SENT) {\r
513           pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];\r
514         }\r
515         /* Reduce congestion window and ssthresh. */\r
516         eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);\r
517         pcb->ssthresh = eff_wnd >> 1;\r
518         if (pcb->ssthresh < pcb->mss) {\r
519           pcb->ssthresh = pcb->mss * 2;\r
520         }\r
521         pcb->cwnd = pcb->mss;\r
522         LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F" ssthresh %"U16_F"\n",\r
523                                 pcb->cwnd, pcb->ssthresh));\r
524  \r
525         /* The following needs to be called AFTER cwnd is set to one mss - STJ */\r
526         tcp_rexmit_rto(pcb);\r
527      }\r
528     }\r
529     /* Check if this PCB has stayed too long in FIN-WAIT-2 */\r
530     if (pcb->state == FIN_WAIT_2) {\r
531       if ((u32_t)(tcp_ticks - pcb->tmr) >\r
532         TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {\r
533         ++pcb_remove;\r
534         LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n"));\r
535       }\r
536     }\r
537 \r
538    /* Check if KEEPALIVE should be sent */\r
539    if((pcb->so_options & SOF_KEEPALIVE) && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) {\r
540       if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)  {\r
541          LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n",\r
542                                  ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),\r
543                                  ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));\r
544 \r
545          tcp_abort(pcb);\r
546       }\r
547       else if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + pcb->keep_cnt * TCP_KEEPINTVL) / TCP_SLOW_INTERVAL) {\r
548          tcp_keepalive(pcb);\r
549          pcb->keep_cnt++;\r
550       }\r
551    }\r
552 \r
553     /* If this PCB has queued out of sequence data, but has been\r
554        inactive for too long, will drop the data (it will eventually\r
555        be retransmitted). */\r
556 #if TCP_QUEUE_OOSEQ    \r
557     if (pcb->ooseq != NULL &&\r
558        (u32_t)tcp_ticks - pcb->tmr >=\r
559        pcb->rto * TCP_OOSEQ_TIMEOUT) {\r
560       tcp_segs_free(pcb->ooseq);\r
561       pcb->ooseq = NULL;\r
562       LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n"));\r
563     }\r
564 #endif /* TCP_QUEUE_OOSEQ */\r
565 \r
566     /* Check if this PCB has stayed too long in SYN-RCVD */\r
567     if (pcb->state == SYN_RCVD) {\r
568       if ((u32_t)(tcp_ticks - pcb->tmr) >\r
569         TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) {\r
570         ++pcb_remove;\r
571         LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n"));\r
572       }\r
573     }\r
574 \r
575     /* Check if this PCB has stayed too long in LAST-ACK */\r
576     if (pcb->state == LAST_ACK) {\r
577       if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {\r
578         ++pcb_remove;\r
579         LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n"));\r
580       }\r
581     }\r
582 \r
583     /* If the PCB should be removed, do it. */\r
584     if (pcb_remove) {\r
585       tcp_pcb_purge(pcb);      \r
586       /* Remove PCB from tcp_active_pcbs list. */\r
587       if (prev != NULL) {\r
588   LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs);\r
589         prev->next = pcb->next;\r
590       } else {\r
591         /* This PCB was the first. */\r
592         LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb);\r
593         tcp_active_pcbs = pcb->next;\r
594       }\r
595 \r
596       TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);\r
597 \r
598       pcb2 = pcb->next;\r
599       memp_free(MEMP_TCP_PCB, pcb);\r
600       pcb = pcb2;\r
601     } else {\r
602 \r
603       /* We check if we should poll the connection. */\r
604       ++pcb->polltmr;\r
605       if (pcb->polltmr >= pcb->pollinterval) {\r
606         pcb->polltmr = 0;\r
607         LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));\r
608         TCP_EVENT_POLL(pcb, err);\r
609         if (err == ERR_OK) {\r
610           tcp_output(pcb);\r
611         }\r
612       }\r
613       \r
614       prev = pcb;\r
615       pcb = pcb->next;\r
616     }\r
617   }\r
618 \r
619   \r
620   /* Steps through all of the TIME-WAIT PCBs. */\r
621   prev = NULL;    \r
622   pcb = tcp_tw_pcbs;\r
623   while (pcb != NULL) {\r
624     LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);\r
625     pcb_remove = 0;\r
626 \r
627     /* Check if this PCB has stayed long enough in TIME-WAIT */\r
628     if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {\r
629       ++pcb_remove;\r
630     }\r
631     \r
632 \r
633 \r
634     /* If the PCB should be removed, do it. */\r
635     if (pcb_remove) {\r
636       tcp_pcb_purge(pcb);      \r
637       /* Remove PCB from tcp_tw_pcbs list. */\r
638       if (prev != NULL) {\r
639   LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs);\r
640         prev->next = pcb->next;\r
641       } else {\r
642         /* This PCB was the first. */\r
643         LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);\r
644         tcp_tw_pcbs = pcb->next;\r
645       }\r
646       pcb2 = pcb->next;\r
647       memp_free(MEMP_TCP_PCB, pcb);\r
648       pcb = pcb2;\r
649     } else {\r
650       prev = pcb;\r
651       pcb = pcb->next;\r
652     }\r
653   }\r
654 }\r
655 \r
656 /**\r
657  * Is called every TCP_FAST_INTERVAL (250 ms) and sends delayed ACKs.\r
658  */\r
659 void\r
660 tcp_fasttmr(void)\r
661 {\r
662   struct tcp_pcb *pcb;\r
663 \r
664   /* send delayed ACKs */  \r
665   for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\r
666     if (pcb->flags & TF_ACK_DELAY) {\r
667       LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));\r
668       tcp_ack_now(pcb);\r
669       pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);\r
670     }\r
671   }\r
672 }\r
673 \r
674 /**\r
675  * Deallocates a list of TCP segments (tcp_seg structures).\r
676  *\r
677  */\r
678 u8_t\r
679 tcp_segs_free(struct tcp_seg *seg)\r
680 {\r
681   u8_t count = 0;\r
682   struct tcp_seg *next;\r
683   while (seg != NULL) {\r
684     next = seg->next;\r
685     count += tcp_seg_free(seg);\r
686     seg = next;\r
687   }\r
688   return count;\r
689 }\r
690 \r
691 /**\r
692  * Frees a TCP segment.\r
693  *\r
694  */\r
695 u8_t\r
696 tcp_seg_free(struct tcp_seg *seg)\r
697 {\r
698   u8_t count = 0;\r
699   \r
700   if (seg != NULL) {\r
701     if (seg->p != NULL) {\r
702       count = pbuf_free(seg->p);\r
703 #if TCP_DEBUG\r
704       seg->p = NULL;\r
705 #endif /* TCP_DEBUG */\r
706     }\r
707     memp_free(MEMP_TCP_SEG, seg);\r
708   }\r
709   return count;\r
710 }\r
711 \r
712 /**\r
713  * Sets the priority of a connection.\r
714  *\r
715  */\r
716 void\r
717 tcp_setprio(struct tcp_pcb *pcb, u8_t prio)\r
718 {\r
719   pcb->prio = prio;\r
720 }\r
721 #if TCP_QUEUE_OOSEQ\r
722 \r
723 /**\r
724  * Returns a copy of the given TCP segment.\r
725  *\r
726  */ \r
727 struct tcp_seg *\r
728 tcp_seg_copy(struct tcp_seg *seg)\r
729 {\r
730   struct tcp_seg *cseg;\r
731 \r
732   cseg = memp_malloc(MEMP_TCP_SEG);\r
733   if (cseg == NULL) {\r
734     return NULL;\r
735   }\r
736   memcpy((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); \r
737   pbuf_ref(cseg->p);\r
738   return cseg;\r
739 }\r
740 #endif\r
741 \r
742 #if LWIP_CALLBACK_API\r
743 static err_t\r
744 tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)\r
745 {\r
746   arg = arg;\r
747   if (p != NULL) {\r
748     pbuf_free(p);\r
749   } else if (err == ERR_OK) {\r
750     return tcp_close(pcb);\r
751   }\r
752   return ERR_OK;\r
753 }\r
754 #endif /* LWIP_CALLBACK_API */\r
755 \r
756 static void\r
757 tcp_kill_prio(u8_t prio)\r
758 {\r
759   struct tcp_pcb *pcb, *inactive;\r
760   u32_t inactivity;\r
761   u8_t mprio;\r
762 \r
763 \r
764   mprio = TCP_PRIO_MAX;\r
765   \r
766   /* We kill the oldest active connection that has lower priority than\r
767      prio. */\r
768   inactivity = 0;\r
769   inactive = NULL;\r
770   for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\r
771     if (pcb->prio <= prio &&\r
772        pcb->prio <= mprio &&\r
773        (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {\r
774       inactivity = tcp_ticks - pcb->tmr;\r
775       inactive = pcb;\r
776       mprio = pcb->prio;\r
777     }\r
778   }\r
779   if (inactive != NULL) {\r
780     LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n",\r
781            (void *)inactive, inactivity));\r
782     tcp_abort(inactive);\r
783   }      \r
784 }\r
785 \r
786 \r
787 static void\r
788 tcp_kill_timewait(void)\r
789 {\r
790   struct tcp_pcb *pcb, *inactive;\r
791   u32_t inactivity;\r
792 \r
793   inactivity = 0;\r
794   inactive = NULL;\r
795   for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {\r
796     if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {\r
797       inactivity = tcp_ticks - pcb->tmr;\r
798       inactive = pcb;\r
799     }\r
800   }\r
801   if (inactive != NULL) {\r
802     LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n",\r
803            (void *)inactive, inactivity));\r
804     tcp_abort(inactive);\r
805   }      \r
806 }\r
807 \r
808 \r
809 \r
810 struct tcp_pcb *\r
811 tcp_alloc(u8_t prio)\r
812 {\r
813   struct tcp_pcb *pcb;\r
814   u32_t iss;\r
815   \r
816   pcb = memp_malloc(MEMP_TCP_PCB);\r
817   if (pcb == NULL) {\r
818     /* Try killing oldest connection in TIME-WAIT. */\r
819     LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n"));\r
820     tcp_kill_timewait();\r
821     pcb = memp_malloc(MEMP_TCP_PCB);\r
822     if (pcb == NULL) {\r
823       tcp_kill_prio(prio);    \r
824       pcb = memp_malloc(MEMP_TCP_PCB);\r
825     }\r
826   }\r
827   if (pcb != NULL) {\r
828     memset(pcb, 0, sizeof(struct tcp_pcb));\r
829     pcb->prio = TCP_PRIO_NORMAL;\r
830     pcb->snd_buf = TCP_SND_BUF;\r
831     pcb->snd_queuelen = 0;\r
832     pcb->rcv_wnd = TCP_WND;\r
833     pcb->tos = 0;\r
834     pcb->ttl = TCP_TTL;\r
835     pcb->mss = TCP_MSS;\r
836     pcb->rto = 3000 / TCP_SLOW_INTERVAL;\r
837     pcb->sa = 0;\r
838     pcb->sv = 3000 / TCP_SLOW_INTERVAL;\r
839     pcb->rtime = 0;\r
840     pcb->cwnd = 1;\r
841     iss = tcp_next_iss();\r
842     pcb->snd_wl2 = iss;\r
843     pcb->snd_nxt = iss;\r
844     pcb->snd_max = iss;\r
845     pcb->lastack = iss;\r
846     pcb->snd_lbb = iss;   \r
847     pcb->tmr = tcp_ticks;\r
848 \r
849     pcb->polltmr = 0;\r
850 \r
851 #if LWIP_CALLBACK_API\r
852     pcb->recv = tcp_recv_null;\r
853 #endif /* LWIP_CALLBACK_API */  \r
854     \r
855     /* Init KEEPALIVE timer */\r
856     pcb->keepalive = TCP_KEEPDEFAULT;\r
857     pcb->keep_cnt = 0;\r
858   }\r
859   return pcb;\r
860 }\r
861 \r
862 /**\r
863  * Creates a new TCP protocol control block but doesn't place it on\r
864  * any of the TCP PCB lists.\r
865  *\r
866  * @internal: Maybe there should be a idle TCP PCB list where these\r
867  * PCBs are put on. We can then implement port reservation using\r
868  * tcp_bind(). Currently, we lack this (BSD socket type of) feature.\r
869  */\r
870 \r
871 struct tcp_pcb *\r
872 tcp_new(void)\r
873 {\r
874   return tcp_alloc(TCP_PRIO_NORMAL);\r
875 }\r
876 \r
877 /*\r
878  * tcp_arg():\r
879  *\r
880  * Used to specify the argument that should be passed callback\r
881  * functions.\r
882  *\r
883  */ \r
884 \r
885 void\r
886 tcp_arg(struct tcp_pcb *pcb, void *arg)\r
887 {  \r
888   pcb->callback_arg = arg;\r
889 }\r
890 #if LWIP_CALLBACK_API\r
891 \r
892 /**\r
893  * Used to specify the function that should be called when a TCP\r
894  * connection receives data.\r
895  *\r
896  */ \r
897 void\r
898 tcp_recv(struct tcp_pcb *pcb,\r
899    err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err))\r
900 {\r
901   pcb->recv = recv;\r
902 }\r
903 \r
904 /**\r
905  * Used to specify the function that should be called when TCP data\r
906  * has been successfully delivered to the remote host.\r
907  *\r
908  */ \r
909 \r
910 void\r
911 tcp_sent(struct tcp_pcb *pcb,\r
912    err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len))\r
913 {\r
914   pcb->sent = sent;\r
915 }\r
916 \r
917 /**\r
918  * Used to specify the function that should be called when a fatal error\r
919  * has occured on the connection.\r
920  *\r
921  */ \r
922 void\r
923 tcp_err(struct tcp_pcb *pcb,\r
924    void (* errf)(void *arg, err_t err))\r
925 {\r
926   pcb->errf = errf;\r
927 }\r
928 \r
929 /**\r
930  * Used for specifying the function that should be called when a\r
931  * LISTENing connection has been connected to another host.\r
932  *\r
933  */ \r
934 void\r
935 tcp_accept(struct tcp_pcb *pcb,\r
936      err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err))\r
937 {\r
938   ((struct tcp_pcb_listen *)pcb)->accept = accept;\r
939 }\r
940 #endif /* LWIP_CALLBACK_API */\r
941 \r
942 \r
943 /**\r
944  * Used to specify the function that should be called periodically\r
945  * from TCP. The interval is specified in terms of the TCP coarse\r
946  * timer interval, which is called twice a second.\r
947  *\r
948  */ \r
949 void\r
950 tcp_poll(struct tcp_pcb *pcb,\r
951    err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval)\r
952 {\r
953 #if LWIP_CALLBACK_API\r
954   pcb->poll = poll;\r
955 #endif /* LWIP_CALLBACK_API */  \r
956   pcb->pollinterval = interval;\r
957 }\r
958 \r
959 /**\r
960  * Purges a TCP PCB. Removes any buffered data and frees the buffer memory.\r
961  *\r
962  */\r
963 void\r
964 tcp_pcb_purge(struct tcp_pcb *pcb)\r
965 {\r
966   if (pcb->state != CLOSED &&\r
967      pcb->state != TIME_WAIT &&\r
968      pcb->state != LISTEN) {\r
969 \r
970     LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n"));\r
971     \r
972     if (pcb->unsent != NULL) {    \r
973       LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n"));\r
974     }\r
975     if (pcb->unacked != NULL) {    \r
976       LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n"));\r
977     }\r
978 #if TCP_QUEUE_OOSEQ /* LW */\r
979     if (pcb->ooseq != NULL) {    \r
980       LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n"));\r
981     }\r
982     \r
983     tcp_segs_free(pcb->ooseq);\r
984     pcb->ooseq = NULL;\r
985 #endif /* TCP_QUEUE_OOSEQ */\r
986     tcp_segs_free(pcb->unsent);\r
987     tcp_segs_free(pcb->unacked);\r
988     pcb->unacked = pcb->unsent = NULL;\r
989   }\r
990 }\r
991 \r
992 /**\r
993  * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.\r
994  *\r
995  */\r
996 void\r
997 tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)\r
998 {\r
999   TCP_RMV(pcblist, pcb);\r
1000 \r
1001   tcp_pcb_purge(pcb);\r
1002   \r
1003   /* if there is an outstanding delayed ACKs, send it */\r
1004   if (pcb->state != TIME_WAIT &&\r
1005      pcb->state != LISTEN &&\r
1006      pcb->flags & TF_ACK_DELAY) {\r
1007     pcb->flags |= TF_ACK_NOW;\r
1008     tcp_output(pcb);\r
1009   }  \r
1010   pcb->state = CLOSED;\r
1011 \r
1012   LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane());\r
1013 }\r
1014 \r
1015 /**\r
1016  * Calculates a new initial sequence number for new connections.\r
1017  *\r
1018  */\r
1019 u32_t\r
1020 tcp_next_iss(void)\r
1021 {\r
1022   static u32_t iss = 6510;\r
1023   \r
1024   iss += tcp_ticks;       /* XXX */\r
1025   return iss;\r
1026 }\r
1027 \r
1028 #if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG\r
1029 void\r
1030 tcp_debug_print(struct tcp_hdr *tcphdr)\r
1031 {\r
1032   LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n"));\r
1033   LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));\r
1034   LWIP_DEBUGF(TCP_DEBUG, ("|    %5"U16_F"      |    %5"U16_F"      | (src port, dest port)\n",\r
1035          ntohs(tcphdr->src), ntohs(tcphdr->dest)));\r
1036   LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));\r
1037   LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (seq no)\n",\r
1038           ntohl(tcphdr->seqno)));\r
1039   LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));\r
1040   LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (ack no)\n",\r
1041          ntohl(tcphdr->ackno)));\r
1042   LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));\r
1043   LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" |   |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"|     %5"U16_F"     | (hdrlen, flags (",\r
1044        TCPH_HDRLEN(tcphdr),\r
1045          TCPH_FLAGS(tcphdr) >> 5 & 1,\r
1046          TCPH_FLAGS(tcphdr) >> 4 & 1,\r
1047          TCPH_FLAGS(tcphdr) >> 3 & 1,\r
1048          TCPH_FLAGS(tcphdr) >> 2 & 1,\r
1049          TCPH_FLAGS(tcphdr) >> 1 & 1,\r
1050          TCPH_FLAGS(tcphdr) & 1,\r
1051          ntohs(tcphdr->wnd)));\r
1052   tcp_debug_print_flags(TCPH_FLAGS(tcphdr));\r
1053   LWIP_DEBUGF(TCP_DEBUG, ("), win)\n"));\r
1054   LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));\r
1055   LWIP_DEBUGF(TCP_DEBUG, ("|    0x%04"X16_F"     |     %5"U16_F"     | (chksum, urgp)\n",\r
1056          ntohs(tcphdr->chksum), ntohs(tcphdr->urgp)));\r
1057   LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));\r
1058 }\r
1059 \r
1060 void\r
1061 tcp_debug_print_state(enum tcp_state s)\r
1062 {\r
1063   LWIP_DEBUGF(TCP_DEBUG, ("State: "));\r
1064   switch (s) {\r
1065   case CLOSED:\r
1066     LWIP_DEBUGF(TCP_DEBUG, ("CLOSED\n"));\r
1067     break;\r
1068  case LISTEN:\r
1069    LWIP_DEBUGF(TCP_DEBUG, ("LISTEN\n"));\r
1070    break;\r
1071   case SYN_SENT:\r
1072     LWIP_DEBUGF(TCP_DEBUG, ("SYN_SENT\n"));\r
1073     break;\r
1074   case SYN_RCVD:\r
1075     LWIP_DEBUGF(TCP_DEBUG, ("SYN_RCVD\n"));\r
1076     break;\r
1077   case ESTABLISHED:\r
1078     LWIP_DEBUGF(TCP_DEBUG, ("ESTABLISHED\n"));\r
1079     break;\r
1080   case FIN_WAIT_1:\r
1081     LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_1\n"));\r
1082     break;\r
1083   case FIN_WAIT_2:\r
1084     LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_2\n"));\r
1085     break;\r
1086   case CLOSE_WAIT:\r
1087     LWIP_DEBUGF(TCP_DEBUG, ("CLOSE_WAIT\n"));\r
1088     break;\r
1089   case CLOSING:\r
1090     LWIP_DEBUGF(TCP_DEBUG, ("CLOSING\n"));\r
1091     break;\r
1092   case LAST_ACK:\r
1093     LWIP_DEBUGF(TCP_DEBUG, ("LAST_ACK\n"));\r
1094     break;\r
1095   case TIME_WAIT:\r
1096     LWIP_DEBUGF(TCP_DEBUG, ("TIME_WAIT\n"));\r
1097    break;\r
1098   }\r
1099 }\r
1100 \r
1101 void\r
1102 tcp_debug_print_flags(u8_t flags)\r
1103 {\r
1104   if (flags & TCP_FIN) {\r
1105     LWIP_DEBUGF(TCP_DEBUG, ("FIN "));\r
1106   }\r
1107   if (flags & TCP_SYN) {\r
1108     LWIP_DEBUGF(TCP_DEBUG, ("SYN "));\r
1109   }\r
1110   if (flags & TCP_RST) {\r
1111     LWIP_DEBUGF(TCP_DEBUG, ("RST "));\r
1112   }\r
1113   if (flags & TCP_PSH) {\r
1114     LWIP_DEBUGF(TCP_DEBUG, ("PSH "));\r
1115   }\r
1116   if (flags & TCP_ACK) {\r
1117     LWIP_DEBUGF(TCP_DEBUG, ("ACK "));\r
1118   }\r
1119   if (flags & TCP_URG) {\r
1120     LWIP_DEBUGF(TCP_DEBUG, ("URG "));\r
1121   }\r
1122   if (flags & TCP_ECE) {\r
1123     LWIP_DEBUGF(TCP_DEBUG, ("ECE "));\r
1124   }\r
1125   if (flags & TCP_CWR) {\r
1126     LWIP_DEBUGF(TCP_DEBUG, ("CWR "));\r
1127   }\r
1128 }\r
1129 \r
1130 void\r
1131 tcp_debug_print_pcbs(void)\r
1132 {\r
1133   struct tcp_pcb *pcb;\r
1134   LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n"));\r
1135   for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\r
1136     LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",\r
1137                        pcb->local_port, pcb->remote_port,\r
1138                        pcb->snd_nxt, pcb->rcv_nxt));\r
1139     tcp_debug_print_state(pcb->state);\r
1140   }    \r
1141   LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n"));\r
1142   for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {\r
1143     LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",\r
1144                        pcb->local_port, pcb->remote_port,\r
1145                        pcb->snd_nxt, pcb->rcv_nxt));\r
1146     tcp_debug_print_state(pcb->state);\r
1147   }    \r
1148   LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n"));\r
1149   for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {\r
1150     LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",\r
1151                        pcb->local_port, pcb->remote_port,\r
1152                        pcb->snd_nxt, pcb->rcv_nxt));\r
1153     tcp_debug_print_state(pcb->state);\r
1154   }    \r
1155 }\r
1156 \r
1157 s16_t\r
1158 tcp_pcbs_sane(void)\r
1159 {\r
1160   struct tcp_pcb *pcb;\r
1161   for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\r
1162     LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED);\r
1163     LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN);\r
1164     LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);\r
1165   }\r
1166   for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {\r
1167     LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);\r
1168   }\r
1169   return 1;\r
1170 }\r
1171 #endif /* TCP_DEBUG */\r
1172 #endif /* LWIP_TCP */\r
1173 \r
1174 \r
1175 \r
1176 \r
1177 \r
1178 \r
1179 \r
1180 \r
1181 \r
1182 \r