4 * Transmission Control Protocol, outgoing traffic
\r
6 * The output functions of TCP.
\r
11 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
\r
12 * All rights reserved.
\r
14 * Redistribution and use in source and binary forms, with or without modification,
\r
15 * are permitted provided that the following conditions are met:
\r
17 * 1. Redistributions of source code must retain the above copyright notice,
\r
18 * this list of conditions and the following disclaimer.
\r
19 * 2. Redistributions in binary form must reproduce the above copyright notice,
\r
20 * this list of conditions and the following disclaimer in the documentation
\r
21 * and/or other materials provided with the distribution.
\r
22 * 3. The name of the author may not be used to endorse or promote products
\r
23 * derived from this software without specific prior written permission.
\r
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
\r
26 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
27 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
\r
28 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
\r
29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
\r
30 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
\r
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
\r
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
\r
33 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
\r
36 * This file is part of the lwIP TCP/IP stack.
\r
38 * Author: Adam Dunkels <adam@sics.se>
\r
44 #include "lwip/def.h"
\r
45 #include "lwip/opt.h"
\r
46 #include "lwip/mem.h"
\r
47 #include "lwip/memp.h"
\r
48 #include "lwip/sys.h"
\r
49 #include "lwip/ip_addr.h"
\r
50 #include "lwip/netif.h"
\r
51 #include "lwip/inet.h"
\r
52 #include "lwip/tcp.h"
\r
53 #include "lwip/stats.h"
\r
54 #include "lwip/snmp.h"
\r
58 /* Forward declarations.*/
\r
59 static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
\r
62 tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags)
\r
64 /* no data, no length, flags, copy=1, no optdata, no optdatalen */
\r
65 return tcp_enqueue(pcb, NULL, 0, flags, 1, NULL, 0);
\r
69 * Write data for sending (but does not send it immediately).
\r
71 * It waits in the expectation of more data being sent soon (as
\r
72 * it can send them more efficiently by combining them together).
\r
73 * To prompt the system to send data now, call tcp_output() after
\r
74 * calling tcp_write().
\r
76 * @arg pcb Protocol control block of the TCP connection to enqueue data for.
\r
82 tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy)
\r
84 LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, arg=%p, len=%"U16_F", copy=%"U16_F")\n", (void *)pcb,
\r
85 arg, len, (u16_t)copy));
\r
86 /* connection is in valid state for data transmission? */
\r
87 if (pcb->state == ESTABLISHED ||
\r
88 pcb->state == CLOSE_WAIT ||
\r
89 pcb->state == SYN_SENT ||
\r
90 pcb->state == SYN_RCVD) {
\r
92 return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0);
\r
96 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_STATE | 3, ("tcp_write() called in invalid state\n"));
\r
102 * Enqueue either data or TCP options (but not both) for tranmission
\r
106 * @arg pcb Protocol control block for the TCP connection to enqueue data for.
\r
107 * @arg arg Pointer to the data to be enqueued for sending.
\r
108 * @arg len Data length in bytes
\r
110 * @arg copy 1 if data must be copied, 0 if data is non-volatile and can be
\r
116 tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
\r
117 u8_t flags, u8_t copy,
\r
118 u8_t *optdata, u8_t optlen)
\r
121 struct tcp_seg *seg, *useg, *queue;
\r
127 LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue(pcb=%p, arg=%p, len=%"U16_F", flags=%"X16_F", copy=%"U16_F")\n",
\r
128 (void *)pcb, arg, len, (u16_t)flags, (u16_t)copy));
\r
129 LWIP_ASSERT("tcp_enqueue: len == 0 || optlen == 0 (programmer violates API)",
\r
130 len == 0 || optlen == 0);
\r
131 LWIP_ASSERT("tcp_enqueue: arg == NULL || optdata == NULL (programmer violates API)",
\r
132 arg == NULL || optdata == NULL);
\r
133 /* fail on too much data */
\r
134 if (len > pcb->snd_buf) {
\r
135 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n", len, pcb->snd_buf));
\r
141 /* seqno will be the sequence number of the first segment enqueued
\r
142 * by the call to this function. */
\r
143 seqno = pcb->snd_lbb;
\r
145 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen));
\r
147 /* If total number of pbufs on the unsent/unacked queues exceeds the
\r
148 * configured maximum, return an error */
\r
149 queuelen = pcb->snd_queuelen;
\r
150 if (queuelen >= TCP_SND_QUEUELEN) {
\r
151 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too long queue %"U16_F" (max %"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
\r
152 TCP_STATS_INC(tcp.memerr);
\r
155 if (queuelen != 0) {
\r
156 LWIP_ASSERT("tcp_enqueue: pbufs on queue => at least one queue non-empty",
\r
157 pcb->unacked != NULL || pcb->unsent != NULL);
\r
159 LWIP_ASSERT("tcp_enqueue: no pbufs on queue => both queues empty",
\r
160 pcb->unacked == NULL && pcb->unsent == NULL);
\r
163 /* First, break up the data into segments and tuck them together in
\r
164 * the local "queue" variable. */
\r
165 useg = queue = seg = NULL;
\r
167 while (queue == NULL || left > 0) {
\r
169 /* The segment length should be the MSS if the data to be enqueued
\r
170 * is larger than the MSS. */
\r
171 seglen = left > pcb->mss? pcb->mss: left;
\r
173 /* Allocate memory for tcp_seg, and fill in fields. */
\r
174 seg = memp_malloc(MEMP_TCP_SEG);
\r
176 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for tcp_seg\n"));
\r
182 /* first segment of to-be-queued data? */
\r
183 if (queue == NULL) {
\r
186 /* subsequent segments of to-be-queued data */
\r
188 /* Attach the segment to the end of the queued segments */
\r
189 LWIP_ASSERT("useg != NULL", useg != NULL);
\r
192 /* remember last segment of to-be-queued data for next iteration */
\r
195 /* If copy is set, memory should be allocated
\r
196 * and data copied into pbuf, otherwise data comes from
\r
197 * ROM or other static memory, and need not be copied. If
\r
198 * optdata is != NULL, we have options instead of data. */
\r
201 if (optdata != NULL) {
\r
202 if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
\r
206 seg->dataptr = seg->p->payload;
\r
208 /* copy from volatile memory? */
\r
210 if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) {
\r
211 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));
\r
216 memcpy(seg->p->payload, ptr, seglen);
\r
218 seg->dataptr = seg->p->payload;
\r
220 /* do not copy data */
\r
222 /* First, allocate a pbuf for holding the data.
\r
223 * since the referenced data is available at least until it is sent out on the
\r
224 * link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM
\r
225 * instead of PBUF_REF here.
\r
227 if ((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {
\r
228 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n"));
\r
232 /* reference the non-volatile payload data */
\r
234 seg->dataptr = ptr;
\r
236 /* Second, allocate a pbuf for the headers. */
\r
237 if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) {
\r
238 /* If allocation fails, we have to deallocate the data pbuf as
\r
241 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for header pbuf\n"));
\r
246 /* Concatenate the headers and data pbufs together. */
\r
247 pbuf_cat(seg->p/*header*/, p/*data*/);
\r
251 /* Now that there are more segments queued, we check again if the
\r
252 length of the queue exceeds the configured maximum. */
\r
253 if (queuelen > TCP_SND_QUEUELEN) {
\r
254 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
\r
260 /* build TCP header */
\r
261 if (pbuf_header(seg->p, TCP_HLEN)) {
\r
262 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: no room for TCP header in pbuf.\n"));
\r
263 TCP_STATS_INC(tcp.err);
\r
266 seg->tcphdr = seg->p->payload;
\r
267 seg->tcphdr->src = htons(pcb->local_port);
\r
268 seg->tcphdr->dest = htons(pcb->remote_port);
\r
269 seg->tcphdr->seqno = htonl(seqno);
\r
270 seg->tcphdr->urgp = 0;
\r
271 TCPH_FLAGS_SET(seg->tcphdr, flags);
\r
272 /* don't fill in tcphdr->ackno and tcphdr->wnd until later */
\r
274 /* Copy the options into the header, if they are present. */
\r
275 if (optdata == NULL) {
\r
276 TCPH_HDRLEN_SET(seg->tcphdr, 5);
\r
279 TCPH_HDRLEN_SET(seg->tcphdr, (5 + optlen / 4));
\r
280 /* Copy options into data portion of segment.
\r
281 Options can thus only be sent in non data carrying
\r
282 segments such as SYN|ACK. */
\r
283 memcpy(seg->dataptr, optdata, optlen);
\r
285 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE, ("tcp_enqueue: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n",
\r
286 ntohl(seg->tcphdr->seqno),
\r
287 ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),
\r
292 ptr = (void *)((u8_t *)ptr + seglen);
\r
295 /* Now that the data to be enqueued has been broken up into TCP
\r
296 segments in the queue variable, we add them to the end of the
\r
297 pcb->unsent queue. */
\r
298 if (pcb->unsent == NULL) {
\r
302 for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);
\r
304 /* { useg is last segment on the unsent queue, NULL if list is empty } */
\r
306 /* If there is room in the last pbuf on the unsent queue,
\r
307 chain the first pbuf on the queue together with that. */
\r
308 if (useg != NULL &&
\r
309 TCP_TCPLEN(useg) != 0 &&
\r
310 !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&
\r
311 !(flags & (TCP_SYN | TCP_FIN)) &&
\r
312 /* fit within max seg size */
\r
313 useg->len + queue->len <= pcb->mss) {
\r
314 /* Remove TCP header from first segment of our to-be-queued list */
\r
315 pbuf_header(queue->p, -TCP_HLEN);
\r
316 pbuf_cat(useg->p, queue->p);
\r
317 useg->len += queue->len;
\r
318 useg->next = queue->next;
\r
320 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE | DBG_STATE, ("tcp_enqueue: chaining segments, new len %"U16_F"\n", useg->len));
\r
321 if (seg == queue) {
\r
324 memp_free(MEMP_TCP_SEG, queue);
\r
328 if (useg == NULL) {
\r
329 /* initialize list with this segment */
\r
330 pcb->unsent = queue;
\r
332 /* enqueue segment */
\r
334 useg->next = queue;
\r
337 if ((flags & TCP_SYN) || (flags & TCP_FIN)) {
\r
340 pcb->snd_lbb += len;
\r
342 pcb->snd_buf -= len;
\r
344 /* update number of segments on the queues */
\r
345 pcb->snd_queuelen = queuelen;
\r
346 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %"S16_F" (after enqueued)\n", pcb->snd_queuelen));
\r
347 if (pcb->snd_queuelen != 0) {
\r
348 LWIP_ASSERT("tcp_enqueue: valid queue length",
\r
349 pcb->unacked != NULL || pcb->unsent != NULL);
\r
352 /* Set the PSH flag in the last segment that we enqueued, but only
\r
353 if the segment has data (indicated by seglen > 0). */
\r
354 if (seg != NULL && seglen > 0 && seg->tcphdr != NULL) {
\r
355 TCPH_SET_FLAG(seg->tcphdr, TCP_PSH);
\r
360 TCP_STATS_INC(tcp.memerr);
\r
362 if (queue != NULL) {
\r
363 tcp_segs_free(queue);
\r
365 if (pcb->snd_queuelen != 0) {
\r
366 LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
\r
367 pcb->unsent != NULL);
\r
369 LWIP_DEBUGF(TCP_QLEN_DEBUG | DBG_STATE, ("tcp_enqueue: %"S16_F" (with mem err)\n", pcb->snd_queuelen));
\r
373 /* find out what we can send and send it */
\r
375 tcp_output(struct tcp_pcb *pcb)
\r
378 struct tcp_hdr *tcphdr;
\r
379 struct tcp_seg *seg, *useg;
\r
383 #endif /* TCP_CWND_DEBUG */
\r
385 /* First, check if we are invoked by the TCP input processing
\r
386 code. If so, we do not output anything. Instead, we rely on the
\r
387 input processing code to call us when input processing is done
\r
389 if (tcp_input_pcb == pcb) {
\r
393 wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);
\r
397 /* useg should point to last segment on unacked queue */
\r
398 useg = pcb->unacked;
\r
399 if (useg != NULL) {
\r
400 for (; useg->next != NULL; useg = useg->next);
\r
403 /* If the TF_ACK_NOW flag is set and no data will be sent (either
\r
404 * because the ->unsent queue is empty or because the window does
\r
405 * not allow it), construct an empty ACK segment and send it.
\r
407 * If data is to be sent, we will just piggyback the ACK (see below).
\r
409 if (pcb->flags & TF_ACK_NOW &&
\r
411 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
\r
412 p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
\r
414 LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
\r
417 LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));
\r
418 /* remove ACK flags from the PCB, as we send an empty ACK now */
\r
419 pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
\r
421 tcphdr = p->payload;
\r
422 tcphdr->src = htons(pcb->local_port);
\r
423 tcphdr->dest = htons(pcb->remote_port);
\r
424 tcphdr->seqno = htonl(pcb->snd_nxt);
\r
425 tcphdr->ackno = htonl(pcb->rcv_nxt);
\r
426 TCPH_FLAGS_SET(tcphdr, TCP_ACK);
\r
427 tcphdr->wnd = htons(pcb->rcv_wnd);
\r
429 TCPH_HDRLEN_SET(tcphdr, 5);
\r
431 tcphdr->chksum = 0;
\r
432 #if CHECKSUM_GEN_TCP
\r
433 tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
\r
434 IP_PROTO_TCP, p->tot_len);
\r
436 ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
\r
443 #if TCP_OUTPUT_DEBUG
\r
445 LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", (void*)pcb->unsent));
\r
447 #endif /* TCP_OUTPUT_DEBUG */
\r
450 LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U32_F", cwnd %"U16_F", wnd %"U32_F", seg == NULL, ack %"U32_F"\n",
\r
451 pcb->snd_wnd, pcb->cwnd, wnd,
\r
454 LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U32_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n",
\r
455 pcb->snd_wnd, pcb->cwnd, wnd,
\r
456 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
\r
457 ntohl(seg->tcphdr->seqno), pcb->lastack));
\r
459 #endif /* TCP_CWND_DEBUG */
\r
460 /* data available and window allows it to be sent? */
\r
461 while (seg != NULL &&
\r
462 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
\r
464 LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U32_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n",
\r
465 pcb->snd_wnd, pcb->cwnd, wnd,
\r
466 ntohl(seg->tcphdr->seqno) + seg->len -
\r
468 ntohl(seg->tcphdr->seqno), pcb->lastack, i));
\r
470 #endif /* TCP_CWND_DEBUG */
\r
472 pcb->unsent = seg->next;
\r
474 if (pcb->state != SYN_SENT) {
\r
475 TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);
\r
476 pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
\r
479 tcp_output_segment(seg, pcb);
\r
480 pcb->snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
\r
481 if (TCP_SEQ_LT(pcb->snd_max, pcb->snd_nxt)) {
\r
482 pcb->snd_max = pcb->snd_nxt;
\r
484 /* put segment on unacknowledged list if length > 0 */
\r
485 if (TCP_TCPLEN(seg) > 0) {
\r
487 /* unacked list is empty? */
\r
488 if (pcb->unacked == NULL) {
\r
489 pcb->unacked = seg;
\r
491 /* unacked list is not empty? */
\r
493 /* In the case of fast retransmit, the packet should not go to the tail
\r
494 * of the unacked queue, but rather at the head. We need to check for
\r
495 * this case. -STJ Jul 27, 2004 */
\r
496 if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){
\r
497 /* add segment to head of unacked list */
\r
498 seg->next = pcb->unacked;
\r
499 pcb->unacked = seg;
\r
501 /* add segment to tail of unacked list */
\r
506 /* do not queue empty segments on the unacked list */
\r
516 * Actually send a TCP segment over IP
\r
519 tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
\r
522 struct netif *netif;
\r
524 /** @bug Exclude retransmitted segments from this count. */
\r
525 snmp_inc_tcpoutsegs();
\r
527 /* The TCP header has already been constructed, but the ackno and
\r
528 wnd fields remain. */
\r
529 seg->tcphdr->ackno = htonl(pcb->rcv_nxt);
\r
531 /* silly window avoidance */
\r
532 if (pcb->rcv_wnd < pcb->mss) {
\r
533 seg->tcphdr->wnd = 0;
\r
535 /* advertise our receive window size in this TCP segment */
\r
536 seg->tcphdr->wnd = htons(pcb->rcv_wnd);
\r
539 /* If we don't have a local IP address, we get one by
\r
540 calling ip_route(). */
\r
541 if (ip_addr_isany(&(pcb->local_ip))) {
\r
542 netif = ip_route(&(pcb->remote_ip));
\r
543 if (netif == NULL) {
\r
546 ip_addr_set(&(pcb->local_ip), &(netif->ip_addr));
\r
551 if (pcb->rttest == 0) {
\r
552 pcb->rttest = tcp_ticks;
\r
553 pcb->rtseq = ntohl(seg->tcphdr->seqno);
\r
555 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq));
\r
557 LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n",
\r
558 htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +
\r
561 len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);
\r
563 seg->p->len -= len;
\r
564 seg->p->tot_len -= len;
\r
566 seg->p->payload = seg->tcphdr;
\r
568 seg->tcphdr->chksum = 0;
\r
569 #if CHECKSUM_GEN_TCP
\r
570 seg->tcphdr->chksum = inet_chksum_pseudo(seg->p,
\r
573 IP_PROTO_TCP, seg->p->tot_len);
\r
575 TCP_STATS_INC(tcp.xmit);
\r
577 ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
\r
582 tcp_rst(u32_t seqno, u32_t ackno,
\r
583 struct ip_addr *local_ip, struct ip_addr *remote_ip,
\r
584 u16_t local_port, u16_t remote_port)
\r
587 struct tcp_hdr *tcphdr;
\r
588 p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
\r
590 LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));
\r
594 tcphdr = p->payload;
\r
595 tcphdr->src = htons(local_port);
\r
596 tcphdr->dest = htons(remote_port);
\r
597 tcphdr->seqno = htonl(seqno);
\r
598 tcphdr->ackno = htonl(ackno);
\r
599 TCPH_FLAGS_SET(tcphdr, TCP_RST | TCP_ACK);
\r
600 tcphdr->wnd = htons(TCP_WND);
\r
602 TCPH_HDRLEN_SET(tcphdr, 5);
\r
604 tcphdr->chksum = 0;
\r
605 #if CHECKSUM_GEN_TCP
\r
606 tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,
\r
607 IP_PROTO_TCP, p->tot_len);
\r
609 TCP_STATS_INC(tcp.xmit);
\r
610 snmp_inc_tcpoutrsts();
\r
611 /* Send output with hardcoded TTL since we have no access to the pcb */
\r
612 ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);
\r
614 LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));
\r
617 /* requeue all unacked segments for retransmission */
\r
619 tcp_rexmit_rto(struct tcp_pcb *pcb)
\r
621 struct tcp_seg *seg;
\r
623 if (pcb->unacked == NULL) {
\r
627 /* Move all unacked segments to the head of the unsent queue */
\r
628 for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
\r
629 /* concatenate unsent queue after unacked queue */
\r
630 seg->next = pcb->unsent;
\r
631 /* unsent queue is the concatenated queue (of unacked, unsent) */
\r
632 pcb->unsent = pcb->unacked;
\r
633 /* unacked queue is now empty */
\r
634 pcb->unacked = NULL;
\r
636 pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
\r
637 /* increment number of retransmissions */
\r
640 /* Don't take any RTT measurements after retransmitting. */
\r
643 /* Do the actual retransmission */
\r
648 tcp_rexmit(struct tcp_pcb *pcb)
\r
650 struct tcp_seg *seg;
\r
652 if (pcb->unacked == NULL) {
\r
656 /* Move the first unacked segment to the unsent queue */
\r
657 seg = pcb->unacked->next;
\r
658 pcb->unacked->next = pcb->unsent;
\r
659 pcb->unsent = pcb->unacked;
\r
660 pcb->unacked = seg;
\r
662 pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
\r
666 /* Don't take any rtt measurements after retransmitting. */
\r
669 /* Do the actual retransmission. */
\r
670 snmp_inc_tcpretranssegs();
\r
677 tcp_keepalive(struct tcp_pcb *pcb)
\r
680 struct tcp_hdr *tcphdr;
\r
682 LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
\r
683 ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
\r
684 ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));
\r
686 LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt %"U16_F"\n", tcp_ticks, pcb->tmr, pcb->keep_cnt));
\r
688 p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
\r
691 LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: could not allocate memory for pbuf\n"));
\r
695 tcphdr = p->payload;
\r
696 tcphdr->src = htons(pcb->local_port);
\r
697 tcphdr->dest = htons(pcb->remote_port);
\r
698 tcphdr->seqno = htonl(pcb->snd_nxt - 1);
\r
699 tcphdr->ackno = htonl(pcb->rcv_nxt);
\r
700 tcphdr->wnd = htons(pcb->rcv_wnd);
\r
702 TCPH_HDRLEN_SET(tcphdr, 5);
\r
704 tcphdr->chksum = 0;
\r
705 #if CHECKSUM_GEN_TCP
\r
706 tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, IP_PROTO_TCP, p->tot_len);
\r
708 TCP_STATS_INC(tcp.xmit);
\r
710 /* Send output to IP */
\r
711 ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
\r
715 LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n", pcb->snd_nxt - 1, pcb->rcv_nxt));
\r
718 #endif /* LWIP_TCP */
\r