/[lwip]/lwip/src/core/tcp_out.c
ViewVC logotype

Diff of /lwip/src/core/tcp_out.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.38 by kieranm, Sun Sep 12 16:34:06 2004 UTC revision 1.39 by likewise, Sun Dec 26 01:36:37 2004 UTC
# Line 79  tcp_write(struct tcp_pcb *pcb, const voi Line 79  tcp_write(struct tcp_pcb *pcb, const voi
79  {  {
80    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, arg=%p, len=%u, copy=%d)\n", (void *)pcb,    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, arg=%p, len=%u, copy=%d)\n", (void *)pcb,
81      arg, len, (unsigned int)copy));      arg, len, (unsigned int)copy));
82    if (pcb->state == SYN_SENT ||    /* connection is in valid state for data transmission? */
83       pcb->state == SYN_RCVD ||    if (pcb->state == ESTABLISHED ||
84       pcb->state == ESTABLISHED ||       pcb->state == CLOSE_WAIT ||
85       pcb->state == CLOSE_WAIT) {       pcb->state == SYN_SENT ||
86         pcb->state == SYN_RCVD) {
87      if (len > 0) {      if (len > 0) {
88        return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0);        return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0);
89      }      }
# Line 93  tcp_write(struct tcp_pcb *pcb, const voi Line 94  tcp_write(struct tcp_pcb *pcb, const voi
94    }    }
95  }  }
96    
97    /**
98     * Enqueue data for tranmission
99     *
100     * @arg pcb Protocol control block for the TCP connection to enqueue data for.
101     * @arg arg Pointer to the data to be enqueued for sending.
102     * @arg len Data length in bytes
103     * @arg flags
104     * @arg optdata
105     * @arg optlen
106     */
107  err_t  err_t
108  tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,  tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,
109        u8_t flags, u8_t copy,    u8_t flags, u8_t copy,
110              u8_t *optdata, u8_t optlen)    u8_t *optdata, u8_t optlen)
111  {  {
112    struct pbuf *p;    struct pbuf *p;
113    struct tcp_seg *seg, *useg, *queue;    struct tcp_seg *seg, *useg, *queue;
# Line 107  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 118  tcp_enqueue(struct tcp_pcb *pcb, void *a
118    
119    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue(pcb=%p, arg=%p, len=%u, flags=%x, copy=%u)\n",    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue(pcb=%p, arg=%p, len=%u, flags=%x, copy=%u)\n",
120      (void *)pcb, arg, len, (unsigned int)flags, (unsigned int)copy));      (void *)pcb, arg, len, (unsigned int)flags, (unsigned int)copy));
   left = len;  
   ptr = arg;  
121    /* fail on too much data */    /* fail on too much data */
122    if (len > pcb->snd_buf) {    if (len > pcb->snd_buf) {
123      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too much data (len=%u > snd_buf=%u)\n", len, pcb->snd_buf));      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too much data (len=%u > snd_buf=%u)\n", len, pcb->snd_buf));
124      return ERR_MEM;      return ERR_MEM;
125    }    }
126      left = len;
127      ptr = arg;
128    
129    /* seqno will be the sequence number of the first segment enqueued    /* seqno will be the sequence number of the first segment enqueued
130     * by the call to this function. */     * by the call to this function. */
131    seqno = pcb->snd_lbb;    seqno = pcb->snd_lbb;
132    
   queue = NULL;  
