tcp.c
上传用户:yyhongfa
上传日期:2013-01-18
资源大小:267k
文件大小:38k
- /**
- * @file
- *
- * Transmission Control Protocol for IP
- *
- * This file contains common functions for the TCP implementation, such as functinos
- * for manipulating the data structures and the TCP timer functions. TCP functions
- * related to input and output is found in tcp_in.c and tcp_out.c respectively.
- *
- */
- /*
- * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- *
- * This file is part of the lwIP TCP/IP stack.
- *
- * Author: Adam Dunkels <adam@sics.se>
- *
- */
- #include <string.h>
- #include "lwip/opt.h"
- #include "lwip/def.h"
- #include "lwip/mem.h"
- #include "lwip/memp.h"
- #include "lwip/tcp.h"
- #include "uart.h"
- #if LWIP_TCP
- /* Incremented every coarse grained timer shot
- (typically every 500 ms, determined by TCP_COARSE_TIMEOUT). */
- u32_t tcp_ticks;
- const u8_t tcp_backoff[13] =
- { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};
- /* The TCP PCB lists. */
- /** List of all TCP PCBs in LISTEN state */
- union tcp_listen_pcbs_t tcp_listen_pcbs;
- /** List of all TCP PCBs that are in a state in which
- * they accept or send data. */
- struct tcp_pcb *tcp_active_pcbs;
- /** List of all TCP PCBs in TIME-WAIT state */
- struct tcp_pcb *tcp_tw_pcbs;
- struct tcp_pcb *tcp_tmp_pcb;
- static u8_t tcp_timer;
- static u16_t tcp_new_port(void);
- /**
- * Initializes the TCP layer.
- */
- void
- tcp_init(void)
- {
- /* Clear globals. */
- tcp_listen_pcbs.listen_pcbs = NULL;
- tcp_active_pcbs = NULL;
- tcp_tw_pcbs = NULL;
- tcp_tmp_pcb = NULL;
-
- /* initialize timer */
- tcp_ticks = 0;
- tcp_timer = 0;
-
- }
- /*
- *this fun will be called ,when some EVENT happed to TCP CONNECT
- * created by skier 2006.01.30
- */
- #if LWIP_EVENT_API
- typedef enum
- {
- PPP_DEAD = 0,
- PPP_ESTABLISHED,
- UDP_ESTABLISHED,
- TCP_CONNECTING,
- TCP_ESTABLISHED,
- TCP_CLOSING,
-
- TCPIP_STATE_UNKNOWN,
- }MY_TCPIP_STATE;
- extern void set_Mytcpip_state(MY_TCPIP_STATE state);
- extern void tcp_data_ind(u8_t *buf, u16_t len);
- extern void clear_sys_err(void);
- extern void add_sys_err(void);
- /*
- *create by skier 2006.01.31
- *this func will be called when the state of TCP Connect is changed.
- *this fun is very simple, you shuold complete it very carefully.
- */
- err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb,
- LWIP_STATE lwip_event,
- struct pbuf *p,
- u16_t size,
- err_t err)
- {
- struct pbuf *temp = p;
- //DEBUG_FUNCTION("lwip_tcp_event()");
- switch(lwip_event)
- {
- case LWIP_EVENT_ACCEPT:
- //tcp listen. accept a TCP Connect.
- DEBUG_EVENT("LWIP_EVENT_ACCEPT");
- break;
-
- case LWIP_EVENT_SENT:
- //receive the ACK from TCP Peer.
- //Data send successful!
- DEBUG_EVENT("LWIP_EVENT_SENT");
- clear_sys_err();
- break;
-
- /*
- *receive some data from TCP Peer
- */
- case LWIP_EVENT_RECV:
- DEBUG_EVENT("LWIP_EVENT_RECV");
-
- while(temp != NULL)
- {
- tcp_data_ind((u8_t *)temp->payload, temp->len);
- temp = temp->next;
- }
- clear_sys_err();
-
- break;
-
- case LWIP_EVENT_CONNECTED:
- //I this the connect of My TCP connect successful!
- DEBUG_EVENT("LWIP_EVENT_CONNECTED");
- set_Mytcpip_state(TCP_ESTABLISHED);
- break;
-
- case LWIP_EVENT_POLL:
- // DEBUG_EVENT("LWIP_EVENT_POLL");
- break;
-
- case LWIP_EVENT_ERR:
- DEBUG_EVENT("LWIP_EVENT_ERR");
- set_Mytcpip_state(PPP_ESTABLISHED);
- add_sys_err();
- break;
-
- default :
- break;
- }
- return ERR_OK;
- }
- #endif
- #if LWIP_TCP
- static int tcpip_tcp_timer_active = 0;
- static void
- tcpip_tcp_timer(void *arg)
- {
- (void)arg;
- /* call TCP timer handler */
- tcp_tmr();
- /* timer still needed? */
- if (tcp_active_pcbs || tcp_tw_pcbs) {
- /* restart timer */
- //TIMEOUT(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
- TCP_TIMER_START(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
- } else {
- /* disable timer */
- tcpip_tcp_timer_active = 0;
- /*
- *new added by skier 2006.01.29
- */
- TCP_TIMER_STOP(tcpip_tcp_timer, NULL);
- }
- }
- #if !NO_SYS
- void
- tcp_timer_needed(void)
- {
- /* timer is off but needed again? */
- if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
- /* enable and start timer */
- tcpip_tcp_timer_active = 1;
- TCP_TIMER_START(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
- }
- }
- #endif /* !NO_SYS */
- #endif /* LWIP_TCP */
- /**
- * Called periodically to dispatch TCP timers.
- *
- */
- void
- tcp_tmr(void)
- {
- /* Call tcp_fasttmr() every 250 ms */
- tcp_fasttmr();
- if (++tcp_timer & 1) {
- /* Call tcp_tmr() every 500 ms, i.e., every other timer
- tcp_tmr() is called. */
- tcp_slowtmr();
- }
- }
- /**
- * Closes the connection held by the PCB.
- *
- */
- err_t
- tcp_close(struct tcp_pcb *pcb)
- {
- err_t err;
- #if TCP_DEBUG
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in state "));
- tcp_debug_print_state(pcb->state);
- LWIP_DEBUGF(TCP_DEBUG, ("n"));
- #endif /* TCP_DEBUG */
- switch (pcb->state) {
- case CLOSED:
- /* Closing a pcb in the CLOSED state might seem erroneous,
- * however, it is in this state once allocated and as yet unused
- * and the user needs some way to free it should the need arise.
- * Calling tcp_close() with a pcb that has already been closed, (i.e. twice)
- * or for a pcb that has been used and then entered the CLOSED state
- * is erroneous, but this should never happen as the pcb has in those cases
- * been freed, and so any remaining handles are bogus. */
- err = ERR_OK;
- memp_free(MEMP_TCP_PCB, pcb);
- pcb = NULL;
- break;
- case LISTEN:
- err = ERR_OK;
- tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb);
- memp_free(MEMP_TCP_PCB_LISTEN, pcb);
- pcb = NULL;
- break;
- case SYN_SENT:
- err = ERR_OK;
- tcp_pcb_remove(&tcp_active_pcbs, pcb);
- memp_free(MEMP_TCP_PCB, pcb);
- pcb = NULL;
- break;
- case SYN_RCVD:
- case ESTABLISHED:
- err = tcp_send_ctrl(pcb, TCP_FIN);
- if (err == ERR_OK) {
- pcb->state = FIN_WAIT_1;
- }
- break;
- case CLOSE_WAIT:
- err = tcp_send_ctrl(pcb, TCP_FIN);
- if (err == ERR_OK) {
- pcb->state = LAST_ACK;
- }
- break;
- default:
- /* Has already been closed, do nothing. */
- err = ERR_OK;
- pcb = NULL;
- break;
- }
- if (pcb != NULL && err == ERR_OK) {
- err = tcp_output(pcb);
- }
- return err;
- }
- /**
- * Aborts a connection by sending a RST to the remote host and deletes
- * the local protocol control block. This is done when a connection is
- * killed because of shortage of memory.
- *
- */
- void
- tcp_abort(struct tcp_pcb *pcb)
- {
- u32_t seqno, ackno;
- u16_t remote_port, local_port;
- struct ip_addr remote_ip, local_ip;
- #if LWIP_CALLBACK_API
- void (* errf)(void *arg, err_t err);
- #endif /* LWIP_CALLBACK_API */
- void *errf_arg;
-
- /* Figure out on which TCP PCB list we are, and remove us. If we
- are in an active state, call the receive function associated with
- the PCB with a NULL argument, and send an RST to the remote end. */
- if (pcb->state == TIME_WAIT) {
- tcp_pcb_remove(&tcp_tw_pcbs, pcb);
- memp_free(MEMP_TCP_PCB, pcb);
- } else {
- seqno = pcb->snd_nxt;
- ackno = pcb->rcv_nxt;
- ip_addr_set(&local_ip, &(pcb->local_ip));
- ip_addr_set(&remote_ip, &(pcb->remote_ip));
- local_port = pcb->local_port;
- remote_port = pcb->remote_port;
- #if LWIP_CALLBACK_API
- errf = pcb->errf;
- #endif /* LWIP_CALLBACK_API */
- errf_arg = pcb->callback_arg;
- tcp_pcb_remove(&tcp_active_pcbs, pcb);
- if (pcb->unacked != NULL) {
- tcp_segs_free(pcb->unacked);
- }
- if (pcb->unsent != NULL) {
- tcp_segs_free(pcb->unsent);
- }
- #if TCP_QUEUE_OOSEQ
- if (pcb->ooseq != NULL) {
- tcp_segs_free(pcb->ooseq);
- }
- #endif /* TCP_QUEUE_OOSEQ */
- memp_free(MEMP_TCP_PCB, pcb);
- TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
- LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abort: sending RSTn"));
- tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);
- }
- }
- /**
- * Binds the connection to a local portnumber and IP address. If the
- * IP address is not given (i.e., ipaddr == NULL), the IP address of
- * the outgoing network interface is used instead.
- *
- */
- err_t
- tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
- {
- struct tcp_pcb *cpcb;
- #if SO_REUSE
- int reuse_port_all_set = 1;
- #endif /* SO_REUSE */
- if (port == 0) {
- port = tcp_new_port();
- }
- #if SO_REUSE == 0
- /* Check if the address already is in use. */
- for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs;
- cpcb != NULL; cpcb = cpcb->next) {
- if (cpcb->local_port == port) {
- if (ip_addr_isany(&(cpcb->local_ip)) ||
- ip_addr_isany(ipaddr) ||
- ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
- return ERR_USE;
- }
- }
- }
- for(cpcb = tcp_active_pcbs;
- cpcb != NULL; cpcb = cpcb->next) {
- if (cpcb->local_port == port) {
- if (ip_addr_isany(&(cpcb->local_ip)) ||
- ip_addr_isany(ipaddr) ||
- ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
- return ERR_USE;
- }
- }
- }
- #else /* SO_REUSE */
- /* Search through list of PCB's in LISTEN state.
-
- If there is a PCB bound to specified port and IP_ADDR_ANY another PCB can be bound to the interface IP
- or to the loopback address on the same port if SOF_REUSEADDR is set. Any combination of PCB's bound to
- the same local port, but to one address out of {IP_ADDR_ANY, 127.0.0.1, interface IP} at a time is valid.
- But no two PCB's bound to same local port and same local address is valid.
-
- If SOF_REUSEPORT is set several PCB's can be bound to same local port and same local address also. But then
- all PCB's must have the SOF_REUSEPORT option set.
-
- When the two options aren't set and specified port is already bound, ERR_USE is returned saying that
- address is already in use. */
- for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; cpcb != NULL; cpcb = cpcb->next) {
- if(cpcb->local_port == port) {
- if(ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
- if(pcb->so_options & SOF_REUSEPORT) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's: SO_REUSEPORT set and same address.n"));
- reuse_port_all_set = (reuse_port_all_set && (cpcb->so_options & SOF_REUSEPORT));
- }
- else {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's: SO_REUSEPORT not set and same address.n"));
- return ERR_USE;
- }
- }
- else if((ip_addr_isany(ipaddr) && !ip_addr_isany(&(cpcb->local_ip))) ||
- (!ip_addr_isany(ipaddr) && ip_addr_isany(&(cpcb->local_ip)))) {
- if(!(pcb->so_options & SOF_REUSEADDR) && !(pcb->so_options & SOF_REUSEPORT)) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's SO_REUSEPORT or SO_REUSEADDR not set and not the same address.n"));
- return ERR_USE;
- }
- else {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's SO_REUSEPORT or SO_REUSEADDR set and not the same address.n"));
- }
- }
- }
- }
- /* Search through list of PCB's in a state in which they can accept or send data. Same decription as for
- PCB's in state LISTEN applies to this PCB's regarding the options SOF_REUSEADDR and SOF_REUSEPORT. */
- for(cpcb = tcp_active_pcbs; cpcb != NULL; cpcb = cpcb->next) {
- if(cpcb->local_port == port) {
- if(ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
- if(pcb->so_options & SOF_REUSEPORT) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT set and same address.n"));
- reuse_port_all_set = (reuse_port_all_set && (cpcb->so_options & SOF_REUSEPORT));
- }
- else {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT not set and same address.n"));
- return ERR_USE;
- }
- }
- else if((ip_addr_isany(ipaddr) && !ip_addr_isany(&(cpcb->local_ip))) ||
- (!ip_addr_isany(ipaddr) && ip_addr_isany(&(cpcb->local_ip)))) {
- if(!(pcb->so_options & SOF_REUSEADDR) && !(pcb->so_options & SOF_REUSEPORT)) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT or SO_REUSEADDR not set and not the same address.n"));
- return ERR_USE;
- }
- else {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT or SO_REUSEADDR set and not the same address.n"));
- }
- }
- }
- }
- /* Search through list of PCB's in TIME_WAIT state. If SO_REUSEADDR is set a bound combination [IP, port}
- can be rebound. The same applies when SOF_REUSEPORT is set.
-
- If SOF_REUSEPORT is set several PCB's can be bound to same local port and same local address also. But then
- all PCB's must have the SOF_REUSEPORT option set.
-
- When the two options aren't set and specified port is already bound, ERR_USE is returned saying that
- address is already in use. */
- for(cpcb = tcp_tw_pcbs; cpcb != NULL; cpcb = cpcb->next) {
- if(cpcb->local_port == port) {
- if(ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
- if(!(pcb->so_options & SOF_REUSEADDR) && !(pcb->so_options & SOF_REUSEPORT)) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in TIME_WAIT PCB's SO_REUSEPORT or SO_REUSEADDR not set and same address.n"));
- return ERR_USE;
- }
- else if(pcb->so_options & SOF_REUSEPORT) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in TIME_WAIT PCB's SO_REUSEPORT set and same address.n"));
- reuse_port_all_set = (reuse_port_all_set && (cpcb->so_options & SOF_REUSEPORT));
- }
- }
- }
- }
- /* If SOF_REUSEPORT isn't set in all PCB's bound to specified port and local address specified then
- {IP, port} can't be reused. */
- if(!reuse_port_all_set) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: not all sockets have SO_REUSEPORT set.n"));
- return ERR_USE;
- }
- #endif /* SO_REUSE */
- if (!ip_addr_isany(ipaddr)) {
- pcb->local_ip = *ipaddr;
- }
- pcb->local_port = port;
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %un", port));
- return ERR_OK;
- }
- #if LWIP_CALLBACK_API
- static err_t
- tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err)
- {
- (void)arg;
- (void)pcb;
- (void)err;
- return ERR_ABRT;
- }
- #endif /* LWIP_CALLBACK_API */
- /**
- * Set the state of the connection to be LISTEN, which means that it
- * is able to accept incoming connections. The protocol control block
- * is reallocated in order to consume less memory. Setting the
- * connection to LISTEN is an irreversible process.
- *
- */
- struct tcp_pcb *
- tcp_listen(struct tcp_pcb *pcb)
- {
- struct tcp_pcb_listen *lpcb;
- /* already listening? */
- if (pcb->state == LISTEN) {
- return pcb;
- }
- lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN);
- if (lpcb == NULL) {
- return NULL;
- }
- lpcb->callback_arg = pcb->callback_arg;
- lpcb->local_port = pcb->local_port;
- lpcb->state = LISTEN;
- lpcb->so_options = pcb->so_options;
- lpcb->so_options |= SOF_ACCEPTCONN;
- lpcb->ttl = pcb->ttl;
- lpcb->tos = pcb->tos;
- ip_addr_set(&lpcb->local_ip, &pcb->local_ip);
- memp_free(MEMP_TCP_PCB, pcb);
- #if LWIP_CALLBACK_API
- lpcb->accept = tcp_accept_null;
- #endif /* LWIP_CALLBACK_API */
- TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb);
- return (struct tcp_pcb *)lpcb;
- }
- /**
- * This function should be called by the application when it has
- * processed the data. The purpose is to advertise a larger window
- * when the data has been processed.
- *
- */
- void
- tcp_recved(struct tcp_pcb *pcb, u16_t len)
- {
- if ((u32_t)pcb->rcv_wnd + len > TCP_WND) {
- pcb->rcv_wnd = TCP_WND;
- } else {
- pcb->rcv_wnd += len;
- }
- if (!(pcb->flags & TF_ACK_DELAY) &&
- !(pcb->flags & TF_ACK_NOW)) {
- /*
- * We send an ACK here (if one is not already pending, hence
- * the above tests) as tcp_recved() implies that the application
- * has processed some data, and so we can open the receiver's
- * window to allow more to be transmitted. This could result in
- * two ACKs being sent for each received packet in some limited cases
- * (where the application is only receiving data, and is slow to
- * process it) but it is necessary to guarantee that the sender can
- * continue to transmit.
- */
- tcp_ack(pcb);
- }
- else if (pcb->flags & TF_ACK_DELAY && pcb->rcv_wnd >= TCP_WND/2) {
- /* If we can send a window update such that there is a full
- * segment available in the window, do so now. This is sort of
- * nagle-like in its goals, and tries to hit a compromise between
- * sending acks each time the window is updated, and only sending
- * window updates when a timer expires. The "threshold" used
- * above (currently TCP_WND/2) can be tuned to be more or less
- * aggressive */
- tcp_ack_now(pcb);
- }
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %u bytes, wnd %u (%u).n",
- len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd));
- }
- /**
- * A nastly hack featuring 'goto' statements that allocates a
- * new TCP local port.
- */
- static u16_t
- tcp_new_port(void)
- {
- struct tcp_pcb *pcb;
- #ifndef TCP_LOCAL_PORT_RANGE_START
- #define TCP_LOCAL_PORT_RANGE_START 4096
- #define TCP_LOCAL_PORT_RANGE_END 0x7fff
- #endif
- static u16_t port = TCP_LOCAL_PORT_RANGE_START;
-
- again:
- if (++port > TCP_LOCAL_PORT_RANGE_END) {
- port = TCP_LOCAL_PORT_RANGE_START;
- }
-
- for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
- if (pcb->local_port == port) {
- goto again;
- }
- }
- for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
- if (pcb->local_port == port) {
- goto again;
- }
- }
- for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {
- if (pcb->local_port == port) {
- goto again;
- }
- }
- return port;
- }
- /**
- * Connects to another host. The function given as the "connected"
- * argument will be called when the connection has been established.
- *
- */
- err_t
- tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,
- err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err))
- {
- u32_t optdata;
- err_t ret;
- u32_t iss;
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %un", port));
- if (ipaddr != NULL) {
- pcb->remote_ip = *ipaddr;
- } else {
- return ERR_VAL;
- }
- pcb->remote_port = port;
- if (pcb->local_port == 0) {
- pcb->local_port = tcp_new_port();
- }
- iss = tcp_next_iss();
- pcb->rcv_nxt = 0;
- pcb->snd_nxt = iss;
- pcb->lastack = iss - 1;
- pcb->snd_lbb = iss - 1;
- pcb->rcv_wnd = TCP_WND;
- pcb->snd_wnd = TCP_WND;
- pcb->mss = TCP_MSS;
- pcb->cwnd = 1;
- pcb->ssthresh = pcb->mss * 10;
- pcb->state = SYN_SENT;
- #if LWIP_CALLBACK_API
- pcb->connected = connected;
- #endif /* LWIP_CALLBACK_API */
- TCP_REG(&tcp_active_pcbs, pcb);
-
- /* Build an MSS option */
- optdata = htonl(((u32_t)2 << 24) |
- ((u32_t)4 << 16) |
- (((u32_t)pcb->mss / 256) << 8) |
- (pcb->mss & 255));
- ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, (u8_t *)&optdata, 4);
- if (ret == ERR_OK) {
- tcp_output(pcb);
- }
- return ret;
- }
- /**
- * Called every 500 ms and implements the retransmission timer and the timer that
- * removes PCBs that have been in TIME-WAIT for enough time. It also increments
- * various timers such as the inactivity timer in each PCB.
- */
- void
- tcp_slowtmr(void)
- {
- struct tcp_pcb *pcb, *pcb2, *prev;
- u32_t eff_wnd;
- u8_t pcb_remove; /* flag if a PCB should be removed */
- err_t err;
- err = ERR_OK;
- ++tcp_ticks;
- /* Steps through all of the active PCBs. */
- prev = NULL;
- pcb = tcp_active_pcbs;
- if (pcb == NULL) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbsn"));
- }
- while (pcb != NULL) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcbn"));
- LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSEDn", pcb->state != CLOSED);
- LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTENn", pcb->state != LISTEN);
- LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAITn", pcb->state != TIME_WAIT);
- pcb_remove = 0;
- if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) {
- ++pcb_remove;
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reachedn"));
- }
- else if (pcb->nrtx == TCP_MAXRTX) {
- ++pcb_remove;
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reachedn"));
- } else {
- ++pcb->rtime;
- if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {
- /* Time for a retransmission. */
- LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %u pcb->rto %un",
- pcb->rtime, pcb->rto));
- /* Double retransmission time-out unless we are trying to
- * connect to somebody (i.e., we are in SYN_SENT). */
- if (pcb->state != SYN_SENT) {
- pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];
- }
- /* Reduce congestion window and ssthresh. */
- eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);
- pcb->ssthresh = eff_wnd >> 1;
- if (pcb->ssthresh < pcb->mss) {
- pcb->ssthresh = pcb->mss * 2;
- }
- pcb->cwnd = pcb->mss;
- LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %u ssthresh %un",
- pcb->cwnd, pcb->ssthresh));
-
- /* The following needs to be called AFTER cwnd is set to one mss - STJ */
- tcp_rexmit_rto(pcb);
- }
- }
- /* Check if this PCB has stayed too long in FIN-WAIT-2 */
- if (pcb->state == FIN_WAIT_2) {
- if ((u32_t)(tcp_ticks - pcb->tmr) >
- TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {
- ++pcb_remove;
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2n"));
- }
- }
- /* Check if KEEPALIVE should be sent */
- if((pcb->so_options & SOF_KEEPALIVE) && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) {
- if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + TCP_MAXIDLE) / TCP_SLOW_INTERVAL) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %u.%u.%u.%u.n",
- ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
- ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));
- tcp_abort(pcb);
- }
- else if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + pcb->keep_cnt * TCP_KEEPINTVL) / TCP_SLOW_INTERVAL) {
- tcp_keepalive(pcb);
- pcb->keep_cnt++;
- }
- }
- /* If this PCB has queued out of sequence data, but has been
- inactive for too long, will drop the data (it will eventually
- be retransmitted). */
- #if TCP_QUEUE_OOSEQ
- if (pcb->ooseq != NULL &&
- (u32_t)tcp_ticks - pcb->tmr >=
- pcb->rto * TCP_OOSEQ_TIMEOUT) {
- tcp_segs_free(pcb->ooseq);
- pcb->ooseq = NULL;
- LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued datan"));
- }
- #endif /* TCP_QUEUE_OOSEQ */
- /* Check if this PCB has stayed too long in SYN-RCVD */
- if (pcb->state == SYN_RCVD) {
- if ((u32_t)(tcp_ticks - pcb->tmr) >
- TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) {
- ++pcb_remove;
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVDn"));
- }
- }
- /* If the PCB should be removed, do it. */
- if (pcb_remove) {
- tcp_pcb_purge(pcb);
- /* Remove PCB from tcp_active_pcbs list. */
- if (prev != NULL) {
- LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs);
- prev->next = pcb->next;
- } else {
- /* This PCB was the first. */
- LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb);
- tcp_active_pcbs = pcb->next;
- }
- TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);
- pcb2 = pcb->next;
- memp_free(MEMP_TCP_PCB, pcb);
- pcb = pcb2;
- } else {
- /* We check if we should poll the connection. */
- ++pcb->polltmr;
- if (pcb->polltmr >= pcb->pollinterval) {
- pcb->polltmr = 0;
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling applicationn"));
- TCP_EVENT_POLL(pcb, err);
- if (err == ERR_OK) {
- tcp_output(pcb);
- }
- }
-
- prev = pcb;
- pcb = pcb->next;
- }
- }
-
- /* Steps through all of the TIME-WAIT PCBs. */
- prev = NULL;
- pcb = tcp_tw_pcbs;
- while (pcb != NULL) {
- LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
- pcb_remove = 0;
- /* Check if this PCB has stayed long enough in TIME-WAIT */
- if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {
- ++pcb_remove;
- }
-
- /* If the PCB should be removed, do it. */
- if (pcb_remove) {
- tcp_pcb_purge(pcb);
- /* Remove PCB from tcp_tw_pcbs list. */
- if (prev != NULL) {
- LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs);
- prev->next = pcb->next;
- } else {
- /* This PCB was the first. */
- LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);
- tcp_tw_pcbs = pcb->next;
- }
- pcb2 = pcb->next;
- memp_free(MEMP_TCP_PCB, pcb);
- pcb = pcb2;
- } else {
- prev = pcb;
- pcb = pcb->next;
- }
- }
- }
- /**
- * Is called every TCP_FAST_INTERVAL (250 ms) and sends delayed ACKs.
- */
- void
- tcp_fasttmr(void)
- {
- struct tcp_pcb *pcb;
- /* send delayed ACKs */
- for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
- if (pcb->flags & TF_ACK_DELAY) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACKn"));
- tcp_ack_now(pcb);
- pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
- }
- }
- }
- /**
- * Deallocates a list of TCP segments (tcp_seg structures).
- *
- */
- u8_t
- tcp_segs_free(struct tcp_seg *seg)
- {
- u8_t count = 0;
- struct tcp_seg *next;
- while (seg != NULL) {
- next = seg->next;
- count += tcp_seg_free(seg);
- seg = next;
- }
- return count;
- }
- /**
- * Frees a TCP segment.
- *
- */
- u8_t
- tcp_seg_free(struct tcp_seg *seg)
- {
- u8_t count = 0;
-
- if (seg != NULL) {
- if (seg->p != NULL) {
- count = pbuf_free(seg->p);
- #if TCP_DEBUG
- seg->p = NULL;
- #endif /* TCP_DEBUG */
- }
- memp_free(MEMP_TCP_SEG, seg);
- }
- return count;
- }
- /**
- * Sets the priority of a connection.
- *
- */
- void
- tcp_setprio(struct tcp_pcb *pcb, u8_t prio)
- {
- pcb->prio = prio;
- }
- #if TCP_QUEUE_OOSEQ
- /**
- * Returns a copy of the given TCP segment.
- *
- */
- struct tcp_seg *
- tcp_seg_copy(struct tcp_seg *seg)
- {
- struct tcp_seg *cseg;
- cseg = memp_malloc(MEMP_TCP_SEG);
- if (cseg == NULL) {
- return NULL;
- }
- memcpy((char *)cseg, (const char *)seg, sizeof(struct tcp_seg));
- pbuf_ref(cseg->p);
- return cseg;
- }
- #endif
- #if LWIP_CALLBACK_API
- static err_t
- tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
- {
- arg = arg;
- if (p != NULL) {
- pbuf_free(p);
- } else if (err == ERR_OK) {
- return tcp_close(pcb);
- }
- return ERR_OK;
- }
- #endif /* LWIP_CALLBACK_API */
- static void
- tcp_kill_prio(u8_t prio)
- {
- struct tcp_pcb *pcb, *inactive;
- u32_t inactivity;
- u8_t mprio;
- mprio = TCP_PRIO_MAX;
-
- /* We kill the oldest active connection that has lower priority than
- prio. */
- inactivity = 0;
- inactive = NULL;
- for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
- if (pcb->prio <= prio &&
- pcb->prio <= mprio &&
- (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {
- inactivity = tcp_ticks - pcb->tmr;
- inactive = pcb;
- mprio = pcb->prio;
- }
- }
- if (inactive != NULL) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%ld)n",
- (void *)inactive, inactivity));
- tcp_abort(inactive);
- }
- }
- static void
- tcp_kill_timewait(void)
- {
- struct tcp_pcb *pcb, *inactive;
- u32_t inactivity;
- inactivity = 0;
- inactive = NULL;
- for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
- if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {
- inactivity = tcp_ticks - pcb->tmr;
- inactive = pcb;
- }
- }
- if (inactive != NULL) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%ld)n",
- (void *)inactive, inactivity));
- tcp_abort(inactive);
- }
- }
- struct tcp_pcb *
- tcp_alloc(u8_t prio)
- {
- struct tcp_pcb *pcb;
- u32_t iss;
-
- pcb = memp_malloc(MEMP_TCP_PCB);
- if (pcb == NULL) {
- /* Try killing oldest connection in TIME-WAIT. */
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connectionn"));
- tcp_kill_timewait();
- pcb = memp_malloc(MEMP_TCP_PCB);
- if (pcb == NULL) {
- tcp_kill_prio(prio);
- pcb = memp_malloc(MEMP_TCP_PCB);
- }
- }
- if (pcb != NULL) {
- memset(pcb, 0, sizeof(struct tcp_pcb));
- pcb->prio = TCP_PRIO_NORMAL;
- pcb->snd_buf = TCP_SND_BUF;
- pcb->snd_queuelen = 0;
- pcb->rcv_wnd = TCP_WND;
- pcb->tos = 0;
- pcb->ttl = TCP_TTL;
- pcb->mss = TCP_MSS;
- pcb->rto = 3000 / TCP_SLOW_INTERVAL;
- pcb->sa = 0;
- pcb->sv = 3000 / TCP_SLOW_INTERVAL;
- pcb->rtime = 0;
- pcb->cwnd = 1;
- iss = tcp_next_iss();
- pcb->snd_wl2 = iss;
- pcb->snd_nxt = iss;
- pcb->snd_max = iss;
- pcb->lastack = iss;
- pcb->snd_lbb = iss;
- pcb->tmr = tcp_ticks;
- pcb->polltmr = 0;
- /*new added by skier 2006.01.31*/
- pcb->pollinterval = 10;
- //end:skier
- #if LWIP_CALLBACK_API
- pcb->recv = tcp_recv_null;
- #endif /* LWIP_CALLBACK_API */
-
- /* Init KEEPALIVE timer */
- pcb->keepalive = TCP_KEEPDEFAULT;
- pcb->keep_cnt = 0;
- }
- return pcb;
- }
- /**
- * Creates a new TCP protocol control block but doesn't place it on
- * any of the TCP PCB lists.
- *
- * @internal: Maybe there should be a idle TCP PCB list where these
- * PCBs are put on. We can then implement port reservation using
- * tcp_bind(). Currently, we lack this (BSD socket type of) feature.
- */
- struct tcp_pcb *
- tcp_new(void)
- {
- return tcp_alloc(TCP_PRIO_NORMAL);
- }
- /*
- * tcp_arg():
- *
- * Used to specify the argument that should be passed callback
- * functions.
- *
- */
- void
- tcp_arg(struct tcp_pcb *pcb, void *arg)
- {
- pcb->callback_arg = arg;
- }
- #if LWIP_CALLBACK_API
- /**
- * Used to specify the function that should be called when a TCP
- * connection receives data.
- *
- */
- void
- tcp_recv(struct tcp_pcb *pcb,
- err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err))
- {
- pcb->recv = recv;
- }
- /**
- * Used to specify the function that should be called when TCP data
- * has been successfully delivered to the remote host.
- *
- */
- void
- tcp_sent(struct tcp_pcb *pcb,
- err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len))
- {
- pcb->sent = sent;
- }
- /**
- * Used to specify the function that should be called when a fatal error
- * has occured on the connection.
- *
- */
- void
- tcp_err(struct tcp_pcb *pcb,
- void (* errf)(void *arg, err_t err))
- {
- pcb->errf = errf;
- }
- /**
- * Used for specifying the function that should be called when a
- * LISTENing connection has been connected to another host.
- *
- */
- void
- tcp_accept(struct tcp_pcb *pcb,
- err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err))
- {
- ((struct tcp_pcb_listen *)pcb)->accept = accept;
- }
- #endif /* LWIP_CALLBACK_API */
- /**
- * Used to specify the function that should be called periodically
- * from TCP. The interval is specified in terms of the TCP coarse
- * timer interval, which is called twice a second.
- *
- */
- void
- tcp_poll(struct tcp_pcb *pcb,
- err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval)
- {
- #if LWIP_CALLBACK_API
- pcb->poll = poll;
- #endif /* LWIP_CALLBACK_API */
- pcb->pollinterval = interval;
- }
- /**
- * Purges a TCP PCB. Removes any buffered data and frees the buffer memory.
- *
- */
- void
- tcp_pcb_purge(struct tcp_pcb *pcb)
- {
- if (pcb->state != CLOSED &&
- pcb->state != TIME_WAIT &&
- pcb->state != LISTEN) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purgen"));
-
- if (pcb->unsent != NULL) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sentn"));
- }
- if (pcb->unacked != NULL) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unackedn"));
- }
- #if TCP_QUEUE_OOSEQ /* LW */
- if (pcb->ooseq != NULL) {
- LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseqn"));
- }
-
- tcp_segs_free(pcb->ooseq);
- pcb->ooseq = NULL;
- #endif /* TCP_QUEUE_OOSEQ */
- tcp_segs_free(pcb->unsent);
- tcp_segs_free(pcb->unacked);
- pcb->unacked = pcb->unsent = NULL;
- }
- }
- /**
- * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.
- *
- */
- void
- tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)
- {
- TCP_RMV(pcblist, pcb);
- tcp_pcb_purge(pcb);
-
- /* if there is an outstanding delayed ACKs, send it */
- if (pcb->state != TIME_WAIT &&
- pcb->state != LISTEN &&
- pcb->flags & TF_ACK_DELAY) {
- pcb->flags |= TF_ACK_NOW;
- tcp_output(pcb);
- }
- pcb->state = CLOSED;
- LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane());
- }
- /**
- * Calculates a new initial sequence number for new connections.
- *
- */
- u32_t
- tcp_next_iss(void)
- {
- static u32_t iss = 6510;
-
- iss += tcp_ticks; /* XXX */
- return iss;
- }
- #if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG
- void
- tcp_debug_print(struct tcp_hdr *tcphdr)
- {
- LWIP_DEBUGF(TCP_DEBUG, ("TCP header:n"));
- LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+n"));
- LWIP_DEBUGF(TCP_DEBUG, ("| %5u | %5u | (src port, dest port)n",
- ntohs(tcphdr->src), ntohs(tcphdr->dest)));
- LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+n"));
- LWIP_DEBUGF(TCP_DEBUG, ("| %010lu | (seq no)n",
- ntohl(tcphdr->seqno)));
- LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+n"));
- LWIP_DEBUGF(TCP_DEBUG, ("| %010lu | (ack no)n",
- ntohl(tcphdr->ackno)));
- LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+n"));
- LWIP_DEBUGF(TCP_DEBUG, ("| %2u | |%u%u%u%u%u%u| %5u | (hdrlen, flags (",
- TCPH_HDRLEN(tcphdr),
- TCPH_FLAGS(tcphdr) >> 5 & 1,
- TCPH_FLAGS(tcphdr) >> 4 & 1,
- TCPH_FLAGS(tcphdr) >> 3 & 1,
- TCPH_FLAGS(tcphdr) >> 2 & 1,
- TCPH_FLAGS(tcphdr) >> 1 & 1,
- TCPH_FLAGS(tcphdr) & 1,
- ntohs(tcphdr->wnd)));
- tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
- LWIP_DEBUGF(TCP_DEBUG, ("), win)n"));
- LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+n"));
- LWIP_DEBUGF(TCP_DEBUG, ("| 0x%04x | %5u | (chksum, urgp)n",
- ntohs(tcphdr->chksum), ntohs(tcphdr->urgp)));
- LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+n"));
- }
- void
- tcp_debug_print_state(enum tcp_state s)
- {
- LWIP_DEBUGF(TCP_DEBUG, ("State: "));
- switch (s) {
- case CLOSED:
- LWIP_DEBUGF(TCP_DEBUG, ("CLOSEDn"));
- break;
- case LISTEN:
- LWIP_DEBUGF(TCP_DEBUG, ("LISTENn"));
- break;
- case SYN_SENT:
- LWIP_DEBUGF(TCP_DEBUG, ("SYN_SENTn"));
- break;
- case SYN_RCVD:
- LWIP_DEBUGF(TCP_DEBUG, ("SYN_RCVDn"));
- break;
- case ESTABLISHED:
- LWIP_DEBUGF(TCP_DEBUG, ("ESTABLISHEDn"));
- break;
- case FIN_WAIT_1:
- LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_1n"));
- break;
- case FIN_WAIT_2:
- LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_2n"));
- break;
- case CLOSE_WAIT:
- LWIP_DEBUGF(TCP_DEBUG, ("CLOSE_WAITn"));
- break;
- case CLOSING:
- LWIP_DEBUGF(TCP_DEBUG, ("CLOSINGn"));
- break;
- case LAST_ACK:
- LWIP_DEBUGF(TCP_DEBUG, ("LAST_ACKn"));
- break;
- case TIME_WAIT:
- LWIP_DEBUGF(TCP_DEBUG, ("TIME_WAITn"));
- break;
- }
- }
- void
- tcp_debug_print_flags(u8_t flags)
- {
- if (flags & TCP_FIN) {
- LWIP_DEBUGF(TCP_DEBUG, ("FIN "));
- }
- if (flags & TCP_SYN) {
- LWIP_DEBUGF(TCP_DEBUG, ("SYN "));
- }
- if (flags & TCP_RST) {
- LWIP_DEBUGF(TCP_DEBUG, ("RST "));
- }
- if (flags & TCP_PSH) {
- LWIP_DEBUGF(TCP_DEBUG, ("PSH "));
- }
- if (flags & TCP_ACK) {
- LWIP_DEBUGF(TCP_DEBUG, ("ACK "));
- }
- if (flags & TCP_URG) {
- LWIP_DEBUGF(TCP_DEBUG, ("URG "));
- }
- if (flags & TCP_ECE) {
- LWIP_DEBUGF(TCP_DEBUG, ("ECE "));
- }
- if (flags & TCP_CWR) {
- LWIP_DEBUGF(TCP_DEBUG, ("CWR "));
- }
- }
- void
- tcp_debug_print_pcbs(void)
- {
- struct tcp_pcb *pcb;
- LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:n"));
- for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
- LWIP_DEBUGF(TCP_DEBUG, ("Local port %u, foreign port %u snd_nxt %lu rcv_nxt %lu ",
- pcb->local_port, pcb->remote_port,
- pcb->snd_nxt, pcb->rcv_nxt));
- tcp_debug_print_state(pcb->state);
- }
- LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:n"));
- for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {
- LWIP_DEBUGF(TCP_DEBUG, ("Local port %u, foreign port %u snd_nxt %lu rcv_nxt %lu ",
- pcb->local_port, pcb->remote_port,
- pcb->snd_nxt, pcb->rcv_nxt));
- tcp_debug_print_state(pcb->state);
- }
- LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:n"));
- for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
- LWIP_DEBUGF(TCP_DEBUG, ("Local port %u, foreign port %u snd_nxt %lu rcv_nxt %lu ",
- pcb->local_port, pcb->remote_port,
- pcb->snd_nxt, pcb->rcv_nxt));
- tcp_debug_print_state(pcb->state);
- }
- }
- int
- tcp_pcbs_sane(void)
- {
- struct tcp_pcb *pcb;
- for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
- LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED);
- LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN);
- LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
- }
- for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
- LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
- }
- return 1;
- }
- #endif /* TCP_DEBUG */
- #endif /* LWIP_TCP */