1/* 2 * Copyright (c) 2004,2007 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 30 * The Regents of the University of California. All rights reserved. 31 * 32 * Redistribution and use in source and binary forms, with or without 33 * modification, are permitted provided that the following conditions 34 * are met: 35 * 1. Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * 2. Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditions and the following disclaimer in the 39 * documentation and/or other materials provided with the distribution. 40 * 3. All advertising materials mentioning features or use of this software 41 * must display the following acknowledgement: 42 * This product includes software developed by the University of 43 * California, Berkeley and its contributors. 44 * 4. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 * 60 */ 61 62#define _IP_VHL 63 64 65#include <sys/param.h> 66#include <sys/systm.h> 67#include <sys/kernel.h> 68#include <sys/sysctl.h> 69#include <sys/mbuf.h> 70#include <sys/domain.h> 71#include <sys/protosw.h> 72#include <sys/socket.h> 73#include <sys/socketvar.h> 74 75#include <kern/zalloc.h> 76 77#include <net/route.h> 78 79#include <netinet/in.h> 80#include <netinet/in_systm.h> 81#include <netinet/ip.h> 82#include <netinet/in_pcb.h> 83#include <netinet/ip_var.h> 84#if INET6 85#include <netinet6/in6_pcb.h> 86#include <netinet/ip6.h> 87#include <netinet6/ip6_var.h> 88#endif 89#include <netinet/tcp.h> 90//#define TCPOUTFLAGS 91#include <netinet/tcp_fsm.h> 92#include <netinet/tcp_seq.h> 93#include <netinet/tcp_timer.h> 94#include <netinet/tcp_var.h> 95#include <netinet/tcpip.h> 96#if TCPDEBUG 97#include <netinet/tcp_debug.h> 98#endif 99#include <sys/kdebug.h> 100 101#if IPSEC 102#include <netinet6/ipsec.h> 103#endif /*IPSEC*/ 104 105int tcp_do_sack = 1; 106SYSCTL_INT(_net_inet_tcp, OID_AUTO, sack, CTLFLAG_RW, &tcp_do_sack, 0, 107 "Enable/Disable TCP SACK support"); 108static int tcp_sack_maxholes = 128; 109SYSCTL_INT(_net_inet_tcp, OID_AUTO, sack_maxholes, CTLFLAG_RW, 110 &tcp_sack_maxholes, 0, 111 "Maximum number of TCP SACK holes allowed per connection"); 112 113static int tcp_sack_globalmaxholes = 65536; 114SYSCTL_INT(_net_inet_tcp, OID_AUTO, sack_globalmaxholes, CTLFLAG_RW, 115 &tcp_sack_globalmaxholes, 0, 116 "Global maximum number of TCP SACK holes"); 117 118static int tcp_sack_globalholes = 0; 119SYSCTL_INT(_net_inet_tcp, OID_AUTO, sack_globalholes, CTLFLAG_RD, 120 &tcp_sack_globalholes, 0, 121 "Global number of TCP SACK holes currently allocated"); 122 123extern struct zone *sack_hole_zone; 124 125/* 126 * This function is called upon receipt of new valid data (while not in header 127 * prediction mode), and it updates the ordered list of sacks. 128 */ 129void 130tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_start, tcp_seq rcv_end) 131{ 132 /* 133 * First reported block MUST be the most recent one. Subsequent 134 * blocks SHOULD be in the order in which they arrived at the 135 * receiver. These two conditions make the implementation fully 136 * compliant with RFC 2018. 137 */ 138 struct sackblk head_blk, saved_blks[MAX_SACK_BLKS]; 139 int num_head, num_saved, i; 140 141 /* SACK block for the received segment. */ 142 head_blk.start = rcv_start; 143 head_blk.end = rcv_end; 144 145 /* 146 * Merge updated SACK blocks into head_blk, and 147 * save unchanged SACK blocks into saved_blks[]. 148 * num_saved will have the number of the saved SACK blocks. 149 */ 150 num_saved = 0; 151 for (i = 0; i < tp->rcv_numsacks; i++) { 152 tcp_seq start = tp->sackblks[i].start; 153 tcp_seq end = tp->sackblks[i].end; 154 if (SEQ_GEQ(start, end) || SEQ_LEQ(start, tp->rcv_nxt)) { 155 /* 156 * Discard this SACK block. 157 */ 158 } else if (SEQ_LEQ(head_blk.start, end) && 159 SEQ_GEQ(head_blk.end, start)) { 160 /* 161 * Merge this SACK block into head_blk. 162 * This SACK block itself will be discarded. 163 */ 164 if (SEQ_GT(head_blk.start, start)) 165 head_blk.start = start; 166 if (SEQ_LT(head_blk.end, end)) 167 head_blk.end = end; 168 } else { 169 /* 170 * Save this SACK block. 171 */ 172 saved_blks[num_saved].start = start; 173 saved_blks[num_saved].end = end; 174 num_saved++; 175 } 176 } 177 178 /* 179 * Update SACK list in tp->sackblks[]. 180 */ 181 num_head = 0; 182 if (SEQ_GT(head_blk.start, tp->rcv_nxt)) { 183 /* 184 * The received data segment is an out-of-order segment. 185 * Put head_blk at the top of SACK list. 186 */ 187 tp->sackblks[0] = head_blk; 188 num_head = 1; 189 /* 190 * If the number of saved SACK blocks exceeds its limit, 191 * discard the last SACK block. 192 */ 193 if (num_saved >= MAX_SACK_BLKS) 194 num_saved--; 195 } 196 if (num_saved > 0) { 197 /* 198 * Copy the saved SACK blocks back. 199 */ 200 bcopy(saved_blks, &tp->sackblks[num_head], 201 sizeof(struct sackblk) * num_saved); 202 } 203 204 /* Save the number of SACK blocks. */ 205 tp->rcv_numsacks = num_head + num_saved; 206} 207 208/* 209 * Delete all receiver-side SACK information. 210 */ 211void 212tcp_clean_sackreport( struct tcpcb *tp) 213{ 214/* 215 int i; 216 217 tp->rcv_numsacks = 0; 218 for (i = 0; i < MAX_SACK_BLKS; i++) 219 tp->sackblks[i].start = tp->sackblks[i].end=0; 220*/ 221 bzero(&tp->sackblks[0], sizeof (struct sackblk) * MAX_SACK_BLKS); 222} 223 224/* 225 * Allocate struct sackhole. 226 */ 227static struct sackhole * 228tcp_sackhole_alloc(struct tcpcb *tp, tcp_seq start, tcp_seq end) 229{ 230 struct sackhole *hole; 231 232 if (tp->snd_numholes >= tcp_sack_maxholes || 233 tcp_sack_globalholes >= tcp_sack_globalmaxholes) { 234 tcpstat.tcps_sack_sboverflow++; 235 return NULL; 236 } 237 238 hole = (struct sackhole *)zalloc_noblock(sack_hole_zone); 239 if (hole == NULL) 240 return NULL; 241 242 hole->start = start; 243 hole->end = end; 244 hole->rxmit = start; 245 246 tp->snd_numholes++; 247 tcp_sack_globalholes++; 248 249 return hole; 250} 251 252/* 253 * Free struct sackhole. 254 */ 255static void 256tcp_sackhole_free(struct tcpcb *tp, struct sackhole *hole) 257{ 258 zfree(sack_hole_zone, hole); 259 260 tp->snd_numholes--; 261 tcp_sack_globalholes--; 262} 263 264/* 265 * Insert new SACK hole into scoreboard. 266 */ 267static struct sackhole * 268tcp_sackhole_insert(struct tcpcb *tp, tcp_seq start, tcp_seq end, 269 struct sackhole *after) 270{ 271 struct sackhole *hole; 272 273 /* Allocate a new SACK hole. */ 274 hole = tcp_sackhole_alloc(tp, start, end); 275 if (hole == NULL) 276 return NULL; 277 278 /* Insert the new SACK hole into scoreboard */ 279 if (after != NULL) 280 TAILQ_INSERT_AFTER(&tp->snd_holes, after, hole, scblink); 281 else 282 TAILQ_INSERT_TAIL(&tp->snd_holes, hole, scblink); 283 284 /* Update SACK hint. */ 285 if (tp->sackhint.nexthole == NULL) 286 tp->sackhint.nexthole = hole; 287 288 return hole; 289} 290 291/* 292 * Remove SACK hole from scoreboard. 293 */ 294static void 295tcp_sackhole_remove(struct tcpcb *tp, struct sackhole *hole) 296{ 297 /* Update SACK hint. */ 298 if (tp->sackhint.nexthole == hole) 299 tp->sackhint.nexthole = TAILQ_NEXT(hole, scblink); 300 301 /* Remove this SACK hole. */ 302 TAILQ_REMOVE(&tp->snd_holes, hole, scblink); 303 304 /* Free this SACK hole. */ 305 tcp_sackhole_free(tp, hole); 306} 307 308/* 309 * Process cumulative ACK and the TCP SACK option to update the scoreboard. 310 * tp->snd_holes is an ordered list of holes (oldest to newest, in terms of 311 * the sequence space). 312 */ 313void 314tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack) 315{ 316 struct sackhole *cur, *temp; 317 struct sackblk sack, sack_blocks[TCP_MAX_SACK + 1], *sblkp; 318 int i, j, num_sack_blks; 319 320 num_sack_blks = 0; 321 /* 322 * If SND.UNA will be advanced by SEG.ACK, and if SACK holes exist, 323 * treat [SND.UNA, SEG.ACK) as if it is a SACK block. 324 */ 325 if (SEQ_LT(tp->snd_una, th_ack) && !TAILQ_EMPTY(&tp->snd_holes)) { 326 sack_blocks[num_sack_blks].start = tp->snd_una; 327 sack_blocks[num_sack_blks++].end = th_ack; 328 } 329 /* 330 * Append received valid SACK blocks to sack_blocks[]. 331 */ 332 for (i = 0; i < to->to_nsacks; i++) { 333 bcopy((to->to_sacks + i * TCPOLEN_SACK), &sack, sizeof(sack)); 334 sack.start = ntohl(sack.start); 335 sack.end = ntohl(sack.end); 336 if (SEQ_GT(sack.end, sack.start) && 337 SEQ_GT(sack.start, tp->snd_una) && 338 SEQ_GT(sack.start, th_ack) && 339 SEQ_LEQ(sack.end, tp->snd_max)) 340 sack_blocks[num_sack_blks++] = sack; 341 } 342 343 /* 344 * Return if SND.UNA is not advanced and no valid SACK block 345 * is received. 346 */ 347 if (num_sack_blks == 0) 348 return; 349 350 /* 351 * Sort the SACK blocks so we can update the scoreboard 352 * with just one pass. The overhead of sorting upto 4+1 elements 353 * is less than making upto 4+1 passes over the scoreboard. 354 */ 355 for (i = 0; i < num_sack_blks; i++) { 356 for (j = i + 1; j < num_sack_blks; j++) { 357 if (SEQ_GT(sack_blocks[i].end, sack_blocks[j].end)) { 358 sack = sack_blocks[i]; 359 sack_blocks[i] = sack_blocks[j]; 360 sack_blocks[j] = sack; 361 } 362 } 363 } 364 if (TAILQ_EMPTY(&tp->snd_holes)) 365 /* 366 * Empty scoreboard. Need to initialize snd_fack (it may be 367 * uninitialized or have a bogus value). Scoreboard holes 368 * (from the sack blocks received) are created later below (in 369 * the logic that adds holes to the tail of the scoreboard). 370 */ 371 tp->snd_fack = SEQ_MAX(tp->snd_una, th_ack); 372 /* 373 * In the while-loop below, incoming SACK blocks (sack_blocks[]) 374 * and SACK holes (snd_holes) are traversed from their tails with 375 * just one pass in order to reduce the number of compares especially 376 * when the bandwidth-delay product is large. 377 * Note: Typically, in the first RTT of SACK recovery, the highest 378 * three or four SACK blocks with the same ack number are received. 379 * In the second RTT, if retransmitted data segments are not lost, 380 * the highest three or four SACK blocks with ack number advancing 381 * are received. 382 */ 383 sblkp = &sack_blocks[num_sack_blks - 1]; /* Last SACK block */ 384 if (SEQ_LT(tp->snd_fack, sblkp->start)) { 385 /* 386 * The highest SACK block is beyond fack. 387 * Append new SACK hole at the tail. 388 * If the second or later highest SACK blocks are also 389 * beyond the current fack, they will be inserted by 390 * way of hole splitting in the while-loop below. 391 */ 392 temp = tcp_sackhole_insert(tp, tp->snd_fack,sblkp->start,NULL); 393 if (temp != NULL) { 394 tp->snd_fack = sblkp->end; 395 /* Go to the previous sack block. */ 396 sblkp--; 397 } else { 398 /* 399 * We failed to add a new hole based on the current 400 * sack block. Skip over all the sack blocks that 401 * fall completely to the right of snd_fack and proceed 402 * to trim the scoreboard based on the remaining sack 403 * blocks. This also trims the scoreboard for th_ack 404 * (which is sack_blocks[0]). 405 */ 406 while (sblkp >= sack_blocks && 407 SEQ_LT(tp->snd_fack, sblkp->start)) 408 sblkp--; 409 if (sblkp >= sack_blocks && 410 SEQ_LT(tp->snd_fack, sblkp->end)) 411 tp->snd_fack = sblkp->end; 412 } 413 } else if (SEQ_LT(tp->snd_fack, sblkp->end)) 414 /* fack is advanced. */ 415 tp->snd_fack = sblkp->end; 416 /* We must have at least one SACK hole in scoreboard */ 417 cur = TAILQ_LAST(&tp->snd_holes, sackhole_head); /* Last SACK hole */ 418 /* 419 * Since the incoming sack blocks are sorted, we can process them 420 * making one sweep of the scoreboard. 421 */ 422 while (sblkp >= sack_blocks && cur != NULL) { 423 if (SEQ_GEQ(sblkp->start, cur->end)) { 424 /* 425 * SACKs data beyond the current hole. 426 * Go to the previous sack block. 427 */ 428 sblkp--; 429 continue; 430 } 431 if (SEQ_LEQ(sblkp->end, cur->start)) { 432 /* 433 * SACKs data before the current hole. 434 * Go to the previous hole. 435 */ 436 cur = TAILQ_PREV(cur, sackhole_head, scblink); 437 continue; 438 } 439 tp->sackhint.sack_bytes_rexmit -= (cur->rxmit - cur->start); 440 if (SEQ_LEQ(sblkp->start, cur->start)) { 441 /* Data acks at least the beginning of hole */ 442 if (SEQ_GEQ(sblkp->end, cur->end)) { 443 /* Acks entire hole, so delete hole */ 444 temp = cur; 445 cur = TAILQ_PREV(cur, sackhole_head, scblink); 446 tcp_sackhole_remove(tp, temp); 447 /* 448 * The sack block may ack all or part of the next 449 * hole too, so continue onto the next hole. 450 */ 451 continue; 452 } else { 453 /* Move start of hole forward */ 454 cur->start = sblkp->end; 455 cur->rxmit = SEQ_MAX(cur->rxmit, cur->start); 456 } 457 } else { 458 /* Data acks at least the end of hole */ 459 if (SEQ_GEQ(sblkp->end, cur->end)) { 460 /* Move end of hole backward */ 461 cur->end = sblkp->start; 462 cur->rxmit = SEQ_MIN(cur->rxmit, cur->end); 463 } else { 464 /* 465 * ACKs some data in middle of a hole; need to 466 * split current hole 467 */ 468 temp = tcp_sackhole_insert(tp, sblkp->end, 469 cur->end, cur); 470 if (temp != NULL) { 471 if (SEQ_GT(cur->rxmit, temp->rxmit)) { 472 temp->rxmit = cur->rxmit; 473 tp->sackhint.sack_bytes_rexmit 474 += (temp->rxmit 475 - temp->start); 476 } 477 cur->end = sblkp->start; 478 cur->rxmit = SEQ_MIN(cur->rxmit, 479 cur->end); 480 } 481 } 482 } 483 tp->sackhint.sack_bytes_rexmit += (cur->rxmit - cur->start); 484 /* 485 * Testing sblkp->start against cur->start tells us whether 486 * we're done with the sack block or the sack hole. 487 * Accordingly, we advance one or the other. 488 */ 489 if (SEQ_LEQ(sblkp->start, cur->start)) 490 cur = TAILQ_PREV(cur, sackhole_head, scblink); 491 else 492 sblkp--; 493 } 494} 495 496/* 497 * Free all SACK holes to clear the scoreboard. 498 */ 499void 500tcp_free_sackholes(struct tcpcb *tp) 501{ 502 struct sackhole *q; 503 504 while ((q = TAILQ_FIRST(&tp->snd_holes)) != NULL) 505 tcp_sackhole_remove(tp, q); 506 tp->sackhint.sack_bytes_rexmit = 0; 507 508} 509 510/* 511 * Partial ack handling within a sack recovery episode. 512 * Keeping this very simple for now. When a partial ack 513 * is received, force snd_cwnd to a value that will allow 514 * the sender to transmit no more than 2 segments. 515 * If necessary, a better scheme can be adopted at a 516 * later point, but for now, the goal is to prevent the 517 * sender from bursting a large amount of data in the midst 518 * of sack recovery. 519 */ 520void 521tcp_sack_partialack(tp, th) 522 struct tcpcb *tp; 523 struct tcphdr *th; 524{ 525 int num_segs = 1; 526 527 tp->t_timer[TCPT_REXMT] = 0; 528 tp->t_rtttime = 0; 529 /* send one or 2 segments based on how much new data was acked */ 530 if (((th->th_ack - tp->snd_una) / tp->t_maxseg) > 2) 531 num_segs = 2; 532 tp->snd_cwnd = (tp->sackhint.sack_bytes_rexmit + 533 (tp->snd_nxt - tp->sack_newdata) + 534 num_segs * tp->t_maxseg); 535 if (tp->snd_cwnd > tp->snd_ssthresh) 536 tp->snd_cwnd = tp->snd_ssthresh; 537 tp->t_flags |= TF_ACKNOW; 538 (void) tcp_output(tp); 539} 540 541/* 542 * Debug version of tcp_sack_output() that walks the scoreboard. Used for 543 * now to sanity check the hint. 544 */ 545static struct sackhole * 546tcp_sack_output_debug(struct tcpcb *tp, int *sack_bytes_rexmt) 547{ 548 struct sackhole *p; 549 550 *sack_bytes_rexmt = 0; 551 TAILQ_FOREACH(p, &tp->snd_holes, scblink) { 552 if (SEQ_LT(p->rxmit, p->end)) { 553 if (SEQ_LT(p->rxmit, tp->snd_una)) {/* old SACK hole */ 554 continue; 555 } 556 *sack_bytes_rexmt += (p->rxmit - p->start); 557 break; 558 } 559 *sack_bytes_rexmt += (p->rxmit - p->start); 560 } 561 return (p); 562} 563 564/* 565 * Returns the next hole to retransmit and the number of retransmitted bytes 566 * from the scoreboard. We store both the next hole and the number of 567 * retransmitted bytes as hints (and recompute these on the fly upon SACK/ACK 568 * reception). This avoids scoreboard traversals completely. 569 * 570 * The loop here will traverse *at most* one link. Here's the argument. 571 * For the loop to traverse more than 1 link before finding the next hole to 572 * retransmit, we would need to have at least 1 node following the current hint 573 * with (rxmit == end). But, for all holes following the current hint, 574 * (start == rxmit), since we have not yet retransmitted from them. Therefore, 575 * in order to traverse more 1 link in the loop below, we need to have at least 576 * one node following the current hint with (start == rxmit == end). 577 * But that can't happen, (start == end) means that all the data in that hole 578 * has been sacked, in which case, the hole would have been removed from the 579 * scoreboard. 580 */ 581struct sackhole * 582tcp_sack_output(struct tcpcb *tp, int *sack_bytes_rexmt) 583{ 584 struct sackhole *hole = NULL, *dbg_hole = NULL; 585 int dbg_bytes_rexmt; 586 587 dbg_hole = tcp_sack_output_debug(tp, &dbg_bytes_rexmt); 588 *sack_bytes_rexmt = tp->sackhint.sack_bytes_rexmit; 589 hole = tp->sackhint.nexthole; 590 if (hole == NULL || SEQ_LT(hole->rxmit, hole->end)) 591 goto out; 592 while ((hole = TAILQ_NEXT(hole, scblink)) != NULL) { 593 if (SEQ_LT(hole->rxmit, hole->end)) { 594 tp->sackhint.nexthole = hole; 595 break; 596 } 597 } 598out: 599 if (dbg_hole != hole) { 600 printf("%s: Computed sack hole not the same as cached value\n", __func__); 601 hole = dbg_hole; 602 } 603 if (*sack_bytes_rexmt != dbg_bytes_rexmt) { 604 printf("%s: Computed sack_bytes_retransmitted (%d) not " 605 "the same as cached value (%d)\n", 606 __func__, dbg_bytes_rexmt, *sack_bytes_rexmt); 607 *sack_bytes_rexmt = dbg_bytes_rexmt; 608 } 609 return (hole); 610} 611 612/* 613 * After a timeout, the SACK list may be rebuilt. This SACK information 614 * should be used to avoid retransmitting SACKed data. This function 615 * traverses the SACK list to see if snd_nxt should be moved forward. 616 */ 617void 618tcp_sack_adjust(struct tcpcb *tp) 619{ 620 struct sackhole *p, *cur = TAILQ_FIRST(&tp->snd_holes); 621 622 if (cur == NULL) 623 return; /* No holes */ 624 if (SEQ_GEQ(tp->snd_nxt, tp->snd_fack)) 625 return; /* We're already beyond any SACKed blocks */ 626 /* 627 * Two cases for which we want to advance snd_nxt: 628 * i) snd_nxt lies between end of one hole and beginning of another 629 * ii) snd_nxt lies between end of last hole and snd_fack 630 */ 631 while ((p = TAILQ_NEXT(cur, scblink)) != NULL) { 632 if (SEQ_LT(tp->snd_nxt, cur->end)) 633 return; 634 if (SEQ_GEQ(tp->snd_nxt, p->start)) 635 cur = p; 636 else { 637 tp->snd_nxt = p->start; 638 return; 639 } 640 } 641 if (SEQ_LT(tp->snd_nxt, cur->end)) 642 return; 643 tp->snd_nxt = tp->snd_fack; 644 return; 645} 646