133    LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %u\n", (unsigned int)pcb->snd_queuelen));    LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %u\n", (unsigned int)pcb->snd_queuelen));
134    
135    /* Check if the queue length exceeds the configured maximum queue    /* Check if the queue length exceeds the configured maximum queue
# Line 129  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 139  tcp_enqueue(struct tcp_pcb *pcb, void *a
139      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too long queue %u (max %u)\n", queuelen, TCP_SND_QUEUELEN));      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too long queue %u (max %u)\n", queuelen, TCP_SND_QUEUELEN));
140      goto memerr;      goto memerr;
141    }    }
142      if (queuelen != 0) {
143    if (pcb->snd_queuelen != 0) {      LWIP_ASSERT("tcp_enqueue: queue length non-zero and at least one queue non-empty",
144      LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||        pcb->unacked != NULL || pcb->unsent != NULL);
145      pcb->unsent != NULL);    } else {
146        LWIP_ASSERT("tcp_enqueue: queue length zero and queues empty",
147          pcb->unacked == NULL && pcb->unsent == NULL);
148    }    }
149    
   seg = useg = NULL;  
   seglen = 0;  
   
150    /* First, break up the data into segments and tuck them together in    /* First, break up the data into segments and tuck them together in
151     * the local "queue" variable. */     * the local "queue" variable. */
152      useg = queue = seg = NULL;
153      seglen = 0;
154    while (queue == NULL || left > 0) {    while (queue == NULL || left > 0) {
155    
156      /* The segment length should be the MSS if the data to be enqueued      /* The segment length should be the MSS if the data to be enqueued
# Line 155  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 166  tcp_enqueue(struct tcp_pcb *pcb, void *a
166      seg->next = NULL;      seg->next = NULL;
167      seg->p = NULL;      seg->p = NULL;
168    
169        /* first segment of to-be-queued data? */
170      if (queue == NULL) {      if (queue == NULL) {
171        useg = queue = seg;        useg = queue = seg;
172      }      }
173        /* subsequent segments of to-be-queued data */
174      else {      else {
175        /* Attach the segment to the end of the queued segments. */        /* Attach the segment to the end of the queued segments. */
176        LWIP_ASSERT("useg != NULL", useg != NULL);        LWIP_ASSERT("useg != NULL", useg != NULL);
177        useg->next = seg;        useg->next = seg;
178          /* remember last segment of to-be-queued data for next iteration */
179        useg = seg;        useg = seg;
180      }      }
181        /* { useg == seg } */
182    
183      /* If copy is set, memory should be allocated      /* If copy is set, memory should be allocated
184       * and data copied into pbuf, otherwise data comes from       * and data copied into pbuf, otherwise data comes from
185       * ROM or other static memory, and need not be copied. If       * ROM or other static memory, and need not be copied. If
186       * optdata is != NULL, we have options instead of data. */       * optdata is != NULL, we have options instead of data. */
187        
188        /* options? */
189      if (optdata != NULL) {      if (optdata != NULL) {
190        if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {        if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
191          goto memerr;          goto memerr;
# Line 176  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 193  tcp_enqueue(struct tcp_pcb *pcb, void *a
193        ++queuelen;        ++queuelen;
194        seg->dataptr = seg->p->payload;        seg->dataptr = seg->p->payload;
195      }      }
196        /* copy from volatile memory? */
197      else if (copy) {      else if (copy) {
198        if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) {        if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) {
199          LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue : could not allocate memory for pbuf copy size %u\n", seglen));          LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue : could not allocate memory for pbuf copy size %u\n", seglen));
# Line 190  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 208  tcp_enqueue(struct tcp_pcb *pcb, void *a
208      /* do not copy data */      /* do not copy data */
209      else {      else {
210    
211        /* first, allocate a pbuf for holding the data.        /* First, allocate a pbuf for holding the data.
212         * since the referenced data is available at least until it is sent out on the         * since the referenced data is available at least until it is sent out on the
213         * link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM         * link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM
214         * instead of PBUF_REF here.         * instead of PBUF_REF here.
# Line 200  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 218  tcp_enqueue(struct tcp_pcb *pcb, void *a
218          goto memerr;          goto memerr;
219        }        }
220        ++queuelen;        ++queuelen;
221          /* reference the non-volatile payload data */
222        p->payload = ptr;        p->payload = ptr;
223        seg->dataptr = ptr;        seg->dataptr = ptr;
224    
# Line 214  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 233  tcp_enqueue(struct tcp_pcb *pcb, void *a
233        ++queuelen;        ++queuelen;
234    
235        /* Concatenate the headers and data pbufs together. */        /* Concatenate the headers and data pbufs together. */
236        pbuf_cat(seg->p, p);        pbuf_cat(seg->p/*header*/, p/*data*/);
237        p = NULL;        p = NULL;
238      }      }
239    
# Line 226  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 245  tcp_enqueue(struct tcp_pcb *pcb, void *a
245      }      }
246    
247      seg->len = seglen;      seg->len = seglen;
 #if 0 /* Was commented out. TODO: can someone say why this is here? */  
     if ((flags & TCP_SYN) || (flags & TCP_FIN)) {  
       ++seg->len;  
     }  
 #endif  
     /* Build TCP header. */  
     if (pbuf_header(seg->p, TCP_HLEN)) {  
248    
249        /* build TCP header */
250        if (pbuf_header(seg->p, TCP_HLEN)) {
251        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: no room for TCP header in pbuf.\n"));        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: no room for TCP header in pbuf.\n"));
   
252        TCP_STATS_INC(tcp.err);        TCP_STATS_INC(tcp.err);
253        goto memerr;        goto memerr;
254      }      }
# Line 268  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 281  tcp_enqueue(struct tcp_pcb *pcb, void *a
281      ptr = (void *)((char *)ptr + seglen);      ptr = (void *)((char *)ptr + seglen);
282    }    }
283    
   
