4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/types.h>
27 #include <sys/debug.h>
28 #include <netinet/tcp.h>
29 #include <sys/systm.h>
30 #include <sys/stropts.h>
31 #include <netinet/in.h>
32 #include <netinet/ip6.h>
33 #include <inet/common.h>
37 /* kmem cache for notsack_blk_t */
38 kmem_cache_t
*tcp_notsack_blk_cache
;
41 * To insert a new blk to the array of SACK blk in receiver.
44 * sack_blk_t *head: pointer to the array of SACK blks.
45 * tcp_seq begin: starting seq num of the new blk.
46 * tcp_seq end: ending seq num of the new blk.
47 * int32_t *num: (referenced) total num of SACK blks on the list.
50 tcp_sack_insert(sack_blk_t
*head
, tcp_seq begin
, tcp_seq end
, int32_t *num
)
52 int32_t i
, j
, old_num
, new_num
;
53 sack_blk_t tmp
[MAX_SACK_BLK
- 1];
55 /* The array is empty, just add the new one. */
57 head
[0].begin
= begin
;
64 * Check for overlap. There are five cases.
66 * 1. there is no overlap with any other SACK blks.
67 * 2. new SACK blk is completely contained in another blk.
68 * 3. tail part of new SACK blk overlaps with another blk.
69 * 4. head part of new SACK blk overlaps with another blk.
70 * 5. new SACK blk completely contains another blk.
72 * Use tmp to hold old SACK blks. After the loop, copy them back
76 if (old_num
> MAX_SACK_BLK
- 1) {
77 old_num
= MAX_SACK_BLK
- 1;
81 for (i
= 0; i
< old_num
; i
++) {
82 if (SEQ_LT(end
, head
[i
].begin
) || SEQ_GT(begin
, head
[i
].end
)) {
83 /* Case 1: continue to check. */
84 tmp
[j
].begin
= head
[i
].begin
;
85 tmp
[j
].end
= head
[i
].end
;
88 } else if (SEQ_GEQ(begin
, head
[i
].begin
) &&
89 SEQ_LEQ(end
, head
[i
].end
)) {
90 /* Case 2: re-insert the old blk to the head. */
91 begin
= head
[i
].begin
;
93 } else if (SEQ_LEQ(end
, head
[i
].end
) &&
94 SEQ_GEQ(end
, head
[i
].begin
)) {
96 * Case 3: Extend the new blk, remove the old one
97 * and continue to check.
100 } else if (SEQ_GEQ(begin
, head
[i
].begin
) &&
101 SEQ_LEQ(begin
, head
[i
].end
)) {
103 begin
= head
[i
].begin
;
106 * Common code for all cases except the first one, which
107 * copies the original SACK blk into the tmp storage. Other
108 * cases remove the original SACK blk by not copying into
114 head
[0].begin
= begin
;
116 for (i
= 0; i
< new_num
; i
++) {
117 head
[i
+1].begin
= tmp
[i
].begin
;
118 head
[i
+1].end
= tmp
[i
].end
;
125 * To remove a SACK block.
128 * sack_blk_t *head: pointer to the array of SACK blks.
129 * tcp_seq end: to remove all sack blk with seq num less than end.
130 * int32_t *num: (referenced) total num of SACK blks in the array.
133 tcp_sack_remove(sack_blk_t
*head
, tcp_seq end
, int32_t *num
)
135 sack_blk_t tmp
[MAX_SACK_BLK
];
136 int32_t i
, j
, old_num
, new_num
;
144 /* Walk thru the whole list and copy the new list to tmp[]. */
145 for (i
= 0; i
< old_num
; i
++) {
146 if (SEQ_GT(end
, head
[i
].begin
)) {
148 * Check to see if the old SACK blk needs to be
149 * removed or updated. If the old blk is just
150 * partially covered, update begin and continue.
151 * If the old blk is completely covered, remove it
152 * and continue to check.
154 if (SEQ_GEQ(end
, head
[i
].end
)) {
159 tmp
[j
].end
= head
[i
].end
;
162 tmp
[j
].begin
= head
[i
].begin
;
163 tmp
[j
].end
= head
[i
].end
;
167 /* Copy tmp[] back to the original list. */
168 for (i
= 0; i
< new_num
; i
++) {
169 head
[i
].begin
= tmp
[i
].begin
;
170 head
[i
].end
= tmp
[i
].end
;
177 * Use the SACK info to insert a "notsack'ed" blk. The notsack'ed blk list
178 * contains the list of blks which have not been selectively acknowledged
179 * by the receiver. The SACK info is a blk which is being selectively
180 * acknowledged by the receiver.
183 * notsack_blk_t **head: address of the pointer to the list of notsack'ed
185 * tcp_seq begin: starting seq num of the SACK info.
186 * tcp_seq end: ending seq num of the SACK info.
187 * int32_t *num: (referenced) total num of notsack'ed blk on the list.
188 * uint32_t *sum: (referenced) total num of bytes of all the notsack'ed
192 tcp_notsack_insert(notsack_blk_t
**head
, tcp_seq begin
, tcp_seq end
,
193 int32_t *num
, uint32_t *sum
)
195 notsack_blk_t
*prev
, *tmp
, *new;
196 uint32_t tmp_sum
, tmp_num
;
204 /* Find the right place of updating the list. */
205 while ((tmp
!= NULL
) && SEQ_LEQ(tmp
->end
, begin
)) {
212 * This can happen only when TCP sends new data but the notsack list
220 * This means the new SACK info covers something that is not on
223 if (SEQ_LEQ(end
, tmp
->begin
)) {
227 /* The SACK info covers up to this blk. So just check for this blk. */
228 if (SEQ_LEQ(end
, tmp
->end
)) {
230 * Only this notsack'ed blk is completely covered. Delete
233 if (end
== tmp
->end
&& SEQ_LEQ(begin
, tmp
->begin
)) {
235 prev
->next
= tmp
->next
;
240 *sum
-= tmp
->end
- tmp
->begin
;
241 kmem_cache_free(tcp_notsack_blk_cache
, tmp
);
244 /* This blk is partially covered. */
245 if (SEQ_GEQ(begin
, tmp
->begin
)) {
246 /* Check what needs to be updated. */
247 if (begin
== tmp
->begin
) {
248 *sum
-= end
- tmp
->begin
;
250 } else if (end
== tmp
->end
) {
251 *sum
-= tmp
->end
- begin
;
255 /* Split the notsack blk. */
256 if ((new = kmem_cache_alloc(
257 tcp_notsack_blk_cache
, KM_NOSLEEP
)) ==
263 new->next
= tmp
->next
;
272 *sum
-= end
- tmp
->begin
;
278 /* Need to check for coverage of this blk and later blks. */
281 if (SEQ_LT(tmp
->begin
, begin
)) {
282 tmp_sum
-= tmp
->end
- begin
;
289 while (tmp
!= NULL
) {
290 /* The coverage stops here. */
291 if (SEQ_GT(tmp
->begin
, end
)) {
294 /* Is the blk completely or partially covered? */
295 if (SEQ_LEQ(tmp
->end
, end
)) {
297 tmp_sum
-= tmp
->end
- tmp
->begin
;
299 prev
->next
= tmp
->next
;
300 kmem_cache_free(tcp_notsack_blk_cache
,
305 kmem_cache_free(tcp_notsack_blk_cache
,
311 * This blk is partially covered. It also
312 * means it should be the end of coverage.
314 tmp_sum
-= end
- tmp
->begin
;
326 * To remove notsack'ed blks.
329 * notsack_blk_t **head: address of the pointer to the list of notsack'ed
331 * tcp_seq end: to remove all notsack'ed blk with seq num less than end.
332 * int32_t *num: (referenced) total num of notsack'ed blks.
333 * uint32_t *sum: (referenced) total num of bytes of all the notsack'ed
337 tcp_notsack_remove(notsack_blk_t
**head
, tcp_seq end
, int32_t *num
,
340 notsack_blk_t
*prev
, *tmp
;
341 uint32_t tmp_sum
= *sum
;
348 while (tmp
!= NULL
) {
349 /* There is nothing to discard. */
350 if (SEQ_GT(tmp
->begin
, end
)) {
354 /* Is the blk completely or partially covered? */
355 if (SEQ_GEQ(end
, tmp
->end
)) {
357 tmp_sum
-= tmp
->end
- tmp
->begin
;
360 kmem_cache_free(tcp_notsack_blk_cache
, tmp
);
363 prev
->next
= tmp
->next
;
364 kmem_cache_free(tcp_notsack_blk_cache
, tmp
);
368 tmp_sum
-= end
- tmp
->begin
;
378 * To update the notsack'ed list when new data is sent.
380 * Assumption: this should only be called when new notsack blk is to be added.
383 * notsack_blk_t **head: address of the pointer to the list of notsack'ed
385 * tcp_seq begin: beginning seq num of new data.
386 * tcp_seq end: ending seq num of new data.
387 * int32_t *num: (referenced) total num of notsack'ed blks.
388 * uint32_t *sum: (referenced) total num of bytes of all the notsack'ed
391 void tcp_notsack_update(notsack_blk_t
**head
, tcp_seq begin
, tcp_seq end
,
392 int32_t *num
, uint32_t *sum
)
397 /* If the list is empty, create a new one. */
399 if ((tmp
= kmem_cache_alloc(tcp_notsack_blk_cache
,
400 KM_NOSLEEP
)) == NULL
) {
414 * Find the place to add the new blk. This assumes that new data
415 * is being sent, so the place to insert the new notsack blk is at
416 * the end of the list.
418 while (tmp
->next
!= NULL
) {
422 /* Does the new blk overlap with old one? */
423 if (SEQ_GEQ(tmp
->end
, begin
)) {
424 *sum
+= end
- tmp
->end
;
427 /* No. Need to create a new notsack blk. */
428 tmp
->next
= kmem_cache_alloc(tcp_notsack_blk_cache
, KM_NOSLEEP
);
429 if (tmp
->next
!= NULL
) {