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$ 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_ipfw.h" /* for ipfw_fwd */ 100 #include "opt_inet.h" 101 #include "opt_inet6.h" 102 #include "opt_ipsec.h" 103 #include "opt_tcpdebug.h" 104 #include "opt_tcp_input.h" 105 #include "opt_tcp_sack.h" 106 107 #include <sys/param.h> 108 #include <sys/systm.h> 109 #include <sys/kernel.h> 110 #include <sys/sysctl.h> 111 #include <sys/malloc.h> 112 #include <sys/mbuf.h> 113 #include <sys/proc.h> /* for proc0 declaration */ 114 #include <sys/protosw.h> 115 #include <sys/socket.h> 116 #include <sys/socketvar.h> 117 #include <sys/syslog.h> 118 #include <sys/systm.h> 119 120 #include <machine/cpu.h> /* before tcp_seq.h, for tcp_random18() */ 121 122 #include <vm/uma.h> 123 124 #include <net/if.h> 125 #include <net/route.h> 126 127 #include <netinet/in.h> 128 #include <netinet/in_systm.h> 129 #include <netinet/ip.h> 130 #include <netinet/ip_icmp.h> /* for ICMP_BANDLIM */ 131 #include <netinet/in_var.h> 132 #include <netinet/icmp_var.h> /* for ICMP_BANDLIM */ 133 #include <netinet/in_pcb.h> 134 #include <netinet/ip_var.h> 135 #include <netinet/ip6.h> 136 #include <netinet/icmp6.h> 137 #include <netinet6/nd6.h> 138 #include <netinet6/ip6_var.h> 139 #include <netinet6/in6_pcb.h> 140 #include <netinet/tcp.h> 141 #include <netinet/tcp_fsm.h> 142 #include <netinet/tcp_seq.h> 143 #include <netinet/tcp_timer.h> 144 #include <netinet/tcp_var.h> 145 #include <netinet6/tcp6_var.h> 146 #include <netinet/tcpip.h> 147 #ifdef TCPDEBUG 148 #include <netinet/tcp_debug.h> 149 150 u_char tcp_saveipgen[40]; /* the size must be of max ip header, now IPv6 */ 151 struct tcphdr tcp_savetcp; 152 #endif /* TCPDEBUG */ 153 154 #ifdef FAST_IPSEC 155 #include <netipsec/ipsec.h> 156 #include <netipsec/ipsec6.h> 157 #endif 158 159 #ifdef IPSEC 160 #include <netinet6/ipsec.h> 161 #include <netinet6/ipsec6.h> 162 #include <netkey/key.h> 163 #endif /*IPSEC*/ 164 #include <machine/in_cksum.h> 165 166 extern struct uma_zone *sack_hole_zone; 167 168 /* 169 * This function is called upon receipt of new valid data (while not in header 170 * prediction mode), and it updates the ordered list of sacks. 171 */ 172 void 173 tcp_update_sack_list(tp) 174 struct tcpcb *tp; 175 { 176 /* 177 * First reported block MUST be the most recent one. Subsequent 178 * blocks SHOULD be in the order in which they arrived at the 179 * receiver. These two conditions make the implementation fully 180 * compliant with RFC 2018. 181 */ 182 int i, j = 0, count = 0, lastpos = -1; 183 struct sackblk sack, firstsack, temp[MAX_SACK_BLKS]; 184 185 INP_LOCK_ASSERT(tp->t_inpcb); 186 /* First clean up current list of sacks */ 187 for (i = 0; i < tp->rcv_numsacks; i++) { 188 sack = tp->sackblks[i]; 189 if (sack.start == 0 && sack.end == 0) { 190 count++; /* count = number of blocks to be discarded */ 191 continue; 192 } 193 if (SEQ_LEQ(sack.end, tp->rcv_nxt)) { 194 tp->sackblks[i].start = tp->sackblks[i].end = 0; 195 count++; 196 } else { 197 temp[j].start = tp->sackblks[i].start; 198 temp[j++].end = tp->sackblks[i].end; 199 } 200 } 201 tp->rcv_numsacks -= count; 202 if (tp->rcv_numsacks == 0) { /* no sack blocks currently (fast path) */ 203 tcp_clean_sackreport(tp); 204 if (SEQ_LT(tp->rcv_nxt, tp->rcv_laststart)) { 205 /* ==> need first sack block */ 206 tp->sackblks[0].start = tp->rcv_laststart; 207 tp->sackblks[0].end = tp->rcv_lastend; 208 tp->rcv_numsacks = 1; 209 } 210 return; 211 } 212 /* Otherwise, sack blocks are already present. */ 213 for (i = 0; i < tp->rcv_numsacks; i++) 214 tp->sackblks[i] = temp[i]; /* first copy back sack list */ 215 if (SEQ_GEQ(tp->rcv_nxt, tp->rcv_lastend)) 216 return; /* sack list remains unchanged */ 217 /* 218 * From here, segment just received should be (part of) the 1st sack. 219 * Go through list, possibly coalescing sack block entries. 220 */ 221 firstsack.start = tp->rcv_laststart; 222 firstsack.end = tp->rcv_lastend; 223 for (i = 0; i < tp->rcv_numsacks; i++) { 224 sack = tp->sackblks[i]; 225 if (SEQ_LT(sack.end, firstsack.start) || 226 SEQ_GT(sack.start, firstsack.end)) 227 continue; /* no overlap */ 228 if (sack.start == firstsack.start && sack.end == firstsack.end){ 229 /* 230 * identical block; delete it here since we will 231 * move it to the front of the list. 232 */ 233 tp->sackblks[i].start = tp->sackblks[i].end = 0; 234 lastpos = i; /* last posn with a zero entry */ 235 continue; 236 } 237 if (SEQ_LEQ(sack.start, firstsack.start)) 238 firstsack.start = sack.start; /* merge blocks */ 239 if (SEQ_GEQ(sack.end, firstsack.end)) 240 firstsack.end = sack.end; /* merge blocks */ 241 tp->sackblks[i].start = tp->sackblks[i].end = 0; 242 lastpos = i; /* last posn with a zero entry */ 243 } 244 if (lastpos != -1) { /* at least one merge */ 245 for (i = 0, j = 1; i < tp->rcv_numsacks; i++) { 246 sack = tp->sackblks[i]; 247 if (sack.start == 0 && sack.end == 0) 248 continue; 249 temp[j++] = sack; 250 } 251 tp->rcv_numsacks = j; /* including first blk (added later) */ 252 for (i = 1; i < tp->rcv_numsacks; i++) /* now copy back */ 253 tp->sackblks[i] = temp[i]; 254 } else { /* no merges -- shift sacks by 1 */ 255 if (tp->rcv_numsacks < MAX_SACK_BLKS) 256 tp->rcv_numsacks++; 257 for (i = tp->rcv_numsacks-1; i > 0; i--) 258 tp->sackblks[i] = tp->sackblks[i-1]; 259 } 260 tp->sackblks[0] = firstsack; 261 return; 262 } 263 264 /* 265 * Delete all receiver-side SACK information. 266 */ 267 void 268 tcp_clean_sackreport(tp) 269 struct tcpcb *tp; 270 { 271 int i; 272 273 INP_LOCK_ASSERT(tp->t_inpcb); 274 tp->rcv_numsacks = 0; 275 for (i = 0; i < MAX_SACK_BLKS; i++) 276 tp->sackblks[i].start = tp->sackblks[i].end=0; 277 } 278 279 /* 280 * Process the TCP SACK option. Returns 1 if tcp_dooptions() should continue, 281 * and 0 otherwise, if the option was fine. tp->snd_holes is an ordered list 282 * of holes (oldest to newest, in terms of the sequence space). 283 */ 284 int 285 tcp_sack_option(struct tcpcb *tp, struct tcphdr *th, u_char *cp, int optlen) 286 { 287 int tmp_olen; 288 u_char *tmp_cp; 289 struct sackhole *cur, *p, *temp; 290 291 INP_LOCK_ASSERT(tp->t_inpcb); 292 if (!tp->sack_enable) 293 return (1); 294 295 /* Note: TCPOLEN_SACK must be 2*sizeof(tcp_seq) */ 296 if (optlen <= 2 || (optlen - 2) % TCPOLEN_SACK != 0) 297 return (1); 298 tmp_cp = cp + 2; 299 tmp_olen = optlen - 2; 300 tcpstat.tcps_sack_rcv_blocks++; 301 if (tp->snd_numholes < 0) 302 tp->snd_numholes = 0; 303 if (tp->t_maxseg == 0) 304 panic("tcp_sack_option"); /* Should never happen */ 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 continue; /* 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 593