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