kEIS

Dependents:   EthernetInterface_ccx

Fork of lwip by mbed official

Committer:
khayakawa
Date:
Sat Sep 28 16:34:37 2013 +0000
Revision:
11:7799ae488ba0
Parent:
0:51ac1d130fd4
KEIS

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 */