4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 1997-2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 /* Modified to be used by inetboot. */
31 #include <sys/types.h>
32 #include <socket_impl.h>
33 #include <sys/debug.h>
34 #include <netinet/tcp.h>
35 #include <sys/systm.h>
36 #include <sys/stropts.h>
37 #include <netinet/in.h>
38 #include <netinet/ip6.h>
39 #include <inet/common.h>
40 #include <sys/salib.h>
41 #include <sys/socket.h>
47 * To insert a new blk to the array of SACK blk in receiver.
50 * sack_blk_t *head: pointer to the array of SACK blks.
51 * tcp_seq begin: starting seq num of the new blk.
52 * tcp_seq end: ending seq num of the new blk.
53 * int32_t *num: (referenced) total num of SACK blks on the list.
56 tcp_sack_insert(sack_blk_t
*head
, tcp_seq begin
, tcp_seq end
, int32_t *num
)
58 int32_t i
, j
, old_num
, new_num
;
59 sack_blk_t tmp
[MAX_SACK_BLK
- 1];
61 /* The array is empty, just add the new one. */
63 head
[0].begin
= begin
;
70 * Check for overlap. There are five cases.
72 * 1. there is no overlap with any other SACK blks.
73 * 2. new SACK blk is completely contained in another blk.
74 * 3. tail part of new SACK blk overlaps with another blk.
75 * 4. head part of new SACK blk overlaps with another blk.
76 * 5. new SACK blk completely contains another blk.
78 * Use tmp to hold old SACK blks. After the loop, copy them back
82 if (old_num
> MAX_SACK_BLK
- 1) {
83 old_num
= MAX_SACK_BLK
- 1;
87 for (i
= 0; i
< old_num
; i
++) {
88 if (SEQ_LT(end
, head
[i
].begin
) || SEQ_GT(begin
, head
[i
].end
)) {
89 /* Case 1: continue to check. */
90 tmp
[j
].begin
= head
[i
].begin
;
91 tmp
[j
].end
= head
[i
].end
;
94 } else if (SEQ_GEQ(begin
, head
[i
].begin
) &&
95 SEQ_LEQ(end
, head
[i
].end
)) {
96 /* Case 2: re-insert the old blk to the head. */
97 begin
= head
[i
].begin
;
99 } else if (SEQ_LEQ(end
, head
[i
].end
) &&
100 SEQ_GEQ(end
, head
[i
].begin
)) {
102 * Case 3: Extend the new blk, remove the old one
103 * and continue to check.
106 } else if (SEQ_GEQ(begin
, head
[i
].begin
) &&
107 SEQ_LEQ(begin
, head
[i
].end
)) {
109 begin
= head
[i
].begin
;
112 * Common code for all cases except the first one, which
113 * copies the original SACK blk into the tmp storage. Other
114 * cases remove the original SACK blk by not copying into
120 head
[0].begin
= begin
;
122 for (i
= 0; i
< new_num
; i
++) {
123 head
[i
+1].begin
= tmp
[i
].begin
;
124 head
[i
+1].end
= tmp
[i
].end
;
131 * To remove a SACK block.
134 * sack_blk_t *head: pointer to the array of SACK blks.
135 * tcp_seq end: to remove all sack blk with seq num less than end.
136 * int32_t *num: (referenced) total num of SACK blks in the array.
139 tcp_sack_remove(sack_blk_t
*head
, tcp_seq end
, int32_t *num
)
141 sack_blk_t tmp
[MAX_SACK_BLK
];
142 int32_t i
, j
, old_num
, new_num
;
150 /* Walk thru the whole list and copy the new list to tmp[]. */
151 for (i
= 0; i
< old_num
; i
++) {
152 if (SEQ_GT(end
, head
[i
].begin
)) {
154 * Check to see if the old SACK blk needs to be
155 * removed or updated. If the old blk is just
156 * partially covered, update begin and continue.
157 * If the old blk is completely covered, remove it
158 * and continue to check.
160 if (SEQ_GEQ(end
, head
[i
].end
)) {
165 tmp
[j
].end
= head
[i
].end
;
168 tmp
[j
].begin
= head
[i
].begin
;
169 tmp
[j
].end
= head
[i
].end
;
173 /* Copy tmp[] back to the original list. */
174 for (i
= 0; i
< new_num
; i
++) {
175 head
[i
].begin
= tmp
[i
].begin
;
176 head
[i
].end
= tmp
[i
].end
;
183 * Use the SACK info to insert a "notsack'ed" blk. The notsack'ed blk list
184 * contains the list of blks which have not been selectively acknowledged
185 * by the receiver. The SACK info is a blk which is being selectively
186 * acknowledged by the receiver.
189 * notsack_blk_t **head: address of the pointer to the list of notsack'ed
191 * tcp_seq begin: starting seq num of the SACK info.
192 * tcp_seq end: ending seq num of the SACK info.
193 * int32_t *num: (referenced) total num of notsack'ed blk on the list.
194 * uint32_t *sum: (referenced) total num of bytes of all the notsack'ed
198 tcp_notsack_insert(notsack_blk_t
**head
, tcp_seq begin
, tcp_seq end
,
199 int32_t *num
, uint32_t *sum
)
201 notsack_blk_t
*prev
, *tmp
, *new;
202 uint32_t tmp_sum
, tmp_num
;
210 /* Find the right place of updating the list. */
211 while ((tmp
!= NULL
) && SEQ_LEQ(tmp
->end
, begin
)) {
218 * This can happen only when TCP sends new data but the notsack list
226 * This means the new SACK info covers something that is not on
229 if (SEQ_LEQ(end
, tmp
->begin
)) {
233 /* The SACK info covers up to this blk. So just check for this blk. */
234 if (SEQ_LEQ(end
, tmp
->end
)) {
236 * Only this notsack'ed blk is completely covered. Delete
239 if (end
== tmp
->end
&& SEQ_LEQ(begin
, tmp
->begin
)) {
241 prev
->next
= tmp
->next
;
246 *sum
-= tmp
->end
- tmp
->begin
;
247 bkmem_free(tmp
, sizeof (notsack_blk_t
));
250 /* This blk is partially covered. */
251 if (SEQ_GEQ(begin
, tmp
->begin
)) {
252 /* Check what needs to be updated. */
253 if (begin
== tmp
->begin
) {
254 *sum
-= end
- tmp
->begin
;
256 } else if (end
== tmp
->end
) {
257 *sum
-= tmp
->end
- begin
;
261 /* Split the notsack blk. */
262 if ((new = (notsack_blk_t
*)bkmem_alloc(
263 sizeof (notsack_blk_t
))) == NULL
) {
268 new->next
= tmp
->next
;
277 *sum
-= end
- tmp
->begin
;
283 /* Need to check for coverage of this blk and later blks. */
286 if (SEQ_LT(tmp
->begin
, begin
)) {
287 tmp_sum
-= tmp
->end
- begin
;
294 while (tmp
!= NULL
) {
295 /* The coverage stops here. */
296 if (SEQ_GT(tmp
->begin
, end
)) {
299 /* Is the blk completely or partially covered? */
300 if (SEQ_LEQ(tmp
->end
, end
)) {
302 tmp_sum
-= tmp
->end
- tmp
->begin
;
304 prev
->next
= tmp
->next
;
305 bkmem_free((caddr_t
)tmp
,
306 sizeof (notsack_blk_t
));
310 bkmem_free((caddr_t
)tmp
,
311 sizeof (notsack_blk_t
));
316 * This blk is partially covered. It also
317 * means it should be the end of coverage.
319 tmp_sum
-= end
- tmp
->begin
;
331 * To remove notsack'ed blks.
334 * notsack_blk_t **head: address of the pointer to the list of notsack'ed
336 * tcp_seq end: to remove all notsack'ed blk with seq num less than end.
337 * int32_t *num: (referenced) total num of notsack'ed blks.
338 * uint32_t *sum: (referenced) total num of bytes of all the notsack'ed
342 tcp_notsack_remove(notsack_blk_t
**head
, tcp_seq end
, int32_t *num
,
345 notsack_blk_t
*prev
, *tmp
;
346 uint32_t tmp_sum
= *sum
;
353 while (tmp
!= NULL
) {
354 /* There is nothing to discard. */
355 if (SEQ_GT(tmp
->begin
, end
)) {
359 /* Is the blk completely or partially covered? */
360 if (SEQ_GEQ(end
, tmp
->end
)) {
362 tmp_sum
-= tmp
->end
- tmp
->begin
;
365 bkmem_free((caddr_t
)tmp
,
366 sizeof (notsack_blk_t
));
369 prev
->next
= tmp
->next
;
370 bkmem_free((caddr_t
)tmp
,
371 sizeof (notsack_blk_t
));
375 tmp_sum
-= end
- tmp
->begin
;
385 * To update the notsack'ed list when new data is sent.
387 * Assumption: this should only be called when new notsack blk is to be added.
390 * notsack_blk_t **head: address of the pointer to the list of notsack'ed
392 * tcp_seq begin: beginning seq num of new data.
393 * tcp_seq end: ending seq num of new data.
394 * int32_t *num: (referenced) total num of notsack'ed blks.
395 * uint32_t *sum: (referenced) total num of bytes of all the notsack'ed
398 void tcp_notsack_update(notsack_blk_t
**head
, tcp_seq begin
, tcp_seq end
,
399 int32_t *num
, uint32_t *sum
)
404 /* If the list is empty, create a new one. */
406 if ((tmp
= (notsack_blk_t
*)bkmem_alloc(
407 sizeof (notsack_blk_t
))) == NULL
) {
421 * Find the place to add the new blk. This assumes that new data
422 * is being sent, so the place to insert the new notsack blk is at
423 * the end of the list.
425 while (tmp
->next
!= NULL
) {
429 /* Does the new blk overlap with old one? */
430 if (SEQ_GEQ(tmp
->end
, begin
)) {
431 *sum
+= end
- tmp
->end
;
434 /* No. Need to create a new notsack blk. */
435 tmp
->next
= (notsack_blk_t
*)bkmem_alloc(
436 sizeof (notsack_blk_t
));
437 if (tmp
->next
!= NULL
) {