10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*12056SKacheong.Poon@Sun.COM * Common Development and Distribution License (the "License").
6*12056SKacheong.Poon@Sun.COM * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*12056SKacheong.Poon@Sun.COM * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate #include <sys/types.h>
260Sstevel@tonic-gate #include <sys/kmem.h>
270Sstevel@tonic-gate #include <sys/debug.h>
280Sstevel@tonic-gate #include <netinet/tcp.h>
290Sstevel@tonic-gate #include <sys/systm.h>
300Sstevel@tonic-gate #include <sys/stropts.h>
310Sstevel@tonic-gate #include <netinet/in.h>
320Sstevel@tonic-gate #include <netinet/ip6.h>
330Sstevel@tonic-gate #include <inet/common.h>
340Sstevel@tonic-gate #include <inet/ip.h>
350Sstevel@tonic-gate #include <inet/tcp.h>
360Sstevel@tonic-gate
37*12056SKacheong.Poon@Sun.COM /* kmem cache for notsack_blk_t */
38*12056SKacheong.Poon@Sun.COM kmem_cache_t *tcp_notsack_blk_cache;
39*12056SKacheong.Poon@Sun.COM
400Sstevel@tonic-gate /*
410Sstevel@tonic-gate * To insert a new blk to the array of SACK blk in receiver.
420Sstevel@tonic-gate *
430Sstevel@tonic-gate * Parameters:
440Sstevel@tonic-gate * sack_blk_t *head: pointer to the array of SACK blks.
450Sstevel@tonic-gate * tcp_seq begin: starting seq num of the new blk.
460Sstevel@tonic-gate * tcp_seq end: ending seq num of the new blk.
470Sstevel@tonic-gate * int32_t *num: (referenced) total num of SACK blks on the list.
480Sstevel@tonic-gate */
490Sstevel@tonic-gate void
tcp_sack_insert(sack_blk_t * head,tcp_seq begin,tcp_seq end,int32_t * num)500Sstevel@tonic-gate tcp_sack_insert(sack_blk_t *head, tcp_seq begin, tcp_seq end, int32_t *num)
510Sstevel@tonic-gate {
520Sstevel@tonic-gate int32_t i, j, old_num, new_num;
530Sstevel@tonic-gate sack_blk_t tmp[MAX_SACK_BLK - 1];
540Sstevel@tonic-gate
550Sstevel@tonic-gate /* The array is empty, just add the new one. */
560Sstevel@tonic-gate if (*num == 0) {
570Sstevel@tonic-gate head[0].begin = begin;
580Sstevel@tonic-gate head[0].end = end;
590Sstevel@tonic-gate *num = 1;
600Sstevel@tonic-gate return;
610Sstevel@tonic-gate }
620Sstevel@tonic-gate
630Sstevel@tonic-gate /*
640Sstevel@tonic-gate * Check for overlap. There are five cases.
650Sstevel@tonic-gate *
660Sstevel@tonic-gate * 1. there is no overlap with any other SACK blks.
670Sstevel@tonic-gate * 2. new SACK blk is completely contained in another blk.
680Sstevel@tonic-gate * 3. tail part of new SACK blk overlaps with another blk.
690Sstevel@tonic-gate * 4. head part of new SACK blk overlaps with another blk.
700Sstevel@tonic-gate * 5. new SACK blk completely contains another blk.
710Sstevel@tonic-gate *
720Sstevel@tonic-gate * Use tmp to hold old SACK blks. After the loop, copy them back
730Sstevel@tonic-gate * to head.
740Sstevel@tonic-gate */
750Sstevel@tonic-gate old_num = *num;
760Sstevel@tonic-gate if (old_num > MAX_SACK_BLK - 1) {
770Sstevel@tonic-gate old_num = MAX_SACK_BLK - 1;
780Sstevel@tonic-gate }
790Sstevel@tonic-gate new_num = old_num;
800Sstevel@tonic-gate j = 0;
810Sstevel@tonic-gate for (i = 0; i < old_num; i++) {
820Sstevel@tonic-gate if (SEQ_LT(end, head[i].begin) || SEQ_GT(begin, head[i].end)) {
830Sstevel@tonic-gate /* Case 1: continue to check. */
840Sstevel@tonic-gate tmp[j].begin = head[i].begin;
850Sstevel@tonic-gate tmp[j].end = head[i].end;
860Sstevel@tonic-gate j++;
870Sstevel@tonic-gate continue;
880Sstevel@tonic-gate } else if (SEQ_GEQ(begin, head[i].begin) &&
890Sstevel@tonic-gate SEQ_LEQ(end, head[i].end)) {
900Sstevel@tonic-gate /* Case 2: re-insert the old blk to the head. */
910Sstevel@tonic-gate begin = head[i].begin;
920Sstevel@tonic-gate end = head[i].end;
930Sstevel@tonic-gate } else if (SEQ_LEQ(end, head[i].end) &&
940Sstevel@tonic-gate SEQ_GEQ(end, head[i].begin)) {
950Sstevel@tonic-gate /*
960Sstevel@tonic-gate * Case 3: Extend the new blk, remove the old one
970Sstevel@tonic-gate * and continue to check.
980Sstevel@tonic-gate */
990Sstevel@tonic-gate end = head[i].end;
1000Sstevel@tonic-gate } else if (SEQ_GEQ(begin, head[i].begin) &&
1010Sstevel@tonic-gate SEQ_LEQ(begin, head[i].end)) {
1020Sstevel@tonic-gate /* Case 4 */
1030Sstevel@tonic-gate begin = head[i].begin;
1040Sstevel@tonic-gate }
1050Sstevel@tonic-gate /*
1060Sstevel@tonic-gate * Common code for all cases except the first one, which
1070Sstevel@tonic-gate * copies the original SACK blk into the tmp storage. Other
1080Sstevel@tonic-gate * cases remove the original SACK blk by not copying into
1090Sstevel@tonic-gate * tmp storage.
1100Sstevel@tonic-gate */
1110Sstevel@tonic-gate new_num--;
1120Sstevel@tonic-gate }
1130Sstevel@tonic-gate
1140Sstevel@tonic-gate head[0].begin = begin;
1150Sstevel@tonic-gate head[0].end = end;
1160Sstevel@tonic-gate for (i = 0; i < new_num; i++) {
1170Sstevel@tonic-gate head[i+1].begin = tmp[i].begin;
1180Sstevel@tonic-gate head[i+1].end = tmp[i].end;
1190Sstevel@tonic-gate }
1200Sstevel@tonic-gate *num = new_num + 1;
1210Sstevel@tonic-gate }
1220Sstevel@tonic-gate
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate /*
1250Sstevel@tonic-gate * To remove a SACK block.
1260Sstevel@tonic-gate *
1270Sstevel@tonic-gate * Parameters:
1280Sstevel@tonic-gate * sack_blk_t *head: pointer to the array of SACK blks.
1290Sstevel@tonic-gate * tcp_seq end: to remove all sack blk with seq num less than end.
1300Sstevel@tonic-gate * int32_t *num: (referenced) total num of SACK blks in the array.
1310Sstevel@tonic-gate */
1320Sstevel@tonic-gate void
tcp_sack_remove(sack_blk_t * head,tcp_seq end,int32_t * num)1330Sstevel@tonic-gate tcp_sack_remove(sack_blk_t *head, tcp_seq end, int32_t *num)
1340Sstevel@tonic-gate {
1350Sstevel@tonic-gate sack_blk_t tmp[MAX_SACK_BLK];
1360Sstevel@tonic-gate int32_t i, j, old_num, new_num;
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate if (*num == 0)
1390Sstevel@tonic-gate return;
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate old_num = *num;
1420Sstevel@tonic-gate new_num = old_num;
1430Sstevel@tonic-gate j = 0;
1440Sstevel@tonic-gate /* Walk thru the whole list and copy the new list to tmp[]. */
1450Sstevel@tonic-gate for (i = 0; i < old_num; i++) {
1460Sstevel@tonic-gate if (SEQ_GT(end, head[i].begin)) {
1470Sstevel@tonic-gate /*
1480Sstevel@tonic-gate * Check to see if the old SACK blk needs to be
1490Sstevel@tonic-gate * removed or updated. If the old blk is just
1500Sstevel@tonic-gate * partially covered, update begin and continue.
1510Sstevel@tonic-gate * If the old blk is completely covered, remove it
1520Sstevel@tonic-gate * and continue to check.
1530Sstevel@tonic-gate */
1540Sstevel@tonic-gate if (SEQ_GEQ(end, head[i].end)) {
1550Sstevel@tonic-gate new_num--;
1560Sstevel@tonic-gate continue;
1570Sstevel@tonic-gate } else {
1580Sstevel@tonic-gate tmp[j].begin = end;
1590Sstevel@tonic-gate tmp[j].end = head[i].end;
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate } else {
1620Sstevel@tonic-gate tmp[j].begin = head[i].begin;
1630Sstevel@tonic-gate tmp[j].end = head[i].end;
1640Sstevel@tonic-gate }
1650Sstevel@tonic-gate j++;
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate /* Copy tmp[] back to the original list. */
1680Sstevel@tonic-gate for (i = 0; i < new_num; i++) {
1690Sstevel@tonic-gate head[i].begin = tmp[i].begin;
1700Sstevel@tonic-gate head[i].end = tmp[i].end;
1710Sstevel@tonic-gate }
1720Sstevel@tonic-gate *num = new_num;
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate /*
1770Sstevel@tonic-gate * Use the SACK info to insert a "notsack'ed" blk. The notsack'ed blk list
1780Sstevel@tonic-gate * contains the list of blks which have not been selectively acknowledged
1790Sstevel@tonic-gate * by the receiver. The SACK info is a blk which is being selectively
1800Sstevel@tonic-gate * acknowledged by the receiver.
1810Sstevel@tonic-gate *
1820Sstevel@tonic-gate * Parameters:
1830Sstevel@tonic-gate * notsack_blk_t **head: address of the pointer to the list of notsack'ed
1840Sstevel@tonic-gate * blks.
1850Sstevel@tonic-gate * tcp_seq begin: starting seq num of the SACK info.
1860Sstevel@tonic-gate * tcp_seq end: ending seq num of the SACK info.
1870Sstevel@tonic-gate * int32_t *num: (referenced) total num of notsack'ed blk on the list.
1880Sstevel@tonic-gate * uint32_t *sum: (referenced) total num of bytes of all the notsack'ed
1890Sstevel@tonic-gate * blks.
1900Sstevel@tonic-gate */
1910Sstevel@tonic-gate void
tcp_notsack_insert(notsack_blk_t ** head,tcp_seq begin,tcp_seq end,int32_t * num,uint32_t * sum)1920Sstevel@tonic-gate tcp_notsack_insert(notsack_blk_t **head, tcp_seq begin, tcp_seq end,
1930Sstevel@tonic-gate int32_t *num, uint32_t *sum)
1940Sstevel@tonic-gate {
1950Sstevel@tonic-gate notsack_blk_t *prev, *tmp, *new;
1960Sstevel@tonic-gate uint32_t tmp_sum, tmp_num;
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate if (*head == NULL) {
1990Sstevel@tonic-gate return;
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate
2020Sstevel@tonic-gate tmp = *head;
2030Sstevel@tonic-gate prev = NULL;
2040Sstevel@tonic-gate /* Find the right place of updating the list. */
2050Sstevel@tonic-gate while ((tmp != NULL) && SEQ_LEQ(tmp->end, begin)) {
2060Sstevel@tonic-gate prev = tmp;
2070Sstevel@tonic-gate (tmp->sack_cnt)++;
2080Sstevel@tonic-gate tmp = tmp->next;
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate /*
2120Sstevel@tonic-gate * This can happen only when TCP sends new data but the notsack list
2130Sstevel@tonic-gate * is not updated.
2140Sstevel@tonic-gate */
2150Sstevel@tonic-gate if (tmp == NULL) {
2160Sstevel@tonic-gate return;
2170Sstevel@tonic-gate }
2180Sstevel@tonic-gate
2190Sstevel@tonic-gate /*
2200Sstevel@tonic-gate * This means the new SACK info covers something that is not on
2210Sstevel@tonic-gate * the list anymore.
2220Sstevel@tonic-gate */
2230Sstevel@tonic-gate if (SEQ_LEQ(end, tmp->begin)) {
2240Sstevel@tonic-gate return;
2250Sstevel@tonic-gate }
2260Sstevel@tonic-gate
2270Sstevel@tonic-gate /* The SACK info covers up to this blk. So just check for this blk. */
2280Sstevel@tonic-gate if (SEQ_LEQ(end, tmp->end)) {
2290Sstevel@tonic-gate /*
2300Sstevel@tonic-gate * Only this notsack'ed blk is completely covered. Delete
2310Sstevel@tonic-gate * it and return.
2320Sstevel@tonic-gate */
2330Sstevel@tonic-gate if (end == tmp->end && SEQ_LEQ(begin, tmp->begin)) {
2340Sstevel@tonic-gate if (prev != NULL) {
2350Sstevel@tonic-gate prev->next = tmp->next;
2360Sstevel@tonic-gate } else {
2370Sstevel@tonic-gate *head = tmp->next;
2380Sstevel@tonic-gate }
2390Sstevel@tonic-gate (*num)--;
2400Sstevel@tonic-gate *sum -= tmp->end - tmp->begin;
241*12056SKacheong.Poon@Sun.COM kmem_cache_free(tcp_notsack_blk_cache, tmp);
2420Sstevel@tonic-gate return;
2430Sstevel@tonic-gate }
2440Sstevel@tonic-gate /* This blk is partially covered. */
2450Sstevel@tonic-gate if (SEQ_GEQ(begin, tmp->begin)) {
2460Sstevel@tonic-gate /* Check what needs to be updated. */
2470Sstevel@tonic-gate if (begin == tmp->begin) {
2480Sstevel@tonic-gate *sum -= end - tmp->begin;
2490Sstevel@tonic-gate tmp->begin = end;
2500Sstevel@tonic-gate } else if (end == tmp->end) {
2510Sstevel@tonic-gate *sum -= tmp->end - begin;
2520Sstevel@tonic-gate tmp->end = begin;
2530Sstevel@tonic-gate (tmp->sack_cnt)++;
2540Sstevel@tonic-gate } else {
2550Sstevel@tonic-gate /* Split the notsack blk. */
256*12056SKacheong.Poon@Sun.COM if ((new = kmem_cache_alloc(
257*12056SKacheong.Poon@Sun.COM tcp_notsack_blk_cache, KM_NOSLEEP)) ==
258*12056SKacheong.Poon@Sun.COM NULL) {
2590Sstevel@tonic-gate return;
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate new->end = tmp->end;
2620Sstevel@tonic-gate new->begin = end;
2630Sstevel@tonic-gate new->next = tmp->next;
2640Sstevel@tonic-gate new->sack_cnt = 0;
2650Sstevel@tonic-gate tmp->end = begin;
2660Sstevel@tonic-gate tmp->next = new;
2670Sstevel@tonic-gate (tmp->sack_cnt)++;
2680Sstevel@tonic-gate (*num)++;
2690Sstevel@tonic-gate *sum -= end - begin;
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate } else {
2720Sstevel@tonic-gate *sum -= end - tmp->begin;
2730Sstevel@tonic-gate tmp->begin = end;
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate return;
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate
2780Sstevel@tonic-gate /* Need to check for coverage of this blk and later blks. */
2790Sstevel@tonic-gate tmp_sum = *sum;
2800Sstevel@tonic-gate tmp_num = *num;
2810Sstevel@tonic-gate if (SEQ_LT(tmp->begin, begin)) {
2820Sstevel@tonic-gate tmp_sum -= tmp->end - begin;
2830Sstevel@tonic-gate tmp->end = begin;
2840Sstevel@tonic-gate (tmp->sack_cnt)++;
2850Sstevel@tonic-gate prev = tmp;
2860Sstevel@tonic-gate tmp = tmp->next;
2870Sstevel@tonic-gate }
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate while (tmp != NULL) {
2900Sstevel@tonic-gate /* The coverage stops here. */
2910Sstevel@tonic-gate if (SEQ_GT(tmp->begin, end)) {
2920Sstevel@tonic-gate break;
2930Sstevel@tonic-gate } else {
2940Sstevel@tonic-gate /* Is the blk completely or partially covered? */
2950Sstevel@tonic-gate if (SEQ_LEQ(tmp->end, end)) {
2960Sstevel@tonic-gate tmp_num--;
2970Sstevel@tonic-gate tmp_sum -= tmp->end - tmp->begin;
2980Sstevel@tonic-gate if (prev != NULL) {
2990Sstevel@tonic-gate prev->next = tmp->next;
300*12056SKacheong.Poon@Sun.COM kmem_cache_free(tcp_notsack_blk_cache,
301*12056SKacheong.Poon@Sun.COM tmp);
3020Sstevel@tonic-gate tmp = prev->next;
3030Sstevel@tonic-gate } else {
3040Sstevel@tonic-gate *head = tmp->next;
305*12056SKacheong.Poon@Sun.COM kmem_cache_free(tcp_notsack_blk_cache,
306*12056SKacheong.Poon@Sun.COM tmp);
3070Sstevel@tonic-gate tmp = *head;
3080Sstevel@tonic-gate }
3090Sstevel@tonic-gate } else {
3100Sstevel@tonic-gate /*
3110Sstevel@tonic-gate * This blk is partially covered. It also
3120Sstevel@tonic-gate * means it should be the end of coverage.
3130Sstevel@tonic-gate */
3140Sstevel@tonic-gate tmp_sum -= end - tmp->begin;
3150Sstevel@tonic-gate tmp->begin = end;
3160Sstevel@tonic-gate break;
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate }
3190Sstevel@tonic-gate }
3200Sstevel@tonic-gate *num = tmp_num;
3210Sstevel@tonic-gate *sum = tmp_sum;
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate /*
3260Sstevel@tonic-gate * To remove notsack'ed blks.
3270Sstevel@tonic-gate *
3280Sstevel@tonic-gate * Parameters:
3290Sstevel@tonic-gate * notsack_blk_t **head: address of the pointer to the list of notsack'ed
3300Sstevel@tonic-gate * blks.
3310Sstevel@tonic-gate * tcp_seq end: to remove all notsack'ed blk with seq num less than end.
3320Sstevel@tonic-gate * int32_t *num: (referenced) total num of notsack'ed blks.
3330Sstevel@tonic-gate * uint32_t *sum: (referenced) total num of bytes of all the notsack'ed
3340Sstevel@tonic-gate * blks.
3350Sstevel@tonic-gate */
3360Sstevel@tonic-gate void
tcp_notsack_remove(notsack_blk_t ** head,tcp_seq end,int32_t * num,uint32_t * sum)3370Sstevel@tonic-gate tcp_notsack_remove(notsack_blk_t **head, tcp_seq end, int32_t *num,
3380Sstevel@tonic-gate uint32_t *sum)
3390Sstevel@tonic-gate {
3400Sstevel@tonic-gate notsack_blk_t *prev, *tmp;
3410Sstevel@tonic-gate uint32_t tmp_sum = *sum;
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate if (*head == NULL)
3440Sstevel@tonic-gate return;
3450Sstevel@tonic-gate
3460Sstevel@tonic-gate prev = NULL;
3470Sstevel@tonic-gate tmp = *head;
3480Sstevel@tonic-gate while (tmp != NULL) {
3490Sstevel@tonic-gate /* There is nothing to discard. */
3500Sstevel@tonic-gate if (SEQ_GT(tmp->begin, end)) {
3510Sstevel@tonic-gate break;
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate /* Is the blk completely or partially covered? */
3550Sstevel@tonic-gate if (SEQ_GEQ(end, tmp->end)) {
3560Sstevel@tonic-gate (*num)--;
3570Sstevel@tonic-gate tmp_sum -= tmp->end - tmp->begin;
3580Sstevel@tonic-gate if (prev == NULL) {
3590Sstevel@tonic-gate *head = tmp->next;
360*12056SKacheong.Poon@Sun.COM kmem_cache_free(tcp_notsack_blk_cache, tmp);
3610Sstevel@tonic-gate tmp = *head;
3620Sstevel@tonic-gate } else {
3630Sstevel@tonic-gate prev->next = tmp->next;
364*12056SKacheong.Poon@Sun.COM kmem_cache_free(tcp_notsack_blk_cache, tmp);
3650Sstevel@tonic-gate tmp = prev->next;
3660Sstevel@tonic-gate }
3670Sstevel@tonic-gate } else {
3680Sstevel@tonic-gate tmp_sum -= end - tmp->begin;
3690Sstevel@tonic-gate tmp->begin = end;
3700Sstevel@tonic-gate break;
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate }
3730Sstevel@tonic-gate *sum = tmp_sum;
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate
3770Sstevel@tonic-gate /*
3780Sstevel@tonic-gate * To update the notsack'ed list when new data is sent.
3790Sstevel@tonic-gate *
3800Sstevel@tonic-gate * Assumption: this should only be called when new notsack blk is to be added.
3810Sstevel@tonic-gate *
3820Sstevel@tonic-gate * Parameters:
3830Sstevel@tonic-gate * notsack_blk_t **head: address of the pointer to the list of notsack'ed
3840Sstevel@tonic-gate * blks.
3850Sstevel@tonic-gate * tcp_seq begin: beginning seq num of new data.
3860Sstevel@tonic-gate * tcp_seq end: ending seq num of new data.
3870Sstevel@tonic-gate * int32_t *num: (referenced) total num of notsack'ed blks.
3880Sstevel@tonic-gate * uint32_t *sum: (referenced) total num of bytes of all the notsack'ed
3890Sstevel@tonic-gate * blks.
3900Sstevel@tonic-gate */
tcp_notsack_update(notsack_blk_t ** head,tcp_seq begin,tcp_seq end,int32_t * num,uint32_t * sum)3910Sstevel@tonic-gate void tcp_notsack_update(notsack_blk_t **head, tcp_seq begin, tcp_seq end,
3920Sstevel@tonic-gate int32_t *num, uint32_t *sum)
3930Sstevel@tonic-gate {
3940Sstevel@tonic-gate notsack_blk_t *tmp;
3950Sstevel@tonic-gate
3960Sstevel@tonic-gate tmp = *head;
3970Sstevel@tonic-gate /* If the list is empty, create a new one. */
3980Sstevel@tonic-gate if (tmp == NULL) {
399*12056SKacheong.Poon@Sun.COM if ((tmp = kmem_cache_alloc(tcp_notsack_blk_cache,
400*12056SKacheong.Poon@Sun.COM KM_NOSLEEP)) == NULL) {
4010Sstevel@tonic-gate return;
4020Sstevel@tonic-gate }
4030Sstevel@tonic-gate tmp->begin = begin;
4040Sstevel@tonic-gate tmp->end = end;
4050Sstevel@tonic-gate tmp->next = NULL;
4060Sstevel@tonic-gate tmp->sack_cnt = 0;
4070Sstevel@tonic-gate *head = tmp;
4080Sstevel@tonic-gate *num = 1;
4090Sstevel@tonic-gate *sum = end - begin;
4100Sstevel@tonic-gate return;
4110Sstevel@tonic-gate }
4120Sstevel@tonic-gate
4130Sstevel@tonic-gate /*
4140Sstevel@tonic-gate * Find the place to add the new blk. This assumes that new data
4150Sstevel@tonic-gate * is being sent, so the place to insert the new notsack blk is at
4160Sstevel@tonic-gate * the end of the list.
4170Sstevel@tonic-gate */
4180Sstevel@tonic-gate while (tmp->next != NULL) {
4190Sstevel@tonic-gate tmp = tmp->next;
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate
4220Sstevel@tonic-gate /* Does the new blk overlap with old one? */
4230Sstevel@tonic-gate if (SEQ_GEQ(tmp->end, begin)) {
4240Sstevel@tonic-gate *sum += end - tmp->end;
4250Sstevel@tonic-gate tmp->end = end;
4260Sstevel@tonic-gate } else {
4270Sstevel@tonic-gate /* No. Need to create a new notsack blk. */
428*12056SKacheong.Poon@Sun.COM tmp->next = kmem_cache_alloc(tcp_notsack_blk_cache, KM_NOSLEEP);
4290Sstevel@tonic-gate if (tmp->next != NULL) {
4300Sstevel@tonic-gate tmp = tmp->next;
4310Sstevel@tonic-gate tmp->begin = begin;
4320Sstevel@tonic-gate tmp->end = end;
4330Sstevel@tonic-gate tmp->next = NULL;
4340Sstevel@tonic-gate tmp->sack_cnt = 0;
4350Sstevel@tonic-gate (*num)++;
4360Sstevel@tonic-gate *sum += end - begin;
4370Sstevel@tonic-gate }
4380Sstevel@tonic-gate }
4390Sstevel@tonic-gate }
440