Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

tcp.c

Go to the documentation of this file.
00001 
00007 /*
00008  * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
00009  * All rights reserved. 
00010  * 
00011  * Redistribution and use in source and binary forms, with or without modification, 
00012  * are permitted provided that the following conditions are met:
00013  *
00014  * 1. Redistributions of source code must retain the above copyright notice,
00015  *    this list of conditions and the following disclaimer.
00016  * 2. Redistributions in binary form must reproduce the above copyright notice,
00017  *    this list of conditions and the following disclaimer in the documentation
00018  *    and/or other materials provided with the distribution.
00019  * 3. The name of the author may not be used to endorse or promote products
00020  *    derived from this software without specific prior written permission. 
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
00023  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
00024  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
00025  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00026  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
00027  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
00028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
00029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
00030  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
00031  * OF SUCH DAMAGE.
00032  *
00033  * This file is part of the lwIP TCP/IP stack.
00034  * 
00035  * Author: Adam Dunkels <adam@sics.se>
00036  *
00037  * CHANGELOG: this file has been modified by Sergio Perez Alcañiz <serpeal@disca.upv.es> 
00038  *            Departamento de Informática de Sistemas y Computadores          
00039  *            Universidad Politécnica de Valencia                             
00040  *            Valencia (Spain)    
00041  *            Date: April 2003                                          
00042  *  
00043  */
00044 
00045 /*-----------------------------------------------------------------------------------*/
00046 /* tcp.c
00047  *
00048  * This file contains common functions for the TCP implementation, such as functinos
00049  * for manipulating the data structures and the TCP timer functions. TCP functions
00050  * related to input and output is found in tcp_input.c and tcp_output.c respectively.
00051  *
00052  */
00053 /*-----------------------------------------------------------------------------------*/
00054 
00055 
00056 #include "lwip/opt.h"
00057 #include "lwip/def.h"
00058 #include "lwip/mem.h"
00059 #include "lwip/memp.h"
00060 
00061 #include "lwip/tcp.h"
00062 
00063 #define htons HTONS
00064 #define htonl HTONL
00065 
00066 #if LWIP_TCP
00067 
00068 /* Incremented every coarse grained timer shot
00069    (typically every 500 ms, determined by TCP_COARSE_TIMEOUT). */
00070 u32_t tcp_ticks;
00071 const u8_t tcp_backoff[13] =
00072     { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};
00073 
00074 /* The TCP PCB lists. */
00075 struct tcp_pcb_listen *tcp_listen_pcbs;  /* List of all TCP PCBs in LISTEN state. */
00076 struct tcp_pcb *tcp_active_pcbs;  /* List of all TCP PCBs that are in a
00077                                  state in which they accept or send
00078                                  data. */
00079 struct tcp_pcb *tcp_tw_pcbs;      /* List of all TCP PCBs in TIME-WAIT. */
00080 
00081 struct tcp_pcb *tcp_tmp_pcb;
00082 
00083 #define MIN(x,y) (x) < (y)? (x): (y)
00084 
00085 static u8_t tcp_timer;
00086 
00087 static u16_t tcp_new_port(void);
00088 
00089 /*-----------------------------------------------------------------------------------*/
00090 /*
00091  * tcp_init():
00092  *
00093  * Initializes the TCP layer.
00094  */
00095 /*-----------------------------------------------------------------------------------*/
00096 void
00097 tcp_init(void)
00098 {
00099   /* Clear globals. */
00100   tcp_listen_pcbs = NULL;
00101   tcp_active_pcbs = NULL;
00102   tcp_tw_pcbs = NULL;
00103   tcp_tmp_pcb = NULL;
00104   
00105   /* initialize timer */
00106   tcp_ticks = 0;
00107   tcp_timer = 0;
00108   
00109 }
00110 /*-----------------------------------------------------------------------------------*/
00111 /*
00112  * tcp_tmr():
00113  *
00114  * Called periodically to dispatch TCP timers.
00115  *
00116  */
00117 /*-----------------------------------------------------------------------------------*/
00118 void
00119 tcp_tmr(void)
00120 {
00121   ++tcp_timer;
00122   if(tcp_timer == 10) {
00123     tcp_timer = 0;
00124   }
00125   
00126   if(tcp_timer & 1) {
00127     /* Call tcp_fasttmr() every 200 ms, i.e., every other timer
00128        tcp_tmr() is called. */
00129     tcp_fasttmr();
00130   }
00131   if(tcp_timer == 0 || tcp_timer == 5) {
00132     /* Call tcp_slowtmr() every 500 ms, i.e., every fifth timer
00133        tcp_tmr() is called. */
00134     tcp_slowtmr();
00135   }
00136 }
00137 /*-----------------------------------------------------------------------------------*/
00138 /*
00139  * tcp_close():
00140  *
00141  * Closes the connection held by the PCB.
00142  *
00143  */
00144 /*-----------------------------------------------------------------------------------*/
00145 err_t
00146 tcp_close(struct tcp_pcb *pcb)
00147 {
00148   err_t err;
00149 
00150 #if TCP_DEBUG
00151   DEBUGF(TCP_DEBUG, ("tcp_close: closing in state "));
00152   tcp_debug_print_state(pcb->state);
00153   DEBUGF(TCP_DEBUG, ("\n"));
00154 #endif /* TCP_DEBUG */
00155   switch(pcb->state) {
00156   case LISTEN:
00157     err = ERR_OK;
00158     tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs, pcb);
00159     memp_free(MEMP_TCP_PCB_LISTEN, pcb);
00160     pcb = NULL;
00161     break;
00162   case SYN_SENT:
00163     err = ERR_OK;
00164     tcp_pcb_remove(&tcp_active_pcbs, pcb);
00165     memp_free(MEMP_TCP_PCB, pcb);
00166     pcb = NULL;
00167     break;
00168   case SYN_RCVD:
00169     err = tcp_send_ctrl(pcb, TCP_FIN);
00170     if(err == ERR_OK) {
00171       pcb->state = FIN_WAIT_1;
00172     }
00173     break;
00174   case ESTABLISHED:
00175     err = tcp_send_ctrl(pcb, TCP_FIN);
00176     if(err == ERR_OK) {
00177       pcb->state = FIN_WAIT_1;
00178     }
00179     break;
00180   case CLOSE_WAIT:
00181     err = tcp_send_ctrl(pcb, TCP_FIN);
00182     if(err == ERR_OK) {
00183       pcb->state = LAST_ACK;
00184     }
00185     break;
00186   default:
00187     /* Has already been closed, do nothing. */
00188     err = ERR_OK;
00189     pcb = NULL;
00190     break;
00191   }
00192 
00193   if(pcb != NULL && err == ERR_OK) {
00194     err = tcp_output(pcb);
00195   }
00196   return err;
00197 }
00198 /*-----------------------------------------------------------------------------------*/
00199 /*
00200  * tcp_abort()
00201  *
00202  * Aborts a connection by sending a RST to the remote host and deletes
00203  * the local protocol control block. This is done when a connection is
00204  * killed because of shortage of memory.
00205  *
00206  */
00207 /*-----------------------------------------------------------------------------------*/
00208 void
00209 tcp_abort(struct tcp_pcb *pcb)
00210 {
00211   u32_t seqno, ackno;
00212   u16_t remote_port, local_port;
00213   struct ip_addr remote_ip, local_ip;
00214 #if LWIP_CALLBACK_API  
00215   void (* errf)(void *arg, err_t err);
00216 #endif /* LWIP_CALLBACK_API */
00217   void *errf_arg;
00218 
00219   
00220   /* Figure out on which TCP PCB list we are, and remove us. If we
00221      are in an active state, call the receive function associated with
00222      the PCB with a NULL argument, and send an RST to the remote end. */
00223   if(pcb->state == TIME_WAIT) {
00224     tcp_pcb_remove(&tcp_tw_pcbs, pcb);
00225     memp_free(MEMP_TCP_PCB, pcb);
00226   } else {
00227     seqno = pcb->snd_nxt;
00228     ackno = pcb->rcv_nxt;
00229     ip_addr_set(&local_ip, &(pcb->local_ip));
00230     ip_addr_set(&remote_ip, &(pcb->remote_ip));
00231     local_port = pcb->local_port;
00232     remote_port = pcb->remote_port;
00233 #if LWIP_CALLBACK_API
00234     errf = pcb->errf;
00235 #endif /* LWIP_CALLBACK_API */
00236     errf_arg = pcb->callback_arg;
00237     tcp_pcb_remove(&tcp_active_pcbs, pcb);
00238     if(pcb->unacked != NULL) {
00239       tcp_segs_free(pcb->unacked);
00240     }
00241     if(pcb->unsent != NULL) {
00242       tcp_segs_free(pcb->unsent);
00243     }
00244 #if TCP_QUEUE_OOSEQ    
00245     if(pcb->ooseq != NULL) {
00246       tcp_segs_free(pcb->ooseq);
00247     }
00248 #endif /* TCP_QUEUE_OOSEQ */
00249     memp_free(MEMP_TCP_PCB, pcb);
00250     TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
00251     DEBUGF(TCP_RST_DEBUG, ("tcp_abort: sending RST\n"));
00252     tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);
00253   }
00254 }
00255 /*-----------------------------------------------------------------------------------*/
00256 /*
00257  * tcp_bind():
00258  *
00259  * Binds the connection to a local portnumber and IP address. If the
00260  * IP address is not given (i.e., ipaddr == NULL), the IP address of
00261  * the outgoing network interface is used instead.
00262  *
00263  */
00264 /*-----------------------------------------------------------------------------------*/
00265 err_t
00266 tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
00267 {
00268   struct tcp_pcb *cpcb;
00269 
00270   if(port == 0) {
00271     port = tcp_new_port();
00272   }
00273 
00274   /* Check if the address already is in use. */
00275   for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs;
00276       cpcb != NULL; cpcb = cpcb->next) {
00277     if(cpcb->local_port == port) {
00278       if(ip_addr_isany(&(cpcb->local_ip)) ||
00279          ip_addr_isany(ipaddr) ||
00280          ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
00281         return ERR_USE;
00282       }
00283     }
00284   }
00285   for(cpcb = tcp_active_pcbs;
00286       cpcb != NULL; cpcb = cpcb->next) {
00287     if(cpcb->local_port == port) {
00288       if(ip_addr_isany(&(cpcb->local_ip)) ||
00289          ip_addr_isany(ipaddr) ||
00290          ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
00291         return ERR_USE;
00292       }
00293     }
00294   }
00295   if(!ip_addr_isany(ipaddr)) {
00296     pcb->local_ip = *ipaddr;
00297   }
00298   pcb->local_port = port;
00299   DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %u\n", port));
00300   return ERR_OK;
00301 }
00302 #if LWIP_CALLBACK_API
00303 static err_t
00304 tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err)
00305 {
00306   return ERR_ABRT;
00307 }
00308 #endif /* LWIP_CALLBACK_API */
00309 /*-----------------------------------------------------------------------------------*/
00310 /*
00311  * tcp_listen():
00312  *
00313  * Set the state of the connection to be LISTEN, which means that it
00314  * is able to accept incoming connections. The protocol control block
00315  * is reallocated in order to consume less memory. Setting the
00316  * connection to LISTEN is an irreversible process.
00317  *
00318  */
00319 /*-----------------------------------------------------------------------------------*/
00320 struct tcp_pcb *
00321 tcp_listen(struct tcp_pcb *pcb)
00322 {
00323   struct tcp_pcb_listen *lpcb;
00324 
00325   /* already listening? */
00326   if(pcb->state == LISTEN) {
00327     return pcb;
00328   }
00329   lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN);
00330   if(lpcb == NULL) {
00331     return NULL;
00332   }
00333   lpcb->callback_arg = pcb->callback_arg;
00334   lpcb->local_port = pcb->local_port;
00335   lpcb->state = LISTEN;
00336   ip_addr_set(&lpcb->local_ip, &pcb->local_ip);
00337   memp_free(MEMP_TCP_PCB, pcb);
00338 #if LWIP_CALLBACK_API
00339   lpcb->accept = tcp_accept_null;
00340 #endif /* LWIP_CALLBACK_API */
00341   TCP_REG(&tcp_listen_pcbs, lpcb);
00342   return (struct tcp_pcb *)lpcb;
00343 }
00344 /*-----------------------------------------------------------------------------------*/
00345 /*
00346  * tcp_recved():
00347  *
00348  * This function should be called by the application when it has
00349  * processed the data. The purpose is to advertise a larger window
00350  * when the data has been processed.
00351  *
00352  */
00353 /*-----------------------------------------------------------------------------------*/
00354 void
00355 tcp_recved(struct tcp_pcb *pcb, u16_t len)
00356 {
00357   pcb->rcv_wnd += len;
00358   if(pcb->rcv_wnd > TCP_WND) {
00359     pcb->rcv_wnd = TCP_WND;
00360   }
00361   if(!(pcb->flags & TF_ACK_DELAY) &&
00362      !(pcb->flags & TF_ACK_NOW)) {
00363     tcp_ack(pcb);
00364   }
00365   DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %u bytes, wnd %u (%u).\n",
00366                      len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd));
00367 }
00368 /*-----------------------------------------------------------------------------------*/
00369 /*
00370  * tcp_new_port():
00371  *
00372  * A nastly hack featuring 'goto' statements that allocates a
00373  * new TCP local port.
00374  */
00375 /*-----------------------------------------------------------------------------------*/
00376 static u16_t
00377 tcp_new_port(void)
00378 {
00379   struct tcp_pcb *pcb;
00380 #ifndef TCP_LOCAL_PORT_RANGE_START
00381 #define TCP_LOCAL_PORT_RANGE_START 4096
00382 #define TCP_LOCAL_PORT_RANGE_END   0x7fff
00383 #endif
00384   static u16_t port = TCP_LOCAL_PORT_RANGE_START;
00385   
00386  again:
00387   if(++port > TCP_LOCAL_PORT_RANGE_END) {
00388     port = TCP_LOCAL_PORT_RANGE_START;
00389   }
00390   
00391   for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
00392     if(pcb->local_port == port) {
00393       goto again;
00394     }
00395   }
00396   for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
00397     if(pcb->local_port == port) {
00398       goto again;
00399     }
00400   }
00401   for(pcb = (struct tcp_pcb *)tcp_listen_pcbs; pcb != NULL; pcb = pcb->next) {
00402     if(pcb->local_port == port) {
00403       goto again;
00404     }
00405   }
00406   return port;
00407 }
00408 /*-----------------------------------------------------------------------------------*/
00409 /*
00410  * tcp_connect():
00411  *
00412  * Connects to another host. The function given as the "connected"
00413  * argument will be called when the connection has been established.
00414  *
00415  */
00416 /*-----------------------------------------------------------------------------------*/
00417 err_t
00418 tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,
00419             err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err))
00420 {
00421   u32_t optdata;
00422   err_t ret;
00423   u32_t iss;
00424 
00425   DEBUGF(TCP_DEBUG, ("tcp_connect to port %u\n", port));
00426   if(ipaddr != NULL) {
00427     pcb->remote_ip = *ipaddr;
00428   } else {
00429     return ERR_VAL;
00430   }
00431   pcb->remote_port = port;
00432   if(pcb->local_port == 0) {
00433     pcb->local_port = tcp_new_port();
00434   }
00435   iss = tcp_next_iss();
00436   pcb->rcv_nxt = 0;
00437   pcb->snd_nxt = iss;
00438   pcb->lastack = iss - 1;
00439   pcb->snd_lbb = iss - 1;
00440   pcb->rcv_wnd = TCP_WND;
00441   pcb->snd_wnd = TCP_WND;
00442   pcb->mss = TCP_MSS;
00443   pcb->cwnd = 1;
00444   pcb->ssthresh = pcb->mss * 10;
00445   pcb->state = SYN_SENT;
00446 #if LWIP_CALLBACK_API  
00447   pcb->connected = connected;
00448 #endif /* LWIP_CALLBACK_API */  
00449   TCP_REG(&tcp_active_pcbs, pcb);
00450   
00451   /* Build an MSS option */
00452   optdata = htonl(((u32_t)2 << 24) | 
00453                   ((u32_t)4 << 16) | 
00454                   (((u32_t)pcb->mss / 256) << 8) |
00455                   (pcb->mss & 255));
00456 
00457   ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, (u8_t *)&optdata, 4);
00458   if(ret == ERR_OK) { 
00459     tcp_output(pcb);
00460   }
00461   return ret;
00462 } 
00463 /*-----------------------------------------------------------------------------------*/
00464 /*
00465  * tcp_slowtmr():
00466  *
00467  * Called every 500 ms and implements the retransmission timer and the timer that
00468  * removes PCBs that have been in TIME-WAIT for enough time. It also increments
00469  * various timers such as the inactivity timer in each PCB.
00470  */
00471 /*-----------------------------------------------------------------------------------*/
00472 void
00473 tcp_slowtmr(void)
00474 {
00475   struct tcp_pcb *pcb, *pcb2, *prev;
00476   u32_t eff_wnd;
00477   u8_t pcb_remove;      /* flag if a PCB should be removed */
00478   err_t err;
00479   
00480   err = ERR_OK;
00481 
00482   ++tcp_ticks;
00483   
00484   /* Steps through all of the active PCBs. */
00485   prev = NULL;
00486   pcb = tcp_active_pcbs;
00487   if (pcb == NULL) DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n"));
00488   while(pcb != NULL) {
00489     DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n"));
00490     LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED);
00491     LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN);
00492     LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT);
00493 
00494     pcb_remove = 0;
00495 
00496     if(pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) {
00497       ++pcb_remove;
00498       DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n"));
00499     }
00500     else if(pcb->nrtx == TCP_MAXRTX) {
00501       ++pcb_remove;
00502       DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n"));
00503     } else {
00504       ++pcb->rtime;
00505       if(pcb->unacked != NULL && pcb->rtime >= pcb->rto) {
00506 
00507         /* Time for a retransmission. */
00508         DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %u pcb->rto %u\n",
00509                                pcb->rtime, pcb->rto));
00510 
00511         /* Double retransmission time-out unless we are trying to
00512            connect to somebody (i.e., we are in SYN_SENT). */
00513         if(pcb->state != SYN_SENT) {
00514           pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];
00515         }
00516 
00517         tcp_rexmit(pcb);
00518         
00519         /* Reduce congestion window and ssthresh. */
00520         eff_wnd = MIN(pcb->cwnd, pcb->snd_wnd);
00521         pcb->ssthresh = eff_wnd >> 1;
00522         if(pcb->ssthresh < pcb->mss) {
00523           pcb->ssthresh = pcb->mss * 2;
00524         }
00525         pcb->cwnd = pcb->mss;
00526 
00527         DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %u ssthresh %u\n",
00528                                 pcb->cwnd, pcb->ssthresh));
00529       }
00530     }
00531           
00532     /* Check if this PCB has stayed too long in FIN-WAIT-2 */
00533     if(pcb->state == FIN_WAIT_2) {
00534       if((u32_t)(tcp_ticks - pcb->tmr) >
00535          TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {
00536         ++pcb_remove;
00537         DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n"));
00538       }
00539     }
00540 
00541     /* If this PCB has queued out of sequence data, but has been
00542        inactive for too long, will drop the data (it will eventually
00543        be retransmitted). */
00544 #if TCP_QUEUE_OOSEQ    
00545     if(pcb->ooseq != NULL &&
00546        (u32_t)tcp_ticks - pcb->tmr >=
00547        pcb->rto * TCP_OOSEQ_TIMEOUT) {
00548       tcp_segs_free(pcb->ooseq);
00549       pcb->ooseq = NULL;
00550       DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n"));
00551     }
00552 #endif /* TCP_QUEUE_OOSEQ */
00553 
00554     /* Check if this PCB has stayed too long in SYN-RCVD */
00555     if(pcb->state == SYN_RCVD) {
00556       if((u32_t)(tcp_ticks - pcb->tmr) >
00557          TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) {
00558         ++pcb_remove;
00559         DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n"));
00560       }
00561     }
00562 
00563 
00564     /* If the PCB should be removed, do it. */
00565     if(pcb_remove) {
00566       tcp_pcb_purge(pcb);      
00567       /* Remove PCB from tcp_active_pcbs list. */
00568       if(prev != NULL) {
00569         LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs);
00570         prev->next = pcb->next;
00571       } else {
00572         /* This PCB was the first. */
00573         LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb);
00574         tcp_active_pcbs = pcb->next;
00575       }
00576 
00577       TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);
00578 
00579       pcb2 = pcb->next;
00580       memp_free(MEMP_TCP_PCB, pcb);
00581       pcb = pcb2;
00582     } else {
00583 
00584       /* We check if we should poll the connection. */
00585       ++pcb->polltmr;
00586       if(pcb->polltmr >= pcb->pollinterval) {
00587         pcb->polltmr = 0;
00588         DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));
00589         TCP_EVENT_POLL(pcb, err);
00590         if(err == ERR_OK) {
00591           tcp_output(pcb);
00592         }
00593       }
00594       
00595       prev = pcb;
00596       pcb = pcb->next;
00597     }
00598   }
00599 
00600   
00601   /* Steps through all of the TIME-WAIT PCBs. */
00602   prev = NULL;    
00603   pcb = tcp_tw_pcbs;
00604   while(pcb != NULL) {
00605     LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
00606     pcb_remove = 0;
00607 
00608     /* Check if this PCB has stayed long enough in TIME-WAIT */
00609     if((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {
00610       ++pcb_remove;
00611     }
00612     
00613 
00614 
00615     /* If the PCB should be removed, do it. */
00616     if(pcb_remove) {
00617       tcp_pcb_purge(pcb);      
00618       /* Remove PCB from tcp_tw_pcbs list. */
00619       if(prev != NULL) {
00620         LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs);
00621         prev->next = pcb->next;
00622       } else {
00623         /* This PCB was the first. */
00624         LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);
00625         tcp_tw_pcbs = pcb->next;
00626       }
00627       pcb2 = pcb->next;
00628       memp_free(MEMP_TCP_PCB, pcb);
00629       pcb = pcb2;
00630     } else {
00631       prev = pcb;
00632       pcb = pcb->next;
00633     }
00634   }
00635 }
00636 /*-----------------------------------------------------------------------------------*/
00637 /*
00638  * tcp_fasttmr():
00639  *
00640  * Is called every TCP_FINE_TIMEOUT (100 ms) and sends delayed ACKs.
00641  */
00642 /*-----------------------------------------------------------------------------------*/
00643 void
00644 tcp_fasttmr(void)
00645 {
00646   struct tcp_pcb *pcb;
00647 
00648   /* send delayed ACKs */  
00649   for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
00650     if(pcb->flags & TF_ACK_DELAY) {
00651       DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));
00652       tcp_ack_now(pcb);
00653       pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
00654     }
00655   }
00656 }
00657 /*-----------------------------------------------------------------------------------*/
00658 /*
00659  * tcp_segs_free():
00660  *
00661  * Deallocates a list of TCP segments (tcp_seg structures).
00662  *
00663  */
00664 /*-----------------------------------------------------------------------------------*/
00665 u8_t
00666 tcp_segs_free(struct tcp_seg *seg)
00667 {
00668   u8_t count = 0;
00669   struct tcp_seg *next;
00670  again:  
00671   if(seg != NULL) {
00672     next = seg->next;
00673     count += tcp_seg_free(seg);
00674     seg = next;
00675     goto again;
00676   }
00677   return count;
00678 }
00679 /*-----------------------------------------------------------------------------------*/
00680 /*
00681  * tcp_seg_free():
00682  *
00683  * Frees a TCP segment.
00684  *
00685  */
00686 /*-----------------------------------------------------------------------------------*/
00687 u8_t
00688 tcp_seg_free(struct tcp_seg *seg)
00689 {
00690   u8_t count = 0;
00691   
00692   if(seg != NULL) {
00693     if(seg->p == NULL) {
00694       memp_free(MEMP_TCP_SEG, seg);
00695     } else {
00696       count = pbuf_free(seg->p);
00697 #if TCP_DEBUG
00698       seg->p = NULL;
00699 #endif /* TCP_DEBUG */
00700       memp_free(MEMP_TCP_SEG, seg);
00701     }
00702   }
00703   return count;
00704 }
00705 /*-----------------------------------------------------------------------------------*/
00706 /*
00707  * tcp_setprio():
00708  *
00709  * Sets the priority of a connection.
00710  *
00711  */
00712 /*-----------------------------------------------------------------------------------*/
00713 void
00714 tcp_setprio(struct tcp_pcb *pcb, u8_t prio)
00715 {
00716   pcb->prio = prio;
00717 }
00718 /*-----------------------------------------------------------------------------------*/
00719 /*
00720  * tcp_seg_copy():
00721  *
00722  * Returns a copy of the given TCP segment.
00723  *
00724  */ 
00725 /*-----------------------------------------------------------------------------------*/
00726 struct tcp_seg *
00727 tcp_seg_copy(struct tcp_seg *seg)
00728 {
00729   struct tcp_seg *cseg;
00730 
00731   cseg = memp_malloc(MEMP_TCP_SEG);
00732   if(cseg == NULL) {
00733     return NULL;
00734   }
00735   memcpy((char *)cseg, (const char *)seg, sizeof(struct tcp_seg)); 
00736   pbuf_ref(cseg->p);
00737   return cseg;
00738 }
00739 /*-----------------------------------------------------------------------------------*/
00740 #if LWIP_CALLBACK_API
00741 static err_t
00742 tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
00743 {
00744   arg = arg;
00745   if(p != NULL) {
00746     pbuf_free(p);
00747   } else if(err == ERR_OK) {
00748     return tcp_close(pcb);
00749   }
00750   return ERR_OK;
00751 }
00752 #endif /* LWIP_CALLBACK_API */
00753 /*-----------------------------------------------------------------------------------*/
00754 static void
00755 tcp_kill_prio(u8_t prio)
00756 {
00757   struct tcp_pcb *pcb, *inactive;
00758   u32_t inactivity;
00759   u8_t mprio;
00760 
00761 
00762   mprio = TCP_PRIO_MAX;
00763   
00764   /* We kill the oldest active connection that has lower priority than
00765      prio. */
00766   inactivity = 0;
00767   inactive = NULL;
00768   for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
00769     if(pcb->prio <= prio &&
00770        pcb->prio <= mprio &&
00771        (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {
00772       inactivity = tcp_ticks - pcb->tmr;
00773       inactive = pcb;
00774       mprio = pcb->prio;
00775     }
00776   }
00777   if(inactive != NULL) {
00778     DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB 0x%p (%ld)\n",
00779                        (void *)inactive, inactivity));
00780     tcp_abort(inactive);
00781   }      
00782 }
00783 
00784 /*-----------------------------------------------------------------------------------*/
00785 static void
00786 tcp_kill_timewait(void)
00787 {
00788   struct tcp_pcb *pcb, *inactive;
00789   u32_t inactivity;
00790 
00791   inactivity = 0;
00792   inactive = NULL;
00793   for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
00794     if((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {
00795       inactivity = tcp_ticks - pcb->tmr;
00796       inactive = pcb;
00797     }
00798   }
00799   if(inactive != NULL) {
00800     DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB 0x%p (%ld)\n",
00801                        (void *)inactive, inactivity));
00802     tcp_abort(inactive);
00803   }      
00804 }
00805 
00806 /*-----------------------------------------------------------------------------------*/
00807 /*-----------------------------------------------------------------------------------*/
00808 struct tcp_pcb *
00809 tcp_alloc(u8_t prio)
00810 {
00811   struct tcp_pcb *pcb;
00812   u32_t iss;
00813   
00814   pcb = memp_malloc(MEMP_TCP_PCB);
00815   if(pcb == NULL) {
00816     /* Try killing oldest connection in TIME-WAIT. */
00817     DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n"));
00818     tcp_kill_timewait();
00819     pcb = memp_malloc(MEMP_TCP_PCB);
00820     if(pcb == NULL) {
00821       tcp_kill_prio(prio);    
00822       pcb = memp_malloc(MEMP_TCP_PCB);
00823     }
00824   }
00825   if(pcb != NULL) {
00826     memset(pcb, 0, sizeof(struct tcp_pcb));
00827     pcb->prio = TCP_PRIO_NORMAL;
00828     pcb->snd_buf = TCP_SND_BUF;
00829     pcb->snd_queuelen = 0;
00830     pcb->rcv_wnd = TCP_WND;
00831     pcb->mss = TCP_MSS;
00832     pcb->rto = 3000 / TCP_SLOW_INTERVAL;
00833     pcb->sa = 0;
00834     pcb->sv = 3000 / TCP_SLOW_INTERVAL;
00835     pcb->rtime = 0;
00836     pcb->cwnd = 1;
00837     iss = tcp_next_iss();
00838     pcb->snd_wl2 = iss;
00839     pcb->snd_nxt = iss;
00840     pcb->snd_max = iss;
00841     pcb->lastack = iss;
00842     pcb->snd_lbb = iss;   
00843     pcb->tmr = tcp_ticks;
00844 
00845     pcb->polltmr = 0;
00846 
00847 #if LWIP_CALLBACK_API
00848     pcb->recv = tcp_recv_null;
00849 #endif /* LWIP_CALLBACK_API */  
00850   }
00851   return pcb;
00852 }
00853 /*-----------------------------------------------------------------------------------*/
00854 /*
00855  * tcp_new():
00856  *
00857  * Creates a new TCP protocol control block but doesn't place it on
00858  * any of the TCP PCB lists.
00859  *
00860  */
00861 /*-----------------------------------------------------------------------------------*/
00862 struct tcp_pcb *
00863 tcp_new(void)
00864 {
00865   return tcp_alloc(TCP_PRIO_NORMAL);
00866 }
00867 /*-----------------------------------------------------------------------------------*/
00868 /*
00869  * tcp_arg():
00870  *
00871  * Used to specify the argument that should be passed callback
00872  * functions.
00873  *
00874  */ 
00875 /*-----------------------------------------------------------------------------------*/
00876 void
00877 tcp_arg(struct tcp_pcb *pcb, void *arg)
00878 {  
00879   pcb->callback_arg = arg;
00880 }
00881 /*-----------------------------------------------------------------------------------*/
00882 /*
00883  * tcp_recv():
00884  *
00885  * Used to specify the function that should be called when a TCP
00886  * connection receives data.
00887  *
00888  */ 
00889 /*-----------------------------------------------------------------------------------*/
00890 #if LWIP_CALLBACK_API
00891 void
00892 tcp_recv(struct tcp_pcb *pcb,
00893          err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err))
00894 {
00895   pcb->recv = recv;
00896 }
00897 #endif /* LWIP_CALLBACK_API */
00898 /*-----------------------------------------------------------------------------------*/
00899 /*
00900  * tcp_sent():
00901  *
00902  * Used to specify the function that should be called when TCP data
00903  * has been successfully delivered to the remote host.
00904  *
00905  */ 
00906 /*-----------------------------------------------------------------------------------*/
00907 #if LWIP_CALLBACK_API
00908 void
00909 tcp_sent(struct tcp_pcb *pcb,
00910          err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len))
00911 {
00912   pcb->sent = sent;
00913 }
00914 #endif /* LWIP_CALLBACK_API */
00915 /*-----------------------------------------------------------------------------------*/
00916 /*
00917  * tcp_err():
00918  *
00919  * Used to specify the function that should be called when a fatal error
00920  * has occured on the connection.
00921  *
00922  */ 
00923 /*-----------------------------------------------------------------------------------*/
00924 #if LWIP_CALLBACK_API
00925 void
00926 tcp_err(struct tcp_pcb *pcb,
00927          void (* errf)(void *arg, err_t err))
00928 {
00929   pcb->errf = errf;
00930 }
00931 #endif /* LWIP_CALLBACK_API */
00932 /*-----------------------------------------------------------------------------------*/
00933 /*
00934  * tcp_poll():
00935  *
00936  * Used to specify the function that should be called periodically
00937  * from TCP. The interval is specified in terms of the TCP coarse
00938  * timer interval, which is called twice a second.
00939  *
00940  */ 
00941 /*-----------------------------------------------------------------------------------*/
00942 void
00943 tcp_poll(struct tcp_pcb *pcb,
00944          err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval)
00945 {
00946 #if LWIP_CALLBACK_API
00947   pcb->poll = poll;
00948 #endif /* LWIP_CALLBACK_API */  
00949   pcb->pollinterval = interval;
00950 }
00951 /*-----------------------------------------------------------------------------------*/
00952 /*
00953  * tcp_accept():
00954  *
00955  * Used for specifying the function that should be called when a
00956  * LISTENing connection has been connected to another host.
00957  *
00958  */ 
00959 /*-----------------------------------------------------------------------------------*/
00960 #if LWIP_CALLBACK_API
00961 void
00962 tcp_accept(struct tcp_pcb *pcb,
00963            err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err))
00964 {
00965   ((struct tcp_pcb_listen *)pcb)->accept = accept;
00966 }
00967 #endif /* LWIP_CALLBACK_API */
00968 /*-----------------------------------------------------------------------------------*/
00969 /*
00970  * tcp_pcb_purge():
00971  *
00972  * Purges a TCP PCB. Removes any buffered data and frees the buffer memory.
00973  *
00974  */
00975 /*-----------------------------------------------------------------------------------*/
00976 void
00977 tcp_pcb_purge(struct tcp_pcb *pcb)
00978 {
00979   if(pcb->state != CLOSED &&
00980      pcb->state != TIME_WAIT &&
00981      pcb->state != LISTEN) {
00982 
00983     DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n"));
00984     
00985 #if TCP_DEBUG
00986     if(pcb->unsent != NULL) {    
00987       DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n"));
00988     }
00989     if(pcb->unacked != NULL) {    
00990       DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n"));
00991     }
00992 #if TCP_QUEUE_OOSEQ /* LW */
00993     if(pcb->ooseq != NULL) {    
00994       DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n"));
00995     }
00996 #endif
00997 #endif /* TCP_DEBUG */
00998     tcp_segs_free(pcb->unsent);
00999 #if TCP_QUEUE_OOSEQ
01000     tcp_segs_free(pcb->ooseq);
01001 #endif /* TCP_QUEUE_OOSEQ */
01002     tcp_segs_free(pcb->unacked);
01003     pcb->unacked = pcb->unsent =
01004 #if TCP_QUEUE_OOSEQ
01005       pcb->ooseq =
01006 #endif /* TCP_QUEUE_OOSEQ */
01007       NULL;
01008   }
01009 }
01010 /*-----------------------------------------------------------------------------------*/
01011 /*
01012  * tcp_pcb_remove():
01013  *
01014  * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.
01015  *
01016  */
01017 /*-----------------------------------------------------------------------------------*/
01018 void
01019 tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)
01020 {
01021   TCP_RMV(pcblist, pcb);
01022 
01023   tcp_pcb_purge(pcb);
01024   
01025   /* if there is an outstanding delayed ACKs, send it */
01026   if(pcb->state != TIME_WAIT &&
01027      pcb->state != LISTEN &&
01028      pcb->flags & TF_ACK_DELAY) {
01029     pcb->flags |= TF_ACK_NOW;
01030     tcp_output(pcb);
01031   }  
01032   pcb->state = CLOSED;
01033 
01034   LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane());
01035 }
01036 /*-----------------------------------------------------------------------------------*/
01037 /*
01038  * tcp_next_iss():
01039  *
01040  * Calculates a new initial sequence number for new connections.
01041  *
01042  */
01043 /*-----------------------------------------------------------------------------------*/
01044 u32_t
01045 tcp_next_iss(void)
01046 {
01047   static u32_t iss = 6510;
01048   
01049   iss += tcp_ticks;       /* XXX */
01050   return iss;
01051 }
01052 /*-----------------------------------------------------------------------------------*/
01053 #if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG
01054 void
01055 tcp_debug_print(struct tcp_hdr *tcphdr)
01056 {
01057   DEBUGF(TCP_DEBUG, ("TCP header:\n"));
01058   DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
01059   DEBUGF(TCP_DEBUG, ("|      %04x     |      %04x     | (src port, dest port)\n",
01060                      tcphdr->src, tcphdr->dest));
01061   DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
01062   DEBUGF(TCP_DEBUG, ("|            %08lu           | (seq no)\n",
01063                             tcphdr->seqno));
01064   DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
01065   DEBUGF(TCP_DEBUG, ("|            %08lu           | (ack no)\n",
01066                      tcphdr->ackno));
01067   DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
01068   DEBUGF(TCP_DEBUG, ("| %2u |    |%u%u%u%u%u|    %5u      | (offset, flags (",
01069                          TCPH_OFFSET(tcphdr),
01070                      TCPH_FLAGS(tcphdr) >> 4 & 1,
01071                      TCPH_FLAGS(tcphdr) >> 4 & 1,
01072                      TCPH_FLAGS(tcphdr) >> 3 & 1,
01073                      TCPH_FLAGS(tcphdr) >> 2 & 1,
01074                      TCPH_FLAGS(tcphdr) >> 1 & 1,
01075                      TCPH_FLAGS(tcphdr) & 1,
01076                      tcphdr->wnd));
01077   tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
01078   DEBUGF(TCP_DEBUG, ("), win)\n"));
01079   DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
01080   DEBUGF(TCP_DEBUG, ("|    0x%04x     |     %5u     | (chksum, urgp)\n",
01081                      ntohs(tcphdr->chksum), ntohs(tcphdr->urgp)));
01082   DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
01083 }
01084 /*-----------------------------------------------------------------------------------*/
01085 void
01086 tcp_debug_print_state(enum tcp_state s)
01087 {
01088   DEBUGF(TCP_DEBUG, ("State: "));
01089   switch(s) {
01090   case CLOSED:
01091     DEBUGF(TCP_DEBUG, ("CLOSED\n"));
01092     break;
01093  case LISTEN:
01094    DEBUGF(TCP_DEBUG, ("LISTEN\n"));
01095    break;
01096   case SYN_SENT:
01097     DEBUGF(TCP_DEBUG, ("SYN_SENT\n"));
01098     break;
01099   case SYN_RCVD:
01100     DEBUGF(TCP_DEBUG, ("SYN_RCVD\n"));
01101     break;
01102   case ESTABLISHED:
01103     DEBUGF(TCP_DEBUG, ("ESTABLISHED\n"));
01104     break;
01105   case FIN_WAIT_1:
01106     DEBUGF(TCP_DEBUG, ("FIN_WAIT_1\n"));
01107     break;
01108   case FIN_WAIT_2:
01109     DEBUGF(TCP_DEBUG, ("FIN_WAIT_2\n"));
01110     break;
01111   case CLOSE_WAIT:
01112     DEBUGF(TCP_DEBUG, ("CLOSE_WAIT\n"));
01113     break;
01114   case CLOSING:
01115     DEBUGF(TCP_DEBUG, ("CLOSING\n"));
01116     break;
01117   case LAST_ACK:
01118     DEBUGF(TCP_DEBUG, ("LAST_ACK\n"));
01119     break;
01120   case TIME_WAIT:
01121     DEBUGF(TCP_DEBUG, ("TIME_WAIT\n"));
01122    break;
01123   }
01124 }
01125 /*-----------------------------------------------------------------------------------*/
01126 void
01127 tcp_debug_print_flags(u8_t flags)
01128 {
01129   if(flags & TCP_FIN) {
01130     DEBUGF(TCP_DEBUG, ("FIN "));
01131   }
01132   if(flags & TCP_SYN) {
01133     DEBUGF(TCP_DEBUG, ("SYN "));
01134   }
01135   if(flags & TCP_RST) {
01136     DEBUGF(TCP_DEBUG, ("RST "));
01137   }
01138   if(flags & TCP_PSH) {
01139     DEBUGF(TCP_DEBUG, ("PSH "));
01140   }
01141   if(flags & TCP_ACK) {
01142     DEBUGF(TCP_DEBUG, ("ACK "));
01143   }
01144   if(flags & TCP_URG) {
01145     DEBUGF(TCP_DEBUG, ("URG "));
01146   }
01147 }
01148 /*-----------------------------------------------------------------------------------*/
01149 void
01150 tcp_debug_print_pcbs(void)
01151 {
01152   struct tcp_pcb *pcb;
01153   DEBUGF(TCP_DEBUG, ("Active PCB states:\n"));
01154   for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
01155     DEBUGF(TCP_DEBUG, ("Local port %u, foreign port %u snd_nxt %lu rcv_nxt %lu ",
01156                        pcb->local_port, pcb->remote_port,
01157                        pcb->snd_nxt, pcb->rcv_nxt));
01158     tcp_debug_print_state(pcb->state);
01159   }    
01160   DEBUGF(TCP_DEBUG, ("Listen PCB states:\n"));
01161   for(pcb = (struct tcp_pcb *)tcp_listen_pcbs; pcb != NULL; pcb = pcb->next) {
01162     DEBUGF(TCP_DEBUG, ("Local port %u, foreign port %u snd_nxt %lu rcv_nxt %lu ",
01163                        pcb->local_port, pcb->remote_port,
01164                        pcb->snd_nxt, pcb->rcv_nxt));
01165     tcp_debug_print_state(pcb->state);
01166   }    
01167   DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n"));
01168   for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
01169     DEBUGF(TCP_DEBUG, ("Local port %u, foreign port %u snd_nxt %lu rcv_nxt %lu ",
01170                        pcb->local_port, pcb->remote_port,
01171                        pcb->snd_nxt, pcb->rcv_nxt));
01172     tcp_debug_print_state(pcb->state);
01173   }    
01174 }
01175 /*-----------------------------------------------------------------------------------*/
01176 int
01177 tcp_pcbs_sane(void)
01178 {
01179   struct tcp_pcb *pcb;
01180   for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
01181     LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED);
01182     LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN);
01183     LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
01184   }
01185   for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
01186     LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
01187   }
01188   return 1;
01189 }
01190 #endif /* TCP_DEBUG */
01191 #endif /* LWIP_TCP */
01192 /*-----------------------------------------------------------------------------------*/
01193 
01194 
01195 
01196 
01197 
01198 
01199 
01200 
01201 

Generated on Wed Jan 14 12:58:57 2004 for RTL-lwIP-0.4 by doxygen 1.3.4