The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/tcp_sack.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 4. Neither the name of the University nor the names of its contributors
   14  *    may be used to endorse or promote products derived from this software
   15  *    without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  *      @(#)tcp_sack.c  8.12 (Berkeley) 5/24/95
   30  * $FreeBSD: releng/5.3/sys/netinet/tcp_sack.c 155190 2006-02-01 19:43:36Z cperciva $
   31  */
   32 
   33 /*
   34  * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994
   35  *      The Regents of the University of California.  All rights reserved.
   36  *
   37  * Redistribution and use in source and binary forms, with or without
   38  * modification, are permitted provided that the following conditions
   39  * are met:
   40  * 1. Redistributions of source code must retain the above copyright
   41  *    notice, this list of conditions and the following disclaimer.
   42  * 2. Redistributions in binary form must reproduce the above copyright
   43  *    notice, this list of conditions and the following disclaimer in the
   44  *    documentation and/or other materials provided with the distribution.
   45  * 3. Neither the name of the University nor the names of its contributors
   46  *    may be used to endorse or promote products derived from this software
   47  *    without specific prior written permission.
   48  *
   49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   59  * SUCH DAMAGE.
   60  *
   61  *      @@(#)COPYRIGHT  1.1 (NRL) 17 January 1995
   62  *
   63  * NRL grants permission for redistribution and use in source and binary
   64  * forms, with or without modification, of the software and documentation
   65  * created at NRL provided that the following conditions are met:
   66  *
   67  * 1. Redistributions of source code must retain the above copyright
   68  *    notice, this list of conditions and the following disclaimer.
   69  * 2. Redistributions in binary form must reproduce the above copyright
   70  *    notice, this list of conditions and the following disclaimer in the
   71  *    documentation and/or other materials provided with the distribution.
   72  * 3. All advertising materials mentioning features or use of this software
   73  *    must display the following acknowledgements:
   74  *      This product includes software developed by the University of
   75  *      California, Berkeley and its contributors.
   76  *      This product includes software developed at the Information
   77  *      Technology Division, US Naval Research Laboratory.
   78  * 4. Neither the name of the NRL nor the names of its contributors
   79  *    may be used to endorse or promote products derived from this software
   80  *    without specific prior written permission.
   81  *
   82  * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
   83  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   84  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
   85  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL NRL OR
   86  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   87  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   88  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   89  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   90  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   91  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   92  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   93  *
   94  * The views and conclusions contained in the software and documentation
   95  * are those of the authors and should not be interpreted as representing
   96  * official policies, either expressed or implied, of the US Naval
   97  * Research Laboratory (NRL).
   98  */
   99 #include "opt_inet.h"
  100 #include "opt_inet6.h"
  101 #include "opt_ipsec.h"
  102 #include "opt_tcpdebug.h"
  103 #include "opt_tcp_input.h"
  104 #include "opt_tcp_sack.h"
  105 
  106 #include <sys/param.h>
  107 #include <sys/systm.h>
  108 #include <sys/kernel.h>
  109 #include <sys/sysctl.h>
  110 #include <sys/malloc.h>
  111 #include <sys/mbuf.h>
  112 #include <sys/proc.h>           /* for proc0 declaration */
  113 #include <sys/protosw.h>
  114 #include <sys/socket.h>
  115 #include <sys/socketvar.h>
  116 #include <sys/syslog.h>
  117 #include <sys/systm.h>
  118 
  119 #include <machine/cpu.h>        /* before tcp_seq.h, for tcp_random18() */
  120 
  121 #include <vm/uma.h>
  122 
  123 #include <net/if.h>
  124 #include <net/route.h>
  125 
  126 #include <netinet/in.h>
  127 #include <netinet/in_systm.h>
  128 #include <netinet/ip.h>
  129 #include <netinet/ip_icmp.h>    /* for ICMP_BANDLIM             */
  130 #include <netinet/in_var.h>
  131 #include <netinet/icmp_var.h>   /* for ICMP_BANDLIM             */
  132 #include <netinet/in_pcb.h>
  133 #include <netinet/ip_var.h>
  134 #include <netinet/ip6.h>
  135 #include <netinet/icmp6.h>
  136 #include <netinet6/nd6.h>
  137 #include <netinet6/ip6_var.h>
  138 #include <netinet6/in6_pcb.h>
  139 #include <netinet/tcp.h>
  140 #include <netinet/tcp_fsm.h>
  141 #include <netinet/tcp_seq.h>
  142 #include <netinet/tcp_timer.h>
  143 #include <netinet/tcp_var.h>
  144 #include <netinet6/tcp6_var.h>
  145 #include <netinet/tcpip.h>
  146 #ifdef TCPDEBUG
  147 #include <netinet/tcp_debug.h>
  148 
  149 u_char tcp_saveipgen[40]; /* the size must be of max ip header, now IPv6 */
  150 struct tcphdr tcp_savetcp;
  151 #endif /* TCPDEBUG */
  152 
  153 #ifdef FAST_IPSEC
  154 #include <netipsec/ipsec.h>
  155 #include <netipsec/ipsec6.h>
  156 #endif
  157 
  158 #ifdef IPSEC
  159 #include <netinet6/ipsec.h>
  160 #include <netinet6/ipsec6.h>
  161 #include <netkey/key.h>
  162 #endif /*IPSEC*/
  163 #include <machine/in_cksum.h>
  164 
  165 extern struct uma_zone *sack_hole_zone;
  166 
  167 /*
  168  * This function is called upon receipt of new valid data (while not in header
  169  * prediction mode), and it updates the ordered list of sacks.
  170  */
  171 void
  172 tcp_update_sack_list(tp)
  173         struct tcpcb *tp;
  174 {
  175         /*
  176          * First reported block MUST be the most recent one.  Subsequent
  177          * blocks SHOULD be in the order in which they arrived at the
  178          * receiver.  These two conditions make the implementation fully
  179          * compliant with RFC 2018.
  180          */
  181         int i, j = 0, count = 0, lastpos = -1;
  182         struct sackblk sack, firstsack, temp[MAX_SACK_BLKS];
  183 
  184         INP_LOCK_ASSERT(tp->t_inpcb);
  185         /* First clean up current list of sacks */
  186         for (i = 0; i < tp->rcv_numsacks; i++) {
  187                 sack = tp->sackblks[i];
  188                 if (sack.start == 0 && sack.end == 0) {
  189                         count++; /* count = number of blocks to be discarded */
  190                         continue;
  191                 }
  192                 if (SEQ_LEQ(sack.end, tp->rcv_nxt)) {
  193                         tp->sackblks[i].start = tp->sackblks[i].end = 0;
  194                         count++;
  195                 } else {
  196                         temp[j].start = tp->sackblks[i].start;
  197                         temp[j++].end = tp->sackblks[i].end;
  198                 }
  199         }
  200         tp->rcv_numsacks -= count;
  201         if (tp->rcv_numsacks == 0) { /* no sack blocks currently (fast path) */
  202                 tcp_clean_sackreport(tp);
  203                 if (SEQ_LT(tp->rcv_nxt, tp->rcv_laststart)) {
  204                         /* ==> need first sack block */
  205                         tp->sackblks[0].start = tp->rcv_laststart;
  206                         tp->sackblks[0].end = tp->rcv_lastend;
  207                         tp->rcv_numsacks = 1;
  208                 }
  209                 return;
  210         }
  211         /* Otherwise, sack blocks are already present. */
  212         for (i = 0; i < tp->rcv_numsacks; i++)
  213                 tp->sackblks[i] = temp[i]; /* first copy back sack list */
  214         if (SEQ_GEQ(tp->rcv_nxt, tp->rcv_lastend))
  215                 return;     /* sack list remains unchanged */
  216         /*
  217          * From here, segment just received should be (part of) the 1st sack.
  218          * Go through list, possibly coalescing sack block entries.
  219          */
  220         firstsack.start = tp->rcv_laststart;
  221         firstsack.end = tp->rcv_lastend;
  222         for (i = 0; i < tp->rcv_numsacks; i++) {
  223                 sack = tp->sackblks[i];
  224                 if (SEQ_LT(sack.end, firstsack.start) ||
  225                     SEQ_GT(sack.start, firstsack.end))
  226                         continue; /* no overlap */
  227                 if (sack.start == firstsack.start && sack.end == firstsack.end){
  228                         /*
  229                          * identical block; delete it here since we will
  230                          * move it to the front of the list.
  231                          */
  232                         tp->sackblks[i].start = tp->sackblks[i].end = 0;
  233                         lastpos = i;    /* last posn with a zero entry */
  234                         continue;
  235                 }
  236                 if (SEQ_LEQ(sack.start, firstsack.start))
  237                         firstsack.start = sack.start; /* merge blocks */
  238                 if (SEQ_GEQ(sack.end, firstsack.end))
  239                         firstsack.end = sack.end;     /* merge blocks */
  240                 tp->sackblks[i].start = tp->sackblks[i].end = 0;
  241                 lastpos = i;    /* last posn with a zero entry */
  242         }
  243         if (lastpos != -1) {    /* at least one merge */
  244                 for (i = 0, j = 1; i < tp->rcv_numsacks; i++) {
  245                         sack = tp->sackblks[i];
  246                         if (sack.start == 0 && sack.end == 0)
  247                                 continue;
  248                         temp[j++] = sack;
  249                 }
  250                 tp->rcv_numsacks = j; /* including first blk (added later) */
  251                 for (i = 1; i < tp->rcv_numsacks; i++) /* now copy back */
  252                         tp->sackblks[i] = temp[i];
  253         } else {        /* no merges -- shift sacks by 1 */
  254                 if (tp->rcv_numsacks < MAX_SACK_BLKS)
  255                         tp->rcv_numsacks++;
  256                 for (i = tp->rcv_numsacks-1; i > 0; i--)
  257                         tp->sackblks[i] = tp->sackblks[i-1];
  258         }
  259         tp->sackblks[0] = firstsack;
  260         return;
  261 }
  262 
  263 /*
  264  * Delete all receiver-side SACK information.
  265  */
  266 void
  267 tcp_clean_sackreport(tp)
  268         struct tcpcb *tp;
  269 {
  270         int i;
  271 
  272         INP_LOCK_ASSERT(tp->t_inpcb);
  273         tp->rcv_numsacks = 0;
  274         for (i = 0; i < MAX_SACK_BLKS; i++)
  275                 tp->sackblks[i].start = tp->sackblks[i].end=0;
  276 }
  277 
  278 /*
  279  * Process the TCP SACK option.  Returns 1 if tcp_dooptions() should continue,
  280  * and 0 otherwise, if the option was fine.  tp->snd_holes is an ordered list
  281  * of holes (oldest to newest, in terms of the sequence space).
  282  */
  283 int
  284 tcp_sack_option(struct tcpcb *tp, struct tcphdr *th, u_char *cp, int optlen)
  285 {
  286         int tmp_olen;
  287         u_char *tmp_cp;
  288         struct sackhole *cur, *p, *temp;
  289 
  290         INP_LOCK_ASSERT(tp->t_inpcb);
  291         if (!tp->sack_enable)
  292                 return (1);
  293 
  294         /* Note: TCPOLEN_SACK must be 2*sizeof(tcp_seq) */
  295         if (optlen <= 2 || (optlen - 2) % TCPOLEN_SACK != 0)
  296                 return (1);
  297         tmp_cp = cp + 2;
  298         tmp_olen = optlen - 2;
  299         tcpstat.tcps_sack_rcv_blocks++;
  300         if (tp->snd_numholes < 0)
  301                 tp->snd_numholes = 0;
  302         if (tp->t_maxseg == 0)
  303                 panic("tcp_sack_option"); /* Should never happen */
  304 next_block:
  305         while (tmp_olen > 0) {
  306                 struct sackblk sack;
  307 
  308                 bcopy(tmp_cp, (char *) &(sack.start), sizeof(tcp_seq));
  309                 sack.start = ntohl(sack.start);
  310                 bcopy(tmp_cp + sizeof(tcp_seq),
  311                     (char *) &(sack.end), sizeof(tcp_seq));
  312                 sack.end = ntohl(sack.end);
  313                 tmp_olen -= TCPOLEN_SACK;
  314                 tmp_cp += TCPOLEN_SACK;
  315                 if (SEQ_LEQ(sack.end, sack.start))
  316                         continue; /* bad SACK fields */
  317                 if (SEQ_LEQ(sack.end, tp->snd_una))
  318                         continue; /* old block */
  319                 if (SEQ_GT(th->th_ack, tp->snd_una)) {
  320                         if (SEQ_LT(sack.start, th->th_ack))
  321                                 continue;
  322                 }
  323                 if (SEQ_GT(sack.end, tp->snd_max))
  324                         continue;
  325                 if (tp->snd_holes == NULL) { /* first hole */
  326                         tp->snd_holes = (struct sackhole *)
  327                                 uma_zalloc(sack_hole_zone,M_NOWAIT);
  328                         if (tp->snd_holes == NULL) {
  329                                 /* ENOBUFS, so ignore SACKed block for now*/
  330                                 continue;
  331                         }
  332                         cur = tp->snd_holes;
  333                         cur->start = th->th_ack;
  334                         cur->end = sack.start;
  335                         cur->rxmit = cur->start;
  336                         cur->next = NULL;
  337                         tp->snd_numholes = 1;
  338                         tp->rcv_lastsack = sack.end;
  339                         continue; /* with next sack block */
  340                 }
  341                 /* Go thru list of holes:  p = previous,  cur = current */
  342                 p = cur = tp->snd_holes;
  343                 while (cur) {
  344                         if (SEQ_LEQ(sack.end, cur->start))
  345                                 /* SACKs data before the current hole */
  346                                 break; /* no use going through more holes */
  347                         if (SEQ_GEQ(sack.start, cur->end)) {
  348                                 /* SACKs data beyond the current hole */
  349                                 p = cur;
  350                                 cur = cur->next;
  351                                 continue;
  352                         }
  353                         if (SEQ_LEQ(sack.start, cur->start)) {
  354                                 /* Data acks at least the beginning of hole */
  355                                 if (SEQ_GEQ(sack.end, cur->end)) {
  356                                         /* Acks entire hole, so delete hole */
  357                                         if (p != cur) {
  358                                                 p->next = cur->next;
  359                                                 uma_zfree(sack_hole_zone, cur);
  360                                                 cur = p->next;
  361                                         } else {
  362                                                 cur = cur->next;
  363                                                 uma_zfree(sack_hole_zone, p);
  364                                                 p = cur;
  365                                                 tp->snd_holes = p;
  366                                         }
  367                                         tp->snd_numholes--;
  368                                         continue;
  369                                 }
  370                                 /* otherwise, move start of hole forward */
  371                                 cur->start = sack.end;
  372                                 cur->rxmit = SEQ_MAX(cur->rxmit, cur->start);
  373                                 p = cur;
  374                                 cur = cur->next;
  375                                 continue;
  376                         }
  377                         /* move end of hole backward */
  378                         if (SEQ_GEQ(sack.end, cur->end)) {
  379                                 cur->end = sack.start;
  380                                 cur->rxmit = SEQ_MIN(cur->rxmit, cur->end);
  381                                 p = cur;
  382                                 cur = cur->next;
  383                                 continue;
  384                         }
  385                         if (SEQ_LT(cur->start, sack.start) &&
  386                             SEQ_GT(cur->end, sack.end)) {
  387                                 /*
  388                                  * ACKs some data in middle of a hole; need to
  389                                  * split current hole
  390                                  */
  391                                 temp = (struct sackhole *)
  392                                         uma_zalloc(sack_hole_zone,M_NOWAIT);
  393                                 if (temp == NULL)
  394                                         goto next_block; /* ENOBUFS */
  395                                 temp->next = cur->next;
  396                                 temp->start = sack.end;
  397                                 temp->end = cur->end;
  398                                 temp->rxmit = SEQ_MAX(cur->rxmit, temp->start);
  399                                 cur->end = sack.start;
  400                                 cur->rxmit = SEQ_MIN(cur->rxmit, cur->end);
  401                                 cur->next = temp;
  402                                 p = temp;
  403                                 cur = p->next;
  404                                 tp->snd_numholes++;
  405                         }
  406                 }
  407                 /* At this point, p points to the last hole on the list */
  408                 if (SEQ_LT(tp->rcv_lastsack, sack.start)) {
  409                         /*
  410                          * Need to append new hole at end.
  411                          * Last hole is p (and it's not NULL).
  412                          */
  413                         temp = (struct sackhole *)
  414                                 uma_zalloc(sack_hole_zone,M_NOWAIT);
  415                         if (temp == NULL)
  416                                 continue; /* ENOBUFS */
  417                         temp->start = tp->rcv_lastsack;
  418                         temp->end = sack.start;
  419                         temp->rxmit = temp->start;
  420                         temp->next = 0;
  421                         p->next = temp;
  422                         tp->rcv_lastsack = sack.end;
  423                         tp->snd_numholes++;
  424                 }
  425         }
  426         return (0);
  427 }
  428 
  429 /*
  430  * Delete stale (i.e, cumulatively ack'd) holes.  Hole is deleted only if
  431  * it is completely acked; otherwise, tcp_sack_option(), called from
  432  * tcp_dooptions(), will fix up the hole.
  433  */
  434 void
  435 tcp_del_sackholes(tp, th)
  436         struct tcpcb *tp;
  437         struct tcphdr *th;
  438 {
  439         INP_LOCK_ASSERT(tp->t_inpcb);
  440         if (tp->sack_enable && tp->t_state != TCPS_LISTEN) {
  441                 /* max because this could be an older ack just arrived */
  442                 tcp_seq lastack = SEQ_GT(th->th_ack, tp->snd_una) ?
  443                         th->th_ack : tp->snd_una;
  444                 struct sackhole *cur = tp->snd_holes;
  445                 struct sackhole *prev;
  446                 while (cur)
  447                         if (SEQ_LEQ(cur->end, lastack)) {
  448                                 prev = cur;
  449                                 cur = cur->next;
  450                                 uma_zfree(sack_hole_zone, prev);
  451                                 tp->snd_numholes--;
  452                         } else if (SEQ_LT(cur->start, lastack)) {
  453                                 cur->start = lastack;
  454                                 if (SEQ_LT(cur->rxmit, cur->start))
  455                                         cur->rxmit = cur->start;
  456                                 break;
  457                         } else
  458                                 break;
  459                 tp->snd_holes = cur;
  460         }
  461 }
  462 
  463 void
  464 tcp_free_sackholes(struct tcpcb *tp)
  465 {
  466         struct sackhole *p, *q;
  467 
  468         INP_LOCK_ASSERT(tp->t_inpcb);
  469         q = tp->snd_holes;
  470         while (q != NULL) {
  471                 p = q;
  472                 q = q->next;
  473                 uma_zfree(sack_hole_zone, p);
  474         }
  475         tp->snd_holes = 0;
  476 }
  477 
  478 /*
  479  * Checks for partial ack.  If partial ack arrives, turn off retransmission
  480  * timer, deflate the window, do not clear tp->t_dupacks, and return 1.
  481  * If the ack advances at least to tp->snd_recover, return 0.
  482  */
  483 void
  484 tcp_sack_partialack(tp, th)
  485         struct tcpcb *tp;
  486         struct tcphdr *th;
  487 {
  488         INP_LOCK_ASSERT(tp->t_inpcb);
  489         u_long  ocwnd = tp->snd_cwnd;
  490 
  491         callout_stop(tp->tt_rexmt);
  492         tp->t_rtttime = 0;
  493         /*
  494          * Set snd_cwnd to one segment beyond acknowledged offset
  495          * (tp->snd_una has not yet been updated when this function is called.)
  496          */
  497         /*
  498          * Should really be
  499          * min(tp->snd_cwnd, tp->t_maxseg + (th->th_ack - tp->snd_una))
  500          */
  501         tp->snd_cwnd = tp->t_maxseg + (th->th_ack - tp->snd_una);
  502         tp->t_flags |= TF_ACKNOW;
  503         (void) tcp_output(tp);
  504         tp->snd_cwnd = ocwnd;
  505         /*
  506          * Partial window deflation.  Relies on fact that tp->snd_una
  507          * not updated yet.
  508          */
  509         tp->snd_cwnd -= (th->th_ack - tp->snd_una - tp->t_maxseg);
  510 }
  511 
  512 #ifdef TCP_SACK_DEBUG
  513 void
  514 tcp_print_holes(struct tcpcb *tp)
  515 {
  516         struct sackhole *p = tp->snd_holes;
  517         if (p == 0)
  518                 return;
  519         printf("Hole report: start--end dups rxmit\n");
  520         while (p) {
  521                 printf("%x--%x r %x\n", p->start, p->end, p->rxmit);
  522                 p = p->next;
  523         }
  524         printf("\n");
  525 }
  526 #endif /* TCP_SACK_DEBUG */
  527 
  528 /*
  529  * Returns pointer to a sackhole if there are any pending retransmissions;
  530  * NULL otherwise.
  531  */
  532 struct sackhole *
  533 tcp_sack_output(struct tcpcb *tp)
  534 {
  535         struct sackhole *p;
  536 
  537         INP_LOCK_ASSERT(tp->t_inpcb);
  538         if (!tp->sack_enable)
  539                 return (NULL);
  540         p = tp->snd_holes;
  541         while (p) {
  542                 if (SEQ_LT(p->rxmit, p->end)) {
  543                         if (SEQ_LT(p->rxmit, tp->snd_una)) {/* old SACK hole */
  544                                 p = p->next;
  545                                 continue;
  546                         }
  547 #ifdef TCP_SACK_DEBUG
  548                         if (p)
  549                                 tcp_print_holes(tp);
  550 #endif
  551                         return (p);
  552                 }
  553                 p = p->next;
  554         }
  555         return (NULL);
  556 }
  557 
  558 /*
  559  * After a timeout, the SACK list may be rebuilt.  This SACK information
  560  * should be used to avoid retransmitting SACKed data.  This function
  561  * traverses the SACK list to see if snd_nxt should be moved forward.
  562  */
  563 void
  564 tcp_sack_adjust(struct tcpcb *tp)
  565 {
  566         INP_LOCK_ASSERT(tp->t_inpcb);
  567         struct sackhole *cur = tp->snd_holes;
  568         if (cur == NULL)
  569                 return; /* No holes */
  570         if (SEQ_GEQ(tp->snd_nxt, tp->rcv_lastsack))
  571                 return; /* We're already beyond any SACKed blocks */
  572         /*
  573          * Two cases for which we want to advance snd_nxt:
  574          * i) snd_nxt lies between end of one hole and beginning of another
  575          * ii) snd_nxt lies between end of last hole and rcv_lastsack
  576          */
  577         while (cur->next) {
  578                 if (SEQ_LT(tp->snd_nxt, cur->end))
  579                         return;
  580                 if (SEQ_GEQ(tp->snd_nxt, cur->next->start))
  581                         cur = cur->next;
  582                 else {
  583                         tp->snd_nxt = cur->next->start;
  584                         return;
  585                 }
  586         }
  587         if (SEQ_LT(tp->snd_nxt, cur->end))
  588                 return;
  589         tp->snd_nxt = tp->rcv_lastsack;
  590         return;
  591 }
  592 

Cache object: 33272a9bcbf46f67e13fa6c48472bda4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.