ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

tcp_out.c
Go to the documentation of this file.
00001 
00009 /*
00010  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
00011  * All rights reserved.
00012  *
00013  * Redistribution and use in source and binary forms, with or without modification,
00014  * are permitted provided that the following conditions are met:
00015  *
00016  * 1. Redistributions of source code must retain the above copyright notice,
00017  *    this list of conditions and the following disclaimer.
00018  * 2. Redistributions in binary form must reproduce the above copyright notice,
00019  *    this list of conditions and the following disclaimer in the documentation
00020  *    and/or other materials provided with the distribution.
00021  * 3. The name of the author may not be used to endorse or promote products
00022  *    derived from this software without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00025  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00026  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00027  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00028  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00029  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00032  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00033  * OF SUCH DAMAGE.
00034  *
00035  * This file is part of the lwIP TCP/IP stack.
00036  *
00037  * Author: Adam Dunkels <adam@sics.se>
00038  *
00039  */
00040 
00041 #include "lwip/opt.h"
00042 
00043 #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */
00044 
00045 #include "lwip/tcp_impl.h"
00046 #include "lwip/def.h"
00047 #include "lwip/mem.h"
00048 #include "lwip/memp.h"
00049 #include "lwip/sys.h"
00050 #include "lwip/ip_addr.h"
00051 #include "lwip/netif.h"
00052 #include "lwip/inet_chksum.h"
00053 #include "lwip/stats.h"
00054 #include "lwip/snmp.h"
00055 
00056 #include <string.h>
00057 
00058 /* Define some copy-macros for checksum-on-copy so that the code looks
00059    nicer by preventing too many ifdef's. */
00060 #if TCP_CHECKSUM_ON_COPY
00061 #define TCP_DATA_COPY(dst, src, len, seg) do { \
00062   tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), \
00063                      len, &seg->chksum, &seg->chksum_swapped); \
00064   seg->flags |= TF_SEG_DATA_CHECKSUMMED; } while(0)
00065 #define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped)  \
00066   tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), len, chksum, chksum_swapped);
00067 #else /* TCP_CHECKSUM_ON_COPY*/
00068 #define TCP_DATA_COPY(dst, src, len, seg)                     MEMCPY(dst, src, len)
00069 #define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) MEMCPY(dst, src, len)
00070 #endif /* TCP_CHECKSUM_ON_COPY*/
00071 
00074 #ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK
00075 #define TCP_CHECKSUM_ON_COPY_SANITY_CHECK   0
00076 #endif
00077 
00078 /* Forward declarations.*/
00079 static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
00080 
00091 static struct pbuf *
00092 tcp_output_alloc_header(struct tcp_pcb *pcb, u16_t optlen, u16_t datalen,
00093                       u32_t seqno_be /* already in network byte order */)
00094 {
00095   struct tcp_hdr *tcphdr;
00096   struct pbuf *p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen + datalen, PBUF_RAM);
00097   if (p != NULL) {
00098     LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
00099                  (p->len >= TCP_HLEN + optlen));
00100     tcphdr = (struct tcp_hdr *)p->payload;
00101     tcphdr->src = htons(pcb->local_port);
00102     tcphdr->dest = htons(pcb->remote_port);
00103     tcphdr->seqno = seqno_be;
00104     tcphdr->ackno = htonl(pcb->rcv_nxt);
00105     TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), TCP_ACK);
00106     tcphdr->wnd = htons(pcb->rcv_ann_wnd);
00107     tcphdr->chksum = 0;
00108     tcphdr->urgp = 0;
00109 
00110     /* If we're sending a packet, update the announced right window edge */
00111     pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
00112   }
00113   return p;
00114 }
00115 
00122 err_t
00123 tcp_send_fin(struct tcp_pcb *pcb)
00124 {
00125   /* first, try to add the fin to the last unsent segment */
00126   if (pcb->unsent != NULL) {
00127     struct tcp_seg *last_unsent;
00128     for (last_unsent = pcb->unsent; last_unsent->next != NULL;
00129          last_unsent = last_unsent->next);
00130 
00131     if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) {
00132       /* no SYN/FIN/RST flag in the header, we can add the FIN flag */
00133       TCPH_SET_FLAG(last_unsent->tcphdr, TCP_FIN);
00134       pcb->flags |= TF_FIN;
00135       return ERR_OK;
00136     }
00137   }
00138   /* no data, no length, flags, copy=1, no optdata */
00139   return tcp_enqueue_flags(pcb, TCP_FIN);
00140 }
00141 
00156 static struct tcp_seg *
00157 tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno, u8_t optflags)
00158 {
00159   struct tcp_seg *seg;
00160   u8_t optlen = LWIP_TCP_OPT_LENGTH(optflags);
00161 
00162   if ((seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG)) == NULL) {
00163     LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no memory.\n"));
00164     pbuf_free(p);
00165     return NULL;
00166   }
00167   seg->flags = optflags;
00168   seg->next = NULL;
00169   seg->p = p;
00170   seg->len = p->tot_len - optlen;
00171 #if TCP_OVERSIZE_DBGCHECK
00172   seg->oversize_left = 0;
00173 #endif /* TCP_OVERSIZE_DBGCHECK */
00174 #if TCP_CHECKSUM_ON_COPY
00175   seg->chksum = 0;
00176   seg->chksum_swapped = 0;
00177   /* check optflags */
00178   LWIP_ASSERT("invalid optflags passed: TF_SEG_DATA_CHECKSUMMED",
00179               (optflags & TF_SEG_DATA_CHECKSUMMED) == 0);
00180 #endif /* TCP_CHECKSUM_ON_COPY */
00181 
00182   /* build TCP header */
00183   if (pbuf_header(p, TCP_HLEN)) {
00184     LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no room for TCP header in pbuf.\n"));
00185     TCP_STATS_INC(tcp.err);
00186     tcp_seg_free(seg);
00187     return NULL;
00188   }
00189   seg->tcphdr = (struct tcp_hdr *)seg->p->payload;
00190   seg->tcphdr->src = htons(pcb->local_port);
00191   seg->tcphdr->dest = htons(pcb->remote_port);
00192   seg->tcphdr->seqno = htonl(seqno);
00193   /* ackno is set in tcp_output */
00194   TCPH_HDRLEN_FLAGS_SET(seg->tcphdr, (5 + optlen / 4), flags);
00195   /* wnd and chksum are set in tcp_output */
00196   seg->tcphdr->urgp = 0;
00197   return seg;
00198 } 
00199 
00215 #if TCP_OVERSIZE
00216 static struct pbuf *
00217 tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length,
00218                   u16_t *oversize, struct tcp_pcb *pcb, u8_t apiflags,
00219                   u8_t first_seg)
00220 {
00221   struct pbuf *p;
00222   u16_t alloc = length;
00223 
00224 #if LWIP_NETIF_TX_SINGLE_PBUF
00225   LWIP_UNUSED_ARG(max_length);
00226   LWIP_UNUSED_ARG(pcb);
00227   LWIP_UNUSED_ARG(apiflags);
00228   LWIP_UNUSED_ARG(first_seg);
00229   /* always create MSS-sized pbufs */
00230   alloc = TCP_MSS;
00231 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
00232   if (length < max_length) {
00233     /* Should we allocate an oversized pbuf, or just the minimum
00234      * length required? If tcp_write is going to be called again
00235      * before this segment is transmitted, we want the oversized
00236      * buffer. If the segment will be transmitted immediately, we can
00237      * save memory by allocating only length. We use a simple
00238      * heuristic based on the following information:
00239      *
00240      * Did the user set TCP_WRITE_FLAG_MORE?
00241      *
00242      * Will the Nagle algorithm defer transmission of this segment?
00243      */
00244     if ((apiflags & TCP_WRITE_FLAG_MORE) ||
00245         (!(pcb->flags & TF_NODELAY) &&
00246          (!first_seg ||
00247           pcb->unsent != NULL ||
00248           pcb->unacked != NULL))) {
00249       alloc = LWIP_MIN(max_length, LWIP_MEM_ALIGN_SIZE(length + TCP_OVERSIZE));
00250     }
00251   }
00252 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
00253   p = pbuf_alloc(layer, alloc, PBUF_RAM);
00254   if (p == NULL) {
00255     return NULL;
00256   }
00257   LWIP_ASSERT("need unchained pbuf", p->next == NULL);
00258   *oversize = p->len - length;
00259   /* trim p->len to the currently used size */
00260   p->len = p->tot_len = length;
00261   return p;
00262 }
00263 #else /* TCP_OVERSIZE */
00264 #define tcp_pbuf_prealloc(layer, length, mx, os, pcb, api, fst) pbuf_alloc((layer), (length), PBUF_RAM)
00265 #endif /* TCP_OVERSIZE */
00266 
00267 #if TCP_CHECKSUM_ON_COPY
00268 
00269 static void
00270 tcp_seg_add_chksum(u16_t chksum, u16_t len, u16_t *seg_chksum,
00271                    u8_t *seg_chksum_swapped)
00272 {
00273   u32_t helper;
00274   /* add chksum to old chksum and fold to u16_t */
00275   helper = chksum + *seg_chksum;
00276   chksum = FOLD_U32T(helper);
00277   if ((len & 1) != 0) {
00278     *seg_chksum_swapped = 1 - *seg_chksum_swapped;
00279     chksum = SWAP_BYTES_IN_WORD(chksum);
00280   }
00281   *seg_chksum = chksum;
00282 }
00283 #endif /* TCP_CHECKSUM_ON_COPY */
00284 
00291 static err_t
00292 tcp_write_checks(struct tcp_pcb *pcb, u16_t len)
00293 {
00294   /* connection is in invalid state for data transmission? */
00295   if ((pcb->state != ESTABLISHED) &&
00296       (pcb->state != CLOSE_WAIT) &&
00297       (pcb->state != SYN_SENT) &&
00298       (pcb->state != SYN_RCVD)) {
00299     LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | LWIP_DBG_LEVEL_SEVERE, ("tcp_write() called in invalid state\n"));
00300     return ERR_CONN;
00301   } else if (len == 0) {
00302     return ERR_OK;
00303   }
00304 
00305   /* fail on too much data */
00306   if (len > pcb->snd_buf) {
00307     LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n",
00308       len, pcb->snd_buf));
00309     pcb->flags |= TF_NAGLEMEMERR;
00310     return ERR_MEM;
00311   }
00312 
00313   LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen));
00314 
00315   /* If total number of pbufs on the unsent/unacked queues exceeds the
00316    * configured maximum, return an error */
00317   /* check for configured max queuelen and possible overflow */
00318   if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
00319     LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too long queue %"U16_F" (max %"U16_F")\n",
00320       pcb->snd_queuelen, TCP_SND_QUEUELEN));
00321     TCP_STATS_INC(tcp.memerr);
00322     pcb->flags |= TF_NAGLEMEMERR;
00323     return ERR_MEM;
00324   }
00325   if (pcb->snd_queuelen != 0) {
00326     LWIP_ASSERT("tcp_write: pbufs on queue => at least one queue non-empty",
00327       pcb->unacked != NULL || pcb->unsent != NULL);
00328   } else {
00329     LWIP_ASSERT("tcp_write: no pbufs on queue => both queues empty",
00330       pcb->unacked == NULL && pcb->unsent == NULL);
00331   }
00332   return ERR_OK;
00333 }
00334 
00351 err_t
00352 tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
00353 {
00354   struct pbuf *concat_p = NULL;
00355   struct tcp_seg *last_unsent = NULL, *seg = NULL, *prev_seg = NULL, *queue = NULL;
00356   u16_t pos = 0; /* position in 'arg' data */
00357   u16_t queuelen;
00358   u8_t optlen = 0;
00359   u8_t optflags = 0;
00360 #if TCP_OVERSIZE
00361   u16_t oversize = 0;
00362   u16_t oversize_used = 0;
00363 #endif /* TCP_OVERSIZE */
00364 #if TCP_CHECKSUM_ON_COPY
00365   u16_t concat_chksum = 0;
00366   u8_t concat_chksum_swapped = 0;
00367   u16_t concat_chksummed = 0;
00368 #endif /* TCP_CHECKSUM_ON_COPY */
00369   err_t err;
00370 
00371 #if LWIP_NETIF_TX_SINGLE_PBUF
00372   /* Always copy to try to create single pbufs for TX */
00373   apiflags |= TCP_WRITE_FLAG_COPY;
00374 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
00375 
00376   LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n",
00377     (void *)pcb, arg, len, (u16_t)apiflags));
00378   LWIP_ERROR("tcp_write: arg == NULL (programmer violates API)", 
00379              arg != NULL, return ERR_ARG;);
00380 
00381   err = tcp_write_checks(pcb, len);
00382   if (err != ERR_OK) {
00383     return err;
00384   }
00385   queuelen = pcb->snd_queuelen;
00386 
00387 #if LWIP_TCP_TIMESTAMPS
00388   if ((pcb->flags & TF_TIMESTAMP)) {
00389     optflags = TF_SEG_OPTS_TS;
00390     optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
00391   }
00392 #endif /* LWIP_TCP_TIMESTAMPS */
00393 
00394 
00395   /*
00396    * TCP segmentation is done in three phases with increasing complexity:
00397    *
00398    * 1. Copy data directly into an oversized pbuf.
00399    * 2. Chain a new pbuf to the end of pcb->unsent.
00400    * 3. Create new segments.
00401    *
00402    * We may run out of memory at any point. In that case we must
00403    * return ERR_MEM and not change anything in pcb. Therefore, all
00404    * changes are recorded in local variables and committed at the end
00405    * of the function. Some pcb fields are maintained in local copies:
00406    *
00407    * queuelen = pcb->snd_queuelen
00408    * oversize = pcb->unsent_oversize
00409    *
00410    * These variables are set consistently by the phases:
00411    *
00412    * seg points to the last segment tampered with.
00413    *
00414    * pos records progress as data is segmented.
00415    */
00416 
00417   /* Find the tail of the unsent queue. */
00418   if (pcb->unsent != NULL) {
00419     u16_t space;
00420     u16_t unsent_optlen;
00421 
00422     /* @todo: this could be sped up by keeping last_unsent in the pcb */
00423     for (last_unsent = pcb->unsent; last_unsent->next != NULL;
00424          last_unsent = last_unsent->next);
00425 
00426     /* Usable space at the end of the last unsent segment */
00427     unsent_optlen = LWIP_TCP_OPT_LENGTH(last_unsent->flags);
00428     space = pcb->mss - (last_unsent->len + unsent_optlen);
00429 
00430     /*
00431      * Phase 1: Copy data directly into an oversized pbuf.
00432      *
00433      * The number of bytes copied is recorded in the oversize_used
00434      * variable. The actual copying is done at the bottom of the
00435      * function.
00436      */
00437 #if TCP_OVERSIZE
00438 #if TCP_OVERSIZE_DBGCHECK
00439     /* check that pcb->unsent_oversize matches last_unsent->unsent_oversize */
00440     LWIP_ASSERT("unsent_oversize mismatch (pcb vs. last_unsent)",
00441                 pcb->unsent_oversize == last_unsent->oversize_left);
00442 #endif /* TCP_OVERSIZE_DBGCHECK */
00443     oversize = pcb->unsent_oversize;
00444     if (oversize > 0) {
00445       LWIP_ASSERT("inconsistent oversize vs. space", oversize_used <= space);
00446       seg = last_unsent;
00447       oversize_used = oversize < len ? oversize : len;
00448       pos += oversize_used;
00449       oversize -= oversize_used;
00450       space -= oversize_used;
00451     }
00452     /* now we are either finished or oversize is zero */
00453     LWIP_ASSERT("inconsistend oversize vs. len", (oversize == 0) || (pos == len));
00454 #endif /* TCP_OVERSIZE */
00455 
00456     /*
00457      * Phase 2: Chain a new pbuf to the end of pcb->unsent.
00458      *
00459      * We don't extend segments containing SYN/FIN flags or options
00460      * (len==0). The new pbuf is kept in concat_p and pbuf_cat'ed at
00461      * the end.
00462      */
00463     if ((pos < len) && (space > 0) && (last_unsent->len > 0)) {
00464       u16_t seglen = space < len - pos ? space : len - pos;
00465       seg = last_unsent;
00466 
00467       /* Create a pbuf with a copy or reference to seglen bytes. We
00468        * can use PBUF_RAW here since the data appears in the middle of
00469        * a segment. A header will never be prepended. */
00470       if (apiflags & TCP_WRITE_FLAG_COPY) {
00471         /* Data is copied */
00472         if ((concat_p = tcp_pbuf_prealloc(PBUF_RAW, seglen, space, &oversize, pcb, apiflags, 1)) == NULL) {
00473           LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,
00474                       ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n",
00475                        seglen));
00476           goto memerr;
00477         }
00478 #if TCP_OVERSIZE_DBGCHECK
00479         last_unsent->oversize_left = oversize;
00480 #endif /* TCP_OVERSIZE_DBGCHECK */
00481         TCP_DATA_COPY2(concat_p->payload, (u8_t*)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped);
00482 #if TCP_CHECKSUM_ON_COPY
00483         concat_chksummed += seglen;
00484 #endif /* TCP_CHECKSUM_ON_COPY */
00485       } else {
00486         /* Data is not copied */
00487         if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) {
00488           LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,
00489                       ("tcp_write: could not allocate memory for zero-copy pbuf\n"));
00490           goto memerr;
00491         }
00492 #if TCP_CHECKSUM_ON_COPY
00493         /* calculate the checksum of nocopy-data */
00494         tcp_seg_add_chksum(~inet_chksum((u8_t*)arg + pos, seglen), seglen,
00495           &concat_chksum, &concat_chksum_swapped);
00496         concat_chksummed += seglen;
00497 #endif /* TCP_CHECKSUM_ON_COPY */
00498         /* reference the non-volatile payload data */
00499         concat_p->payload = (u8_t*)arg + pos;
00500       }
00501 
00502       pos += seglen;
00503       queuelen += pbuf_clen(concat_p);
00504     }
00505   } else {
00506 #if TCP_OVERSIZE
00507     LWIP_ASSERT("unsent_oversize mismatch (pcb->unsent is NULL)",
00508                 pcb->unsent_oversize == 0);
00509 #endif /* TCP_OVERSIZE */
00510   }
00511 
00512   /*
00513    * Phase 3: Create new segments.
00514    *
00515    * The new segments are chained together in the local 'queue'
00516    * variable, ready to be appended to pcb->unsent.
00517    */
00518   while (pos < len) {
00519     struct pbuf *p;
00520     u16_t left = len - pos;
00521     u16_t max_len = pcb->mss - optlen;
00522     u16_t seglen = left > max_len ? max_len : left;
00523 #if TCP_CHECKSUM_ON_COPY
00524     u16_t chksum = 0;
00525     u8_t chksum_swapped = 0;
00526 #endif /* TCP_CHECKSUM_ON_COPY */
00527 
00528     if (apiflags & TCP_WRITE_FLAG_COPY) {
00529       /* If copy is set, memory should be allocated and data copied
00530        * into pbuf */
00531       if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, pcb->mss, &oversize, pcb, apiflags, queue == NULL)) == NULL) {
00532         LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));
00533         goto memerr;
00534       }
00535       LWIP_ASSERT("tcp_write: check that first pbuf can hold the complete seglen",
00536                   (p->len >= seglen));
00537       TCP_DATA_COPY2((char *)p->payload + optlen, (u8_t*)arg + pos, seglen, &chksum, &chksum_swapped);
00538     } else {
00539       /* Copy is not set: First allocate a pbuf for holding the data.
00540        * Since the referenced data is available at least until it is
00541        * sent out on the link (as it has to be ACKed by the remote
00542        * party) we can safely use PBUF_ROM instead of PBUF_REF here.
00543        */
00544       struct pbuf *p2;
00545 #if TCP_OVERSIZE
00546       LWIP_ASSERT("oversize == 0", oversize == 0);
00547 #endif /* TCP_OVERSIZE */
00548       if ((p2 = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {
00549         LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for zero-copy pbuf\n"));
00550         goto memerr;
00551       }
00552 #if TCP_CHECKSUM_ON_COPY
00553       /* calculate the checksum of nocopy-data */
00554       chksum = ~inet_chksum((u8_t*)arg + pos, seglen);
00555 #endif /* TCP_CHECKSUM_ON_COPY */
00556       /* reference the non-volatile payload data */
00557       p2->payload = (u8_t*)arg + pos;
00558 
00559       /* Second, allocate a pbuf for the headers. */
00560       if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
00561         /* If allocation fails, we have to deallocate the data pbuf as
00562          * well. */
00563         pbuf_free(p2);
00564         LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for header pbuf\n"));
00565         goto memerr;
00566       }
00567       /* Concatenate the headers and data pbufs together. */
00568       pbuf_cat(p/*header*/, p2/*data*/);
00569     }
00570 
00571     queuelen += pbuf_clen(p);
00572 
00573     /* Now that there are more segments queued, we check again if the
00574      * length of the queue exceeds the configured maximum or
00575      * overflows. */
00576     if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
00577       LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
00578       pbuf_free(p);
00579       goto memerr;
00580     }
00581 
00582     if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) {
00583       goto memerr;
00584     }
00585 #if TCP_OVERSIZE_DBGCHECK
00586     seg->oversize_left = oversize;
00587 #endif /* TCP_OVERSIZE_DBGCHECK */
00588 #if TCP_CHECKSUM_ON_COPY
00589     seg->chksum = chksum;
00590     seg->chksum_swapped = chksum_swapped;
00591     seg->flags |= TF_SEG_DATA_CHECKSUMMED;
00592 #endif /* TCP_CHECKSUM_ON_COPY */
00593 
00594     /* first segment of to-be-queued data? */
00595     if (queue == NULL) {
00596       queue = seg;
00597     } else {
00598       /* Attach the segment to the end of the queued segments */
00599       LWIP_ASSERT("prev_seg != NULL", prev_seg != NULL);
00600       prev_seg->next = seg;
00601     }
00602     /* remember last segment of to-be-queued data for next iteration */
00603     prev_seg = seg;
00604 
00605     LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_write: queueing %"U32_F":%"U32_F"\n",
00606       ntohl(seg->tcphdr->seqno),
00607       ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg)));
00608 
00609     pos += seglen;
00610   }
00611 
00612   /*
00613    * All three segmentation phases were successful. We can commit the
00614    * transaction.
00615    */
00616 
00617   /*
00618    * Phase 1: If data has been added to the preallocated tail of
00619    * last_unsent, we update the length fields of the pbuf chain.
00620    */
00621 #if TCP_OVERSIZE
00622   if (oversize_used > 0) {
00623     struct pbuf *p;
00624     /* Bump tot_len of whole chain, len of tail */
00625     for (p = last_unsent->p; p; p = p->next) {
00626       p->tot_len += oversize_used;
00627       if (p->next == NULL) {
00628         TCP_DATA_COPY((char *)p->payload + p->len, arg, oversize_used, last_unsent);
00629         p->len += oversize_used;
00630       }
00631     }
00632     last_unsent->len += oversize_used;
00633 #if TCP_OVERSIZE_DBGCHECK
00634     last_unsent->oversize_left -= oversize_used;
00635 #endif /* TCP_OVERSIZE_DBGCHECK */
00636   }
00637   pcb->unsent_oversize = oversize;
00638 #endif /* TCP_OVERSIZE */
00639 
00640   /*
00641    * Phase 2: concat_p can be concatenated onto last_unsent->p
00642    */
00643   if (concat_p != NULL) {
00644     LWIP_ASSERT("tcp_write: cannot concatenate when pcb->unsent is empty",
00645       (last_unsent != NULL));
00646     pbuf_cat(last_unsent->p, concat_p);
00647     last_unsent->len += concat_p->tot_len;
00648 #if TCP_CHECKSUM_ON_COPY
00649     if (concat_chksummed) {
00650       tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum,
00651         &last_unsent->chksum_swapped);
00652       last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED;
00653     }
00654 #endif /* TCP_CHECKSUM_ON_COPY */
00655   }
00656 
00657   /*
00658    * Phase 3: Append queue to pcb->unsent. Queue may be NULL, but that
00659    * is harmless
00660    */
00661   if (last_unsent == NULL) {
00662     pcb->unsent = queue;
00663   } else {
00664     last_unsent->next = queue;
00665   }
00666 
00667   /*
00668    * Finally update the pcb state.
00669    */
00670   pcb->snd_lbb += len;
00671   pcb->snd_buf -= len;
00672   pcb->snd_queuelen = queuelen;
00673 
00674   LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: %"S16_F" (after enqueued)\n",
00675     pcb->snd_queuelen));
00676   if (pcb->snd_queuelen != 0) {
00677     LWIP_ASSERT("tcp_write: valid queue length",
00678                 pcb->unacked != NULL || pcb->unsent != NULL);
00679   }
00680 
00681   /* Set the PSH flag in the last segment that we enqueued. */
00682   if (seg != NULL && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE)==0)) {
00683     TCPH_SET_FLAG(seg->tcphdr, TCP_PSH);
00684   }
00685 
00686   return ERR_OK;
00687 memerr:
00688   pcb->flags |= TF_NAGLEMEMERR;
00689   TCP_STATS_INC(tcp.memerr);
00690 
00691   if (concat_p != NULL) {
00692     pbuf_free(concat_p);
00693   }
00694   if (queue != NULL) {
00695     tcp_segs_free(queue);
00696   }
00697   if (pcb->snd_queuelen != 0) {
00698     LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL ||
00699       pcb->unsent != NULL);
00700   }
00701   LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_write: %"S16_F" (with mem err)\n", pcb->snd_queuelen));
00702   return ERR_MEM;
00703 }
00704 
00715 err_t
00716 tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
00717 {
00718   struct pbuf *p;
00719   struct tcp_seg *seg;
00720   u8_t optflags = 0;
00721   u8_t optlen = 0;
00722 
00723   LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen));
00724 
00725   LWIP_ASSERT("tcp_enqueue_flags: need either TCP_SYN or TCP_FIN in flags (programmer violates API)",
00726               (flags & (TCP_SYN | TCP_FIN)) != 0);
00727 
00728   /* check for configured max queuelen and possible overflow */
00729   if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
00730     LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: too long queue %"U16_F" (max %"U16_F")\n",
00731                                        pcb->snd_queuelen, TCP_SND_QUEUELEN));
00732     TCP_STATS_INC(tcp.memerr);
00733     pcb->flags |= TF_NAGLEMEMERR;
00734     return ERR_MEM;
00735   }
00736 
00737   if (flags & TCP_SYN) {
00738     optflags = TF_SEG_OPTS_MSS;
00739   }
00740 #if LWIP_TCP_TIMESTAMPS
00741   if ((pcb->flags & TF_TIMESTAMP)) {
00742     optflags |= TF_SEG_OPTS_TS;
00743   }
00744 #endif /* LWIP_TCP_TIMESTAMPS */
00745   optlen = LWIP_TCP_OPT_LENGTH(optflags);
00746 
00747   /* tcp_enqueue_flags is always called with either SYN or FIN in flags.
00748    * We need one available snd_buf byte to do that.
00749    * This means we can't send FIN while snd_buf==0. A better fix would be to
00750    * not include SYN and FIN sequence numbers in the snd_buf count. */
00751   if (pcb->snd_buf == 0) {
00752     LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: no send buffer available\n"));
00753     TCP_STATS_INC(tcp.memerr);
00754     return ERR_MEM;
00755   }
00756 
00757   /* Allocate pbuf with room for TCP header + options */
00758   if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
00759     pcb->flags |= TF_NAGLEMEMERR;
00760     TCP_STATS_INC(tcp.memerr);
00761     return ERR_MEM;
00762   }
00763   LWIP_ASSERT("tcp_enqueue_flags: check that first pbuf can hold optlen",
00764               (p->len >= optlen));
00765 
00766   /* Allocate memory for tcp_seg, and fill in fields. */
00767   if ((seg = tcp_create_segment(pcb, p, flags, pcb->snd_lbb, optflags)) == NULL) {
00768     pcb->flags |= TF_NAGLEMEMERR;
00769     TCP_STATS_INC(tcp.memerr);
00770     return ERR_MEM;
00771   }
00772   LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
00773   LWIP_ASSERT("tcp_enqueue_flags: invalid segment length", seg->len == 0);
00774 
00775   LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE,
00776               ("tcp_enqueue_flags: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n",
00777                ntohl(seg->tcphdr->seqno),
00778                ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),
00779                (u16_t)flags));
00780 
00781   /* Now append seg to pcb->unsent queue */
00782   if (pcb->unsent == NULL) {
00783     pcb->unsent = seg;
00784   } else {
00785     struct tcp_seg *useg;
00786     for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);
00787     useg->next = seg;
00788   }
00789 #if TCP_OVERSIZE
00790   /* The new unsent tail has no space */
00791   pcb->unsent_oversize = 0;
00792 #endif /* TCP_OVERSIZE */
00793 
00794   /* SYN and FIN bump the sequence number */
00795   if ((flags & TCP_SYN) || (flags & TCP_FIN)) {
00796     pcb->snd_lbb++;
00797     /* optlen does not influence snd_buf */
00798     pcb->snd_buf--;
00799   }
00800   if (flags & TCP_FIN) {
00801     pcb->flags |= TF_FIN;
00802   }
00803 
00804   /* update number of segments on the queues */
00805   pcb->snd_queuelen += pbuf_clen(seg->p);
00806   LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: %"S16_F" (after enqueued)\n", pcb->snd_queuelen));
00807   if (pcb->snd_queuelen != 0) {
00808     LWIP_ASSERT("tcp_enqueue_flags: invalid queue length",
00809       pcb->unacked != NULL || pcb->unsent != NULL);
00810   }
00811 
00812   return ERR_OK;
00813 }
00814  
00815 
00816 #if LWIP_TCP_TIMESTAMPS
00817 /* Build a timestamp option (12 bytes long) at the specified options pointer)
00818  *
00819  * @param pcb tcp_pcb
00820  * @param opts option pointer where to store the timestamp option
00821  */
00822 static void
00823 tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts)
00824 {
00825   /* Pad with two NOP options to make everything nicely aligned */
00826   opts[0] = PP_HTONL(0x0101080A);
00827   opts[1] = htonl(sys_now());
00828   opts[2] = htonl(pcb->ts_recent);
00829 }
00830 #endif
00831 
00836 err_t
00837 tcp_send_empty_ack(struct tcp_pcb *pcb)
00838 {
00839   struct pbuf *p;
00840   struct tcp_hdr *tcphdr;
00841   u8_t optlen = 0;
00842 
00843 #if LWIP_TCP_TIMESTAMPS
00844   if (pcb->flags & TF_TIMESTAMP) {
00845     optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
00846   }
00847 #endif
00848 
00849   p = tcp_output_alloc_header(pcb, optlen, 0, htonl(pcb->snd_nxt));
00850   if (p == NULL) {
00851     LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
00852     return ERR_BUF;
00853   }
00854   tcphdr = (struct tcp_hdr *)p->payload;
00855   LWIP_DEBUGF(TCP_OUTPUT_DEBUG, 
00856               ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));
00857   /* remove ACK flags from the PCB, as we send an empty ACK now */
00858   pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
00859 
00860   /* NB. MSS option is only sent on SYNs, so ignore it here */
00861 #if LWIP_TCP_TIMESTAMPS
00862   pcb->ts_lastacksent = pcb->rcv_nxt;
00863 
00864   if (pcb->flags & TF_TIMESTAMP) {
00865     tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1));
00866   }
00867 #endif 
00868 
00869 #if CHECKSUM_GEN_TCP
00870   tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
00871         IP_PROTO_TCP, p->tot_len);
00872 #endif
00873 #if LWIP_NETIF_HWADDRHINT
00874   ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
00875       IP_PROTO_TCP, &(pcb->addr_hint));
00876 #else /* LWIP_NETIF_HWADDRHINT*/
00877   ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
00878       IP_PROTO_TCP);
00879 #endif /* LWIP_NETIF_HWADDRHINT*/
00880   pbuf_free(p);
00881 
00882   return ERR_OK;
00883 }
00884 
00892 err_t
00893 tcp_output(struct tcp_pcb *pcb)
00894 {
00895   struct tcp_seg *seg, *useg;
00896   u32_t wnd, snd_nxt;
00897 #if TCP_CWND_DEBUG
00898   s16_t i = 0;
00899 #endif /* TCP_CWND_DEBUG */
00900 
00901   /* First, check if we are invoked by the TCP input processing
00902      code. If so, we do not output anything. Instead, we rely on the
00903      input processing code to call us when input processing is done
00904      with. */
00905   if (tcp_input_pcb == pcb) {
00906     return ERR_OK;
00907   }
00908 
00909   wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);
00910 
00911   seg = pcb->unsent;
00912 
00913   /* If the TF_ACK_NOW flag is set and no data will be sent (either
00914    * because the ->unsent queue is empty or because the window does
00915    * not allow it), construct an empty ACK segment and send it.
00916    *
00917    * If data is to be sent, we will just piggyback the ACK (see below).
00918    */
00919   if (pcb->flags & TF_ACK_NOW &&
00920      (seg == NULL ||
00921       ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
00922      return tcp_send_empty_ack(pcb);
00923   }
00924 
00925   /* useg should point to last segment on unacked queue */
00926   useg = pcb->unacked;
00927   if (useg != NULL) {
00928     for (; useg->next != NULL; useg = useg->next);
00929   }
00930 
00931 #if TCP_OUTPUT_DEBUG
00932   if (seg == NULL) {
00933     LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n",
00934                                    (void*)pcb->unsent));
00935   }
00936 #endif /* TCP_OUTPUT_DEBUG */
00937 #if TCP_CWND_DEBUG
00938   if (seg == NULL) {
00939     LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F
00940                                  ", cwnd %"U16_F", wnd %"U32_F
00941                                  ", seg == NULL, ack %"U32_F"\n",
00942                                  pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack));
00943   } else {
00944     LWIP_DEBUGF(TCP_CWND_DEBUG, 
00945                 ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F
00946                  ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n",
00947                  pcb->snd_wnd, pcb->cwnd, wnd,
00948                  ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
00949                  ntohl(seg->tcphdr->seqno), pcb->lastack));
00950   }
00951 #endif /* TCP_CWND_DEBUG */
00952   /* data available and window allows it to be sent? */
00953   while (seg != NULL &&
00954          ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
00955     LWIP_ASSERT("RST not expected here!", 
00956                 (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0);
00957     /* Stop sending if the nagle algorithm would prevent it
00958      * Don't stop:
00959      * - if tcp_write had a memory error before (prevent delayed ACK timeout) or
00960      * - if FIN was already enqueued for this PCB (SYN is always alone in a segment -
00961      *   either seg->next != NULL or pcb->unacked == NULL;
00962      *   RST is no sent using tcp_write/tcp_output.
00963      */
00964     if((tcp_do_output_nagle(pcb) == 0) &&
00965       ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)){
00966       break;
00967     }
00968 #if TCP_CWND_DEBUG
00969     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",
00970                             pcb->snd_wnd, pcb->cwnd, wnd,
00971                             ntohl(seg->tcphdr->seqno) + seg->len -
00972                             pcb->lastack,
00973                             ntohl(seg->tcphdr->seqno), pcb->lastack, i));
00974     ++i;
00975 #endif /* TCP_CWND_DEBUG */
00976 
00977     pcb->unsent = seg->next;
00978 
00979     if (pcb->state != SYN_SENT) {
00980       TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);
00981       pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
00982     }
00983 
00984     tcp_output_segment(seg, pcb);
00985     snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
00986     if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) {
00987       pcb->snd_nxt = snd_nxt;
00988     }
00989     /* put segment on unacknowledged list if length > 0 */
00990     if (TCP_TCPLEN(seg) > 0) {
00991       seg->next = NULL;
00992       /* unacked list is empty? */
00993       if (pcb->unacked == NULL) {
00994         pcb->unacked = seg;
00995         useg = seg;
00996       /* unacked list is not empty? */
00997       } else {
00998         /* In the case of fast retransmit, the packet should not go to the tail
00999          * of the unacked queue, but rather somewhere before it. We need to check for
01000          * this case. -STJ Jul 27, 2004 */
01001         if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))) {
01002           /* add segment to before tail of unacked list, keeping the list sorted */
01003           struct tcp_seg **cur_seg = &(pcb->unacked);
01004           while (*cur_seg &&
01005             TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) {
01006               cur_seg = &((*cur_seg)->next );
01007           }
01008           seg->next = (*cur_seg);
01009           (*cur_seg) = seg;
01010         } else {
01011           /* add segment to tail of unacked list */
01012           useg->next = seg;
01013           useg = useg->next;
01014         }
01015       }
01016     /* do not queue empty segments on the unacked list */
01017     } else {
01018       tcp_seg_free(seg);
01019     }
01020     seg = pcb->unsent;
01021   }
01022 #if TCP_OVERSIZE
01023   if (pcb->unsent == NULL) {
01024     /* last unsent has been removed, reset unsent_oversize */
01025     pcb->unsent_oversize = 0;
01026   }
01027 #endif /* TCP_OVERSIZE */
01028 
01029   if (seg != NULL && pcb->persist_backoff == 0 && 
01030       ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) {
01031     /* prepare for persist timer */
01032     pcb->persist_cnt = 0;
01033     pcb->persist_backoff = 1;
01034   }
01035 
01036   pcb->flags &= ~TF_NAGLEMEMERR;
01037   return ERR_OK;
01038 }
01039 
01046 static void
01047 tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
01048 {
01049   u16_t len;
01050   struct netif *netif;
01051   u32_t *opts;
01052 
01054   snmp_inc_tcpoutsegs();
01055 
01056   /* The TCP header has already been constructed, but the ackno and
01057    wnd fields remain. */
01058   seg->tcphdr->ackno = htonl(pcb->rcv_nxt);
01059 
01060   /* advertise our receive window size in this TCP segment */
01061   seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd);
01062 
01063   pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
01064 
01065   /* Add any requested options.  NB MSS option is only set on SYN
01066      packets, so ignore it here */
01067   LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
01068   opts = (u32_t *)(void *)(seg->tcphdr + 1);
01069   if (seg->flags & TF_SEG_OPTS_MSS) {
01070     TCP_BUILD_MSS_OPTION(*opts);
01071     opts += 1;
01072   }
01073 #if LWIP_TCP_TIMESTAMPS
01074   pcb->ts_lastacksent = pcb->rcv_nxt;
01075 
01076   if (seg->flags & TF_SEG_OPTS_TS) {
01077     tcp_build_timestamp_option(pcb, opts);
01078     opts += 3;
01079   }
01080 #endif
01081 
01082   /* Set retransmission timer running if it is not currently enabled 
01083      This must be set before checking the route. */
01084   if (pcb->rtime == -1) {
01085     pcb->rtime = 0;
01086   }
01087 
01088   /* If we don't have a local IP address, we get one by
01089      calling ip_route(). */
01090   if (ip_addr_isany(&(pcb->local_ip))) {
01091     netif = ip_route(&(pcb->remote_ip));
01092     if (netif == NULL) {
01093       return;
01094     }
01095     ip_addr_copy(pcb->local_ip, netif->ip_addr);
01096   }
01097 
01098   if (pcb->rttest == 0) {
01099     pcb->rttest = tcp_ticks;
01100     pcb->rtseq = ntohl(seg->tcphdr->seqno);
01101 
01102     LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq));
01103   }
01104   LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n",
01105           htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +
01106           seg->len));
01107 
01108   len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);
01109 
01110   seg->p->len -= len;
01111   seg->p->tot_len -= len;
01112 
01113   seg->p->payload = seg->tcphdr;
01114 
01115   seg->tcphdr->chksum = 0;
01116 #if CHECKSUM_GEN_TCP
01117 #if TCP_CHECKSUM_ON_COPY
01118   {
01119     u32_t acc;
01120 #if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
01121     u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
01122            &(pcb->remote_ip),
01123            IP_PROTO_TCP, seg->p->tot_len);
01124 #endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
01125     if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) {
01126       LWIP_ASSERT("data included but not checksummed",
01127         seg->p->tot_len == (TCPH_HDRLEN(seg->tcphdr) * 4));
01128     }
01129 
01130     /* rebuild TCP header checksum (TCP header changes for retransmissions!) */
01131     acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip),
01132              &(pcb->remote_ip),
01133              IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);
01134     /* add payload checksum */
01135     if (seg->chksum_swapped) {
01136       seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum);
01137       seg->chksum_swapped = 0;
01138     }
01139     acc += (u16_t)~(seg->chksum);
01140     seg->tcphdr->chksum = FOLD_U32T(acc);
01141 #if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
01142     if (chksum_slow != seg->tcphdr->chksum) {
01143       LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING,
01144                   ("tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"\n",
01145                   seg->tcphdr->chksum, chksum_slow));
01146       seg->tcphdr->chksum = chksum_slow;
01147     }
01148 #endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
01149   }
01150 #else /* TCP_CHECKSUM_ON_COPY */
01151   seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
01152          &(pcb->remote_ip),
01153          IP_PROTO_TCP, seg->p->tot_len);
01154 #endif /* TCP_CHECKSUM_ON_COPY */
01155 #endif /* CHECKSUM_GEN_TCP */
01156   TCP_STATS_INC(tcp.xmit);
01157 
01158 #if LWIP_NETIF_HWADDRHINT
01159   ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
01160       IP_PROTO_TCP, &(pcb->addr_hint));
01161 #else /* LWIP_NETIF_HWADDRHINT*/
01162   ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
01163       IP_PROTO_TCP);
01164 #endif /* LWIP_NETIF_HWADDRHINT*/
01165 }
01166 
01187 void
01188 tcp_rst(u32_t seqno, u32_t ackno,
01189   ip_addr_t *local_ip, ip_addr_t *remote_ip,
01190   u16_t local_port, u16_t remote_port)
01191 {
01192   struct pbuf *p;
01193   struct tcp_hdr *tcphdr;
01194   p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
01195   if (p == NULL) {
01196       LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));
01197       return;
01198   }
01199   LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
01200               (p->len >= sizeof(struct tcp_hdr)));
01201 
01202   tcphdr = (struct tcp_hdr *)p->payload;
01203   tcphdr->src = htons(local_port);
01204   tcphdr->dest = htons(remote_port);
01205   tcphdr->seqno = htonl(seqno);
01206   tcphdr->ackno = htonl(ackno);
01207   TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK);
01208   tcphdr->wnd = PP_HTONS(TCP_WND);
01209   tcphdr->chksum = 0;
01210   tcphdr->urgp = 0;
01211 
01212 #if CHECKSUM_GEN_TCP
01213   tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,
01214               IP_PROTO_TCP, p->tot_len);
01215 #endif
01216   TCP_STATS_INC(tcp.xmit);
01217   snmp_inc_tcpoutrsts();
01218    /* Send output with hardcoded TTL since we have no access to the pcb */
01219   ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);
01220   pbuf_free(p);
01221   LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));
01222 }
01223 
01231 void
01232 tcp_rexmit_rto(struct tcp_pcb *pcb)
01233 {
01234   struct tcp_seg *seg;
01235 
01236   if (pcb->unacked == NULL) {
01237     return;
01238   }
01239 
01240   /* Move all unacked segments to the head of the unsent queue */
01241   for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
01242   /* concatenate unsent queue after unacked queue */
01243   seg->next = pcb->unsent;
01244   /* unsent queue is the concatenated queue (of unacked, unsent) */
01245   pcb->unsent = pcb->unacked;
01246   /* unacked queue is now empty */
01247   pcb->unacked = NULL;
01248 
01249   /* increment number of retransmissions */
01250   ++pcb->nrtx;
01251 
01252   /* Don't take any RTT measurements after retransmitting. */
01253   pcb->rttest = 0;
01254 
01255   /* Do the actual retransmission */
01256   tcp_output(pcb);
01257 }
01258 
01266 void
01267 tcp_rexmit(struct tcp_pcb *pcb)
01268 {
01269   struct tcp_seg *seg;
01270   struct tcp_seg **cur_seg;
01271 
01272   if (pcb->unacked == NULL) {
01273     return;
01274   }
01275 
01276   /* Move the first unacked segment to the unsent queue */
01277   /* Keep the unsent queue sorted. */
01278   seg = pcb->unacked;
01279   pcb->unacked = seg->next;
01280 
01281   cur_seg = &(pcb->unsent);
01282   while (*cur_seg &&
01283     TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) {
01284       cur_seg = &((*cur_seg)->next );
01285   }
01286   seg->next = *cur_seg;
01287   *cur_seg = seg;
01288 
01289   ++pcb->nrtx;
01290 
01291   /* Don't take any rtt measurements after retransmitting. */
01292   pcb->rttest = 0;
01293 
01294   /* Do the actual retransmission. */
01295   snmp_inc_tcpretranssegs();
01296   /* No need to call tcp_output: we are always called from tcp_input()
01297      and thus tcp_output directly returns. */
01298 }
01299 
01300 
01306 void 
01307 tcp_rexmit_fast(struct tcp_pcb *pcb)
01308 {
01309   if (pcb->unacked != NULL && !(pcb->flags & TF_INFR)) {
01310     /* This is fast retransmit. Retransmit the first unacked segment. */
01311     LWIP_DEBUGF(TCP_FR_DEBUG, 
01312                 ("tcp_receive: dupacks %"U16_F" (%"U32_F
01313                  "), fast retransmit %"U32_F"\n",
01314                  (u16_t)pcb->dupacks, pcb->lastack,
01315                  ntohl(pcb->unacked->tcphdr->seqno)));
01316     tcp_rexmit(pcb);
01317 
01318     /* Set ssthresh to half of the minimum of the current
01319      * cwnd and the advertised window */
01320     if (pcb->cwnd > pcb->snd_wnd) {
01321       pcb->ssthresh = pcb->snd_wnd / 2;
01322     } else {
01323       pcb->ssthresh = pcb->cwnd / 2;
01324     }
01325     
01326     /* The minimum value for ssthresh should be 2 MSS */
01327     if (pcb->ssthresh < 2*pcb->mss) {
01328       LWIP_DEBUGF(TCP_FR_DEBUG, 
01329                   ("tcp_receive: The minimum value for ssthresh %"U16_F
01330                    " should be min 2 mss %"U16_F"...\n",
01331                    pcb->ssthresh, 2*pcb->mss));
01332       pcb->ssthresh = 2*pcb->mss;
01333     }
01334     
01335     pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
01336     pcb->flags |= TF_INFR;
01337   } 
01338 }
01339 
01340 
01349 void
01350 tcp_keepalive(struct tcp_pcb *pcb)
01351 {
01352   struct pbuf *p;
01353   struct tcp_hdr *tcphdr;
01354 
01355   LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
01356                           ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
01357                           ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
01358 
01359   LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F"   pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", 
01360                           tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
01361    
01362   p = tcp_output_alloc_header(pcb, 0, 0, htonl(pcb->snd_nxt - 1));
01363   if(p == NULL) {
01364     LWIP_DEBUGF(TCP_DEBUG, 
01365                 ("tcp_keepalive: could not allocate memory for pbuf\n"));
01366     return;
01367   }
01368   tcphdr = (struct tcp_hdr *)p->payload;
01369 
01370 #if CHECKSUM_GEN_TCP
01371   tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
01372                                       IP_PROTO_TCP, p->tot_len);
01373 #endif
01374   TCP_STATS_INC(tcp.xmit);
01375 
01376   /* Send output to IP */
01377 #if LWIP_NETIF_HWADDRHINT
01378   ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
01379     &(pcb->addr_hint));
01380 #else /* LWIP_NETIF_HWADDRHINT*/
01381   ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
01382 #endif /* LWIP_NETIF_HWADDRHINT*/
01383 
01384   pbuf_free(p);
01385 
01386   LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n",
01387                           pcb->snd_nxt - 1, pcb->rcv_nxt));
01388 }
01389 
01390 
01399 void
01400 tcp_zero_window_probe(struct tcp_pcb *pcb)
01401 {
01402   struct pbuf *p;
01403   struct tcp_hdr *tcphdr;
01404   struct tcp_seg *seg;
01405   u16_t len;
01406   u8_t is_fin;
01407 
01408   LWIP_DEBUGF(TCP_DEBUG, 
01409               ("tcp_zero_window_probe: sending ZERO WINDOW probe to %"
01410                U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
01411                ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
01412                ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
01413 
01414   LWIP_DEBUGF(TCP_DEBUG, 
01415               ("tcp_zero_window_probe: tcp_ticks %"U32_F
01416                "   pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", 
01417                tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
01418 
01419   seg = pcb->unacked;
01420 
01421   if(seg == NULL) {
01422     seg = pcb->unsent;
01423   }
01424   if(seg == NULL) {
01425     return;
01426   }
01427 
01428   is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0);
01429   /* we want to send one seqno: either FIN or data (no options) */
01430   len = is_fin ? 0 : 1;
01431 
01432   p = tcp_output_alloc_header(pcb, 0, len, seg->tcphdr->seqno);
01433   if(p == NULL) {
01434     LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n"));
01435     return;
01436   }
01437   tcphdr = (struct tcp_hdr *)p->payload;
01438 
01439   if (is_fin) {
01440     /* FIN segment, no data */
01441     TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN);
01442   } else {
01443     /* Data segment, copy in one byte from the head of the unacked queue */
01444     struct tcp_hdr *thdr = (struct tcp_hdr *)seg->p->payload;
01445     char *d = ((char *)p->payload + TCP_HLEN);
01446     pbuf_copy_partial(seg->p, d, 1, TCPH_HDRLEN(thdr) * 4);
01447   }
01448 
01449 #if CHECKSUM_GEN_TCP
01450   tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
01451                                       IP_PROTO_TCP, p->tot_len);
01452 #endif
01453   TCP_STATS_INC(tcp.xmit);
01454 
01455   /* Send output to IP */
01456 #if LWIP_NETIF_HWADDRHINT
01457   ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
01458     &(pcb->addr_hint));
01459 #else /* LWIP_NETIF_HWADDRHINT*/
01460   ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
01461 #endif /* LWIP_NETIF_HWADDRHINT*/
01462 
01463   pbuf_free(p);
01464 
01465   LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F
01466                           " ackno %"U32_F".\n",
01467                           pcb->snd_nxt - 1, pcb->rcv_nxt));
01468 }
01469 #endif /* LWIP_TCP */

Generated on Sat May 26 2012 04:34:59 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.