59 |
#include "lwip/stats.h" |
#include "lwip/stats.h" |
60 |
|
|
61 |
#if LWIP_TCP |
#if LWIP_TCP |
|
#define MIN(x,y) (x) < (y)? (x): (y) |
|
|
|
|
|
|
|
62 |
|
|
63 |
/* Forward declarations.*/ |
/* Forward declarations.*/ |
64 |
static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb); |
static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb); |
112 |
} |
} |
113 |
|
|
114 |
/* seqno will be the sequence number of the first segment enqueued |
/* seqno will be the sequence number of the first segment enqueued |
115 |
by the call to this function. */ |
* by the call to this function. */ |
116 |
seqno = pcb->snd_lbb; |
seqno = pcb->snd_lbb; |
117 |
|
|
118 |
queue = NULL; |
queue = NULL; |
119 |
DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %d\n", pcb->snd_queuelen)); |
DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %d\n", pcb->snd_queuelen)); |
120 |
|
|
121 |
/* Check if the queue length exceeds the configured maximum queue |
/* Check if the queue length exceeds the configured maximum queue |
122 |
length. If so, we return an error. */ |
* length. If so, we return an error. */ |
123 |
queuelen = pcb->snd_queuelen; |
queuelen = pcb->snd_queuelen; |
124 |
if (queuelen >= TCP_SND_QUEUELEN) { |
if (queuelen >= TCP_SND_QUEUELEN) { |
125 |
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: too long queue %d (max %d)\n", queuelen, TCP_SND_QUEUELEN)); |
DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too long queue %d (max %d)\n", queuelen, TCP_SND_QUEUELEN)); |
126 |
goto memerr; |
goto memerr; |
127 |
} |
} |
128 |
|
|
135 |
seglen = 0; |
seglen = 0; |
136 |
|
|
137 |
/* First, break up the data into segments and tuck them together in |
/* First, break up the data into segments and tuck them together in |
138 |
the local "queue" variable. */ |
* the local "queue" variable. */ |
139 |
while (queue == NULL || left > 0) { |
while (queue == NULL || left > 0) { |
140 |
|
|
141 |
/* The segment length should be the MSS if the data to be enqueued |
/* The segment length should be the MSS if the data to be enqueued |
142 |
is larger than the MSS. */ |
* is larger than the MSS. */ |
143 |
seglen = left > pcb->mss? pcb->mss: left; |
seglen = left > pcb->mss? pcb->mss: left; |
144 |
|
|
145 |
/* Allocate memory for tcp_seg, and fill in fields. */ |
/* Allocate memory for tcp_seg, and fill in fields. */ |
146 |
seg = memp_malloc(MEMP_TCP_SEG); |
seg = memp_malloc(MEMP_TCP_SEG); |
147 |
if (seg == NULL) { |
if (seg == NULL) { |
148 |
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for tcp_seg\n")); |
DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for tcp_seg\n")); |
149 |
goto memerr; |
goto memerr; |
150 |
} |
} |
151 |
seg->next = NULL; |
seg->next = NULL; |
156 |
} |
} |
157 |
else { |
else { |
158 |
/* Attach the segment to the end of the queued segments. */ |
/* Attach the segment to the end of the queued segments. */ |
159 |
for(useg = queue; useg->next != NULL; useg = useg->next); |
for (useg = queue; useg->next != NULL; useg = useg->next); |
160 |
useg->next = seg; |
useg->next = seg; |
161 |
} |
} |
162 |
|
|
163 |
/* If copy is set, memory should be allocated |
/* If copy is set, memory should be allocated |
164 |
and data copied into pbuf, otherwise data comes from |
* and data copied into pbuf, otherwise data comes from |
165 |
ROM or other static memory, and need not be copied. If |
* ROM or other static memory, and need not be copied. If |
166 |
optdata is != NULL, we have options instead of data. */ |
* optdata is != NULL, we have options instead of data. */ |
167 |
if (optdata != NULL) { |
if (optdata != NULL) { |
168 |
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { |
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { |
169 |
goto memerr; |
goto memerr; |
173 |
} |
} |
174 |
else if (copy) { |
else if (copy) { |
175 |
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) { |
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) { |
176 |
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for pbuf copy size %u\n", seglen)); |
DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for pbuf copy size %u\n", seglen)); |
177 |
goto memerr; |
goto memerr; |
178 |
} |
} |
179 |
++queuelen; |
++queuelen; |
201 |
/* Second, allocate a pbuf for the headers. */ |
/* Second, allocate a pbuf for the headers. */ |
202 |
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) { |
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) { |
203 |
/* If allocation fails, we have to deallocate the data pbuf as |
/* If allocation fails, we have to deallocate the data pbuf as |
204 |
well. */ |
* well. */ |
205 |
pbuf_free(p); |
pbuf_free(p); |
206 |
DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for header pbuf\n")); |
DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for header pbuf\n")); |
207 |
goto memerr; |
goto memerr; |
211 |
/* Chain the headers and data pbufs together. */ |
/* Chain the headers and data pbufs together. */ |
212 |
pbuf_chain(seg->p, p); |
pbuf_chain(seg->p, p); |
213 |
pbuf_free(p); |
pbuf_free(p); |
214 |
|
p = NULL; |
215 |
} |
} |
216 |
|
|
217 |
/* Now that there are more segments queued, we check again if the |
/* Now that there are more segments queued, we check again if the |
218 |
length of the queue exceeds the configured maximum. */ |
length of the queue exceeds the configured maximum. */ |
219 |
if (queuelen > TCP_SND_QUEUELEN) { |
if (queuelen > TCP_SND_QUEUELEN) { |
220 |
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: queue too long %d (%d)\n", queuelen, TCP_SND_QUEUELEN)); |
DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: queue too long %d (%d)\n", queuelen, TCP_SND_QUEUELEN)); |
221 |
goto memerr; |
goto memerr; |
222 |
} |
} |
223 |
|
|
273 |
useg = NULL; |
useg = NULL; |
274 |
} |
} |
275 |
else { |
else { |
276 |
for(useg = pcb->unsent; useg->next != NULL; useg = useg->next); |
for (useg = pcb->unsent; useg->next != NULL; useg = useg->next); |
277 |
} |
} |
278 |
|
|
279 |
/* If there is room in the last pbuf on the unsent queue, |
/* If there is room in the last pbuf on the unsent queue, |
365 |
return ERR_OK; |
return ERR_OK; |
366 |
} |
} |
367 |
|
|
368 |
wnd = MIN(pcb->snd_wnd, pcb->cwnd); |
wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd); |
369 |
|
|
370 |
|
|
371 |
seg = pcb->unsent; |
seg = pcb->unsent; |
457 |
|
|
458 |
|
|
459 |
} else { |
} else { |
460 |
for(useg = pcb->unacked; useg->next != NULL; useg = useg->next); |
for (useg = pcb->unacked; useg->next != NULL; useg = useg->next); |
461 |
useg->next = seg; |
useg->next = seg; |
462 |
} |
} |
463 |
} else { |
} else { |
573 |
} |
} |
574 |
|
|
575 |
/* Move all unacked segments to the unsent queue. */ |
/* Move all unacked segments to the unsent queue. */ |
576 |
for(seg = pcb->unacked; seg->next != NULL; seg = seg->next); |
for (seg = pcb->unacked; seg->next != NULL; seg = seg->next); |
577 |
|
|
578 |
seg->next = pcb->unsent; |
seg->next = pcb->unsent; |
579 |
pcb->unsent = pcb->unacked; |
pcb->unsent = pcb->unacked; |