Home | History | Annotate | Line # | Download | only in netinet
      1  1.36      maxv /* $NetBSD: tcp_sack.c,v 1.36 2018/05/18 18:58:51 maxv Exp $ */
      2   1.1  jonathan 
      3   1.1  jonathan /*
      4   1.1  jonathan  * Copyright (c) 2005 The NetBSD Foundation, Inc.
      5   1.1  jonathan  * All rights reserved.
      6   1.1  jonathan  *
      7   1.1  jonathan  * This code is derived from software contributed to The NetBSD Foundation
      8   1.1  jonathan  * by Kentaro A. Kurahone.
      9   1.1  jonathan  *
     10   1.1  jonathan  * Redistribution and use in source and binary forms, with or without
     11   1.1  jonathan  * modification, are permitted provided that the following conditions
     12   1.1  jonathan  * are met:
     13   1.1  jonathan  * 1. Redistributions of source code must retain the above copyright
     14   1.1  jonathan  *    notice, this list of conditions and the following disclaimer.
     15   1.1  jonathan  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1  jonathan  *    notice, this list of conditions and the following disclaimer in the
     17   1.1  jonathan  *    documentation and/or other materials provided with the distribution.
     18   1.1  jonathan  *
     19   1.1  jonathan  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.1  jonathan  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.1  jonathan  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.1  jonathan  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.1  jonathan  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.1  jonathan  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.1  jonathan  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.1  jonathan  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.1  jonathan  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.1  jonathan  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.1  jonathan  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1  jonathan  */
     31   1.1  jonathan 
     32   1.1  jonathan /*
     33   1.1  jonathan  * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995
     34   1.1  jonathan  *	The Regents of the University of California.  All rights reserved.
     35   1.1  jonathan  *
     36   1.1  jonathan  * Redistribution and use in source and binary forms, with or without
     37   1.1  jonathan  * modification, are permitted provided that the following conditions
     38   1.1  jonathan  * are met:
     39   1.1  jonathan  * 1. Redistributions of source code must retain the above copyright
     40   1.1  jonathan  *    notice, this list of conditions and the following disclaimer.
     41   1.1  jonathan  * 2. Redistributions in binary form must reproduce the above copyright
     42   1.1  jonathan  *    notice, this list of conditions and the following disclaimer in the
     43   1.1  jonathan  *    documentation and/or other materials provided with the distribution.
     44   1.1  jonathan  * 4. Neither the name of the University nor the names of its contributors
     45   1.1  jonathan  *    may be used to endorse or promote products derived from this software
     46   1.1  jonathan  *    without specific prior written permission.
     47   1.1  jonathan  *
     48   1.1  jonathan  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     49   1.1  jonathan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     50   1.1  jonathan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     51   1.1  jonathan  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     52   1.1  jonathan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     53   1.1  jonathan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     54   1.1  jonathan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     55   1.1  jonathan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     56   1.1  jonathan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     57   1.1  jonathan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     58   1.1  jonathan  * SUCH DAMAGE.
     59   1.1  jonathan  *
     60   1.1  jonathan  *	@(#)tcp_sack.c	8.12 (Berkeley) 5/24/95
     61   1.1  jonathan  * $FreeBSD: src/sys/netinet/tcp_sack.c,v 1.3.2.2 2004/12/25 23:02:57 rwatson Exp $
     62   1.1  jonathan  */
     63   1.1  jonathan 
     64   1.1  jonathan /*
     65   1.1  jonathan  *	@@(#)COPYRIGHT	1.1 (NRL) 17 January 1995
     66   1.1  jonathan  *
     67   1.1  jonathan  * NRL grants permission for redistribution and use in source and binary
     68   1.1  jonathan  * forms, with or without modification, of the software and documentation
     69   1.1  jonathan  * created at NRL provided that the following conditions are met:
     70   1.1  jonathan  *
     71   1.1  jonathan  * 1. Redistributions of source code must retain the above copyright
     72   1.1  jonathan  *    notice, this list of conditions and the following disclaimer.
     73   1.1  jonathan  * 2. Redistributions in binary form must reproduce the above copyright
     74   1.1  jonathan  *    notice, this list of conditions and the following disclaimer in the
     75   1.1  jonathan  *    documentation and/or other materials provided with the distribution.
     76   1.1  jonathan  * 3. All advertising materials mentioning features or use of this software
     77   1.1  jonathan  *    must display the following acknowledgements:
     78   1.1  jonathan  *	This product includes software developed by the University of
     79   1.1  jonathan  *	California, Berkeley and its contributors.
     80   1.1  jonathan  *	This product includes software developed at the Information
     81   1.1  jonathan  *	Technology Division, US Naval Research Laboratory.
     82   1.1  jonathan  * 4. Neither the name of the NRL nor the names of its contributors
     83   1.1  jonathan  *    may be used to endorse or promote products derived from this software
     84   1.1  jonathan  *    without specific prior written permission.
     85   1.1  jonathan  *
     86   1.1  jonathan  * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
     87   1.1  jonathan  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     88   1.1  jonathan  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
     89   1.1  jonathan  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL NRL OR
     90   1.1  jonathan  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     91   1.1  jonathan  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     92   1.1  jonathan  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     93   1.1  jonathan  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     94   1.1  jonathan  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     95   1.1  jonathan  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     96   1.1  jonathan  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     97   1.1  jonathan  *
     98   1.1  jonathan  * The views and conclusions contained in the software and documentation
     99   1.1  jonathan  * are those of the authors and should not be interpreted as representing
    100   1.1  jonathan  * official policies, either expressed or implied, of the US Naval
    101   1.1  jonathan  * Research Laboratory (NRL).
    102   1.1  jonathan  */
    103   1.1  jonathan 
    104   1.1  jonathan #include <sys/cdefs.h>
    105  1.36      maxv __KERNEL_RCSID(0, "$NetBSD: tcp_sack.c,v 1.36 2018/05/18 18:58:51 maxv Exp $");
    106   1.1  jonathan 
    107  1.32     pooka #ifdef _KERNEL_OPT
    108   1.1  jonathan #include "opt_inet.h"
    109   1.1  jonathan #include "opt_inet_csum.h"
    110   1.1  jonathan #include "opt_tcp_debug.h"
    111  1.22      yamt #include "opt_ddb.h"
    112  1.32     pooka #endif
    113   1.1  jonathan 
    114   1.1  jonathan #include <sys/param.h>
    115   1.1  jonathan #include <sys/systm.h>
    116   1.1  jonathan #include <sys/mbuf.h>
    117   1.1  jonathan #include <sys/protosw.h>
    118   1.1  jonathan #include <sys/socket.h>
    119   1.1  jonathan #include <sys/socketvar.h>
    120   1.1  jonathan #include <sys/errno.h>
    121   1.1  jonathan #include <sys/syslog.h>
    122   1.1  jonathan #include <sys/pool.h>
    123   1.1  jonathan #include <sys/domain.h>
    124   1.1  jonathan #include <sys/kernel.h>
    125   1.1  jonathan 
    126   1.1  jonathan #include <net/if.h>
    127   1.1  jonathan #include <net/route.h>
    128   1.1  jonathan #include <net/if_types.h>
    129   1.1  jonathan 
    130   1.1  jonathan #include <netinet/in.h>
    131   1.1  jonathan #include <netinet/in_systm.h>
    132   1.1  jonathan #include <netinet/ip.h>
    133   1.1  jonathan #include <netinet/in_pcb.h>
    134   1.1  jonathan #include <netinet/in_var.h>
    135   1.1  jonathan #include <netinet/ip_var.h>
    136   1.1  jonathan 
    137   1.1  jonathan #ifdef INET6
    138   1.1  jonathan #include <netinet/ip6.h>
    139   1.1  jonathan #include <netinet6/ip6_var.h>
    140   1.1  jonathan #include <netinet6/in6_pcb.h>
    141   1.1  jonathan #include <netinet6/ip6_var.h>
    142   1.1  jonathan #include <netinet6/in6_var.h>
    143   1.1  jonathan #include <netinet/icmp6.h>
    144   1.1  jonathan #endif
    145   1.1  jonathan 
    146   1.1  jonathan #ifndef INET6
    147   1.1  jonathan #include <netinet/ip6.h>
    148   1.1  jonathan #endif
    149   1.1  jonathan 
    150   1.1  jonathan #include <netinet/tcp.h>
    151   1.1  jonathan #include <netinet/tcp_fsm.h>
    152   1.1  jonathan #include <netinet/tcp_seq.h>
    153   1.1  jonathan #include <netinet/tcp_timer.h>
    154   1.1  jonathan #include <netinet/tcp_var.h>
    155   1.1  jonathan #include <netinet/tcp_debug.h>
    156   1.1  jonathan 
    157   1.1  jonathan /* SACK block pool. */
    158  1.25     pooka static struct pool sackhole_pool;
    159  1.25     pooka 
    160  1.25     pooka void
    161  1.28      matt tcp_sack_init(void)
    162  1.25     pooka {
    163  1.25     pooka 
    164  1.25     pooka 	pool_init(&sackhole_pool, sizeof(struct sackhole), 0, 0, 0,
    165  1.25     pooka 	    "sackholepl", NULL, IPL_SOFTNET);
    166  1.25     pooka }
    167  1.19      yamt 
    168  1.19      yamt static struct sackhole *
    169  1.19      yamt sack_allochole(struct tcpcb *tp)
    170  1.19      yamt {
    171  1.19      yamt 	struct sackhole *hole;
    172  1.19      yamt 
    173  1.19      yamt 	if (tp->snd_numholes >= tcp_sack_tp_maxholes ||
    174  1.19      yamt 	    tcp_sack_globalholes >= tcp_sack_globalmaxholes) {
    175  1.19      yamt 		return NULL;
    176  1.19      yamt 	}
    177  1.19      yamt 	hole = pool_get(&sackhole_pool, PR_NOWAIT);
    178  1.19      yamt 	if (hole == NULL) {
    179  1.19      yamt 		return NULL;
    180  1.19      yamt 	}
    181  1.19      yamt 	tp->snd_numholes++;
    182  1.19      yamt 	tcp_sack_globalholes++;
    183  1.19      yamt 
    184  1.19      yamt 	return hole;
    185  1.19      yamt }
    186  1.19      yamt 
    187  1.19      yamt static struct sackhole *
    188  1.19      yamt sack_inserthole(struct tcpcb *tp, tcp_seq start, tcp_seq end,
    189  1.19      yamt     struct sackhole *prev)
    190  1.19      yamt {
    191  1.19      yamt 	struct sackhole *hole;
    192  1.19      yamt 
    193  1.19      yamt 	hole = sack_allochole(tp);
    194  1.19      yamt 	if (hole == NULL) {
    195  1.19      yamt 		return NULL;
    196  1.19      yamt 	}
    197  1.19      yamt 	hole->start = hole->rxmit = start;
    198  1.19      yamt 	hole->end = end;
    199  1.19      yamt 	if (prev != NULL) {
    200  1.19      yamt 		TAILQ_INSERT_AFTER(&tp->snd_holes, prev, hole, sackhole_q);
    201  1.19      yamt 	} else {
    202  1.19      yamt 		TAILQ_INSERT_TAIL(&tp->snd_holes, hole, sackhole_q);
    203  1.19      yamt 	}
    204  1.19      yamt 	return hole;
    205  1.19      yamt }
    206  1.19      yamt 
    207  1.19      yamt static struct sackhole *
    208  1.19      yamt sack_removehole(struct tcpcb *tp, struct sackhole *hole)
    209  1.19      yamt {
    210  1.19      yamt 	struct sackhole *next;
    211  1.19      yamt 
    212  1.19      yamt 	next = TAILQ_NEXT(hole, sackhole_q);
    213  1.19      yamt 	tp->snd_numholes--;
    214  1.19      yamt 	tcp_sack_globalholes--;
    215  1.19      yamt 	TAILQ_REMOVE(&tp->snd_holes, hole, sackhole_q);
    216  1.19      yamt 	pool_put(&sackhole_pool, hole);
    217  1.19      yamt 
    218  1.19      yamt 	return next;
    219  1.19      yamt }
    220   1.1  jonathan 
    221  1.26      yamt /*
    222  1.26      yamt  * tcp_new_dsack: record the reception of a duplicated segment.
    223  1.26      yamt  */
    224  1.26      yamt 
    225   1.1  jonathan void
    226   1.1  jonathan tcp_new_dsack(struct tcpcb *tp, tcp_seq seq, u_int32_t len)
    227   1.1  jonathan {
    228  1.26      yamt 
    229   1.1  jonathan 	if (TCP_SACK_ENABLED(tp)) {
    230   1.1  jonathan 		tp->rcv_dsack_block.left = seq;
    231   1.1  jonathan 		tp->rcv_dsack_block.right = seq + len;
    232   1.1  jonathan 		tp->rcv_sack_flags |= TCPSACK_HAVED;
    233   1.1  jonathan 	}
    234   1.1  jonathan }
    235   1.1  jonathan 
    236  1.26      yamt /*
    237  1.26      yamt  * tcp_sack_option: parse the given SACK option and update the scoreboard.
    238  1.26      yamt  */
    239  1.26      yamt 
    240   1.1  jonathan void
    241  1.21      yamt tcp_sack_option(struct tcpcb *tp, const struct tcphdr *th, const u_char *cp,
    242  1.21      yamt     int optlen)
    243   1.1  jonathan {
    244   1.5      yamt 	struct sackblk
    245   1.5      yamt 	    t_sack_block[(MAX_TCPOPTLEN - 2) / (sizeof(u_int32_t) * 2)];
    246   1.1  jonathan 	struct sackblk *sack = NULL;
    247   1.1  jonathan 	struct sackhole *cur = NULL;
    248   1.1  jonathan 	struct sackhole *tmp = NULL;
    249  1.21      yamt 	const char *lp = cp + 2;
    250  1.18      yamt 	int i, j, num_sack_blks;
    251   1.1  jonathan 	tcp_seq left, right, acked;
    252   1.1  jonathan 
    253   1.1  jonathan 	/*
    254  1.11  kurahone 	 * If we aren't processing SACK responses, this is not an ACK
    255  1.11  kurahone 	 * or the peer sends us a sack option with invalid length, don't
    256   1.1  jonathan 	 * update the scoreboard.
    257   1.1  jonathan 	 */
    258  1.11  kurahone 	if (!TCP_SACK_ENABLED(tp) || ((th->th_flags & TH_ACK) == 0) ||
    259  1.11  kurahone 			(optlen % 8 != 2 || optlen < 10)) {
    260   1.1  jonathan 		return;
    261   1.1  jonathan 	}
    262   1.1  jonathan 
    263  1.12  kurahone 	/*
    264  1.12  kurahone 	 * If we don't want any SACK holes to be allocated, just return.
    265  1.12  kurahone 	 */
    266  1.12  kurahone 	if (tcp_sack_globalmaxholes == 0 || tcp_sack_tp_maxholes == 0) {
    267  1.12  kurahone 		return;
    268  1.12  kurahone 	}
    269  1.12  kurahone 
    270  1.11  kurahone 	/* If the ACK is outside [snd_una, snd_max], ignore the SACK options. */
    271  1.11  kurahone 	if (SEQ_LT(th->th_ack, tp->snd_una) || SEQ_GT(th->th_ack, tp->snd_max))
    272  1.11  kurahone 		return;
    273  1.11  kurahone 
    274   1.1  jonathan 	/*
    275   1.1  jonathan 	 * Extract SACK blocks.
    276   1.1  jonathan 	 *
    277   1.1  jonathan 	 * Note that t_sack_block is sorted so that we only need to do
    278   1.1  jonathan 	 * one pass over the sequence number space. (SACK "fast-path")
    279   1.1  jonathan 	 */
    280   1.1  jonathan 	num_sack_blks = optlen / 8;
    281   1.1  jonathan 	acked = (SEQ_GT(th->th_ack, tp->snd_una)) ? th->th_ack : tp->snd_una;
    282  1.20   reinoud 	for (i = 0; i < num_sack_blks; i++, lp += sizeof(uint32_t) * 2) {
    283  1.20   reinoud 		memcpy(&left, lp, sizeof(uint32_t));
    284  1.20   reinoud 		memcpy(&right, lp + sizeof(uint32_t), sizeof(uint32_t));
    285   1.3      yamt 		left = ntohl(left);
    286   1.3      yamt 		right = ntohl(right);
    287   1.1  jonathan 
    288  1.13      yamt 		if (SEQ_LEQ(right, acked) || SEQ_GT(right, tp->snd_max) ||
    289   1.4      yamt 		    SEQ_GEQ(left, right)) {
    290   1.1  jonathan 			/* SACK entry that's old, or invalid. */
    291   1.1  jonathan 			i--;
    292   1.1  jonathan 			num_sack_blks--;
    293   1.1  jonathan 			continue;
    294   1.1  jonathan 		}
    295   1.1  jonathan 
    296   1.1  jonathan 		/* Insertion sort. */
    297   1.2      yamt 		for (j = i; (j > 0) && SEQ_LT(left, t_sack_block[j - 1].left);
    298   1.2      yamt 		    j--) {
    299   1.1  jonathan 			t_sack_block[j].left = t_sack_block[j - 1].left;
    300   1.1  jonathan 			t_sack_block[j].right = t_sack_block[j - 1].right;
    301   1.1  jonathan 		}
    302   1.1  jonathan 		t_sack_block[j].left = left;
    303   1.1  jonathan 		t_sack_block[j].right = right;
    304   1.1  jonathan 	}
    305   1.1  jonathan 
    306   1.1  jonathan 	/* Update the scoreboard. */
    307   1.1  jonathan 	cur = TAILQ_FIRST(&tp->snd_holes);
    308   1.1  jonathan 	for (i = 0; i < num_sack_blks; i++) {
    309   1.1  jonathan 		sack = &t_sack_block[i];
    310   1.1  jonathan 		/*
    311   1.1  jonathan 		 * FACK TCP.  Update snd_fack so we can enter Fast
    312   1.1  jonathan 		 * Recovery early.
    313   1.1  jonathan 		 */
    314   1.1  jonathan 		if (SEQ_GEQ(sack->right, tp->snd_fack))
    315   1.1  jonathan 			tp->snd_fack = sack->right;
    316   1.1  jonathan 
    317   1.1  jonathan 		if (TAILQ_EMPTY(&tp->snd_holes)) {
    318   1.1  jonathan 			/* First hole. */
    319  1.19      yamt 			cur = sack_inserthole(tp, th->th_ack, sack->left, NULL);
    320   1.1  jonathan 			if (cur == NULL) {
    321   1.1  jonathan 				/* ENOBUFS, bail out*/
    322   1.1  jonathan 				return;
    323   1.1  jonathan 			}
    324   1.1  jonathan 			tp->rcv_lastsack = sack->right;
    325   1.1  jonathan 			continue; /* With next sack block */
    326   1.1  jonathan 		}
    327   1.1  jonathan 
    328   1.1  jonathan 		/* Go through the list of holes. */
    329   1.1  jonathan 		while (cur) {
    330   1.6      yamt 			if (SEQ_LEQ(sack->right, cur->start))
    331   1.1  jonathan 				/* SACKs data before the current hole */
    332   1.1  jonathan 				break; /* No use going through more holes */
    333   1.1  jonathan 
    334   1.1  jonathan 			if (SEQ_GEQ(sack->left, cur->end)) {
    335   1.1  jonathan 				/* SACKs data beyond the current hole */
    336   1.1  jonathan 				cur = TAILQ_NEXT(cur, sackhole_q);
    337   1.1  jonathan 				continue;
    338   1.1  jonathan 			}
    339   1.1  jonathan 
    340   1.1  jonathan 			if (SEQ_LEQ(sack->left, cur->start)) {
    341   1.1  jonathan 				/* Data acks at least the beginning of hole */
    342   1.1  jonathan 				if (SEQ_GEQ(sack->right, cur->end)) {
    343   1.1  jonathan 					/* Acks entire hole, so delete hole */
    344  1.19      yamt 					cur = sack_removehole(tp, cur);
    345   1.1  jonathan 					break;
    346   1.1  jonathan 				}
    347   1.1  jonathan 
    348   1.1  jonathan 				/* Otherwise, move start of hole forward */
    349   1.1  jonathan 				cur->start = sack->right;
    350   1.1  jonathan 				cur->rxmit = SEQ_MAX(cur->rxmit, cur->start);
    351   1.1  jonathan 				break;
    352   1.1  jonathan 			}
    353   1.1  jonathan 
    354   1.1  jonathan 			if (SEQ_GEQ(sack->right, cur->end)) {
    355   1.1  jonathan 				/* Move end of hole backward. */
    356   1.1  jonathan 				cur->end = sack->left;
    357   1.1  jonathan 				cur->rxmit = SEQ_MIN(cur->rxmit, cur->end);
    358   1.1  jonathan 				cur = TAILQ_NEXT(cur, sackhole_q);
    359   1.1  jonathan 				break;
    360   1.1  jonathan 			}
    361   1.1  jonathan 
    362   1.1  jonathan 			if (SEQ_LT(cur->start, sack->left) &&
    363   1.1  jonathan 			    SEQ_GT(cur->end, sack->right)) {
    364   1.1  jonathan 				/*
    365   1.1  jonathan 				 * ACKs some data in middle of a hole; need to
    366   1.1  jonathan 				 * split current hole
    367   1.1  jonathan 				 */
    368  1.19      yamt 				tmp = sack_inserthole(tp, sack->right, cur->end,
    369  1.19      yamt 				    cur);
    370   1.1  jonathan 				if (tmp == NULL) {
    371   1.1  jonathan 					return;
    372   1.1  jonathan 				}
    373   1.1  jonathan 				tmp->rxmit = SEQ_MAX(cur->rxmit, tmp->start);
    374   1.1  jonathan 				cur->end = sack->left;
    375   1.1  jonathan 				cur->rxmit = SEQ_MIN(cur->rxmit, cur->end);
    376   1.7      yamt 				cur = tmp;
    377   1.1  jonathan 				break;
    378   1.1  jonathan 			}
    379   1.1  jonathan 		}
    380   1.1  jonathan 
    381   1.1  jonathan 		/* At this point, we have reached the tail of the list. */
    382   1.1  jonathan 		if (SEQ_LT(tp->rcv_lastsack, sack->left)) {
    383   1.1  jonathan 			/*
    384   1.1  jonathan 			 * Need to append new hole at end.
    385   1.1  jonathan 			 */
    386  1.19      yamt 			cur = sack_inserthole(tp, tp->rcv_lastsack, sack->left,
    387  1.19      yamt 			    NULL);
    388  1.19      yamt 			if (cur == NULL) {
    389  1.12  kurahone 				return;
    390  1.12  kurahone 			}
    391   1.1  jonathan 		}
    392   1.8      yamt 		if (SEQ_LT(tp->rcv_lastsack, sack->right)) {
    393   1.8      yamt 			tp->rcv_lastsack = sack->right;
    394   1.8      yamt 		}
    395   1.1  jonathan 	}
    396   1.1  jonathan }
    397   1.1  jonathan 
    398  1.26      yamt /*
    399  1.26      yamt  * tcp_del_sackholes: remove holes covered by a cumulative ACK.
    400  1.26      yamt  */
    401  1.26      yamt 
    402   1.1  jonathan void
    403  1.21      yamt tcp_del_sackholes(struct tcpcb *tp, const struct tcphdr *th)
    404   1.1  jonathan {
    405   1.1  jonathan 	/* Max because this could be an older ack that just arrived. */
    406   1.1  jonathan 	tcp_seq lastack = SEQ_GT(th->th_ack, tp->snd_una) ?
    407   1.1  jonathan 		th->th_ack : tp->snd_una;
    408   1.1  jonathan 	struct sackhole *cur = TAILQ_FIRST(&tp->snd_holes);
    409   1.1  jonathan 
    410   1.1  jonathan 	while (cur) {
    411   1.1  jonathan 		if (SEQ_LEQ(cur->end, lastack)) {
    412  1.19      yamt 			cur = sack_removehole(tp, cur);
    413   1.1  jonathan 		} else if (SEQ_LT(cur->start, lastack)) {
    414   1.1  jonathan 			cur->start = lastack;
    415   1.1  jonathan 			if (SEQ_LT(cur->rxmit, cur->start))
    416   1.1  jonathan 				cur->rxmit = cur->start;
    417   1.1  jonathan 			break;
    418   1.1  jonathan 		} else
    419   1.1  jonathan 			break;
    420   1.1  jonathan 	}
    421   1.1  jonathan }
    422   1.1  jonathan 
    423  1.26      yamt /*
    424  1.26      yamt  * tcp_free_sackholes: clear the scoreboard.
    425  1.26      yamt  */
    426  1.26      yamt 
    427   1.1  jonathan void
    428   1.1  jonathan tcp_free_sackholes(struct tcpcb *tp)
    429   1.1  jonathan {
    430   1.1  jonathan 	struct sackhole *sack;
    431   1.1  jonathan 
    432   1.1  jonathan 	/* Free up the SACK hole list. */
    433  1.19      yamt 	while ((sack = TAILQ_FIRST(&tp->snd_holes)) != NULL) {
    434  1.19      yamt 		sack_removehole(tp, sack);
    435   1.1  jonathan 	}
    436  1.19      yamt 	KASSERT(tp->snd_numholes == 0);
    437   1.1  jonathan }
    438   1.1  jonathan 
    439   1.1  jonathan /*
    440   1.1  jonathan  * Returns pointer to a sackhole if there are any pending retransmissions;
    441   1.1  jonathan  * NULL otherwise.
    442   1.1  jonathan  */
    443   1.1  jonathan struct sackhole *
    444   1.1  jonathan tcp_sack_output(struct tcpcb *tp, int *sack_bytes_rexmt)
    445   1.1  jonathan {
    446   1.1  jonathan 	struct sackhole *cur = NULL;
    447   1.1  jonathan 
    448  1.17      yamt 	if (!TCP_SACK_ENABLED(tp))
    449   1.1  jonathan 		return (NULL);
    450   1.1  jonathan 
    451   1.1  jonathan 	*sack_bytes_rexmt = 0;
    452   1.1  jonathan 	TAILQ_FOREACH(cur, &tp->snd_holes, sackhole_q) {
    453   1.1  jonathan 		if (SEQ_LT(cur->rxmit, cur->end)) {
    454   1.2      yamt 			if (SEQ_LT(cur->rxmit, tp->snd_una)) {
    455   1.2      yamt 				/* old SACK hole */
    456   1.1  jonathan 				continue;
    457   1.1  jonathan 			}
    458   1.1  jonathan 			*sack_bytes_rexmt += (cur->rxmit - cur->start);
    459   1.1  jonathan 			break;
    460   1.1  jonathan 		}
    461   1.1  jonathan 		*sack_bytes_rexmt += (cur->rxmit - cur->start);
    462   1.1  jonathan 	}
    463   1.1  jonathan 
    464   1.1  jonathan 	return (cur);
    465   1.1  jonathan }
    466   1.1  jonathan 
    467   1.1  jonathan /*
    468   1.1  jonathan  * After a timeout, the SACK list may be rebuilt.  This SACK information
    469   1.1  jonathan  * should be used to avoid retransmitting SACKed data.  This function
    470   1.1  jonathan  * traverses the SACK list to see if snd_nxt should be moved forward.
    471   1.1  jonathan  */
    472   1.1  jonathan void
    473   1.1  jonathan tcp_sack_adjust(struct tcpcb *tp)
    474   1.1  jonathan {
    475   1.1  jonathan 	struct sackhole *cur = TAILQ_FIRST(&tp->snd_holes);
    476   1.1  jonathan 	struct sackhole *n = NULL;
    477   1.1  jonathan 
    478   1.1  jonathan 	if (TAILQ_EMPTY(&tp->snd_holes))
    479   1.1  jonathan 		return; /* No holes */
    480   1.1  jonathan 	if (SEQ_GEQ(tp->snd_nxt, tp->rcv_lastsack))
    481   1.1  jonathan 		return; /* We're already beyond any SACKed blocks */
    482   1.1  jonathan 
    483   1.1  jonathan 	/*
    484   1.1  jonathan 	 * Two cases for which we want to advance snd_nxt:
    485   1.1  jonathan 	 * i) snd_nxt lies between end of one hole and beginning of another
    486   1.1  jonathan 	 * ii) snd_nxt lies between end of last hole and rcv_lastsack
    487   1.1  jonathan 	 */
    488   1.1  jonathan 	while ((n = TAILQ_NEXT(cur, sackhole_q)) != NULL) {
    489   1.1  jonathan 		if (SEQ_LT(tp->snd_nxt, cur->end))
    490   1.1  jonathan 			return;
    491   1.1  jonathan 		if (SEQ_GEQ(tp->snd_nxt, n->start))
    492   1.1  jonathan 			cur = n;
    493   1.1  jonathan 		else {
    494   1.1  jonathan 			tp->snd_nxt = n->start;
    495   1.1  jonathan 			return;
    496   1.1  jonathan 		}
    497   1.1  jonathan 	}
    498   1.1  jonathan 	if (SEQ_LT(tp->snd_nxt, cur->end))
    499   1.1  jonathan 		return;
    500   1.1  jonathan 	tp->snd_nxt = tp->rcv_lastsack;
    501   1.1  jonathan 
    502   1.1  jonathan 	return;
    503   1.1  jonathan }
    504   1.9      yamt 
    505  1.26      yamt /*
    506  1.26      yamt  * tcp_sack_numblks: return the number of SACK blocks to send.
    507  1.26      yamt  */
    508  1.26      yamt 
    509   1.9      yamt int
    510  1.10      yamt tcp_sack_numblks(const struct tcpcb *tp)
    511   1.9      yamt {
    512  1.10      yamt 	int numblks;
    513   1.9      yamt 
    514  1.10      yamt 	if (!TCP_SACK_ENABLED(tp)) {
    515   1.9      yamt 		return 0;
    516   1.9      yamt 	}
    517   1.9      yamt 
    518  1.10      yamt 	numblks = (((tp->rcv_sack_flags & TCPSACK_HAVED) != 0) ? 1 : 0) +
    519  1.10      yamt 	    tp->t_segqlen;
    520  1.10      yamt 
    521  1.10      yamt 	if (numblks == 0) {
    522  1.10      yamt 		return 0;
    523  1.10      yamt 	}
    524  1.10      yamt 
    525  1.10      yamt 	if (numblks > TCP_SACK_MAX) {
    526  1.10      yamt 		numblks = TCP_SACK_MAX;
    527  1.10      yamt 	}
    528  1.10      yamt 
    529  1.10      yamt 	return numblks;
    530   1.9      yamt }
    531  1.22      yamt 
    532  1.22      yamt #if defined(DDB)
    533  1.22      yamt void sack_dump(const struct tcpcb *);
    534  1.22      yamt 
    535  1.22      yamt void
    536  1.22      yamt sack_dump(const struct tcpcb *tp)
    537  1.22      yamt {
    538  1.22      yamt 	const struct sackhole *cur;
    539  1.22      yamt 
    540  1.22      yamt 	printf("snd_una=%" PRIu32 ", snd_max=%" PRIu32 "\n",
    541  1.22      yamt 	    tp->snd_una, tp->snd_max);
    542  1.22      yamt 	printf("rcv_lastsack=%" PRIu32 ", snd_fack=%" PRIu32 "\n",
    543  1.22      yamt 	    tp->rcv_lastsack, tp->snd_fack);
    544  1.22      yamt 	printf("numholes=%d\n", tp->snd_numholes);
    545  1.22      yamt 	TAILQ_FOREACH(cur, &tp->snd_holes, sackhole_q) {
    546  1.22      yamt 		printf("\t%" PRIu32 "-%" PRIu32 ", rxmit=%" PRIu32 "\n",
    547  1.22      yamt 		    cur->start, cur->end, cur->rxmit);
    548  1.22      yamt 	}
    549  1.22      yamt }
    550  1.22      yamt #endif /* defined(DDB) */
    551