176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @file
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Transmission Control Protocol, outgoing traffic
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The output functions of TCP.
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * All rights reserved.
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Redistribution and use in source and binary forms, with or without modification,
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * are permitted provided that the following conditions are met:
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1. Redistributions of source code must retain the above copyright notice,
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *    this list of conditions and the following disclaimer.
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 2. Redistributions in binary form must reproduce the above copyright notice,
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *    this list of conditions and the following disclaimer in the documentation
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *    and/or other materials provided with the distribution.
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 3. The name of the author may not be used to endorse or promote products
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *    derived from this software without specific prior written permission.
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * OF SUCH DAMAGE.
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This file is part of the lwIP TCP/IP stack.
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Author: Adam Dunkels <adam@sics.se>
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/opt.h"
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/tcp_impl.h"
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/def.h"
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/mem.h"
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/memp.h"
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/sys.h"
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/ip_addr.h"
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/netif.h"
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/inet_chksum.h"
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/stats.h"
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/snmp.h"
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <string.h>
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Define some copy-macros for checksum-on-copy so that the code looks
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   nicer by preventing too many ifdef's. */
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_CHECKSUM_ON_COPY
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define TCP_DATA_COPY(dst, src, len, seg) do { \
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), \
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                     len, &seg->chksum, &seg->chksum_swapped); \
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->flags |= TF_SEG_DATA_CHECKSUMMED; } while(0)
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped)  \
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), len, chksum, chksum_swapped);
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else /* TCP_CHECKSUM_ON_COPY*/
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define TCP_DATA_COPY(dst, src, len, seg)                     MEMCPY(dst, src, len)
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) MEMCPY(dst, src, len)
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_CHECKSUM_ON_COPY*/
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Define this to 1 for an extra check that the output checksum is valid
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * (usefule when the checksum is generated by the application, not the stack) */
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK   0
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Forward declarations.*/
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Allocate a pbuf and create a tcphdr at p->payload, used for output
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * functions other than the default tcp_output -> tcp_output_segment
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * (e.g. tcp_send_empty_ack, etc.)
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param pcb tcp pcb for which to send a packet (used to initialize tcp_hdr)
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param optlen length of header-options
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param datalen length of tcp data to reserve in pbuf
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param seqno_be seqno in network byte order (big-endian)
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return pbuf with p->payload being the tcp_hdr
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct pbuf *
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantcp_output_alloc_header(struct tcp_pcb *pcb, u16_t optlen, u16_t datalen,
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                      u32_t seqno_be /* already in network byte order */)
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct tcp_hdr *tcphdr;
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct pbuf *p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen + datalen, PBUF_RAM);
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (p != NULL) {
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                 (p->len >= TCP_HLEN + optlen));
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    tcphdr = (struct tcp_hdr *)p->payload;
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    tcphdr->src = htons(pcb->local_port);
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    tcphdr->dest = htons(pcb->remote_port);
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    tcphdr->seqno = seqno_be;
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    tcphdr->ackno = htonl(pcb->rcv_nxt);
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), TCP_ACK);
10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    tcphdr->wnd = htons(pcb->rcv_ann_wnd);
10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    tcphdr->chksum = 0;
10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    tcphdr->urgp = 0;
10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* If we're sending a packet, update the announced right window edge */
11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return p;
11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Called by tcp_close() to send a segment including FIN flag but not data.
11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param pcb the tcp_pcb over which to send a segment
12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return ERR_OK if sent, another err_t otherwise
12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_t
12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantcp_send_fin(struct tcp_pcb *pcb)
12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* first, try to add the fin to the last unsent segment */
12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (pcb->unsent != NULL) {
12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct tcp_seg *last_unsent;
12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (last_unsent = pcb->unsent; last_unsent->next != NULL;
12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         last_unsent = last_unsent->next);
13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) {
13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* no SYN/FIN/RST flag in the header, we can add the FIN flag */
13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      TCPH_SET_FLAG(last_unsent->tcphdr, TCP_FIN);
13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      return ERR_OK;
13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* no data, no length, flags, copy=1, no optdata */
13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return tcp_enqueue_flags(pcb, TCP_FIN);
13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Create a TCP segment with prefilled header.
14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Called by tcp_write and tcp_enqueue_flags.
14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param pcb Protocol control block for the TCP connection.
14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param p pbuf that is used to hold the TCP header.
14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param flags TCP flags for header.
14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param seqno TCP sequence number of this packet
15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param optflags options to include in TCP header
15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return a new tcp_seg pointing to p, or NULL.
15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The TCP header is filled in except ackno and wnd.
15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * p is freed on failure.
15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct tcp_seg *
15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno, u8_t optflags)
15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct tcp_seg *seg;
15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u8_t optlen = LWIP_TCP_OPT_LENGTH(optflags);
16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if ((seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG)) == NULL) {
16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no memory.\n"));
16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pbuf_free(p);
16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return NULL;
16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->flags = optflags;
16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->next = NULL;
16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->p = p;
16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->len = p->tot_len - optlen;
17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_OVERSIZE_DBGCHECK
17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->oversize_left = 0;
17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_OVERSIZE_DBGCHECK */
17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_CHECKSUM_ON_COPY
17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->chksum = 0;
17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->chksum_swapped = 0;
17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* check optflags */
17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ASSERT("invalid optflags passed: TF_SEG_DATA_CHECKSUMMED",
17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman              (optflags & TF_SEG_DATA_CHECKSUMMED) == 0);
17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_CHECKSUM_ON_COPY */
18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* build TCP header */
18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (pbuf_header(p, TCP_HLEN)) {
18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no room for TCP header in pbuf.\n"));
18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    TCP_STATS_INC(tcp.err);
18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    tcp_seg_free(seg);
18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return NULL;
18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->tcphdr = (struct tcp_hdr *)seg->p->payload;
18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->tcphdr->src = htons(pcb->local_port);
19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->tcphdr->dest = htons(pcb->remote_port);
19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->tcphdr->seqno = htonl(seqno);
19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* ackno is set in tcp_output */
19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  TCPH_HDRLEN_FLAGS_SET(seg->tcphdr, (5 + optlen / 4), flags);
19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* wnd and chksum are set in tcp_output */
19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->tcphdr->urgp = 0;
19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return seg;
19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Allocate a PBUF_RAM pbuf, perhaps with extra space at the end.
20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This function is like pbuf_alloc(layer, length, PBUF_RAM) except
20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * there may be extra bytes available at the end.
20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param layer flag to define header size.
20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param length size of the pbuf's payload.
20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param max_length maximum usable size of payload+oversize.
20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param oversize pointer to a u16_t that will receive the number of usable tail bytes.
20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param pcb The TCP connection that willo enqueue the pbuf.
21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param apiflags API flags given to tcp_write.
21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param first_seg true when this pbuf will be used in the first enqueued segment.
21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param
21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_OVERSIZE
21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct pbuf *
21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length,
21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                  u16_t *oversize, struct tcp_pcb *pcb, u8_t apiflags,
21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                  u8_t first_seg)
21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct pbuf *p;
22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u16_t alloc = length;
22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_NETIF_TX_SINGLE_PBUF
22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_UNUSED_ARG(max_length);
22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_UNUSED_ARG(pcb);
22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_UNUSED_ARG(apiflags);
22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_UNUSED_ARG(first_seg);
22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* always create MSS-sized pbufs */
22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  alloc = TCP_MSS;
23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else /* LWIP_NETIF_TX_SINGLE_PBUF */
23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (length < max_length) {
23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Should we allocate an oversized pbuf, or just the minimum
23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * length required? If tcp_write is going to be called again
23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * before this segment is transmitted, we want the oversized
23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * buffer. If the segment will be transmitted immediately, we can
23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * save memory by allocating only length. We use a simple
23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * heuristic based on the following information:
23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *
23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * Did the user set TCP_WRITE_FLAG_MORE?
24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *
24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * Will the Nagle algorithm defer transmission of this segment?
24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     */
24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if ((apiflags & TCP_WRITE_FLAG_MORE) ||
24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        (!(pcb->flags & TF_NODELAY) &&
24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         (!first_seg ||
24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          pcb->unsent != NULL ||
24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          pcb->unacked != NULL))) {
24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      alloc = LWIP_MIN(max_length, LWIP_MEM_ALIGN_SIZE(length + TCP_OVERSIZE));
24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  p = pbuf_alloc(layer, alloc, PBUF_RAM);
25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (p == NULL) {
25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return NULL;
25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ASSERT("need unchained pbuf", p->next == NULL);
25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  *oversize = p->len - length;
25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* trim p->len to the currently used size */
25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  p->len = p->tot_len = length;
26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return p;
26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else /* TCP_OVERSIZE */
26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define tcp_pbuf_prealloc(layer, length, mx, os, pcb, api, fst) pbuf_alloc((layer), (length), PBUF_RAM)
26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_OVERSIZE */
26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_CHECKSUM_ON_COPY
26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Add a checksum of newly added data to the segment */
26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantcp_seg_add_chksum(u16_t chksum, u16_t len, u16_t *seg_chksum,
27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                   u8_t *seg_chksum_swapped)
27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u32_t helper;
27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* add chksum to old chksum and fold to u16_t */
27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  helper = chksum + *seg_chksum;
27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  chksum = FOLD_U32T(helper);
27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if ((len & 1) != 0) {
27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    *seg_chksum_swapped = 1 - *seg_chksum_swapped;
27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    chksum = SWAP_BYTES_IN_WORD(chksum);
27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  *seg_chksum = chksum;
28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_CHECKSUM_ON_COPY */
28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Checks if tcp_write is allowed or not (checks state, snd_buf and snd_queuelen).
28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param pcb the tcp pcb to check for
28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param len length of data to send (checked agains snd_buf)
28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return ERR_OK if tcp_write is allowed to proceed, another err_t otherwise
28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic err_t
29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantcp_write_checks(struct tcp_pcb *pcb, u16_t len)
29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* connection is in invalid state for data transmission? */
29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if ((pcb->state != ESTABLISHED) &&
29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      (pcb->state != CLOSE_WAIT) &&
29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      (pcb->state != SYN_SENT) &&
29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      (pcb->state != SYN_RCVD)) {
29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | LWIP_DBG_LEVEL_SEVERE, ("tcp_write() called in invalid state\n"));
29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return ERR_CONN;
30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  } else if (len == 0) {
30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return ERR_OK;
30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* fail on too much data */
30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (len > pcb->snd_buf) {
30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n",
30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      len, pcb->snd_buf));
30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->flags |= TF_NAGLEMEMERR;
30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return ERR_MEM;
31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen));
31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* If total number of pbufs on the unsent/unacked queues exceeds the
31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * configured maximum, return an error */
31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* check for configured max queuelen and possible overflow */
31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too long queue %"U16_F" (max %"U16_F")\n",
31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      pcb->snd_queuelen, TCP_SND_QUEUELEN));
32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    TCP_STATS_INC(tcp.memerr);
32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->flags |= TF_NAGLEMEMERR;
32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return ERR_MEM;
32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (pcb->snd_queuelen != 0) {
32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_ASSERT("tcp_write: pbufs on queue => at least one queue non-empty",
32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      pcb->unacked != NULL || pcb->unsent != NULL);
32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  } else {
32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_ASSERT("tcp_write: no pbufs on queue => both queues empty",
32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      pcb->unacked == NULL && pcb->unsent == NULL);
33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return ERR_OK;
33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Write data for sending (but does not send it immediately).
33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * It waits in the expectation of more data being sent soon (as
33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * it can send them more efficiently by combining them together).
33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * To prompt the system to send data now, call tcp_output() after
34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * calling tcp_write().
34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param pcb Protocol control block for the TCP connection to enqueue data for.
34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param arg Pointer to the data to be enqueued for sending.
34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param len Data length in bytes
34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param apiflags combination of following flags :
34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack
34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent,
34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return ERR_OK if enqueued, another err_t on error
34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_t
35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct pbuf *concat_p = NULL;
35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct tcp_seg *last_unsent = NULL, *seg = NULL, *prev_seg = NULL, *queue = NULL;
35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u16_t pos = 0; /* position in 'arg' data */
35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u16_t queuelen;
35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u8_t optlen = 0;
35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u8_t optflags = 0;
35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_OVERSIZE
36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u16_t oversize = 0;
36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u16_t oversize_used = 0;
36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_OVERSIZE */
36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_CHECKSUM_ON_COPY
36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u16_t concat_chksum = 0;
36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u8_t concat_chksum_swapped = 0;
36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u16_t concat_chksummed = 0;
36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_CHECKSUM_ON_COPY */
36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  err_t err;
36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_NETIF_TX_SINGLE_PBUF
37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Always copy to try to create single pbufs for TX */
37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  apiflags |= TCP_WRITE_FLAG_COPY;
37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n",
37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    (void *)pcb, arg, len, (u16_t)apiflags));
37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ERROR("tcp_write: arg == NULL (programmer violates API)",
37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman             arg != NULL, return ERR_ARG;);
37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  err = tcp_write_checks(pcb, len);
38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (err != ERR_OK) {
38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return err;
38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  queuelen = pcb->snd_queuelen;
38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_TCP_TIMESTAMPS
38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if ((pcb->flags & TF_TIMESTAMP)) {
38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    optflags = TF_SEG_OPTS_TS;
38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_TCP_TIMESTAMPS */
39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /*
39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * TCP segmentation is done in three phases with increasing complexity:
39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   *
39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * 1. Copy data directly into an oversized pbuf.
39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * 2. Chain a new pbuf to the end of pcb->unsent.
39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * 3. Create new segments.
40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   *
40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * We may run out of memory at any point. In that case we must
40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * return ERR_MEM and not change anything in pcb. Therefore, all
40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * changes are recorded in local variables and committed at the end
40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * of the function. Some pcb fields are maintained in local copies:
40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   *
40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * queuelen = pcb->snd_queuelen
40776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * oversize = pcb->unsent_oversize
40876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   *
40976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * These variables are set consistently by the phases:
41076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   *
41176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * seg points to the last segment tampered with.
41276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   *
41376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * pos records progress as data is segmented.
41476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   */
41576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
41676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Find the tail of the unsent queue. */
41776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (pcb->unsent != NULL) {
41876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u16_t space;
41976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u16_t unsent_optlen;
42076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
42176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* @todo: this could be sped up by keeping last_unsent in the pcb */
42276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (last_unsent = pcb->unsent; last_unsent->next != NULL;
42376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         last_unsent = last_unsent->next);
42476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
42576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Usable space at the end of the last unsent segment */
42676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    unsent_optlen = LWIP_TCP_OPT_LENGTH(last_unsent->flags);
42776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    space = pcb->mss - (last_unsent->len + unsent_optlen);
42876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
42976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /*
43076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * Phase 1: Copy data directly into an oversized pbuf.
43176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *
43276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * The number of bytes copied is recorded in the oversize_used
43376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * variable. The actual copying is done at the bottom of the
43476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * function.
43576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     */
43676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_OVERSIZE
43776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_OVERSIZE_DBGCHECK
43876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* check that pcb->unsent_oversize matches last_unsent->unsent_oversize */
43976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_ASSERT("unsent_oversize mismatch (pcb vs. last_unsent)",
44076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                pcb->unsent_oversize == last_unsent->oversize_left);
44176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_OVERSIZE_DBGCHECK */
44276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    oversize = pcb->unsent_oversize;
44376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (oversize > 0) {
44476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_ASSERT("inconsistent oversize vs. space", oversize_used <= space);
44576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      seg = last_unsent;
44676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      oversize_used = oversize < len ? oversize : len;
44776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      pos += oversize_used;
44876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      oversize -= oversize_used;
44976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      space -= oversize_used;
45076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
45176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* now we are either finished or oversize is zero */
45276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_ASSERT("inconsistend oversize vs. len", (oversize == 0) || (pos == len));
45376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_OVERSIZE */
45476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
45576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /*
45676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * Phase 2: Chain a new pbuf to the end of pcb->unsent.
45776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *
45876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * We don't extend segments containing SYN/FIN flags or options
45976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * (len==0). The new pbuf is kept in concat_p and pbuf_cat'ed at
46076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * the end.
46176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     */
46276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if ((pos < len) && (space > 0) && (last_unsent->len > 0)) {
46376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      u16_t seglen = space < len - pos ? space : len - pos;
46476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      seg = last_unsent;
46576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
46676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* Create a pbuf with a copy or reference to seglen bytes. We
46776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       * can use PBUF_RAW here since the data appears in the middle of
46876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       * a segment. A header will never be prepended. */
46976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if (apiflags & TCP_WRITE_FLAG_COPY) {
47076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* Data is copied */
47176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        if ((concat_p = tcp_pbuf_prealloc(PBUF_RAW, seglen, space, &oversize, pcb, apiflags, 1)) == NULL) {
47276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,
47376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                      ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n",
47476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                       seglen));
47576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          goto memerr;
47676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        }
47776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_OVERSIZE_DBGCHECK
47876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        last_unsent->oversize_left = oversize;
47976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_OVERSIZE_DBGCHECK */
48076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        TCP_DATA_COPY2(concat_p->payload, (u8_t*)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped);
48176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_CHECKSUM_ON_COPY
48276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        concat_chksummed += seglen;
48376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_CHECKSUM_ON_COPY */
48476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      } else {
48576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* Data is not copied */
48676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) {
48776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,
48876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                      ("tcp_write: could not allocate memory for zero-copy pbuf\n"));
48976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          goto memerr;
49076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        }
49176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_CHECKSUM_ON_COPY
49276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* calculate the checksum of nocopy-data */
49376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        tcp_seg_add_chksum(~inet_chksum((u8_t*)arg + pos, seglen), seglen,
49476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          &concat_chksum, &concat_chksum_swapped);
49576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        concat_chksummed += seglen;
49676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_CHECKSUM_ON_COPY */
49776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* reference the non-volatile payload data */
49876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        concat_p->payload = (u8_t*)arg + pos;
49976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
50076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
50176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      pos += seglen;
50276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      queuelen += pbuf_clen(concat_p);
50376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
50476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  } else {
50576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_OVERSIZE
50676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_ASSERT("unsent_oversize mismatch (pcb->unsent is NULL)",
50776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                pcb->unsent_oversize == 0);
50876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_OVERSIZE */
50976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
51076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
51176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /*
51276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * Phase 3: Create new segments.
51376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   *
51476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * The new segments are chained together in the local 'queue'
51576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * variable, ready to be appended to pcb->unsent.
51676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   */
51776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  while (pos < len) {
51876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct pbuf *p;
51976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u16_t left = len - pos;
52076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u16_t max_len = pcb->mss - optlen;
52176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u16_t seglen = left > max_len ? max_len : left;
52276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_CHECKSUM_ON_COPY
52376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u16_t chksum = 0;
52476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u8_t chksum_swapped = 0;
52576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_CHECKSUM_ON_COPY */
52676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
52776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (apiflags & TCP_WRITE_FLAG_COPY) {
52876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* If copy is set, memory should be allocated and data copied
52976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       * into pbuf */
53076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, pcb->mss, &oversize, pcb, apiflags, queue == NULL)) == NULL) {
53176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));
53276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        goto memerr;
53376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
53476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_ASSERT("tcp_write: check that first pbuf can hold the complete seglen",
53576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                  (p->len >= seglen));
53676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      TCP_DATA_COPY2((char *)p->payload + optlen, (u8_t*)arg + pos, seglen, &chksum, &chksum_swapped);
53776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
53876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* Copy is not set: First allocate a pbuf for holding the data.
53976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       * Since the referenced data is available at least until it is
54076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       * sent out on the link (as it has to be ACKed by the remote
54176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       * party) we can safely use PBUF_ROM instead of PBUF_REF here.
54276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       */
54376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      struct pbuf *p2;
54476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_OVERSIZE
54576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_ASSERT("oversize == 0", oversize == 0);
54676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_OVERSIZE */
54776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if ((p2 = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {
54876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for zero-copy pbuf\n"));
54976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        goto memerr;
55076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
55176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_CHECKSUM_ON_COPY
55276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* calculate the checksum of nocopy-data */
55376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      chksum = ~inet_chksum((u8_t*)arg + pos, seglen);
55476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_CHECKSUM_ON_COPY */
55576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* reference the non-volatile payload data */
55676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      p2->payload = (u8_t*)arg + pos;
55776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
55876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* Second, allocate a pbuf for the headers. */
55976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
56076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* If allocation fails, we have to deallocate the data pbuf as
56176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         * well. */
56276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        pbuf_free(p2);
56376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for header pbuf\n"));
56476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        goto memerr;
56576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
56676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* Concatenate the headers and data pbufs together. */
56776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      pbuf_cat(p/*header*/, p2/*data*/);
56876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
56976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
57076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    queuelen += pbuf_clen(p);
57176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
57276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Now that there are more segments queued, we check again if the
57376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * length of the queue exceeds the configured maximum or
57476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * overflows. */
57576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
57676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
57776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      pbuf_free(p);
57876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      goto memerr;
57976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
58076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
58176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) {
58276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      goto memerr;
58376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
58476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_OVERSIZE_DBGCHECK
58576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    seg->oversize_left = oversize;
58676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_OVERSIZE_DBGCHECK */
58776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_CHECKSUM_ON_COPY
58876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    seg->chksum = chksum;
58976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    seg->chksum_swapped = chksum_swapped;
59076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    seg->flags |= TF_SEG_DATA_CHECKSUMMED;
59176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_CHECKSUM_ON_COPY */
59276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
59376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* first segment of to-be-queued data? */
59476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (queue == NULL) {
59576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      queue = seg;
59676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
59776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* Attach the segment to the end of the queued segments */
59876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_ASSERT("prev_seg != NULL", prev_seg != NULL);
59976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      prev_seg->next = seg;
60076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
60176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* remember last segment of to-be-queued data for next iteration */
60276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    prev_seg = seg;
60376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
60476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_write: queueing %"U32_F":%"U32_F"\n",
60576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ntohl(seg->tcphdr->seqno),
60676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg)));
60776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
60876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pos += seglen;
60976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
61076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
61176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /*
61276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * All three segmentation phases were successful. We can commit the
61376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * transaction.
61476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   */
61576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
61676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /*
61776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * Phase 1: If data has been added to the preallocated tail of
61876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * last_unsent, we update the length fields of the pbuf chain.
61976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   */
62076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_OVERSIZE
62176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (oversize_used > 0) {
62276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct pbuf *p;
62376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Bump tot_len of whole chain, len of tail */
62476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (p = last_unsent->p; p; p = p->next) {
62576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      p->tot_len += oversize_used;
62676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if (p->next == NULL) {
62776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        TCP_DATA_COPY((char *)p->payload + p->len, arg, oversize_used, last_unsent);
62876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        p->len += oversize_used;
62976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
63076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
63176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    last_unsent->len += oversize_used;
63276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_OVERSIZE_DBGCHECK
63376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    last_unsent->oversize_left -= oversize_used;
63476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_OVERSIZE_DBGCHECK */
63576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
63676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pcb->unsent_oversize = oversize;
63776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_OVERSIZE */
63876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
63976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /*
64076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * Phase 2: concat_p can be concatenated onto last_unsent->p
64176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   */
64276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (concat_p != NULL) {
64376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_ASSERT("tcp_write: cannot concatenate when pcb->unsent is empty",
64476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      (last_unsent != NULL));
64576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pbuf_cat(last_unsent->p, concat_p);
64676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    last_unsent->len += concat_p->tot_len;
64776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_CHECKSUM_ON_COPY
64876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (concat_chksummed) {
64976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum,
65076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        &last_unsent->chksum_swapped);
65176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED;
65276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
65376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_CHECKSUM_ON_COPY */
65476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
65576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
65676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /*
65776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * Phase 3: Append queue to pcb->unsent. Queue may be NULL, but that
65876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * is harmless
65976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   */
66076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (last_unsent == NULL) {
66176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->unsent = queue;
66276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  } else {
66376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    last_unsent->next = queue;
66476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
66576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
66676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /*
66776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * Finally update the pcb state.
66876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   */
66976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pcb->snd_lbb += len;
67076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pcb->snd_buf -= len;
67176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pcb->snd_queuelen = queuelen;
67276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
67376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: %"S16_F" (after enqueued)\n",
67476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->snd_queuelen));
67576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (pcb->snd_queuelen != 0) {
67676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_ASSERT("tcp_write: valid queue length",
67776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                pcb->unacked != NULL || pcb->unsent != NULL);
67876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
67976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
68076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Set the PSH flag in the last segment that we enqueued. */
68176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (seg != NULL && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE)==0)) {
68276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    TCPH_SET_FLAG(seg->tcphdr, TCP_PSH);
68376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
68476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
68576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return ERR_OK;
68676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanmemerr:
68776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pcb->flags |= TF_NAGLEMEMERR;
68876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  TCP_STATS_INC(tcp.memerr);
68976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
69076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (concat_p != NULL) {
69176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pbuf_free(concat_p);
69276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
69376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (queue != NULL) {
69476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    tcp_segs_free(queue);
69576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
69676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (pcb->snd_queuelen != 0) {
69776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL ||
69876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      pcb->unsent != NULL);
69976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
70076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_write: %"S16_F" (with mem err)\n", pcb->snd_queuelen));
70176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return ERR_MEM;
70276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
70376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
70476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
70576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Enqueue TCP options for transmission.
70676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
70776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Called by tcp_connect(), tcp_listen_input(), and tcp_send_ctrl().
70876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
70976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param pcb Protocol control block for the TCP connection.
71076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param flags TCP header flags to set in the outgoing segment.
71176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param optdata pointer to TCP options, or NULL.
71276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param optlen length of TCP options in bytes.
71376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
71476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_t
71576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
71676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
71776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct pbuf *p;
71876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct tcp_seg *seg;
71976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u8_t optflags = 0;
72076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u8_t optlen = 0;
72176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
72276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen));
72376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
72476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ASSERT("tcp_enqueue_flags: need either TCP_SYN or TCP_FIN in flags (programmer violates API)",
72576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman              (flags & (TCP_SYN | TCP_FIN)) != 0);
72676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
72776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* check for configured max queuelen and possible overflow */
72876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
72976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: too long queue %"U16_F" (max %"U16_F")\n",
73076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                                       pcb->snd_queuelen, TCP_SND_QUEUELEN));
73176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    TCP_STATS_INC(tcp.memerr);
73276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->flags |= TF_NAGLEMEMERR;
73376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return ERR_MEM;
73476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
73576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
73676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (flags & TCP_SYN) {
73776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    optflags = TF_SEG_OPTS_MSS;
73876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
73976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_TCP_TIMESTAMPS
74076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if ((pcb->flags & TF_TIMESTAMP)) {
74176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    optflags |= TF_SEG_OPTS_TS;
74276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
74376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_TCP_TIMESTAMPS */
74476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  optlen = LWIP_TCP_OPT_LENGTH(optflags);
74576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
74676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* tcp_enqueue_flags is always called with either SYN or FIN in flags.
74776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * We need one available snd_buf byte to do that.
74876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * This means we can't send FIN while snd_buf==0. A better fix would be to
74976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * not include SYN and FIN sequence numbers in the snd_buf count. */
75076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (pcb->snd_buf == 0) {
75176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: no send buffer available\n"));
75276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    TCP_STATS_INC(tcp.memerr);
75376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return ERR_MEM;
75476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
75576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
75676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Allocate pbuf with room for TCP header + options */
75776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
75876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->flags |= TF_NAGLEMEMERR;
75976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    TCP_STATS_INC(tcp.memerr);
76076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return ERR_MEM;
76176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
76276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ASSERT("tcp_enqueue_flags: check that first pbuf can hold optlen",
76376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman              (p->len >= optlen));
76476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
76576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Allocate memory for tcp_seg, and fill in fields. */
76676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if ((seg = tcp_create_segment(pcb, p, flags, pcb->snd_lbb, optflags)) == NULL) {
76776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->flags |= TF_NAGLEMEMERR;
76876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    TCP_STATS_INC(tcp.memerr);
76976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return ERR_MEM;
77076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
77176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
77276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ASSERT("tcp_enqueue_flags: invalid segment length", seg->len == 0);
77376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
77476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE,
77576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman              ("tcp_enqueue_flags: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n",
77676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman               ntohl(seg->tcphdr->seqno),
77776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman               ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),
77876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman               (u16_t)flags));
77976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
78076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Now append seg to pcb->unsent queue */
78176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (pcb->unsent == NULL) {
78276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->unsent = seg;
78376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  } else {
78476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct tcp_seg *useg;
78576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);
78676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    useg->next = seg;
78776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
78876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_OVERSIZE
78976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* The new unsent tail has no space */
79076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pcb->unsent_oversize = 0;
79176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_OVERSIZE */
79276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
79376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* SYN and FIN bump the sequence number */
79476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if ((flags & TCP_SYN) || (flags & TCP_FIN)) {
79576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->snd_lbb++;
79676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* optlen does not influence snd_buf */
79776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->snd_buf--;
79876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
79976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (flags & TCP_FIN) {
80076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->flags |= TF_FIN;
80176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
80276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
80376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* update number of segments on the queues */
80476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pcb->snd_queuelen += pbuf_clen(seg->p);
80576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: %"S16_F" (after enqueued)\n", pcb->snd_queuelen));
80676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (pcb->snd_queuelen != 0) {
80776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_ASSERT("tcp_enqueue_flags: invalid queue length",
80876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      pcb->unacked != NULL || pcb->unsent != NULL);
80976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
81076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
81176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return ERR_OK;
81276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
81376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
81476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
81576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_TCP_TIMESTAMPS
81676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Build a timestamp option (12 bytes long) at the specified options pointer)
81776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
81876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param pcb tcp_pcb
81976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param opts option pointer where to store the timestamp option
82076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
82176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
82276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts)
82376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
82476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Pad with two NOP options to make everything nicely aligned */
82576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  opts[0] = PP_HTONL(0x0101080A);
82676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  opts[1] = htonl(sys_now());
82776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  opts[2] = htonl(pcb->ts_recent);
82876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
82976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
83076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
83176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Send an ACK without data.
83276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
83376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param pcb Protocol control block for the TCP connection to send the ACK
83476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
83576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_t
83676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantcp_send_empty_ack(struct tcp_pcb *pcb)
83776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
83876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct pbuf *p;
83976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct tcp_hdr *tcphdr;
84076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u8_t optlen = 0;
84176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
84276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_TCP_TIMESTAMPS
84376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (pcb->flags & TF_TIMESTAMP) {
84476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
84576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
84676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
84776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
84876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  p = tcp_output_alloc_header(pcb, optlen, 0, htonl(pcb->snd_nxt));
84976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (p == NULL) {
85076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
85176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return ERR_BUF;
85276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
85376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  tcphdr = (struct tcp_hdr *)p->payload;
85476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(TCP_OUTPUT_DEBUG,
85576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman              ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));
85676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* remove ACK flags from the PCB, as we send an empty ACK now */
85776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
85876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
85976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* NB. MSS option is only sent on SYNs, so ignore it here */
86076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_TCP_TIMESTAMPS
86176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pcb->ts_lastacksent = pcb->rcv_nxt;
86276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
86376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (pcb->flags & TF_TIMESTAMP) {
86476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1));
86576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
86676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
86776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
86876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if CHECKSUM_GEN_TCP
86976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
87076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        IP_PROTO_TCP, p->tot_len);
87176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
87276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_NETIF_HWADDRHINT
87376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
87476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      IP_PROTO_TCP, &(pcb->addr_hint));
87576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else /* LWIP_NETIF_HWADDRHINT*/
87676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
87776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      IP_PROTO_TCP);
87876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_NETIF_HWADDRHINT*/
87976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pbuf_free(p);
88076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
88176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return ERR_OK;
88276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
88376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
88476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
88576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Find out what we can send and send it
88676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
88776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param pcb Protocol control block for the TCP connection to send data
88876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return ERR_OK if data has been sent or nothing to send
88976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *         another err_t on error
89076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
89176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_t
89276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantcp_output(struct tcp_pcb *pcb)
89376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
89476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct tcp_seg *seg, *useg;
89576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u32_t wnd, snd_nxt;
89676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_CWND_DEBUG
89776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  s16_t i = 0;
89876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_CWND_DEBUG */
89976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
90076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* First, check if we are invoked by the TCP input processing
90176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     code. If so, we do not output anything. Instead, we rely on the
90276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     input processing code to call us when input processing is done
90376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     with. */
90476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (tcp_input_pcb == pcb) {
90576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return ERR_OK;
90676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
90776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
90876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);
90976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
91076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg = pcb->unsent;
91176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
91276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* If the TF_ACK_NOW flag is set and no data will be sent (either
91376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * because the ->unsent queue is empty or because the window does
91476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * not allow it), construct an empty ACK segment and send it.
91576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   *
91676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * If data is to be sent, we will just piggyback the ACK (see below).
91776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   */
91876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (pcb->flags & TF_ACK_NOW &&
91976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     (seg == NULL ||
92076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
92176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     return tcp_send_empty_ack(pcb);
92276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
92376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
92476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* useg should point to last segment on unacked queue */
92576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  useg = pcb->unacked;
92676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (useg != NULL) {
92776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (; useg->next != NULL; useg = useg->next);
92876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
92976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
93076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_OUTPUT_DEBUG
93176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (seg == NULL) {
93276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n",
93376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                                   (void*)pcb->unsent));
93476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
93576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_OUTPUT_DEBUG */
93676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_CWND_DEBUG
93776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (seg == NULL) {
93876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F
93976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                                 ", cwnd %"U16_F", wnd %"U32_F
94076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                                 ", seg == NULL, ack %"U32_F"\n",
94176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                                 pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack));
94276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  } else {
94376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(TCP_CWND_DEBUG,
94476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F
94576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                 ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n",
94676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                 pcb->snd_wnd, pcb->cwnd, wnd,
94776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
94876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                 ntohl(seg->tcphdr->seqno), pcb->lastack));
94976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
95076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_CWND_DEBUG */
95176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* data available and window allows it to be sent? */
95276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  while (seg != NULL &&
95376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
95476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_ASSERT("RST not expected here!",
95576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0);
95676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Stop sending if the nagle algorithm would prevent it
95776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * Don't stop:
95876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * - if tcp_write had a memory error before (prevent delayed ACK timeout) or
95976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * - if FIN was already enqueued for this PCB (SYN is always alone in a segment -
96076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *   either seg->next != NULL or pcb->unacked == NULL;
96176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     *   RST is no sent using tcp_write/tcp_output.
96276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     */
96376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if((tcp_do_output_nagle(pcb) == 0) &&
96476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)){
96576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      break;
96676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
96776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_CWND_DEBUG
96876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n",
96976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                            pcb->snd_wnd, pcb->cwnd, wnd,
97076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                            ntohl(seg->tcphdr->seqno) + seg->len -
97176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                            pcb->lastack,
97276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                            ntohl(seg->tcphdr->seqno), pcb->lastack, i));
97376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ++i;
97476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_CWND_DEBUG */
97576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
97676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->unsent = seg->next;
97776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
97876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (pcb->state != SYN_SENT) {
97976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);
98076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
98176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
98276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
98376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    tcp_output_segment(seg, pcb);
98476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
98576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) {
98676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      pcb->snd_nxt = snd_nxt;
98776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
98876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* put segment on unacknowledged list if length > 0 */
98976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (TCP_TCPLEN(seg) > 0) {
99076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      seg->next = NULL;
99176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* unacked list is empty? */
99276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if (pcb->unacked == NULL) {
99376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        pcb->unacked = seg;
99476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        useg = seg;
99576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* unacked list is not empty? */
99676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      } else {
99776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* In the case of fast retransmit, the packet should not go to the tail
99876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         * of the unacked queue, but rather somewhere before it. We need to check for
99976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         * this case. -STJ Jul 27, 2004 */
100076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))) {
100176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          /* add segment to before tail of unacked list, keeping the list sorted */
100276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          struct tcp_seg **cur_seg = &(pcb->unacked);
100376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          while (*cur_seg &&
100476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) {
100576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman              cur_seg = &((*cur_seg)->next );
100676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          }
100776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          seg->next = (*cur_seg);
100876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          (*cur_seg) = seg;
100976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        } else {
101076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          /* add segment to tail of unacked list */
101176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          useg->next = seg;
101276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          useg = useg->next;
101376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        }
101476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
101576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* do not queue empty segments on the unacked list */
101676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
101776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      tcp_seg_free(seg);
101876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
101976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    seg = pcb->unsent;
102076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
102176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_OVERSIZE
102276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (pcb->unsent == NULL) {
102376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* last unsent has been removed, reset unsent_oversize */
102476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->unsent_oversize = 0;
102576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
102676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_OVERSIZE */
102776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
102876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (seg != NULL && pcb->persist_backoff == 0 &&
102976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) {
103076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* prepare for persist timer */
103176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->persist_cnt = 0;
103276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->persist_backoff = 1;
103376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
103476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
103576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pcb->flags &= ~TF_NAGLEMEMERR;
103676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return ERR_OK;
103776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
103876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
103976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
104076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Called by tcp_output() to actually send a TCP segment over IP.
104176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
104276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param seg the tcp_seg to send
104376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param pcb the tcp_pcb for the TCP connection used to send the segment
104476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
104576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
104676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
104776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
104876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u16_t len;
104976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct netif *netif;
105076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u32_t *opts;
105176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
105276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /** @bug Exclude retransmitted segments from this count. */
105376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  snmp_inc_tcpoutsegs();
105476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
105576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* The TCP header has already been constructed, but the ackno and
105676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   wnd fields remain. */
105776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->tcphdr->ackno = htonl(pcb->rcv_nxt);
105876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
105976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* advertise our receive window size in this TCP segment */
106076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd);
106176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
106276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
106376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
106476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Add any requested options.  NB MSS option is only set on SYN
106576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     packets, so ignore it here */
106676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
106776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  opts = (u32_t *)(void *)(seg->tcphdr + 1);
106876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (seg->flags & TF_SEG_OPTS_MSS) {
106976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    TCP_BUILD_MSS_OPTION(*opts);
107076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    opts += 1;
107176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
107276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_TCP_TIMESTAMPS
107376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pcb->ts_lastacksent = pcb->rcv_nxt;
107476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
107576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (seg->flags & TF_SEG_OPTS_TS) {
107676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    tcp_build_timestamp_option(pcb, opts);
107776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    opts += 3;
107876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
107976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
108076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
108176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Set retransmission timer running if it is not currently enabled
108276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     This must be set before checking the route. */
108376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (pcb->rtime == -1) {
108476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->rtime = 0;
108576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
108676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
108776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* If we don't have a local IP address, we get one by
108876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     calling ip_route(). */
108976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (ip_addr_isany(&(pcb->local_ip))) {
109076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    netif = ip_route(&(pcb->remote_ip));
109176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (netif == NULL) {
109276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      return;
109376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
109476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ip_addr_copy(pcb->local_ip, netif->ip_addr);
109576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
109676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
109776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (pcb->rttest == 0) {
109876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->rttest = tcp_ticks;
109976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->rtseq = ntohl(seg->tcphdr->seqno);
110076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
110176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq));
110276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
110376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n",
110476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +
110576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          seg->len));
110676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
110776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);
110876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
110976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->p->len -= len;
111076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->p->tot_len -= len;
111176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
111276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->p->payload = seg->tcphdr;
111376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
111476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->tcphdr->chksum = 0;
111576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if CHECKSUM_GEN_TCP
111676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_CHECKSUM_ON_COPY
111776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  {
111876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u32_t acc;
111976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
112076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
112176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           &(pcb->remote_ip),
112276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           IP_PROTO_TCP, seg->p->tot_len);
112376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
112476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) {
112576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_ASSERT("data included but not checksummed",
112676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        seg->p->tot_len == (TCPH_HDRLEN(seg->tcphdr) * 4));
112776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
112876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
112976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* rebuild TCP header checksum (TCP header changes for retransmissions!) */
113076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip),
113176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman             &(pcb->remote_ip),
113276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman             IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);
113376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* add payload checksum */
113476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (seg->chksum_swapped) {
113576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum);
113676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      seg->chksum_swapped = 0;
113776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
113876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    acc += (u16_t)~(seg->chksum);
113976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    seg->tcphdr->chksum = FOLD_U32T(acc);
114076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
114176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (chksum_slow != seg->tcphdr->chksum) {
114276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING,
114376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                  ("tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"\n",
114476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                  seg->tcphdr->chksum, chksum_slow));
114576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      seg->tcphdr->chksum = chksum_slow;
114676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
114776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
114876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
114976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else /* TCP_CHECKSUM_ON_COPY */
115076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
115176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         &(pcb->remote_ip),
115276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         IP_PROTO_TCP, seg->p->tot_len);
115376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* TCP_CHECKSUM_ON_COPY */
115476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* CHECKSUM_GEN_TCP */
115576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  TCP_STATS_INC(tcp.xmit);
115676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
115776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_NETIF_HWADDRHINT
115876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
115976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      IP_PROTO_TCP, &(pcb->addr_hint));
116076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else /* LWIP_NETIF_HWADDRHINT*/
116176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
116276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      IP_PROTO_TCP);
116376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_NETIF_HWADDRHINT*/
116476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
116576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
116676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
116776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Send a TCP RESET packet (empty segment with RST flag set) either to
116876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * abort a connection or to show that there is no matching local connection
116976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * for a received segment.
117076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
117176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Called by tcp_abort() (to abort a local connection), tcp_input() (if no
117276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * matching local pcb was found), tcp_listen_input() (if incoming segment
117376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * has ACK flag set) and tcp_process() (received segment in the wrong state)
117476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
117576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Since a RST segment is in most cases not sent for an active connection,
117676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * tcp_rst() has a number of arguments that are taken from a tcp_pcb for
117776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * most other segment output functions.
117876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
117976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param seqno the sequence number to use for the outgoing segment
118076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ackno the acknowledge number to use for the outgoing segment
118176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param local_ip the local IP address to send the segment from
118276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param remote_ip the remote IP address to send the segment to
118376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param local_port the local TCP port to send the segment from
118476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param remote_port the remote TCP port to send the segment to
118576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
118676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid
118776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantcp_rst(u32_t seqno, u32_t ackno,
118876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ip_addr_t *local_ip, ip_addr_t *remote_ip,
118976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u16_t local_port, u16_t remote_port)
119076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
119176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct pbuf *p;
119276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct tcp_hdr *tcphdr;
119376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
119476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (p == NULL) {
119576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));
119676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      return;
119776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
119876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
119976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman              (p->len >= sizeof(struct tcp_hdr)));
120076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
120176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  tcphdr = (struct tcp_hdr *)p->payload;
120276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  tcphdr->src = htons(local_port);
120376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  tcphdr->dest = htons(remote_port);
120476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  tcphdr->seqno = htonl(seqno);
120576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  tcphdr->ackno = htonl(ackno);
120676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK);
120776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  tcphdr->wnd = PP_HTONS(TCP_WND);
120876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  tcphdr->chksum = 0;
120976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  tcphdr->urgp = 0;
121076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
121176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if CHECKSUM_GEN_TCP
121276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,
121376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman              IP_PROTO_TCP, p->tot_len);
121476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
121576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  TCP_STATS_INC(tcp.xmit);
121676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  snmp_inc_tcpoutrsts();
121776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   /* Send output with hardcoded TTL since we have no access to the pcb */
121876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);
121976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pbuf_free(p);
122076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));
122176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
122276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
122376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
122476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Requeue all unacked segments for retransmission
122576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
122676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Called by tcp_slowtmr() for slow retransmission.
122776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
122876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param pcb the tcp_pcb for which to re-enqueue all unacked segments
122976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
123076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid
123176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantcp_rexmit_rto(struct tcp_pcb *pcb)
123276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
123376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct tcp_seg *seg;
123476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
123576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (pcb->unacked == NULL) {
123676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return;
123776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
123876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
123976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Move all unacked segments to the head of the unsent queue */
124076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
124176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* concatenate unsent queue after unacked queue */
124276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->next = pcb->unsent;
124376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* unsent queue is the concatenated queue (of unacked, unsent) */
124476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pcb->unsent = pcb->unacked;
124576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* unacked queue is now empty */
124676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pcb->unacked = NULL;
124776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
124876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* increment number of retransmissions */
124976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ++pcb->nrtx;
125076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
125176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Don't take any RTT measurements after retransmitting. */
125276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pcb->rttest = 0;
125376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
125476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Do the actual retransmission */
125576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  tcp_output(pcb);
125676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
125776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
125876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
125976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Requeue the first unacked segment for retransmission
126076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
126176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Called by tcp_receive() for fast retramsmit.
126276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
126376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param pcb the tcp_pcb for which to retransmit the first unacked segment
126476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
126576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid
126676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantcp_rexmit(struct tcp_pcb *pcb)
126776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
126876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct tcp_seg *seg;
126976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct tcp_seg **cur_seg;
127076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
127176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (pcb->unacked == NULL) {
127276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return;
127376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
127476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
127576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Move the first unacked segment to the unsent queue */
127676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Keep the unsent queue sorted. */
127776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg = pcb->unacked;
127876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pcb->unacked = seg->next;
127976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
128076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  cur_seg = &(pcb->unsent);
128176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  while (*cur_seg &&
128276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) {
128376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      cur_seg = &((*cur_seg)->next );
128476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
128576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg->next = *cur_seg;
128676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  *cur_seg = seg;
128776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
128876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ++pcb->nrtx;
128976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
129076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Don't take any rtt measurements after retransmitting. */
129176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pcb->rttest = 0;
129276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
129376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Do the actual retransmission. */
129476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  snmp_inc_tcpretranssegs();
129576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* No need to call tcp_output: we are always called from tcp_input()
129676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     and thus tcp_output directly returns. */
129776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
129876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
129976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
130076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
130176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Handle retransmission after three dupacks received
130276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
130376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param pcb the tcp_pcb for which to retransmit the first unacked segment
130476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
130576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid
130676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantcp_rexmit_fast(struct tcp_pcb *pcb)
130776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
130876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (pcb->unacked != NULL && !(pcb->flags & TF_INFR)) {
130976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* This is fast retransmit. Retransmit the first unacked segment. */
131076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(TCP_FR_DEBUG,
131176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                ("tcp_receive: dupacks %"U16_F" (%"U32_F
131276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                 "), fast retransmit %"U32_F"\n",
131376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                 (u16_t)pcb->dupacks, pcb->lastack,
131476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                 ntohl(pcb->unacked->tcphdr->seqno)));
131576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    tcp_rexmit(pcb);
131676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
131776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Set ssthresh to half of the minimum of the current
131876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * cwnd and the advertised window */
131976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (pcb->cwnd > pcb->snd_wnd) {
132076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      pcb->ssthresh = pcb->snd_wnd / 2;
132176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
132276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      pcb->ssthresh = pcb->cwnd / 2;
132376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
132476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
132576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* The minimum value for ssthresh should be 2 MSS */
132676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (pcb->ssthresh < 2*pcb->mss) {
132776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_DEBUGF(TCP_FR_DEBUG,
132876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                  ("tcp_receive: The minimum value for ssthresh %"U16_F
132976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                   " should be min 2 mss %"U16_F"...\n",
133076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                   pcb->ssthresh, 2*pcb->mss));
133176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      pcb->ssthresh = 2*pcb->mss;
133276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
133376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
133476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
133576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pcb->flags |= TF_INFR;
133676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
133776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
133876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
133976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
134076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
134176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Send keepalive packets to keep a connection active although
134276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * no data is sent over it.
134376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
134476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Called by tcp_slowtmr()
134576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
134676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param pcb the tcp_pcb for which to send a keepalive packet
134776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
134876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid
134976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantcp_keepalive(struct tcp_pcb *pcb)
135076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
135176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct pbuf *p;
135276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct tcp_hdr *tcphdr;
135376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
135476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
135576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                          ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
135676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                          ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
135776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
135876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F"   pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",
135976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                          tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
136076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
136176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  p = tcp_output_alloc_header(pcb, 0, 0, htonl(pcb->snd_nxt - 1));
136276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if(p == NULL) {
136376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(TCP_DEBUG,
136476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                ("tcp_keepalive: could not allocate memory for pbuf\n"));
136576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return;
136676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
136776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  tcphdr = (struct tcp_hdr *)p->payload;
136876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
136976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if CHECKSUM_GEN_TCP
137076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
137176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                                      IP_PROTO_TCP, p->tot_len);
137276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
137376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  TCP_STATS_INC(tcp.xmit);
137476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
137576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Send output to IP */
137676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_NETIF_HWADDRHINT
137776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
137876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    &(pcb->addr_hint));
137976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else /* LWIP_NETIF_HWADDRHINT*/
138076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
138176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_NETIF_HWADDRHINT*/
138276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
138376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pbuf_free(p);
138476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
138576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n",
138676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                          pcb->snd_nxt - 1, pcb->rcv_nxt));
138776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
138876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
138976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
139076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
139176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Send persist timer zero-window probes to keep a connection active
139276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * when a window update is lost.
139376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
139476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Called by tcp_slowtmr()
139576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
139676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param pcb the tcp_pcb for which to send a zero-window probe packet
139776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
139876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid
139976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmantcp_zero_window_probe(struct tcp_pcb *pcb)
140076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
140176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct pbuf *p;
140276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct tcp_hdr *tcphdr;
140376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct tcp_seg *seg;
140476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u16_t len;
140576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u8_t is_fin;
140676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
140776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(TCP_DEBUG,
140876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman              ("tcp_zero_window_probe: sending ZERO WINDOW probe to %"
140976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman               U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
141076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman               ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
141176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman               ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
141276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
141376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(TCP_DEBUG,
141476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman              ("tcp_zero_window_probe: tcp_ticks %"U32_F
141576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman               "   pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",
141676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman               tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
141776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
141876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  seg = pcb->unacked;
141976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
142076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if(seg == NULL) {
142176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    seg = pcb->unsent;
142276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
142376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if(seg == NULL) {
142476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return;
142576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
142676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
142776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0);
142876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* we want to send one seqno: either FIN or data (no options) */
142976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  len = is_fin ? 0 : 1;
143076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
143176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  p = tcp_output_alloc_header(pcb, 0, len, seg->tcphdr->seqno);
143276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if(p == NULL) {
143376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n"));
143476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return;
143576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
143676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  tcphdr = (struct tcp_hdr *)p->payload;
143776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
143876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (is_fin) {
143976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* FIN segment, no data */
144076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN);
144176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  } else {
144276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Data segment, copy in one byte from the head of the unacked queue */
144376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct tcp_hdr *thdr = (struct tcp_hdr *)seg->p->payload;
144476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    char *d = ((char *)p->payload + TCP_HLEN);
144576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pbuf_copy_partial(seg->p, d, 1, TCPH_HDRLEN(thdr) * 4);
144676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
144776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
144876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if CHECKSUM_GEN_TCP
144976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
145076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                                      IP_PROTO_TCP, p->tot_len);
145176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
145276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  TCP_STATS_INC(tcp.xmit);
145376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
145476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Send output to IP */
145576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_NETIF_HWADDRHINT
145676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
145776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    &(pcb->addr_hint));
145876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else /* LWIP_NETIF_HWADDRHINT*/
145976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
146076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_NETIF_HWADDRHINT*/
146176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
146276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pbuf_free(p);
146376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
146476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F
146576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                          " ackno %"U32_F".\n",
146676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                          pcb->snd_nxt - 1, pcb->rcv_nxt));
146776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
146876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_TCP */
1469