npcb->rcv_nxt = seqno + 1;
npcb->rcv_ann_right_edge = npcb->rcv_nxt;
npcb->snd_wnd = tcphdr->wnd;
+ npcb->snd_wnd_max = tcphdr->wnd;
npcb->ssthresh = npcb->snd_wnd;
npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
npcb->callback_arg = pcb->callback_arg;
pcb->rcv_ann_right_edge = pcb->rcv_nxt;
pcb->lastack = ackno;
pcb->snd_wnd = tcphdr->wnd;
+ pcb->snd_wnd_max = tcphdr->wnd;
pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
pcb->state = ESTABLISHED;
* data, and if so frees the memory of the buffered data. Next, is places the
* segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment
* is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until
- * i it has been removed from the buffer.
+ * it has been removed from the buffer.
*
* If the incoming segment constitutes an ACK for a segment that was used for RTT
* estimation, the RTT is estimated here as well.
(pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||
(pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {
pcb->snd_wnd = tcphdr->wnd;
+ /* keep track of the biggest window announced by the remote host to calculate
+ the maximum segment size */
+ if (pcb->snd_wnd_max < tcphdr->wnd) {
+ pcb->snd_wnd_max = tcphdr->wnd;
+ }
pcb->snd_wl1 = seqno;
pcb->snd_wl2 = ackno;
if (pcb->snd_wnd == 0) {
LWIP_UNUSED_ARG(apiflags);
LWIP_UNUSED_ARG(first_seg);
/* always create MSS-sized pbufs */
- alloc = pcb->mss;
+ alloc = max_length;
#else /* LWIP_NETIF_TX_SINGLE_PBUF */
if (length < max_length) {
/* Should we allocate an oversized pbuf, or just the minimum
u16_t concat_chksummed = 0;
#endif /* TCP_CHECKSUM_ON_COPY */
err_t err;
+ /* don't allocate segments bigger than half the maximum window we ever received */
+ u16_t mss_local = LWIP_MIN(pcb->mss, pcb->snd_wnd_max/2);
#if LWIP_NETIF_TX_SINGLE_PBUF
/* Always copy to try to create single pbufs for TX */
/* Usable space at the end of the last unsent segment */
unsent_optlen = LWIP_TCP_OPT_LENGTH(last_unsent->flags);
- space = pcb->mss - (last_unsent->len + unsent_optlen);
+ space = mss_local - (last_unsent->len + unsent_optlen);
/*
* Phase 1: Copy data directly into an oversized pbuf.
while (pos < len) {
struct pbuf *p;
u16_t left = len - pos;
- u16_t max_len = pcb->mss - optlen;
+ u16_t max_len = mss_local - optlen;
u16_t seglen = left > max_len ? max_len : left;
#if TCP_CHECKSUM_ON_COPY
u16_t chksum = 0;
if (apiflags & TCP_WRITE_FLAG_COPY) {
/* If copy is set, memory should be allocated and data copied
* into pbuf */
- if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, pcb->mss, &oversize, pcb, apiflags, queue == NULL)) == NULL) {
+ if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, mss_local, &oversize, pcb, apiflags, queue == NULL)) == NULL) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));
goto memerr;
}
/* Add any requested options. NB MSS option is only set on SYN
packets, so ignore it here */
- //LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
opts = (u32_t *)(void *)(seg->tcphdr + 1);
if (seg->flags & TF_SEG_OPTS_MSS) {
*opts = TCP_BUILD_MSS_OPTION(pcb->mss);