/[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.26 by kieranm, Tue Jun 10 10:45:29 2003 UTC revision 1.27 by likewise, Wed Jun 11 22:34:51 2003 UTC
# Line 5  Line 5 
5   */   */
6  /*  /*
7   * Copyright (c) 2001-2003 Swedish Institute of Computer Science.   * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
8   * All rights reserved.   * All rights reserved.
9   *   *
10   * Redistribution and use in source and binary forms, with or without modification,   * Redistribution and use in source and binary forms, with or without modification,
11   * are permitted provided that the following conditions are met:   * are permitted provided that the following conditions are met:
12   *   *
13   * 1. Redistributions of source code must retain the above copyright notice,   * 1. Redistributions of source code must retain the above copyright notice,
# Line 16  Line 16 
16   *    this list of conditions and the following disclaimer in the documentation   *    this list of conditions and the following disclaimer in the documentation
17   *    and/or other materials provided with the distribution.   *    and/or other materials provided with the distribution.
18   * 3. The name of the author may not be used to endorse or promote products   * 3. The name of the author may not be used to endorse or promote products
19   *    derived from this software without specific prior written permission.   *    derived from this software without specific prior written permission.
20   *   *
21   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24   * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,   * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26   * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS   * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29   * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY   * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30   * OF SUCH DAMAGE.   * OF SUCH DAMAGE.
31   *   *
32   * This file is part of the lwIP TCP/IP stack.   * This file is part of the lwIP TCP/IP stack.
33   *   *
34   * Author: Adam Dunkels <adam@sics.se>   * Author: Adam Dunkels <adam@sics.se>
35   *   *
36   */   */
# Line 75  tcp_send_ctrl(struct tcp_pcb *pcb, u8_t Line 75  tcp_send_ctrl(struct tcp_pcb *pcb, u8_t
75  err_t  err_t
76  tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy)  tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy)
77  {  {
78    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, arg=%p, len=%u, copy=%d)\n", (void *)pcb, arg, len, copy));    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, arg=%p, len=%u, copy=%d)\n", (void *)pcb,
79        arg, len, (unsigned int)copy));
80    if (pcb->state == SYN_SENT ||    if (pcb->state == SYN_SENT ||
81       pcb->state == SYN_RCVD ||       pcb->state == SYN_RCVD ||
82       pcb->state == ESTABLISHED ||       pcb->state == ESTABLISHED ||
# Line 102  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 103  tcp_enqueue(struct tcp_pcb *pcb, void *a
103    void *ptr;    void *ptr;
104    u8_t queuelen;    u8_t queuelen;
105    
106    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue(pcb=%p, arg=%p, len=%u, flags=%x, copy=%d)\n", (void *)pcb, arg, len, flags, copy));    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue(pcb=%p, arg=%p, len=%u, flags=%x, copy=%u)\n",
107        (void *)pcb, arg, len, (unsigned int)flags, (unsigned int)copy));
108    left = len;    left = len;
109    ptr = arg;    ptr = arg;
110    /* fail on too much data */    /* fail on too much data */
111    if (len > pcb->snd_buf) {    if (len > pcb->snd_buf) {
112      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too much data (len=%d > snd_buf=%d)\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));
113      return ERR_MEM;      return ERR_MEM;
114    }    }
115    
# Line 116  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 118  tcp_enqueue(struct tcp_pcb *pcb, void *a
118    seqno = pcb->snd_lbb;    seqno = pcb->snd_lbb;
119    
120    queue = NULL;    queue = NULL;
121    LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %d\n", pcb->snd_queuelen));    LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %u\n", (unsigned int)pcb->snd_queuelen));
122    
123    /* Check if the queue length exceeds the configured maximum queue    /* Check if the queue length exceeds the configured maximum queue
124     * length. If so, we return an error. */     * length. If so, we return an error. */
125    queuelen = pcb->snd_queuelen;    queuelen = pcb->snd_queuelen;
126    if (queuelen >= TCP_SND_QUEUELEN) {    if (queuelen >= TCP_SND_QUEUELEN) {
127      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too long queue %d (max %d)\n", queuelen, TCP_SND_QUEUELEN));      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too long queue %u (max %u)\n", queuelen, TCP_SND_QUEUELEN));
128      goto memerr;      goto memerr;
129    }      }
130    
131    if (pcb->snd_queuelen != 0) {    if (pcb->snd_queuelen != 0) {
132      LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||      LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
133      pcb->unsent != NULL);            pcb->unsent != NULL);
134    }    }
135    
136    seg = NULL;    seg = NULL;
# Line 173  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 175  tcp_enqueue(struct tcp_pcb *pcb, void *a
175      }      }
176      else if (copy) {      else if (copy) {
177        if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) {        if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) {
178          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));
179          goto memerr;          goto memerr;
180        }        }
181        ++queuelen;        ++queuelen;
# Line 191  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 193  tcp_enqueue(struct tcp_pcb *pcb, void *a
193         * instead of PBUF_REF here.         * instead of PBUF_REF here.
194         */         */
195        if ((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {        if ((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {
196          LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n"));                  LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n"));
197          goto memerr;          goto memerr;
198        }        }
199        ++queuelen;        ++queuelen;
# Line 203  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 205  tcp_enqueue(struct tcp_pcb *pcb, void *a
205          /* If allocation fails, we have to deallocate the data pbuf as          /* If allocation fails, we have to deallocate the data pbuf as
206           * well. */           * well. */
207          pbuf_free(p);          pbuf_free(p);
208          LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for header pbuf\n"));                LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for header pbuf\n"));
209          goto memerr;          goto memerr;
210        }        }
211        ++queuelen;        ++queuelen;
# Line 217  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 219  tcp_enqueue(struct tcp_pcb *pcb, void *a
219      /* Now that there are more segments queued, we check again if the      /* Now that there are more segments queued, we check again if the
220      length of the queue exceeds the configured maximum. */      length of the queue exceeds the configured maximum. */
221      if (queuelen > TCP_SND_QUEUELEN) {      if (queuelen > TCP_SND_QUEUELEN) {
222        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: queue too long %d (%d)\n", queuelen, TCP_SND_QUEUELEN));          LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: queue too long %u (%u)\n", queuelen, TCP_SND_QUEUELEN));
223        goto memerr;        goto memerr;
224      }      }
225    
226      seg->len = seglen;      seg->len = seglen;
227  #if 0 /* Was commented out. TODO: can someone say why this is here? */  #if 0 /* Was commented out. TODO: can someone say why this is here? */
228      if ((flags & TCP_SYN) || (flags & TCP_FIN)) {      if ((flags & TCP_SYN) || (flags & TCP_FIN)) {
229        ++seg->len;        ++seg->len;
230      }      }
231  #endif  #endif
# Line 300  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 302  tcp_enqueue(struct tcp_pcb *pcb, void *a
302      }      }
303      memp_free(MEMP_TCP_SEG, queue);      memp_free(MEMP_TCP_SEG, queue);
304    }    }
305    else {          else {
306      if (useg == NULL) {      if (useg == NULL) {
307        pcb->unsent = queue;        pcb->unsent = queue;
308    
# Line 365  tcp_output(struct tcp_pcb *pcb) Line 367  tcp_output(struct tcp_pcb *pcb)
367    if (tcp_input_pcb == pcb) {    if (tcp_input_pcb == pcb) {
368      return ERR_OK;      return ERR_OK;
369    }    }
370      
371    wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);    wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);
372    
373      
374    seg = pcb->unsent;    seg = pcb->unsent;
375    
376    /* If the TF_ACK_NOW flag is set, we check if there is data that is    /* If the TF_ACK_NOW flag is set, we check if there is data that is
# Line 386  tcp_output(struct tcp_pcb *pcb) Line 388  tcp_output(struct tcp_pcb *pcb)
388        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"));
389        return ERR_BUF;        return ERR_BUF;
390      }      }
391      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));
392        
393      tcphdr = p->payload;      tcphdr = p->payload;
394      tcphdr->src = htons(pcb->local_port);      tcphdr->src = htons(pcb->local_port);
395      tcphdr->dest = htons(pcb->remote_port);      tcphdr->dest = htons(pcb->remote_port);
# Line 397  tcp_output(struct tcp_pcb *pcb) Line 399  tcp_output(struct tcp_pcb *pcb)
399      tcphdr->wnd = htons(pcb->rcv_wnd);      tcphdr->wnd = htons(pcb->rcv_wnd);
400      tcphdr->urgp = 0;      tcphdr->urgp = 0;
401      TCPH_OFFSET_SET(tcphdr, 5 << 4);      TCPH_OFFSET_SET(tcphdr, 5 << 4);
402        
403      tcphdr->chksum = 0;      tcphdr->chksum = 0;
404      tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),      tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
405            IP_PROTO_TCP, p->tot_len);            IP_PROTO_TCP, p->tot_len);
# Line 407  tcp_output(struct tcp_pcb *pcb) Line 409  tcp_output(struct tcp_pcb *pcb)
409      pbuf_free(p);      pbuf_free(p);
410    
411      return ERR_OK;      return ERR_OK;
412    }    }
413      
414  #if TCP_OUTPUT_DEBUG  #if TCP_OUTPUT_DEBUG
415    if (seg == NULL) {    if (seg == NULL) {
416      LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", pcb->unsent));      LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", pcb->unsent));
# Line 426  tcp_output(struct tcp_pcb *pcb) Line 428  tcp_output(struct tcp_pcb *pcb)
428                              ntohl(seg->tcphdr->seqno), pcb->lastack));                              ntohl(seg->tcphdr->seqno), pcb->lastack));
429    }    }
430  #endif /* TCP_CWND_DEBUG */  #endif /* TCP_CWND_DEBUG */
431      
432    while (seg != NULL &&    while (seg != NULL &&
433    ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {    ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
434  #if TCP_CWND_DEBUG  #if TCP_CWND_DEBUG
# Line 439  tcp_output(struct tcp_pcb *pcb) Line 441  tcp_output(struct tcp_pcb *pcb)
441  #endif /* TCP_CWND_DEBUG */  #endif /* TCP_CWND_DEBUG */
442    
443      pcb->unsent = seg->next;      pcb->unsent = seg->next;
444        
445      if (pcb->state != SYN_SENT) {      if (pcb->state != SYN_SENT) {
446        TCPH_FLAGS_SET(seg->tcphdr, TCPH_FLAGS(seg->tcphdr) | TCP_ACK);        TCPH_FLAGS_SET(seg->tcphdr, TCPH_FLAGS(seg->tcphdr) | TCP_ACK);
447        pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);        pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
448      }      }
449        
450      tcp_output_segment(seg, pcb);      tcp_output_segment(seg, pcb);
451      pcb->snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);      pcb->snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
452      if (TCP_SEQ_LT(pcb->snd_max, pcb->snd_nxt)) {      if (TCP_SEQ_LT(pcb->snd_max, pcb->snd_nxt)) {
# Line 455  tcp_output(struct tcp_pcb *pcb) Line 457  tcp_output(struct tcp_pcb *pcb)
457        seg->next = NULL;        seg->next = NULL;
458        if (pcb->unacked == NULL) {        if (pcb->unacked == NULL) {
459          pcb->unacked = seg;          pcb->unacked = seg;
460      
461      
462        } else {        } else {
463          for (useg = pcb->unacked; useg->next != NULL; useg = useg->next);          for (useg = pcb->unacked; useg->next != NULL; useg = useg->next);
464          useg->next = seg;          useg->next = seg;
# Line 465  tcp_output(struct tcp_pcb *pcb) Line 467  tcp_output(struct tcp_pcb *pcb)
467        tcp_seg_free(seg);        tcp_seg_free(seg);
468      }      }
469      seg = pcb->unsent;      seg = pcb->unsent;
470    }      }
471    return ERR_OK;    return ERR_OK;
472  }  }
473  /*-----------------------------------------------------------------------------------*/  /*-----------------------------------------------------------------------------------*/
# Line 498  tcp_output_segment(struct tcp_seg *seg, Line 500  tcp_output_segment(struct tcp_seg *seg,
500    }    }
501    
502    pcb->rtime = 0;    pcb->rtime = 0;
503      
504    if (pcb->rttest == 0) {    if (pcb->rttest == 0) {
505      pcb->rttest = tcp_ticks;      pcb->rttest = tcp_ticks;
506      pcb->rtseq = ntohl(seg->tcphdr->seqno);      pcb->rtseq = ntohl(seg->tcphdr->seqno);
# Line 510  tcp_output_segment(struct tcp_seg *seg, Line 512  tcp_output_segment(struct tcp_seg *seg,
512            seg->len));            seg->len));
513    
514    len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);    len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);
515      
516    seg->p->len -= len;    seg->p->len -= len;
517    seg->p->tot_len -= len;    seg->p->tot_len -= len;
518      
519    seg->p->payload = seg->tcphdr;    seg->p->payload = seg->tcphdr;
520        
521    seg->tcphdr->chksum = 0;    seg->tcphdr->chksum = 0;
522    seg->tcphdr->chksum = inet_chksum_pseudo(seg->p,    seg->tcphdr->chksum = inet_chksum_pseudo(seg->p,
523               &(pcb->local_ip),               &(pcb->local_ip),
# Line 551  tcp_rst(u32_t seqno, u32_t ackno, Line 553  tcp_rst(u32_t seqno, u32_t ackno,
553    tcphdr->wnd = htons(TCP_WND);    tcphdr->wnd = htons(TCP_WND);
554    tcphdr->urgp = 0;    tcphdr->urgp = 0;
555    TCPH_OFFSET_SET(tcphdr, 5 << 4);    TCPH_OFFSET_SET(tcphdr, 5 << 4);
556      
557    tcphdr->chksum = 0;    tcphdr->chksum = 0;
558    tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,    tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,
559                IP_PROTO_TCP, p->tot_len);                IP_PROTO_TCP, p->tot_len);
# Line 572  tcp_rexmit(struct tcp_pcb *pcb) Line 574  tcp_rexmit(struct tcp_pcb *pcb)
574    if (pcb->unacked == NULL) {    if (pcb->unacked == NULL) {
575      return;      return;
576    }    }
577      
578    /* Move all unacked segments to the unsent queue. */    /* Move all unacked segments to the unsent queue. */
579    for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);    for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
580      
581    seg->next = pcb->unsent;    seg->next = pcb->unsent;
582    pcb->unsent = pcb->unacked;    pcb->unsent = pcb->unacked;
583      
584    pcb->unacked = NULL;    pcb->unacked = NULL;
585      
586      
587    pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);    pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
588      
589    ++pcb->nrtx;    ++pcb->nrtx;
590      
591    /* Don't take any rtt measurements after retransmitting. */        /* Don't take any rtt measurements after retransmitting. */
592    pcb->rttest = 0;    pcb->rttest = 0;
593      
594    /* Do the actual retransmission. */    /* Do the actual retransmission. */
595    tcp_output(pcb);    tcp_output(pcb);
596    

Legend:
Removed from v.1.26  
changed lines
  Added in v.1.27

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