fix for corrupted graphics when manipulating config files
[open-ps2-loader.git] / modules / network / SMSTCPIP / tcp.c
blobe2a259aeb918a46cec643577901412ecee65d661
1 /**
2 * @file
4 * Transmission Control Protocol for IP
5 */
7 /*
8 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
9 * All rights reserved.
11 * Redistribution and use in source and binary forms, with or without modification,
12 * are permitted provided that the following conditions are met:
14 * 1. Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31 * OF SUCH DAMAGE.
33 * This file is part of the lwIP TCP/IP stack.
35 * Author: Adam Dunkels <adam@sics.se>
40 /* tcp.c
42 * This file contains common functions for the TCP implementation, such as functinos
43 * for manipulating the data structures and the TCP timer functions. TCP functions
44 * related to input and output is found in tcp_input.c and tcp_output.c respectively.
50 #include "lwip/opt.h"
51 #include "lwip/def.h"
52 #include "lwip/mem.h"
53 #include "lwip/memp.h"
55 #include "lwip/tcp.h"
57 #include "sysclib.h"
59 #include "smsutils.h"
61 #include "thbase.h"
63 #if LWIP_TCP
65 /* Incremented every coarse grained timer shot
66 (typically every 500 ms, determined by TCP_COARSE_TIMEOUT). */
67 u32_t tcp_ticks;
69 const u8_t tcp_backoff[13] =
70 { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};
72 /* The TCP PCB lists. */
73 struct tcp_pcb_listen *tcp_listen_pcbs; /* List of all TCP PCBs in LISTEN state. */
74 struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a
75 state in which they accept or send
76 data. */
77 struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */
79 struct tcp_pcb *tcp_tmp_pcb;
81 static u8_t tcp_timer;
83 static u16_t tcp_new_port(void);
86 * tcp_init():
88 * Initializes the TCP layer.
91 void
92 tcp_init(void)
94 /* Clear globals. */
95 tcp_listen_pcbs = NULL;
96 tcp_active_pcbs = NULL;
97 tcp_tw_pcbs = NULL;
98 tcp_tmp_pcb = NULL;
100 /* initialize timer */
101 tcp_ticks = 0;
102 tcp_timer = 0;
107 * tcp_tmr():
109 * Called periodically to dispatch TCP timers.
113 void
114 tcp_tmr(void)
116 /* Call tcp_fasttmr() every 250 ms */
117 tcp_fasttmr();
119 if (++tcp_timer & 1) {
120 /* Call tcp_tmr() every 500 ms, i.e., every other timer
121 tcp_tmr() is called. */
122 tcp_slowtmr();
127 * tcp_close():
129 * Closes the connection held by the PCB.
133 err_t
134 tcp_close(struct tcp_pcb *pcb)
136 err_t err;
138 #if TCP_DEBUG
139 LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in state "));
140 tcp_debug_print_state(pcb->state);
141 LWIP_DEBUGF(TCP_DEBUG, ("\n"));
142 #endif /* TCP_DEBUG */
143 switch (pcb->state) {
144 case LISTEN:
145 err = ERR_OK;
146 tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs, pcb);
147 memp_free(MEMP_TCP_PCB_LISTEN, pcb);
148 pcb = NULL;
149 break;
150 case SYN_SENT:
151 err = ERR_OK;
152 tcp_pcb_remove(&tcp_active_pcbs, pcb);
153 memp_free(MEMP_TCP_PCB, pcb);
154 pcb = NULL;
155 break;
156 case SYN_RCVD:
157 case ESTABLISHED:
158 err = tcp_send_ctrl(pcb, TCP_FIN);
159 if (err == ERR_OK) {
160 pcb->state = FIN_WAIT_1;
162 break;
163 case CLOSE_WAIT:
164 err = tcp_send_ctrl(pcb, TCP_FIN);
165 if (err == ERR_OK) {
166 pcb->state = LAST_ACK;
168 break;
169 default:
170 /* Has already been closed, do nothing. */
171 err = ERR_OK;
172 pcb = NULL;
173 break;
176 if (pcb != NULL && err == ERR_OK) {
177 err = tcp_output(pcb);
179 return err;
183 * tcp_abort()
185 * Aborts a connection by sending a RST to the remote host and deletes
186 * the local protocol control block. This is done when a connection is
187 * killed because of shortage of memory.
191 void
192 tcp_abort(struct tcp_pcb *pcb)
194 u32_t seqno, ackno;
195 u16_t remote_port, local_port;
196 struct ip_addr remote_ip, local_ip;
197 #if LWIP_CALLBACK_API
198 void (* errf)(void *arg, err_t err);
199 #endif /* LWIP_CALLBACK_API */
200 void *errf_arg;
203 /* Figure out on which TCP PCB list we are, and remove us. If we
204 are in an active state, call the receive function associated with
205 the PCB with a NULL argument, and send an RST to the remote end. */
206 if (pcb->state == TIME_WAIT) {
207 tcp_pcb_remove(&tcp_tw_pcbs, pcb);
208 memp_free(MEMP_TCP_PCB, pcb);
209 } else {
210 seqno = pcb->snd_nxt;
211 ackno = pcb->rcv_nxt;
212 ip_addr_set(&local_ip, &(pcb->local_ip));
213 ip_addr_set(&remote_ip, &(pcb->remote_ip));
214 local_port = pcb->local_port;
215 remote_port = pcb->remote_port;
216 #if LWIP_CALLBACK_API
217 errf = pcb->errf;
218 #endif /* LWIP_CALLBACK_API */
219 errf_arg = pcb->callback_arg;
220 tcp_pcb_remove(&tcp_active_pcbs, pcb);
221 if (pcb->unacked != NULL) {
222 tcp_segs_free(pcb->unacked);
224 if (pcb->unsent != NULL) {
225 tcp_segs_free(pcb->unsent);
227 #if TCP_QUEUE_OOSEQ
228 if (pcb->ooseq != NULL) {
229 tcp_segs_free(pcb->ooseq);
231 #endif /* TCP_QUEUE_OOSEQ */
232 memp_free(MEMP_TCP_PCB, pcb);
233 TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
234 LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abort: sending RST\n"));
235 tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);
240 * tcp_bind():
242 * Binds the connection to a local portnumber and IP address. If the
243 * IP address is not given (i.e., ipaddr == NULL), the IP address of
244 * the outgoing network interface is used instead.
248 err_t
249 tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
251 struct tcp_pcb *cpcb;
252 #ifdef SO_REUSE
253 int reuse_port_all_set = 1;
254 #endif /* SO_REUSE */
256 if (port == 0) {
257 port = tcp_new_port();
259 #ifndef SO_REUSE
260 /* Check if the address already is in use. */
261 for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs;
262 cpcb != NULL; cpcb = cpcb->next) {
263 if (cpcb->local_port == port) {
264 if (ip_addr_isany(&(cpcb->local_ip)) ||
265 ip_addr_isany(ipaddr) ||
266 ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
267 return ERR_USE;
271 for(cpcb = tcp_active_pcbs;
272 cpcb != NULL; cpcb = cpcb->next) {
273 if (cpcb->local_port == port) {
274 if (ip_addr_isany(&(cpcb->local_ip)) ||
275 ip_addr_isany(ipaddr) ||
276 ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
277 return ERR_USE;
281 #else /* SO_REUSE */
282 /* Search through list of PCB's in LISTEN state.
284 If there is a PCB bound to specified port and IP_ADDR_ANY another PCB can be bound to the interface IP
285 or to the loopback address on the same port if SOF_REUSEADDR is set. Any combination of PCB's bound to
286 the same local port, but to one address out of {IP_ADDR_ANY, 127.0.0.1, interface IP} at a time is valid.
287 But no two PCB's bound to same local port and same local address is valid.
289 If SOF_REUSEPORT is set several PCB's can be bound to same local port and same local address also. But then
290 all PCB's must have the SOF_REUSEPORT option set.
292 When the two options aren't set and specified port is already bound, ERR_USE is returned saying that
293 address is already in use. */
294 for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs; cpcb != NULL; cpcb = cpcb->next) {
295 if(cpcb->local_port == port) {
296 if(ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
297 if(pcb->so_options & SOF_REUSEPORT) {
298 LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's: SO_REUSEPORT set and same address.\n"));
299 reuse_port_all_set = (reuse_port_all_set && (cpcb->so_options & SOF_REUSEPORT));
301 else {
302 LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's: SO_REUSEPORT not set and same address.\n"));
303 return ERR_USE;
306 else if((ip_addr_isany(ipaddr) && !ip_addr_isany(&(cpcb->local_ip))) ||
307 (!ip_addr_isany(ipaddr) && ip_addr_isany(&(cpcb->local_ip)))) {
308 if(!(pcb->so_options & SOF_REUSEADDR) && !(pcb->so_options & SOF_REUSEPORT)) {
309 LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's SO_REUSEPORT or SO_REUSEADDR not set and not the same address.\n"));
310 return ERR_USE;
312 else {
313 LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's SO_REUSEPORT or SO_REUSEADDR set and not the same address.\n"));
319 /* Search through list of PCB's in a state in which they can accept or send data. Same decription as for
320 PCB's in state LISTEN applies to this PCB's regarding the options SOF_REUSEADDR and SOF_REUSEPORT. */
321 for(cpcb = tcp_active_pcbs; cpcb != NULL; cpcb = cpcb->next) {
322 if(cpcb->local_port == port) {
323 if(ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
324 if(pcb->so_options & SOF_REUSEPORT) {
325 LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT set and same address.\n"));
326 reuse_port_all_set = (reuse_port_all_set && (cpcb->so_options & SOF_REUSEPORT));
328 else {
329 LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT not set and same address.\n"));
330 return ERR_USE;
333 else if((ip_addr_isany(ipaddr) && !ip_addr_isany(&(cpcb->local_ip))) ||
334 (!ip_addr_isany(ipaddr) && ip_addr_isany(&(cpcb->local_ip)))) {
335 if(!(pcb->so_options & SOF_REUSEADDR) && !(pcb->so_options & SOF_REUSEPORT)) {
336 LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT or SO_REUSEADDR not set and not the same address.\n"));
337 return ERR_USE;
339 else {
340 LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT or SO_REUSEADDR set and not the same address.\n"));
346 /* Search through list of PCB's in TIME_WAIT state. If SO_REUSEADDR is set a bound combination [IP, port}
347 can be rebound. The same applies when SOF_REUSEPORT is set.
349 If SOF_REUSEPORT is set several PCB's can be bound to same local port and same local address also. But then
350 all PCB's must have the SOF_REUSEPORT option set.
352 When the two options aren't set and specified port is already bound, ERR_USE is returned saying that
353 address is already in use. */
354 for(cpcb = tcp_tw_pcbs; cpcb != NULL; cpcb = cpcb->next) {
355 if(cpcb->local_port == port) {
356 if(ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
357 if(!(pcb->so_options & SOF_REUSEADDR) && !(pcb->so_options & SOF_REUSEPORT)) {
358 LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in TIME_WAIT PCB's SO_REUSEPORT or SO_REUSEADDR not set and same address.\n"));
359 return ERR_USE;
361 else if(pcb->so_options & SOF_REUSEPORT) {
362 LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in TIME_WAIT PCB's SO_REUSEPORT set and same address.\n"));
363 reuse_port_all_set = (reuse_port_all_set && (cpcb->so_options & SOF_REUSEPORT));
369 /* If SOF_REUSEPORT isn't set in all PCB's bound to specified port and local address specified then
370 {IP, port} can't be reused. */
371 if(!reuse_port_all_set) {
372 LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: not all sockets have SO_REUSEPORT set.\n"));
373 return ERR_USE;
375 #endif /* SO_REUSE */
377 if (!ip_addr_isany(ipaddr)) {
378 pcb->local_ip = *ipaddr;
380 pcb->local_port = port;
381 LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %u\n", port));
382 return ERR_OK;
384 #if LWIP_CALLBACK_API
385 static err_t
386 tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err)
388 (void)arg;
389 (void)pcb;
390 (void)err;
392 return ERR_ABRT;
394 #endif /* LWIP_CALLBACK_API */
397 * tcp_listen():
399 * Set the state of the connection to be LISTEN, which means that it
400 * is able to accept incoming connections. The protocol control block
401 * is reallocated in order to consume less memory. Setting the
402 * connection to LISTEN is an irreversible process.
406 struct tcp_pcb *
407 tcp_listen(struct tcp_pcb *pcb)
409 struct tcp_pcb_listen *lpcb;
411 /* already listening? */
412 if (pcb->state == LISTEN) {
413 return pcb;
415 lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN);
416 if (lpcb == NULL) {
417 return NULL;
419 lpcb->callback_arg = pcb->callback_arg;
420 lpcb->local_port = pcb->local_port;
421 lpcb->state = LISTEN;
422 lpcb->so_options = pcb->so_options;
423 lpcb->so_options |= SOF_ACCEPTCONN;
424 lpcb->ttl = pcb->ttl;
425 lpcb->tos = pcb->tos;
426 ip_addr_set(&lpcb->local_ip, &pcb->local_ip);
427 memp_free(MEMP_TCP_PCB, pcb);
428 #if LWIP_CALLBACK_API
429 lpcb->accept = tcp_accept_null;
430 #endif /* LWIP_CALLBACK_API */
431 TCP_REG(&tcp_listen_pcbs, lpcb);
432 return (struct tcp_pcb *)lpcb;
436 * tcp_recved():
438 * This function should be called by the application when it has
439 * processed the data. The purpose is to advertise a larger window
440 * when the data has been processed.
444 void
445 tcp_recved(struct tcp_pcb *pcb, u16_t len)
447 if ((u32_t)pcb->rcv_wnd + len > TCP_WND) {
448 pcb->rcv_wnd = TCP_WND;
449 } else {
450 pcb->rcv_wnd += len;
452 if (pcb->flags & TF_ACKNODELAY) {
453 tcp_ack_now(pcb);
454 pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
455 } else if (!(pcb->flags & TF_ACK_DELAY) &&
456 !(pcb->flags & TF_ACK_NOW)) {
457 tcp_ack(pcb);
460 LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %u bytes, wnd %u (%u).\n",
461 len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd));
465 * tcp_new_port():
467 * A nastly hack featuring 'goto' statements that allocates a
468 * new TCP local port.
471 static u16_t
472 tcp_new_port(void)
474 struct tcp_pcb *pcb;
475 #ifndef TCP_LOCAL_PORT_RANGE_START
476 #define TCP_LOCAL_PORT_RANGE_START 4096
477 #define TCP_LOCAL_PORT_RANGE_END 0x7fff
478 #endif
479 static u16_t port = TCP_LOCAL_PORT_RANGE_START;
480 // randomize the port value a bit to avoid TCP conflicts
481 // on lost connections
482 iop_sys_clock_t tme;
483 GetSystemTime(&tme);
484 port += (tme.lo) % 8192;
486 again:
487 if (++port > TCP_LOCAL_PORT_RANGE_END) {
488 port = TCP_LOCAL_PORT_RANGE_START;
491 for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
492 if (pcb->local_port == port) {
493 goto again;
496 for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
497 if (pcb->local_port == port) {
498 goto again;
501 for(pcb = (struct tcp_pcb *)tcp_listen_pcbs; pcb != NULL; pcb = pcb->next) {
502 if (pcb->local_port == port) {
503 goto again;
506 return port;
510 * tcp_connect():
512 * Connects to another host. The function given as the "connected"
513 * argument will be called when the connection has been established.
517 err_t
518 tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,
519 err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err))
521 u32_t optdata;
522 err_t ret;
523 u32_t iss;
525 LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %u\n", port));
526 if (ipaddr != NULL) {
527 pcb->remote_ip = *ipaddr;
528 } else {
529 return ERR_VAL;
531 pcb->remote_port = port;
532 if (pcb->local_port == 0) {
533 pcb->local_port = tcp_new_port();
535 iss = tcp_next_iss();
536 pcb->rcv_nxt = 0;
537 pcb->snd_nxt = iss;
538 pcb->lastack = iss - 1;
539 pcb->snd_lbb = iss - 1;
540 pcb->rcv_wnd = TCP_WND;
541 pcb->snd_wnd = TCP_WND;
542 pcb->mss = TCP_MSS;
543 pcb->cwnd = 1;
544 pcb->ssthresh = pcb->mss * 10;
545 pcb->state = SYN_SENT;
546 #if LWIP_CALLBACK_API
547 pcb->connected = connected;
548 #endif /* LWIP_CALLBACK_API */
549 TCP_REG(&tcp_active_pcbs, pcb);
551 /* Build an MSS option */
552 optdata = htonl(((u32_t)2 << 24) |
553 ((u32_t)4 << 16) |
554 (((u32_t)pcb->mss / 256) << 8) |
555 (pcb->mss & 255));
557 ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, (u8_t *)&optdata, 4);
558 if (ret == ERR_OK) {
559 tcp_output(pcb);
561 return ret;
565 * tcp_slowtmr():
567 * Called every 500 ms and implements the retransmission timer and the timer that
568 * removes PCBs that have been in TIME-WAIT for enough time. It also increments
569 * various timers such as the inactivity timer in each PCB.
572 void
573 tcp_slowtmr(void)
575 struct tcp_pcb *pcb, *pcb2, *prev;
576 u32_t eff_wnd;
577 u8_t pcb_remove; /* flag if a PCB should be removed */
578 err_t err;
580 err = ERR_OK;
582 ++tcp_ticks;
584 /* Steps through all of the active PCBs. */
585 prev = NULL;
586 pcb = tcp_active_pcbs;
587 if (pcb == NULL) LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n"));
588 while (pcb != NULL) {
589 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n"));
590 LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED);
591 LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN);
592 LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT);
594 pcb_remove = 0;
596 if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) {
597 ++pcb_remove;
598 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n"));
600 else if (pcb->nrtx == TCP_MAXRTX) {
601 ++pcb_remove;
602 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n"));
603 } else {
604 ++pcb->rtime;
605 if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {
607 /* Time for a retransmission. */
608 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %u pcb->rto %u\n",
609 pcb->rtime, pcb->rto));
611 /* Double retransmission time-out unless we are trying to
612 * connect to somebody (i.e., we are in SYN_SENT). */
613 if (pcb->state != SYN_SENT) {
614 pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];
616 tcp_rexmit(pcb);
617 /* Reduce congestion window and ssthresh. */
618 eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);
619 pcb->ssthresh = eff_wnd >> 1;
620 if (pcb->ssthresh < pcb->mss) {
621 pcb->ssthresh = pcb->mss * 2;
623 pcb->cwnd = pcb->mss;
624 LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %u ssthresh %u\n",
625 pcb->cwnd, pcb->ssthresh));
628 /* Check if this PCB has stayed too long in FIN-WAIT-2 */
629 if (pcb->state == FIN_WAIT_2) {
630 if ((u32_t)(tcp_ticks - pcb->tmr) >
631 TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {
632 ++pcb_remove;
633 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n"));
637 /* Check if KEEPALIVE should be sent */
638 if((pcb->so_options & SOF_KEEPALIVE) && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) {
639 if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + TCP_MAXIDLE) / TCP_SLOW_INTERVAL) {
640 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %u.%u.%u.%u.\n",
641 ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
642 ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));
644 tcp_abort(pcb);
646 else if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keepalive + pcb->keep_cnt * TCP_KEEPINTVL) / TCP_SLOW_INTERVAL) {
647 tcp_keepalive(pcb);
648 pcb->keep_cnt++;
652 /* If this PCB has queued out of sequence data, but has been
653 inactive for too long, will drop the data (it will eventually
654 be retransmitted). */
655 #if TCP_QUEUE_OOSEQ
656 if (pcb->ooseq != NULL &&
657 (u32_t)tcp_ticks - pcb->tmr >=
658 pcb->rto * TCP_OOSEQ_TIMEOUT) {
659 tcp_segs_free(pcb->ooseq);
660 pcb->ooseq = NULL;
661 LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n"));
663 #endif /* TCP_QUEUE_OOSEQ */
665 /* Check if this PCB has stayed too long in SYN-RCVD */
666 if (pcb->state == SYN_RCVD) {
667 if ((u32_t)(tcp_ticks - pcb->tmr) >
668 TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) {
669 ++pcb_remove;
670 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n"));
675 /* If the PCB should be removed, do it. */
676 if (pcb_remove) {
677 tcp_pcb_purge(pcb);
678 /* Remove PCB from tcp_active_pcbs list. */
679 if (prev != NULL) {
680 LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs);
681 prev->next = pcb->next;
682 } else {
683 /* This PCB was the first. */
684 LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb);
685 tcp_active_pcbs = pcb->next;
688 TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);
690 pcb2 = pcb->next;
691 memp_free(MEMP_TCP_PCB, pcb);
692 pcb = pcb2;
693 } else {
695 /* We check if we should poll the connection. */
696 ++pcb->polltmr;
697 if (pcb->polltmr >= pcb->pollinterval) {
698 pcb->polltmr = 0;
699 LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));
700 TCP_EVENT_POLL(pcb, err);
701 if (err == ERR_OK) {
702 tcp_output(pcb);
706 prev = pcb;
707 pcb = pcb->next;
712 /* Steps through all of the TIME-WAIT PCBs. */
713 prev = NULL;
714 pcb = tcp_tw_pcbs;
715 while (pcb != NULL) {
716 LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
717 pcb_remove = 0;
719 /* Check if this PCB has stayed long enough in TIME-WAIT */
720 if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {
721 ++pcb_remove;
726 /* If the PCB should be removed, do it. */
727 if (pcb_remove) {
728 tcp_pcb_purge(pcb);
729 /* Remove PCB from tcp_tw_pcbs list. */
730 if (prev != NULL) {
731 LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs);
732 prev->next = pcb->next;
733 } else {
734 /* This PCB was the first. */
735 LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);
736 tcp_tw_pcbs = pcb->next;
738 pcb2 = pcb->next;
739 memp_free(MEMP_TCP_PCB, pcb);
740 pcb = pcb2;
741 } else {
742 prev = pcb;
743 pcb = pcb->next;
749 * tcp_fasttmr():
751 * Is called every TCP_FAST_INTERVAL (250 ms) and sends delayed ACKs.
754 void
755 tcp_fasttmr(void)
757 struct tcp_pcb *pcb;
759 /* send delayed ACKs */
760 for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
761 if (pcb->flags & TF_ACK_DELAY) {
762 tcp_ack_now(pcb);
763 pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
769 * tcp_segs_free():
771 * Deallocates a list of TCP segments (tcp_seg structures).
775 u8_t
776 tcp_segs_free(struct tcp_seg *seg)
778 u8_t count = 0;
779 struct tcp_seg *next;
780 while (seg != NULL) {
781 next = seg->next;
782 count += tcp_seg_free(seg);
783 seg = next;
785 return count;
789 * tcp_seg_free():
791 * Frees a TCP segment.
795 u8_t
796 tcp_seg_free(struct tcp_seg *seg)
798 u8_t count = 0;
800 if (seg != NULL) {
801 if (seg->p != NULL) {
802 count = pbuf_free(seg->p);
803 #if TCP_DEBUG
804 seg->p = NULL;
805 #endif /* TCP_DEBUG */
807 memp_free(MEMP_TCP_SEG, seg);
809 return count;
811 #if TCP_QUEUE_OOSEQ
814 * tcp_seg_copy():
816 * Returns a copy of the given TCP segment.
820 struct tcp_seg *
821 tcp_seg_copy(struct tcp_seg *seg)
823 struct tcp_seg *cseg;
825 cseg = memp_malloc(MEMP_TCP_SEG);
826 if (cseg == NULL) {
827 return NULL;
829 mips_memcpy((char *)cseg, (const char *)seg, sizeof(struct tcp_seg));
830 pbuf_ref(cseg->p);
831 return cseg;
833 #endif
835 #if LWIP_CALLBACK_API
836 static err_t
837 tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
839 arg = arg;
840 if (p != NULL) {
841 pbuf_free(p);
842 } else if (err == ERR_OK) {
843 return tcp_close(pcb);
845 return ERR_OK;
847 #endif /* LWIP_CALLBACK_API */
849 static void
850 tcp_kill_prio(u8_t prio)
852 struct tcp_pcb *pcb, *inactive;
853 u32_t inactivity;
854 u8_t mprio;
857 mprio = TCP_PRIO_MAX;
859 /* We kill the oldest active connection that has lower priority than
860 prio. */
861 inactivity = 0;
862 inactive = NULL;
863 for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
864 if (pcb->prio <= prio &&
865 pcb->prio <= mprio &&
866 (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {
867 inactivity = tcp_ticks - pcb->tmr;
868 inactive = pcb;
869 mprio = pcb->prio;
872 if (inactive != NULL) {
873 LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB 0x%p (%ld)\n",
874 (void *)inactive, inactivity));
875 tcp_abort(inactive);
880 static void
881 tcp_kill_timewait(void)
883 struct tcp_pcb *pcb, *inactive;
884 u32_t inactivity;
886 inactivity = 0;
887 inactive = NULL;
888 for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
889 if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {
890 inactivity = tcp_ticks - pcb->tmr;
891 inactive = pcb;
894 if (inactive != NULL) {
895 LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB 0x%p (%ld)\n",
896 (void *)inactive, inactivity));
897 tcp_abort(inactive);
903 struct tcp_pcb *
904 tcp_alloc(u8_t prio)
906 struct tcp_pcb *pcb;
907 u32_t iss;
909 pcb = memp_malloc(MEMP_TCP_PCB);
910 if (pcb == NULL) {
911 /* Try killing oldest connection in TIME-WAIT. */
912 LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n"));
913 tcp_kill_timewait();
914 pcb = memp_malloc(MEMP_TCP_PCB);
915 if (pcb == NULL) {
916 tcp_kill_prio(prio);
917 pcb = memp_malloc(MEMP_TCP_PCB);
920 if (pcb != NULL) {
921 mips_memset(pcb, 0, sizeof(struct tcp_pcb));
922 pcb->prio = TCP_PRIO_NORMAL;
923 pcb->snd_buf = TCP_SND_BUF;
924 pcb->snd_queuelen = 0;
925 pcb->rcv_wnd = TCP_WND;
926 pcb->tos = 0;
927 pcb->ttl = TCP_TTL;
928 pcb->mss = TCP_MSS;
929 pcb->rto = 3000 / TCP_SLOW_INTERVAL;
930 pcb->sa = 0;
931 pcb->sv = 3000 / TCP_SLOW_INTERVAL;
932 pcb->rtime = 0;
933 pcb->cwnd = 1;
934 iss = tcp_next_iss();
935 pcb->snd_wl2 = iss;
936 pcb->snd_nxt = iss;
937 pcb->snd_max = iss;
938 pcb->lastack = iss;
939 pcb->snd_lbb = iss;
940 pcb->tmr = tcp_ticks;
942 pcb->polltmr = 0;
944 #if LWIP_CALLBACK_API
945 pcb->recv = tcp_recv_null;
946 #endif /* LWIP_CALLBACK_API */
948 /* Init KEEPALIVE timer */
949 pcb->keepalive = TCP_KEEPDEFAULT;
950 pcb->keep_cnt = 0;
952 return pcb;
954 #if LWIP_CALLBACK_API
957 * tcp_recv():
959 * Used to specify the function that should be called when a TCP
960 * connection receives data.
964 void
965 tcp_recv(struct tcp_pcb *pcb,
966 err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err))
968 pcb->recv = recv;
972 * tcp_sent():
974 * Used to specify the function that should be called when TCP data
975 * has been successfully delivered to the remote host.
979 void
980 tcp_sent(struct tcp_pcb *pcb,
981 err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len))
983 pcb->sent = sent;
987 * tcp_err():
989 * Used to specify the function that should be called when a fatal error
990 * has occured on the connection.
994 void
995 tcp_err(struct tcp_pcb *pcb,
996 void (* errf)(void *arg, err_t err))
998 pcb->errf = errf;
1000 void
1001 tcp_accept(struct tcp_pcb *pcb,
1002 err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err))
1004 ((struct tcp_pcb_listen *)pcb)->accept = accept;
1006 #endif /* LWIP_CALLBACK_API */
1010 * tcp_poll():
1012 * Used to specify the function that should be called periodically
1013 * from TCP. The interval is specified in terms of the TCP coarse
1014 * timer interval, which is called twice a second.
1018 void
1019 tcp_poll(struct tcp_pcb *pcb,
1020 err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval)
1022 #if LWIP_CALLBACK_API
1023 pcb->poll = poll;
1024 #endif /* LWIP_CALLBACK_API */
1025 pcb->pollinterval = interval;
1029 * tcp_pcb_purge():
1031 * Purges a TCP PCB. Removes any buffered data and frees the buffer memory.
1035 void
1036 tcp_pcb_purge(struct tcp_pcb *pcb)
1038 if (pcb->state != CLOSED &&
1039 pcb->state != TIME_WAIT &&
1040 pcb->state != LISTEN) {
1042 LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n"));
1044 if (pcb->unsent != NULL) {
1045 LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n"));
1047 if (pcb->unacked != NULL) {
1048 LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n"));
1050 #if TCP_QUEUE_OOSEQ /* LW */
1051 if (pcb->ooseq != NULL) {
1052 LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n"));
1055 tcp_segs_free(pcb->ooseq);
1056 pcb->ooseq = NULL;
1057 #endif /* TCP_QUEUE_OOSEQ */
1058 tcp_segs_free(pcb->unsent);
1059 tcp_segs_free(pcb->unacked);
1060 pcb->unacked = pcb->unsent = NULL;
1065 * tcp_pcb_remove():
1067 * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.
1071 void
1072 tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)
1074 TCP_RMV(pcblist, pcb);
1076 tcp_pcb_purge(pcb);
1078 /* if there is an outstanding delayed ACKs, send it */
1079 if (pcb->state != TIME_WAIT &&
1080 pcb->state != LISTEN &&
1081 pcb->flags & TF_ACK_DELAY) {
1082 pcb->flags |= TF_ACK_NOW;
1083 tcp_output(pcb);
1085 pcb->state = CLOSED;
1087 LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane());
1091 * tcp_next_iss():
1093 * Calculates a new initial sequence number for new connections.
1097 u32_t
1098 tcp_next_iss(void)
1100 static u32_t iss = 6510;
1102 iss += tcp_ticks; /* XXX */
1103 return iss;
1106 #endif /* LWIP_TCP */