]> git.sur5r.net Git - freertos/blob - Demo/Common/ethernet/lwIP/core/tcp_out.c
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@82 1d2547de-c912-0410-9cb9...
[freertos] / Demo / Common / ethernet / lwIP / core / tcp_out.c
1 /**\r
2  * @file\r
3  *\r
4  * Transmission Control Protocol, outgoing traffic\r
5  *\r
6  * The output functions of TCP.\r
7  *\r
8  */\r
9 \r
10 /*\r
11  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
12  * All rights reserved.\r
13  *\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
16  *\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
24  *\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
34  * OF SUCH DAMAGE.\r
35  *\r
36  * This file is part of the lwIP TCP/IP stack.\r
37  *\r
38  * Author: Adam Dunkels <adam@sics.se>\r
39  *\r
40  */\r
41 \r
42 #include <string.h>\r
43 \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
55 \r
56 #if LWIP_TCP\r
57 \r
58 /* Forward declarations.*/\r
59 static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);\r
60 \r
61 err_t\r
62 tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags)\r
63 {\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
66 }\r
67 \r
68 /**\r
69  * Write data for sending (but does not send it immediately).\r
70  *\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
75  * \r
76  * @arg pcb Protocol control block of the TCP connection to enqueue data for. \r
77  * \r
78  * @see tcp_write()\r
79  */\r
80 \r
81 err_t\r
82 tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy)\r
83 {\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
91     if (len > 0) {\r
92       return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0);\r
93     }\r
94     return ERR_OK;\r
95   } else {\r
96     LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_STATE | 3, ("tcp_write() called in invalid state\n"));\r
97     return ERR_CONN;\r
98   }\r
99 }\r
100 \r
101 /**\r
102  * Enqueue either data or TCP options (but not both) for tranmission\r
103  * \r
104  * \r
105  * \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
109  * @arg flags\r
110  * @arg copy 1 if data must be copied, 0 if data is non-volatile and can be\r
111  * referenced.\r
112  * @arg optdata\r
113  * @arg optlen\r
114  */\r
115 err_t\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
119 {\r
120   struct pbuf *p;\r
121   struct tcp_seg *seg, *useg, *queue;\r
122   u32_t left, seqno;\r
123   u16_t seglen;\r
124   void *ptr;\r
125   u8_t queuelen;\r
126 \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
136     return ERR_MEM;\r
137   }\r
138   left = len;\r
139   ptr = arg;\r
140 \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
144 \r
145   LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen));\r
146 \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
153     return ERR_MEM;\r
154   }\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
158   } else {\r
159     LWIP_ASSERT("tcp_enqueue: no pbufs on queue => both queues empty",\r
160       pcb->unacked == NULL && pcb->unsent == NULL);\r
161   }\r
162 \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
166   seglen = 0;\r
167   while (queue == NULL || left > 0) {\r
168 \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
172 \r
173     /* Allocate memory for tcp_seg, and fill in fields. */\r
174     seg = memp_malloc(MEMP_TCP_SEG);\r
175     if (seg == NULL) {\r
176       LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for tcp_seg\n"));\r
177       goto memerr;\r
178     }\r
179     seg->next = NULL;\r
180     seg->p = NULL;\r
181 \r
182     /* first segment of to-be-queued data? */\r
183     if (queue == NULL) {\r
184       queue = seg;\r
185     }\r
186     /* subsequent segments of to-be-queued data */\r
187     else {\r
188       /* Attach the segment to the end of the queued segments */\r
189       LWIP_ASSERT("useg != NULL", useg != NULL);\r
190       useg->next = seg;\r
191     }\r
192     /* remember last segment of to-be-queued data for next iteration */\r
193     useg = seg;\r
194 \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
199      \r
200     /* options? */\r
201     if (optdata != NULL) {\r
202       if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {\r
203         goto memerr;\r
204       }\r
205       ++queuelen;\r
206       seg->dataptr = seg->p->payload;\r
207     }\r
208     /* copy from volatile memory? */\r
209     else if (copy) {\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
212         goto memerr;\r
213       }\r
214       ++queuelen;\r
215       if (arg != NULL) {\r
216         memcpy(seg->p->payload, ptr, seglen);\r
217       }\r
218       seg->dataptr = seg->p->payload;\r
219     }\r
220     /* do not copy data */\r
221     else {\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
226        */\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
229         goto memerr;\r
230       }\r
231       ++queuelen;\r
232       /* reference the non-volatile payload data */\r
233       p->payload = ptr;\r
234       seg->dataptr = ptr;\r
235 \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
239          * well. */\r
240         pbuf_free(p);\r
241         LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for header pbuf\n"));\r
242         goto memerr;\r
243       }\r
244       ++queuelen;\r
245 \r
246       /* Concatenate the headers and data pbufs together. */\r
247       pbuf_cat(seg->p/*header*/, p/*data*/);\r
248       p = NULL;\r
249     }\r
250 \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
255       goto memerr;\r
256     }\r
257 \r
258     seg->len = seglen;\r
259 \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
264       goto memerr;\r
265     }\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
273 \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
277     }\r
278     else {\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
284     }\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
288       (u16_t)flags));\r
289 \r
290     left -= seglen;\r
291     seqno += seglen;\r
292     ptr = (void *)((u8_t *)ptr + seglen);\r
293   }\r
294 \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
299     useg = NULL;\r
300   }\r
301   else {\r
302     for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);\r
303   }\r
304   /* { useg is last segment on the unsent queue, NULL if list is empty } */\r
305 \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
319 \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
322       seg = NULL;\r
323     }\r
324     memp_free(MEMP_TCP_SEG, queue);\r
325   }\r
326   else {\r
327     /* empty list */\r
328     if (useg == NULL) {\r
329       /* initialize list with this segment */\r
330       pcb->unsent = queue;\r
331     }\r
332     /* enqueue segment */\r
333     else {\r
334       useg->next = queue;\r
335     }\r
336   }\r
337   if ((flags & TCP_SYN) || (flags & TCP_FIN)) {\r
338     ++len;\r
339   }\r
340   pcb->snd_lbb += len;\r
341 \r
342   pcb->snd_buf -= len;\r
343 \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
350   }\r
351 \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
356   }\r
357 \r
358   return ERR_OK;\r
359 memerr:\r
360   TCP_STATS_INC(tcp.memerr);\r
361 \r
362   if (queue != NULL) {\r
363     tcp_segs_free(queue);\r
364   }\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
368   }\r
369   LWIP_DEBUGF(TCP_QLEN_DEBUG | DBG_STATE, ("tcp_enqueue: %"S16_F" (with mem err)\n", pcb->snd_queuelen));\r
370   return ERR_MEM;\r
371 }\r
372 \r
373 /* find out what we can send and send it */\r
374 err_t\r
375 tcp_output(struct tcp_pcb *pcb)\r
376 {\r
377   struct pbuf *p;\r
378   struct tcp_hdr *tcphdr;\r
379   struct tcp_seg *seg, *useg;\r
380   u32_t wnd;\r
381 #if TCP_CWND_DEBUG\r
382   s16_t i = 0;\r
383 #endif /* TCP_CWND_DEBUG */\r
384 \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
388      with. */\r
389   if (tcp_input_pcb == pcb) {\r
390     return ERR_OK;\r
391   }\r
392 \r
393   wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);\r
394 \r
395   seg = pcb->unsent;\r
396 \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
401   }                                                                             \r
402    \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
406    *\r
407    * If data is to be sent, we will just piggyback the ACK (see below).\r
408    */\r
409   if (pcb->flags & TF_ACK_NOW &&\r
410      (seg == NULL ||\r
411       ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {\r
412     p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);\r
413     if (p == NULL) {\r
414       LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));\r
415       return ERR_BUF;\r
416     }\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
420 \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
428     tcphdr->urgp = 0;\r
429     TCPH_HDRLEN_SET(tcphdr, 5);\r
430 \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
435 #endif\r
436     ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,\r
437         IP_PROTO_TCP);\r
438     pbuf_free(p);\r
439 \r
440     return ERR_OK;\r
441   }\r
442 \r
443 #if TCP_OUTPUT_DEBUG\r
444   if (seg == NULL) {\r
445     LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", (void*)pcb->unsent));\r
446   }\r
447 #endif /* TCP_OUTPUT_DEBUG */\r
448 #if TCP_CWND_DEBUG\r
449   if (seg == NULL) {\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
452                             pcb->lastack));\r
453   } else {\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
458   }\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
463 #if TCP_CWND_DEBUG\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
467                             pcb->lastack,\r
468                             ntohl(seg->tcphdr->seqno), pcb->lastack, i));\r
469     ++i;\r
470 #endif /* TCP_CWND_DEBUG */\r
471 \r
472     pcb->unsent = seg->next;\r
473 \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
477     }\r
478 \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
483     }\r
484     /* put segment on unacknowledged list if length > 0 */\r
485     if (TCP_TCPLEN(seg) > 0) {\r
486       seg->next = NULL;\r
487       /* unacked list is empty? */\r
488       if (pcb->unacked == NULL) {\r
489         pcb->unacked = seg;\r
490         useg = seg;\r
491       /* unacked list is not empty? */\r
492       } else {\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
500         } else {\r
501           /* add segment to tail of unacked list */\r
502           useg->next = seg;\r
503           useg = useg->next;\r
504         }\r
505       }\r
506     /* do not queue empty segments on the unacked list */\r
507     } else {\r
508       tcp_seg_free(seg);\r
509     }\r
510     seg = pcb->unsent;\r
511   }\r
512   return ERR_OK;\r
513 }\r
514 \r
515 /**\r
516  * Actually send a TCP segment over IP\r
517  */\r
518 static void\r
519 tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)\r
520 {\r
521   u16_t len;\r
522   struct netif *netif;\r
523 \r
524   /** @bug Exclude retransmitted segments from this count. */\r
525   snmp_inc_tcpoutsegs();\r
526 \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
530 \r
531   /* silly window avoidance */\r
532   if (pcb->rcv_wnd < pcb->mss) {\r
533     seg->tcphdr->wnd = 0;\r
534   } else {\r
535     /* advertise our receive window size in this TCP segment */\r
536     seg->tcphdr->wnd = htons(pcb->rcv_wnd);\r
537   }\r
538 \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
544       return;\r
545     }\r
546     ip_addr_set(&(pcb->local_ip), &(netif->ip_addr));\r
547   }\r
548 \r
549   pcb->rtime = 0;\r
550 \r
551   if (pcb->rttest == 0) {\r
552     pcb->rttest = tcp_ticks;\r
553     pcb->rtseq = ntohl(seg->tcphdr->seqno);\r
554 \r
555     LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq));\r
556   }\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
559           seg->len));\r
560 \r
561   len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);\r
562 \r
563   seg->p->len -= len;\r
564   seg->p->tot_len -= len;\r
565 \r
566   seg->p->payload = seg->tcphdr;\r
567 \r
568   seg->tcphdr->chksum = 0;\r
569 #if CHECKSUM_GEN_TCP\r
570   seg->tcphdr->chksum = inet_chksum_pseudo(seg->p,\r
571              &(pcb->local_ip),\r
572              &(pcb->remote_ip),\r
573              IP_PROTO_TCP, seg->p->tot_len);\r
574 #endif\r
575   TCP_STATS_INC(tcp.xmit);\r
576 \r
577   ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,\r
578       IP_PROTO_TCP);\r
579 }\r
580 \r
581 void\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
585 {\r
586   struct pbuf *p;\r
587   struct tcp_hdr *tcphdr;\r
588   p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);\r
589   if (p == NULL) {\r
590       LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));\r
591       return;\r
592   }\r
593 \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
601   tcphdr->urgp = 0;\r
602   TCPH_HDRLEN_SET(tcphdr, 5);\r
603 \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
608 #endif\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
613   pbuf_free(p);\r
614   LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));\r
615 }\r
616 \r
617 /* requeue all unacked segments for retransmission */\r
618 void\r
619 tcp_rexmit_rto(struct tcp_pcb *pcb)\r
620 {\r
621   struct tcp_seg *seg;\r
622 \r
623   if (pcb->unacked == NULL) {\r
624     return;\r
625   }\r
626 \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
635 \r
636   pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);\r
637   /* increment number of retransmissions */\r
638   ++pcb->nrtx;\r
639 \r
640   /* Don't take any RTT measurements after retransmitting. */\r
641   pcb->rttest = 0;\r
642 \r
643   /* Do the actual retransmission */\r
644   tcp_output(pcb);\r
645 }\r
646 \r
647 void\r
648 tcp_rexmit(struct tcp_pcb *pcb)\r
649 {\r
650   struct tcp_seg *seg;\r
651 \r
652   if (pcb->unacked == NULL) {\r
653     return;\r
654   }\r
655 \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
661 \r
662   pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);\r
663 \r
664   ++pcb->nrtx;\r
665 \r
666   /* Don't take any rtt measurements after retransmitting. */\r
667   pcb->rttest = 0;\r
668 \r
669   /* Do the actual retransmission. */\r
670   snmp_inc_tcpretranssegs();\r
671   tcp_output(pcb);\r
672 \r
673 }\r
674 \r
675 \r
676 void\r
677 tcp_keepalive(struct tcp_pcb *pcb)\r
678 {\r
679    struct pbuf *p;\r
680    struct tcp_hdr *tcphdr;\r
681 \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
685 \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
687    \r
688    p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);\r
689 \r
690    if(p == NULL) {\r
691       LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: could not allocate memory for pbuf\n"));\r
692       return;\r
693    }\r
694 \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
701    tcphdr->urgp = 0;\r
702    TCPH_HDRLEN_SET(tcphdr, 5);\r
703    \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
707 #endif\r
708   TCP_STATS_INC(tcp.xmit);\r
709 \r
710    /* Send output to IP */\r
711   ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);\r
712 \r
713   pbuf_free(p);\r
714 \r
715   LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n", pcb->snd_nxt - 1, pcb->rcv_nxt));\r
716 }\r
717 \r
718 #endif /* LWIP_TCP */\r
719 \r
720 \r
721 \r
722 \r
723 \r
724 \r
725 \r
726 \r
727 \r