284    /* Now that the data to be enqueued has been broken up into TCP    /* Now that the data to be enqueued has been broken up into TCP
285    segments in the queue variable, we add them to the end of the    segments in the queue variable, we add them to the end of the
286    pcb->unsent queue. */    pcb->unsent queue. */
# Line 278  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 290  tcp_enqueue(struct tcp_pcb *pcb, void *a
290    else {    else {
291      for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);      for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);
292    }    }
293      /* { useg is last segment on the unsent queue, NULL if list is empty } */
294    
295    /* If there is room in the last pbuf on the unsent queue,    /* If there is room in the last pbuf on the unsent queue,
296    chain the first pbuf on the queue together with that. */    chain the first pbuf on the queue together with that. */
# Line 285  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 298  tcp_enqueue(struct tcp_pcb *pcb, void *a
298      TCP_TCPLEN(useg) != 0 &&      TCP_TCPLEN(useg) != 0 &&
299      !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&      !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&
300      !(flags & (TCP_SYN | TCP_FIN)) &&      !(flags & (TCP_SYN | TCP_FIN)) &&
301        /* fit within max seg size */
302      useg->len + queue->len <= pcb->mss) {      useg->len + queue->len <= pcb->mss) {
303      /* Remove TCP header from first segment. */      /* Remove TCP header from first segment of our to-be-queued list */
304      pbuf_header(queue->p, -TCP_HLEN);      pbuf_header(queue->p, -TCP_HLEN);
305      pbuf_cat(useg->p, queue->p);      pbuf_cat(useg->p, queue->p);
306      useg->len += queue->len;      useg->len += queue->len;
307      useg->next = queue->next;      useg->next = queue->next;
308    
309      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE | DBG_STATE, ("tcp_enqueue: chaining, new len %u\n", useg->len));      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_TRACE | DBG_STATE, ("tcp_enqueue: chaining segments, new len %u\n", useg->len));
310      if (seg == queue) {      if (seg == queue) {
311        seg = NULL;        seg = NULL;
312      }      }
313      memp_free(MEMP_TCP_SEG, queue);      memp_free(MEMP_TCP_SEG, queue);
314    }    }
315    else {    else {
316        /* empty list */
317      if (useg == NULL) {      if (useg == NULL) {
318          /* initialize list with this segment */
319        pcb->unsent = queue;        pcb->unsent = queue;
   
320      }      }
321        /* enqueue segment */
322      else {      else {
323        useg->next = queue;        useg->next = queue;
324      }      }
# Line 315  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 331  tcp_enqueue(struct tcp_pcb *pcb, void *a
331    pcb->snd_queuelen = queuelen;    pcb->snd_queuelen = queuelen;
332    LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d (after enqueued)\n", pcb->snd_queuelen));    LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d (after enqueued)\n", pcb->snd_queuelen));
333    if (pcb->snd_queuelen != 0) {    if (pcb->snd_queuelen != 0) {
334      LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||      LWIP_ASSERT("tcp_enqueue: valid queue length",
335        pcb->unsent != NULL);        pcb->unacked != NULL || pcb->unsent != NULL);
   
336    }    }
337    
338    /* Set the PSH flag in the last segment that we enqueued, but only    /* Set the PSH flag in the last segment that we enqueued, but only
# Line 336  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 351  tcp_enqueue(struct tcp_pcb *pcb, void *a
351    if (pcb->snd_queuelen != 0) {    if (pcb->snd_queuelen != 0) {
352      LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||      LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
353        pcb->unsent != NULL);        pcb->unsent != NULL);
   
354    }    }
355    LWIP_DEBUGF(TCP_QLEN_DEBUG | DBG_STATE, ("tcp_enqueue: %d (with mem err)\n", pcb->snd_queuelen));    LWIP_DEBUGF(TCP_QLEN_DEBUG | DBG_STATE, ("tcp_enqueue: %d (with mem err)\n", pcb->snd_queuelen));
356    return ERR_MEM;    return ERR_MEM;
# Line 364  tcp_output(struct tcp_pcb *pcb) Line 378  tcp_output(struct tcp_pcb *pcb)
378    
379    wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);    wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);
380    
   
381    seg = pcb->unsent;    seg = pcb->unsent;
382    
383    /* useg should point to last segment on unacked queue */    /* useg should point to last segment on unacked queue */
# Line 372  tcp_output(struct tcp_pcb *pcb) Line 385  tcp_output(struct tcp_pcb *pcb)
385    if (useg != NULL) {    if (useg != NULL) {
386      for (; useg->next != NULL; useg = useg->next);      for (; useg->next != NULL; useg = useg->next);
387    }                                                                                }                                                                            
   
