Used in Live Traffic Update Nokia LCD Display Project

Fork of NetServices by Segundo Equipo

Committer:
rrajan8
Date:
Wed Mar 06 19:07:23 2013 +0000
Revision:
8:92b57208ab99
Parent:
0:ac1725ba162c
This project utilizes mbed's networking features to display live traffic updates on the Nokia LCD using the MapQuest API's Traffic Web Service.

Who changed what in which revision?

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