xref: /onnv-gate/usr/src/uts/common/inet/tcp/tcp_sack.c (revision 12056:4811a59c20b7)
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