www.pudn.com > TCPmodbushy.rar > tcp.c
/** * @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* */ #include #include "o:/lwip/opt.h" #include "o:/lwip/def.h" #include "o:/lwip/mem.h" #include "o:/lwip/memp.h" #include "o:/lwip/tcp.h" #if LWIP_TCP /* Incremented every coarse grained timer shot (typically every 500 ms, determined by TCP_COARSE_TIMEOUT). */ u32_t data tcp_ticks; /*code 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 xdata tcp_listen_pcbs; /** List of all TCP PCBs that are in a state in which * they accept or send data. */ struct tcp_pcb xdata * xdata tcp_active_pcbs; /** List of all TCP PCBs in TIME-WAIT state */ struct tcp_pcb xdata * xdata tcp_tw_pcbs; struct tcp_pcb xdata * xdata tcp_tmp_pcb; static u8_t data tcp_timer; static u16_t tcp_new_port(void); struct tcp_manager_block xdata Manager_Tcp_Table[MEMP_NUM_TCP_PCB]; /** * 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; Init_Manager_Tcp_Table(); } /****************************************************************************** * TCP open a port for listen ******************************************************************************/ void StartListen( void ) { struct tcp_pcb_listen xdata *lpcb; lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN); if (lpcb == NULL) { return; } lpcb->local_port = TCP_LOCAL_PORT; lpcb->state = LISTEN; TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb); return; } /****************************************************************************** * Close a port for listen ******************************************************************************/ void StopListen( void ) { if( tcp_listen_pcbs.listen_pcbs != NULL ) { struct tcp_pcb xdata *tmp; tmp = tcp_listen_pcbs.pcbs; tcp_pcb_remove((struct tcp_pcb xdata * xdata *)&tcp_listen_pcbs.pcbs, tcp_listen_pcbs.pcbs); memp_free(MEMP_TCP_PCB_LISTEN, tmp); } } /****************************************************************************** * TBOX as a Master send data should create LINK if no have Links * NULL: create failed ******************************************************************************/ struct tcp_pcb xdata* ConnectedDest( u16_t SelfPort, u32_t DestIP, u16_t DestPor ) { struct tcp_pcb xdata* Tmp; #ifdef TESTDEBUG test[9]++; #endif Tmp = tcp_new(); if( Tmp != NULL) { if( tcp_bind( Tmp, SelfPort ) == ERR_OK ) { struct ip_addr xdata ipDestIP; ipDestIP.addr = DestIP; if( tcp_connect( Tmp, (struct ip_addr xdata *)&ipDestIP, DestPor) == ERR_OK ) return Tmp; } tcp_close(Tmp); } } /****************************************************************************** * TBOX as a Master send data should create LINK if no have Links * NULL: create failed ******************************************************************************/ err_t SendTcpDATA( struct tcp_pcb xdata* pTcpLINK, struct MEMB xdata *pMemb ) { //struct pbuf xdata *p u16_t len; struct MEMB xdata *Tmp; Tmp = pMemb; len = 0; while( Tmp != NULL ) { len += Tmp->size; Tmp = Tmp->link; } if(pTcpLINK->state == ESTABLISHED || pTcpLINK->state == CLOSE_WAIT || pTcpLINK->state == SYN_SENT || pTcpLINK->state == SYN_RCVD) { if ( len > 0) { if( tcp_enqueue(pTcpLINK, (void xdata *)pMemb, len, 0, 1, NULL, 0) == ERR_OK ) { tcp_output(pTcpLINK); return ERR_OK; } else { #ifdef TESTDEBUG test[6]++; #endif } } } else { #ifdef TESTDEBUG test[4]++; #endif return ERR_CONN; } } /****************************************************************************** * Init TCP LINK TABLE ******************************************************************************/ void Init_Manager_Tcp_Table( void ) { u8_t i; for( i=0; i unsent != NULL ) ||( Manager_Tcp_Table[i].pPointTcp_Pcb->unacked != NULL ) ) return 1; } } return 0; } /** * 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(); } } void tcp_close_AllLink( void ) { struct tcp_pcb xdata *pcb; pcb = tcp_active_pcbs; while (pcb != NULL) { /* this connection must be aborted */ struct tcp_pcb xdata *next = pcb->next; tcp_abort(pcb); pcb = next; } } /** * Closes the connection held by the PCB. * */ err_t tcp_close(struct tcp_pcb xdata *pcb) { err_t err; RemoveAItemFromTable( pcb ); 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 xdata * xdata *)&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 xdata *pcb) { u32_t seqno, ackno; u16_t remote_port, local_port; struct ip_addr xdata remote_ip, local_ip; RemoveAItemFromTable( pcb ); /* 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, &(netif->ip_addr)); ip_addr_set(&remote_ip, &(pcb->remote_ip)); local_port = pcb->local_port; remote_port = pcb->remote_port; 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); /****************************************************************************** add err( TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT) ) ******************************************************************************/ // sending RST 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 xdata *pcb, u16_t port) { struct tcp_pcb xdata *cpcb; if (port == 0) { port = tcp_new_port(); } /* Check if the address already is in use. */ for(cpcb = (struct tcp_pcb xdata *)tcp_listen_pcbs.pcbs; cpcb != NULL; cpcb = cpcb->next) { if (cpcb->local_port == port) { return ERR_USE; } } for(cpcb = tcp_active_pcbs; cpcb != NULL; cpcb = cpcb->next) { if (cpcb->local_port == port) { return ERR_USE; } } pcb->local_port = port; return ERR_OK; } /** * A nastly hack featuring 'goto' statements that allocates a * new TCP local port. */ static u16_t tcp_new_port(void) { struct tcp_pcb xdata *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 data 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 xdata *)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 xdata *pcb, struct ip_addr xdata *ipaddr, u16_t port) { u32_t optdata; err_t ret; u32_t iss; LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", 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 = TCP_MSS * 10;//pcb->mss*10 pcb->state = SYN_SENT; 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 xdata *)&optdata, 4); if (ret == ERR_OK) { AddAItemToTable(pcb); 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 xdata *pcb; struct tcp_pcb xdata *pcb2; struct tcp_pcb xdata *prev; u32_t eff_wnd; u8_t pcb_remove; /* flag if a PCB should be removed */ err_t err; err = ERR_OK; ++tcp_ticks; /* add account TIME */ pcb = tcp_active_pcbs; while( pcb != NULL ) { if( ( pcb->rttest != 0)&&( pcb->rttest != 0xff ) ) pcb->rttest++; if( pcb->tmr != 0xff ) pcb->tmr++; pcb = pcb->next; } pcb = tcp_tw_pcbs; while( pcb != NULL ) { if( ( pcb->rttest != 0)&&( pcb->rttest != 0xff ) ) pcb->rttest++; if( pcb->tmr != 0xff ) pcb->tmr++; pcb = pcb->next; } /* Steps through all of the active PCBs. */ prev = NULL; pcb = tcp_active_pcbs; while (pcb != NULL) { pcb_remove = 0; if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) { ++pcb_remove; LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n")); } else if (pcb->nrtx == TCP_MAXRTX) { ++pcb_remove; LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n")); } else { ++pcb->rtime; if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) { /* Time for a retransmission. */ /* Double retransmission time-out unless we are trying to * connect to somebody (i.e., we are in SYN_SENT). */ if (pcb->state != SYN_SENT) { if( pcb->rto <= (3000/TCP_SLOW_INTERVAL) ) pcb->rto = pcb->rto + 1; } /* 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 %"U16_F" ssthresh %"U16_F"\n", pcb->cwnd, pcb->ssthresh)); #ifdef TESTDEBUG test[7]++; #endif /* 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 ( pcb->tmr > TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL ) { ++pcb_remove; LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n")); } } /* 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) && (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 data\n")); } #endif /* TCP_QUEUE_OOSEQ */ /* Check if this PCB has stayed too long in SYN-RCVD */ if (pcb->state == SYN_RCVD) { if ( pcb->tmr > TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL ) { ++pcb_remove; LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n")); } } /* Check if this PCB has stayed too long in LAST-ACK */ if (pcb->state == LAST_ACK) { if ( pcb->tmr > 2 * TCP_MSL / TCP_SLOW_INTERVAL ) { ++pcb_remove; LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n")); } } /* If the PCB should be removed, do it. */ if (pcb_remove) { RemoveAItemFromTable( pcb ); 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; } /****************************************************************************** add err infor( TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT), you socket bei yizhou ) ******************************************************************************/ pcb2 = pcb->next; memp_free(MEMP_TCP_PCB, pcb); pcb = pcb2; } else { 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 ( 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 xdata *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 ACK\n")); 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 xdata *seg) { u8_t count = 0; struct tcp_seg xdata *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 xdata *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; } #if TCP_QUEUE_OOSEQ /** * Returns a copy of the given TCP segment. * */ struct tcp_seg xdata * tcp_seg_copy(struct tcp_seg xdata *seg) { struct tcp_seg xdata *cseg; cseg = memp_malloc(MEMP_TCP_SEG); if (cseg == NULL) { return NULL; } memcpy((u8_t xdata *)cseg, (const u8_t xdata *)seg, sizeof(struct tcp_seg)); pbuf_ref(cseg->p); return cseg; } #endif /****************************************************************************** * kill activePCB must be a oldest and unactive time highe 12S ******************************************************************************/ #define KILL_UNACTIVE_PCB_TIME_LEVEL (15000/TCP_SLOW_INTERVAL) /*12S*/ static void tcp_kill_oldest_active(void) { struct tcp_pcb xdata *pcb; struct tcp_pcb xdata *inactive; u8_t inactivity; /* We kill the oldest active connection that has lower priority than prio. */ inactivity = KILL_UNACTIVE_PCB_TIME_LEVEL; inactive = NULL; for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { if ( pcb->tmr >= inactivity ) { inactivity = pcb->tmr; inactive = pcb; } } if (inactive != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_oldest_active: killing oldest PCB %p (%"S32_F")\n", (void *)inactive, inactivity)); tcp_abort(inactive); } } static void tcp_kill_timewait(void) { struct tcp_pcb xdata *pcb; struct tcp_pcb xdata *inactive; u8_t inactivity; inactivity = 0; inactive = NULL; for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { if ( pcb->tmr >= inactivity) { inactivity = pcb->tmr; inactive = pcb; } } if (inactive != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n", (void *)inactive, inactivity)); tcp_abort(inactive); } } struct tcp_pcb xdata* tcp_alloc(void) { struct tcp_pcb xdata *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 connection\n")); tcp_kill_timewait(); pcb = memp_malloc(MEMP_TCP_PCB); if (pcb == NULL) { tcp_kill_oldest_active(); pcb = memp_malloc(MEMP_TCP_PCB); } } if (pcb != NULL) { memset(pcb, 0, sizeof(struct tcp_pcb)); // pcb->snd_buf = TCP_SND_BUF; pcb->snd_queuelen = 0; // pcb->rcv_wnd = TCP_WND; pcb->mss = TCP_MSS; pcb->rto = 1500 / 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 = 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 xdata* tcp_new(void) { return tcp_alloc(); } /** * Purges a TCP PCB. Removes any buffered data and frees the buffer memory. * */ void tcp_pcb_purge(struct tcp_pcb xdata *pcb) { if (pcb->state != CLOSED && pcb->state != TIME_WAIT && pcb->state != LISTEN) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n")); if (pcb->unsent != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n")); } if (pcb->unacked != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n")); } #if TCP_QUEUE_OOSEQ /* LW */ if (pcb->ooseq != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n")); } 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 xdata * xdata *pcblist, struct tcp_pcb xdata *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 data iss = 6510; iss += tcp_ticks; /* XXX */ return iss; } #endif /* LWIP_TCP */