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:
Fri Jun 22 09:25:39 2012 +0000
Revision:
0:51ac1d130fd4
Child:
13:8e34c2cbce5d
Initial import from lwip-1.4.0: http://download.savannah.gnu.org/releases/lwip/lwip-1.4.0.zip

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 0:51ac1d130fd4 649 tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum,
mbed_official 0:51ac1d130fd4 650 &last_unsent->chksum_swapped);
mbed_official 0:51ac1d130fd4 651 last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED;
mbed_official 0:51ac1d130fd4 652 }
mbed_official 0:51ac1d130fd4 653 #endif /* TCP_CHECKSUM_ON_COPY */
mbed_official 0:51ac1d130fd4 654 }
mbed_official 0:51ac1d130fd4 655
mbed_official 0:51ac1d130fd4 656 /*
mbed_official 0:51ac1d130fd4 657 * Phase 3: Append queue to pcb->unsent. Queue may be NULL, but that
mbed_official 0:51ac1d130fd4 658 * is harmless
mbed_official 0:51ac1d130fd4 659 */
mbed_official 0:51ac1d130fd4 660 if (last_unsent == NULL) {
mbed_official 0:51ac1d130fd4 661 pcb->unsent = queue;
mbed_official 0:51ac1d130fd4 662 } else {
mbed_official 0:51ac1d130fd4 663 last_unsent->next = queue;
mbed_official 0:51ac1d130fd4 664 }
mbed_official 0:51ac1d130fd4 665
mbed_official 0:51ac1d130fd4 666 /*
mbed_official 0:51ac1d130fd4 667 * Finally update the pcb state.
mbed_official 0:51ac1d130fd4 668 */
mbed_official 0:51ac1d130fd4 669 pcb->snd_lbb += len;
mbed_official 0:51ac1d130fd4 670 pcb->snd_buf -= len;
mbed_official 0:51ac1d130fd4 671 pcb->snd_queuelen = queuelen;
mbed_official 0:51ac1d130fd4 672
mbed_official 0:51ac1d130fd4 673 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: %"S16_F" (after enqueued)\n",
mbed_official 0:51ac1d130fd4 674 pcb->snd_queuelen));
mbed_official 0:51ac1d130fd4 675 if (pcb->snd_queuelen != 0) {
mbed_official 0:51ac1d130fd4 676 LWIP_ASSERT("tcp_write: valid queue length",
mbed_official 0:51ac1d130fd4 677 pcb->unacked != NULL || pcb->unsent != NULL);
mbed_official 0:51ac1d130fd4 678 }
mbed_official 0:51ac1d130fd4 679
mbed_official 0:51ac1d130fd4 680 /* Set the PSH flag in the last segment that we enqueued. */
mbed_official 0:51ac1d130fd4 681 if (seg != NULL && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE)==0)) {
mbed_official 0:51ac1d130fd4 682 TCPH_SET_FLAG(seg->tcphdr, TCP_PSH);
mbed_official 0:51ac1d130fd4 683 }
mbed_official 0:51ac1d130fd4 684
mbed_official 0:51ac1d130fd4 685 return ERR_OK;
mbed_official 0:51ac1d130fd4 686 memerr:
mbed_official 0:51ac1d130fd4 687 pcb->flags |= TF_NAGLEMEMERR;
mbed_official 0:51ac1d130fd4 688 TCP_STATS_INC(tcp.memerr);
mbed_official 0:51ac1d130fd4 689
mbed_official 0:51ac1d130fd4 690 if (concat_p != NULL) {
mbed_official 0:51ac1d130fd4 691 pbuf_free(concat_p);
mbed_official 0:51ac1d130fd4 692 }
mbed_official 0:51ac1d130fd4 693 if (queue != NULL) {
mbed_official 0:51ac1d130fd4 694 tcp_segs_free(queue);
mbed_official 0:51ac1d130fd4 695 }
mbed_official 0:51ac1d130fd4 696 if (pcb->snd_queuelen != 0) {
mbed_official 0:51ac1d130fd4 697 LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL ||
mbed_official 0:51ac1d130fd4 698 pcb->unsent != NULL);
mbed_official 0:51ac1d130fd4 699 }
mbed_official 0:51ac1d130fd4 700 LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_write: %"S16_F" (with mem err)\n", pcb->snd_queuelen));
mbed_official 0:51ac1d130fd4 701 return ERR_MEM;
mbed_official 0:51ac1d130fd4 702 }
mbed_official 0:51ac1d130fd4 703
mbed_official 0:51ac1d130fd4 704 /**
mbed_official 0:51ac1d130fd4 705 * Enqueue TCP options for transmission.
mbed_official 0:51ac1d130fd4 706 *
mbed_official 0:51ac1d130fd4 707 * Called by tcp_connect(), tcp_listen_input(), and tcp_send_ctrl().
mbed_official 0:51ac1d130fd4 708 *
mbed_official 0:51ac1d130fd4 709 * @param pcb Protocol control block for the TCP connection.
mbed_official 0:51ac1d130fd4 710 * @param flags TCP header flags to set in the outgoing segment.
mbed_official 0:51ac1d130fd4 711 * @param optdata pointer to TCP options, or NULL.
mbed_official 0:51ac1d130fd4 712 * @param optlen length of TCP options in bytes.
mbed_official 0:51ac1d130fd4 713 */
mbed_official 0:51ac1d130fd4 714 err_t
mbed_official 0:51ac1d130fd4 715 tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
mbed_official 0:51ac1d130fd4 716 {
mbed_official 0:51ac1d130fd4 717 struct pbuf *p;
mbed_official 0:51ac1d130fd4 718 struct tcp_seg *seg;
mbed_official 0:51ac1d130fd4 719 u8_t optflags = 0;
mbed_official 0:51ac1d130fd4 720 u8_t optlen = 0;
mbed_official 0:51ac1d130fd4 721
mbed_official 0:51ac1d130fd4 722 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen));
mbed_official 0:51ac1d130fd4 723
mbed_official 0:51ac1d130fd4 724 LWIP_ASSERT("tcp_enqueue_flags: need either TCP_SYN or TCP_FIN in flags (programmer violates API)",
mbed_official 0:51ac1d130fd4 725 (flags & (TCP_SYN | TCP_FIN)) != 0);
mbed_official 0:51ac1d130fd4 726
mbed_official 0:51ac1d130fd4 727 /* check for configured max queuelen and possible overflow */
mbed_official 0:51ac1d130fd4 728 if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
mbed_official 0:51ac1d130fd4 729 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: too long queue %"U16_F" (max %"U16_F")\n",
mbed_official 0:51ac1d130fd4 730 pcb->snd_queuelen, TCP_SND_QUEUELEN));
mbed_official 0:51ac1d130fd4 731 TCP_STATS_INC(tcp.memerr);
mbed_official 0:51ac1d130fd4 732 pcb->flags |= TF_NAGLEMEMERR;
mbed_official 0:51ac1d130fd4 733 return ERR_MEM;
mbed_official 0:51ac1d130fd4 734 }
mbed_official 0:51ac1d130fd4 735
mbed_official 0:51ac1d130fd4 736 if (flags & TCP_SYN) {
mbed_official 0:51ac1d130fd4 737 optflags = TF_SEG_OPTS_MSS;
mbed_official 0:51ac1d130fd4 738 }
mbed_official 0:51ac1d130fd4 739 #if LWIP_TCP_TIMESTAMPS
mbed_official 0:51ac1d130fd4 740 if ((pcb->flags & TF_TIMESTAMP)) {
mbed_official 0:51ac1d130fd4 741 optflags |= TF_SEG_OPTS_TS;
mbed_official 0:51ac1d130fd4 742 }
mbed_official 0:51ac1d130fd4 743 #endif /* LWIP_TCP_TIMESTAMPS */
mbed_official 0:51ac1d130fd4 744 optlen = LWIP_TCP_OPT_LENGTH(optflags);
mbed_official 0:51ac1d130fd4 745
mbed_official 0:51ac1d130fd4 746 /* tcp_enqueue_flags is always called with either SYN or FIN in flags.
mbed_official 0:51ac1d130fd4 747 * We need one available snd_buf byte to do that.
mbed_official 0:51ac1d130fd4 748 * This means we can't send FIN while snd_buf==0. A better fix would be to
mbed_official 0:51ac1d130fd4 749 * not include SYN and FIN sequence numbers in the snd_buf count. */
mbed_official 0:51ac1d130fd4 750 if (pcb->snd_buf == 0) {
mbed_official 0:51ac1d130fd4 751 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: no send buffer available\n"));
mbed_official 0:51ac1d130fd4 752 TCP_STATS_INC(tcp.memerr);
mbed_official 0:51ac1d130fd4 753 return ERR_MEM;
mbed_official 0:51ac1d130fd4 754 }
mbed_official 0:51ac1d130fd4 755
mbed_official 0:51ac1d130fd4 756 /* Allocate pbuf with room for TCP header + options */
mbed_official 0:51ac1d130fd4 757 if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
mbed_official 0:51ac1d130fd4 758 pcb->flags |= TF_NAGLEMEMERR;
mbed_official 0:51ac1d130fd4 759 TCP_STATS_INC(tcp.memerr);
mbed_official 0:51ac1d130fd4 760 return ERR_MEM;
mbed_official 0:51ac1d130fd4 761 }
mbed_official 0:51ac1d130fd4 762 LWIP_ASSERT("tcp_enqueue_flags: check that first pbuf can hold optlen",
mbed_official 0:51ac1d130fd4 763 (p->len >= optlen));
mbed_official 0:51ac1d130fd4 764
mbed_official 0:51ac1d130fd4 765 /* Allocate memory for tcp_seg, and fill in fields. */
mbed_official 0:51ac1d130fd4 766 if ((seg = tcp_create_segment(pcb, p, flags, pcb->snd_lbb, optflags)) == NULL) {
mbed_official 0:51ac1d130fd4 767 pcb->flags |= TF_NAGLEMEMERR;
mbed_official 0:51ac1d130fd4 768 TCP_STATS_INC(tcp.memerr);
mbed_official 0:51ac1d130fd4 769 return ERR_MEM;
mbed_official 0:51ac1d130fd4 770 }
mbed_official 0:51ac1d130fd4 771 LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
mbed_official 0:51ac1d130fd4 772 LWIP_ASSERT("tcp_enqueue_flags: invalid segment length", seg->len == 0);
mbed_official 0:51ac1d130fd4 773
mbed_official 0:51ac1d130fd4 774 LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE,
mbed_official 0:51ac1d130fd4 775 ("tcp_enqueue_flags: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n",
mbed_official 0:51ac1d130fd4 776 ntohl(seg->tcphdr->seqno),
mbed_official 0:51ac1d130fd4 777 ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),
mbed_official 0:51ac1d130fd4 778 (u16_t)flags));
mbed_official 0:51ac1d130fd4 779
mbed_official 0:51ac1d130fd4 780 /* Now append seg to pcb->unsent queue */
mbed_official 0:51ac1d130fd4 781 if (pcb->unsent == NULL) {
mbed_official 0:51ac1d130fd4 782 pcb->unsent = seg;
mbed_official 0:51ac1d130fd4 783 } else {
mbed_official 0:51ac1d130fd4 784 struct tcp_seg *useg;
mbed_official 0:51ac1d130fd4 785 for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);
mbed_official 0:51ac1d130fd4 786 useg->next = seg;
mbed_official 0:51ac1d130fd4 787 }
mbed_official 0:51ac1d130fd4 788 #if TCP_OVERSIZE
mbed_official 0:51ac1d130fd4 789 /* The new unsent tail has no space */
mbed_official 0:51ac1d130fd4 790 pcb->unsent_oversize = 0;
mbed_official 0:51ac1d130fd4 791 #endif /* TCP_OVERSIZE */
mbed_official 0:51ac1d130fd4 792
mbed_official 0:51ac1d130fd4 793 /* SYN and FIN bump the sequence number */
mbed_official 0:51ac1d130fd4 794 if ((flags & TCP_SYN) || (flags & TCP_FIN)) {
mbed_official 0:51ac1d130fd4 795 pcb->snd_lbb++;
mbed_official 0:51ac1d130fd4 796 /* optlen does not influence snd_buf */
mbed_official 0:51ac1d130fd4 797 pcb->snd_buf--;
mbed_official 0:51ac1d130fd4 798 }
mbed_official 0:51ac1d130fd4 799 if (flags & TCP_FIN) {
mbed_official 0:51ac1d130fd4 800 pcb->flags |= TF_FIN;
mbed_official 0:51ac1d130fd4 801 }
mbed_official 0:51ac1d130fd4 802
mbed_official 0:51ac1d130fd4 803 /* update number of segments on the queues */
mbed_official 0:51ac1d130fd4 804 pcb->snd_queuelen += pbuf_clen(seg->p);
mbed_official 0:51ac1d130fd4 805 LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: %"S16_F" (after enqueued)\n", pcb->snd_queuelen));
mbed_official 0:51ac1d130fd4 806 if (pcb->snd_queuelen != 0) {
mbed_official 0:51ac1d130fd4 807 LWIP_ASSERT("tcp_enqueue_flags: invalid queue length",
mbed_official 0:51ac1d130fd4 808 pcb->unacked != NULL || pcb->unsent != NULL);
mbed_official 0:51ac1d130fd4 809 }
mbed_official 0:51ac1d130fd4 810
mbed_official 0:51ac1d130fd4 811 return ERR_OK;
mbed_official 0:51ac1d130fd4 812 }
mbed_official 0:51ac1d130fd4 813
mbed_official 0:51ac1d130fd4 814
mbed_official 0:51ac1d130fd4 815 #if LWIP_TCP_TIMESTAMPS
mbed_official 0:51ac1d130fd4 816 /* Build a timestamp option (12 bytes long) at the specified options pointer)
mbed_official 0:51ac1d130fd4 817 *
mbed_official 0:51ac1d130fd4 818 * @param pcb tcp_pcb
mbed_official 0:51ac1d130fd4 819 * @param opts option pointer where to store the timestamp option
mbed_official 0:51ac1d130fd4 820 */
mbed_official 0:51ac1d130fd4 821 static void
mbed_official 0:51ac1d130fd4 822 tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts)
mbed_official 0:51ac1d130fd4 823 {
mbed_official 0:51ac1d130fd4 824 /* Pad with two NOP options to make everything nicely aligned */
mbed_official 0:51ac1d130fd4 825 opts[0] = PP_HTONL(0x0101080A);
mbed_official 0:51ac1d130fd4 826 opts[1] = htonl(sys_now());
mbed_official 0:51ac1d130fd4 827 opts[2] = htonl(pcb->ts_recent);
mbed_official 0:51ac1d130fd4 828 }
mbed_official 0:51ac1d130fd4 829 #endif
mbed_official 0:51ac1d130fd4 830
mbed_official 0:51ac1d130fd4 831 /** Send an ACK without data.
mbed_official 0:51ac1d130fd4 832 *
mbed_official 0:51ac1d130fd4 833 * @param pcb Protocol control block for the TCP connection to send the ACK
mbed_official 0:51ac1d130fd4 834 */
mbed_official 0:51ac1d130fd4 835 err_t
mbed_official 0:51ac1d130fd4 836 tcp_send_empty_ack(struct tcp_pcb *pcb)
mbed_official 0:51ac1d130fd4 837 {
mbed_official 0:51ac1d130fd4 838 struct pbuf *p;
mbed_official 0:51ac1d130fd4 839 struct tcp_hdr *tcphdr;
mbed_official 0:51ac1d130fd4 840 u8_t optlen = 0;
mbed_official 0:51ac1d130fd4 841
mbed_official 0:51ac1d130fd4 842 #if LWIP_TCP_TIMESTAMPS
mbed_official 0:51ac1d130fd4 843 if (pcb->flags & TF_TIMESTAMP) {
mbed_official 0:51ac1d130fd4 844 optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
mbed_official 0:51ac1d130fd4 845 }
mbed_official 0:51ac1d130fd4 846 #endif
mbed_official 0:51ac1d130fd4 847
mbed_official 0:51ac1d130fd4 848 p = tcp_output_alloc_header(pcb, optlen, 0, htonl(pcb->snd_nxt));
mbed_official 0:51ac1d130fd4 849 if (p == NULL) {
mbed_official 0:51ac1d130fd4 850 LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
mbed_official 0:51ac1d130fd4 851 return ERR_BUF;
mbed_official 0:51ac1d130fd4 852 }
mbed_official 0:51ac1d130fd4 853 tcphdr = (struct tcp_hdr *)p->payload;
mbed_official 0:51ac1d130fd4 854 LWIP_DEBUGF(TCP_OUTPUT_DEBUG,
mbed_official 0:51ac1d130fd4 855 ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));
mbed_official 0:51ac1d130fd4 856 /* remove ACK flags from the PCB, as we send an empty ACK now */
mbed_official 0:51ac1d130fd4 857 pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
mbed_official 0:51ac1d130fd4 858
mbed_official 0:51ac1d130fd4 859 /* NB. MSS option is only sent on SYNs, so ignore it here */
mbed_official 0:51ac1d130fd4 860 #if LWIP_TCP_TIMESTAMPS
mbed_official 0:51ac1d130fd4 861 pcb->ts_lastacksent = pcb->rcv_nxt;
mbed_official 0:51ac1d130fd4 862
mbed_official 0:51ac1d130fd4 863 if (pcb->flags & TF_TIMESTAMP) {
mbed_official 0:51ac1d130fd4 864 tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1));
mbed_official 0:51ac1d130fd4 865 }
mbed_official 0:51ac1d130fd4 866 #endif
mbed_official 0:51ac1d130fd4 867
mbed_official 0:51ac1d130fd4 868 #if CHECKSUM_GEN_TCP
mbed_official 0:51ac1d130fd4 869 tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
mbed_official 0:51ac1d130fd4 870 IP_PROTO_TCP, p->tot_len);
mbed_official 0:51ac1d130fd4 871 #endif
mbed_official 0:51ac1d130fd4 872 #if LWIP_NETIF_HWADDRHINT
mbed_official 0:51ac1d130fd4 873 ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
mbed_official 0:51ac1d130fd4 874 IP_PROTO_TCP, &(pcb->addr_hint));
mbed_official 0:51ac1d130fd4 875 #else /* LWIP_NETIF_HWADDRHINT*/
mbed_official 0:51ac1d130fd4 876 ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
mbed_official 0:51ac1d130fd4 877 IP_PROTO_TCP);
mbed_official 0:51ac1d130fd4 878 #endif /* LWIP_NETIF_HWADDRHINT*/
mbed_official 0:51ac1d130fd4 879 pbuf_free(p);
mbed_official 0:51ac1d130fd4 880
mbed_official 0:51ac1d130fd4 881 return ERR_OK;
mbed_official 0:51ac1d130fd4 882 }
mbed_official 0:51ac1d130fd4 883
mbed_official 0:51ac1d130fd4 884 /**
mbed_official 0:51ac1d130fd4 885 * Find out what we can send and send it
mbed_official 0:51ac1d130fd4 886 *
mbed_official 0:51ac1d130fd4 887 * @param pcb Protocol control block for the TCP connection to send data
mbed_official 0:51ac1d130fd4 888 * @return ERR_OK if data has been sent or nothing to send
mbed_official 0:51ac1d130fd4 889 * another err_t on error
mbed_official 0:51ac1d130fd4 890 */
mbed_official 0:51ac1d130fd4 891 err_t
mbed_official 0:51ac1d130fd4 892 tcp_output(struct tcp_pcb *pcb)
mbed_official 0:51ac1d130fd4 893 {
mbed_official 0:51ac1d130fd4 894 struct tcp_seg *seg, *useg;
mbed_official 0:51ac1d130fd4 895 u32_t wnd, snd_nxt;
mbed_official 0:51ac1d130fd4 896 #if TCP_CWND_DEBUG
mbed_official 0:51ac1d130fd4 897 s16_t i = 0;
mbed_official 0:51ac1d130fd4 898 #endif /* TCP_CWND_DEBUG */
mbed_official 0:51ac1d130fd4 899
mbed_official 0:51ac1d130fd4 900 /* First, check if we are invoked by the TCP input processing
mbed_official 0:51ac1d130fd4 901 code. If so, we do not output anything. Instead, we rely on the
mbed_official 0:51ac1d130fd4 902 input processing code to call us when input processing is done
mbed_official 0:51ac1d130fd4 903 with. */
mbed_official 0:51ac1d130fd4 904 if (tcp_input_pcb == pcb) {
mbed_official 0:51ac1d130fd4 905 return ERR_OK;
mbed_official 0:51ac1d130fd4 906 }
mbed_official 0:51ac1d130fd4 907
mbed_official 0:51ac1d130fd4 908 wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);
mbed_official 0:51ac1d130fd4 909
mbed_official 0:51ac1d130fd4 910 seg = pcb->unsent;
mbed_official 0:51ac1d130fd4 911
mbed_official 0:51ac1d130fd4 912 /* If the TF_ACK_NOW flag is set and no data will be sent (either
mbed_official 0:51ac1d130fd4 913 * because the ->unsent queue is empty or because the window does
mbed_official 0:51ac1d130fd4 914 * not allow it), construct an empty ACK segment and send it.
mbed_official 0:51ac1d130fd4 915 *
mbed_official 0:51ac1d130fd4 916 * If data is to be sent, we will just piggyback the ACK (see below).
mbed_official 0:51ac1d130fd4 917 */
mbed_official 0:51ac1d130fd4 918 if (pcb->flags & TF_ACK_NOW &&
mbed_official 0:51ac1d130fd4 919 (seg == NULL ||
mbed_official 0:51ac1d130fd4 920 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
mbed_official 0:51ac1d130fd4 921 return tcp_send_empty_ack(pcb);
mbed_official 0:51ac1d130fd4 922 }
mbed_official 0:51ac1d130fd4 923
mbed_official 0:51ac1d130fd4 924 /* useg should point to last segment on unacked queue */
mbed_official 0:51ac1d130fd4 925 useg = pcb->unacked;
mbed_official 0:51ac1d130fd4 926 if (useg != NULL) {
mbed_official 0:51ac1d130fd4 927 for (; useg->next != NULL; useg = useg->next);
mbed_official 0:51ac1d130fd4 928 }
mbed_official 0:51ac1d130fd4 929
mbed_official 0:51ac1d130fd4 930 #if TCP_OUTPUT_DEBUG
mbed_official 0:51ac1d130fd4 931 if (seg == NULL) {
mbed_official 0:51ac1d130fd4 932 LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n",
mbed_official 0:51ac1d130fd4 933 (void*)pcb->unsent));
mbed_official 0:51ac1d130fd4 934 }
mbed_official 0:51ac1d130fd4 935 #endif /* TCP_OUTPUT_DEBUG */
mbed_official 0:51ac1d130fd4 936 #if TCP_CWND_DEBUG
mbed_official 0:51ac1d130fd4 937 if (seg == NULL) {
mbed_official 0:51ac1d130fd4 938 LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F
mbed_official 0:51ac1d130fd4 939 ", cwnd %"U16_F", wnd %"U32_F
mbed_official 0:51ac1d130fd4 940 ", seg == NULL, ack %"U32_F"\n",
mbed_official 0:51ac1d130fd4 941 pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack));
mbed_official 0:51ac1d130fd4 942 } else {
mbed_official 0:51ac1d130fd4 943 LWIP_DEBUGF(TCP_CWND_DEBUG,
mbed_official 0:51ac1d130fd4 944 ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F
mbed_official 0:51ac1d130fd4 945 ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n",
mbed_official 0:51ac1d130fd4 946 pcb->snd_wnd, pcb->cwnd, wnd,
mbed_official 0:51ac1d130fd4 947 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
mbed_official 0:51ac1d130fd4 948 ntohl(seg->tcphdr->seqno), pcb->lastack));
mbed_official 0:51ac1d130fd4 949 }
mbed_official 0:51ac1d130fd4 950 #endif /* TCP_CWND_DEBUG */
mbed_official 0:51ac1d130fd4 951 /* data available and window allows it to be sent? */
mbed_official 0:51ac1d130fd4 952 while (seg != NULL &&
mbed_official 0:51ac1d130fd4 953 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
mbed_official 0:51ac1d130fd4 954 LWIP_ASSERT("RST not expected here!",
mbed_official 0:51ac1d130fd4 955 (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0);
mbed_official 0:51ac1d130fd4 956 /* Stop sending if the nagle algorithm would prevent it
mbed_official 0:51ac1d130fd4 957 * Don't stop:
mbed_official 0:51ac1d130fd4 958 * - if tcp_write had a memory error before (prevent delayed ACK timeout) or
mbed_official 0:51ac1d130fd4 959 * - if FIN was already enqueued for this PCB (SYN is always alone in a segment -
mbed_official 0:51ac1d130fd4 960 * either seg->next != NULL or pcb->unacked == NULL;
mbed_official 0:51ac1d130fd4 961 * RST is no sent using tcp_write/tcp_output.
mbed_official 0:51ac1d130fd4 962 */
mbed_official 0:51ac1d130fd4 963 if((tcp_do_output_nagle(pcb) == 0) &&
mbed_official 0:51ac1d130fd4 964 ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)){
mbed_official 0:51ac1d130fd4 965 break;
mbed_official 0:51ac1d130fd4 966 }
mbed_official 0:51ac1d130fd4 967 #if TCP_CWND_DEBUG
mbed_official 0:51ac1d130fd4 968 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 969 pcb->snd_wnd, pcb->cwnd, wnd,
mbed_official 0:51ac1d130fd4 970 ntohl(seg->tcphdr->seqno) + seg->len -
mbed_official 0:51ac1d130fd4 971 pcb->lastack,
mbed_official 0:51ac1d130fd4 972 ntohl(seg->tcphdr->seqno), pcb->lastack, i));
mbed_official 0:51ac1d130fd4 973 ++i;
mbed_official 0:51ac1d130fd4 974 #endif /* TCP_CWND_DEBUG */
mbed_official 0:51ac1d130fd4 975
mbed_official 0:51ac1d130fd4 976 pcb->unsent = seg->next;
mbed_official 0:51ac1d130fd4 977
mbed_official 0:51ac1d130fd4 978 if (pcb->state != SYN_SENT) {
mbed_official 0:51ac1d130fd4 979 TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);
mbed_official 0:51ac1d130fd4 980 pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
mbed_official 0:51ac1d130fd4 981 }
mbed_official 0:51ac1d130fd4 982
mbed_official 0:51ac1d130fd4 983 tcp_output_segment(seg, pcb);
mbed_official 0:51ac1d130fd4 984 snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
mbed_official 0:51ac1d130fd4 985 if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) {
mbed_official 0:51ac1d130fd4 986 pcb->snd_nxt = snd_nxt;
mbed_official 0:51ac1d130fd4 987 }
mbed_official 0:51ac1d130fd4 988 /* put segment on unacknowledged list if length > 0 */
mbed_official 0:51ac1d130fd4 989 if (TCP_TCPLEN(seg) > 0) {
mbed_official 0:51ac1d130fd4 990 seg->next = NULL;
mbed_official 0:51ac1d130fd4 991 /* unacked list is empty? */
mbed_official 0:51ac1d130fd4 992 if (pcb->unacked == NULL) {
mbed_official 0:51ac1d130fd4 993 pcb->unacked = seg;
mbed_official 0:51ac1d130fd4 994 useg = seg;
mbed_official 0:51ac1d130fd4 995 /* unacked list is not empty? */
mbed_official 0:51ac1d130fd4 996 } else {
mbed_official 0:51ac1d130fd4 997 /* In the case of fast retransmit, the packet should not go to the tail
mbed_official 0:51ac1d130fd4 998 * of the unacked queue, but rather somewhere before it. We need to check for
mbed_official 0:51ac1d130fd4 999 * this case. -STJ Jul 27, 2004 */
mbed_official 0:51ac1d130fd4 1000 if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))) {
mbed_official 0:51ac1d130fd4 1001 /* add segment to before tail of unacked list, keeping the list sorted */
mbed_official 0:51ac1d130fd4 1002 struct tcp_seg **cur_seg = &(pcb->unacked);
mbed_official 0:51ac1d130fd4 1003 while (*cur_seg &&
mbed_official 0:51ac1d130fd4 1004 TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) {
mbed_official 0:51ac1d130fd4 1005 cur_seg = &((*cur_seg)->next );
mbed_official 0:51ac1d130fd4 1006 }
mbed_official 0:51ac1d130fd4 1007 seg->next = (*cur_seg);
mbed_official 0:51ac1d130fd4 1008 (*cur_seg) = seg;
mbed_official 0:51ac1d130fd4 1009 } else {
mbed_official 0:51ac1d130fd4 1010 /* add segment to tail of unacked list */
mbed_official 0:51ac1d130fd4 1011 useg->next = seg;
mbed_official 0:51ac1d130fd4 1012 useg = useg->next;
mbed_official 0:51ac1d130fd4 1013 }
mbed_official 0:51ac1d130fd4 1014 }
mbed_official 0:51ac1d130fd4 1015 /* do not queue empty segments on the unacked list */
mbed_official 0:51ac1d130fd4 1016 } else {
mbed_official 0:51ac1d130fd4 1017 tcp_seg_free(seg);
mbed_official 0:51ac1d130fd4 1018 }
mbed_official 0:51ac1d130fd4 1019 seg = pcb->unsent;
mbed_official 0:51ac1d130fd4 1020 }
mbed_official 0:51ac1d130fd4 1021 #if TCP_OVERSIZE
mbed_official 0:51ac1d130fd4 1022 if (pcb->unsent == NULL) {
mbed_official 0:51ac1d130fd4 1023 /* last unsent has been removed, reset unsent_oversize */
mbed_official 0:51ac1d130fd4 1024 pcb->unsent_oversize = 0;
mbed_official 0:51ac1d130fd4 1025 }
mbed_official 0:51ac1d130fd4 1026 #endif /* TCP_OVERSIZE */
mbed_official 0:51ac1d130fd4 1027
mbed_official 0:51ac1d130fd4 1028 if (seg != NULL && pcb->persist_backoff == 0 &&
mbed_official 0:51ac1d130fd4 1029 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) {
mbed_official 0:51ac1d130fd4 1030 /* prepare for persist timer */
mbed_official 0:51ac1d130fd4 1031 pcb->persist_cnt = 0;
mbed_official 0:51ac1d130fd4 1032 pcb->persist_backoff = 1;
mbed_official 0:51ac1d130fd4 1033 }
mbed_official 0:51ac1d130fd4 1034
mbed_official 0:51ac1d130fd4 1035 pcb->flags &= ~TF_NAGLEMEMERR;
mbed_official 0:51ac1d130fd4 1036 return ERR_OK;
mbed_official 0:51ac1d130fd4 1037 }
mbed_official 0:51ac1d130fd4 1038
mbed_official 0:51ac1d130fd4 1039 /**
mbed_official 0:51ac1d130fd4 1040 * Called by tcp_output() to actually send a TCP segment over IP.
mbed_official 0:51ac1d130fd4 1041 *
mbed_official 0:51ac1d130fd4 1042 * @param seg the tcp_seg to send
mbed_official 0:51ac1d130fd4 1043 * @param pcb the tcp_pcb for the TCP connection used to send the segment
mbed_official 0:51ac1d130fd4 1044 */
mbed_official 0:51ac1d130fd4 1045 static void
mbed_official 0:51ac1d130fd4 1046 tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
mbed_official 0:51ac1d130fd4 1047 {
mbed_official 0:51ac1d130fd4 1048 u16_t len;
mbed_official 0:51ac1d130fd4 1049 struct netif *netif;
mbed_official 0:51ac1d130fd4 1050 u32_t *opts;
mbed_official 0:51ac1d130fd4 1051
mbed_official 0:51ac1d130fd4 1052 /** @bug Exclude retransmitted segments from this count. */
mbed_official 0:51ac1d130fd4 1053 snmp_inc_tcpoutsegs();
mbed_official 0:51ac1d130fd4 1054
mbed_official 0:51ac1d130fd4 1055 /* The TCP header has already been constructed, but the ackno and
mbed_official 0:51ac1d130fd4 1056 wnd fields remain. */
mbed_official 0:51ac1d130fd4 1057 seg->tcphdr->ackno = htonl(pcb->rcv_nxt);
mbed_official 0:51ac1d130fd4 1058
mbed_official 0:51ac1d130fd4 1059 /* advertise our receive window size in this TCP segment */
mbed_official 0:51ac1d130fd4 1060 seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd);
mbed_official 0:51ac1d130fd4 1061
mbed_official 0:51ac1d130fd4 1062 pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
mbed_official 0:51ac1d130fd4 1063
mbed_official 0:51ac1d130fd4 1064 /* Add any requested options. NB MSS option is only set on SYN
mbed_official 0:51ac1d130fd4 1065 packets, so ignore it here */
mbed_official 0:51ac1d130fd4 1066 LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
mbed_official 0:51ac1d130fd4 1067 opts = (u32_t *)(void *)(seg->tcphdr + 1);
mbed_official 0:51ac1d130fd4 1068 if (seg->flags & TF_SEG_OPTS_MSS) {
mbed_official 0:51ac1d130fd4 1069 TCP_BUILD_MSS_OPTION(*opts);
mbed_official 0:51ac1d130fd4 1070 opts += 1;
mbed_official 0:51ac1d130fd4 1071 }
mbed_official 0:51ac1d130fd4 1072 #if LWIP_TCP_TIMESTAMPS
mbed_official 0:51ac1d130fd4 1073 pcb->ts_lastacksent = pcb->rcv_nxt;
mbed_official 0:51ac1d130fd4 1074
mbed_official 0:51ac1d130fd4 1075 if (seg->flags & TF_SEG_OPTS_TS) {
mbed_official 0:51ac1d130fd4 1076 tcp_build_timestamp_option(pcb, opts);
mbed_official 0:51ac1d130fd4 1077 opts += 3;
mbed_official 0:51ac1d130fd4 1078 }
mbed_official 0:51ac1d130fd4 1079 #endif
mbed_official 0:51ac1d130fd4 1080
mbed_official 0:51ac1d130fd4 1081 /* Set retransmission timer running if it is not currently enabled
mbed_official 0:51ac1d130fd4 1082 This must be set before checking the route. */
mbed_official 0:51ac1d130fd4 1083 if (pcb->rtime == -1) {
mbed_official 0:51ac1d130fd4 1084 pcb->rtime = 0;
mbed_official 0:51ac1d130fd4 1085 }
mbed_official 0:51ac1d130fd4 1086
mbed_official 0:51ac1d130fd4 1087 /* If we don't have a local IP address, we get one by
mbed_official 0:51ac1d130fd4 1088 calling ip_route(). */
mbed_official 0:51ac1d130fd4 1089 if (ip_addr_isany(&(pcb->local_ip))) {
mbed_official 0:51ac1d130fd4 1090 netif = ip_route(&(pcb->remote_ip));
mbed_official 0:51ac1d130fd4 1091 if (netif == NULL) {
mbed_official 0:51ac1d130fd4 1092 return;
mbed_official 0:51ac1d130fd4 1093 }
mbed_official 0:51ac1d130fd4 1094 ip_addr_copy(pcb->local_ip, netif->ip_addr);
mbed_official 0:51ac1d130fd4 1095 }
mbed_official 0:51ac1d130fd4 1096
mbed_official 0:51ac1d130fd4 1097 if (pcb->rttest == 0) {
mbed_official 0:51ac1d130fd4 1098 pcb->rttest = tcp_ticks;
mbed_official 0:51ac1d130fd4 1099 pcb->rtseq = ntohl(seg->tcphdr->seqno);
mbed_official 0:51ac1d130fd4 1100
mbed_official 0:51ac1d130fd4 1101 LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq));
mbed_official 0:51ac1d130fd4 1102 }
mbed_official 0:51ac1d130fd4 1103 LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n",
mbed_official 0:51ac1d130fd4 1104 htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +
mbed_official 0:51ac1d130fd4 1105 seg->len));
mbed_official 0:51ac1d130fd4 1106
mbed_official 0:51ac1d130fd4 1107 len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);
mbed_official 0:51ac1d130fd4 1108
mbed_official 0:51ac1d130fd4 1109 seg->p->len -= len;
mbed_official 0:51ac1d130fd4 1110 seg->p->tot_len -= len;
mbed_official 0:51ac1d130fd4 1111
mbed_official 0:51ac1d130fd4 1112 seg->p->payload = seg->tcphdr;
mbed_official 0:51ac1d130fd4 1113
mbed_official 0:51ac1d130fd4 1114 seg->tcphdr->chksum = 0;
mbed_official 0:51ac1d130fd4 1115 #if CHECKSUM_GEN_TCP
mbed_official 0:51ac1d130fd4 1116 #if TCP_CHECKSUM_ON_COPY
mbed_official 0:51ac1d130fd4 1117 {
mbed_official 0:51ac1d130fd4 1118 u32_t acc;
mbed_official 0:51ac1d130fd4 1119 #if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
mbed_official 0:51ac1d130fd4 1120 u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
mbed_official 0:51ac1d130fd4 1121 &(pcb->remote_ip),
mbed_official 0:51ac1d130fd4 1122 IP_PROTO_TCP, seg->p->tot_len);
mbed_official 0:51ac1d130fd4 1123 #endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
mbed_official 0:51ac1d130fd4 1124 if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) {
mbed_official 0:51ac1d130fd4 1125 LWIP_ASSERT("data included but not checksummed",
mbed_official 0:51ac1d130fd4 1126 seg->p->tot_len == (TCPH_HDRLEN(seg->tcphdr) * 4));
mbed_official 0:51ac1d130fd4 1127 }
mbed_official 0:51ac1d130fd4 1128
mbed_official 0:51ac1d130fd4 1129 /* rebuild TCP header checksum (TCP header changes for retransmissions!) */
mbed_official 0:51ac1d130fd4 1130 acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip),
mbed_official 0:51ac1d130fd4 1131 &(pcb->remote_ip),
mbed_official 0:51ac1d130fd4 1132 IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);
mbed_official 0:51ac1d130fd4 1133 /* add payload checksum */
mbed_official 0:51ac1d130fd4 1134 if (seg->chksum_swapped) {
mbed_official 0:51ac1d130fd4 1135 seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum);
mbed_official 0:51ac1d130fd4 1136 seg->chksum_swapped = 0;
mbed_official 0:51ac1d130fd4 1137 }
mbed_official 0:51ac1d130fd4 1138 acc += (u16_t)~(seg->chksum);
mbed_official 0:51ac1d130fd4 1139 seg->tcphdr->chksum = FOLD_U32T(acc);
mbed_official 0:51ac1d130fd4 1140 #if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
mbed_official 0:51ac1d130fd4 1141 if (chksum_slow != seg->tcphdr->chksum) {
mbed_official 0:51ac1d130fd4 1142 LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING,
mbed_official 0:51ac1d130fd4 1143 ("tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"\n",
mbed_official 0:51ac1d130fd4 1144 seg->tcphdr->chksum, chksum_slow));
mbed_official 0:51ac1d130fd4 1145 seg->tcphdr->chksum = chksum_slow;
mbed_official 0:51ac1d130fd4 1146 }
mbed_official 0:51ac1d130fd4 1147 #endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
mbed_official 0:51ac1d130fd4 1148 }
mbed_official 0:51ac1d130fd4 1149 #else /* TCP_CHECKSUM_ON_COPY */
mbed_official 0:51ac1d130fd4 1150 seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
mbed_official 0:51ac1d130fd4 1151 &(pcb->remote_ip),
mbed_official 0:51ac1d130fd4 1152 IP_PROTO_TCP, seg->p->tot_len);
mbed_official 0:51ac1d130fd4 1153 #endif /* TCP_CHECKSUM_ON_COPY */
mbed_official 0:51ac1d130fd4 1154 #endif /* CHECKSUM_GEN_TCP */
mbed_official 0:51ac1d130fd4 1155 TCP_STATS_INC(tcp.xmit);
mbed_official 0:51ac1d130fd4 1156
mbed_official 0:51ac1d130fd4 1157 #if LWIP_NETIF_HWADDRHINT
mbed_official 0:51ac1d130fd4 1158 ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
mbed_official 0:51ac1d130fd4 1159 IP_PROTO_TCP, &(pcb->addr_hint));
mbed_official 0:51ac1d130fd4 1160 #else /* LWIP_NETIF_HWADDRHINT*/
mbed_official 0:51ac1d130fd4 1161 ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
mbed_official 0:51ac1d130fd4 1162 IP_PROTO_TCP);
mbed_official 0:51ac1d130fd4 1163 #endif /* LWIP_NETIF_HWADDRHINT*/
mbed_official 0:51ac1d130fd4 1164 }
mbed_official 0:51ac1d130fd4 1165
mbed_official 0:51ac1d130fd4 1166 /**
mbed_official 0:51ac1d130fd4 1167 * Send a TCP RESET packet (empty segment with RST flag set) either to
mbed_official 0:51ac1d130fd4 1168 * abort a connection or to show that there is no matching local connection
mbed_official 0:51ac1d130fd4 1169 * for a received segment.
mbed_official 0:51ac1d130fd4 1170 *
mbed_official 0:51ac1d130fd4 1171 * Called by tcp_abort() (to abort a local connection), tcp_input() (if no
mbed_official 0:51ac1d130fd4 1172 * matching local pcb was found), tcp_listen_input() (if incoming segment
mbed_official 0:51ac1d130fd4 1173 * has ACK flag set) and tcp_process() (received segment in the wrong state)
mbed_official 0:51ac1d130fd4 1174 *
mbed_official 0:51ac1d130fd4 1175 * Since a RST segment is in most cases not sent for an active connection,
mbed_official 0:51ac1d130fd4 1176 * tcp_rst() has a number of arguments that are taken from a tcp_pcb for
mbed_official 0:51ac1d130fd4 1177 * most other segment output functions.
mbed_official 0:51ac1d130fd4 1178 *
mbed_official 0:51ac1d130fd4 1179 * @param seqno the sequence number to use for the outgoing segment
mbed_official 0:51ac1d130fd4 1180 * @param ackno the acknowledge number to use for the outgoing segment
mbed_official 0:51ac1d130fd4 1181 * @param local_ip the local IP address to send the segment from
mbed_official 0:51ac1d130fd4 1182 * @param remote_ip the remote IP address to send the segment to
mbed_official 0:51ac1d130fd4 1183 * @param local_port the local TCP port to send the segment from
mbed_official 0:51ac1d130fd4 1184 * @param remote_port the remote TCP port to send the segment to
mbed_official 0:51ac1d130fd4 1185 */
mbed_official 0:51ac1d130fd4 1186 void
mbed_official 0:51ac1d130fd4 1187 tcp_rst(u32_t seqno, u32_t ackno,
mbed_official 0:51ac1d130fd4 1188 ip_addr_t *local_ip, ip_addr_t *remote_ip,
mbed_official 0:51ac1d130fd4 1189 u16_t local_port, u16_t remote_port)
mbed_official 0:51ac1d130fd4 1190 {
mbed_official 0:51ac1d130fd4 1191 struct pbuf *p;
mbed_official 0:51ac1d130fd4 1192 struct tcp_hdr *tcphdr;
mbed_official 0:51ac1d130fd4 1193 p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
mbed_official 0:51ac1d130fd4 1194 if (p == NULL) {
mbed_official 0:51ac1d130fd4 1195 LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));
mbed_official 0:51ac1d130fd4 1196 return;
mbed_official 0:51ac1d130fd4 1197 }
mbed_official 0:51ac1d130fd4 1198 LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
mbed_official 0:51ac1d130fd4 1199 (p->len >= sizeof(struct tcp_hdr)));
mbed_official 0:51ac1d130fd4 1200
mbed_official 0:51ac1d130fd4 1201 tcphdr = (struct tcp_hdr *)p->payload;
mbed_official 0:51ac1d130fd4 1202 tcphdr->src = htons(local_port);
mbed_official 0:51ac1d130fd4 1203 tcphdr->dest = htons(remote_port);
mbed_official 0:51ac1d130fd4 1204 tcphdr->seqno = htonl(seqno);
mbed_official 0:51ac1d130fd4 1205 tcphdr->ackno = htonl(ackno);
mbed_official 0:51ac1d130fd4 1206 TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK);
mbed_official 0:51ac1d130fd4 1207 tcphdr->wnd = PP_HTONS(TCP_WND);
mbed_official 0:51ac1d130fd4 1208 tcphdr->chksum = 0;
mbed_official 0:51ac1d130fd4 1209 tcphdr->urgp = 0;
mbed_official 0:51ac1d130fd4 1210
mbed_official 0:51ac1d130fd4 1211 #if CHECKSUM_GEN_TCP
mbed_official 0:51ac1d130fd4 1212 tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,
mbed_official 0:51ac1d130fd4 1213 IP_PROTO_TCP, p->tot_len);
mbed_official 0:51ac1d130fd4 1214 #endif
mbed_official 0:51ac1d130fd4 1215 TCP_STATS_INC(tcp.xmit);
mbed_official 0:51ac1d130fd4 1216 snmp_inc_tcpoutrsts();
mbed_official 0:51ac1d130fd4 1217 /* Send output with hardcoded TTL since we have no access to the pcb */
mbed_official 0:51ac1d130fd4 1218 ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);
mbed_official 0:51ac1d130fd4 1219 pbuf_free(p);
mbed_official 0:51ac1d130fd4 1220 LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));
mbed_official 0:51ac1d130fd4 1221 }
mbed_official 0:51ac1d130fd4 1222
mbed_official 0:51ac1d130fd4 1223 /**
mbed_official 0:51ac1d130fd4 1224 * Requeue all unacked segments for retransmission
mbed_official 0:51ac1d130fd4 1225 *
mbed_official 0:51ac1d130fd4 1226 * Called by tcp_slowtmr() for slow retransmission.
mbed_official 0:51ac1d130fd4 1227 *
mbed_official 0:51ac1d130fd4 1228 * @param pcb the tcp_pcb for which to re-enqueue all unacked segments
mbed_official 0:51ac1d130fd4 1229 */
mbed_official 0:51ac1d130fd4 1230 void
mbed_official 0:51ac1d130fd4 1231 tcp_rexmit_rto(struct tcp_pcb *pcb)
mbed_official 0:51ac1d130fd4 1232 {
mbed_official 0:51ac1d130fd4 1233 struct tcp_seg *seg;
mbed_official 0:51ac1d130fd4 1234
mbed_official 0:51ac1d130fd4 1235 if (pcb->unacked == NULL) {
mbed_official 0:51ac1d130fd4 1236 return;
mbed_official 0:51ac1d130fd4 1237 }
mbed_official 0:51ac1d130fd4 1238
mbed_official 0:51ac1d130fd4 1239 /* Move all unacked segments to the head of the unsent queue */
mbed_official 0:51ac1d130fd4 1240 for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
mbed_official 0:51ac1d130fd4 1241 /* concatenate unsent queue after unacked queue */
mbed_official 0:51ac1d130fd4 1242 seg->next = pcb->unsent;
mbed_official 0:51ac1d130fd4 1243 /* unsent queue is the concatenated queue (of unacked, unsent) */
mbed_official 0:51ac1d130fd4 1244 pcb->unsent = pcb->unacked;
mbed_official 0:51ac1d130fd4 1245 /* unacked queue is now empty */
mbed_official 0:51ac1d130fd4 1246 pcb->unacked = NULL;
mbed_official 0:51ac1d130fd4 1247
mbed_official 0:51ac1d130fd4 1248 /* increment number of retransmissions */
mbed_official 0:51ac1d130fd4 1249 ++pcb->nrtx;
mbed_official 0:51ac1d130fd4 1250
mbed_official 0:51ac1d130fd4 1251 /* Don't take any RTT measurements after retransmitting. */
mbed_official 0:51ac1d130fd4 1252 pcb->rttest = 0;
mbed_official 0:51ac1d130fd4 1253
mbed_official 0:51ac1d130fd4 1254 /* Do the actual retransmission */
mbed_official 0:51ac1d130fd4 1255 tcp_output(pcb);
mbed_official 0:51ac1d130fd4 1256 }
mbed_official 0:51ac1d130fd4 1257
mbed_official 0:51ac1d130fd4 1258 /**
mbed_official 0:51ac1d130fd4 1259 * Requeue the first unacked segment for retransmission
mbed_official 0:51ac1d130fd4 1260 *
mbed_official 0:51ac1d130fd4 1261 * Called by tcp_receive() for fast retramsmit.
mbed_official 0:51ac1d130fd4 1262 *
mbed_official 0:51ac1d130fd4 1263 * @param pcb the tcp_pcb for which to retransmit the first unacked segment
mbed_official 0:51ac1d130fd4 1264 */
mbed_official 0:51ac1d130fd4 1265 void
mbed_official 0:51ac1d130fd4 1266 tcp_rexmit(struct tcp_pcb *pcb)
mbed_official 0:51ac1d130fd4 1267 {
mbed_official 0:51ac1d130fd4 1268 struct tcp_seg *seg;
mbed_official 0:51ac1d130fd4 1269 struct tcp_seg **cur_seg;
mbed_official 0:51ac1d130fd4 1270
mbed_official 0:51ac1d130fd4 1271 if (pcb->unacked == NULL) {
mbed_official 0:51ac1d130fd4 1272 return;
mbed_official 0:51ac1d130fd4 1273 }
mbed_official 0:51ac1d130fd4 1274
mbed_official 0:51ac1d130fd4 1275 /* Move the first unacked segment to the unsent queue */
mbed_official 0:51ac1d130fd4 1276 /* Keep the unsent queue sorted. */
mbed_official 0:51ac1d130fd4 1277 seg = pcb->unacked;
mbed_official 0:51ac1d130fd4 1278 pcb->unacked = seg->next;
mbed_official 0:51ac1d130fd4 1279
mbed_official 0:51ac1d130fd4 1280 cur_seg = &(pcb->unsent);
mbed_official 0:51ac1d130fd4 1281 while (*cur_seg &&
mbed_official 0:51ac1d130fd4 1282 TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) {
mbed_official 0:51ac1d130fd4 1283 cur_seg = &((*cur_seg)->next );
mbed_official 0:51ac1d130fd4 1284 }
mbed_official 0:51ac1d130fd4 1285 seg->next = *cur_seg;
mbed_official 0:51ac1d130fd4 1286 *cur_seg = seg;
mbed_official 0:51ac1d130fd4 1287
mbed_official 0:51ac1d130fd4 1288 ++pcb->nrtx;
mbed_official 0:51ac1d130fd4 1289
mbed_official 0:51ac1d130fd4 1290 /* Don't take any rtt measurements after retransmitting. */
mbed_official 0:51ac1d130fd4 1291 pcb->rttest = 0;
mbed_official 0:51ac1d130fd4 1292
mbed_official 0:51ac1d130fd4 1293 /* Do the actual retransmission. */
mbed_official 0:51ac1d130fd4 1294 snmp_inc_tcpretranssegs();
mbed_official 0:51ac1d130fd4 1295 /* No need to call tcp_output: we are always called from tcp_input()
mbed_official 0:51ac1d130fd4 1296 and thus tcp_output directly returns. */
mbed_official 0:51ac1d130fd4 1297 }
mbed_official 0:51ac1d130fd4 1298
mbed_official 0:51ac1d130fd4 1299
mbed_official 0:51ac1d130fd4 1300 /**
mbed_official 0:51ac1d130fd4 1301 * Handle retransmission after three dupacks received
mbed_official 0:51ac1d130fd4 1302 *
mbed_official 0:51ac1d130fd4 1303 * @param pcb the tcp_pcb for which to retransmit the first unacked segment
mbed_official 0:51ac1d130fd4 1304 */
mbed_official 0:51ac1d130fd4 1305 void
mbed_official 0:51ac1d130fd4 1306 tcp_rexmit_fast(struct tcp_pcb *pcb)
mbed_official 0:51ac1d130fd4 1307 {
mbed_official 0:51ac1d130fd4 1308 if (pcb->unacked != NULL && !(pcb->flags & TF_INFR)) {
mbed_official 0:51ac1d130fd4 1309 /* This is fast retransmit. Retransmit the first unacked segment. */
mbed_official 0:51ac1d130fd4 1310 LWIP_DEBUGF(TCP_FR_DEBUG,
mbed_official 0:51ac1d130fd4 1311 ("tcp_receive: dupacks %"U16_F" (%"U32_F
mbed_official 0:51ac1d130fd4 1312 "), fast retransmit %"U32_F"\n",
mbed_official 0:51ac1d130fd4 1313 (u16_t)pcb->dupacks, pcb->lastack,
mbed_official 0:51ac1d130fd4 1314 ntohl(pcb->unacked->tcphdr->seqno)));
mbed_official 0:51ac1d130fd4 1315 tcp_rexmit(pcb);
mbed_official 0:51ac1d130fd4 1316
mbed_official 0:51ac1d130fd4 1317 /* Set ssthresh to half of the minimum of the current
mbed_official 0:51ac1d130fd4 1318 * cwnd and the advertised window */
mbed_official 0:51ac1d130fd4 1319 if (pcb->cwnd > pcb->snd_wnd) {
mbed_official 0:51ac1d130fd4 1320 pcb->ssthresh = pcb->snd_wnd / 2;
mbed_official 0:51ac1d130fd4 1321 } else {
mbed_official 0:51ac1d130fd4 1322 pcb->ssthresh = pcb->cwnd / 2;
mbed_official 0:51ac1d130fd4 1323 }
mbed_official 0:51ac1d130fd4 1324
mbed_official 0:51ac1d130fd4 1325 /* The minimum value for ssthresh should be 2 MSS */
mbed_official 0:51ac1d130fd4 1326 if (pcb->ssthresh < 2*pcb->mss) {
mbed_official 0:51ac1d130fd4 1327 LWIP_DEBUGF(TCP_FR_DEBUG,
mbed_official 0:51ac1d130fd4 1328 ("tcp_receive: The minimum value for ssthresh %"U16_F
mbed_official 0:51ac1d130fd4 1329 " should be min 2 mss %"U16_F"...\n",
mbed_official 0:51ac1d130fd4 1330 pcb->ssthresh, 2*pcb->mss));
mbed_official 0:51ac1d130fd4 1331 pcb->ssthresh = 2*pcb->mss;
mbed_official 0:51ac1d130fd4 1332 }
mbed_official 0:51ac1d130fd4 1333
mbed_official 0:51ac1d130fd4 1334 pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
mbed_official 0:51ac1d130fd4 1335 pcb->flags |= TF_INFR;
mbed_official 0:51ac1d130fd4 1336 }
mbed_official 0:51ac1d130fd4 1337 }
mbed_official 0:51ac1d130fd4 1338
mbed_official 0:51ac1d130fd4 1339
mbed_official 0:51ac1d130fd4 1340 /**
mbed_official 0:51ac1d130fd4 1341 * Send keepalive packets to keep a connection active although
mbed_official 0:51ac1d130fd4 1342 * no data is sent over it.
mbed_official 0:51ac1d130fd4 1343 *
mbed_official 0:51ac1d130fd4 1344 * Called by tcp_slowtmr()
mbed_official 0:51ac1d130fd4 1345 *
mbed_official 0:51ac1d130fd4 1346 * @param pcb the tcp_pcb for which to send a keepalive packet
mbed_official 0:51ac1d130fd4 1347 */
mbed_official 0:51ac1d130fd4 1348 void
mbed_official 0:51ac1d130fd4 1349 tcp_keepalive(struct tcp_pcb *pcb)
mbed_official 0:51ac1d130fd4 1350 {
mbed_official 0:51ac1d130fd4 1351 struct pbuf *p;
mbed_official 0:51ac1d130fd4 1352 struct tcp_hdr *tcphdr;
mbed_official 0:51ac1d130fd4 1353
mbed_official 0:51ac1d130fd4 1354 LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
mbed_official 0:51ac1d130fd4 1355 ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
mbed_official 0:51ac1d130fd4 1356 ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
mbed_official 0:51ac1d130fd4 1357
mbed_official 0:51ac1d130fd4 1358 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 1359 tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
mbed_official 0:51ac1d130fd4 1360
mbed_official 0:51ac1d130fd4 1361 p = tcp_output_alloc_header(pcb, 0, 0, htonl(pcb->snd_nxt - 1));
mbed_official 0:51ac1d130fd4 1362 if(p == NULL) {
mbed_official 0:51ac1d130fd4 1363 LWIP_DEBUGF(TCP_DEBUG,
mbed_official 0:51ac1d130fd4 1364 ("tcp_keepalive: could not allocate memory for pbuf\n"));
mbed_official 0:51ac1d130fd4 1365 return;
mbed_official 0:51ac1d130fd4 1366 }
mbed_official 0:51ac1d130fd4 1367 tcphdr = (struct tcp_hdr *)p->payload;
mbed_official 0:51ac1d130fd4 1368
mbed_official 0:51ac1d130fd4 1369 #if CHECKSUM_GEN_TCP
mbed_official 0:51ac1d130fd4 1370 tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
mbed_official 0:51ac1d130fd4 1371 IP_PROTO_TCP, p->tot_len);
mbed_official 0:51ac1d130fd4 1372 #endif
mbed_official 0:51ac1d130fd4 1373 TCP_STATS_INC(tcp.xmit);
mbed_official 0:51ac1d130fd4 1374
mbed_official 0:51ac1d130fd4 1375 /* Send output to IP */
mbed_official 0:51ac1d130fd4 1376 #if LWIP_NETIF_HWADDRHINT
mbed_official 0:51ac1d130fd4 1377 ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
mbed_official 0:51ac1d130fd4 1378 &(pcb->addr_hint));
mbed_official 0:51ac1d130fd4 1379 #else /* LWIP_NETIF_HWADDRHINT*/
mbed_official 0:51ac1d130fd4 1380 ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
mbed_official 0:51ac1d130fd4 1381 #endif /* LWIP_NETIF_HWADDRHINT*/
mbed_official 0:51ac1d130fd4 1382
mbed_official 0:51ac1d130fd4 1383 pbuf_free(p);
mbed_official 0:51ac1d130fd4 1384
mbed_official 0:51ac1d130fd4 1385 LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n",
mbed_official 0:51ac1d130fd4 1386 pcb->snd_nxt - 1, pcb->rcv_nxt));
mbed_official 0:51ac1d130fd4 1387 }
mbed_official 0:51ac1d130fd4 1388
mbed_official 0:51ac1d130fd4 1389
mbed_official 0:51ac1d130fd4 1390 /**
mbed_official 0:51ac1d130fd4 1391 * Send persist timer zero-window probes to keep a connection active
mbed_official 0:51ac1d130fd4 1392 * when a window update is lost.
mbed_official 0:51ac1d130fd4 1393 *
mbed_official 0:51ac1d130fd4 1394 * Called by tcp_slowtmr()
mbed_official 0:51ac1d130fd4 1395 *
mbed_official 0:51ac1d130fd4 1396 * @param pcb the tcp_pcb for which to send a zero-window probe packet
mbed_official 0:51ac1d130fd4 1397 */
mbed_official 0:51ac1d130fd4 1398 void
mbed_official 0:51ac1d130fd4 1399 tcp_zero_window_probe(struct tcp_pcb *pcb)
mbed_official 0:51ac1d130fd4 1400 {
mbed_official 0:51ac1d130fd4 1401 struct pbuf *p;
mbed_official 0:51ac1d130fd4 1402 struct tcp_hdr *tcphdr;
mbed_official 0:51ac1d130fd4 1403 struct tcp_seg *seg;
mbed_official 0:51ac1d130fd4 1404 u16_t len;
mbed_official 0:51ac1d130fd4 1405 u8_t is_fin;
mbed_official 0:51ac1d130fd4 1406
mbed_official 0:51ac1d130fd4 1407 LWIP_DEBUGF(TCP_DEBUG,
mbed_official 0:51ac1d130fd4 1408 ("tcp_zero_window_probe: sending ZERO WINDOW probe to %"
mbed_official 0:51ac1d130fd4 1409 U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
mbed_official 0:51ac1d130fd4 1410 ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
mbed_official 0:51ac1d130fd4 1411 ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
mbed_official 0:51ac1d130fd4 1412
mbed_official 0:51ac1d130fd4 1413 LWIP_DEBUGF(TCP_DEBUG,
mbed_official 0:51ac1d130fd4 1414 ("tcp_zero_window_probe: tcp_ticks %"U32_F
mbed_official 0:51ac1d130fd4 1415 " pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",
mbed_official 0:51ac1d130fd4 1416 tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
mbed_official 0:51ac1d130fd4 1417
mbed_official 0:51ac1d130fd4 1418 seg = pcb->unacked;
mbed_official 0:51ac1d130fd4 1419
mbed_official 0:51ac1d130fd4 1420 if(seg == NULL) {
mbed_official 0:51ac1d130fd4 1421 seg = pcb->unsent;
mbed_official 0:51ac1d130fd4 1422 }
mbed_official 0:51ac1d130fd4 1423 if(seg == NULL) {
mbed_official 0:51ac1d130fd4 1424 return;
mbed_official 0:51ac1d130fd4 1425 }
mbed_official 0:51ac1d130fd4 1426
mbed_official 0:51ac1d130fd4 1427 is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0);
mbed_official 0:51ac1d130fd4 1428 /* we want to send one seqno: either FIN or data (no options) */
mbed_official 0:51ac1d130fd4 1429 len = is_fin ? 0 : 1;
mbed_official 0:51ac1d130fd4 1430
mbed_official 0:51ac1d130fd4 1431 p = tcp_output_alloc_header(pcb, 0, len, seg->tcphdr->seqno);
mbed_official 0:51ac1d130fd4 1432 if(p == NULL) {
mbed_official 0:51ac1d130fd4 1433 LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n"));
mbed_official 0:51ac1d130fd4 1434 return;
mbed_official 0:51ac1d130fd4 1435 }
mbed_official 0:51ac1d130fd4 1436 tcphdr = (struct tcp_hdr *)p->payload;
mbed_official 0:51ac1d130fd4 1437
mbed_official 0:51ac1d130fd4 1438 if (is_fin) {
mbed_official 0:51ac1d130fd4 1439 /* FIN segment, no data */
mbed_official 0:51ac1d130fd4 1440 TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN);
mbed_official 0:51ac1d130fd4 1441 } else {
mbed_official 0:51ac1d130fd4 1442 /* Data segment, copy in one byte from the head of the unacked queue */
mbed_official 0:51ac1d130fd4 1443 struct tcp_hdr *thdr = (struct tcp_hdr *)seg->p->payload;
mbed_official 0:51ac1d130fd4 1444 char *d = ((char *)p->payload + TCP_HLEN);
mbed_official 0:51ac1d130fd4 1445 pbuf_copy_partial(seg->p, d, 1, TCPH_HDRLEN(thdr) * 4);
mbed_official 0:51ac1d130fd4 1446 }
mbed_official 0:51ac1d130fd4 1447
mbed_official 0:51ac1d130fd4 1448 #if CHECKSUM_GEN_TCP
mbed_official 0:51ac1d130fd4 1449 tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
mbed_official 0:51ac1d130fd4 1450 IP_PROTO_TCP, p->tot_len);
mbed_official 0:51ac1d130fd4 1451 #endif
mbed_official 0:51ac1d130fd4 1452 TCP_STATS_INC(tcp.xmit);
mbed_official 0:51ac1d130fd4 1453
mbed_official 0:51ac1d130fd4 1454 /* Send output to IP */
mbed_official 0:51ac1d130fd4 1455 #if LWIP_NETIF_HWADDRHINT
mbed_official 0:51ac1d130fd4 1456 ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
mbed_official 0:51ac1d130fd4 1457 &(pcb->addr_hint));
mbed_official 0:51ac1d130fd4 1458 #else /* LWIP_NETIF_HWADDRHINT*/
mbed_official 0:51ac1d130fd4 1459 ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
mbed_official 0:51ac1d130fd4 1460 #endif /* LWIP_NETIF_HWADDRHINT*/
mbed_official 0:51ac1d130fd4 1461
mbed_official 0:51ac1d130fd4 1462 pbuf_free(p);
mbed_official 0:51ac1d130fd4 1463
mbed_official 0:51ac1d130fd4 1464 LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F
mbed_official 0:51ac1d130fd4 1465 " ackno %"U32_F".\n",
mbed_official 0:51ac1d130fd4 1466 pcb->snd_nxt - 1, pcb->rcv_nxt));
mbed_official 0:51ac1d130fd4 1467 }
mbed_official 0:51ac1d130fd4 1468 #endif /* LWIP_TCP */