79 |
tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy) |
tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy) |
80 |
{ |
{ |
81 |
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, arg=%p, len=%u, copy=%d)\n", (void *)pcb, arg, len, copy)); |
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, arg=%p, len=%u, copy=%d)\n", (void *)pcb, arg, len, copy)); |
82 |
if(pcb->state == SYN_SENT || |
if (pcb->state == SYN_SENT || |
83 |
pcb->state == SYN_RCVD || |
pcb->state == SYN_RCVD || |
84 |
pcb->state == ESTABLISHED || |
pcb->state == ESTABLISHED || |
85 |
pcb->state == CLOSE_WAIT) { |
pcb->state == CLOSE_WAIT) { |
86 |
if(len > 0) { |
if (len > 0) { |
87 |
return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0); |
return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0); |
88 |
} |
} |
89 |
return ERR_OK; |
return ERR_OK; |
109 |
left = len; |
left = len; |
110 |
ptr = arg; |
ptr = arg; |
111 |
/* fail on too much data */ |
/* fail on too much data */ |
112 |
if(len > pcb->snd_buf) { |
if (len > pcb->snd_buf) { |
113 |
DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too much data (len=%d > snd_buf=%d)\n", len, pcb->snd_buf)); |
DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too much data (len=%d > snd_buf=%d)\n", len, pcb->snd_buf)); |
114 |
return ERR_MEM; |
return ERR_MEM; |
115 |
} |
} |
124 |
/* Check if the queue length exceeds the configured maximum queue |
/* Check if the queue length exceeds the configured maximum queue |
125 |
length. If so, we return an error. */ |
length. If so, we return an error. */ |
126 |
queuelen = pcb->snd_queuelen; |
queuelen = pcb->snd_queuelen; |
127 |
if(queuelen >= TCP_SND_QUEUELEN) { |
if (queuelen >= TCP_SND_QUEUELEN) { |
128 |
DEBUGF(TCP_OUTPUT_DEBUG | 3, ("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)); |
129 |
goto memerr; |
goto memerr; |
130 |
} |
} |
131 |
|
|
132 |
if(pcb->snd_queuelen != 0) { |
if (pcb->snd_queuelen != 0) { |
133 |
LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL || |
LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL || |
134 |
pcb->unsent != NULL); |
pcb->unsent != NULL); |
135 |
} |
} |
139 |
|
|
140 |
/* First, break up the data into segments and tuck them together in |
/* First, break up the data into segments and tuck them together in |
141 |
the local "queue" variable. */ |
the local "queue" variable. */ |
142 |
while(queue == NULL || left > 0) { |
while (queue == NULL || left > 0) { |
143 |
|
|
144 |
/* 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 |
145 |
is larger than the MSS. */ |
is larger than the MSS. */ |
147 |
|
|
148 |
/* Allocate memory for tcp_seg, and fill in fields. */ |
/* Allocate memory for tcp_seg, and fill in fields. */ |
149 |
seg = memp_malloc(MEMP_TCP_SEG); |
seg = memp_malloc(MEMP_TCP_SEG); |
150 |
if(seg == NULL) { |
if (seg == NULL) { |
151 |
DEBUGF(TCP_OUTPUT_DEBUG | 2, ("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")); |
152 |
goto memerr; |
goto memerr; |
153 |
} |
} |
154 |
seg->next = NULL; |
seg->next = NULL; |
155 |
seg->p = NULL; |
seg->p = NULL; |
156 |
|
|
157 |
if(queue == NULL) { |
if (queue == NULL) { |
158 |
queue = seg; |
queue = seg; |
159 |
} |
} |
160 |
else { |
else { |
168 |
ROM or other static memory, and need not be copied. If |
ROM or other static memory, and need not be copied. If |
169 |
optdata is != NULL, we have options instead of data. */ |
optdata is != NULL, we have options instead of data. */ |
170 |
if (optdata != NULL) { |
if (optdata != NULL) { |
171 |
if((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { |
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { |
172 |
goto memerr; |
goto memerr; |
173 |
} |
} |
174 |
++queuelen; |
++queuelen; |
175 |
seg->dataptr = seg->p->payload; |
seg->dataptr = seg->p->payload; |
176 |
} |
} |
177 |
else if (copy) { |
else if (copy) { |
178 |
if((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) { |
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) { |
179 |
DEBUGF(TCP_OUTPUT_DEBUG | 2, ("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)); |
180 |
goto memerr; |
goto memerr; |
181 |
} |
} |
182 |
++queuelen; |
++queuelen; |
183 |
if(arg != NULL) { |
if (arg != NULL) { |
184 |
memcpy(seg->p->payload, ptr, seglen); |
memcpy(seg->p->payload, ptr, seglen); |
185 |
} |
} |
186 |
seg->dataptr = seg->p->payload; |
seg->dataptr = seg->p->payload; |
193 |
* link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM |
* link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM |
194 |
* instead of PBUF_REF here. |
* instead of PBUF_REF here. |
195 |
*/ |
*/ |
196 |
if((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) { |
if ((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) { |
197 |
DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n")); |
DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n")); |
198 |
goto memerr; |
goto memerr; |
199 |
} |
} |
202 |
seg->dataptr = ptr; |
seg->dataptr = ptr; |
203 |
|
|
204 |
/* Second, allocate a pbuf for the headers. */ |
/* Second, allocate a pbuf for the headers. */ |
205 |
if((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) { |
if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) { |
206 |
/* If allocation fails, we have to deallocate the data pbuf as |
/* If allocation fails, we have to deallocate the data pbuf as |
207 |
well. */ |
well. */ |
208 |
pbuf_free(p); |
pbuf_free(p); |
218 |
|
|
219 |
/* Now that there are more segments queued, we check again if the |
/* Now that there are more segments queued, we check again if the |
220 |
length of the queue exceeds the configured maximum. */ |
length of the queue exceeds the configured maximum. */ |
221 |
if(queuelen > TCP_SND_QUEUELEN) { |
if (queuelen > TCP_SND_QUEUELEN) { |
222 |
DEBUGF(TCP_OUTPUT_DEBUG | 2, ("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)); |
223 |
goto memerr; |
goto memerr; |
224 |
} |
} |
225 |
|
|
226 |
seg->len = seglen; |
seg->len = seglen; |
227 |
/* if((flags & TCP_SYN) || (flags & TCP_FIN)) { |
/* if ((flags & TCP_SYN) || (flags & TCP_FIN)) { |
228 |
++seg->len; |
++seg->len; |
229 |
}*/ |
}*/ |
230 |
|
|
231 |
/* Build TCP header. */ |
/* Build TCP header. */ |
232 |
if(pbuf_header(seg->p, TCP_HLEN)) { |
if (pbuf_header(seg->p, TCP_HLEN)) { |
233 |
|
|
234 |
DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: no room for TCP header in pbuf.\n")); |
DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: no room for TCP header in pbuf.\n")); |
235 |
|
|
247 |
/* don't fill in tcphdr->ackno and tcphdr->wnd until later */ |
/* don't fill in tcphdr->ackno and tcphdr->wnd until later */ |
248 |
|
|
249 |
/* Copy the options into the header, if they are present. */ |
/* Copy the options into the header, if they are present. */ |
250 |
if(optdata == NULL) { |
if (optdata == NULL) { |
251 |
TCPH_OFFSET_SET(seg->tcphdr, 5 << 4); |
TCPH_OFFSET_SET(seg->tcphdr, 5 << 4); |
252 |
} |
} |
253 |
else { |
else { |
271 |
/* Now that the data to be enqueued has been broken up into TCP |
/* Now that the data to be enqueued has been broken up into TCP |
272 |
segments in the queue variable, we add them to the end of the |
segments in the queue variable, we add them to the end of the |
273 |
pcb->unsent queue. */ |
pcb->unsent queue. */ |
274 |
if(pcb->unsent == NULL) { |
if (pcb->unsent == NULL) { |
275 |
useg = NULL; |
useg = NULL; |
276 |
} |
} |
277 |
else { |
else { |
280 |
|
|
281 |
/* If there is room in the last pbuf on the unsent queue, |
/* If there is room in the last pbuf on the unsent queue, |
282 |
chain the first pbuf on the queue together with that. */ |
chain the first pbuf on the queue together with that. */ |
283 |
if(useg != NULL && |
if (useg != NULL && |
284 |
TCP_TCPLEN(useg) != 0 && |
TCP_TCPLEN(useg) != 0 && |
285 |
!(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) && |
!(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) && |
286 |
!(flags & (TCP_SYN | TCP_FIN)) && |
!(flags & (TCP_SYN | TCP_FIN)) && |
296 |
useg->next = queue->next; |
useg->next = queue->next; |
297 |
|
|
298 |
DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE | DBG_STATE, ("tcp_enqueue: chaining, new len %u\n", useg->len)); |
DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE | DBG_STATE, ("tcp_enqueue: chaining, new len %u\n", useg->len)); |
299 |
if(seg == queue) { |
if (seg == queue) { |
300 |
seg = NULL; |
seg = NULL; |
301 |
} |
} |
302 |
memp_free(MEMP_TCP_SEG, queue); |
memp_free(MEMP_TCP_SEG, queue); |
303 |
} |
} |
304 |
else { |
else { |
305 |
if(useg == NULL) { |
if (useg == NULL) { |
306 |
pcb->unsent = queue; |
pcb->unsent = queue; |
307 |
|
|
308 |
} |
} |
310 |
useg->next = queue; |
useg->next = queue; |
311 |
} |
} |
312 |
} |
} |
313 |
if((flags & TCP_SYN) || (flags & TCP_FIN)) { |
if ((flags & TCP_SYN) || (flags & TCP_FIN)) { |
314 |
++len; |
++len; |
315 |
} |
} |
316 |
pcb->snd_lbb += len; |
pcb->snd_lbb += len; |
317 |
pcb->snd_buf -= len; |
pcb->snd_buf -= len; |
318 |
pcb->snd_queuelen = queuelen; |
pcb->snd_queuelen = queuelen; |
319 |
DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d (after enqueued)\n", pcb->snd_queuelen)); |
DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d (after enqueued)\n", pcb->snd_queuelen)); |
320 |
if(pcb->snd_queuelen != 0) { |
if (pcb->snd_queuelen != 0) { |
321 |
LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL || |
LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL || |
322 |
pcb->unsent != NULL); |
pcb->unsent != NULL); |
323 |
|
|
325 |
|
|
326 |
/* Set the PSH flag in the last segment that we enqueued, but only |
/* Set the PSH flag in the last segment that we enqueued, but only |
327 |
if the segment has data (indicated by seglen > 0). */ |
if the segment has data (indicated by seglen > 0). */ |
328 |
if(seg != NULL && seglen > 0 && seg->tcphdr != NULL) { |
if (seg != NULL && seglen > 0 && seg->tcphdr != NULL) { |
329 |
TCPH_FLAGS_SET(seg->tcphdr, TCPH_FLAGS(seg->tcphdr) | TCP_PSH); |
TCPH_FLAGS_SET(seg->tcphdr, TCPH_FLAGS(seg->tcphdr) | TCP_PSH); |
330 |
} |
} |
331 |
|
|
335 |
++lwip_stats.tcp.memerr; |
++lwip_stats.tcp.memerr; |
336 |
#endif /* TCP_STATS */ |
#endif /* TCP_STATS */ |
337 |
|
|
338 |
if(queue != NULL) { |
if (queue != NULL) { |
339 |
tcp_segs_free(queue); |
tcp_segs_free(queue); |
340 |
} |
} |
341 |
if(pcb->snd_queuelen != 0) { |
if (pcb->snd_queuelen != 0) { |
342 |
LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL || |
LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL || |
343 |
pcb->unsent != NULL); |
pcb->unsent != NULL); |
344 |
|
|
363 |
code. If so, we do not output anything. Instead, we rely on the |
code. If so, we do not output anything. Instead, we rely on the |
364 |
input processing code to call us when input processing is done |
input processing code to call us when input processing is done |
365 |
with. */ |
with. */ |
366 |
if(tcp_input_pcb == pcb) { |
if (tcp_input_pcb == pcb) { |
367 |
return ERR_OK; |
return ERR_OK; |
368 |
} |
} |
369 |
|
|
378 |
sent (either because the ->unsent queue is empty or because the |
sent (either because the ->unsent queue is empty or because the |
379 |
window doesn't allow it) we'll have to construct an empty ACK |
window doesn't allow it) we'll have to construct an empty ACK |
380 |
segment and send it. */ |
segment and send it. */ |
381 |
if(pcb->flags & TF_ACK_NOW && |
if (pcb->flags & TF_ACK_NOW && |
382 |
(seg == NULL || |
(seg == NULL || |
383 |
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) { |
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) { |
384 |
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); |
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); |
385 |
p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); |
p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); |
386 |
if(p == NULL) { |
if (p == NULL) { |
387 |
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n")); |
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n")); |
388 |
return ERR_BUF; |
return ERR_BUF; |
389 |
} |
} |
411 |
} |
} |
412 |
|
|
413 |
#if TCP_OUTPUT_DEBUG |
#if TCP_OUTPUT_DEBUG |
414 |
if(seg == NULL) { |
if (seg == NULL) { |
415 |
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", pcb->unsent)); |
DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", pcb->unsent)); |
416 |
} |
} |
417 |
#endif /* TCP_OUTPUT_DEBUG */ |
#endif /* TCP_OUTPUT_DEBUG */ |
418 |
#if TCP_CWND_DEBUG |
#if TCP_CWND_DEBUG |
419 |
if(seg == NULL) { |
if (seg == NULL) { |
420 |
DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %lu, cwnd %lu, wnd %lu, seg == NULL, ack %lu\n", |
DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %lu, cwnd %lu, wnd %lu, seg == NULL, ack %lu\n", |
421 |
pcb->snd_wnd, pcb->cwnd, wnd, |
pcb->snd_wnd, pcb->cwnd, wnd, |
422 |
pcb->lastack)); |
pcb->lastack)); |
428 |
} |
} |
429 |
#endif /* TCP_CWND_DEBUG */ |
#endif /* TCP_CWND_DEBUG */ |
430 |
|
|
431 |
while(seg != NULL && |
while (seg != NULL && |
432 |
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) { |
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) { |
433 |
#if TCP_CWND_DEBUG |
#if TCP_CWND_DEBUG |
434 |
DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %lu, cwnd %lu, wnd %lu, effwnd %lu, seq %lu, ack %lu, i%d\n", |
DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %lu, cwnd %lu, wnd %lu, effwnd %lu, seq %lu, ack %lu, i%d\n", |
441 |
|
|
442 |
pcb->unsent = seg->next; |
pcb->unsent = seg->next; |
443 |
|
|
444 |
if(pcb->state != SYN_SENT) { |
if (pcb->state != SYN_SENT) { |
445 |
TCPH_FLAGS_SET(seg->tcphdr, TCPH_FLAGS(seg->tcphdr) | TCP_ACK); |
TCPH_FLAGS_SET(seg->tcphdr, TCPH_FLAGS(seg->tcphdr) | TCP_ACK); |
446 |
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); |
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); |
447 |
} |
} |
448 |
|
|
449 |
tcp_output_segment(seg, pcb); |
tcp_output_segment(seg, pcb); |
450 |
pcb->snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg); |
pcb->snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg); |
451 |
if(TCP_SEQ_LT(pcb->snd_max, pcb->snd_nxt)) { |
if (TCP_SEQ_LT(pcb->snd_max, pcb->snd_nxt)) { |
452 |
pcb->snd_max = pcb->snd_nxt; |
pcb->snd_max = pcb->snd_nxt; |
453 |
} |
} |
454 |
/* put segment on unacknowledged list if length > 0 */ |
/* put segment on unacknowledged list if length > 0 */ |
455 |
if(TCP_TCPLEN(seg) > 0) { |
if (TCP_TCPLEN(seg) > 0) { |
456 |
seg->next = NULL; |
seg->next = NULL; |
457 |
if(pcb->unacked == NULL) { |
if (pcb->unacked == NULL) { |
458 |
pcb->unacked = seg; |
pcb->unacked = seg; |
459 |
|
|
460 |
|
|
481 |
seg->tcphdr->ackno = htonl(pcb->rcv_nxt); |
seg->tcphdr->ackno = htonl(pcb->rcv_nxt); |
482 |
|
|
483 |
/* silly window avoidance */ |
/* silly window avoidance */ |
484 |
if(pcb->rcv_wnd < pcb->mss) { |
if (pcb->rcv_wnd < pcb->mss) { |
485 |
seg->tcphdr->wnd = 0; |
seg->tcphdr->wnd = 0; |
486 |
} else { |
} else { |
487 |
/* advertise our receive window size in this TCP segment */ |
/* advertise our receive window size in this TCP segment */ |
490 |
|
|
491 |
/* If we don't have a local IP address, we get one by |
/* If we don't have a local IP address, we get one by |
492 |
calling ip_route(). */ |
calling ip_route(). */ |
493 |
if(ip_addr_isany(&(pcb->local_ip))) { |
if (ip_addr_isany(&(pcb->local_ip))) { |
494 |
netif = ip_route(&(pcb->remote_ip)); |
netif = ip_route(&(pcb->remote_ip)); |
495 |
if(netif == NULL) { |
if (netif == NULL) { |
496 |
return; |
return; |
497 |
} |
} |
498 |
ip_addr_set(&(pcb->local_ip), &(netif->ip_addr)); |
ip_addr_set(&(pcb->local_ip), &(netif->ip_addr)); |
500 |
|
|
501 |
pcb->rtime = 0; |
pcb->rtime = 0; |
502 |
|
|
503 |
if(pcb->rttest == 0) { |
if (pcb->rttest == 0) { |
504 |
pcb->rttest = tcp_ticks; |
pcb->rttest = tcp_ticks; |
505 |
pcb->rtseq = ntohl(seg->tcphdr->seqno); |
pcb->rtseq = ntohl(seg->tcphdr->seqno); |
506 |
|
|
538 |
struct pbuf *p; |
struct pbuf *p; |
539 |
struct tcp_hdr *tcphdr; |
struct tcp_hdr *tcphdr; |
540 |
p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); |
p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); |
541 |
if(p == NULL) { |
if (p == NULL) { |
542 |
DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n")); |
DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n")); |
543 |
return; |
return; |
544 |
} |
} |
570 |
{ |
{ |
571 |
struct tcp_seg *seg; |
struct tcp_seg *seg; |
572 |
|
|
573 |
if(pcb->unacked == NULL) { |
if (pcb->unacked == NULL) { |
574 |
return; |
return; |
575 |
} |
} |
576 |
|
|