fix for corrupted graphics when manipulating config files
[open-ps2-loader.git] / modules / network / SMSTCPIP / tcp_out.c
blob045ef84fb82a1afed7bd0322f9cf5999fee12e12
1 /**
2 * @file
4 * Transmission Control Protocol, outgoing traffic
5 */
6 /*
7 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
8 * All rights reserved.
10 * Redistribution and use in source and binary forms, with or without modification,
11 * are permitted provided that the following conditions are met:
13 * 1. Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30 * OF SUCH DAMAGE.
32 * This file is part of the lwIP TCP/IP stack.
34 * Author: Adam Dunkels <adam@sics.se>
39 /* tcp_output.c
41 * The output functions of TCP.
47 #include "lwip/def.h"
48 #include "lwip/opt.h"
50 #include "lwip/mem.h"
51 #include "lwip/memp.h"
52 #include "lwip/sys.h"
54 #include "lwip/netif.h"
56 #include "lwip/inet.h"
57 #include "lwip/tcp.h"
59 #include "lwip/stats.h"
61 #include "sysclib.h"
63 #include "smsutils.h"
65 #if LWIP_TCP
67 /* Forward declarations.*/
68 static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
72 err_t
73 tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags)
75 return tcp_enqueue(pcb, NULL, 0, flags, 1, NULL, 0);
79 err_t
80 tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy)
82 LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, arg=%p, len=%u, copy=%d)\n", (void *)pcb,
83 arg, len, (unsigned int)copy));
84 if (pcb->state == SYN_SENT ||
85 pcb->state == SYN_RCVD ||
86 pcb->state == ESTABLISHED ||
87 pcb->state == CLOSE_WAIT) {
88 if (len > 0) {
89 return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0);
91 return ERR_OK;
92 } else {
93 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_STATE | 3, ("tcp_write() called in invalid state\n"));
94 return ERR_CONN;
98 err_t tcp_enqueue (
99 struct tcp_pcb* pcb, void* arg, u16_t len,
100 u8_t flags, u8_t copy,
101 u8_t* optdata, u8_t optlen
104 struct pbuf* p;
105 struct tcp_seg* seg, *useg, *queue;
106 u32_t left, seqno;
107 u16_t seglen;
108 void* ptr;
109 u8_t queuelen;
110 flags_t lPCBFlags = pcb -> flags;
111 int iSegCNT = 0;
113 left = len;
114 ptr = arg;
116 if ( len > pcb -> snd_buf ) return ERR_MEM;
118 seqno = pcb -> snd_lbb;
119 queue = NULL;
120 queuelen = pcb -> snd_queuelen;
122 if ( queuelen >= TCP_SND_QUEUELEN ) goto memerr;
124 seg = useg = NULL;
125 seglen = 0;
127 while ( !queue || left > 0 ) {
129 if ( lPCBFlags & TF_EVENSEG ) {
131 ++iSegCNT;
133 seglen = left > pcb -> mss ? pcb -> mss
134 : (((iSegCNT%2) == 1)? ((left + 1) / 2): left);
135 } else seglen = left > pcb -> mss ? pcb -> mss : left;
137 seg = memp_malloc ( MEMP_TCP_SEG );
139 if ( !seg ) goto memerr;
141 seg -> next = NULL;
142 seg -> p = NULL;
144 if ( !queue )
145 useg = queue = seg;
146 else {
147 useg -> next = seg;
148 useg = seg;
149 } /* end else */
151 if (optdata != NULL) {
152 if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
153 goto memerr;
155 ++queuelen;
156 seg->dataptr = seg->p->payload;
158 else if (copy) {
159 if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) {
160 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue : could not allocate memory for pbuf copy size %u\n", seglen));
161 goto memerr;
163 ++queuelen;
164 if (arg != NULL) {
165 mips_memcpy(seg->p->payload, ptr, seglen);
167 seg->dataptr = seg->p->payload;
169 /* do not copy data */
170 else {
172 /* first, allocate a pbuf for holding the data.
173 * since the referenced data is available at least until it is sent out on the
174 * link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM
175 * instead of PBUF_REF here.
177 if ((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {
178 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n"));
179 goto memerr;
181 ++queuelen;
182 p->payload = ptr;
183 seg->dataptr = ptr;
185 /* Second, allocate a pbuf for the headers. */
186 if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) {
187 /* If allocation fails, we have to deallocate the data pbuf as
188 * well. */
189 pbuf_free(p);
190 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for header pbuf\n"));
191 goto memerr;
193 ++queuelen;
195 /* Concatenate the headers and data pbufs together. */
196 pbuf_cat(seg->p, p);
197 p = NULL;
200 /* Now that there are more segments queued, we check again if the
201 length of the queue exceeds the configured maximum. */
202 if (queuelen > TCP_SND_QUEUELEN) {
203 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: queue too long %u (%u)\n", queuelen, TCP_SND_QUEUELEN));
204 goto memerr;
207 seg->len = seglen;
209 if (pbuf_header(seg->p, TCP_HLEN)) {
211 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: no room for TCP header in pbuf.\n"));
213 TCP_STATS_INC(tcp.err);
214 goto memerr;
216 seg->tcphdr = seg->p->payload;
217 seg->tcphdr->src = htons(pcb->local_port);
218 seg->tcphdr->dest = htons(pcb->remote_port);
219 seg->tcphdr->seqno = htonl(seqno);
220 seg->tcphdr->urgp = 0;
221 TCPH_FLAGS_SET(seg->tcphdr, flags);
222 /* don't fill in tcphdr->ackno and tcphdr->wnd until later */
224 /* Copy the options into the header, if they are present. */
225 if (optdata == NULL) {
226 TCPH_HDRLEN_SET(seg->tcphdr, 5);
228 else {
229 TCPH_HDRLEN_SET(seg->tcphdr, (5 + optlen / 4));
230 /* Copy options into data portion of segment.
231 Options can thus only be sent in non data carrying
232 segments such as SYN|ACK. */
233 mips_memcpy(seg->dataptr, optdata, optlen);
236 left -= seglen;
237 seqno += seglen;
238 ptr = (void *)((char *)ptr + seglen);
242 /* Now that the data to be enqueued has been broken up into TCP
243 segments in the queue variable, we add them to the end of the
244 pcb->unsent queue. */
245 if (pcb->unsent == NULL) {
246 useg = NULL;
248 else {
249 for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);
252 /* If there is room in the last pbuf on the unsent queue,
253 chain the first pbuf on the queue together with that. */
254 if (useg != NULL &&
255 TCP_TCPLEN(useg) != 0 &&
256 !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&
257 !(flags & (TCP_SYN | TCP_FIN)) &&
258 useg->len + queue->len <= pcb->mss) {
259 /* Remove TCP header from first segment. */
260 pbuf_header(queue->p, -TCP_HLEN);
261 pbuf_cat(useg->p, queue->p);
262 useg->len += queue->len;
263 useg->next = queue->next;
265 if (seg == queue) seg = NULL;
267 memp_free(MEMP_TCP_SEG, queue);
269 else {
270 if (useg == NULL) {
271 pcb->unsent = queue;
274 else {
275 useg->next = queue;
278 if ((flags & TCP_SYN) || (flags & TCP_FIN)) {
279 ++len;
281 pcb->snd_lbb += len;
282 pcb->snd_buf -= len;
283 pcb->snd_queuelen = queuelen;
284 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d (after enqueued)\n", pcb->snd_queuelen));
285 if (pcb->snd_queuelen != 0) {
286 LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
287 pcb->unsent != NULL);
291 /* Set the PSH flag in the last segment that we enqueued, but only
292 if the segment has data (indicated by seglen > 0). */
293 if (seg != NULL && seglen > 0 && seg->tcphdr != NULL) {
294 TCPH_SET_FLAG(seg->tcphdr, TCP_PSH);
297 return ERR_OK;
298 memerr:
299 TCP_STATS_INC(tcp.memerr);
301 if (queue != NULL) {
302 tcp_segs_free(queue);
304 if (pcb->snd_queuelen != 0) {
305 LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
306 pcb->unsent != NULL);
309 LWIP_DEBUGF(TCP_QLEN_DEBUG | DBG_STATE, ("tcp_enqueue: %d (with mem err)\n", pcb->snd_queuelen));
310 return ERR_MEM;
313 /* find out what we can send and send it */
314 err_t
315 tcp_output(struct tcp_pcb *pcb)
317 struct pbuf *p;
318 struct tcp_hdr *tcphdr;
319 struct tcp_seg *seg, *useg;
320 u32_t wnd;
321 #if TCP_CWND_DEBUG
322 int i = 0;
323 #endif /* TCP_CWND_DEBUG */
325 /* First, check if we are invoked by the TCP input processing
326 code. If so, we do not output anything. Instead, we rely on the
327 input processing code to call us when input processing is done
328 with. */
329 if (tcp_input_pcb == pcb) {
330 return ERR_OK;
333 wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);
336 seg = pcb->unsent;
338 /* useg should point to last segment on unacked queue */
339 useg = pcb->unacked;
340 if (useg != NULL) {
341 for (; useg->next != NULL; useg = useg->next);
345 /* If the TF_ACK_NOW flag is set, we check if there is data that is
346 to be sent. If data is to be sent out, we'll just piggyback our
347 acknowledgement with the outgoing segment. If no data will be
348 sent (either because the ->unsent queue is empty or because the
349 window doesn't allow it) we'll have to construct an empty ACK
350 segment and send it. */
351 if (pcb->flags & TF_ACK_NOW &&
352 (seg == NULL ||
353 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
354 pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
355 p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
356 if (p == NULL) {
357 LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
358 return ERR_BUF;
360 LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: sending ACK for %lu\n", pcb->rcv_nxt));
362 tcphdr = p->payload;
363 tcphdr->src = htons(pcb->local_port);
364 tcphdr->dest = htons(pcb->remote_port);
365 tcphdr->seqno = htonl(pcb->snd_nxt);
366 tcphdr->ackno = htonl(pcb->rcv_nxt);
367 TCPH_FLAGS_SET(tcphdr, TCP_ACK);
368 tcphdr->wnd = htons(pcb->rcv_wnd);
369 tcphdr->urgp = 0;
370 TCPH_HDRLEN_SET(tcphdr, 5);
372 tcphdr->chksum = 0;
373 tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
374 IP_PROTO_TCP, p->tot_len);
377 ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
378 IP_PROTO_TCP);
379 pbuf_free(p);
381 return ERR_OK;
384 while (seg != NULL &&
385 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
387 pcb->unsent = seg->next;
389 if (pcb->state != SYN_SENT) {
390 TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);
391 pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
394 tcp_output_segment(seg, pcb);
395 pcb->snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
396 if (TCP_SEQ_LT(pcb->snd_max, pcb->snd_nxt)) {
397 pcb->snd_max = pcb->snd_nxt;
399 /* put segment on unacknowledged list if length > 0 */
400 if (TCP_TCPLEN(seg) > 0) {
401 seg->next = NULL;
402 if (pcb->unacked == NULL) {
403 pcb->unacked = seg;
404 useg = seg;
405 } else {
406 useg->next = seg;
407 useg = useg->next;
409 } else {
410 tcp_seg_free(seg);
412 seg = pcb->unsent;
414 return ERR_OK;
418 static void
419 tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
421 u16_t len;
422 struct netif *netif;
424 /* The TCP header has already been constructed, but the ackno and
425 wnd fields remain. */
426 seg->tcphdr->ackno = htonl(pcb->rcv_nxt);
428 /* silly window avoidance */
429 if (pcb->rcv_wnd < pcb->mss) {
430 seg->tcphdr->wnd = 0;
431 } else {
432 /* advertise our receive window size in this TCP segment */
433 seg->tcphdr->wnd = htons(pcb->rcv_wnd);
436 /* If we don't have a local IP address, we get one by
437 calling ip_route(). */
438 if (ip_addr_isany(&(pcb->local_ip))) {
439 netif = ip_route(&(pcb->remote_ip));
440 if (netif == NULL) {
441 return;
443 ip_addr_set(&(pcb->local_ip), &(netif->ip_addr));
446 pcb->rtime = 0;
448 if (pcb->rttest == 0) {
449 pcb->rttest = tcp_ticks;
450 pcb->rtseq = ntohl(seg->tcphdr->seqno);
452 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %lu\n", pcb->rtseq));
454 LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %lu:%lu\n",
455 htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +
456 seg->len));
458 len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);
460 seg->p->len -= len;
461 seg->p->tot_len -= len;
463 seg->p->payload = seg->tcphdr;
465 seg->tcphdr->chksum = 0;
466 seg->tcphdr->chksum = inet_chksum_pseudo(seg->p,
467 &(pcb->local_ip),
468 &(pcb->remote_ip),
469 IP_PROTO_TCP, seg->p->tot_len);
470 TCP_STATS_INC(tcp.xmit);
472 ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
473 IP_PROTO_TCP);
476 void
477 tcp_rst(u32_t seqno, u32_t ackno,
478 struct ip_addr *local_ip, struct ip_addr *remote_ip,
479 u16_t local_port, u16_t remote_port)
481 struct pbuf *p;
482 struct tcp_hdr *tcphdr;
483 p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
484 if (p == NULL) {
485 LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));
486 return;
489 tcphdr = p->payload;
490 tcphdr->src = htons(local_port);
491 tcphdr->dest = htons(remote_port);
492 tcphdr->seqno = htonl(seqno);
493 tcphdr->ackno = htonl(ackno);
494 TCPH_FLAGS_SET(tcphdr, TCP_RST | TCP_ACK);
495 tcphdr->wnd = htons(TCP_WND);
496 tcphdr->urgp = 0;
497 TCPH_HDRLEN_SET(tcphdr, 5);
499 tcphdr->chksum = 0;
500 tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,
501 IP_PROTO_TCP, p->tot_len);
503 TCP_STATS_INC(tcp.xmit);
504 /* Send output with hardcoded TTL since we have no access to the pcb */
505 ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);
506 pbuf_free(p);
507 LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %lu ackno %lu.\n", seqno, ackno));
510 void
511 tcp_rexmit(struct tcp_pcb *pcb)
513 struct tcp_seg *seg;
515 if (pcb->unacked == NULL) {
516 return;
519 /* Move all unacked segments to the unsent queue. */
520 for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
522 seg->next = pcb->unsent;
523 pcb->unsent = pcb->unacked;
525 pcb->unacked = NULL;
528 pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
530 ++pcb->nrtx;
532 /* Don't take any rtt measurements after retransmitting. */
533 pcb->rttest = 0;
535 /* Do the actual retransmission. */
536 tcp_output(pcb);
540 void
541 tcp_keepalive(struct tcp_pcb *pcb)
543 struct pbuf *p;
544 struct tcp_hdr *tcphdr;
546 LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %u.%u.%u.%u\n",
547 ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
548 ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));
550 LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %ld pcb->tmr %ld pcb->keep_cnt %ld\n", tcp_ticks, pcb->tmr, pcb->keep_cnt));
552 p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
554 if(p == NULL) {
555 LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: could not allocate memory for pbuf\n"));
556 return;
559 tcphdr = p->payload;
560 tcphdr->src = htons(pcb->local_port);
561 tcphdr->dest = htons(pcb->remote_port);
562 tcphdr->seqno = htonl(pcb->snd_nxt - 1);
563 tcphdr->ackno = htonl(pcb->rcv_nxt);
564 tcphdr->wnd = htons(pcb->rcv_wnd);
565 tcphdr->urgp = 0;
566 TCPH_HDRLEN_SET(tcphdr, 5);
568 tcphdr->chksum = 0;
569 tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, IP_PROTO_TCP, p->tot_len);
571 TCP_STATS_INC(tcp.xmit);
573 /* Send output to IP */
574 ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
576 pbuf_free(p);
578 LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_keepalive: seqno %lu ackno %lu.\n", pcb->snd_nxt - 1, pcb->rcv_nxt));
581 #endif /* LWIP_TCP */