388        
389    /* If the TF_ACK_NOW flag is set, we check if there is data that is    /* If the TF_ACK_NOW flag is set and no data will be sent (either
390       to be sent. If data is to be sent out, we'll just piggyback our     * because the ->unsent queue is empty or because the window does
391       acknowledgement with the outgoing segment. If no data will be     * not allow it), construct an empty ACK segment and send it.
392       sent (either because the ->unsent queue is empty or because the     *
393       window doesn't allow it) we'll have to construct an empty ACK     * If data is to be sent, we will just piggyback the ACK (see below).
394       segment and send it. */     */
395    if (pcb->flags & TF_ACK_NOW &&    if (pcb->flags & TF_ACK_NOW &&
396       (seg == NULL ||       (seg == NULL ||
397        ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {        ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
     pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);  
398      p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);      p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
399      if (p == NULL) {      if (p == NULL) {
400        LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));        LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
401        return ERR_BUF;        return ERR_BUF;
402      }      }
403      LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: sending ACK for %lu\n", pcb->rcv_nxt));      LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: sending ACK for %lu\n", pcb->rcv_nxt));
404        /* remove ACK flags from the PCB, as we send an empty ACK now */
405        pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
406    
407      tcphdr = p->payload;      tcphdr = p->payload;
408      tcphdr->src = htons(pcb->local_port);      tcphdr->src = htons(pcb->local_port);
# Line 406  tcp_output(struct tcp_pcb *pcb) Line 419  tcp_output(struct tcp_pcb *pcb)
419      tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),      tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
420            IP_PROTO_TCP, p->tot_len);            IP_PROTO_TCP, p->tot_len);
421  #endif  #endif
   
