xref: /illumos-gate/usr/src/uts/common/inet/tcp/tcp_sack.c (revision 66cd0f60)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*66cd0f60SKacheong Poon  * Common Development and Distribution License (the "License").
6*66cd0f60SKacheong Poon  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*66cd0f60SKacheong Poon  * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include <sys/types.h>
267c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
277c478bd9Sstevel@tonic-gate #include <sys/debug.h>
287c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
297c478bd9Sstevel@tonic-gate #include <sys/systm.h>
307c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
317c478bd9Sstevel@tonic-gate #include <netinet/in.h>
327c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
337c478bd9Sstevel@tonic-gate #include <inet/common.h>
347c478bd9Sstevel@tonic-gate #include <inet/ip.h>
357c478bd9Sstevel@tonic-gate #include <inet/tcp.h>
367c478bd9Sstevel@tonic-gate 
37*66cd0f60SKacheong Poon /* kmem cache for notsack_blk_t */
38*66cd0f60SKacheong Poon kmem_cache_t	*tcp_notsack_blk_cache;
39*66cd0f60SKacheong Poon 
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate  * To insert a new blk to the array of SACK blk in receiver.
427c478bd9Sstevel@tonic-gate  *
437c478bd9Sstevel@tonic-gate  * Parameters:
447c478bd9Sstevel@tonic-gate  *	sack_blk_t *head: pointer to the array of SACK blks.
457c478bd9Sstevel@tonic-gate  *	tcp_seq begin: starting seq num of the new blk.
467c478bd9Sstevel@tonic-gate  *	tcp_seq end: ending seq num of the new blk.
477c478bd9Sstevel@tonic-gate  *	int32_t *num: (referenced) total num of SACK blks on the list.
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate void
tcp_sack_insert(sack_blk_t * head,tcp_seq begin,tcp_seq end,int32_t * num)507c478bd9Sstevel@tonic-gate tcp_sack_insert(sack_blk_t *head, tcp_seq begin, tcp_seq end, int32_t *num)
517c478bd9Sstevel@tonic-gate {
527c478bd9Sstevel@tonic-gate 	int32_t	i, j, old_num, new_num;
537c478bd9Sstevel@tonic-gate 	sack_blk_t tmp[MAX_SACK_BLK - 1];
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate 	/* The array is empty, just add the new one. */
567c478bd9Sstevel@tonic-gate 	if (*num == 0) {
577c478bd9Sstevel@tonic-gate 		head[0].begin = begin;
587c478bd9Sstevel@tonic-gate 		head[0].end = end;
597c478bd9Sstevel@tonic-gate 		*num = 1;
607c478bd9Sstevel@tonic-gate 		return;
617c478bd9Sstevel@tonic-gate 	}
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate 	/*
647c478bd9Sstevel@tonic-gate 	 * Check for overlap.  There are five cases.
657c478bd9Sstevel@tonic-gate 	 *
667c478bd9Sstevel@tonic-gate 	 * 1. there is no overlap with any other SACK blks.
677c478bd9Sstevel@tonic-gate 	 * 2. new SACK blk is completely contained in another blk.
687c478bd9Sstevel@tonic-gate 	 * 3. tail part of new SACK blk overlaps with another blk.
697c478bd9Sstevel@tonic-gate 	 * 4. head part of new SACK blk overlaps with another blk.
707c478bd9Sstevel@tonic-gate 	 * 5. new SACK blk completely contains another blk.
717c478bd9Sstevel@tonic-gate 	 *
727c478bd9Sstevel@tonic-gate 	 * Use tmp to hold old SACK blks.  After the loop, copy them back
737c478bd9Sstevel@tonic-gate 	 * to head.
747c478bd9Sstevel@tonic-gate 	 */
757c478bd9Sstevel@tonic-gate 	old_num = *num;
767c478bd9Sstevel@tonic-gate 	if (old_num > MAX_SACK_BLK - 1) {
777c478bd9Sstevel@tonic-gate 		old_num = MAX_SACK_BLK - 1;
787c478bd9Sstevel@tonic-gate 	}
797c478bd9Sstevel@tonic-gate 	new_num = old_num;
807c478bd9Sstevel@tonic-gate 	j = 0;
817c478bd9Sstevel@tonic-gate 	for (i = 0; i < old_num; i++) {
827c478bd9Sstevel@tonic-gate 		if (SEQ_LT(end, head[i].begin) || SEQ_GT(begin, head[i].end)) {
837c478bd9Sstevel@tonic-gate 			/* Case 1: continue to check. */
847c478bd9Sstevel@tonic-gate 			tmp[j].begin = head[i].begin;
857c478bd9Sstevel@tonic-gate 			tmp[j].end = head[i].end;
867c478bd9Sstevel@tonic-gate 			j++;
877c478bd9Sstevel@tonic-gate 			continue;
887c478bd9Sstevel@tonic-gate 		} else if (SEQ_GEQ(begin, head[i].begin) &&
897c478bd9Sstevel@tonic-gate 		    SEQ_LEQ(end, head[i].end)) {
907c478bd9Sstevel@tonic-gate 			/* Case 2: re-insert the old blk to the head. */
917c478bd9Sstevel@tonic-gate 			begin = head[i].begin;
927c478bd9Sstevel@tonic-gate 			end = head[i].end;
937c478bd9Sstevel@tonic-gate 		} else if (SEQ_LEQ(end, head[i].end) &&
947c478bd9Sstevel@tonic-gate 		    SEQ_GEQ(end, head[i].begin)) {
957c478bd9Sstevel@tonic-gate 			/*
967c478bd9Sstevel@tonic-gate 			 * Case 3: Extend the new blk, remove the old one
977c478bd9Sstevel@tonic-gate 			 * and continue to check.
987c478bd9Sstevel@tonic-gate 			 */
997c478bd9Sstevel@tonic-gate 			end = head[i].end;
1007c478bd9Sstevel@tonic-gate 		} else if (SEQ_GEQ(begin, head[i].begin) &&
1017c478bd9Sstevel@tonic-gate 		    SEQ_LEQ(begin, head[i].end)) {
1027c478bd9Sstevel@tonic-gate 			/* Case 4 */
1037c478bd9Sstevel@tonic-gate 			begin = head[i].begin;
1047c478bd9Sstevel@tonic-gate 		}
1057c478bd9Sstevel@tonic-gate 		/*
1067c478bd9Sstevel@tonic-gate 		 * Common code for all cases except the first one, which
1077c478bd9Sstevel@tonic-gate 		 * copies the original SACK blk into the tmp storage.  Other
1087c478bd9Sstevel@tonic-gate 		 * cases remove the original SACK blk by not copying into
1097c478bd9Sstevel@tonic-gate 		 * tmp storage.
1107c478bd9Sstevel@tonic-gate 		 */
1117c478bd9Sstevel@tonic-gate 		new_num--;
1127c478bd9Sstevel@tonic-gate 	}
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	head[0].begin = begin;
1157c478bd9Sstevel@tonic-gate 	head[0].end = end;
1167c478bd9Sstevel@tonic-gate 	for (i = 0; i < new_num; i++) {
1177c478bd9Sstevel@tonic-gate 		head[i+1].begin = tmp[i].begin;
1187c478bd9Sstevel@tonic-gate 		head[i+1].end = tmp[i].end;
1197c478bd9Sstevel@tonic-gate 	}
1207c478bd9Sstevel@tonic-gate 	*num = new_num + 1;
1217c478bd9Sstevel@tonic-gate }
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate /*
1257c478bd9Sstevel@tonic-gate  * To remove a SACK block.
1267c478bd9Sstevel@tonic-gate  *
1277c478bd9Sstevel@tonic-gate  * Parameters:
1287c478bd9Sstevel@tonic-gate  *	sack_blk_t *head: pointer to the array of SACK blks.
1297c478bd9Sstevel@tonic-gate  *	tcp_seq end: to remove all sack blk with seq num less than end.
1307c478bd9Sstevel@tonic-gate  *	int32_t *num: (referenced) total num of SACK blks in the array.
1317c478bd9Sstevel@tonic-gate  */
1327c478bd9Sstevel@tonic-gate void
tcp_sack_remove(sack_blk_t * head,tcp_seq end,int32_t * num)1337c478bd9Sstevel@tonic-gate tcp_sack_remove(sack_blk_t *head, tcp_seq end, int32_t *num)
1347c478bd9Sstevel@tonic-gate {
1357c478bd9Sstevel@tonic-gate 	sack_blk_t tmp[MAX_SACK_BLK];
1367c478bd9Sstevel@tonic-gate 	int32_t i, j, old_num, new_num;
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	if (*num == 0)
1397c478bd9Sstevel@tonic-gate 		return;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	old_num = *num;
1427c478bd9Sstevel@tonic-gate 	new_num = old_num;
1437c478bd9Sstevel@tonic-gate 	j = 0;
1447c478bd9Sstevel@tonic-gate 	/* Walk thru the whole list and copy the new list to tmp[]. */
1457c478bd9Sstevel@tonic-gate 	for (i = 0; i < old_num; i++) {
1467c478bd9Sstevel@tonic-gate 		if (SEQ_GT(end, head[i].begin)) {
1477c478bd9Sstevel@tonic-gate 			/*
1487c478bd9Sstevel@tonic-gate 			 * Check to see if the old SACK blk needs to be
1497c478bd9Sstevel@tonic-gate 			 * removed or updated.  If the old blk is just
1507c478bd9Sstevel@tonic-gate 			 * partially covered, update begin and continue.
1517c478bd9Sstevel@tonic-gate 			 * If the old blk is completely covered, remove it
1527c478bd9Sstevel@tonic-gate 			 * and continue to check.
1537c478bd9Sstevel@tonic-gate 			 */
1547c478bd9Sstevel@tonic-gate 			if (SEQ_GEQ(end, head[i].end)) {
1557c478bd9Sstevel@tonic-gate 				new_num--;
1567c478bd9Sstevel@tonic-gate 				continue;
1577c478bd9Sstevel@tonic-gate 			} else {
1587c478bd9Sstevel@tonic-gate 				tmp[j].begin = end;
1597c478bd9Sstevel@tonic-gate 				tmp[j].end = head[i].end;
1607c478bd9Sstevel@tonic-gate 			}
1617c478bd9Sstevel@tonic-gate 		} else {
1627c478bd9Sstevel@tonic-gate 			tmp[j].begin = head[i].begin;
1637c478bd9Sstevel@tonic-gate 			tmp[j].end = head[i].end;
1647c478bd9Sstevel@tonic-gate 		}
1657c478bd9Sstevel@tonic-gate 		j++;
1667c478bd9Sstevel@tonic-gate 	}
1677c478bd9Sstevel@tonic-gate 	/* Copy tmp[] back to the original list. */
1687c478bd9Sstevel@tonic-gate 	for (i = 0; i < new_num; i++) {
1697c478bd9Sstevel@tonic-gate 		head[i].begin = tmp[i].begin;
1707c478bd9Sstevel@tonic-gate 		head[i].end = tmp[i].end;
1717c478bd9Sstevel@tonic-gate 	}
1727c478bd9Sstevel@tonic-gate 	*num = new_num;
1737c478bd9Sstevel@tonic-gate }
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate /*
1777c478bd9Sstevel@tonic-gate  * Use the SACK info to insert a "notsack'ed" blk.  The notsack'ed blk list
1787c478bd9Sstevel@tonic-gate  * contains the list of blks which have not been selectively acknowledged
1797c478bd9Sstevel@tonic-gate  * by the receiver.  The SACK info is a blk which is being selectively
1807c478bd9Sstevel@tonic-gate  * acknowledged by the receiver.
1817c478bd9Sstevel@tonic-gate  *
1827c478bd9Sstevel@tonic-gate  * Parameters:
1837c478bd9Sstevel@tonic-gate  *	notsack_blk_t **head: address of the pointer to the list of notsack'ed
1847c478bd9Sstevel@tonic-gate  *		blks.
1857c478bd9Sstevel@tonic-gate  *	tcp_seq begin: starting seq num of the SACK info.
1867c478bd9Sstevel@tonic-gate  *	tcp_seq end: ending seq num of the SACK info.
1877c478bd9Sstevel@tonic-gate  *	int32_t *num: (referenced) total num of notsack'ed blk on the list.
1887c478bd9Sstevel@tonic-gate  *	uint32_t *sum: (referenced) total num of bytes of all the notsack'ed
1897c478bd9Sstevel@tonic-gate  *		blks.
1907c478bd9Sstevel@tonic-gate  */
1917c478bd9Sstevel@tonic-gate void
tcp_notsack_insert(notsack_blk_t ** head,tcp_seq begin,tcp_seq end,int32_t * num,uint32_t * sum)1927c478bd9Sstevel@tonic-gate tcp_notsack_insert(notsack_blk_t **head, tcp_seq begin, tcp_seq end,
1937c478bd9Sstevel@tonic-gate     int32_t *num, uint32_t *sum)
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate 	notsack_blk_t *prev, *tmp, *new;
1967c478bd9Sstevel@tonic-gate 	uint32_t tmp_sum, tmp_num;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	if (*head == NULL) {
1997c478bd9Sstevel@tonic-gate 		return;
2007c478bd9Sstevel@tonic-gate 	}
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	tmp = *head;
2037c478bd9Sstevel@tonic-gate 	prev = NULL;
2047c478bd9Sstevel@tonic-gate 	/* Find the right place of updating the list. */
2057c478bd9Sstevel@tonic-gate 	while ((tmp != NULL) && SEQ_LEQ(tmp->end, begin)) {
2067c478bd9Sstevel@tonic-gate 		prev = tmp;
2077c478bd9Sstevel@tonic-gate 		(tmp->sack_cnt)++;
2087c478bd9Sstevel@tonic-gate 		tmp = tmp->next;
2097c478bd9Sstevel@tonic-gate 	}
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	/*
2127c478bd9Sstevel@tonic-gate 	 * This can happen only when TCP sends new data but the notsack list
2137c478bd9Sstevel@tonic-gate 	 * is not updated.
2147c478bd9Sstevel@tonic-gate 	 */
2157c478bd9Sstevel@tonic-gate 	if (tmp == NULL) {
2167c478bd9Sstevel@tonic-gate 		return;
2177c478bd9Sstevel@tonic-gate 	}
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	/*
2207c478bd9Sstevel@tonic-gate 	 * This means the new SACK info covers something that is not on
2217c478bd9Sstevel@tonic-gate 	 * the list anymore.
2227c478bd9Sstevel@tonic-gate 	 */
2237c478bd9Sstevel@tonic-gate 	if (SEQ_LEQ(end, tmp->begin)) {
2247c478bd9Sstevel@tonic-gate 		return;
2257c478bd9Sstevel@tonic-gate 	}
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	/* The SACK info covers up to this blk.  So just check for this blk. */
2287c478bd9Sstevel@tonic-gate 	if (SEQ_LEQ(end, tmp->end)) {
2297c478bd9Sstevel@tonic-gate 		/*
2307c478bd9Sstevel@tonic-gate 		 * Only this notsack'ed blk is completely covered.  Delete
2317c478bd9Sstevel@tonic-gate 		 * it and return.
2327c478bd9Sstevel@tonic-gate 		 */
2337c478bd9Sstevel@tonic-gate 		if (end == tmp->end && SEQ_LEQ(begin, tmp->begin)) {
2347c478bd9Sstevel@tonic-gate 			if (prev != NULL) {
2357c478bd9Sstevel@tonic-gate 				prev->next = tmp->next;
2367c478bd9Sstevel@tonic-gate 			} else {
2377c478bd9Sstevel@tonic-gate 				*head = tmp->next;
2387c478bd9Sstevel@tonic-gate 			}
2397c478bd9Sstevel@tonic-gate 			(*num)--;
2407c478bd9Sstevel@tonic-gate 			*sum -= tmp->end - tmp->begin;
241*66cd0f60SKacheong Poon 			kmem_cache_free(tcp_notsack_blk_cache, tmp);
2427c478bd9Sstevel@tonic-gate 			return;
2437c478bd9Sstevel@tonic-gate 		}
2447c478bd9Sstevel@tonic-gate 		/* This blk is partially covered. */
2457c478bd9Sstevel@tonic-gate 		if (SEQ_GEQ(begin, tmp->begin)) {
2467c478bd9Sstevel@tonic-gate 			/* Check what needs to be updated. */
2477c478bd9Sstevel@tonic-gate 			if (begin == tmp->begin) {
2487c478bd9Sstevel@tonic-gate 				*sum -= end - tmp->begin;
2497c478bd9Sstevel@tonic-gate 				tmp->begin = end;
2507c478bd9Sstevel@tonic-gate 			} else if (end == tmp->end) {
2517c478bd9Sstevel@tonic-gate 				*sum -= tmp->end - begin;
2527c478bd9Sstevel@tonic-gate 				tmp->end = begin;
2537c478bd9Sstevel@tonic-gate 				(tmp->sack_cnt)++;
2547c478bd9Sstevel@tonic-gate 			} else {
2557c478bd9Sstevel@tonic-gate 				/* Split the notsack blk. */
256*66cd0f60SKacheong Poon 				if ((new = kmem_cache_alloc(
257*66cd0f60SKacheong Poon 				    tcp_notsack_blk_cache, KM_NOSLEEP)) ==
258*66cd0f60SKacheong Poon 				    NULL) {
2597c478bd9Sstevel@tonic-gate 					return;
2607c478bd9Sstevel@tonic-gate 				}
2617c478bd9Sstevel@tonic-gate 				new->end = tmp->end;
2627c478bd9Sstevel@tonic-gate 				new->begin = end;
2637c478bd9Sstevel@tonic-gate 				new->next = tmp->next;
2647c478bd9Sstevel@tonic-gate 				new->sack_cnt = 0;
2657c478bd9Sstevel@tonic-gate 				tmp->end = begin;
2667c478bd9Sstevel@tonic-gate 				tmp->next = new;
2677c478bd9Sstevel@tonic-gate 				(tmp->sack_cnt)++;
2687c478bd9Sstevel@tonic-gate 				(*num)++;
2697c478bd9Sstevel@tonic-gate 				*sum -= end - begin;
2707c478bd9Sstevel@tonic-gate 			}
2717c478bd9Sstevel@tonic-gate 		} else {
2727c478bd9Sstevel@tonic-gate 			*sum -= end - tmp->begin;
2737c478bd9Sstevel@tonic-gate 			tmp->begin = end;
2747c478bd9Sstevel@tonic-gate 		}
2757c478bd9Sstevel@tonic-gate 		return;
2767c478bd9Sstevel@tonic-gate 	}
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	/* Need to check for coverage of this blk and later blks. */
2797c478bd9Sstevel@tonic-gate 	tmp_sum = *sum;
2807c478bd9Sstevel@tonic-gate 	tmp_num = *num;
2817c478bd9Sstevel@tonic-gate 	if (SEQ_LT(tmp->begin, begin)) {
2827c478bd9Sstevel@tonic-gate 		tmp_sum -= tmp->end - begin;
2837c478bd9Sstevel@tonic-gate 		tmp->end = begin;
2847c478bd9Sstevel@tonic-gate 		(tmp->sack_cnt)++;
2857c478bd9Sstevel@tonic-gate 		prev = tmp;
2867c478bd9Sstevel@tonic-gate 		tmp = tmp->next;
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	while (tmp != NULL) {
2907c478bd9Sstevel@tonic-gate 		/* The coverage stops here. */
2917c478bd9Sstevel@tonic-gate 		if (SEQ_GT(tmp->begin, end)) {
2927c478bd9Sstevel@tonic-gate 			break;
2937c478bd9Sstevel@tonic-gate 		} else {
2947c478bd9Sstevel@tonic-gate 			/* Is the blk completely or partially covered? */
2957c478bd9Sstevel@tonic-gate 			if (SEQ_LEQ(tmp->end, end)) {
2967c478bd9Sstevel@tonic-gate 				tmp_num--;
2977c478bd9Sstevel@tonic-gate 				tmp_sum -= tmp->end - tmp->begin;
2987c478bd9Sstevel@tonic-gate 				if (prev != NULL) {
2997c478bd9Sstevel@tonic-gate 					prev->next = tmp->next;
300*66cd0f60SKacheong Poon 					kmem_cache_free(tcp_notsack_blk_cache,
301*66cd0f60SKacheong Poon 					    tmp);
3027c478bd9Sstevel@tonic-gate 					tmp = prev->next;
3037c478bd9Sstevel@tonic-gate 				} else {
3047c478bd9Sstevel@tonic-gate 					*head = tmp->next;
305*66cd0f60SKacheong Poon 					kmem_cache_free(tcp_notsack_blk_cache,
306*66cd0f60SKacheong Poon 					    tmp);
3077c478bd9Sstevel@tonic-gate 					tmp = *head;
3087c478bd9Sstevel@tonic-gate 				}
3097c478bd9Sstevel@tonic-gate 			} else {
3107c478bd9Sstevel@tonic-gate 				/*
3117c478bd9Sstevel@tonic-gate 				 * This blk is partially covered.  It also
3127c478bd9Sstevel@tonic-gate 				 * means it should be the end of coverage.
3137c478bd9Sstevel@tonic-gate 				 */
3147c478bd9Sstevel@tonic-gate 				tmp_sum -= end - tmp->begin;
3157c478bd9Sstevel@tonic-gate 				tmp->begin = end;
3167c478bd9Sstevel@tonic-gate 				break;
3177c478bd9Sstevel@tonic-gate 			}
3187c478bd9Sstevel@tonic-gate 		}
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 	*num = tmp_num;
3217c478bd9Sstevel@tonic-gate 	*sum = tmp_sum;
3227c478bd9Sstevel@tonic-gate }
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate /*
3267c478bd9Sstevel@tonic-gate  * To remove notsack'ed blks.
3277c478bd9Sstevel@tonic-gate  *
3287c478bd9Sstevel@tonic-gate  * Parameters:
3297c478bd9Sstevel@tonic-gate  *	notsack_blk_t **head: address of the pointer to the list of notsack'ed
3307c478bd9Sstevel@tonic-gate  *		blks.
3317c478bd9Sstevel@tonic-gate  *	tcp_seq end: to remove all notsack'ed blk with seq num less than end.
3327c478bd9Sstevel@tonic-gate  *	int32_t *num: (referenced) total num of notsack'ed blks.
3337c478bd9Sstevel@tonic-gate  *	uint32_t *sum: (referenced) total num of bytes of all the notsack'ed
3347c478bd9Sstevel@tonic-gate  *		blks.
3357c478bd9Sstevel@tonic-gate  */
3367c478bd9Sstevel@tonic-gate void
tcp_notsack_remove(notsack_blk_t ** head,tcp_seq end,int32_t * num,uint32_t * sum)3377c478bd9Sstevel@tonic-gate tcp_notsack_remove(notsack_blk_t **head, tcp_seq end, int32_t *num,
3387c478bd9Sstevel@tonic-gate     uint32_t *sum)
3397c478bd9Sstevel@tonic-gate {
3407c478bd9Sstevel@tonic-gate 	notsack_blk_t *prev, *tmp;
3417c478bd9Sstevel@tonic-gate 	uint32_t tmp_sum = *sum;
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	if (*head == NULL)
3447c478bd9Sstevel@tonic-gate 		return;
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	prev = NULL;
3477c478bd9Sstevel@tonic-gate 	tmp = *head;
3487c478bd9Sstevel@tonic-gate 	while (tmp != NULL) {
3497c478bd9Sstevel@tonic-gate 		/* There is nothing to discard. */
3507c478bd9Sstevel@tonic-gate 		if (SEQ_GT(tmp->begin, end)) {
3517c478bd9Sstevel@tonic-gate 			break;
3527c478bd9Sstevel@tonic-gate 		}
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 		/* Is the blk completely or partially covered? */
3557c478bd9Sstevel@tonic-gate 		if (SEQ_GEQ(end, tmp->end)) {
3567c478bd9Sstevel@tonic-gate 			(*num)--;
3577c478bd9Sstevel@tonic-gate 			tmp_sum -= tmp->end - tmp->begin;
3587c478bd9Sstevel@tonic-gate 			if (prev == NULL) {
3597c478bd9Sstevel@tonic-gate 				*head = tmp->next;
360*66cd0f60SKacheong Poon 				kmem_cache_free(tcp_notsack_blk_cache, tmp);
3617c478bd9Sstevel@tonic-gate 				tmp = *head;
3627c478bd9Sstevel@tonic-gate 			} else {
3637c478bd9Sstevel@tonic-gate 				prev->next = tmp->next;
364*66cd0f60SKacheong Poon 				kmem_cache_free(tcp_notsack_blk_cache, tmp);
3657c478bd9Sstevel@tonic-gate 				tmp = prev->next;
3667c478bd9Sstevel@tonic-gate 			}
3677c478bd9Sstevel@tonic-gate 		} else {
3687c478bd9Sstevel@tonic-gate 			tmp_sum -= end - tmp->begin;
3697c478bd9Sstevel@tonic-gate 			tmp->begin = end;
3707c478bd9Sstevel@tonic-gate 			break;
3717c478bd9Sstevel@tonic-gate 		}
3727c478bd9Sstevel@tonic-gate 	}
3737c478bd9Sstevel@tonic-gate 	*sum = tmp_sum;
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate /*
3787c478bd9Sstevel@tonic-gate  * To update the notsack'ed list when new data is sent.
3797c478bd9Sstevel@tonic-gate  *
3807c478bd9Sstevel@tonic-gate  * Assumption: this should only be called when new notsack blk is to be added.
3817c478bd9Sstevel@tonic-gate  *
3827c478bd9Sstevel@tonic-gate  * Parameters:
3837c478bd9Sstevel@tonic-gate  *	notsack_blk_t **head: address of the pointer to the list of notsack'ed
3847c478bd9Sstevel@tonic-gate  *		blks.
3857c478bd9Sstevel@tonic-gate  *	tcp_seq begin: beginning seq num of new data.
3867c478bd9Sstevel@tonic-gate  *	tcp_seq end: ending seq num of new data.
3877c478bd9Sstevel@tonic-gate  *	int32_t *num: (referenced) total num of notsack'ed blks.
3887c478bd9Sstevel@tonic-gate  *	uint32_t *sum: (referenced) total num of bytes of all the notsack'ed
3897c478bd9Sstevel@tonic-gate  *		blks.
3907c478bd9Sstevel@tonic-gate  */
tcp_notsack_update(notsack_blk_t ** head,tcp_seq begin,tcp_seq end,int32_t * num,uint32_t * sum)3917c478bd9Sstevel@tonic-gate void tcp_notsack_update(notsack_blk_t **head, tcp_seq begin, tcp_seq end,
3927c478bd9Sstevel@tonic-gate     int32_t *num, uint32_t *sum)
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate 	notsack_blk_t *tmp;
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	tmp = *head;
3977c478bd9Sstevel@tonic-gate 	/* If the list is empty, create a new one. */
3987c478bd9Sstevel@tonic-gate 	if (tmp == NULL) {
399*66cd0f60SKacheong Poon 		if ((tmp = kmem_cache_alloc(tcp_notsack_blk_cache,
400*66cd0f60SKacheong Poon 		    KM_NOSLEEP)) == NULL) {
4017c478bd9Sstevel@tonic-gate 			return;
4027c478bd9Sstevel@tonic-gate 		}
4037c478bd9Sstevel@tonic-gate 		tmp->begin = begin;
4047c478bd9Sstevel@tonic-gate 		tmp->end = end;
4057c478bd9Sstevel@tonic-gate 		tmp->next = NULL;
4067c478bd9Sstevel@tonic-gate 		tmp->sack_cnt = 0;
4077c478bd9Sstevel@tonic-gate 		*head = tmp;
4087c478bd9Sstevel@tonic-gate 		*num = 1;
4097c478bd9Sstevel@tonic-gate 		*sum = end - begin;
4107c478bd9Sstevel@tonic-gate 		return;
4117c478bd9Sstevel@tonic-gate 	}
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	/*
4147c478bd9Sstevel@tonic-gate 	 * Find the place to add the new blk.  This assumes that new data
4157c478bd9Sstevel@tonic-gate 	 * is being sent, so the place to insert the new notsack blk is at
4167c478bd9Sstevel@tonic-gate 	 * the end of the list.
4177c478bd9Sstevel@tonic-gate 	 */
4187c478bd9Sstevel@tonic-gate 	while (tmp->next != NULL) {
4197c478bd9Sstevel@tonic-gate 		tmp = tmp->next;
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	/* Does the new blk overlap with old one? */
4237c478bd9Sstevel@tonic-gate 	if (SEQ_GEQ(tmp->end, begin)) {
4247c478bd9Sstevel@tonic-gate 		*sum += end - tmp->end;
4257c478bd9Sstevel@tonic-gate 		tmp->end = end;
4267c478bd9Sstevel@tonic-gate 	} else {
4277c478bd9Sstevel@tonic-gate 		/* No.  Need to create a new notsack blk. */
428*66cd0f60SKacheong Poon 		tmp->next = kmem_cache_alloc(tcp_notsack_blk_cache, KM_NOSLEEP);
4297c478bd9Sstevel@tonic-gate 		if (tmp->next != NULL) {
4307c478bd9Sstevel@tonic-gate 			tmp = tmp->next;
4317c478bd9Sstevel@tonic-gate 			tmp->begin = begin;
4327c478bd9Sstevel@tonic-gate 			tmp->end = end;
4337c478bd9Sstevel@tonic-gate 			tmp->next = NULL;
4347c478bd9Sstevel@tonic-gate 			tmp->sack_cnt = 0;
4357c478bd9Sstevel@tonic-gate 			(*num)++;
4367c478bd9Sstevel@tonic-gate 			*sum += end - begin;
4377c478bd9Sstevel@tonic-gate 		}
4387c478bd9Sstevel@tonic-gate 	}
4397c478bd9Sstevel@tonic-gate }
440