77#if LWIP_TCP_TIMESTAMPS
83#ifdef LWIP_HOOK_FILENAME
84#include LWIP_HOOK_FILENAME
88#ifdef LWIP_HOOK_TCP_OUT_TCPOPT_LENGTH
89#define LWIP_TCP_OPT_LENGTH_SEGMENT(flags, pcb) LWIP_HOOK_TCP_OUT_TCPOPT_LENGTH(pcb, LWIP_TCP_OPT_LENGTH(flags))
91#define LWIP_TCP_OPT_LENGTH_SEGMENT(flags, pcb) LWIP_TCP_OPT_LENGTH(flags)
96#if TCP_CHECKSUM_ON_COPY
97#define TCP_DATA_COPY(dst, src, len, seg) do { \
98 tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), \
99 len, &seg->chksum, &seg->chksum_swapped); \
100 seg->flags |= TF_SEG_DATA_CHECKSUMMED; } while(0)
101#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) \
102 tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), len, chksum, chksum_swapped);
104#define TCP_DATA_COPY(dst, src, len, seg) MEMCPY(dst, src, len)
105#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) MEMCPY(dst, src, len)
110#ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK
111#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK 0
114#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
115#ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK_FAIL
116#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK_FAIL(msg) LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING, msg)
122#ifndef TCP_OVERSIZE_CALC_LENGTH
123#define TCP_OVERSIZE_CALC_LENGTH(length) ((length) + TCP_OVERSIZE)
128static err_t tcp_output_segment(
struct tcp_seg *seg,
struct tcp_pcb *pcb,
struct netif *
netif);
129static err_t tcp_output_control_segment_netif(
const struct tcp_pcb *pcb,
struct pbuf *
p,
142 return ip_route(
src,
dst);
160static struct tcp_seg *
169 optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(optflags, pcb);
176 seg->flags = optflags;
179 LWIP_ASSERT(
"p->tot_len >= optlen",
p->tot_len >= optlen);
180 seg->len =
p->tot_len - optlen;
181#if TCP_OVERSIZE_DBGCHECK
182 seg->oversize_left = 0;
184#if TCP_CHECKSUM_ON_COPY
186 seg->chksum_swapped = 0;
188 LWIP_ASSERT(
"invalid optflags passed: TF_SEG_DATA_CHECKSUMMED",
189 (optflags & TF_SEG_DATA_CHECKSUMMED) == 0);
199 seg->tcphdr = (
struct tcp_hdr *)seg->p->payload;
200 seg->tcphdr->src =
lwip_htons(pcb->local_port);
201 seg->tcphdr->dest =
lwip_htons(pcb->remote_port);
206 seg->tcphdr->urgp = 0;
229 u16_t *oversize,
const struct tcp_pcb *pcb,
u8_t apiflags,
238#if LWIP_NETIF_TX_SINGLE_PBUF
245 if (
length < max_length) {
257 if ((apiflags & TCP_WRITE_FLAG_MORE) ||
258 (!(pcb->flags & TF_NODELAY) &&
260 pcb->unsent !=
NULL ||
261 pcb->unacked !=
NULL))) {
277#define tcp_pbuf_prealloc(layer, length, mx, os, pcb, api, fst) pbuf_alloc((layer), (length), PBUF_RAM)
280#if TCP_CHECKSUM_ON_COPY
287 u8_t *seg_chksum_swapped)
291 helper = chksum + *seg_chksum;
293 if ((
len & 1) != 0) {
294 *seg_chksum_swapped = 1 - *seg_chksum_swapped;
297 *seg_chksum = chksum;
308tcp_write_checks(
struct tcp_pcb *pcb,
u16_t len)
313 if ((pcb->state != ESTABLISHED) &&
314 (pcb->state != CLOSE_WAIT) &&
315 (pcb->state != SYN_SENT) &&
316 (pcb->state != SYN_RCVD)) {
319 }
else if (
len == 0) {
324 if (
len > pcb->snd_buf) {
327 tcp_set_flags(pcb, TF_NAGLEMEMERR);
340 tcp_set_flags(pcb, TF_NAGLEMEMERR);
343 if (pcb->snd_queuelen != 0) {
344 LWIP_ASSERT(
"tcp_write: pbufs on queue => at least one queue non-empty",
345 pcb->unacked !=
NULL || pcb->unsent !=
NULL);
347 LWIP_ASSERT(
"tcp_write: no pbufs on queue => both queues empty",
348 pcb->unacked ==
NULL && pcb->unsent ==
NULL);
393tcp_write(
struct tcp_pcb *pcb,
const void *
arg,
u16_t len,
u8_t apiflags)
403 u16_t oversize_used = 0;
404#if TCP_OVERSIZE_DBGCHECK
405 u16_t oversize_add = 0;
409#if TCP_CHECKSUM_ON_COPY
410 u16_t concat_chksum = 0;
411 u8_t concat_chksum_swapped = 0;
412 u16_t concat_chksummed = 0;
420 mss_local =
LWIP_MIN(pcb->mss, TCPWND_MIN16(pcb->snd_wnd_max / 2));
421 mss_local = mss_local ? mss_local : pcb->mss;
425#if LWIP_NETIF_TX_SINGLE_PBUF
427 apiflags |= TCP_WRITE_FLAG_COPY;
432 LWIP_ERROR(
"tcp_write: arg == NULL (programmer violates API)",
435 err = tcp_write_checks(pcb,
len);
439 queuelen = pcb->snd_queuelen;
441#if LWIP_TCP_TIMESTAMPS
442 if ((pcb->flags & TF_TIMESTAMP)) {
445 optflags = TF_SEG_OPTS_TS;
446 optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(TF_SEG_OPTS_TS, pcb);
448 mss_local =
LWIP_MAX(mss_local, LWIP_TCP_OPT_LEN_TS + 1);
452 optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(0, pcb);
479 if (pcb->unsent !=
NULL) {
484 for (last_unsent = pcb->unsent; last_unsent->next !=
NULL;
485 last_unsent = last_unsent->
next);
488 unsent_optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(last_unsent->flags, pcb);
489 LWIP_ASSERT(
"mss_local is too small", mss_local >= last_unsent->len + unsent_optlen);
490 space = mss_local - (last_unsent->len + unsent_optlen);
500#if TCP_OVERSIZE_DBGCHECK
502 LWIP_ASSERT(
"unsent_oversize mismatch (pcb vs. last_unsent)",
503 pcb->unsent_oversize == last_unsent->oversize_left);
505 oversize = pcb->unsent_oversize;
510 pos += oversize_used;
511 oversize -= oversize_used;
512 space -= oversize_used;
518#if !LWIP_NETIF_TX_SINGLE_PBUF
534 if ((
pos <
len) && (
space > 0) && (last_unsent->len > 0)) {
541 if (apiflags & TCP_WRITE_FLAG_COPY) {
543 if ((concat_p = tcp_pbuf_prealloc(
PBUF_RAW, seglen,
space, &oversize, pcb, apiflags, 1)) ==
NULL) {
545 (
"tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n",
549#if TCP_OVERSIZE_DBGCHECK
550 oversize_add = oversize;
552 TCP_DATA_COPY2(concat_p->
payload, (
const u8_t *)
arg +
pos, seglen, &concat_chksum, &concat_chksum_swapped);
553#if TCP_CHECKSUM_ON_COPY
554 concat_chksummed += seglen;
564 LWIP_ASSERT(
"tcp_write: ROM pbufs cannot be oversized",
pos == 0);
569 (
"tcp_write: could not allocate memory for zero-copy pbuf\n"));
576#if TCP_CHECKSUM_ON_COPY
579 &concat_chksum, &concat_chksum_swapped);
580 concat_chksummed += seglen;
589 LWIP_ASSERT(
"unsent_oversize mismatch (pcb->unsent is NULL)",
590 pcb->unsent_oversize == 0);
603 u16_t max_len = mss_local - optlen;
605#if TCP_CHECKSUM_ON_COPY
607 u8_t chksum_swapped = 0;
610 if (apiflags & TCP_WRITE_FLAG_COPY) {
617 LWIP_ASSERT(
"tcp_write: check that first pbuf can hold the complete seglen",
619 TCP_DATA_COPY2((
char *)
p->payload + optlen, (
const u8_t *)
arg +
pos, seglen, &chksum, &chksum_swapped);
634#if TCP_CHECKSUM_ON_COPY
636 chksum = ~inet_chksum((
const u8_t *)
arg +
pos, seglen);
672#if TCP_OVERSIZE_DBGCHECK
673 seg->oversize_left = oversize;
675#if TCP_CHECKSUM_ON_COPY
676 seg->chksum = chksum;
677 seg->chksum_swapped = chksum_swapped;
678 seg->flags |= TF_SEG_DATA_CHECKSUMMED;
687 prev_seg->next = seg;
694 lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg)));
703#if TCP_OVERSIZE_DBGCHECK
704 if ((last_unsent !=
NULL) && (oversize_add != 0)) {
705 last_unsent->oversize_left += oversize_add;
714 if (oversize_used > 0) {
717 for (
p = last_unsent->p;
p;
p =
p->next) {
718 p->tot_len += oversize_used;
719 if (
p->next ==
NULL) {
720 TCP_DATA_COPY((
char *)
p->payload +
p->len,
arg, oversize_used, last_unsent);
721 p->len += oversize_used;
724 last_unsent->len += oversize_used;
725#if TCP_OVERSIZE_DBGCHECK
726 LWIP_ASSERT(
"last_unsent->oversize_left >= oversize_used",
727 last_unsent->oversize_left >= oversize_used);
728 last_unsent->oversize_left -= oversize_used;
731 pcb->unsent_oversize = oversize;
738 if (concat_p !=
NULL) {
739 LWIP_ASSERT(
"tcp_write: cannot concatenate when pcb->unsent is empty",
740 (last_unsent !=
NULL));
742 last_unsent->len += concat_p->
tot_len;
743 }
else if (extendlen > 0) {
745 LWIP_ASSERT(
"tcp_write: extension of reference requires reference",
746 last_unsent !=
NULL && last_unsent->p !=
NULL);
747 for (
p = last_unsent->p;
p->next !=
NULL;
p =
p->
next) {
748 p->tot_len += extendlen;
750 p->tot_len += extendlen;
752 last_unsent->len += extendlen;
755#if TCP_CHECKSUM_ON_COPY
756 if (concat_chksummed) {
757 LWIP_ASSERT(
"tcp_write: concat checksum needs concatenated data",
758 concat_p !=
NULL || extendlen > 0);
760 if (concat_chksum_swapped) {
763 tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum,
764 &last_unsent->chksum_swapped);
765 last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED;
773 if (last_unsent ==
NULL) {
776 last_unsent->next =
queue;
784 pcb->snd_queuelen = queuelen;
788 if (pcb->snd_queuelen != 0) {
790 pcb->unacked !=
NULL || pcb->unsent !=
NULL);
794 if (seg !=
NULL && seg->tcphdr !=
NULL && ((apiflags & TCP_WRITE_FLAG_MORE) == 0)) {
800 tcp_set_flags(pcb, TF_NAGLEMEMERR);
803 if (concat_p !=
NULL) {
807 tcp_segs_free(
queue);
809 if (pcb->snd_queuelen != 0) {
811 pcb->unsent !=
NULL);
830tcp_split_unsent_seg(
struct tcp_pcb *pcb,
u16_t split)
832 struct tcp_seg *seg =
NULL, *useg =
NULL;
837 u8_t remainder_flags;
840#if TCP_CHECKSUM_ON_COPY
842 u8_t chksum_swapped = 0;
854 LWIP_ASSERT(
"Can't split segment into length 0", 0);
858 if (useg->len <=
split) {
871 optflags = useg->flags;
872#if TCP_CHECKSUM_ON_COPY
874 optflags &= ~TF_SEG_DATA_CHECKSUMMED;
876 optlen = LWIP_TCP_OPT_LENGTH(optflags);
883 (
"tcp_split_unsent_seg: could not allocate memory for pbuf remainder %u\n",
remainder));
892 (
"tcp_split_unsent_seg: could not copy pbuf remainder %u\n",
remainder));
895#if TCP_CHECKSUM_ON_COPY
898 &chksum, &chksum_swapped);
908 split_flags &= ~TCP_PSH;
912 split_flags &= ~TCP_FIN;
921 (
"tcp_split_unsent_seg: could not create new TCP segment\n"));
925#if TCP_CHECKSUM_ON_COPY
926 seg->chksum = chksum;
927 seg->chksum_swapped = chksum_swapped;
928 seg->flags |= TF_SEG_DATA_CHECKSUMMED;
939#if TCP_OVERSIZE_DBGCHECK
941 useg->oversize_left = 0;
947#if TCP_CHECKSUM_ON_COPY
950 useg->chksum_swapped = 0;
952 offset =
q->tot_len - useg->len;
963 &useg->chksum, &useg->chksum_swapped);
973 seg->next = useg->next;
979 if (seg->next ==
NULL) {
980 pcb->unsent_oversize = 0;
1010 if (pcb->unsent !=
NULL) {
1011 struct tcp_seg *last_unsent;
1012 for (last_unsent = pcb->unsent; last_unsent->next !=
NULL;
1013 last_unsent = last_unsent->
next);
1018 tcp_set_flags(pcb, TF_FIN);
1023 return tcp_enqueue_flags(pcb,
TCP_FIN);
1036tcp_enqueue_flags(
struct tcp_pcb *pcb,
u8_t flags)
1039 struct tcp_seg *seg;
1043 LWIP_ASSERT(
"tcp_enqueue_flags: need either TCP_SYN or TCP_FIN in flags (programmer violates API)",
1054 optflags = TF_SEG_OPTS_MSS;
1056 if ((pcb->state != SYN_RCVD) || (pcb->flags & TF_WND_SCALE)) {
1059 optflags |= TF_SEG_OPTS_WND_SCALE;
1062#if LWIP_TCP_SACK_OUT
1063 if ((pcb->state != SYN_RCVD) || (pcb->flags & TF_SACK)) {
1066 optflags |= TF_SEG_OPTS_SACK_PERM;
1070#if LWIP_TCP_TIMESTAMPS
1071 if ((pcb->flags & TF_TIMESTAMP) || ((
flags &
TCP_SYN) && (pcb->state != SYN_RCVD))) {
1074 optflags |= TF_SEG_OPTS_TS;
1077 optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(optflags, pcb);
1081 tcp_set_flags(pcb, TF_NAGLEMEMERR);
1085 LWIP_ASSERT(
"tcp_enqueue_flags: check that first pbuf can hold optlen",
1086 (
p->len >= optlen));
1090 tcp_set_flags(pcb, TF_NAGLEMEMERR);
1095 LWIP_ASSERT(
"tcp_enqueue_flags: invalid segment length", seg->len == 0);
1100 lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),
1104 if (pcb->unsent ==
NULL) {
1107 struct tcp_seg *useg;
1108 for (useg = pcb->unsent; useg->next !=
NULL; useg = useg->
next);
1113 pcb->unsent_oversize = 0;
1122 tcp_set_flags(pcb, TF_FIN);
1128 if (pcb->snd_queuelen != 0) {
1129 LWIP_ASSERT(
"tcp_enqueue_flags: invalid queue length",
1130 pcb->unacked !=
NULL || pcb->unsent !=
NULL);
1136#if LWIP_TCP_TIMESTAMPS
1143tcp_build_timestamp_option(
const struct tcp_pcb *pcb,
u32_t *opts)
1154#if LWIP_TCP_SACK_OUT
1166tcp_get_num_sacks(
const struct tcp_pcb *pcb,
u8_t optlen)
1172 if (pcb->flags & TF_SACK) {
1181 LWIP_TCP_SACK_VALID(pcb,
i); ++
i) {
1197tcp_build_sack_option(
const struct tcp_pcb *pcb,
u32_t *opts,
u8_t num_sacks)
1207 *(opts++) =
PP_HTONL(0x01010500 + 2 + num_sacks * 8);
1209 for (
i = 0;
i < num_sacks; ++
i) {
1223tcp_build_wnd_scale_option(
u32_t *opts)
1225 LWIP_ASSERT(
"tcp_build_wnd_scale_option: invalid opts", opts !=
NULL);
1241tcp_output(
struct tcp_pcb *pcb)
1243 struct tcp_seg *seg, *useg;
1255 LWIP_ASSERT(
"don't call tcp_output for listen-pcbs",
1256 pcb->state != LISTEN);
1262 if (tcp_input_pcb == pcb) {
1266 wnd =
LWIP_MIN(pcb->snd_wnd, pcb->cwnd);
1272 (
void *)pcb->unsent));
1274 ", cwnd %"TCPWNDSIZE_F
", wnd %"U32_F
1275 ", seg == NULL, ack %"U32_F"\n",
1276 pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack));
1280 if (pcb->flags & TF_ACK_NOW) {
1281 return tcp_send_empty_ack(pcb);
1287 (
"tcp_output: snd_wnd %"TCPWNDSIZE_F
", cwnd %"TCPWNDSIZE_F
", wnd %"U32_F
1289 pcb->snd_wnd, pcb->cwnd, wnd,
1290 lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
1291 lwip_ntohl(seg->tcphdr->seqno), pcb->lastack));
1294 netif = tcp_route(pcb, &pcb->local_ip, &pcb->remote_ip);
1301 const ip_addr_t *local_ip = ip_netif_get_local_ip(
netif, &pcb->remote_ip);
1302 if (local_ip ==
NULL) {
1309 if (
lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd) {
1316 if (wnd == pcb->snd_wnd && pcb->unacked ==
NULL && pcb->persist_backoff == 0) {
1317 pcb->persist_cnt = 0;
1318 pcb->persist_backoff = 1;
1319 pcb->persist_probe = 0;
1322 if (pcb->flags & TF_ACK_NOW) {
1323 return tcp_send_empty_ack(pcb);
1328 pcb->persist_backoff = 0;
1331 useg = pcb->unacked;
1333 for (; useg->next !=
NULL; useg = useg->
next);
1336 while (seg !=
NULL &&
1337 lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
1347 if ((tcp_do_output_nagle(pcb) == 0) &&
1348 ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)) {
1353 pcb->snd_wnd, pcb->cwnd, wnd,
1356 lwip_ntohl(seg->tcphdr->seqno), pcb->lastack,
i));
1360 if (pcb->state != SYN_SENT) {
1364 err = tcp_output_segment(seg, pcb,
netif);
1367 tcp_set_flags(pcb, TF_NAGLEMEMERR);
1370#if TCP_OVERSIZE_DBGCHECK
1371 seg->oversize_left = 0;
1373 pcb->unsent = seg->
next;
1374 if (pcb->state != SYN_SENT) {
1375 tcp_clear_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW);
1377 snd_nxt =
lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
1378 if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) {
1379 pcb->snd_nxt = snd_nxt;
1382 if (TCP_TCPLEN(seg) > 0) {
1385 if (pcb->unacked ==
NULL) {
1395 struct tcp_seg **cur_seg = &(pcb->unacked);
1398 cur_seg = &((*cur_seg)->next );
1400 seg->
next = (*cur_seg);
1415 if (pcb->unsent ==
NULL) {
1417 pcb->unsent_oversize = 0;
1422 tcp_clear_flags(pcb, TF_NAGLEMEMERR);
1436tcp_output_segment_busy(
const struct tcp_seg *seg)
1443 if (seg->p->ref != 1) {
1459tcp_output_segment(
struct tcp_seg *seg,
struct tcp_pcb *pcb,
struct netif *
netif)
1464#if TCP_CHECKSUM_ON_COPY
1465 int seg_chksum_was_swapped = 0;
1472 if (tcp_output_segment_busy(seg)) {
1481 seg->tcphdr->ackno =
lwip_htonl(pcb->rcv_nxt);
1485 if (seg->flags & TF_SEG_OPTS_WND_SCALE) {
1488 seg->tcphdr->wnd =
lwip_htons(TCPWND_MIN16(pcb->rcv_ann_wnd));
1492 seg->tcphdr->wnd =
lwip_htons(TCPWND_MIN16(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd)));
1495 pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
1500 opts = (
u32_t *)(
void *)(seg->tcphdr + 1);
1501 if (seg->flags & TF_SEG_OPTS_MSS) {
1503#if TCP_CALCULATE_EFF_SEND_MSS
1504 mss = tcp_eff_send_mss_netif(
TCP_MSS,
netif, &pcb->remote_ip);
1508 *opts = TCP_BUILD_MSS_OPTION(mss);
1511#if LWIP_TCP_TIMESTAMPS
1512 pcb->ts_lastacksent = pcb->rcv_nxt;
1514 if (seg->flags & TF_SEG_OPTS_TS) {
1515 tcp_build_timestamp_option(pcb, opts);
1520 if (seg->flags & TF_SEG_OPTS_WND_SCALE) {
1521 tcp_build_wnd_scale_option(opts);
1525#if LWIP_TCP_SACK_OUT
1526 if (seg->flags & TF_SEG_OPTS_SACK_PERM) {
1538 if (pcb->rtime < 0) {
1542 if (pcb->rttest == 0) {
1543 pcb->rttest = tcp_ticks;
1559 seg->p->tot_len -=
len;
1561 seg->p->payload = seg->tcphdr;
1563 seg->tcphdr->chksum = 0;
1565#ifdef LWIP_HOOK_TCP_OUT_ADD_TCPOPTS
1566 opts = LWIP_HOOK_TCP_OUT_ADD_TCPOPTS(seg->p, seg->tcphdr, pcb, opts);
1568 LWIP_ASSERT(
"options not filled", (
u8_t *)opts == ((
u8_t *)(seg->tcphdr + 1)) + LWIP_TCP_OPT_LENGTH_SEGMENT(seg->flags, pcb));
1572#if TCP_CHECKSUM_ON_COPY
1574#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
1576 seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip);
1578 if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) {
1585 seg->p->tot_len,
TCPH_HDRLEN_BYTES(seg->tcphdr), &pcb->local_ip, &pcb->remote_ip);
1587 if (seg->chksum_swapped) {
1588 seg_chksum_was_swapped = 1;
1590 seg->chksum_swapped = 0;
1592 acc = (
u16_t)~acc + seg->chksum;
1593 seg->tcphdr->chksum = (
u16_t)~FOLD_U32T(acc);
1594#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
1595 if (chksum_slow != seg->tcphdr->chksum) {
1597 (
"tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"\n",
1598 seg->tcphdr->chksum, chksum_slow));
1599 seg->tcphdr->chksum = chksum_slow;
1604 seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip);
1611 err = ip_output_if(seg->p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl,
1615#if TCP_CHECKSUM_ON_COPY
1616 if (seg_chksum_was_swapped) {
1620 seg->chksum_swapped = 1;
1635tcp_rexmit_rto_prepare(
struct tcp_pcb *pcb)
1637 struct tcp_seg *seg;
1641 if (pcb->unacked ==
NULL) {
1649 for (seg = pcb->unacked; seg->next !=
NULL; seg = seg->
next) {
1650 if (tcp_output_segment_busy(seg)) {
1655 if (tcp_output_segment_busy(seg)) {
1660 seg->next = pcb->unsent;
1661#if TCP_OVERSIZE_DBGCHECK
1663 if (pcb->unsent ==
NULL) {
1664 pcb->unsent_oversize = seg->oversize_left;
1668 pcb->unsent = pcb->unacked;
1670 pcb->unacked =
NULL;
1673 tcp_set_flags(pcb, TF_RTO);
1675 pcb->rto_end =
lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
1690tcp_rexmit_rto_commit(
struct tcp_pcb *pcb)
1695 if (pcb->nrtx < 0xFF) {
1711tcp_rexmit_rto(
struct tcp_pcb *pcb)
1715 if (tcp_rexmit_rto_prepare(pcb) ==
ERR_OK) {
1716 tcp_rexmit_rto_commit(pcb);
1728tcp_rexmit(
struct tcp_pcb *pcb)
1730 struct tcp_seg *seg;
1731 struct tcp_seg **cur_seg;
1735 if (pcb->unacked ==
NULL) {
1743 if (tcp_output_segment_busy(seg)) {
1750 pcb->unacked = seg->next;
1752 cur_seg = &(pcb->unsent);
1755 cur_seg = &((*cur_seg)->next );
1757 seg->next = *cur_seg;
1760 if (seg->next ==
NULL) {
1762 pcb->unsent_oversize = 0;
1766 if (pcb->nrtx < 0xFF) {
1787tcp_rexmit_fast(
struct tcp_pcb *pcb)
1791 if (pcb->unacked !=
NULL && !(pcb->flags & TF_INFR)) {
1795 "), fast retransmit %"U32_F"\n",
1796 (
u16_t)pcb->dupacks, pcb->lastack,
1798 if (tcp_rexmit(pcb) ==
ERR_OK) {
1801 pcb->ssthresh =
LWIP_MIN(pcb->cwnd, pcb->snd_wnd) / 2;
1804 if (pcb->ssthresh < (2U * pcb->mss)) {
1806 (
"tcp_receive: The minimum value for ssthresh %"TCPWNDSIZE_F
1807 " should be min 2 mss %"U16_F"...\n",
1808 pcb->ssthresh, (
u16_t)(2 * pcb->mss)));
1809 pcb->ssthresh = 2 * pcb->mss;
1812 pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
1813 tcp_set_flags(pcb, TF_INFR);
1831 LWIP_ASSERT(
"check that first pbuf can hold struct tcp_hdr",
1836 tcphdr->seqno = seqno_be;
1864 p = tcp_output_alloc_header_common(pcb->rcv_nxt, optlen,
datalen,
1865 seqno_be, pcb->local_port, pcb->remote_port,
TCP_ACK,
1866 TCPWND_MIN16(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd)));
1869 pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
1876tcp_output_fill_options(
const struct tcp_pcb *pcb,
struct pbuf *
p,
u8_t optflags,
u8_t num_sacks)
1880 u16_t sacks_len = 0;
1889#if LWIP_TCP_TIMESTAMPS
1890 if (optflags & TF_SEG_OPTS_TS) {
1891 tcp_build_timestamp_option(pcb, opts);
1896#if LWIP_TCP_SACK_OUT
1897 if (pcb && (num_sacks > 0)) {
1898 tcp_build_sack_option(pcb, opts, num_sacks);
1900 sacks_len = 1 + num_sacks * 2;
1907#ifdef LWIP_HOOK_TCP_OUT_ADD_TCPOPTS
1908 opts = LWIP_HOOK_TCP_OUT_ADD_TCPOPTS(
p,
tcphdr, pcb, opts);
1913 LWIP_ASSERT(
"options not filled", (
u8_t *)opts == ((
u8_t *)(
tcphdr + 1)) + sacks_len * 4 + LWIP_TCP_OPT_LENGTH_SEGMENT(optflags, pcb));
1925tcp_output_control_segment(
const struct tcp_pcb *pcb,
struct pbuf *
p,
1937 return tcp_output_control_segment_netif(pcb,
p,
src,
dst,
netif);
1946tcp_output_control_segment_netif(
const struct tcp_pcb *pcb,
struct pbuf *
p,
1980tcp_rst_common(
const struct tcp_pcb *pcb,
u32_t seqno,
u32_t ackno,
1991 optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(0, pcb);
1999 p = tcp_output_alloc_header_common(ackno, optlen, 0,
lwip_htonl(seqno), local_port,
2005 tcp_output_fill_options(pcb,
p, 0, 0);
2034tcp_rst(
const struct tcp_pcb *pcb,
u32_t seqno,
u32_t ackno,
2040 p = tcp_rst_common(pcb, seqno, ackno, local_ip, remote_ip, local_port, remote_port);
2042 tcp_output_control_segment(pcb,
p, local_ip, remote_ip);
2071 struct pbuf *
p = tcp_rst_common(
NULL, seqno, ackno, local_ip, remote_ip, local_port, remote_port);
2073 tcp_output_control_segment_netif(
NULL,
p, local_ip, remote_ip,
netif);
2086tcp_send_empty_ack(
struct tcp_pcb *pcb)
2090 u8_t optlen, optflags = 0;
2095#if LWIP_TCP_TIMESTAMPS
2096 if (pcb->flags & TF_TIMESTAMP) {
2097 optflags = TF_SEG_OPTS_TS;
2100 optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(optflags, pcb);
2102#if LWIP_TCP_SACK_OUT
2104 if ((num_sacks = tcp_get_num_sacks(pcb, optlen)) > 0) {
2105 optlen += 4 + num_sacks * 8;
2109 p = tcp_output_alloc_header(pcb, optlen, 0,
lwip_htonl(pcb->snd_nxt));
2112 tcp_set_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW);
2116 tcp_output_fill_options(pcb,
p, optflags, num_sacks);
2118#if LWIP_TCP_TIMESTAMPS
2119 pcb->ts_lastacksent = pcb->rcv_nxt;
2123 (
"tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));
2124 err = tcp_output_control_segment(pcb,
p, &pcb->local_ip, &pcb->remote_ip);
2127 tcp_set_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW);
2130 tcp_clear_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW);
2149 u8_t optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(0, pcb);
2158 tcp_ticks, pcb->tmr, (
u16_t)pcb->keep_cnt_sent));
2160 p = tcp_output_alloc_header(pcb, optlen, 0,
lwip_htonl(pcb->snd_nxt - 1));
2163 (
"tcp_keepalive: could not allocate memory for pbuf\n"));
2166 tcp_output_fill_options(pcb,
p, 0, 0);
2167 err = tcp_output_control_segment(pcb,
p, &pcb->local_ip, &pcb->remote_ip);
2170 pcb->snd_nxt - 1, pcb->rcv_nxt, (
int)
err));
2183tcp_zero_window_probe(
struct tcp_pcb *pcb)
2188 struct tcp_seg *seg;
2192 u8_t optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(0, pcb);
2201 (
"tcp_zero_window_probe: tcp_ticks %"U32_F
2202 " pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",
2203 tcp_ticks, pcb->tmr, (
u16_t)pcb->keep_cnt_sent));
2216 if (pcb->persist_probe < 0xFF) {
2217 ++pcb->persist_probe;
2222 len = is_fin ? 0 : 1;
2224 p = tcp_output_alloc_header(pcb, optlen,
len, seg->tcphdr->seqno);
2244 snd_nxt =
lwip_ntohl(seg->tcphdr->seqno) + 1;
2245 if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) {
2246 pcb->snd_nxt = snd_nxt;
2248 tcp_output_fill_options(pcb,
p, 0, 0);
2250 err = tcp_output_control_segment(pcb,
p, &pcb->local_ip, &pcb->remote_ip);
2253 " ackno %"U32_F" err %d.\n",
2254 pcb->snd_nxt - 1, pcb->rcv_nxt, (
int)
err));
static LPSTR * split(LPSTR s, LPINT args)
#define LWIP_DEBUGF(debug, message)
#define LWIP_ERROR(message, expression, handler)
#define LWIP_ASSERT(message, assertion)
GLdouble GLdouble GLdouble GLdouble q
GLuint GLsizei GLsizei * length
GLenum GLuint GLint GLint layer
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
#define LWIP_UNUSED_ARG(x)
#define LWIP_CONST_CAST(target_type, val)
#define LWIP_MEM_ALIGN_SIZE(size)
#define LWIP_DBG_LEVEL_SERIOUS
#define LWIP_DBG_LEVEL_SEVERE
#define LWIP_ASSERT_CORE_LOCKED()
#define LWIP_TCP_MAX_SACK_NUM
struct netif * netif_get_by_index(u8_t idx)
void pbuf_realloc(struct pbuf *p, u16_t new_len)
void pbuf_cat(struct pbuf *h, struct pbuf *t)
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
u8_t pbuf_free(struct pbuf *p)
u16_t pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
u16_t inet_chksum(const void *dataptr, u16_t len)
u16_t ip_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, const ip_addr_t *src, const ip_addr_t *dest)
u16_t ip_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, u16_t chksum_len, const ip_addr_t *src, const ip_addr_t *dest)
#define SWAP_BYTES_IN_WORD(w)
#define ip_addr_isany(ipaddr)
#define ip_addr_copy(dest, src)
#define ip_addr_debug_print_val(debug, ipaddr)
int const JOCTET unsigned int datalen
#define TCPH_HDRLEN_BYTES(phdr)
#define TCPH_SET_FLAG(phdr, flags)
#define TCPH_HDRLEN_FLAGS_SET(phdr, len, flags)
#define TCP_MAX_OPTION_BYTES
#define TCPH_FLAGS_SET(phdr, flags)
#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK_FAIL(printfmsg)
void * memp_malloc(memp_t type)
double __cdecl remainder(double, double)
#define NETIF_RESET_HINTS(netif)
#define IF__NETIF_CHECKSUM_ENABLED(netif, chksumflag)
#define NETIF_SET_HINTS(netif, netifhint)
u8_t pbuf_add_header(struct pbuf *p, size_t header_size_increment)
u16_t pbuf_clen(const struct pbuf *p)
#define PBUF_TYPE_FLAG_DATA_VOLATILE
#define PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS
#define MIB2_STATS_INC(x)
struct pbuf * tcp_create_segment(ip_addr_t *src_ip, ip_addr_t *dst_ip, u16_t src_port, u16_t dst_port, void *data, size_t data_len, u32_t seqno, u32_t ackno, u8_t headerflags)
void tcp_send_fin(struct sock *sk)