Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

tcp_out.c

Go to the documentation of this file.
00001 
00006 /*
00007  * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
00008  * All rights reserved. 
00009  * 
00010  * Redistribution and use in source and binary forms, with or without modification, 
00011  * are permitted provided that the following conditions are met:
00012  *
00013  * 1. Redistributions of source code must retain the above copyright notice,
00014  *    this list of conditions and the following disclaimer.
00015  * 2. Redistributions in binary form must reproduce the above copyright notice,
00016  *    this list of conditions and the following disclaimer in the documentation
00017  *    and/or other materials provided with the distribution.
00018  * 3. The name of the author may not be used to endorse or promote products
00019  *    derived from this software without specific prior written permission. 
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
00022  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
00023  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
00024  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00025  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
00026  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
00027  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
00028  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
00029  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
00030  * OF SUCH DAMAGE.
00031  *
00032  * This file is part of the lwIP TCP/IP stack.
00033  * 
00034  * Author: Adam Dunkels <adam@sics.se>
00035  *
00036  * CHANGELOG: this file has been modified by Sergio Perez Alcañiz <serpeal@disca.upv.es> 
00037  *            Departamento de Informática de Sistemas y Computadores          
00038  *            Universidad Politécnica de Valencia                             
00039  *            Valencia (Spain)    
00040  *            Date: April 2003                                          
00041  *  
00042  */
00043 
00044 /*-----------------------------------------------------------------------------------*/
00045 /* tcp_output.c
00046  *
00047  * The output functions of TCP.
00048  *
00049  */
00050 /*-----------------------------------------------------------------------------------*/
00051 
00052 
00053 #include "lwip/def.h"
00054 #include "lwip/opt.h"
00055 
00056 #include "lwip/mem.h"
00057 #include "lwip/memp.h"
00058 #include "lwip/sys.h"
00059 
00060 #include "lwip/netif.h"
00061 
00062 #include "lwip/inet.h"
00063 #include "lwip/tcp.h"
00064 
00065 #include "lwip/stats.h"
00066 
00067 #if LWIP_TCP
00068 #define MIN(x,y) (x) < (y)? (x): (y)
00069 
00070 #define htons HTONS
00071 #define htonl HTONL
00072 
00073 /* Forward declarations.*/
00074 static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
00075 
00076 
00077 /*-----------------------------------------------------------------------------------*/
00078 err_t
00079 tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags)
00080 {
00081   return tcp_enqueue(pcb, NULL, 0, flags, 1, NULL, 0);
00082 
00083 }
00084 /*-----------------------------------------------------------------------------------*/
00085 err_t
00086 tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy)
00087 {
00088   DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, arg=%p, len=%u, copy=%d)\n", (void *)pcb, arg, len, copy));
00089   if(pcb->state == SYN_SENT ||
00090      pcb->state == SYN_RCVD ||
00091      pcb->state == ESTABLISHED ||
00092      pcb->state == CLOSE_WAIT) {
00093     if(len > 0) {
00094       return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0);
00095     }
00096     return ERR_OK;
00097   } else {
00098     DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write() called in invalid state\n"));
00099     return ERR_CONN;
00100   }
00101 }
00102 /*-----------------------------------------------------------------------------------*/
00103 err_t
00104 tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
00105             u8_t flags, u8_t copy,
00106             u8_t *optdata, u8_t optlen)
00107 {
00108   struct pbuf *p;
00109   struct tcp_seg *seg, *useg, *queue;
00110   u32_t left, seqno;
00111   u16_t seglen;
00112   void *ptr;
00113   u8_t queuelen;
00114 
00115   DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue(pcb=%p, arg=%p, len=%u, flags=%x, copy=%d)\n", (void *)pcb, arg, len, flags, copy));
00116   left = len;
00117   ptr = arg;
00118   /* fail on too much data */
00119   if(len > pcb->snd_buf) {
00120     DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: too much data (len=%d > snd_buf=%d)\n", len, pcb->snd_buf));
00121     return ERR_MEM;
00122   }
00123 
00124   /* seqno will be the sequence number of the first segment enqueued
00125   by the call to this function. */
00126   seqno = pcb->snd_lbb;
00127 
00128     queue = NULL;
00129   DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %d\n", pcb->snd_queuelen));
00130 
00131   /* Check if the queue length exceeds the configured maximum queue
00132   length. If so, we return an error. */
00133   queuelen = pcb->snd_queuelen;
00134   if(queuelen >= TCP_SND_QUEUELEN) {
00135     DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: too long queue %d (max %d)\n", queuelen, TCP_SND_QUEUELEN));
00136     goto memerr;
00137   }   
00138 
00139   if(pcb->snd_queuelen != 0) {
00140     LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
00141     pcb->unsent != NULL);      
00142   }
00143 
00144   seg = NULL;
00145   seglen = 0;
00146 
00147   /* First, break up the data into segments and tuck them together in
00148   the local "queue" variable. */
00149   while(queue == NULL || left > 0) {
00150 
00151     /* The segment length should be the MSS if the data to be enqueued
00152     is larger than the MSS. */
00153     seglen = left > pcb->mss? pcb->mss: left;
00154 
00155     /* Allocate memory for tcp_seg, and fill in fields. */
00156     seg = memp_malloc(MEMP_TCP_SEG);
00157     if(seg == NULL) {
00158       DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for tcp_seg\n"));
00159       goto memerr;
00160     }
00161     seg->next = NULL;
00162     seg->p = NULL;
00163 
00164     if(queue == NULL) {
00165       queue = seg;
00166     }
00167     else {
00168       /* Attach the segment to the end of the queued segments. */
00169       for(useg = queue; useg->next != NULL; useg = useg->next);
00170       useg->next = seg;
00171     }
00172 
00173     /* If copy is set, memory should be allocated
00174     and data copied into pbuf, otherwise data comes from
00175     ROM or other static memory, and need not be copied. If
00176     optdata is != NULL, we have options instead of data. */
00177     if (optdata != NULL) {
00178       if((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
00179         goto memerr;
00180       }
00181       ++queuelen;
00182       seg->dataptr = seg->p->payload;
00183     }
00184     else if (copy) {
00185       if((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) {
00186         DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for pbuf copy size %u\n", seglen));     
00187         goto memerr;
00188       }
00189       ++queuelen;
00190       if(arg != NULL) {
00191         memcpy(seg->p->payload, ptr, seglen);
00192       }
00193       seg->dataptr = seg->p->payload;
00194     }
00195     /* do not copy data */
00196     else {
00197 
00198       /* first, allocate a pbuf for holding the data.
00199        * since the referenced data is available at least until it is sent out on the
00200        * link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM
00201        * instead of PBUF_REF here.
00202        */
00203       if((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {
00204         DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n"));                
00205         goto memerr;
00206       }
00207       ++queuelen;
00208       p->payload = ptr;
00209       seg->dataptr = ptr;
00210 
00211       /* Second, allocate a pbuf for the headers. */
00212       if((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) {
00213         /* If allocation fails, we have to deallocate the data pbuf as
00214            well. */
00215         pbuf_free(p);
00216         DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for header pbuf\n"));           
00217         goto memerr;
00218       }
00219       ++queuelen;
00220 
00221       /* Chain the headers and data pbufs together. */
00222       pbuf_chain(seg->p, p);
00223     }
00224 
00225     /* Now that there are more segments queued, we check again if the
00226     length of the queue exceeds the configured maximum. */
00227     if(queuelen > TCP_SND_QUEUELEN) {
00228       DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: queue too long %d (%d)\n", queuelen, TCP_SND_QUEUELEN));  
00229       goto memerr;
00230     }
00231 
00232     seg->len = seglen;
00233     /*    if((flags & TCP_SYN) || (flags & TCP_FIN)) { 
00234     ++seg->len;
00235     }*/
00236 
00237     /* Build TCP header. */
00238     if(pbuf_header(seg->p, TCP_HLEN)) {
00239 
00240       DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: no room for TCP header in pbuf.\n"));
00241 
00242 #ifdef TCP_STATS
00243       ++lwip_stats.tcp.err;
00244 #endif /* TCP_STATS */
00245       goto memerr;
00246     }
00247     seg->tcphdr = seg->p->payload;
00248     seg->tcphdr->src = htons(pcb->local_port);
00249     seg->tcphdr->dest = htons(pcb->remote_port);
00250     seg->tcphdr->seqno = htonl(seqno);
00251     seg->tcphdr->urgp = 0;
00252     TCPH_FLAGS_SET(seg->tcphdr, flags);
00253     /* don't fill in tcphdr->ackno and tcphdr->wnd until later */
00254 
00255     /* Copy the options into the header, if they are present. */
00256     if(optdata == NULL) {
00257       TCPH_OFFSET_SET(seg->tcphdr, 5 << 4);
00258     }
00259     else {
00260       TCPH_OFFSET_SET(seg->tcphdr, (5 + optlen / 4) << 4);
00261       /* Copy options into data portion of segment.
00262        Options can thus only be sent in non data carrying
00263        segments such as SYN|ACK. */
00264       memcpy(seg->dataptr, optdata, optlen);
00265     }
00266     DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: queueing %lu:%lu (0x%x)\n",
00267       ntohl(seg->tcphdr->seqno),
00268       ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),
00269       flags));
00270 
00271     left -= seglen;
00272     seqno += seglen;
00273     ptr = (void *)((char *)ptr + seglen);
00274   }
00275 
00276 
00277   /* Now that the data to be enqueued has been broken up into TCP
00278   segments in the queue variable, we add them to the end of the
00279   pcb->unsent queue. */
00280   if(pcb->unsent == NULL) {
00281     useg = NULL;
00282   }
00283   else {
00284     for(useg = pcb->unsent; useg->next != NULL; useg = useg->next);
00285   }
00286 
00287   /* If there is room in the last pbuf on the unsent queue,
00288   chain the first pbuf on the queue together with that. */
00289   if(useg != NULL &&
00290     TCP_TCPLEN(useg) != 0 &&
00291     !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&
00292     !(flags & (TCP_SYN | TCP_FIN)) &&
00293     useg->len + queue->len <= pcb->mss) {
00294     /* Remove TCP header from first segment. */
00295     pbuf_header(queue->p, -TCP_HLEN);
00296     pbuf_chain(useg->p, queue->p);
00297     useg->len += queue->len;
00298     useg->next = queue->next;
00299 
00300     DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: chaining, new len %u\n", useg->len));
00301     if(seg == queue) {
00302       seg = NULL;
00303     }
00304     memp_free(MEMP_TCP_SEG, queue);
00305   }
00306   else {      
00307     if(useg == NULL) {
00308       pcb->unsent = queue;
00309 
00310     }
00311     else {
00312       useg->next = queue;
00313     }
00314   }
00315   if((flags & TCP_SYN) || (flags & TCP_FIN)) {
00316     ++len;
00317   }
00318   pcb->snd_lbb += len;
00319   pcb->snd_buf -= len;
00320   pcb->snd_queuelen = queuelen;
00321   DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d (after enqueued)\n", pcb->snd_queuelen));
00322   if(pcb->snd_queuelen != 0) {
00323     LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
00324       pcb->unsent != NULL);
00325 
00326   }
00327 
00328   /* Set the PSH flag in the last segment that we enqueued, but only
00329   if the segment has data (indicated by seglen > 0). */
00330   if(seg != NULL && seglen > 0 && seg->tcphdr != NULL) {
00331     TCPH_FLAGS_SET(seg->tcphdr, TCPH_FLAGS(seg->tcphdr) | TCP_PSH);
00332   }
00333 
00334   return ERR_OK;
00335   memerr:
00336 #ifdef TCP_STATS
00337   ++lwip_stats.tcp.memerr;
00338 #endif /* TCP_STATS */
00339 
00340   if(queue != NULL) {
00341     tcp_segs_free(queue);
00342   }
00343   if(pcb->snd_queuelen != 0) {
00344     LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
00345       pcb->unsent != NULL);
00346 
00347   }
00348   DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d (with mem err)\n", pcb->snd_queuelen));
00349   return ERR_MEM;
00350 }
00351 /*-----------------------------------------------------------------------------------*/
00352 /* find out what we can send and send it */
00353 err_t
00354 tcp_output(struct tcp_pcb *pcb)
00355 {
00356   struct pbuf *p;
00357   struct tcp_hdr *tcphdr;
00358   struct tcp_seg *seg, *useg;
00359   u32_t wnd;
00360 #if TCP_CWND_DEBUG
00361   int i = 0;
00362 #endif /* TCP_CWND_DEBUG */
00363 
00364   /* First, check if we are invoked by the TCP input processing
00365      code. If so, we do not output anything. Instead, we rely on the
00366      input processing code to call us when input processing is done
00367      with. */
00368   if(tcp_input_pcb == pcb) {
00369     return ERR_OK;
00370   }
00371   
00372   wnd = MIN(pcb->snd_wnd, pcb->cwnd);
00373 
00374   
00375   seg = pcb->unsent;
00376 
00377   /* If the TF_ACK_NOW flag is set, we check if there is data that is
00378      to be sent. If data is to be sent out, we'll just piggyback our
00379      acknowledgement with the outgoing segment. If no data will be
00380      sent (either because the ->unsent queue is empty or because the
00381      window doesn't allow it) we'll have to construct an empty ACK
00382      segment and send it. */
00383   if(pcb->flags & TF_ACK_NOW &&
00384      (seg == NULL ||
00385       ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
00386     pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
00387     p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
00388     if(p == NULL) {
00389       DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
00390       return ERR_BUF;
00391     }
00392     DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: sending ACK for %lu\n", pcb->rcv_nxt));    
00393     
00394     tcphdr = p->payload;
00395     tcphdr->src = htons(pcb->local_port);
00396     tcphdr->dest = htons(pcb->remote_port);
00397     tcphdr->seqno = htonl(pcb->snd_nxt);
00398     tcphdr->ackno = htonl(pcb->rcv_nxt);
00399     TCPH_FLAGS_SET(tcphdr, TCP_ACK);
00400     tcphdr->wnd = htons(pcb->rcv_wnd);
00401     tcphdr->urgp = 0;
00402     TCPH_OFFSET_SET(tcphdr, 5 << 4);
00403     
00404     tcphdr->chksum = 0;
00405     tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
00406                                         IP_PROTO_TCP, p->tot_len);
00407 
00408     ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), TCP_TTL,
00409               IP_PROTO_TCP);
00410     pbuf_free(p);
00411 
00412     return ERR_OK;
00413   } 
00414   
00415 #if TCP_OUTPUT_DEBUG
00416   if(seg == NULL) {
00417     DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", pcb->unsent));
00418   }
00419 #endif /* TCP_OUTPUT_DEBUG */
00420 #if TCP_CWND_DEBUG
00421   if(seg == NULL) {
00422     DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %lu, cwnd %lu, wnd %lu, seg == NULL, ack %lu\n",
00423                             pcb->snd_wnd, pcb->cwnd, wnd,
00424                             pcb->lastack));
00425   } else {
00426     DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %lu, cwnd %lu, wnd %lu, effwnd %lu, seq %lu, ack %lu\n",
00427                             pcb->snd_wnd, pcb->cwnd, wnd,
00428                             ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
00429                             ntohl(seg->tcphdr->seqno), pcb->lastack));
00430   }
00431 #endif /* TCP_CWND_DEBUG */
00432   
00433   while(seg != NULL &&
00434         ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
00435 #if TCP_CWND_DEBUG
00436     DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %lu, cwnd %lu, wnd %lu, effwnd %lu, seq %lu, ack %lu, i%d\n",
00437                             pcb->snd_wnd, pcb->cwnd, wnd,
00438                             ntohl(seg->tcphdr->seqno) + seg->len -
00439                             pcb->lastack,
00440                             ntohl(seg->tcphdr->seqno), pcb->lastack, i));
00441     ++i;
00442 #endif /* TCP_CWND_DEBUG */
00443 
00444     pcb->unsent = seg->next;
00445     
00446     if(pcb->state != SYN_SENT) {
00447       TCPH_FLAGS_SET(seg->tcphdr, TCPH_FLAGS(seg->tcphdr) | TCP_ACK);
00448       pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
00449     }
00450     
00451     tcp_output_segment(seg, pcb);
00452     pcb->snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
00453     if(TCP_SEQ_LT(pcb->snd_max, pcb->snd_nxt)) {
00454       pcb->snd_max = pcb->snd_nxt;
00455     }
00456     /* put segment on unacknowledged list if length > 0 */
00457     if(TCP_TCPLEN(seg) > 0) {
00458       seg->next = NULL;
00459       if(pcb->unacked == NULL) {
00460         pcb->unacked = seg;
00461         
00462         
00463       } else {
00464         for(useg = pcb->unacked; useg->next != NULL; useg = useg->next);
00465         useg->next = seg;
00466       }
00467     } else {
00468       tcp_seg_free(seg);
00469     }
00470     seg = pcb->unsent;
00471   }  
00472   return ERR_OK;
00473 }
00474 /*-----------------------------------------------------------------------------------*/
00475 static void
00476 tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
00477 {
00478   u16_t len;
00479   struct netif *netif;
00480 
00481   /* The TCP header has already been constructed, but the ackno and
00482    wnd fields remain. */
00483   seg->tcphdr->ackno = htonl(pcb->rcv_nxt);
00484 
00485   /* silly window avoidance */
00486   if(pcb->rcv_wnd < pcb->mss) {
00487     seg->tcphdr->wnd = 0;
00488   } else {
00489     /* advertise our receive window size in this TCP segment */
00490     seg->tcphdr->wnd = htons(pcb->rcv_wnd);
00491   }
00492 
00493   /* If we don't have a local IP address, we get one by
00494      calling ip_route(). */
00495   if(ip_addr_isany(&(pcb->local_ip))) {
00496     netif = ip_route(&(pcb->remote_ip));
00497     if(netif == NULL) {
00498       return;
00499     }
00500     ip_addr_set(&(pcb->local_ip), &(netif->ip_addr));
00501   }
00502 
00503   pcb->rtime = 0;
00504   
00505   if(pcb->rttest == 0) {
00506     pcb->rttest = tcp_ticks;
00507     pcb->rtseq = ntohl(seg->tcphdr->seqno);
00508 
00509     DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %lu\n", pcb->rtseq));
00510   }
00511   DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %lu:%lu\n",
00512                             htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +
00513                             seg->len));
00514 
00515   len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);
00516   
00517   seg->p->len -= len;
00518   seg->p->tot_len -= len;
00519   
00520   seg->p->payload = seg->tcphdr;
00521     
00522   seg->tcphdr->chksum = 0;
00523   seg->tcphdr->chksum = inet_chksum_pseudo(seg->p,
00524                                            &(pcb->local_ip),
00525                                            &(pcb->remote_ip),
00526                                            IP_PROTO_TCP, seg->p->tot_len);
00527 #ifdef TCP_STATS
00528   ++lwip_stats.tcp.xmit;
00529 #endif /* TCP_STATS */
00530 
00531   ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), TCP_TTL,
00532             IP_PROTO_TCP);
00533 }
00534 /*-----------------------------------------------------------------------------------*/
00535 void
00536 tcp_rst(u32_t seqno, u32_t ackno,
00537         struct ip_addr *local_ip, struct ip_addr *remote_ip,
00538         u16_t local_port, u16_t remote_port)
00539 {
00540   struct pbuf *p;
00541   struct tcp_hdr *tcphdr;
00542   p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
00543   if(p == NULL) {
00544       DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));
00545       return;
00546   }
00547 
00548   tcphdr = p->payload;
00549   tcphdr->src = htons(local_port);
00550   tcphdr->dest = htons(remote_port);
00551   tcphdr->seqno = htonl(seqno);
00552   tcphdr->ackno = htonl(ackno);
00553   TCPH_FLAGS_SET(tcphdr, TCP_RST | TCP_ACK);
00554   tcphdr->wnd = htons(TCP_WND);
00555   tcphdr->urgp = 0;
00556   TCPH_OFFSET_SET(tcphdr, 5 << 4);
00557   
00558   tcphdr->chksum = 0;
00559   tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,
00560                                       IP_PROTO_TCP, p->tot_len);
00561 
00562 #ifdef TCP_STATS
00563   ++lwip_stats.tcp.xmit;
00564 #endif /* TCP_STATS */
00565   ip_output(p, local_ip, remote_ip, TCP_TTL, IP_PROTO_TCP);
00566   pbuf_free(p);
00567   DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %lu ackno %lu.\n", seqno, ackno));
00568 }
00569 /*-----------------------------------------------------------------------------------*/
00570 void
00571 tcp_rexmit(struct tcp_pcb *pcb)
00572 {
00573   struct tcp_seg *seg;
00574 
00575   if(pcb->unacked == NULL) {
00576     return;
00577   }
00578   
00579   /* Move all unacked segments to the unsent queue. */
00580   for(seg = pcb->unacked; seg->next != NULL; seg = seg->next);
00581   
00582   seg->next = pcb->unsent;
00583   pcb->unsent = pcb->unacked;
00584   
00585   pcb->unacked = NULL;
00586   
00587   
00588   pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
00589   
00590   ++pcb->nrtx;
00591   
00592   /* Don't take any rtt measurements after retransmitting. */    
00593   pcb->rttest = 0;
00594   
00595   /* Do the actual retransmission. */
00596   tcp_output(pcb);
00597 
00598 }
00599 #endif /* LWIP_TCP */
00600 
00601 
00602 
00603 
00604 
00605 
00606 
00607 
00608 

Generated on Wed Jan 14 12:58:57 2004 for RTL-lwIP-0.4 by doxygen 1.3.4