xref: /illumos-gate/usr/src/stand/lib/tcp/tcp_sack.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 1997-2003 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /* Modified to be used by inetboot. */
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
32*7c478bd9Sstevel@tonic-gate #include <socket_impl.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
34*7c478bd9Sstevel@tonic-gate #include <netinet/tcp.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
37*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
38*7c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
39*7c478bd9Sstevel@tonic-gate #include <inet/common.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/salib.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #include "tcp_inet.h"
44*7c478bd9Sstevel@tonic-gate #include "tcp_sack.h"
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate /*
47*7c478bd9Sstevel@tonic-gate  * To insert a new blk to the array of SACK blk in receiver.
48*7c478bd9Sstevel@tonic-gate  *
49*7c478bd9Sstevel@tonic-gate  * Parameters:
50*7c478bd9Sstevel@tonic-gate  *	sack_blk_t *head: pointer to the array of SACK blks.
51*7c478bd9Sstevel@tonic-gate  *	tcp_seq begin: starting seq num of the new blk.
52*7c478bd9Sstevel@tonic-gate  *	tcp_seq end: ending seq num of the new blk.
53*7c478bd9Sstevel@tonic-gate  *	int32_t *num: (referenced) total num of SACK blks on the list.
54*7c478bd9Sstevel@tonic-gate  */
55*7c478bd9Sstevel@tonic-gate void
tcp_sack_insert(sack_blk_t * head,tcp_seq begin,tcp_seq end,int32_t * num)56*7c478bd9Sstevel@tonic-gate tcp_sack_insert(sack_blk_t *head, tcp_seq begin, tcp_seq end, int32_t *num)
57*7c478bd9Sstevel@tonic-gate {
58*7c478bd9Sstevel@tonic-gate 	int32_t	i, j, old_num, new_num;
59*7c478bd9Sstevel@tonic-gate 	sack_blk_t tmp[MAX_SACK_BLK - 1];
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate 	/* The array is empty, just add the new one. */
62*7c478bd9Sstevel@tonic-gate 	if (*num == 0) {
63*7c478bd9Sstevel@tonic-gate 		head[0].begin = begin;
64*7c478bd9Sstevel@tonic-gate 		head[0].end = end;
65*7c478bd9Sstevel@tonic-gate 		*num = 1;
66*7c478bd9Sstevel@tonic-gate 		return;
67*7c478bd9Sstevel@tonic-gate 	}
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate 	/*
70*7c478bd9Sstevel@tonic-gate 	 * Check for overlap.  There are five cases.
71*7c478bd9Sstevel@tonic-gate 	 *
72*7c478bd9Sstevel@tonic-gate 	 * 1. there is no overlap with any other SACK blks.
73*7c478bd9Sstevel@tonic-gate 	 * 2. new SACK blk is completely contained in another blk.
74*7c478bd9Sstevel@tonic-gate 	 * 3. tail part of new SACK blk overlaps with another blk.
75*7c478bd9Sstevel@tonic-gate 	 * 4. head part of new SACK blk overlaps with another blk.
76*7c478bd9Sstevel@tonic-gate 	 * 5. new SACK blk completely contains another blk.
77*7c478bd9Sstevel@tonic-gate 	 *
78*7c478bd9Sstevel@tonic-gate 	 * Use tmp to hold old SACK blks.  After the loop, copy them back
79*7c478bd9Sstevel@tonic-gate 	 * to head.
80*7c478bd9Sstevel@tonic-gate 	 */
81*7c478bd9Sstevel@tonic-gate 	old_num = *num;
82*7c478bd9Sstevel@tonic-gate 	if (old_num > MAX_SACK_BLK - 1) {
83*7c478bd9Sstevel@tonic-gate 		old_num = MAX_SACK_BLK - 1;
84*7c478bd9Sstevel@tonic-gate 	}
85*7c478bd9Sstevel@tonic-gate 	new_num = old_num;
86*7c478bd9Sstevel@tonic-gate 	j = 0;
87*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < old_num; i++) {
88*7c478bd9Sstevel@tonic-gate 		if (SEQ_LT(end, head[i].begin) || SEQ_GT(begin, head[i].end)) {
89*7c478bd9Sstevel@tonic-gate 			/* Case 1: continue to check. */
90*7c478bd9Sstevel@tonic-gate 			tmp[j].begin = head[i].begin;
91*7c478bd9Sstevel@tonic-gate 			tmp[j].end = head[i].end;
92*7c478bd9Sstevel@tonic-gate 			j++;
93*7c478bd9Sstevel@tonic-gate 			continue;
94*7c478bd9Sstevel@tonic-gate 		} else if (SEQ_GEQ(begin, head[i].begin) &&
95*7c478bd9Sstevel@tonic-gate 		    SEQ_LEQ(end, head[i].end)) {
96*7c478bd9Sstevel@tonic-gate 			/* Case 2: re-insert the old blk to the head. */
97*7c478bd9Sstevel@tonic-gate 			begin = head[i].begin;
98*7c478bd9Sstevel@tonic-gate 			end = head[i].end;
99*7c478bd9Sstevel@tonic-gate 		} else if (SEQ_LEQ(end, head[i].end) &&
100*7c478bd9Sstevel@tonic-gate 		    SEQ_GEQ(end, head[i].begin)) {
101*7c478bd9Sstevel@tonic-gate 			/*
102*7c478bd9Sstevel@tonic-gate 			 * Case 3: Extend the new blk, remove the old one
103*7c478bd9Sstevel@tonic-gate 			 * and continue to check.
104*7c478bd9Sstevel@tonic-gate 			 */
105*7c478bd9Sstevel@tonic-gate 			end = head[i].end;
106*7c478bd9Sstevel@tonic-gate 		} else if (SEQ_GEQ(begin, head[i].begin) &&
107*7c478bd9Sstevel@tonic-gate 		    SEQ_LEQ(begin, head[i].end)) {
108*7c478bd9Sstevel@tonic-gate 			/* Case 4 */
109*7c478bd9Sstevel@tonic-gate 			begin = head[i].begin;
110*7c478bd9Sstevel@tonic-gate 		}
111*7c478bd9Sstevel@tonic-gate 		/*
112*7c478bd9Sstevel@tonic-gate 		 * Common code for all cases except the first one, which
113*7c478bd9Sstevel@tonic-gate 		 * copies the original SACK blk into the tmp storage.  Other
114*7c478bd9Sstevel@tonic-gate 		 * cases remove the original SACK blk by not copying into
115*7c478bd9Sstevel@tonic-gate 		 * tmp storage.
116*7c478bd9Sstevel@tonic-gate 		 */
117*7c478bd9Sstevel@tonic-gate 		new_num--;
118*7c478bd9Sstevel@tonic-gate 	}
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate 	head[0].begin = begin;
121*7c478bd9Sstevel@tonic-gate 	head[0].end = end;
122*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < new_num; i++) {
123*7c478bd9Sstevel@tonic-gate 		head[i+1].begin = tmp[i].begin;
124*7c478bd9Sstevel@tonic-gate 		head[i+1].end = tmp[i].end;
125*7c478bd9Sstevel@tonic-gate 	}
126*7c478bd9Sstevel@tonic-gate 	*num = new_num + 1;
127*7c478bd9Sstevel@tonic-gate }
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate /*
131*7c478bd9Sstevel@tonic-gate  * To remove a SACK block.
132*7c478bd9Sstevel@tonic-gate  *
133*7c478bd9Sstevel@tonic-gate  * Parameters:
134*7c478bd9Sstevel@tonic-gate  *	sack_blk_t *head: pointer to the array of SACK blks.
135*7c478bd9Sstevel@tonic-gate  *	tcp_seq end: to remove all sack blk with seq num less than end.
136*7c478bd9Sstevel@tonic-gate  *	int32_t *num: (referenced) total num of SACK blks in the array.
137*7c478bd9Sstevel@tonic-gate  */
138*7c478bd9Sstevel@tonic-gate void
tcp_sack_remove(sack_blk_t * head,tcp_seq end,int32_t * num)139*7c478bd9Sstevel@tonic-gate tcp_sack_remove(sack_blk_t *head, tcp_seq end, int32_t *num)
140*7c478bd9Sstevel@tonic-gate {
141*7c478bd9Sstevel@tonic-gate 	sack_blk_t tmp[MAX_SACK_BLK];
142*7c478bd9Sstevel@tonic-gate 	int32_t i, j, old_num, new_num;
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 	if (*num == 0)
145*7c478bd9Sstevel@tonic-gate 		return;
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	old_num = *num;
148*7c478bd9Sstevel@tonic-gate 	new_num = old_num;
149*7c478bd9Sstevel@tonic-gate 	j = 0;
150*7c478bd9Sstevel@tonic-gate 	/* Walk thru the whole list and copy the new list to tmp[]. */
151*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < old_num; i++) {
152*7c478bd9Sstevel@tonic-gate 		if (SEQ_GT(end, head[i].begin)) {
153*7c478bd9Sstevel@tonic-gate 			/*
154*7c478bd9Sstevel@tonic-gate 			 * Check to see if the old SACK blk needs to be
155*7c478bd9Sstevel@tonic-gate 			 * removed or updated.  If the old blk is just
156*7c478bd9Sstevel@tonic-gate 			 * partially covered, update begin and continue.
157*7c478bd9Sstevel@tonic-gate 			 * If the old blk is completely covered, remove it
158*7c478bd9Sstevel@tonic-gate 			 * and continue to check.
159*7c478bd9Sstevel@tonic-gate 			 */
160*7c478bd9Sstevel@tonic-gate 			if (SEQ_GEQ(end, head[i].end)) {
161*7c478bd9Sstevel@tonic-gate 				new_num--;
162*7c478bd9Sstevel@tonic-gate 				continue;
163*7c478bd9Sstevel@tonic-gate 			} else {
164*7c478bd9Sstevel@tonic-gate 				tmp[j].begin = end;
165*7c478bd9Sstevel@tonic-gate 				tmp[j].end = head[i].end;
166*7c478bd9Sstevel@tonic-gate 			}
167*7c478bd9Sstevel@tonic-gate 		} else {
168*7c478bd9Sstevel@tonic-gate 			tmp[j].begin = head[i].begin;
169*7c478bd9Sstevel@tonic-gate 			tmp[j].end = head[i].end;
170*7c478bd9Sstevel@tonic-gate 		}
171*7c478bd9Sstevel@tonic-gate 		j++;
172*7c478bd9Sstevel@tonic-gate 	}
173*7c478bd9Sstevel@tonic-gate 	/* Copy tmp[] back to the original list. */
174*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < new_num; i++) {
175*7c478bd9Sstevel@tonic-gate 		head[i].begin = tmp[i].begin;
176*7c478bd9Sstevel@tonic-gate 		head[i].end = tmp[i].end;
177*7c478bd9Sstevel@tonic-gate 	}
178*7c478bd9Sstevel@tonic-gate 	*num = new_num;
179*7c478bd9Sstevel@tonic-gate }
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate /*
183*7c478bd9Sstevel@tonic-gate  * Use the SACK info to insert a "notsack'ed" blk.  The notsack'ed blk list
184*7c478bd9Sstevel@tonic-gate  * contains the list of blks which have not been selectively acknowledged
185*7c478bd9Sstevel@tonic-gate  * by the receiver.  The SACK info is a blk which is being selectively
186*7c478bd9Sstevel@tonic-gate  * acknowledged by the receiver.
187*7c478bd9Sstevel@tonic-gate  *
188*7c478bd9Sstevel@tonic-gate  * Parameters:
189*7c478bd9Sstevel@tonic-gate  *	notsack_blk_t **head: address of the pointer to the list of notsack'ed
190*7c478bd9Sstevel@tonic-gate  *		blks.
191*7c478bd9Sstevel@tonic-gate  *	tcp_seq begin: starting seq num of the SACK info.
192*7c478bd9Sstevel@tonic-gate  *	tcp_seq end: ending seq num of the SACK info.
193*7c478bd9Sstevel@tonic-gate  *	int32_t *num: (referenced) total num of notsack'ed blk on the list.
194*7c478bd9Sstevel@tonic-gate  *	uint32_t *sum: (referenced) total num of bytes of all the notsack'ed
195*7c478bd9Sstevel@tonic-gate  *		blks.
196*7c478bd9Sstevel@tonic-gate  */
197*7c478bd9Sstevel@tonic-gate void
tcp_notsack_insert(notsack_blk_t ** head,tcp_seq begin,tcp_seq end,int32_t * num,uint32_t * sum)198*7c478bd9Sstevel@tonic-gate tcp_notsack_insert(notsack_blk_t **head, tcp_seq begin, tcp_seq end,
199*7c478bd9Sstevel@tonic-gate     int32_t *num, uint32_t *sum)
200*7c478bd9Sstevel@tonic-gate {
201*7c478bd9Sstevel@tonic-gate 	notsack_blk_t *prev, *tmp, *new;
202*7c478bd9Sstevel@tonic-gate 	uint32_t tmp_sum, tmp_num;
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	if (*head == NULL) {
205*7c478bd9Sstevel@tonic-gate 		return;
206*7c478bd9Sstevel@tonic-gate 	}
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	tmp = *head;
209*7c478bd9Sstevel@tonic-gate 	prev = NULL;
210*7c478bd9Sstevel@tonic-gate 	/* Find the right place of updating the list. */
211*7c478bd9Sstevel@tonic-gate 	while ((tmp != NULL) && SEQ_LEQ(tmp->end, begin)) {
212*7c478bd9Sstevel@tonic-gate 		prev = tmp;
213*7c478bd9Sstevel@tonic-gate 		(tmp->sack_cnt)++;
214*7c478bd9Sstevel@tonic-gate 		tmp = tmp->next;
215*7c478bd9Sstevel@tonic-gate 	}
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 	/*
218*7c478bd9Sstevel@tonic-gate 	 * This can happen only when TCP sends new data but the notsack list
219*7c478bd9Sstevel@tonic-gate 	 * is not updated.
220*7c478bd9Sstevel@tonic-gate 	 */
221*7c478bd9Sstevel@tonic-gate 	if (tmp == NULL) {
222*7c478bd9Sstevel@tonic-gate 		return;
223*7c478bd9Sstevel@tonic-gate 	}
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	/*
226*7c478bd9Sstevel@tonic-gate 	 * This means the new SACK info covers something that is not on
227*7c478bd9Sstevel@tonic-gate 	 * the list anymore.
228*7c478bd9Sstevel@tonic-gate 	 */
229*7c478bd9Sstevel@tonic-gate 	if (SEQ_LEQ(end, tmp->begin)) {
230*7c478bd9Sstevel@tonic-gate 		return;
231*7c478bd9Sstevel@tonic-gate 	}
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	/* The SACK info covers up to this blk.  So just check for this blk. */
234*7c478bd9Sstevel@tonic-gate 	if (SEQ_LEQ(end, tmp->end)) {
235*7c478bd9Sstevel@tonic-gate 		/*
236*7c478bd9Sstevel@tonic-gate 		 * Only this notsack'ed blk is completely covered.  Delete
237*7c478bd9Sstevel@tonic-gate 		 * it and return.
238*7c478bd9Sstevel@tonic-gate 		 */
239*7c478bd9Sstevel@tonic-gate 		if (end == tmp->end && SEQ_LEQ(begin, tmp->begin)) {
240*7c478bd9Sstevel@tonic-gate 			if (prev != NULL) {
241*7c478bd9Sstevel@tonic-gate 				prev->next = tmp->next;
242*7c478bd9Sstevel@tonic-gate 			} else {
243*7c478bd9Sstevel@tonic-gate 				*head = tmp->next;
244*7c478bd9Sstevel@tonic-gate 			}
245*7c478bd9Sstevel@tonic-gate 			(*num)--;
246*7c478bd9Sstevel@tonic-gate 			*sum -= tmp->end - tmp->begin;
247*7c478bd9Sstevel@tonic-gate 			bkmem_free(tmp, sizeof (notsack_blk_t));
248*7c478bd9Sstevel@tonic-gate 			return;
249*7c478bd9Sstevel@tonic-gate 		}
250*7c478bd9Sstevel@tonic-gate 		/* This blk is partially covered. */
251*7c478bd9Sstevel@tonic-gate 		if (SEQ_GEQ(begin, tmp->begin)) {
252*7c478bd9Sstevel@tonic-gate 			/* Check what needs to be updated. */
253*7c478bd9Sstevel@tonic-gate 			if (begin == tmp->begin) {
254*7c478bd9Sstevel@tonic-gate 				*sum -= end - tmp->begin;
255*7c478bd9Sstevel@tonic-gate 				tmp->begin = end;
256*7c478bd9Sstevel@tonic-gate 			} else if (end == tmp->end) {
257*7c478bd9Sstevel@tonic-gate 				*sum -= tmp->end - begin;
258*7c478bd9Sstevel@tonic-gate 				tmp->end = begin;
259*7c478bd9Sstevel@tonic-gate 				(tmp->sack_cnt)++;
260*7c478bd9Sstevel@tonic-gate 			} else {
261*7c478bd9Sstevel@tonic-gate 				/* Split the notsack blk. */
262*7c478bd9Sstevel@tonic-gate 				if ((new = (notsack_blk_t *)bkmem_alloc(
263*7c478bd9Sstevel@tonic-gate 				    sizeof (notsack_blk_t))) == NULL) {
264*7c478bd9Sstevel@tonic-gate 					return;
265*7c478bd9Sstevel@tonic-gate 				}
266*7c478bd9Sstevel@tonic-gate 				new->end = tmp->end;
267*7c478bd9Sstevel@tonic-gate 				new->begin = end;
268*7c478bd9Sstevel@tonic-gate 				new->next = tmp->next;
269*7c478bd9Sstevel@tonic-gate 				new->sack_cnt = 0;
270*7c478bd9Sstevel@tonic-gate 				tmp->end = begin;
271*7c478bd9Sstevel@tonic-gate 				tmp->next = new;
272*7c478bd9Sstevel@tonic-gate 				(tmp->sack_cnt)++;
273*7c478bd9Sstevel@tonic-gate 				(*num)++;
274*7c478bd9Sstevel@tonic-gate 				*sum -= end - begin;
275*7c478bd9Sstevel@tonic-gate 			}
276*7c478bd9Sstevel@tonic-gate 		} else {
277*7c478bd9Sstevel@tonic-gate 			*sum -= end - tmp->begin;
278*7c478bd9Sstevel@tonic-gate 			tmp->begin = end;
279*7c478bd9Sstevel@tonic-gate 		}
280*7c478bd9Sstevel@tonic-gate 		return;
281*7c478bd9Sstevel@tonic-gate 	}
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	/* Need to check for coverage of this blk and later blks. */
284*7c478bd9Sstevel@tonic-gate 	tmp_sum = *sum;
285*7c478bd9Sstevel@tonic-gate 	tmp_num = *num;
286*7c478bd9Sstevel@tonic-gate 	if (SEQ_LT(tmp->begin, begin)) {
287*7c478bd9Sstevel@tonic-gate 		tmp_sum -= tmp->end - begin;
288*7c478bd9Sstevel@tonic-gate 		tmp->end = begin;
289*7c478bd9Sstevel@tonic-gate 		(tmp->sack_cnt)++;
290*7c478bd9Sstevel@tonic-gate 		prev = tmp;
291*7c478bd9Sstevel@tonic-gate 		tmp = tmp->next;
292*7c478bd9Sstevel@tonic-gate 	}
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 	while (tmp != NULL) {
295*7c478bd9Sstevel@tonic-gate 		/* The coverage stops here. */
296*7c478bd9Sstevel@tonic-gate 		if (SEQ_GT(tmp->begin, end)) {
297*7c478bd9Sstevel@tonic-gate 			break;
298*7c478bd9Sstevel@tonic-gate 		} else {
299*7c478bd9Sstevel@tonic-gate 			/* Is the blk completely or partially covered? */
300*7c478bd9Sstevel@tonic-gate 			if (SEQ_LEQ(tmp->end, end)) {
301*7c478bd9Sstevel@tonic-gate 				tmp_num--;
302*7c478bd9Sstevel@tonic-gate 				tmp_sum -= tmp->end - tmp->begin;
303*7c478bd9Sstevel@tonic-gate 				if (prev != NULL) {
304*7c478bd9Sstevel@tonic-gate 					prev->next = tmp->next;
305*7c478bd9Sstevel@tonic-gate 					bkmem_free((caddr_t)tmp,
306*7c478bd9Sstevel@tonic-gate 					    sizeof (notsack_blk_t));
307*7c478bd9Sstevel@tonic-gate 					tmp = prev->next;
308*7c478bd9Sstevel@tonic-gate 				} else {
309*7c478bd9Sstevel@tonic-gate 					*head = tmp->next;
310*7c478bd9Sstevel@tonic-gate 					bkmem_free((caddr_t)tmp,
311*7c478bd9Sstevel@tonic-gate 					    sizeof (notsack_blk_t));
312*7c478bd9Sstevel@tonic-gate 					tmp = *head;
313*7c478bd9Sstevel@tonic-gate 				}
314*7c478bd9Sstevel@tonic-gate 			} else {
315*7c478bd9Sstevel@tonic-gate 				/*
316*7c478bd9Sstevel@tonic-gate 				 * This blk is partially covered.  It also
317*7c478bd9Sstevel@tonic-gate 				 * means it should be the end of coverage.
318*7c478bd9Sstevel@tonic-gate 				 */
319*7c478bd9Sstevel@tonic-gate 				tmp_sum -= end - tmp->begin;
320*7c478bd9Sstevel@tonic-gate 				tmp->begin = end;
321*7c478bd9Sstevel@tonic-gate 				break;
322*7c478bd9Sstevel@tonic-gate 			}
323*7c478bd9Sstevel@tonic-gate 		}
324*7c478bd9Sstevel@tonic-gate 	}
325*7c478bd9Sstevel@tonic-gate 	*num = tmp_num;
326*7c478bd9Sstevel@tonic-gate 	*sum = tmp_sum;
327*7c478bd9Sstevel@tonic-gate }
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate /*
331*7c478bd9Sstevel@tonic-gate  * To remove notsack'ed blks.
332*7c478bd9Sstevel@tonic-gate  *
333*7c478bd9Sstevel@tonic-gate  * Parameters:
334*7c478bd9Sstevel@tonic-gate  *	notsack_blk_t **head: address of the pointer to the list of notsack'ed
335*7c478bd9Sstevel@tonic-gate  *		blks.
336*7c478bd9Sstevel@tonic-gate  *	tcp_seq end: to remove all notsack'ed blk with seq num less than end.
337*7c478bd9Sstevel@tonic-gate  *	int32_t *num: (referenced) total num of notsack'ed blks.
338*7c478bd9Sstevel@tonic-gate  *	uint32_t *sum: (referenced) total num of bytes of all the notsack'ed
339*7c478bd9Sstevel@tonic-gate  *		blks.
340*7c478bd9Sstevel@tonic-gate  */
341*7c478bd9Sstevel@tonic-gate void
tcp_notsack_remove(notsack_blk_t ** head,tcp_seq end,int32_t * num,uint32_t * sum)342*7c478bd9Sstevel@tonic-gate tcp_notsack_remove(notsack_blk_t **head, tcp_seq end, int32_t *num,
343*7c478bd9Sstevel@tonic-gate     uint32_t *sum)
344*7c478bd9Sstevel@tonic-gate {
345*7c478bd9Sstevel@tonic-gate 	notsack_blk_t *prev, *tmp;
346*7c478bd9Sstevel@tonic-gate 	uint32_t tmp_sum = *sum;
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 	if (*head == NULL)
349*7c478bd9Sstevel@tonic-gate 		return;
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 	prev = NULL;
352*7c478bd9Sstevel@tonic-gate 	tmp = *head;
353*7c478bd9Sstevel@tonic-gate 	while (tmp != NULL) {
354*7c478bd9Sstevel@tonic-gate 		/* There is nothing to discard. */
355*7c478bd9Sstevel@tonic-gate 		if (SEQ_GT(tmp->begin, end)) {
356*7c478bd9Sstevel@tonic-gate 			break;
357*7c478bd9Sstevel@tonic-gate 		}
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate 		/* Is the blk completely or partially covered? */
360*7c478bd9Sstevel@tonic-gate 		if (SEQ_GEQ(end, tmp->end)) {
361*7c478bd9Sstevel@tonic-gate 			(*num)--;
362*7c478bd9Sstevel@tonic-gate 			tmp_sum -= tmp->end - tmp->begin;
363*7c478bd9Sstevel@tonic-gate 			if (prev == NULL) {
364*7c478bd9Sstevel@tonic-gate 				*head = tmp->next;
365*7c478bd9Sstevel@tonic-gate 				bkmem_free((caddr_t)tmp,
366*7c478bd9Sstevel@tonic-gate 				    sizeof (notsack_blk_t));
367*7c478bd9Sstevel@tonic-gate 				tmp = *head;
368*7c478bd9Sstevel@tonic-gate 			} else {
369*7c478bd9Sstevel@tonic-gate 				prev->next = tmp->next;
370*7c478bd9Sstevel@tonic-gate 				bkmem_free((caddr_t)tmp,
371*7c478bd9Sstevel@tonic-gate 				    sizeof (notsack_blk_t));
372*7c478bd9Sstevel@tonic-gate 				tmp = tmp->next;
373*7c478bd9Sstevel@tonic-gate 			}
374*7c478bd9Sstevel@tonic-gate 		} else {
375*7c478bd9Sstevel@tonic-gate 			tmp_sum -= end - tmp->begin;
376*7c478bd9Sstevel@tonic-gate 			tmp->begin = end;
377*7c478bd9Sstevel@tonic-gate 			break;
378*7c478bd9Sstevel@tonic-gate 		}
379*7c478bd9Sstevel@tonic-gate 	}
380*7c478bd9Sstevel@tonic-gate 	*sum = tmp_sum;
381*7c478bd9Sstevel@tonic-gate }
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate /*
385*7c478bd9Sstevel@tonic-gate  * To update the notsack'ed list when new data is sent.
386*7c478bd9Sstevel@tonic-gate  *
387*7c478bd9Sstevel@tonic-gate  * Assumption: this should only be called when new notsack blk is to be added.
388*7c478bd9Sstevel@tonic-gate  *
389*7c478bd9Sstevel@tonic-gate  * Parameters:
390*7c478bd9Sstevel@tonic-gate  *	notsack_blk_t **head: address of the pointer to the list of notsack'ed
391*7c478bd9Sstevel@tonic-gate  *		blks.
392*7c478bd9Sstevel@tonic-gate  *	tcp_seq begin: beginning seq num of new data.
393*7c478bd9Sstevel@tonic-gate  *	tcp_seq end: ending seq num of new data.
394*7c478bd9Sstevel@tonic-gate  *	int32_t *num: (referenced) total num of notsack'ed blks.
395*7c478bd9Sstevel@tonic-gate  *	uint32_t *sum: (referenced) total num of bytes of all the notsack'ed
396*7c478bd9Sstevel@tonic-gate  *		blks.
397*7c478bd9Sstevel@tonic-gate  */
tcp_notsack_update(notsack_blk_t ** head,tcp_seq begin,tcp_seq end,int32_t * num,uint32_t * sum)398*7c478bd9Sstevel@tonic-gate void tcp_notsack_update(notsack_blk_t **head, tcp_seq begin, tcp_seq end,
399*7c478bd9Sstevel@tonic-gate     int32_t *num, uint32_t *sum)
400*7c478bd9Sstevel@tonic-gate {
401*7c478bd9Sstevel@tonic-gate 	notsack_blk_t *tmp;
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 	tmp = *head;
404*7c478bd9Sstevel@tonic-gate 	/* If the list is empty, create a new one. */
405*7c478bd9Sstevel@tonic-gate 	if (tmp == NULL) {
406*7c478bd9Sstevel@tonic-gate 		if ((tmp = (notsack_blk_t *)bkmem_alloc(
407*7c478bd9Sstevel@tonic-gate 		    sizeof (notsack_blk_t))) == NULL) {
408*7c478bd9Sstevel@tonic-gate 			return;
409*7c478bd9Sstevel@tonic-gate 		}
410*7c478bd9Sstevel@tonic-gate 		tmp->begin = begin;
411*7c478bd9Sstevel@tonic-gate 		tmp->end = end;
412*7c478bd9Sstevel@tonic-gate 		tmp->next = NULL;
413*7c478bd9Sstevel@tonic-gate 		tmp->sack_cnt = 0;
414*7c478bd9Sstevel@tonic-gate 		*head = tmp;
415*7c478bd9Sstevel@tonic-gate 		*num = 1;
416*7c478bd9Sstevel@tonic-gate 		*sum = end - begin;
417*7c478bd9Sstevel@tonic-gate 		return;
418*7c478bd9Sstevel@tonic-gate 	}
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	/*
421*7c478bd9Sstevel@tonic-gate 	 * Find the place to add the new blk.  This assumes that new data
422*7c478bd9Sstevel@tonic-gate 	 * is being sent, so the place to insert the new notsack blk is at
423*7c478bd9Sstevel@tonic-gate 	 * the end of the list.
424*7c478bd9Sstevel@tonic-gate 	 */
425*7c478bd9Sstevel@tonic-gate 	while (tmp->next != NULL) {
426*7c478bd9Sstevel@tonic-gate 		tmp = tmp->next;
427*7c478bd9Sstevel@tonic-gate 	}
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	/* Does the new blk overlap with old one? */
430*7c478bd9Sstevel@tonic-gate 	if (SEQ_GEQ(tmp->end, begin)) {
431*7c478bd9Sstevel@tonic-gate 		*sum += end - tmp->end;
432*7c478bd9Sstevel@tonic-gate 		tmp->end = end;
433*7c478bd9Sstevel@tonic-gate 	} else {
434*7c478bd9Sstevel@tonic-gate 		/* No.  Need to create a new notsack blk. */
435*7c478bd9Sstevel@tonic-gate 		tmp->next = (notsack_blk_t *)bkmem_alloc(
436*7c478bd9Sstevel@tonic-gate 		    sizeof (notsack_blk_t));
437*7c478bd9Sstevel@tonic-gate 		if (tmp->next != NULL) {
438*7c478bd9Sstevel@tonic-gate 			tmp = tmp->next;
439*7c478bd9Sstevel@tonic-gate 			tmp->begin = begin;
440*7c478bd9Sstevel@tonic-gate 			tmp->end = end;
441*7c478bd9Sstevel@tonic-gate 			tmp->next = NULL;
442*7c478bd9Sstevel@tonic-gate 			tmp->sack_cnt = 0;
443*7c478bd9Sstevel@tonic-gate 			(*num)++;
444*7c478bd9Sstevel@tonic-gate 			*sum += end - begin;
445*7c478bd9Sstevel@tonic-gate 		}
446*7c478bd9Sstevel@tonic-gate 	}
447*7c478bd9Sstevel@tonic-gate }
448