Official mbed lwIP library (version 1.4.0)

Dependents:   LwIPNetworking NetServicesMin EthernetInterface EthernetInterface_RSF ... more

Legacy Networking Libraries

This is an mbed 2 networking library. For mbed OS 5, lwip has been integrated with built-in networking interfaces. The networking libraries have been revised to better support additional network stacks and thread safety here.

This library is based on the code of lwIP v1.4.0

Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
All rights reserved. 

Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
   derived from this software without specific prior written permission. 

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE.
Committer:
mbed_official
Date:
Mon Mar 14 16:15:36 2016 +0000
Revision:
20:08f08bfc3f3d
Parent:
13:8e34c2cbce5d
Synchronized with git revision fec574a5ed6db26aca1b13992ff271bf527d4a0d

Full URL: https://github.com/mbedmicro/mbed/commit/fec574a5ed6db26aca1b13992ff271bf527d4a0d/

Increased allocated netbufs to handle DTLS handshakes

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mbed_official 0:51ac1d130fd4 1 /**
mbed_official 0:51ac1d130fd4 2 * @file
mbed_official 0:51ac1d130fd4 3 * Transmission Control Protocol, outgoing traffic
mbed_official 0:51ac1d130fd4 4 *
mbed_official 0:51ac1d130fd4 5 * The output functions of TCP.
mbed_official 0:51ac1d130fd4 6 *
mbed_official 0:51ac1d130fd4 7 */
mbed_official 0:51ac1d130fd4 8
mbed_official 0:51ac1d130fd4 9 /*
mbed_official 0:51ac1d130fd4 10 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
mbed_official 0:51ac1d130fd4 11 * All rights reserved.
mbed_official 0:51ac1d130fd4 12 *
mbed_official 0:51ac1d130fd4 13 * Redistribution and use in source and binary forms, with or without modification,
mbed_official 0:51ac1d130fd4 14 * are permitted provided that the following conditions are met:
mbed_official 0:51ac1d130fd4 15 *
mbed_official 0:51ac1d130fd4 16 * 1. Redistributions of source code must retain the above copyright notice,
mbed_official 0:51ac1d130fd4 17 * this list of conditions and the following disclaimer.
mbed_official 0:51ac1d130fd4 18 * 2. Redistributions in binary form must reproduce the above copyright notice,
mbed_official 0:51ac1d130fd4 19 * this list of conditions and the following disclaimer in the documentation
mbed_official 0:51ac1d130fd4 20 * and/or other materials provided with the distribution.
mbed_official 0:51ac1d130fd4 21 * 3. The name of the author may not be used to endorse or promote products
mbed_official 0:51ac1d130fd4 22 * derived from this software without specific prior written permission.
mbed_official 0:51ac1d130fd4 23 *
mbed_official 0:51ac1d130fd4 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
mbed_official 0:51ac1d130fd4 25 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
mbed_official 0:51ac1d130fd4 26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
mbed_official 0:51ac1d130fd4 27 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
mbed_official 0:51ac1d130fd4 28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
mbed_official 0:51ac1d130fd4 29 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
mbed_official 0:51ac1d130fd4 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
mbed_official 0:51ac1d130fd4 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
mbed_official 0:51ac1d130fd4 32 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
mbed_official 0:51ac1d130fd4 33 * OF SUCH DAMAGE.
mbed_official 0:51ac1d130fd4 34 *
mbed_official 0:51ac1d130fd4 35 * This file is part of the lwIP TCP/IP stack.
mbed_official 0:51ac1d130fd4 36 *
mbed_official 0:51ac1d130fd4 37 * Author: Adam Dunkels <adam@sics.se>
mbed_official 0:51ac1d130fd4 38 *
mbed_official 0:51ac1d130fd4 39 */
mbed_official 0:51ac1d130fd4 40
mbed_official 0:51ac1d130fd4 41 #include "lwip/opt.h"
mbed_official 0:51ac1d130fd4 42
mbed_official 0:51ac1d130fd4 43 #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
mbed_official 0:51ac1d130fd4 44
mbed_official 0:51ac1d130fd4 45 #include "lwip/tcp_impl.h"
mbed_official 0:51ac1d130fd4 46 #include "lwip/def.h"
mbed_official 0:51ac1d130fd4 47 #include "lwip/mem.h"
mbed_official 0:51ac1d130fd4 48 #include "lwip/memp.h"
mbed_official 0:51ac1d130fd4 49 #include "lwip/sys.h"
mbed_official 0:51ac1d130fd4 50 #include "lwip/ip_addr.h"
mbed_official 0:51ac1d130fd4 51 #include "lwip/netif.h"
mbed_official 0:51ac1d130fd4 52 #include "lwip/inet_chksum.h"
mbed_official 0:51ac1d130fd4 53 #include "lwip/stats.h"
mbed_official 0:51ac1d130fd4 54 #include "lwip/snmp.h"
mbed_official 0:51ac1d130fd4 55
mbed_official 0:51ac1d130fd4 56 #include <string.h>
mbed_official 0:51ac1d130fd4 57
mbed_official 0:51ac1d130fd4 58 /* Define some copy-macros for checksum-on-copy so that the code looks
mbed_official 0:51ac1d130fd4 59 nicer by preventing too many ifdef's. */
mbed_official 0:51ac1d130fd4 60 #if TCP_CHECKSUM_ON_COPY
mbed_official 0:51ac1d130fd4 61 #define TCP_DATA_COPY(dst, src, len, seg) do { \
mbed_official 0:51ac1d130fd4 62 tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), \
mbed_official 0:51ac1d130fd4 63 len, &seg->chksum, &seg->chksum_swapped); \
mbed_official 0:51ac1d130fd4 64 seg->flags |= TF_SEG_DATA_CHECKSUMMED; } while(0)
mbed_official 0:51ac1d130fd4 65 #define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) \
mbed_official 0:51ac1d130fd4 66 tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), len, chksum, chksum_swapped);
mbed_official 0:51ac1d130fd4 67 #else /* TCP_CHECKSUM_ON_COPY*/
mbed_official 0:51ac1d130fd4 68 #define TCP_DATA_COPY(dst, src, len, seg) MEMCPY(dst, src, len)
mbed_official 0:51ac1d130fd4 69 #define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) MEMCPY(dst, src, len)
mbed_official 0:51ac1d130fd4 70 #endif /* TCP_CHECKSUM_ON_COPY*/
mbed_official 0:51ac1d130fd4 71
mbed_official 0:51ac1d130fd4 72 /** Define this to 1 for an extra check that the output checksum is valid
mbed_official 0:51ac1d130fd4 73 * (usefule when the checksum is generated by the application, not the stack) */
mbed_official 0:51ac1d130fd4 74 #ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK
mbed_official 0:51ac1d130fd4 75 #define TCP_CHECKSUM_ON_COPY_SANITY_CHECK 0
mbed_official 0:51ac1d130fd4 76 #endif
mbed_official 0:51ac1d130fd4 77
mbed_official 0:51ac1d130fd4 78 /* Forward declarations.*/
mbed_official 0:51ac1d130fd4 79 static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
mbed_official 0:51ac1d130fd4 80
mbed_official 0:51ac1d130fd4 81 /** Allocate a pbuf and create a tcphdr at p->payload, used for output
mbed_official 0:51ac1d130fd4 82 * functions other than the default tcp_output -> tcp_output_segment
mbed_official 0:51ac1d130fd4 83 * (e.g. tcp_send_empty_ack, etc.)
mbed_official 0:51ac1d130fd4 84 *
mbed_official 0:51ac1d130fd4 85 * @param pcb tcp pcb for which to send a packet (used to initialize tcp_hdr)
mbed_official 0:51ac1d130fd4 86 * @param optlen length of header-options
mbed_official 0:51ac1d130fd4 87 * @param datalen length of tcp data to reserve in pbuf
mbed_official 0:51ac1d130fd4 88 * @param seqno_be seqno in network byte order (big-endian)
mbed_official 0:51ac1d130fd4 89 * @return pbuf with p->payload being the tcp_hdr
mbed_official 0:51ac1d130fd4 90 */
mbed_official 0:51ac1d130fd4 91 static struct pbuf *
mbed_official 0:51ac1d130fd4 92 tcp_output_alloc_header(struct tcp_pcb *pcb, u16_t optlen, u16_t datalen,
mbed_official 0:51ac1d130fd4 93 u32_t seqno_be /* already in network byte order */)
mbed_official 0:51ac1d130fd4 94 {
mbed_official 0:51ac1d130fd4 95 struct tcp_hdr *tcphdr;
mbed_official 0:51ac1d130fd4 96 struct pbuf *p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen + datalen, PBUF_RAM);
mbed_official 0:51ac1d130fd4 97 if (p != NULL) {
mbed_official 0:51ac1d130fd4 98 LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
mbed_official 0:51ac1d130fd4 99 (p->len >= TCP_HLEN + optlen));
mbed_official 0:51ac1d130fd4 100 tcphdr = (struct tcp_hdr *)p->payload;
mbed_official 0:51ac1d130fd4 101 tcphdr->src = htons(pcb->local_port);
mbed_official 0:51ac1d130fd4 102 tcphdr->dest = htons(pcb->remote_port);
mbed_official 0:51ac1d130fd4 103 tcphdr->seqno = seqno_be;
mbed_official 0:51ac1d130fd4 104 tcphdr->ackno = htonl(pcb->rcv_nxt);
mbed_official 0:51ac1d130fd4 105 TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), TCP_ACK);
mbed_official 0:51ac1d130fd4 106 tcphdr->wnd = htons(pcb->rcv_ann_wnd);
mbed_official 0:51ac1d130fd4 107 tcphdr->chksum = 0;
mbed_official 0:51ac1d130fd4 108 tcphdr->urgp = 0;
mbed_official 0:51ac1d130fd4 109
mbed_official 0:51ac1d130fd4 110 /* If we're sending a packet, update the announced right window edge */
mbed_official 0:51ac1d130fd4 111 pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
mbed_official 0:51ac1d130fd4 112 }
mbed_official 0:51ac1d130fd4 113 return p;
mbed_official 0:51ac1d130fd4 114 }
mbed_official 0:51ac1d130fd4 115
mbed_official 0:51ac1d130fd4 116 /**
mbed_official 0:51ac1d130fd4 117 * Called by tcp_close() to send a segment including FIN flag but not data.
mbed_official 0:51ac1d130fd4 118 *
mbed_official 0:51ac1d130fd4 119 * @param pcb the tcp_pcb over which to send a segment
mbed_official 0:51ac1d130fd4 120 * @return ERR_OK if sent, another err_t otherwise
mbed_official 0:51ac1d130fd4 121 */
mbed_official 0:51ac1d130fd4 122 err_t
mbed_official 0:51ac1d130fd4 123 tcp_send_fin(struct tcp_pcb *pcb)
mbed_official 0:51ac1d130fd4 124 {
mbed_official 0:51ac1d130fd4 125 /* first, try to add the fin to the last unsent segment */
mbed_official 0:51ac1d130fd4 126 if (pcb->unsent != NULL) {
mbed_official 0:51ac1d130fd4 127 struct tcp_seg *last_unsent;
mbed_official 0:51ac1d130fd4 128 for (last_unsent = pcb->unsent; last_unsent->next != NULL;
mbed_official 0:51ac1d130fd4 129 last_unsent = last_unsent->next);
mbed_official 0:51ac1d130fd4 130
mbed_official 0:51ac1d130fd4 131 if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) {
mbed_official 0:51ac1d130fd4 132 /* no SYN/FIN/RST flag in the header, we can add the FIN flag */
mbed_official 0:51ac1d130fd4 133 TCPH_SET_FLAG(last_unsent->tcphdr, TCP_FIN);
mbed_official 0:51ac1d130fd4 134 return ERR_OK;
mbed_official 0:51ac1d130fd4 135 }
mbed_official 0:51ac1d130fd4 136 }
mbed_official 0:51ac1d130fd4 137 /* no data, no length, flags, copy=1, no optdata */
mbed_official 0:51ac1d130fd4 138 return tcp_enqueue_flags(pcb, TCP_FIN);
mbed_official 0:51ac1d130fd4 139 }
mbed_official 0:51ac1d130fd4 140
mbed_official 0:51ac1d130fd4 141 /**
mbed_official 0:51ac1d130fd4 142 * Create a TCP segment with prefilled header.
mbed_official 0:51ac1d130fd4 143 *
mbed_official 0:51ac1d130fd4 144 * Called by tcp_write and tcp_enqueue_flags.
mbed_official 0:51ac1d130fd4 145 *
mbed_official 0:51ac1d130fd4 146 * @param pcb Protocol control block for the TCP connection.
mbed_official 0:51ac1d130fd4 147 * @param p pbuf that is used to hold the TCP header.
mbed_official 0:51ac1d130fd4 148 * @param flags TCP flags for header.
mbed_official 0:51ac1d130fd4 149 * @param seqno TCP sequence number of this packet
mbed_official 0:51ac1d130fd4 150 * @param optflags options to include in TCP header
mbed_official 0:51ac1d130fd4 151 * @return a new tcp_seg pointing to p, or NULL.
mbed_official 0:51ac1d130fd4 152 * The TCP header is filled in except ackno and wnd.
mbed_official 0:51ac1d130fd4 153 * p is freed on failure.
mbed_official 0:51ac1d130fd4 154 */
mbed_official 0:51ac1d130fd4 155 static struct tcp_seg *
mbed_official 0:51ac1d130fd4 156 tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno, u8_t optflags)
mbed_official 0:51ac1d130fd4 157 {
mbed_official 0:51ac1d130fd4 158 struct tcp_seg *seg;
mbed_official 0:51ac1d130fd4 159 u8_t optlen = LWIP_TCP_OPT_LENGTH(optflags);
mbed_official 0:51ac1d130fd4 160
mbed_official 0:51ac1d130fd4 161 if ((seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG)) == NULL) {
mbed_official 0:51ac1d130fd4 162 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no memory.\n"));
mbed_official 0:51ac1d130fd4 163 pbuf_free(p);
mbed_official 0:51ac1d130fd4 164 return NULL;
mbed_official 0:51ac1d130fd4 165 }
mbed_official 0:51ac1d130fd4 166 seg->flags = optflags;
mbed_official 0:51ac1d130fd4 167 seg->next = NULL;
mbed_official 0:51ac1d130fd4 168 seg->p = p;
mbed_official 0:51ac1d130fd4 169 seg->len = p->tot_len - optlen;
mbed_official 0:51ac1d130fd4 170 #if TCP_OVERSIZE_DBGCHECK
mbed_official 0:51ac1d130fd4 171 seg->oversize_left = 0;
mbed_official 0:51ac1d130fd4 172 #endif /* TCP_OVERSIZE_DBGCHECK */
mbed_official 0:51ac1d130fd4 173 #if TCP_CHECKSUM_ON_COPY
mbed_official 0:51ac1d130fd4 174 seg->chksum = 0;
mbed_official 0:51ac1d130fd4 175 seg->chksum_swapped = 0;
mbed_official 0:51ac1d130fd4 176 /* check optflags */
mbed_official 0:51ac1d130fd4 177 LWIP_ASSERT("invalid optflags passed: TF_SEG_DATA_CHECKSUMMED",
mbed_official 0:51ac1d130fd4 178 (optflags & TF_SEG_DATA_CHECKSUMMED) == 0);
mbed_official 0:51ac1d130fd4 179 #endif /* TCP_CHECKSUM_ON_COPY */
mbed_official 0:51ac1d130fd4 180
mbed_official 0:51ac1d130fd4 181 /* build TCP header */
mbed_official 0:51ac1d130fd4 182 if (pbuf_header(p, TCP_HLEN)) {
mbed_official 0:51ac1d130fd4 183 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no room for TCP header in pbuf.\n"));
mbed_official 0:51ac1d130fd4 184 TCP_STATS_INC(tcp.err);
mbed_official 0:51ac1d130fd4 185 tcp_seg_free(seg);
mbed_official 0:51ac1d130fd4 186 return NULL;
mbed_official 0:51ac1d130fd4 187 }
mbed_official 0:51ac1d130fd4 188 seg->tcphdr = (struct tcp_hdr *)seg->p->payload;
mbed_official 0:51ac1d130fd4 189 seg->tcphdr->src = htons(pcb->local_port);
mbed_official 0:51ac1d130fd4 190 seg->tcphdr->dest = htons(pcb->remote_port);
mbed_official 0:51ac1d130fd4 191 seg->tcphdr->seqno = htonl(seqno);
mbed_official 0:51ac1d130fd4 192 /* ackno is set in tcp_output */
mbed_official 0:51ac1d130fd4 193 TCPH_HDRLEN_FLAGS_SET(seg->tcphdr, (5 + optlen / 4), flags);
mbed_official 0:51ac1d130fd4 194 /* wnd and chksum are set in tcp_output */
mbed_official 0:51ac1d130fd4 195 seg->tcphdr->urgp = 0;
mbed_official 0:51ac1d130fd4 196 return seg;
mbed_official 0:51ac1d130fd4 197 }
mbed_official 0:51ac1d130fd4 198
mbed_official 0:51ac1d130fd4 199 /**
mbed_official 0:51ac1d130fd4 200 * Allocate a PBUF_RAM pbuf, perhaps with extra space at the end.
mbed_official 0:51ac1d130fd4 201 *
mbed_official 0:51ac1d130fd4 202 * This function is like pbuf_alloc(layer, length, PBUF_RAM) except
mbed_official 0:51ac1d130fd4 203 * there may be extra bytes available at the end.
mbed_official 0:51ac1d130fd4 204 *
mbed_official 0:51ac1d130fd4 205 * @param layer flag to define header size.
mbed_official 0:51ac1d130fd4 206 * @param length size of the pbuf's payload.
mbed_official 0:51ac1d130fd4 207 * @param max_length maximum usable size of payload+oversize.
mbed_official 0:51ac1d130fd4 208 * @param oversize pointer to a u16_t that will receive the number of usable tail bytes.
mbed_official 0:51ac1d130fd4 209 * @param pcb The TCP connection that willo enqueue the pbuf.
mbed_official 0:51ac1d130fd4 210 * @param apiflags API flags given to tcp_write.
mbed_official 0:51ac1d130fd4 211 * @param first_seg true when this pbuf will be used in the first enqueued segment.
mbed_official 0:51ac1d130fd4 212 * @param
mbed_official 0:51ac1d130fd4 213 */
mbed_official 0:51ac1d130fd4 214 #if TCP_OVERSIZE
mbed_official 0:51ac1d130fd4 215 static struct pbuf *
mbed_official 0:51ac1d130fd4 216 tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length,
mbed_official 0:51ac1d130fd4 217 u16_t *oversize, struct tcp_pcb *pcb, u8_t apiflags,
mbed_official 0:51ac1d130fd4 218 u8_t first_seg)
mbed_official 0:51ac1d130fd4 219 {
mbed_official 0:51ac1d130fd4 220 struct pbuf *p;
mbed_official 0:51ac1d130fd4 221 u16_t alloc = length;
mbed_official 0:51ac1d130fd4 222
mbed_official 0:51ac1d130fd4 223 #if LWIP_NETIF_TX_SINGLE_PBUF
mbed_official 0:51ac1d130fd4 224 LWIP_UNUSED_ARG(max_length);
mbed_official 0:51ac1d130fd4 225 LWIP_UNUSED_ARG(pcb);
mbed_official 0:51ac1d130fd4 226 LWIP_UNUSED_ARG(apiflags);
mbed_official 0:51ac1d130fd4 227 LWIP_UNUSED_ARG(first_seg);
mbed_official 0:51ac1d130fd4 228 /* always create MSS-sized pbufs */
mbed_official 0:51ac1d130fd4 229 alloc = TCP_MSS;
mbed_official 0:51ac1d130fd4 230 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
mbed_official 0:51ac1d130fd4 231 if (length < max_length) {
mbed_official 0:51ac1d130fd4 232 /* Should we allocate an oversized pbuf, or just the minimum
mbed_official 0:51ac1d130fd4 233 * length required? If tcp_write is going to be called again
mbed_official 0:51ac1d130fd4 234 * before this segment is transmitted, we want the oversized
mbed_official 0:51ac1d130fd4 235 * buffer. If the segment will be transmitted immediately, we can
mbed_official 0:51ac1d130fd4 236 * save memory by allocating only length. We use a simple
mbed_official 0:51ac1d130fd4 237 * heuristic based on the following information:
mbed_official 0:51ac1d130fd4 238 *
mbed_official 0:51ac1d130fd4 239 * Did the user set TCP_WRITE_FLAG_MORE?
mbed_official 0:51ac1d130fd4 240 *
mbed_official 0:51ac1d130fd4 241 * Will the Nagle algorithm defer transmission of this segment?
mbed_official 0:51ac1d130fd4 242 */
mbed_official 0:51ac1d130fd4 243 if ((apiflags & TCP_WRITE_FLAG_MORE) ||
mbed_official 0:51ac1d130fd4 244 (!(pcb->flags & TF_NODELAY) &&
mbed_official 0:51ac1d130fd4 245 (!first_seg ||
mbed_official 0:51ac1d130fd4 246 pcb->unsent != NULL ||
mbed_official 0:51ac1d130fd4 247 pcb->unacked != NULL))) {
mbed_official 0:51ac1d130fd4 248 alloc = LWIP_MIN(max_length, LWIP_MEM_ALIGN_SIZE(length + TCP_OVERSIZE));
mbed_official 0:51ac1d130fd4 249 }
mbed_official 0:51ac1d130fd4 250 }
mbed_official 0:51ac1d130fd4 251 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
mbed_official 0:51ac1d130fd4 252 p = pbuf_alloc(layer, alloc, PBUF_RAM);
mbed_official 0:51ac1d130fd4 253 if (p == NULL) {
mbed_official 0:51ac1d130fd4 254 return NULL;
mbed_official 0:51ac1d130fd4 255 }
mbed_official 0:51ac1d130fd4 256 LWIP_ASSERT("need unchained pbuf", p->next == NULL);
mbed_official 0:51ac1d130fd4 257 *oversize = p->len - length;
mbed_official 0:51ac1d130fd4 258 /* trim p->len to the currently used size */
mbed_official 0:51ac1d130fd4 259 p->len = p->tot_len = length;
mbed_official 0:51ac1d130fd4 260 return p;
mbed_official 0:51ac1d130fd4 261 }
mbed_official 0:51ac1d130fd4 262 #else /* TCP_OVERSIZE */
mbed_official 0:51ac1d130fd4 263 #define tcp_pbuf_prealloc(layer, length, mx, os, pcb, api, fst) pbuf_alloc((layer), (length), PBUF_RAM)
mbed_official 0:51ac1d130fd4 264 #endif /* TCP_OVERSIZE */
mbed_official 0:51ac1d130fd4 265
mbed_official 0:51ac1d130fd4 266 #if TCP_CHECKSUM_ON_COPY
mbed_official 0:51ac1d130fd4 267 /** Add a checksum of newly added data to the segment */
mbed_official 0:51ac1d130fd4 268 static void
mbed_official 0:51ac1d130fd4 269 tcp_seg_add_chksum(u16_t chksum, u16_t len, u16_t *seg_chksum,
mbed_official 0:51ac1d130fd4 270 u8_t *seg_chksum_swapped)
mbed_official 0:51ac1d130fd4 271 {
mbed_official 0:51ac1d130fd4 272 u32_t helper;
mbed_official 0:51ac1d130fd4 273 /* add chksum to old chksum and fold to u16_t */
mbed_official 0:51ac1d130fd4 274 helper = chksum + *seg_chksum;
mbed_official 0:51ac1d130fd4 275 chksum = FOLD_U32T(helper);
mbed_official 0:51ac1d130fd4 276 if ((len & 1) != 0) {
mbed_official 0:51ac1d130fd4 277 *seg_chksum_swapped = 1 - *seg_chksum_swapped;
mbed_official 0:51ac1d130fd4 278 chksum = SWAP_BYTES_IN_WORD(chksum);
mbed_official 0:51ac1d130fd4 279 }
mbed_official 0:51ac1d130fd4 280 *seg_chksum = chksum;
mbed_official 0:51ac1d130fd4 281 }
mbed_official 0:51ac1d130fd4 282 #endif /* TCP_CHECKSUM_ON_COPY */
mbed_official 0:51ac1d130fd4 283
mbed_official 0:51ac1d130fd4 284 /** Checks if tcp_write is allowed or not (checks state, snd_buf and snd_queuelen).
mbed_official 0:51ac1d130fd4 285 *
mbed_official 0:51ac1d130fd4 286 * @param pcb the tcp pcb to check for
mbed_official 0:51ac1d130fd4 287 * @param len length of data to send (checked agains snd_buf)
mbed_official 0:51ac1d130fd4 288 * @return ERR_OK if tcp_write is allowed to proceed, another err_t otherwise
mbed_official 0:51ac1d130fd4 289 */
mbed_official 0:51ac1d130fd4 290 static err_t
mbed_official 0:51ac1d130fd4 291 tcp_write_checks(struct tcp_pcb *pcb, u16_t len)
mbed_official 0:51ac1d130fd4 292 {
mbed_official 0:51ac1d130fd4 293 /* connection is in invalid state for data transmission? */
mbed_official 0:51ac1d130fd4 294 if ((pcb->state != ESTABLISHED) &&
mbed_official 0:51ac1d130fd4 295 (pcb->state != CLOSE_WAIT) &&
mbed_official 0:51ac1d130fd4 296 (pcb->state != SYN_SENT) &&
mbed_official 0:51ac1d130fd4 297 (pcb->state != SYN_RCVD)) {
mbed_official 0:51ac1d130fd4 298 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | LWIP_DBG_LEVEL_SEVERE, ("tcp_write() called in invalid state\n"));
mbed_official 0:51ac1d130fd4 299 return ERR_CONN;
mbed_official 0:51ac1d130fd4 300 } else if (len == 0) {
mbed_official 0:51ac1d130fd4 301 return ERR_OK;
mbed_official 0:51ac1d130fd4 302 }
mbed_official 0:51ac1d130fd4 303
mbed_official 0:51ac1d130fd4 304 /* fail on too much data */
mbed_official 0:51ac1d130fd4 305 if (len > pcb->snd_buf) {
mbed_official 0:51ac1d130fd4 306 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n",
mbed_official 0:51ac1d130fd4 307 len, pcb->snd_buf));
mbed_official 0:51ac1d130fd4 308 pcb->flags |= TF_NAGLEMEMERR;
mbed_official 0:51ac1d130fd4 309 return ERR_MEM;
mbed_official 0:51ac1d130fd4 310 }
mbed_official 0:51ac1d130fd4 311
mbed_official 0:51ac1d130fd4 312 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen));
mbed_official 0:51ac1d130fd4 313
mbed_official 0:51ac1d130fd4 314 /* If total number of pbufs on the unsent/unacked queues exceeds the
mbed_official 0:51ac1d130fd4 315 * configured maximum, return an error */
mbed_official 0:51ac1d130fd4 316 /* check for configured max queuelen and possible overflow */
mbed_official 0:51ac1d130fd4 317 if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
mbed_official 0:51ac1d130fd4 318 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too long queue %"U16_F" (max %"U16_F")\n",
mbed_official 0:51ac1d130fd4 319 pcb->snd_queuelen, TCP_SND_QUEUELEN));
mbed_official 0:51ac1d130fd4 320 TCP_STATS_INC(tcp.memerr);
mbed_official 0:51ac1d130fd4 321 pcb->flags |= TF_NAGLEMEMERR;
mbed_official 0:51ac1d130fd4 322 return ERR_MEM;
mbed_official 0:51ac1d130fd4 323 }
mbed_official 0:51ac1d130fd4 324 if (pcb->snd_queuelen != 0) {
mbed_official 0:51ac1d130fd4 325 LWIP_ASSERT("tcp_write: pbufs on queue => at least one queue non-empty",
mbed_official 0:51ac1d130fd4 326 pcb->unacked != NULL || pcb->unsent != NULL);
mbed_official 0:51ac1d130fd4 327 } else {
mbed_official 0:51ac1d130fd4 328 LWIP_ASSERT("tcp_write: no pbufs on queue => both queues empty",
mbed_official 0:51ac1d130fd4 329 pcb->unacked == NULL && pcb->unsent == NULL);
mbed_official 0:51ac1d130fd4 330 }
mbed_official 0:51ac1d130fd4 331 return ERR_OK;
mbed_official 0:51ac1d130fd4 332 }
mbed_official 0:51ac1d130fd4 333
mbed_official 0:51ac1d130fd4 334 /**
mbed_official 0:51ac1d130fd4 335 * Write data for sending (but does not send it immediately).
mbed_official 0:51ac1d130fd4 336 *
mbed_official 0:51ac1d130fd4 337 * It waits in the expectation of more data being sent soon (as
mbed_official 0:51ac1d130fd4 338 * it can send them more efficiently by combining them together).
mbed_official 0:51ac1d130fd4 339 * To prompt the system to send data now, call tcp_output() after
mbed_official 0:51ac1d130fd4 340 * calling tcp_write().
mbed_official 0:51ac1d130fd4 341 *
mbed_official 0:51ac1d130fd4 342 * @param pcb Protocol control block for the TCP connection to enqueue data for.
mbed_official 0:51ac1d130fd4 343 * @param arg Pointer to the data to be enqueued for sending.
mbed_official 0:51ac1d130fd4 344 * @param len Data length in bytes
mbed_official 0:51ac1d130fd4 345 * @param apiflags combination of following flags :
mbed_official 0:51ac1d130fd4 346 * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack
mbed_official 0:51ac1d130fd4 347 * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent,
mbed_official 0:51ac1d130fd4 348 * @return ERR_OK if enqueued, another err_t on error
mbed_official 0:51ac1d130fd4 349 */
mbed_official 0:51ac1d130fd4 350 err_t
mbed_official 0:51ac1d130fd4 351 tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
mbed_official 0:51ac1d130fd4 352 {
mbed_official 0:51ac1d130fd4 353 struct pbuf *concat_p = NULL;
mbed_official 0:51ac1d130fd4 354 struct tcp_seg *last_unsent = NULL, *seg = NULL, *prev_seg = NULL, *queue = NULL;
mbed_official 0:51ac1d130fd4 355 u16_t pos = 0; /* position in 'arg' data */
mbed_official 0:51ac1d130fd4 356 u16_t queuelen;
mbed_official 0:51ac1d130fd4 357 u8_t optlen = 0;
mbed_official 0:51ac1d130fd4 358 u8_t optflags = 0;
mbed_official 0:51ac1d130fd4 359 #if TCP_OVERSIZE
mbed_official 0:51ac1d130fd4 360 u16_t oversize = 0;
mbed_official 0:51ac1d130fd4 361 u16_t oversize_used = 0;
mbed_official 0:51ac1d130fd4 362 #endif /* TCP_OVERSIZE */
mbed_official 0:51ac1d130fd4 363 #if TCP_CHECKSUM_ON_COPY
mbed_official 0:51ac1d130fd4 364 u16_t concat_chksum = 0;
mbed_official 0:51ac1d130fd4 365 u8_t concat_chksum_swapped = 0;
mbed_official 0:51ac1d130fd4 366 u16_t concat_chksummed = 0;
mbed_official 0:51ac1d130fd4 367 #endif /* TCP_CHECKSUM_ON_COPY */
mbed_official 0:51ac1d130fd4 368 err_t err;
mbed_official 0:51ac1d130fd4 369
mbed_official 0:51ac1d130fd4 370 #if LWIP_NETIF_TX_SINGLE_PBUF
mbed_official 0:51ac1d130fd4 371 /* Always copy to try to create single pbufs for TX */
mbed_official 0:51ac1d130fd4 372 apiflags |= TCP_WRITE_FLAG_COPY;
mbed_official 0:51ac1d130fd4 373 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
mbed_official 0:51ac1d130fd4 374
mbed_official 0:51ac1d130fd4 375 LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n",
mbed_official 0:51ac1d130fd4 376 (void *)pcb, arg, len, (u16_t)apiflags));
mbed_official 0:51ac1d130fd4 377 LWIP_ERROR("tcp_write: arg == NULL (programmer violates API)",
mbed_official 0:51ac1d130fd4 378 arg != NULL, return ERR_ARG;);
mbed_official 0:51ac1d130fd4 379
mbed_official 0:51ac1d130fd4 380 err = tcp_write_checks(pcb, len);
mbed_official 0:51ac1d130fd4 381 if (err != ERR_OK) {
mbed_official 0:51ac1d130fd4 382 return err;
mbed_official 0:51ac1d130fd4 383 }
mbed_official 0:51ac1d130fd4 384 queuelen = pcb->snd_queuelen;
mbed_official 0:51ac1d130fd4 385
mbed_official 0:51ac1d130fd4 386 #if LWIP_TCP_TIMESTAMPS
mbed_official 0:51ac1d130fd4 387 if ((pcb->flags & TF_TIMESTAMP)) {
mbed_official 0:51ac1d130fd4 388 optflags = TF_SEG_OPTS_TS;
mbed_official 0:51ac1d130fd4 389 optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
mbed_official 0:51ac1d130fd4 390 }
mbed_official 0:51ac1d130fd4 391 #endif /* LWIP_TCP_TIMESTAMPS */
mbed_official 0:51ac1d130fd4 392
mbed_official 0:51ac1d130fd4 393
mbed_official 0:51ac1d130fd4 394 /*
mbed_official 0:51ac1d130fd4 395 * TCP segmentation is done in three phases with increasing complexity:
mbed_official 0:51ac1d130fd4 396 *
mbed_official 0:51ac1d130fd4 397 * 1. Copy data directly into an oversized pbuf.
mbed_official 0:51ac1d130fd4 398 * 2. Chain a new pbuf to the end of pcb->unsent.
mbed_official 0:51ac1d130fd4 399 * 3. Create new segments.
mbed_official 0:51ac1d130fd4 400 *
mbed_official 0:51ac1d130fd4 401 * We may run out of memory at any point. In that case we must
mbed_official 0:51ac1d130fd4 402 * return ERR_MEM and not change anything in pcb. Therefore, all
mbed_official 0:51ac1d130fd4 403 * changes are recorded in local variables and committed at the end
mbed_official 0:51ac1d130fd4 404 * of the function. Some pcb fields are maintained in local copies:
mbed_official 0:51ac1d130fd4 405 *
mbed_official 0:51ac1d130fd4 406 * queuelen = pcb->snd_queuelen
mbed_official 0:51ac1d130fd4 407 * oversize = pcb->unsent_oversize
mbed_official 0:51ac1d130fd4 408 *
mbed_official 0:51ac1d130fd4 409 * These variables are set consistently by the phases:
mbed_official 0:51ac1d130fd4 410 *
mbed_official 0:51ac1d130fd4 411 * seg points to the last segment tampered with.
mbed_official 0:51ac1d130fd4 412 *
mbed_official 0:51ac1d130fd4 413 * pos records progress as data is segmented.
mbed_official 0:51ac1d130fd4 414 */
mbed_official 0:51ac1d130fd4 415
mbed_official 0:51ac1d130fd4 416 /* Find the tail of the unsent queue. */
mbed_official 0:51ac1d130fd4 417 if (pcb->unsent != NULL) {
mbed_official 0:51ac1d130fd4 418 u16_t space;
mbed_official 0:51ac1d130fd4 419 u16_t unsent_optlen;
mbed_official 0:51ac1d130fd4 420
mbed_official 0:51ac1d130fd4 421 /* @todo: this could be sped up by keeping last_unsent in the pcb */
mbed_official 0:51ac1d130fd4 422 for (last_unsent = pcb->unsent; last_unsent->next != NULL;
mbed_official 0:51ac1d130fd4 423 last_unsent = last_unsent->next);
mbed_official 0:51ac1d130fd4 424
mbed_official 0:51ac1d130fd4 425 /* Usable space at the end of the last unsent segment */
mbed_official 0:51ac1d130fd4 426 unsent_optlen = LWIP_TCP_OPT_LENGTH(last_unsent->flags);
mbed_official 0:51ac1d130fd4 427 space = pcb->mss - (last_unsent->len + unsent_optlen);
mbed_official 0:51ac1d130fd4 428
mbed_official 0:51ac1d130fd4 429 /*
mbed_official 0:51ac1d130fd4 430 * Phase 1: Copy data directly into an oversized pbuf.
mbed_official 0:51ac1d130fd4 431 *
mbed_official 0:51ac1d130fd4 432 * The number of bytes copied is recorded in the oversize_used
mbed_official 0:51ac1d130fd4 433 * variable. The actual copying is done at the bottom of the
mbed_official 0:51ac1d130fd4 434 * function.
mbed_official 0:51ac1d130fd4 435 */
mbed_official 0:51ac1d130fd4 436 #if TCP_OVERSIZE
mbed_official 0:51ac1d130fd4 437 #if TCP_OVERSIZE_DBGCHECK
mbed_official 0:51ac1d130fd4 438 /* check that pcb->unsent_oversize matches last_unsent->unsent_oversize */
mbed_official 0:51ac1d130fd4 439 LWIP_ASSERT("unsent_oversize mismatch (pcb vs. last_unsent)",
mbed_official 0:51ac1d130fd4 440 pcb->unsent_oversize == last_unsent->oversize_left);
mbed_official 0:51ac1d130fd4 441 #endif /* TCP_OVERSIZE_DBGCHECK */
mbed_official 0:51ac1d130fd4 442 oversize = pcb->unsent_oversize;
mbed_official 0:51ac1d130fd4 443 if (oversize > 0) {
mbed_official 0:51ac1d130fd4 444 LWIP_ASSERT("inconsistent oversize vs. space", oversize_used <= space);
mbed_official 0:51ac1d130fd4 445 seg = last_unsent;
mbed_official 0:51ac1d130fd4 446 oversize_used = oversize < len ? oversize : len;
mbed_official 0:51ac1d130fd4 447 pos += oversize_used;
mbed_official 0:51ac1d130fd4 448 oversize -= oversize_used;
mbed_official 0:51ac1d130fd4 449 space -= oversize_used;
mbed_official 0:51ac1d130fd4 450 }
mbed_official 0:51ac1d130fd4 451 /* now we are either finished or oversize is zero */
mbed_official 0:51ac1d130fd4 452 LWIP_ASSERT("inconsistend oversize vs. len", (oversize == 0) || (pos == len));
mbed_official 0:51ac1d130fd4 453 #endif /* TCP_OVERSIZE */
mbed_official 0:51ac1d130fd4 454
mbed_official 0:51ac1d130fd4 455 /*
mbed_official 0:51ac1d130fd4 456 * Phase 2: Chain a new pbuf to the end of pcb->unsent.
mbed_official 0:51ac1d130fd4 457 *
mbed_official 0:51ac1d130fd4 458 * We don't extend segments containing SYN/FIN flags or options
mbed_official 0:51ac1d130fd4 459 * (len==0). The new pbuf is kept in concat_p and pbuf_cat'ed at
mbed_official 0:51ac1d130fd4 460 * the end.
mbed_official 0:51ac1d130fd4 461 */
mbed_official 0:51ac1d130fd4 462 if ((pos < len) && (space > 0) && (last_unsent->len > 0)) {
mbed_official 0:51ac1d130fd4 463 u16_t seglen = space < len - pos ? space : len - pos;
mbed_official 0:51ac1d130fd4 464 seg = last_unsent;
mbed_official 0:51ac1d130fd4 465
mbed_official 0:51ac1d130fd4 466 /* Create a pbuf with a copy or reference to seglen bytes. We
mbed_official 0:51ac1d130fd4 467 * can use PBUF_RAW here since the data appears in the middle of
mbed_official 0:51ac1d130fd4 468 * a segment. A header will never be prepended. */
mbed_official 0:51ac1d130fd4 469 if (apiflags & TCP_WRITE_FLAG_COPY) {
mbed_official 0:51ac1d130fd4 470 /* Data is copied */
mbed_official 0:51ac1d130fd4 471 if ((concat_p = tcp_pbuf_prealloc(PBUF_RAW, seglen, space, &oversize, pcb, apiflags, 1)) == NULL) {
mbed_official 0:51ac1d130fd4 472 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,
mbed_official 0:51ac1d130fd4 473 ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n",
mbed_official 0:51ac1d130fd4 474 seglen));
mbed_official 0:51ac1d130fd4 475 goto memerr;
mbed_official 0:51ac1d130fd4 476 }
mbed_official 0:51ac1d130fd4 477 #if TCP_OVERSIZE_DBGCHECK
mbed_official 0:51ac1d130fd4 478 last_unsent->oversize_left = oversize;
mbed_official 0:51ac1d130fd4 479 #endif /* TCP_OVERSIZE_DBGCHECK */
mbed_official 0:51ac1d130fd4 480 TCP_DATA_COPY2(concat_p->payload, (u8_t*)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped);
mbed_official 0:51ac1d130fd4 481 #if TCP_CHECKSUM_ON_COPY
mbed_official 0:51ac1d130fd4 482 concat_chksummed += seglen;
mbed_official 0:51ac1d130fd4 483 #endif /* TCP_CHECKSUM_ON_COPY */
mbed_official 0:51ac1d130fd4 484 } else {
mbed_official 0:51ac1d130fd4 485 /* Data is not copied */
mbed_official 0:51ac1d130fd4 486 if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) {
mbed_official 0:51ac1d130fd4 487 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,
mbed_official 0:51ac1d130fd4 488 ("tcp_write: could not allocate memory for zero-copy pbuf\n"));
mbed_official 0:51ac1d130fd4 489 goto memerr;
mbed_official 0:51ac1d130fd4 490 }
mbed_official 0:51ac1d130fd4 491 #if TCP_CHECKSUM_ON_COPY
mbed_official 0:51ac1d130fd4 492 /* calculate the checksum of nocopy-data */
mbed_official 0:51ac1d130fd4 493 tcp_seg_add_chksum(~inet_chksum((u8_t*)arg + pos, seglen), seglen,
mbed_official 0:51ac1d130fd4 494 &concat_chksum, &concat_chksum_swapped);
mbed_official 0:51ac1d130fd4 495 concat_chksummed += seglen;
mbed_official 0:51ac1d130fd4 496 #endif /* TCP_CHECKSUM_ON_COPY */
mbed_official 0:51ac1d130fd4 497 /* reference the non-volatile payload data */
mbed_official 0:51ac1d130fd4 498 concat_p->payload = (u8_t*)arg + pos;
mbed_official 0:51ac1d130fd4 499 }
mbed_official 0:51ac1d130fd4 500
mbed_official 0:51ac1d130fd4 501 pos += seglen;
mbed_official 0:51ac1d130fd4 502 queuelen += pbuf_clen(concat_p);
mbed_official 0:51ac1d130fd4 503 }
mbed_official 0:51ac1d130fd4 504 } else {
mbed_official 0:51ac1d130fd4 505 #if TCP_OVERSIZE
mbed_official 0:51ac1d130fd4 506 LWIP_ASSERT("unsent_oversize mismatch (pcb->unsent is NULL)",
mbed_official 0:51ac1d130fd4 507 pcb->unsent_oversize == 0);
mbed_official 0:51ac1d130fd4 508 #endif /* TCP_OVERSIZE */
mbed_official 0:51ac1d130fd4 509 }
mbed_official 0:51ac1d130fd4 510
mbed_official 0:51ac1d130fd4 511 /*
mbed_official 0:51ac1d130fd4 512 * Phase 3: Create new segments.
mbed_official 0:51ac1d130fd4 513 *
mbed_official 0:51ac1d130fd4 514 * The new segments are chained together in the local 'queue'
mbed_official 0:51ac1d130fd4 515 * variable, ready to be appended to pcb->unsent.
mbed_official 0:51ac1d130fd4 516 */
mbed_official 0:51ac1d130fd4 517 while (pos < len) {
mbed_official 0:51ac1d130fd4 518 struct pbuf *p;
mbed_official 0:51ac1d130fd4 519 u16_t left = len - pos;
mbed_official 0:51ac1d130fd4 520 u16_t max_len = pcb->mss - optlen;
mbed_official 0:51ac1d130fd4 521 u16_t seglen = left > max_len ? max_len : left;
mbed_official 0:51ac1d130fd4 522 #if TCP_CHECKSUM_ON_COPY
mbed_official 0:51ac1d130fd4 523 u16_t chksum = 0;
mbed_official 0:51ac1d130fd4 524 u8_t chksum_swapped = 0;
mbed_official 0:51ac1d130fd4 525 #endif /* TCP_CHECKSUM_ON_COPY */
mbed_official 0:51ac1d130fd4 526
mbed_official 0:51ac1d130fd4 527 if (apiflags & TCP_WRITE_FLAG_COPY) {
mbed_official 0:51ac1d130fd4 528 /* If copy is set, memory should be allocated and data copied
mbed_official 0:51ac1d130fd4 529 * into pbuf */
mbed_official 0:51ac1d130fd4 530 if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, pcb->mss, &oversize, pcb, apiflags, queue == NULL)) == NULL) {
mbed_official 0:51ac1d130fd4 531 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));
mbed_official 0:51ac1d130fd4 532 goto memerr;
mbed_official 0:51ac1d130fd4 533 }
mbed_official 0:51ac1d130fd4 534 LWIP_ASSERT("tcp_write: check that first pbuf can hold the complete seglen",
mbed_official 0:51ac1d130fd4 535 (p->len >= seglen));
mbed_official 0:51ac1d130fd4 536 TCP_DATA_COPY2((char *)p->payload + optlen, (u8_t*)arg + pos, seglen, &chksum, &chksum_swapped);
mbed_official 0:51ac1d130fd4 537 } else {
mbed_official 0:51ac1d130fd4 538 /* Copy is not set: First allocate a pbuf for holding the data.
mbed_official 0:51ac1d130fd4 539 * Since the referenced data is available at least until it is
mbed_official 0:51ac1d130fd4 540 * sent out on the link (as it has to be ACKed by the remote
mbed_official 0:51ac1d130fd4 541 * party) we can safely use PBUF_ROM instead of PBUF_REF here.
mbed_official 0:51ac1d130fd4 542 */
mbed_official 0:51ac1d130fd4 543 struct pbuf *p2;
mbed_official 0:51ac1d130fd4 544 #if TCP_OVERSIZE
mbed_official 0:51ac1d130fd4 545 LWIP_ASSERT("oversize == 0", oversize == 0);
mbed_official 0:51ac1d130fd4 546 #endif /* TCP_OVERSIZE */
mbed_official 0:51ac1d130fd4 547 if ((p2 = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {
mbed_official 0:51ac1d130fd4 548 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for zero-copy pbuf\n"));
mbed_official 0:51ac1d130fd4 549 goto memerr;
mbed_official 0:51ac1d130fd4 550 }
mbed_official 0:51ac1d130fd4 551 #if TCP_CHECKSUM_ON_COPY
mbed_official 0:51ac1d130fd4 552 /* calculate the checksum of nocopy-data */
mbed_official 0:51ac1d130fd4 553 chksum = ~inet_chksum((u8_t*)arg + pos, seglen);
mbed_official 0:51ac1d130fd4 554 #endif /* TCP_CHECKSUM_ON_COPY */
mbed_official 0:51ac1d130fd4 555 /* reference the non-volatile payload data */
mbed_official 0:51ac1d130fd4 556 p2->payload = (u8_t*)arg + pos;
mbed_official 0:51ac1d130fd4 557
mbed_official 0:51ac1d130fd4 558 /* Second, allocate a pbuf for the headers. */
mbed_official 0:51ac1d130fd4 559 if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
mbed_official 0:51ac1d130fd4 560 /* If allocation fails, we have to deallocate the data pbuf as
mbed_official 0:51ac1d130fd4 561 * well. */
mbed_official 0:51ac1d130fd4 562 pbuf_free(p2);
mbed_official 0:51ac1d130fd4 563 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for header pbuf\n"));
mbed_official 0:51ac1d130fd4 564 goto memerr;
mbed_official 0:51ac1d130fd4 565 }
mbed_official 0:51ac1d130fd4 566 /* Concatenate the headers and data pbufs together. */
mbed_official 0:51ac1d130fd4 567 pbuf_cat(p/*header*/, p2/*data*/);
mbed_official 0:51ac1d130fd4 568 }
mbed_official 0:51ac1d130fd4 569
mbed_official 0:51ac1d130fd4 570 queuelen += pbuf_clen(p);
mbed_official 0:51ac1d130fd4 571
mbed_official 0:51ac1d130fd4 572 /* Now that there are more segments queued, we check again if the
mbed_official 0:51ac1d130fd4 573 * length of the queue exceeds the configured maximum or
mbed_official 0:51ac1d130fd4 574 * overflows. */
mbed_official 0:51ac1d130fd4 575 if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
mbed_official 0:51ac1d130fd4 576 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
mbed_official 0:51ac1d130fd4 577 pbuf_free(p);
mbed_official 0:51ac1d130fd4 578 goto memerr;
mbed_official 0:51ac1d130fd4 579 }
mbed_official 0:51ac1d130fd4 580
mbed_official 0:51ac1d130fd4 581 if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) {
mbed_official 0:51ac1d130fd4 582 goto memerr;
mbed_official 0:51ac1d130fd4 583 }
mbed_official 0:51ac1d130fd4 584 #if TCP_OVERSIZE_DBGCHECK
mbed_official 0:51ac1d130fd4 585 seg->oversize_left = oversize;
mbed_official 0:51ac1d130fd4 586 #endif /* TCP_OVERSIZE_DBGCHECK */
mbed_official 0:51ac1d130fd4 587 #if TCP_CHECKSUM_ON_COPY
mbed_official 0:51ac1d130fd4 588 seg->chksum = chksum;
mbed_official 0:51ac1d130fd4 589 seg->chksum_swapped = chksum_swapped;
mbed_official 0:51ac1d130fd4 590 seg->flags |= TF_SEG_DATA_CHECKSUMMED;
mbed_official 0:51ac1d130fd4 591 #endif /* TCP_CHECKSUM_ON_COPY */
mbed_official 0:51ac1d130fd4 592
mbed_official 0:51ac1d130fd4 593 /* first segment of to-be-queued data? */
mbed_official 0:51ac1d130fd4 594 if (queue == NULL) {
mbed_official 0:51ac1d130fd4 595 queue = seg;
mbed_official 0:51ac1d130fd4 596 } else {
mbed_official 0:51ac1d130fd4 597 /* Attach the segment to the end of the queued segments */
mbed_official 0:51ac1d130fd4 598 LWIP_ASSERT("prev_seg != NULL", prev_seg != NULL);
mbed_official 0:51ac1d130fd4 599 prev_seg->next = seg;
mbed_official 0:51ac1d130fd4 600 }
mbed_official 0:51ac1d130fd4 601 /* remember last segment of to-be-queued data for next iteration */
mbed_official 0:51ac1d130fd4 602 prev_seg = seg;
mbed_official 0:51ac1d130fd4 603
mbed_official 0:51ac1d130fd4 604 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_write: queueing %"U32_F":%"U32_F"\n",
mbed_official 0:51ac1d130fd4 605 ntohl(seg->tcphdr->seqno),
mbed_official 0:51ac1d130fd4 606 ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg)));
mbed_official 0:51ac1d130fd4 607
mbed_official 0:51ac1d130fd4 608 pos += seglen;
mbed_official 0:51ac1d130fd4 609 }
mbed_official 0:51ac1d130fd4 610
mbed_official 0:51ac1d130fd4 611 /*
mbed_official 0:51ac1d130fd4 612 * All three segmentation phases were successful. We can commit the
mbed_official 0:51ac1d130fd4 613 * transaction.
mbed_official 0:51ac1d130fd4 614 */
mbed_official 0:51ac1d130fd4 615
mbed_official 0:51ac1d130fd4 616 /*
mbed_official 0:51ac1d130fd4 617 * Phase 1: If data has been added to the preallocated tail of
mbed_official 0:51ac1d130fd4 618 * last_unsent, we update the length fields of the pbuf chain.
mbed_official 0:51ac1d130fd4 619 */
mbed_official 0:51ac1d130fd4 620 #if TCP_OVERSIZE
mbed_official 0:51ac1d130fd4 621 if (oversize_used > 0) {
mbed_official 0:51ac1d130fd4 622 struct pbuf *p;
mbed_official 0:51ac1d130fd4 623 /* Bump tot_len of whole chain, len of tail */
mbed_official 0:51ac1d130fd4 624 for (p = last_unsent->p; p; p = p->next) {
mbed_official 0:51ac1d130fd4 625 p->tot_len += oversize_used;
mbed_official 0:51ac1d130fd4 626 if (p->next == NULL) {
mbed_official 0:51ac1d130fd4 627 TCP_DATA_COPY((char *)p->payload + p->len, arg, oversize_used, last_unsent);
mbed_official 0:51ac1d130fd4 628 p->len += oversize_used;
mbed_official 0:51ac1d130fd4 629 }
mbed_official 0:51ac1d130fd4 630 }
mbed_official 0:51ac1d130fd4 631 last_unsent->len += oversize_used;
mbed_official 0:51ac1d130fd4 632 #if TCP_OVERSIZE_DBGCHECK
mbed_official 0:51ac1d130fd4 633 last_unsent->oversize_left -= oversize_used;
mbed_official 0:51ac1d130fd4 634 #endif /* TCP_OVERSIZE_DBGCHECK */
mbed_official 0:51ac1d130fd4 635 }
mbed_official 0:51ac1d130fd4 636 pcb->unsent_oversize = oversize;
mbed_official 0:51ac1d130fd4 637 #endif /* TCP_OVERSIZE */
mbed_official 0:51ac1d130fd4 638
mbed_official 0:51ac1d130fd4 639 /*
mbed_official 0:51ac1d130fd4 640 * Phase 2: concat_p can be concatenated onto last_unsent->p
mbed_official 0:51ac1d130fd4 641 */
mbed_official 0:51ac1d130fd4 642 if (concat_p != NULL) {
mbed_official 0:51ac1d130fd4 643 LWIP_ASSERT("tcp_write: cannot concatenate when pcb->unsent is empty",
mbed_official 0:51ac1d130fd4 644 (last_unsent != NULL));
mbed_official 0:51ac1d130fd4 645 pbuf_cat(last_unsent->p, concat_p);
mbed_official 0:51ac1d130fd4 646 last_unsent->len += concat_p->tot_len;
mbed_official 0:51ac1d130fd4 647 #if TCP_CHECKSUM_ON_COPY
mbed_official 0:51ac1d130fd4 648 if (concat_chksummed) {
mbed_official 13:8e34c2cbce5d 649 if (concat_chksum_swapped) {
mbed_official 13:8e34c2cbce5d 650 concat_chksum = SWAP_BYTES_IN_WORD(concat_chksum);
mbed_official 13:8e34c2cbce5d 651 }
mbed_official 0:51ac1d130fd4 652 tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum,
mbed_official 0:51ac1d130fd4 653 &last_unsent->chksum_swapped);
mbed_official 0:51ac1d130fd4 654 last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED;
mbed_official 0:51ac1d130fd4 655 }
mbed_official 0:51ac1d130fd4 656 #endif /* TCP_CHECKSUM_ON_COPY */
mbed_official 0:51ac1d130fd4 657 }
mbed_official 0:51ac1d130fd4 658
mbed_official 0:51ac1d130fd4 659 /*
mbed_official 0:51ac1d130fd4 660 * Phase 3: Append queue to pcb->unsent. Queue may be NULL, but that
mbed_official 0:51ac1d130fd4 661 * is harmless
mbed_official 0:51ac1d130fd4 662 */
mbed_official 0:51ac1d130fd4 663 if (last_unsent == NULL) {
mbed_official 0:51ac1d130fd4 664 pcb->unsent = queue;
mbed_official 0:51ac1d130fd4 665 } else {
mbed_official 0:51ac1d130fd4 666 last_unsent->next = queue;
mbed_official 0:51ac1d130fd4 667 }
mbed_official 0:51ac1d130fd4 668
mbed_official 0:51ac1d130fd4 669 /*
mbed_official 0:51ac1d130fd4 670 * Finally update the pcb state.
mbed_official 0:51ac1d130fd4 671 */
mbed_official 0:51ac1d130fd4 672 pcb->snd_lbb += len;
mbed_official 0:51ac1d130fd4 673 pcb->snd_buf -= len;
mbed_official 0:51ac1d130fd4 674 pcb->snd_queuelen = queuelen;
mbed_official 0:51ac1d130fd4 675
mbed_official 0:51ac1d130fd4 676 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: %"S16_F" (after enqueued)\n",
mbed_official 0:51ac1d130fd4 677 pcb->snd_queuelen));
mbed_official 0:51ac1d130fd4 678 if (pcb->snd_queuelen != 0) {
mbed_official 0:51ac1d130fd4 679 LWIP_ASSERT("tcp_write: valid queue length",
mbed_official 0:51ac1d130fd4 680 pcb->unacked != NULL || pcb->unsent != NULL);
mbed_official 0:51ac1d130fd4 681 }
mbed_official 0:51ac1d130fd4 682
mbed_official 0:51ac1d130fd4 683 /* Set the PSH flag in the last segment that we enqueued. */
mbed_official 0:51ac1d130fd4 684 if (seg != NULL && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE)==0)) {
mbed_official 0:51ac1d130fd4 685 TCPH_SET_FLAG(seg->tcphdr, TCP_PSH);
mbed_official 0:51ac1d130fd4 686 }
mbed_official 0:51ac1d130fd4 687
mbed_official 0:51ac1d130fd4 688 return ERR_OK;
mbed_official 0:51ac1d130fd4 689 memerr:
mbed_official 0:51ac1d130fd4 690 pcb->flags |= TF_NAGLEMEMERR;
mbed_official 0:51ac1d130fd4 691 TCP_STATS_INC(tcp.memerr);
mbed_official 0:51ac1d130fd4 692
mbed_official 0:51ac1d130fd4 693 if (concat_p != NULL) {
mbed_official 0:51ac1d130fd4 694 pbuf_free(concat_p);
mbed_official 0:51ac1d130fd4 695 }
mbed_official 0:51ac1d130fd4 696 if (queue != NULL) {
mbed_official 0:51ac1d130fd4 697 tcp_segs_free(queue);
mbed_official 0:51ac1d130fd4 698 }
mbed_official 0:51ac1d130fd4 699 if (pcb->snd_queuelen != 0) {
mbed_official 0:51ac1d130fd4 700 LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL ||
mbed_official 0:51ac1d130fd4 701 pcb->unsent != NULL);
mbed_official 0:51ac1d130fd4 702 }
mbed_official 0:51ac1d130fd4 703 LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_write: %"S16_F" (with mem err)\n", pcb->snd_queuelen));
mbed_official 0:51ac1d130fd4 704 return ERR_MEM;
mbed_official 0:51ac1d130fd4 705 }
mbed_official 0:51ac1d130fd4 706
mbed_official 0:51ac1d130fd4 707 /**
mbed_official 0:51ac1d130fd4 708 * Enqueue TCP options for transmission.
mbed_official 0:51ac1d130fd4 709 *
mbed_official 0:51ac1d130fd4 710 * Called by tcp_connect(), tcp_listen_input(), and tcp_send_ctrl().
mbed_official 0:51ac1d130fd4 711 *
mbed_official 0:51ac1d130fd4 712 * @param pcb Protocol control block for the TCP connection.
mbed_official 0:51ac1d130fd4 713 * @param flags TCP header flags to set in the outgoing segment.
mbed_official 0:51ac1d130fd4 714 * @param optdata pointer to TCP options, or NULL.
mbed_official 0:51ac1d130fd4 715 * @param optlen length of TCP options in bytes.
mbed_official 0:51ac1d130fd4 716 */
mbed_official 0:51ac1d130fd4 717 err_t
mbed_official 0:51ac1d130fd4 718 tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
mbed_official 0:51ac1d130fd4 719 {
mbed_official 0:51ac1d130fd4 720 struct pbuf *p;
mbed_official 0:51ac1d130fd4 721 struct tcp_seg *seg;
mbed_official 0:51ac1d130fd4 722 u8_t optflags = 0;
mbed_official 0:51ac1d130fd4 723 u8_t optlen = 0;
mbed_official 0:51ac1d130fd4 724
mbed_official 0:51ac1d130fd4 725 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen));
mbed_official 0:51ac1d130fd4 726
mbed_official 0:51ac1d130fd4 727 LWIP_ASSERT("tcp_enqueue_flags: need either TCP_SYN or TCP_FIN in flags (programmer violates API)",
mbed_official 0:51ac1d130fd4 728 (flags & (TCP_SYN | TCP_FIN)) != 0);
mbed_official 0:51ac1d130fd4 729
mbed_official 0:51ac1d130fd4 730 /* check for configured max queuelen and possible overflow */
mbed_official 0:51ac1d130fd4 731 if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
mbed_official 0:51ac1d130fd4 732 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: too long queue %"U16_F" (max %"U16_F")\n",
mbed_official 0:51ac1d130fd4 733 pcb->snd_queuelen, TCP_SND_QUEUELEN));
mbed_official 0:51ac1d130fd4 734 TCP_STATS_INC(tcp.memerr);
mbed_official 0:51ac1d130fd4 735 pcb->flags |= TF_NAGLEMEMERR;
mbed_official 0:51ac1d130fd4 736 return ERR_MEM;
mbed_official 0:51ac1d130fd4 737 }
mbed_official 0:51ac1d130fd4 738
mbed_official 0:51ac1d130fd4 739 if (flags & TCP_SYN) {
mbed_official 0:51ac1d130fd4 740 optflags = TF_SEG_OPTS_MSS;
mbed_official 0:51ac1d130fd4 741 }
mbed_official 0:51ac1d130fd4 742 #if LWIP_TCP_TIMESTAMPS
mbed_official 0:51ac1d130fd4 743 if ((pcb->flags & TF_TIMESTAMP)) {
mbed_official 0:51ac1d130fd4 744 optflags |= TF_SEG_OPTS_TS;
mbed_official 0:51ac1d130fd4 745 }
mbed_official 0:51ac1d130fd4 746 #endif /* LWIP_TCP_TIMESTAMPS */
mbed_official 0:51ac1d130fd4 747 optlen = LWIP_TCP_OPT_LENGTH(optflags);
mbed_official 0:51ac1d130fd4 748
mbed_official 0:51ac1d130fd4 749 /* tcp_enqueue_flags is always called with either SYN or FIN in flags.
mbed_official 0:51ac1d130fd4 750 * We need one available snd_buf byte to do that.
mbed_official 0:51ac1d130fd4 751 * This means we can't send FIN while snd_buf==0. A better fix would be to
mbed_official 0:51ac1d130fd4 752 * not include SYN and FIN sequence numbers in the snd_buf count. */
mbed_official 0:51ac1d130fd4 753 if (pcb->snd_buf == 0) {
mbed_official 0:51ac1d130fd4 754 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: no send buffer available\n"));
mbed_official 0:51ac1d130fd4 755 TCP_STATS_INC(tcp.memerr);
mbed_official 0:51ac1d130fd4 756 return ERR_MEM;
mbed_official 0:51ac1d130fd4 757 }
mbed_official 0:51ac1d130fd4 758
mbed_official 0:51ac1d130fd4 759 /* Allocate pbuf with room for TCP header + options */
mbed_official 0:51ac1d130fd4 760 if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
mbed_official 0:51ac1d130fd4 761 pcb->flags |= TF_NAGLEMEMERR;
mbed_official 0:51ac1d130fd4 762 TCP_STATS_INC(tcp.memerr);
mbed_official 0:51ac1d130fd4 763 return ERR_MEM;
mbed_official 0:51ac1d130fd4 764 }
mbed_official 0:51ac1d130fd4 765 LWIP_ASSERT("tcp_enqueue_flags: check that first pbuf can hold optlen",
mbed_official 0:51ac1d130fd4 766 (p->len >= optlen));
mbed_official 0:51ac1d130fd4 767
mbed_official 0:51ac1d130fd4 768 /* Allocate memory for tcp_seg, and fill in fields. */
mbed_official 0:51ac1d130fd4 769 if ((seg = tcp_create_segment(pcb, p, flags, pcb->snd_lbb, optflags)) == NULL) {
mbed_official 0:51ac1d130fd4 770 pcb->flags |= TF_NAGLEMEMERR;
mbed_official 0:51ac1d130fd4 771 TCP_STATS_INC(tcp.memerr);
mbed_official 0:51ac1d130fd4 772 return ERR_MEM;
mbed_official 0:51ac1d130fd4 773 }
mbed_official 0:51ac1d130fd4 774 LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
mbed_official 0:51ac1d130fd4 775 LWIP_ASSERT("tcp_enqueue_flags: invalid segment length", seg->len == 0);
mbed_official 0:51ac1d130fd4 776
mbed_official 0:51ac1d130fd4 777 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE,
mbed_official 0:51ac1d130fd4 778 ("tcp_enqueue_flags: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n",
mbed_official 0:51ac1d130fd4 779 ntohl(seg->tcphdr->seqno),
mbed_official 0:51ac1d130fd4 780 ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),
mbed_official 0:51ac1d130fd4 781 (u16_t)flags));
mbed_official 0:51ac1d130fd4 782
mbed_official 0:51ac1d130fd4 783 /* Now append seg to pcb->unsent queue */
mbed_official 0:51ac1d130fd4 784 if (pcb->unsent == NULL) {
mbed_official 0:51ac1d130fd4 785 pcb->unsent = seg;
mbed_official 0:51ac1d130fd4 786 } else {
mbed_official 0:51ac1d130fd4 787 struct tcp_seg *useg;
mbed_official 0:51ac1d130fd4 788 for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);
mbed_official 0:51ac1d130fd4 789 useg->next = seg;
mbed_official 0:51ac1d130fd4 790 }
mbed_official 0:51ac1d130fd4 791 #if TCP_OVERSIZE
mbed_official 0:51ac1d130fd4 792 /* The new unsent tail has no space */
mbed_official 0:51ac1d130fd4 793 pcb->unsent_oversize = 0;
mbed_official 0:51ac1d130fd4 794 #endif /* TCP_OVERSIZE */
mbed_official 0:51ac1d130fd4 795
mbed_official 0:51ac1d130fd4 796 /* SYN and FIN bump the sequence number */
mbed_official 0:51ac1d130fd4 797 if ((flags & TCP_SYN) || (flags & TCP_FIN)) {
mbed_official 0:51ac1d130fd4 798 pcb->snd_lbb++;
mbed_official 0:51ac1d130fd4 799 /* optlen does not influence snd_buf */
mbed_official 0:51ac1d130fd4 800 pcb->snd_buf--;
mbed_official 0:51ac1d130fd4 801 }
mbed_official 0:51ac1d130fd4 802 if (flags & TCP_FIN) {
mbed_official 0:51ac1d130fd4 803 pcb->flags |= TF_FIN;
mbed_official 0:51ac1d130fd4 804 }
mbed_official 0:51ac1d130fd4 805
mbed_official 0:51ac1d130fd4 806 /* update number of segments on the queues */
mbed_official 0:51ac1d130fd4 807 pcb->snd_queuelen += pbuf_clen(seg->p);
mbed_official 0:51ac1d130fd4 808 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: %"S16_F" (after enqueued)\n", pcb->snd_queuelen));
mbed_official 0:51ac1d130fd4 809 if (pcb->snd_queuelen != 0) {
mbed_official 0:51ac1d130fd4 810 LWIP_ASSERT("tcp_enqueue_flags: invalid queue length",
mbed_official 0:51ac1d130fd4 811 pcb->unacked != NULL || pcb->unsent != NULL);
mbed_official 0:51ac1d130fd4 812 }
mbed_official 0:51ac1d130fd4 813
mbed_official 0:51ac1d130fd4 814 return ERR_OK;
mbed_official 0:51ac1d130fd4 815 }
mbed_official 0:51ac1d130fd4 816
mbed_official 0:51ac1d130fd4 817
mbed_official 0:51ac1d130fd4 818 #if LWIP_TCP_TIMESTAMPS
mbed_official 0:51ac1d130fd4 819 /* Build a timestamp option (12 bytes long) at the specified options pointer)
mbed_official 0:51ac1d130fd4 820 *
mbed_official 0:51ac1d130fd4 821 * @param pcb tcp_pcb
mbed_official 0:51ac1d130fd4 822 * @param opts option pointer where to store the timestamp option
mbed_official 0:51ac1d130fd4 823 */
mbed_official 0:51ac1d130fd4 824 static void
mbed_official 0:51ac1d130fd4 825 tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts)
mbed_official 0:51ac1d130fd4 826 {
mbed_official 0:51ac1d130fd4 827 /* Pad with two NOP options to make everything nicely aligned */
mbed_official 0:51ac1d130fd4 828 opts[0] = PP_HTONL(0x0101080A);
mbed_official 0:51ac1d130fd4 829 opts[1] = htonl(sys_now());
mbed_official 0:51ac1d130fd4 830 opts[2] = htonl(pcb->ts_recent);
mbed_official 0:51ac1d130fd4 831 }
mbed_official 0:51ac1d130fd4 832 #endif
mbed_official 0:51ac1d130fd4 833
mbed_official 0:51ac1d130fd4 834 /** Send an ACK without data.
mbed_official 0:51ac1d130fd4 835 *
mbed_official 0:51ac1d130fd4 836 * @param pcb Protocol control block for the TCP connection to send the ACK
mbed_official 0:51ac1d130fd4 837 */
mbed_official 0:51ac1d130fd4 838 err_t
mbed_official 0:51ac1d130fd4 839 tcp_send_empty_ack(struct tcp_pcb *pcb)
mbed_official 0:51ac1d130fd4 840 {
mbed_official 0:51ac1d130fd4 841 struct pbuf *p;
mbed_official 0:51ac1d130fd4 842 struct tcp_hdr *tcphdr;
mbed_official 0:51ac1d130fd4 843 u8_t optlen = 0;
mbed_official 0:51ac1d130fd4 844
mbed_official 0:51ac1d130fd4 845 #if LWIP_TCP_TIMESTAMPS
mbed_official 0:51ac1d130fd4 846 if (pcb->flags & TF_TIMESTAMP) {
mbed_official 0:51ac1d130fd4 847 optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
mbed_official 0:51ac1d130fd4 848 }
mbed_official 0:51ac1d130fd4 849 #endif
mbed_official 0:51ac1d130fd4 850
mbed_official 0:51ac1d130fd4 851 p = tcp_output_alloc_header(pcb, optlen, 0, htonl(pcb->snd_nxt));
mbed_official 0:51ac1d130fd4 852 if (p == NULL) {
mbed_official 0:51ac1d130fd4 853 LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
mbed_official 0:51ac1d130fd4 854 return ERR_BUF;
mbed_official 0:51ac1d130fd4 855 }
mbed_official 0:51ac1d130fd4 856 tcphdr = (struct tcp_hdr *)p->payload;
mbed_official 0:51ac1d130fd4 857 LWIP_DEBUGF(TCP_OUTPUT_DEBUG,
mbed_official 0:51ac1d130fd4 858 ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));
mbed_official 0:51ac1d130fd4 859 /* remove ACK flags from the PCB, as we send an empty ACK now */
mbed_official 0:51ac1d130fd4 860 pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
mbed_official 0:51ac1d130fd4 861
mbed_official 0:51ac1d130fd4 862 /* NB. MSS option is only sent on SYNs, so ignore it here */
mbed_official 0:51ac1d130fd4 863 #if LWIP_TCP_TIMESTAMPS
mbed_official 0:51ac1d130fd4 864 pcb->ts_lastacksent = pcb->rcv_nxt;
mbed_official 0:51ac1d130fd4 865
mbed_official 0:51ac1d130fd4 866 if (pcb->flags & TF_TIMESTAMP) {
mbed_official 0:51ac1d130fd4 867 tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1));
mbed_official 0:51ac1d130fd4 868 }
mbed_official 0:51ac1d130fd4 869 #endif
mbed_official 0:51ac1d130fd4 870
mbed_official 0:51ac1d130fd4 871 #if CHECKSUM_GEN_TCP
mbed_official 0:51ac1d130fd4 872 tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
mbed_official 0:51ac1d130fd4 873 IP_PROTO_TCP, p->tot_len);
mbed_official 0:51ac1d130fd4 874 #endif
mbed_official 0:51ac1d130fd4 875 #if LWIP_NETIF_HWADDRHINT
mbed_official 0:51ac1d130fd4 876 ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
mbed_official 0:51ac1d130fd4 877 IP_PROTO_TCP, &(pcb->addr_hint));
mbed_official 0:51ac1d130fd4 878 #else /* LWIP_NETIF_HWADDRHINT*/
mbed_official 0:51ac1d130fd4 879 ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
mbed_official 0:51ac1d130fd4 880 IP_PROTO_TCP);
mbed_official 0:51ac1d130fd4 881 #endif /* LWIP_NETIF_HWADDRHINT*/
mbed_official 0:51ac1d130fd4 882 pbuf_free(p);
mbed_official 0:51ac1d130fd4 883
mbed_official 0:51ac1d130fd4 884 return ERR_OK;
mbed_official 0:51ac1d130fd4 885 }
mbed_official 0:51ac1d130fd4 886
mbed_official 0:51ac1d130fd4 887 /**
mbed_official 0:51ac1d130fd4 888 * Find out what we can send and send it
mbed_official 0:51ac1d130fd4 889 *
mbed_official 0:51ac1d130fd4 890 * @param pcb Protocol control block for the TCP connection to send data
mbed_official 0:51ac1d130fd4 891 * @return ERR_OK if data has been sent or nothing to send
mbed_official 0:51ac1d130fd4 892 * another err_t on error
mbed_official 0:51ac1d130fd4 893 */
mbed_official 0:51ac1d130fd4 894 err_t
mbed_official 0:51ac1d130fd4 895 tcp_output(struct tcp_pcb *pcb)
mbed_official 0:51ac1d130fd4 896 {
mbed_official 0:51ac1d130fd4 897 struct tcp_seg *seg, *useg;
mbed_official 0:51ac1d130fd4 898 u32_t wnd, snd_nxt;
mbed_official 0:51ac1d130fd4 899 #if TCP_CWND_DEBUG
mbed_official 0:51ac1d130fd4 900 s16_t i = 0;
mbed_official 0:51ac1d130fd4 901 #endif /* TCP_CWND_DEBUG */
mbed_official 0:51ac1d130fd4 902
mbed_official 0:51ac1d130fd4 903 /* First, check if we are invoked by the TCP input processing
mbed_official 0:51ac1d130fd4 904 code. If so, we do not output anything. Instead, we rely on the
mbed_official 0:51ac1d130fd4 905 input processing code to call us when input processing is done
mbed_official 0:51ac1d130fd4 906 with. */
mbed_official 0:51ac1d130fd4 907 if (tcp_input_pcb == pcb) {
mbed_official 0:51ac1d130fd4 908 return ERR_OK;
mbed_official 0:51ac1d130fd4 909 }
mbed_official 0:51ac1d130fd4 910
mbed_official 0:51ac1d130fd4 911 wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);
mbed_official 0:51ac1d130fd4 912
mbed_official 0:51ac1d130fd4 913 seg = pcb->unsent;
mbed_official 0:51ac1d130fd4 914
mbed_official 0:51ac1d130fd4 915 /* If the TF_ACK_NOW flag is set and no data will be sent (either
mbed_official 0:51ac1d130fd4 916 * because the ->unsent queue is empty or because the window does
mbed_official 0:51ac1d130fd4 917 * not allow it), construct an empty ACK segment and send it.
mbed_official 0:51ac1d130fd4 918 *
mbed_official 0:51ac1d130fd4 919 * If data is to be sent, we will just piggyback the ACK (see below).
mbed_official 0:51ac1d130fd4 920 */
mbed_official 0:51ac1d130fd4 921 if (pcb->flags & TF_ACK_NOW &&
mbed_official 0:51ac1d130fd4 922 (seg == NULL ||
mbed_official 0:51ac1d130fd4 923 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
mbed_official 0:51ac1d130fd4 924 return tcp_send_empty_ack(pcb);
mbed_official 0:51ac1d130fd4 925 }
mbed_official 0:51ac1d130fd4 926
mbed_official 0:51ac1d130fd4 927 /* useg should point to last segment on unacked queue */
mbed_official 0:51ac1d130fd4 928 useg = pcb->unacked;
mbed_official 0:51ac1d130fd4 929 if (useg != NULL) {
mbed_official 0:51ac1d130fd4 930 for (; useg->next != NULL; useg = useg->next);
mbed_official 0:51ac1d130fd4 931 }
mbed_official 0:51ac1d130fd4 932
mbed_official 0:51ac1d130fd4 933 #if TCP_OUTPUT_DEBUG
mbed_official 0:51ac1d130fd4 934 if (seg == NULL) {
mbed_official 0:51ac1d130fd4 935 LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n",
mbed_official 0:51ac1d130fd4 936 (void*)pcb->unsent));
mbed_official 0:51ac1d130fd4 937 }
mbed_official 0:51ac1d130fd4 938 #endif /* TCP_OUTPUT_DEBUG */
mbed_official 0:51ac1d130fd4 939 #if TCP_CWND_DEBUG
mbed_official 0:51ac1d130fd4 940 if (seg == NULL) {
mbed_official 0:51ac1d130fd4 941 LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F
mbed_official 0:51ac1d130fd4 942 ", cwnd %"U16_F", wnd %"U32_F
mbed_official 0:51ac1d130fd4 943 ", seg == NULL, ack %"U32_F"\n",
mbed_official 0:51ac1d130fd4 944 pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack));
mbed_official 0:51ac1d130fd4 945 } else {
mbed_official 0:51ac1d130fd4 946 LWIP_DEBUGF(TCP_CWND_DEBUG,
mbed_official 0:51ac1d130fd4 947 ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F
mbed_official 0:51ac1d130fd4 948 ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n",
mbed_official 0:51ac1d130fd4 949 pcb->snd_wnd, pcb->cwnd, wnd,
mbed_official 0:51ac1d130fd4 950 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
mbed_official 0:51ac1d130fd4 951 ntohl(seg->tcphdr->seqno), pcb->lastack));
mbed_official 0:51ac1d130fd4 952 }
mbed_official 0:51ac1d130fd4 953 #endif /* TCP_CWND_DEBUG */
mbed_official 0:51ac1d130fd4 954 /* data available and window allows it to be sent? */
mbed_official 0:51ac1d130fd4 955 while (seg != NULL &&
mbed_official 0:51ac1d130fd4 956 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
mbed_official 0:51ac1d130fd4 957 LWIP_ASSERT("RST not expected here!",
mbed_official 0:51ac1d130fd4 958 (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0);
mbed_official 0:51ac1d130fd4 959 /* Stop sending if the nagle algorithm would prevent it
mbed_official 0:51ac1d130fd4 960 * Don't stop:
mbed_official 0:51ac1d130fd4 961 * - if tcp_write had a memory error before (prevent delayed ACK timeout) or
mbed_official 0:51ac1d130fd4 962 * - if FIN was already enqueued for this PCB (SYN is always alone in a segment -
mbed_official 0:51ac1d130fd4 963 * either seg->next != NULL or pcb->unacked == NULL;
mbed_official 0:51ac1d130fd4 964 * RST is no sent using tcp_write/tcp_output.
mbed_official 0:51ac1d130fd4 965 */
mbed_official 0:51ac1d130fd4 966 if((tcp_do_output_nagle(pcb) == 0) &&
mbed_official 0:51ac1d130fd4 967 ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)){
mbed_official 0:51ac1d130fd4 968 break;
mbed_official 0:51ac1d130fd4 969 }
mbed_official 0:51ac1d130fd4 970 #if TCP_CWND_DEBUG
mbed_official 0:51ac1d130fd4 971 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",
mbed_official 0:51ac1d130fd4 972 pcb->snd_wnd, pcb->cwnd, wnd,
mbed_official 0:51ac1d130fd4 973 ntohl(seg->tcphdr->seqno) + seg->len -
mbed_official 0:51ac1d130fd4 974 pcb->lastack,
mbed_official 0:51ac1d130fd4 975 ntohl(seg->tcphdr->seqno), pcb->lastack, i));
mbed_official 0:51ac1d130fd4 976 ++i;
mbed_official 0:51ac1d130fd4 977 #endif /* TCP_CWND_DEBUG */
mbed_official 0:51ac1d130fd4 978
mbed_official 0:51ac1d130fd4 979 pcb->unsent = seg->next;
mbed_official 0:51ac1d130fd4 980
mbed_official 0:51ac1d130fd4 981 if (pcb->state != SYN_SENT) {
mbed_official 0:51ac1d130fd4 982 TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);
mbed_official 0:51ac1d130fd4 983 pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
mbed_official 0:51ac1d130fd4 984 }
mbed_official 0:51ac1d130fd4 985
mbed_official 0:51ac1d130fd4 986 tcp_output_segment(seg, pcb);
mbed_official 0:51ac1d130fd4 987 snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
mbed_official 0:51ac1d130fd4 988 if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) {
mbed_official 0:51ac1d130fd4 989 pcb->snd_nxt = snd_nxt;
mbed_official 0:51ac1d130fd4 990 }
mbed_official 0:51ac1d130fd4 991 /* put segment on unacknowledged list if length > 0 */
mbed_official 0:51ac1d130fd4 992 if (TCP_TCPLEN(seg) > 0) {
mbed_official 0:51ac1d130fd4 993 seg->next = NULL;
mbed_official 0:51ac1d130fd4 994 /* unacked list is empty? */
mbed_official 0:51ac1d130fd4 995 if (pcb->unacked == NULL) {
mbed_official 0:51ac1d130fd4 996 pcb->unacked = seg;
mbed_official 0:51ac1d130fd4 997 useg = seg;
mbed_official 0:51ac1d130fd4 998 /* unacked list is not empty? */
mbed_official 0:51ac1d130fd4 999 } else {
mbed_official 0:51ac1d130fd4 1000 /* In the case of fast retransmit, the packet should not go to the tail
mbed_official 0:51ac1d130fd4 1001 * of the unacked queue, but rather somewhere before it. We need to check for
mbed_official 0:51ac1d130fd4 1002 * this case. -STJ Jul 27, 2004 */
mbed_official 0:51ac1d130fd4 1003 if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))) {
mbed_official 0:51ac1d130fd4 1004 /* add segment to before tail of unacked list, keeping the list sorted */
mbed_official 0:51ac1d130fd4 1005 struct tcp_seg **cur_seg = &(pcb->unacked);
mbed_official 0:51ac1d130fd4 1006 while (*cur_seg &&
mbed_official 0:51ac1d130fd4 1007 TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) {
mbed_official 0:51ac1d130fd4 1008 cur_seg = &((*cur_seg)->next );
mbed_official 0:51ac1d130fd4 1009 }
mbed_official 0:51ac1d130fd4 1010 seg->next = (*cur_seg);
mbed_official 0:51ac1d130fd4 1011 (*cur_seg) = seg;
mbed_official 0:51ac1d130fd4 1012 } else {
mbed_official 0:51ac1d130fd4 1013 /* add segment to tail of unacked list */
mbed_official 0:51ac1d130fd4 1014 useg->next = seg;
mbed_official 0:51ac1d130fd4 1015 useg = useg->next;
mbed_official 0:51ac1d130fd4 1016 }
mbed_official 0:51ac1d130fd4 1017 }
mbed_official 0:51ac1d130fd4 1018 /* do not queue empty segments on the unacked list */
mbed_official 0:51ac1d130fd4 1019 } else {
mbed_official 0:51ac1d130fd4 1020 tcp_seg_free(seg);
mbed_official 0:51ac1d130fd4 1021 }
mbed_official 0:51ac1d130fd4 1022 seg = pcb->unsent;
mbed_official 0:51ac1d130fd4 1023 }
mbed_official 0:51ac1d130fd4 1024 #if TCP_OVERSIZE
mbed_official 0:51ac1d130fd4 1025 if (pcb->unsent == NULL) {
mbed_official 0:51ac1d130fd4 1026 /* last unsent has been removed, reset unsent_oversize */
mbed_official 0:51ac1d130fd4 1027 pcb->unsent_oversize = 0;
mbed_official 0:51ac1d130fd4 1028 }
mbed_official 0:51ac1d130fd4 1029 #endif /* TCP_OVERSIZE */
mbed_official 0:51ac1d130fd4 1030
mbed_official 0:51ac1d130fd4 1031 if (seg != NULL && pcb->persist_backoff == 0 &&
mbed_official 0:51ac1d130fd4 1032 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) {
mbed_official 0:51ac1d130fd4 1033 /* prepare for persist timer */
mbed_official 0:51ac1d130fd4 1034 pcb->persist_cnt = 0;
mbed_official 0:51ac1d130fd4 1035 pcb->persist_backoff = 1;
mbed_official 0:51ac1d130fd4 1036 }
mbed_official 0:51ac1d130fd4 1037
mbed_official 0:51ac1d130fd4 1038 pcb->flags &= ~TF_NAGLEMEMERR;
mbed_official 0:51ac1d130fd4 1039 return ERR_OK;
mbed_official 0:51ac1d130fd4 1040 }
mbed_official 0:51ac1d130fd4 1041
mbed_official 0:51ac1d130fd4 1042 /**
mbed_official 0:51ac1d130fd4 1043 * Called by tcp_output() to actually send a TCP segment over IP.
mbed_official 0:51ac1d130fd4 1044 *
mbed_official 0:51ac1d130fd4 1045 * @param seg the tcp_seg to send
mbed_official 0:51ac1d130fd4 1046 * @param pcb the tcp_pcb for the TCP connection used to send the segment
mbed_official 0:51ac1d130fd4 1047 */
mbed_official 0:51ac1d130fd4 1048 static void
mbed_official 0:51ac1d130fd4 1049 tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
mbed_official 0:51ac1d130fd4 1050 {
mbed_official 0:51ac1d130fd4 1051 u16_t len;
mbed_official 0:51ac1d130fd4 1052 struct netif *netif;
mbed_official 0:51ac1d130fd4 1053 u32_t *opts;
mbed_official 0:51ac1d130fd4 1054
mbed_official 0:51ac1d130fd4 1055 /** @bug Exclude retransmitted segments from this count. */
mbed_official 0:51ac1d130fd4 1056 snmp_inc_tcpoutsegs();
mbed_official 0:51ac1d130fd4 1057
mbed_official 0:51ac1d130fd4 1058 /* The TCP header has already been constructed, but the ackno and
mbed_official 0:51ac1d130fd4 1059 wnd fields remain. */
mbed_official 0:51ac1d130fd4 1060 seg->tcphdr->ackno = htonl(pcb->rcv_nxt);
mbed_official 0:51ac1d130fd4 1061
mbed_official 0:51ac1d130fd4 1062 /* advertise our receive window size in this TCP segment */
mbed_official 0:51ac1d130fd4 1063 seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd);
mbed_official 0:51ac1d130fd4 1064
mbed_official 0:51ac1d130fd4 1065 pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
mbed_official 0:51ac1d130fd4 1066
mbed_official 0:51ac1d130fd4 1067 /* Add any requested options. NB MSS option is only set on SYN
mbed_official 0:51ac1d130fd4 1068 packets, so ignore it here */
mbed_official 0:51ac1d130fd4 1069 LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
mbed_official 0:51ac1d130fd4 1070 opts = (u32_t *)(void *)(seg->tcphdr + 1);
mbed_official 0:51ac1d130fd4 1071 if (seg->flags & TF_SEG_OPTS_MSS) {
mbed_official 0:51ac1d130fd4 1072 TCP_BUILD_MSS_OPTION(*opts);
mbed_official 0:51ac1d130fd4 1073 opts += 1;
mbed_official 0:51ac1d130fd4 1074 }
mbed_official 0:51ac1d130fd4 1075 #if LWIP_TCP_TIMESTAMPS
mbed_official 0:51ac1d130fd4 1076 pcb->ts_lastacksent = pcb->rcv_nxt;
mbed_official 0:51ac1d130fd4 1077
mbed_official 0:51ac1d130fd4 1078 if (seg->flags & TF_SEG_OPTS_TS) {
mbed_official 0:51ac1d130fd4 1079 tcp_build_timestamp_option(pcb, opts);
mbed_official 0:51ac1d130fd4 1080 opts += 3;
mbed_official 0:51ac1d130fd4 1081 }
mbed_official 0:51ac1d130fd4 1082 #endif
mbed_official 0:51ac1d130fd4 1083
mbed_official 0:51ac1d130fd4 1084 /* Set retransmission timer running if it is not currently enabled
mbed_official 0:51ac1d130fd4 1085 This must be set before checking the route. */
mbed_official 0:51ac1d130fd4 1086 if (pcb->rtime == -1) {
mbed_official 0:51ac1d130fd4 1087 pcb->rtime = 0;
mbed_official 0:51ac1d130fd4 1088 }
mbed_official 0:51ac1d130fd4 1089
mbed_official 0:51ac1d130fd4 1090 /* If we don't have a local IP address, we get one by
mbed_official 0:51ac1d130fd4 1091 calling ip_route(). */
mbed_official 0:51ac1d130fd4 1092 if (ip_addr_isany(&(pcb->local_ip))) {
mbed_official 0:51ac1d130fd4 1093 netif = ip_route(&(pcb->remote_ip));
mbed_official 0:51ac1d130fd4 1094 if (netif == NULL) {
mbed_official 0:51ac1d130fd4 1095 return;
mbed_official 0:51ac1d130fd4 1096 }
mbed_official 0:51ac1d130fd4 1097 ip_addr_copy(pcb->local_ip, netif->ip_addr);
mbed_official 0:51ac1d130fd4 1098 }
mbed_official 0:51ac1d130fd4 1099
mbed_official 0:51ac1d130fd4 1100 if (pcb->rttest == 0) {
mbed_official 0:51ac1d130fd4 1101 pcb->rttest = tcp_ticks;
mbed_official 0:51ac1d130fd4 1102 pcb->rtseq = ntohl(seg->tcphdr->seqno);
mbed_official 0:51ac1d130fd4 1103
mbed_official 0:51ac1d130fd4 1104 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq));
mbed_official 0:51ac1d130fd4 1105 }
mbed_official 0:51ac1d130fd4 1106 LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n",
mbed_official 0:51ac1d130fd4 1107 htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +
mbed_official 0:51ac1d130fd4 1108 seg->len));
mbed_official 0:51ac1d130fd4 1109
mbed_official 0:51ac1d130fd4 1110 len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);
mbed_official 0:51ac1d130fd4 1111
mbed_official 0:51ac1d130fd4 1112 seg->p->len -= len;
mbed_official 0:51ac1d130fd4 1113 seg->p->tot_len -= len;
mbed_official 0:51ac1d130fd4 1114
mbed_official 0:51ac1d130fd4 1115 seg->p->payload = seg->tcphdr;
mbed_official 0:51ac1d130fd4 1116
mbed_official 0:51ac1d130fd4 1117 seg->tcphdr->chksum = 0;
mbed_official 0:51ac1d130fd4 1118 #if CHECKSUM_GEN_TCP
mbed_official 0:51ac1d130fd4 1119 #if TCP_CHECKSUM_ON_COPY
mbed_official 0:51ac1d130fd4 1120 {
mbed_official 0:51ac1d130fd4 1121 u32_t acc;
mbed_official 0:51ac1d130fd4 1122 #if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
mbed_official 0:51ac1d130fd4 1123 u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
mbed_official 0:51ac1d130fd4 1124 &(pcb->remote_ip),
mbed_official 0:51ac1d130fd4 1125 IP_PROTO_TCP, seg->p->tot_len);
mbed_official 0:51ac1d130fd4 1126 #endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
mbed_official 0:51ac1d130fd4 1127 if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) {
mbed_official 0:51ac1d130fd4 1128 LWIP_ASSERT("data included but not checksummed",
mbed_official 0:51ac1d130fd4 1129 seg->p->tot_len == (TCPH_HDRLEN(seg->tcphdr) * 4));
mbed_official 0:51ac1d130fd4 1130 }
mbed_official 0:51ac1d130fd4 1131
mbed_official 0:51ac1d130fd4 1132 /* rebuild TCP header checksum (TCP header changes for retransmissions!) */
mbed_official 0:51ac1d130fd4 1133 acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip),
mbed_official 0:51ac1d130fd4 1134 &(pcb->remote_ip),
mbed_official 0:51ac1d130fd4 1135 IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);
mbed_official 0:51ac1d130fd4 1136 /* add payload checksum */
mbed_official 0:51ac1d130fd4 1137 if (seg->chksum_swapped) {
mbed_official 0:51ac1d130fd4 1138 seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum);
mbed_official 0:51ac1d130fd4 1139 seg->chksum_swapped = 0;
mbed_official 0:51ac1d130fd4 1140 }
mbed_official 0:51ac1d130fd4 1141 acc += (u16_t)~(seg->chksum);
mbed_official 0:51ac1d130fd4 1142 seg->tcphdr->chksum = FOLD_U32T(acc);
mbed_official 0:51ac1d130fd4 1143 #if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
mbed_official 0:51ac1d130fd4 1144 if (chksum_slow != seg->tcphdr->chksum) {
mbed_official 0:51ac1d130fd4 1145 LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING,
mbed_official 0:51ac1d130fd4 1146 ("tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"\n",
mbed_official 0:51ac1d130fd4 1147 seg->tcphdr->chksum, chksum_slow));
mbed_official 0:51ac1d130fd4 1148 seg->tcphdr->chksum = chksum_slow;
mbed_official 0:51ac1d130fd4 1149 }
mbed_official 0:51ac1d130fd4 1150 #endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
mbed_official 0:51ac1d130fd4 1151 }
mbed_official 0:51ac1d130fd4 1152 #else /* TCP_CHECKSUM_ON_COPY */
mbed_official 0:51ac1d130fd4 1153 seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
mbed_official 0:51ac1d130fd4 1154 &(pcb->remote_ip),
mbed_official 0:51ac1d130fd4 1155 IP_PROTO_TCP, seg->p->tot_len);
mbed_official 0:51ac1d130fd4 1156 #endif /* TCP_CHECKSUM_ON_COPY */
mbed_official 0:51ac1d130fd4 1157 #endif /* CHECKSUM_GEN_TCP */
mbed_official 0:51ac1d130fd4 1158 TCP_STATS_INC(tcp.xmit);
mbed_official 0:51ac1d130fd4 1159
mbed_official 0:51ac1d130fd4 1160 #if LWIP_NETIF_HWADDRHINT
mbed_official 0:51ac1d130fd4 1161 ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
mbed_official 0:51ac1d130fd4 1162 IP_PROTO_TCP, &(pcb->addr_hint));
mbed_official 0:51ac1d130fd4 1163 #else /* LWIP_NETIF_HWADDRHINT*/
mbed_official 0:51ac1d130fd4 1164 ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
mbed_official 0:51ac1d130fd4 1165 IP_PROTO_TCP);
mbed_official 0:51ac1d130fd4 1166 #endif /* LWIP_NETIF_HWADDRHINT*/
mbed_official 0:51ac1d130fd4 1167 }
mbed_official 0:51ac1d130fd4 1168
mbed_official 0:51ac1d130fd4 1169 /**
mbed_official 0:51ac1d130fd4 1170 * Send a TCP RESET packet (empty segment with RST flag set) either to
mbed_official 0:51ac1d130fd4 1171 * abort a connection or to show that there is no matching local connection
mbed_official 0:51ac1d130fd4 1172 * for a received segment.
mbed_official 0:51ac1d130fd4 1173 *
mbed_official 0:51ac1d130fd4 1174 * Called by tcp_abort() (to abort a local connection), tcp_input() (if no
mbed_official 0:51ac1d130fd4 1175 * matching local pcb was found), tcp_listen_input() (if incoming segment
mbed_official 0:51ac1d130fd4 1176 * has ACK flag set) and tcp_process() (received segment in the wrong state)
mbed_official 0:51ac1d130fd4 1177 *
mbed_official 0:51ac1d130fd4 1178 * Since a RST segment is in most cases not sent for an active connection,
mbed_official 0:51ac1d130fd4 1179 * tcp_rst() has a number of arguments that are taken from a tcp_pcb for
mbed_official 0:51ac1d130fd4 1180 * most other segment output functions.
mbed_official 0:51ac1d130fd4 1181 *
mbed_official 0:51ac1d130fd4 1182 * @param seqno the sequence number to use for the outgoing segment
mbed_official 0:51ac1d130fd4 1183 * @param ackno the acknowledge number to use for the outgoing segment
mbed_official 0:51ac1d130fd4 1184 * @param local_ip the local IP address to send the segment from
mbed_official 0:51ac1d130fd4 1185 * @param remote_ip the remote IP address to send the segment to
mbed_official 0:51ac1d130fd4 1186 * @param local_port the local TCP port to send the segment from
mbed_official 0:51ac1d130fd4 1187 * @param remote_port the remote TCP port to send the segment to
mbed_official 0:51ac1d130fd4 1188 */
mbed_official 0:51ac1d130fd4 1189 void
mbed_official 0:51ac1d130fd4 1190 tcp_rst(u32_t seqno, u32_t ackno,
mbed_official 0:51ac1d130fd4 1191 ip_addr_t *local_ip, ip_addr_t *remote_ip,
mbed_official 0:51ac1d130fd4 1192 u16_t local_port, u16_t remote_port)
mbed_official 0:51ac1d130fd4 1193 {
mbed_official 0:51ac1d130fd4 1194 struct pbuf *p;
mbed_official 0:51ac1d130fd4 1195 struct tcp_hdr *tcphdr;
mbed_official 0:51ac1d130fd4 1196 p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
mbed_official 0:51ac1d130fd4 1197 if (p == NULL) {
mbed_official 0:51ac1d130fd4 1198 LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));
mbed_official 0:51ac1d130fd4 1199 return;
mbed_official 0:51ac1d130fd4 1200 }
mbed_official 0:51ac1d130fd4 1201 LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
mbed_official 0:51ac1d130fd4 1202 (p->len >= sizeof(struct tcp_hdr)));
mbed_official 0:51ac1d130fd4 1203
mbed_official 0:51ac1d130fd4 1204 tcphdr = (struct tcp_hdr *)p->payload;
mbed_official 0:51ac1d130fd4 1205 tcphdr->src = htons(local_port);
mbed_official 0:51ac1d130fd4 1206 tcphdr->dest = htons(remote_port);
mbed_official 0:51ac1d130fd4 1207 tcphdr->seqno = htonl(seqno);
mbed_official 0:51ac1d130fd4 1208 tcphdr->ackno = htonl(ackno);
mbed_official 0:51ac1d130fd4 1209 TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK);
mbed_official 0:51ac1d130fd4 1210 tcphdr->wnd = PP_HTONS(TCP_WND);
mbed_official 0:51ac1d130fd4 1211 tcphdr->chksum = 0;
mbed_official 0:51ac1d130fd4 1212 tcphdr->urgp = 0;
mbed_official 0:51ac1d130fd4 1213
mbed_official 0:51ac1d130fd4 1214 #if CHECKSUM_GEN_TCP
mbed_official 0:51ac1d130fd4 1215 tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,
mbed_official 0:51ac1d130fd4 1216 IP_PROTO_TCP, p->tot_len);
mbed_official 0:51ac1d130fd4 1217 #endif
mbed_official 0:51ac1d130fd4 1218 TCP_STATS_INC(tcp.xmit);
mbed_official 0:51ac1d130fd4 1219 snmp_inc_tcpoutrsts();
mbed_official 0:51ac1d130fd4 1220 /* Send output with hardcoded TTL since we have no access to the pcb */
mbed_official 0:51ac1d130fd4 1221 ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);
mbed_official 0:51ac1d130fd4 1222 pbuf_free(p);
mbed_official 0:51ac1d130fd4 1223 LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));
mbed_official 0:51ac1d130fd4 1224 }
mbed_official 0:51ac1d130fd4 1225
mbed_official 0:51ac1d130fd4 1226 /**
mbed_official 0:51ac1d130fd4 1227 * Requeue all unacked segments for retransmission
mbed_official 0:51ac1d130fd4 1228 *
mbed_official 0:51ac1d130fd4 1229 * Called by tcp_slowtmr() for slow retransmission.
mbed_official 0:51ac1d130fd4 1230 *
mbed_official 0:51ac1d130fd4 1231 * @param pcb the tcp_pcb for which to re-enqueue all unacked segments
mbed_official 0:51ac1d130fd4 1232 */
mbed_official 0:51ac1d130fd4 1233 void
mbed_official 0:51ac1d130fd4 1234 tcp_rexmit_rto(struct tcp_pcb *pcb)
mbed_official 0:51ac1d130fd4 1235 {
mbed_official 0:51ac1d130fd4 1236 struct tcp_seg *seg;
mbed_official 0:51ac1d130fd4 1237
mbed_official 0:51ac1d130fd4 1238 if (pcb->unacked == NULL) {
mbed_official 0:51ac1d130fd4 1239 return;
mbed_official 0:51ac1d130fd4 1240 }
mbed_official 0:51ac1d130fd4 1241
mbed_official 0:51ac1d130fd4 1242 /* Move all unacked segments to the head of the unsent queue */
mbed_official 0:51ac1d130fd4 1243 for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
mbed_official 0:51ac1d130fd4 1244 /* concatenate unsent queue after unacked queue */
mbed_official 0:51ac1d130fd4 1245 seg->next = pcb->unsent;
mbed_official 0:51ac1d130fd4 1246 /* unsent queue is the concatenated queue (of unacked, unsent) */
mbed_official 0:51ac1d130fd4 1247 pcb->unsent = pcb->unacked;
mbed_official 0:51ac1d130fd4 1248 /* unacked queue is now empty */
mbed_official 0:51ac1d130fd4 1249 pcb->unacked = NULL;
mbed_official 0:51ac1d130fd4 1250
mbed_official 0:51ac1d130fd4 1251 /* increment number of retransmissions */
mbed_official 0:51ac1d130fd4 1252 ++pcb->nrtx;
mbed_official 0:51ac1d130fd4 1253
mbed_official 0:51ac1d130fd4 1254 /* Don't take any RTT measurements after retransmitting. */
mbed_official 0:51ac1d130fd4 1255 pcb->rttest = 0;
mbed_official 0:51ac1d130fd4 1256
mbed_official 0:51ac1d130fd4 1257 /* Do the actual retransmission */
mbed_official 0:51ac1d130fd4 1258 tcp_output(pcb);
mbed_official 0:51ac1d130fd4 1259 }
mbed_official 0:51ac1d130fd4 1260
mbed_official 0:51ac1d130fd4 1261 /**
mbed_official 0:51ac1d130fd4 1262 * Requeue the first unacked segment for retransmission
mbed_official 0:51ac1d130fd4 1263 *
mbed_official 0:51ac1d130fd4 1264 * Called by tcp_receive() for fast retramsmit.
mbed_official 0:51ac1d130fd4 1265 *
mbed_official 0:51ac1d130fd4 1266 * @param pcb the tcp_pcb for which to retransmit the first unacked segment
mbed_official 0:51ac1d130fd4 1267 */
mbed_official 0:51ac1d130fd4 1268 void
mbed_official 0:51ac1d130fd4 1269 tcp_rexmit(struct tcp_pcb *pcb)
mbed_official 0:51ac1d130fd4 1270 {
mbed_official 0:51ac1d130fd4 1271 struct tcp_seg *seg;
mbed_official 0:51ac1d130fd4 1272 struct tcp_seg **cur_seg;
mbed_official 0:51ac1d130fd4 1273
mbed_official 0:51ac1d130fd4 1274 if (pcb->unacked == NULL) {
mbed_official 0:51ac1d130fd4 1275 return;
mbed_official 0:51ac1d130fd4 1276 }
mbed_official 0:51ac1d130fd4 1277
mbed_official 0:51ac1d130fd4 1278 /* Move the first unacked segment to the unsent queue */
mbed_official 0:51ac1d130fd4 1279 /* Keep the unsent queue sorted. */
mbed_official 0:51ac1d130fd4 1280 seg = pcb->unacked;
mbed_official 0:51ac1d130fd4 1281 pcb->unacked = seg->next;
mbed_official 0:51ac1d130fd4 1282
mbed_official 0:51ac1d130fd4 1283 cur_seg = &(pcb->unsent);
mbed_official 0:51ac1d130fd4 1284 while (*cur_seg &&
mbed_official 0:51ac1d130fd4 1285 TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) {
mbed_official 0:51ac1d130fd4 1286 cur_seg = &((*cur_seg)->next );
mbed_official 0:51ac1d130fd4 1287 }
mbed_official 0:51ac1d130fd4 1288 seg->next = *cur_seg;
mbed_official 0:51ac1d130fd4 1289 *cur_seg = seg;
mbed_official 0:51ac1d130fd4 1290
mbed_official 0:51ac1d130fd4 1291 ++pcb->nrtx;
mbed_official 0:51ac1d130fd4 1292
mbed_official 0:51ac1d130fd4 1293 /* Don't take any rtt measurements after retransmitting. */
mbed_official 0:51ac1d130fd4 1294 pcb->rttest = 0;
mbed_official 0:51ac1d130fd4 1295
mbed_official 0:51ac1d130fd4 1296 /* Do the actual retransmission. */
mbed_official 0:51ac1d130fd4 1297 snmp_inc_tcpretranssegs();
mbed_official 0:51ac1d130fd4 1298 /* No need to call tcp_output: we are always called from tcp_input()
mbed_official 0:51ac1d130fd4 1299 and thus tcp_output directly returns. */
mbed_official 0:51ac1d130fd4 1300 }
mbed_official 0:51ac1d130fd4 1301
mbed_official 0:51ac1d130fd4 1302
mbed_official 0:51ac1d130fd4 1303 /**
mbed_official 0:51ac1d130fd4 1304 * Handle retransmission after three dupacks received
mbed_official 0:51ac1d130fd4 1305 *
mbed_official 0:51ac1d130fd4 1306 * @param pcb the tcp_pcb for which to retransmit the first unacked segment
mbed_official 0:51ac1d130fd4 1307 */
mbed_official 0:51ac1d130fd4 1308 void
mbed_official 0:51ac1d130fd4 1309 tcp_rexmit_fast(struct tcp_pcb *pcb)
mbed_official 0:51ac1d130fd4 1310 {
mbed_official 0:51ac1d130fd4 1311 if (pcb->unacked != NULL && !(pcb->flags & TF_INFR)) {
mbed_official 0:51ac1d130fd4 1312 /* This is fast retransmit. Retransmit the first unacked segment. */
mbed_official 0:51ac1d130fd4 1313 LWIP_DEBUGF(TCP_FR_DEBUG,
mbed_official 0:51ac1d130fd4 1314 ("tcp_receive: dupacks %"U16_F" (%"U32_F
mbed_official 0:51ac1d130fd4 1315 "), fast retransmit %"U32_F"\n",
mbed_official 0:51ac1d130fd4 1316 (u16_t)pcb->dupacks, pcb->lastack,
mbed_official 0:51ac1d130fd4 1317 ntohl(pcb->unacked->tcphdr->seqno)));
mbed_official 0:51ac1d130fd4 1318 tcp_rexmit(pcb);
mbed_official 0:51ac1d130fd4 1319
mbed_official 0:51ac1d130fd4 1320 /* Set ssthresh to half of the minimum of the current
mbed_official 0:51ac1d130fd4 1321 * cwnd and the advertised window */
mbed_official 0:51ac1d130fd4 1322 if (pcb->cwnd > pcb->snd_wnd) {
mbed_official 0:51ac1d130fd4 1323 pcb->ssthresh = pcb->snd_wnd / 2;
mbed_official 0:51ac1d130fd4 1324 } else {
mbed_official 0:51ac1d130fd4 1325 pcb->ssthresh = pcb->cwnd / 2;
mbed_official 0:51ac1d130fd4 1326 }
mbed_official 0:51ac1d130fd4 1327
mbed_official 0:51ac1d130fd4 1328 /* The minimum value for ssthresh should be 2 MSS */
mbed_official 0:51ac1d130fd4 1329 if (pcb->ssthresh < 2*pcb->mss) {
mbed_official 0:51ac1d130fd4 1330 LWIP_DEBUGF(TCP_FR_DEBUG,
mbed_official 0:51ac1d130fd4 1331 ("tcp_receive: The minimum value for ssthresh %"U16_F
mbed_official 0:51ac1d130fd4 1332 " should be min 2 mss %"U16_F"...\n",
mbed_official 0:51ac1d130fd4 1333 pcb->ssthresh, 2*pcb->mss));
mbed_official 0:51ac1d130fd4 1334 pcb->ssthresh = 2*pcb->mss;
mbed_official 0:51ac1d130fd4 1335 }
mbed_official 0:51ac1d130fd4 1336
mbed_official 0:51ac1d130fd4 1337 pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
mbed_official 0:51ac1d130fd4 1338 pcb->flags |= TF_INFR;
mbed_official 0:51ac1d130fd4 1339 }
mbed_official 0:51ac1d130fd4 1340 }
mbed_official 0:51ac1d130fd4 1341
mbed_official 0:51ac1d130fd4 1342
mbed_official 0:51ac1d130fd4 1343 /**
mbed_official 0:51ac1d130fd4 1344 * Send keepalive packets to keep a connection active although
mbed_official 0:51ac1d130fd4 1345 * no data is sent over it.
mbed_official 0:51ac1d130fd4 1346 *
mbed_official 0:51ac1d130fd4 1347 * Called by tcp_slowtmr()
mbed_official 0:51ac1d130fd4 1348 *
mbed_official 0:51ac1d130fd4 1349 * @param pcb the tcp_pcb for which to send a keepalive packet
mbed_official 0:51ac1d130fd4 1350 */
mbed_official 0:51ac1d130fd4 1351 void
mbed_official 0:51ac1d130fd4 1352 tcp_keepalive(struct tcp_pcb *pcb)
mbed_official 0:51ac1d130fd4 1353 {
mbed_official 0:51ac1d130fd4 1354 struct pbuf *p;
mbed_official 0:51ac1d130fd4 1355 struct tcp_hdr *tcphdr;
mbed_official 0:51ac1d130fd4 1356
mbed_official 0:51ac1d130fd4 1357 LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
mbed_official 0:51ac1d130fd4 1358 ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
mbed_official 0:51ac1d130fd4 1359 ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
mbed_official 0:51ac1d130fd4 1360
mbed_official 0:51ac1d130fd4 1361 LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",
mbed_official 0:51ac1d130fd4 1362 tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
mbed_official 0:51ac1d130fd4 1363
mbed_official 0:51ac1d130fd4 1364 p = tcp_output_alloc_header(pcb, 0, 0, htonl(pcb->snd_nxt - 1));
mbed_official 0:51ac1d130fd4 1365 if(p == NULL) {
mbed_official 0:51ac1d130fd4 1366 LWIP_DEBUGF(TCP_DEBUG,
mbed_official 0:51ac1d130fd4 1367 ("tcp_keepalive: could not allocate memory for pbuf\n"));
mbed_official 0:51ac1d130fd4 1368 return;
mbed_official 0:51ac1d130fd4 1369 }
mbed_official 0:51ac1d130fd4 1370 tcphdr = (struct tcp_hdr *)p->payload;
mbed_official 0:51ac1d130fd4 1371
mbed_official 0:51ac1d130fd4 1372 #if CHECKSUM_GEN_TCP
mbed_official 0:51ac1d130fd4 1373 tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
mbed_official 0:51ac1d130fd4 1374 IP_PROTO_TCP, p->tot_len);
mbed_official 0:51ac1d130fd4 1375 #endif
mbed_official 0:51ac1d130fd4 1376 TCP_STATS_INC(tcp.xmit);
mbed_official 0:51ac1d130fd4 1377
mbed_official 0:51ac1d130fd4 1378 /* Send output to IP */
mbed_official 0:51ac1d130fd4 1379 #if LWIP_NETIF_HWADDRHINT
mbed_official 0:51ac1d130fd4 1380 ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
mbed_official 0:51ac1d130fd4 1381 &(pcb->addr_hint));
mbed_official 0:51ac1d130fd4 1382 #else /* LWIP_NETIF_HWADDRHINT*/
mbed_official 0:51ac1d130fd4 1383 ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
mbed_official 0:51ac1d130fd4 1384 #endif /* LWIP_NETIF_HWADDRHINT*/
mbed_official 0:51ac1d130fd4 1385
mbed_official 0:51ac1d130fd4 1386 pbuf_free(p);
mbed_official 0:51ac1d130fd4 1387
mbed_official 0:51ac1d130fd4 1388 LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n",
mbed_official 0:51ac1d130fd4 1389 pcb->snd_nxt - 1, pcb->rcv_nxt));
mbed_official 0:51ac1d130fd4 1390 }
mbed_official 0:51ac1d130fd4 1391
mbed_official 0:51ac1d130fd4 1392
mbed_official 0:51ac1d130fd4 1393 /**
mbed_official 0:51ac1d130fd4 1394 * Send persist timer zero-window probes to keep a connection active
mbed_official 0:51ac1d130fd4 1395 * when a window update is lost.
mbed_official 0:51ac1d130fd4 1396 *
mbed_official 0:51ac1d130fd4 1397 * Called by tcp_slowtmr()
mbed_official 0:51ac1d130fd4 1398 *
mbed_official 0:51ac1d130fd4 1399 * @param pcb the tcp_pcb for which to send a zero-window probe packet
mbed_official 0:51ac1d130fd4 1400 */
mbed_official 0:51ac1d130fd4 1401 void
mbed_official 0:51ac1d130fd4 1402 tcp_zero_window_probe(struct tcp_pcb *pcb)
mbed_official 0:51ac1d130fd4 1403 {
mbed_official 0:51ac1d130fd4 1404 struct pbuf *p;
mbed_official 0:51ac1d130fd4 1405 struct tcp_hdr *tcphdr;
mbed_official 0:51ac1d130fd4 1406 struct tcp_seg *seg;
mbed_official 0:51ac1d130fd4 1407 u16_t len;
mbed_official 0:51ac1d130fd4 1408 u8_t is_fin;
mbed_official 0:51ac1d130fd4 1409
mbed_official 0:51ac1d130fd4 1410 LWIP_DEBUGF(TCP_DEBUG,
mbed_official 0:51ac1d130fd4 1411 ("tcp_zero_window_probe: sending ZERO WINDOW probe to %"
mbed_official 0:51ac1d130fd4 1412 U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
mbed_official 0:51ac1d130fd4 1413 ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
mbed_official 0:51ac1d130fd4 1414 ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
mbed_official 0:51ac1d130fd4 1415
mbed_official 0:51ac1d130fd4 1416 LWIP_DEBUGF(TCP_DEBUG,
mbed_official 0:51ac1d130fd4 1417 ("tcp_zero_window_probe: tcp_ticks %"U32_F
mbed_official 0:51ac1d130fd4 1418 " pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",
mbed_official 0:51ac1d130fd4 1419 tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
mbed_official 0:51ac1d130fd4 1420
mbed_official 0:51ac1d130fd4 1421 seg = pcb->unacked;
mbed_official 0:51ac1d130fd4 1422
mbed_official 0:51ac1d130fd4 1423 if(seg == NULL) {
mbed_official 0:51ac1d130fd4 1424 seg = pcb->unsent;
mbed_official 0:51ac1d130fd4 1425 }
mbed_official 0:51ac1d130fd4 1426 if(seg == NULL) {
mbed_official 0:51ac1d130fd4 1427 return;
mbed_official 0:51ac1d130fd4 1428 }
mbed_official 0:51ac1d130fd4 1429
mbed_official 0:51ac1d130fd4 1430 is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0);
mbed_official 0:51ac1d130fd4 1431 /* we want to send one seqno: either FIN or data (no options) */
mbed_official 0:51ac1d130fd4 1432 len = is_fin ? 0 : 1;
mbed_official 0:51ac1d130fd4 1433
mbed_official 0:51ac1d130fd4 1434 p = tcp_output_alloc_header(pcb, 0, len, seg->tcphdr->seqno);
mbed_official 0:51ac1d130fd4 1435 if(p == NULL) {
mbed_official 0:51ac1d130fd4 1436 LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n"));
mbed_official 0:51ac1d130fd4 1437 return;
mbed_official 0:51ac1d130fd4 1438 }
mbed_official 0:51ac1d130fd4 1439 tcphdr = (struct tcp_hdr *)p->payload;
mbed_official 0:51ac1d130fd4 1440
mbed_official 0:51ac1d130fd4 1441 if (is_fin) {
mbed_official 0:51ac1d130fd4 1442 /* FIN segment, no data */
mbed_official 0:51ac1d130fd4 1443 TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN);
mbed_official 0:51ac1d130fd4 1444 } else {
mbed_official 0:51ac1d130fd4 1445 /* Data segment, copy in one byte from the head of the unacked queue */
mbed_official 0:51ac1d130fd4 1446 struct tcp_hdr *thdr = (struct tcp_hdr *)seg->p->payload;
mbed_official 0:51ac1d130fd4 1447 char *d = ((char *)p->payload + TCP_HLEN);
mbed_official 0:51ac1d130fd4 1448 pbuf_copy_partial(seg->p, d, 1, TCPH_HDRLEN(thdr) * 4);
mbed_official 0:51ac1d130fd4 1449 }
mbed_official 0:51ac1d130fd4 1450
mbed_official 0:51ac1d130fd4 1451 #if CHECKSUM_GEN_TCP
mbed_official 0:51ac1d130fd4 1452 tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
mbed_official 0:51ac1d130fd4 1453 IP_PROTO_TCP, p->tot_len);
mbed_official 0:51ac1d130fd4 1454 #endif
mbed_official 0:51ac1d130fd4 1455 TCP_STATS_INC(tcp.xmit);
mbed_official 0:51ac1d130fd4 1456
mbed_official 0:51ac1d130fd4 1457 /* Send output to IP */
mbed_official 0:51ac1d130fd4 1458 #if LWIP_NETIF_HWADDRHINT
mbed_official 0:51ac1d130fd4 1459 ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
mbed_official 0:51ac1d130fd4 1460 &(pcb->addr_hint));
mbed_official 0:51ac1d130fd4 1461 #else /* LWIP_NETIF_HWADDRHINT*/
mbed_official 0:51ac1d130fd4 1462 ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
mbed_official 0:51ac1d130fd4 1463 #endif /* LWIP_NETIF_HWADDRHINT*/
mbed_official 0:51ac1d130fd4 1464
mbed_official 0:51ac1d130fd4 1465 pbuf_free(p);
mbed_official 0:51ac1d130fd4 1466
mbed_official 0:51ac1d130fd4 1467 LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F
mbed_official 0:51ac1d130fd4 1468 " ackno %"U32_F".\n",
mbed_official 0:51ac1d130fd4 1469 pcb->snd_nxt - 1, pcb->rcv_nxt));
mbed_official 0:51ac1d130fd4 1470 }
mbed_official 0:51ac1d130fd4 1471 #endif /* LWIP_TCP */