422      ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,      ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
423          IP_PROTO_TCP);          IP_PROTO_TCP);
424      pbuf_free(p);      pbuf_free(p);
# Line 431  tcp_output(struct tcp_pcb *pcb) Line 443  tcp_output(struct tcp_pcb *pcb)
443                              ntohl(seg->tcphdr->seqno), pcb->lastack));                              ntohl(seg->tcphdr->seqno), pcb->lastack));
444    }    }
445  #endif /* TCP_CWND_DEBUG */  #endif /* TCP_CWND_DEBUG */
446      /* data available and window allows it to be sent? */
447    while (seg != NULL &&    while (seg != NULL &&
448    ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {    ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
449  #if TCP_CWND_DEBUG  #if TCP_CWND_DEBUG
# Line 458  tcp_output(struct tcp_pcb *pcb) Line 470  tcp_output(struct tcp_pcb *pcb)
470      /* put segment on unacknowledged list if length > 0 */      /* put segment on unacknowledged list if length > 0 */
471      if (TCP_TCPLEN(seg) > 0) {      if (TCP_TCPLEN(seg) > 0) {
472        seg->next = NULL;        seg->next = NULL;
473          /* unacked list is empty? */
474        if (pcb->unacked == NULL) {        if (pcb->unacked == NULL) {
475          pcb->unacked = seg;          pcb->unacked = seg;
476          useg = seg;          useg = seg;
477          /* unacked list is not empty? */
478        } else {        } else {
479          /* In the case of fast retransmit, the packet should not go to the end          /* In the case of fast retransmit, the packet should not go to the tail
480           * of the unacked queue, but rather at the start. We need to check for           * of the unacked queue, but rather at the head. We need to check for
481           * this case. -STJ Jul 27, 2004 */           * this case. -STJ Jul 27, 2004 */
482          if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){          if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){
483              /* add segment to head of unacked list */
484            seg->next = pcb->unacked;            seg->next = pcb->unacked;
485            pcb->unacked = seg;            pcb->unacked = seg;
486          } else {          } else {
487              /* add segment to tail of unacked list */
488            useg->next = seg;            useg->next = seg;
489            useg = useg->next;            useg = useg->next;
490          }          }
491        }        }
492        /* do not queue empty segments on the unacked list */
493      } else {      } else {
494        tcp_seg_free(seg);        tcp_seg_free(seg);
495      }      }
# Line 481  tcp_output(struct tcp_pcb *pcb) Line 498  tcp_output(struct tcp_pcb *pcb)
498    return ERR_OK;    return ERR_OK;
499  }  }
500    
501    /**
502     * Actually send a TCP segment over IP
503     */
504  static void  static void
505  tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)  tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
506  {  {
# Line 576  tcp_rst(u32_t seqno, u32_t ackno, Line 596  tcp_rst(u32_t seqno, u32_t ackno,
596    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %lu ackno %lu.\n", seqno, ackno));    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %lu ackno %lu.\n", seqno, ackno));
597  }  }
598    
599    /* requeue all unacked segments for retransmission */
600  void  void
601  tcp_rexmit_rto(struct tcp_pcb *pcb)  tcp_rexmit_rto(struct tcp_pcb *pcb)
602  {  {
# Line 585  tcp_rexmit_rto(struct tcp_pcb *pcb) Line 606  tcp_rexmit_rto(struct tcp_pcb *pcb)
606      return;      return;
607    }    }
608    
609    /* Move all unacked segments to the unsent queue. */    /* Move all unacked segments to the head of the unsent queue */
610    for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);    for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
611      /* concatenate unsent queue after unacked queue */
612    seg->next = pcb->unsent;    seg->next = pcb->unsent;
613      /* unsent queue is the concatenated queue (of unacked, unsent) */
614    pcb->unsent = pcb->unacked;    pcb->unsent = pcb->unacked;
615      /* unacked queue is now empty */
616    pcb->unacked = NULL;    pcb->unacked = NULL;
617    
618    pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);    pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
619      /* increment number of retransmissions */
620    ++pcb->nrtx;    ++pcb->nrtx;
621    
622    /* Don't take any rtt measurements after retransmitting. */    /* Don't take any RTT measurements after retransmitting. */
623    pcb->rttest = 0;    pcb->rttest = 0;
624    
625    /* Do the actual retransmission. */    /* Do the actual retransmission */
626    tcp_output(pcb);    tcp_output(pcb);
   
627  }  }
628    
629  void  void

Legend:
Removed from v.1.38  
changed lines
  Added in v.1.39

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26