1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2010-2012, by Michael Tuexen. All rights reserved.
5 * Copyright (c) 2010-2012, by Randall Stewart. All rights reserved.
6 * Copyright (c) 2010-2012, by Robin Seggelmann. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * a) Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 *
14 * b) Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <netinet/sctp_pcb.h>
35
36 /*
37 * Default simple round-robin algorithm.
38 * Just interates the streams in the order they appear.
39 */
40
41 static void
42 sctp_ss_default_add(struct sctp_tcb *, struct sctp_association *,
43 struct sctp_stream_out *,
44 struct sctp_stream_queue_pending *, int);
45
46 static void
47 sctp_ss_default_remove(struct sctp_tcb *, struct sctp_association *,
48 struct sctp_stream_out *,
49 struct sctp_stream_queue_pending *, int);
50
51 static void
sctp_ss_default_init(struct sctp_tcb * stcb,struct sctp_association * asoc,int holds_lock)52 sctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
53 int holds_lock)
54 {
55 uint16_t i;
56
57 if (holds_lock == 0) {
58 SCTP_TCB_SEND_LOCK(stcb);
59 }
60 asoc->ss_data.locked_on_sending = NULL;
61 asoc->ss_data.last_out_stream = NULL;
62 TAILQ_INIT(&asoc->ss_data.out.wheel);
63 /*
64 * If there is data in the stream queues already, the scheduler of
65 * an existing association has been changed. We need to add all
66 * stream queues to the wheel.
67 */
68 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
69 stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, &stcb->asoc,
70 &stcb->asoc.strmout[i],
71 NULL, 1);
72 }
73 if (holds_lock == 0) {
74 SCTP_TCB_SEND_UNLOCK(stcb);
75 }
76 return;
77 }
78
79 static void
sctp_ss_default_clear(struct sctp_tcb * stcb,struct sctp_association * asoc,int clear_values SCTP_UNUSED,int holds_lock)80 sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
81 int clear_values SCTP_UNUSED, int holds_lock)
82 {
83 if (holds_lock == 0) {
84 SCTP_TCB_SEND_LOCK(stcb);
85 }
86 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
87 struct sctp_stream_out *strq;
88
89 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
90 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
91 strq->ss_params.rr.next_spoke.tqe_next = NULL;
92 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
93 }
94 asoc->ss_data.last_out_stream = NULL;
95 if (holds_lock == 0) {
96 SCTP_TCB_SEND_UNLOCK(stcb);
97 }
98 return;
99 }
100
101 static void
sctp_ss_default_init_stream(struct sctp_tcb * stcb,struct sctp_stream_out * strq,struct sctp_stream_out * with_strq)102 sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
103 {
104 if (with_strq != NULL) {
105 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
106 stcb->asoc.ss_data.locked_on_sending = strq;
107 }
108 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
109 stcb->asoc.ss_data.last_out_stream = strq;
110 }
111 }
112 strq->ss_params.rr.next_spoke.tqe_next = NULL;
113 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
114 return;
115 }
116
117 static void
sctp_ss_default_add(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_stream_out * strq,struct sctp_stream_queue_pending * sp SCTP_UNUSED,int holds_lock)118 sctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
119 struct sctp_stream_out *strq,
120 struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock)
121 {
122 if (holds_lock == 0) {
123 SCTP_TCB_SEND_LOCK(stcb);
124 }
125 /* Add to wheel if not already on it and stream queue not empty */
126 if (!TAILQ_EMPTY(&strq->outqueue) &&
127 (strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
128 (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
129 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel,
130 strq, ss_params.rr.next_spoke);
131 }
132 if (holds_lock == 0) {
133 SCTP_TCB_SEND_UNLOCK(stcb);
134 }
135 return;
136 }
137
138 static int
sctp_ss_default_is_empty(struct sctp_tcb * stcb SCTP_UNUSED,struct sctp_association * asoc)139 sctp_ss_default_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
140 {
141 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
142 return (1);
143 } else {
144 return (0);
145 }
146 }
147
148 static void
sctp_ss_default_remove(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_stream_out * strq,struct sctp_stream_queue_pending * sp SCTP_UNUSED,int holds_lock)149 sctp_ss_default_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
150 struct sctp_stream_out *strq,
151 struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock)
152 {
153 if (holds_lock == 0) {
154 SCTP_TCB_SEND_LOCK(stcb);
155 }
156 /*
157 * Remove from wheel if stream queue is empty and actually is on the
158 * wheel
159 */
160 if (TAILQ_EMPTY(&strq->outqueue) &&
161 (strq->ss_params.rr.next_spoke.tqe_next != NULL ||
162 strq->ss_params.rr.next_spoke.tqe_prev != NULL)) {
163 if (asoc->ss_data.last_out_stream == strq) {
164 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream,
165 sctpwheel_listhead,
166 ss_params.rr.next_spoke);
167 if (asoc->ss_data.last_out_stream == NULL) {
168 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
169 sctpwheel_listhead);
170 }
171 if (asoc->ss_data.last_out_stream == strq) {
172 asoc->ss_data.last_out_stream = NULL;
173 }
174 }
175 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
176 strq->ss_params.rr.next_spoke.tqe_next = NULL;
177 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
178 }
179 if (holds_lock == 0) {
180 SCTP_TCB_SEND_UNLOCK(stcb);
181 }
182 return;
183 }
184
185 static struct sctp_stream_out *
sctp_ss_default_select(struct sctp_tcb * stcb SCTP_UNUSED,struct sctp_nets * net,struct sctp_association * asoc)186 sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
187 struct sctp_association *asoc)
188 {
189 struct sctp_stream_out *strq, *strqt;
190
191 if (asoc->ss_data.locked_on_sending) {
192 return (asoc->ss_data.locked_on_sending);
193 }
194 strqt = asoc->ss_data.last_out_stream;
195 default_again:
196 /* Find the next stream to use */
197 if (strqt == NULL) {
198 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
199 } else {
200 strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
201 if (strq == NULL) {
202 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
203 }
204 }
205
206 /*
207 * If CMT is off, we must validate that the stream in question has
208 * the first item pointed towards are network destination requested
209 * by the caller. Note that if we turn out to be locked to a stream
210 * (assigning TSN's then we must stop, since we cannot look for
211 * another stream with data to send to that destination). In CMT's
212 * case, by skipping this check, we will send one data packet
213 * towards the requested net.
214 */
215 if (net != NULL && strq != NULL &&
216 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
217 if (TAILQ_FIRST(&strq->outqueue) &&
218 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
219 TAILQ_FIRST(&strq->outqueue)->net != net) {
220 if (strq == asoc->ss_data.last_out_stream) {
221 return (NULL);
222 } else {
223 strqt = strq;
224 goto default_again;
225 }
226 }
227 }
228 return (strq);
229 }
230
231 static void
sctp_ss_default_scheduled(struct sctp_tcb * stcb,struct sctp_nets * net SCTP_UNUSED,struct sctp_association * asoc,struct sctp_stream_out * strq,int moved_how_much SCTP_UNUSED)232 sctp_ss_default_scheduled(struct sctp_tcb *stcb,
233 struct sctp_nets *net SCTP_UNUSED,
234 struct sctp_association *asoc,
235 struct sctp_stream_out *strq,
236 int moved_how_much SCTP_UNUSED)
237 {
238 struct sctp_stream_queue_pending *sp;
239
240 asoc->ss_data.last_out_stream = strq;
241 if (stcb->asoc.idata_supported == 0) {
242 sp = TAILQ_FIRST(&strq->outqueue);
243 if ((sp != NULL) && (sp->some_taken == 1)) {
244 stcb->asoc.ss_data.locked_on_sending = strq;
245 } else {
246 stcb->asoc.ss_data.locked_on_sending = NULL;
247 }
248 } else {
249 stcb->asoc.ss_data.locked_on_sending = NULL;
250 }
251 return;
252 }
253
254 static void
sctp_ss_default_packet_done(struct sctp_tcb * stcb SCTP_UNUSED,struct sctp_nets * net SCTP_UNUSED,struct sctp_association * asoc SCTP_UNUSED)255 sctp_ss_default_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
256 struct sctp_association *asoc SCTP_UNUSED)
257 {
258 /* Nothing to be done here */
259 return;
260 }
261
262 static int
sctp_ss_default_get_value(struct sctp_tcb * stcb SCTP_UNUSED,struct sctp_association * asoc SCTP_UNUSED,struct sctp_stream_out * strq SCTP_UNUSED,uint16_t * value SCTP_UNUSED)263 sctp_ss_default_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
264 struct sctp_stream_out *strq SCTP_UNUSED, uint16_t *value SCTP_UNUSED)
265 {
266 /* Nothing to be done here */
267 return (-1);
268 }
269
270 static int
sctp_ss_default_set_value(struct sctp_tcb * stcb SCTP_UNUSED,struct sctp_association * asoc SCTP_UNUSED,struct sctp_stream_out * strq SCTP_UNUSED,uint16_t value SCTP_UNUSED)271 sctp_ss_default_set_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
272 struct sctp_stream_out *strq SCTP_UNUSED, uint16_t value SCTP_UNUSED)
273 {
274 /* Nothing to be done here */
275 return (-1);
276 }
277
278 static int
sctp_ss_default_is_user_msgs_incomplete(struct sctp_tcb * stcb SCTP_UNUSED,struct sctp_association * asoc)279 sctp_ss_default_is_user_msgs_incomplete(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
280 {
281 struct sctp_stream_out *strq;
282 struct sctp_stream_queue_pending *sp;
283
284 if (asoc->stream_queue_cnt != 1) {
285 return (0);
286 }
287 strq = asoc->ss_data.locked_on_sending;
288 if (strq == NULL) {
289 return (0);
290 }
291 sp = TAILQ_FIRST(&strq->outqueue);
292 if (sp == NULL) {
293 return (0);
294 }
295 return (!sp->msg_is_complete);
296 }
297
298 /*
299 * Real round-robin algorithm.
300 * Always interates the streams in ascending order.
301 */
302 static void
sctp_ss_rr_add(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_stream_out * strq,struct sctp_stream_queue_pending * sp SCTP_UNUSED,int holds_lock)303 sctp_ss_rr_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
304 struct sctp_stream_out *strq,
305 struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock)
306 {
307 struct sctp_stream_out *strqt;
308
309 if (holds_lock == 0) {
310 SCTP_TCB_SEND_LOCK(stcb);
311 }
312 if (!TAILQ_EMPTY(&strq->outqueue) &&
313 (strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
314 (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
315 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
316 TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
317 } else {
318 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
319 while (strqt != NULL && (strqt->sid < strq->sid)) {
320 strqt = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
321 }
322 if (strqt != NULL) {
323 TAILQ_INSERT_BEFORE(strqt, strq, ss_params.rr.next_spoke);
324 } else {
325 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
326 }
327 }
328 }
329 if (holds_lock == 0) {
330 SCTP_TCB_SEND_UNLOCK(stcb);
331 }
332 return;
333 }
334
335 /*
336 * Real round-robin per packet algorithm.
337 * Always interates the streams in ascending order and
338 * only fills messages of the same stream in a packet.
339 */
340 static struct sctp_stream_out *
sctp_ss_rrp_select(struct sctp_tcb * stcb SCTP_UNUSED,struct sctp_nets * net SCTP_UNUSED,struct sctp_association * asoc)341 sctp_ss_rrp_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
342 struct sctp_association *asoc)
343 {
344 return (asoc->ss_data.last_out_stream);
345 }
346
347 static void
sctp_ss_rrp_packet_done(struct sctp_tcb * stcb SCTP_UNUSED,struct sctp_nets * net,struct sctp_association * asoc)348 sctp_ss_rrp_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
349 struct sctp_association *asoc)
350 {
351 struct sctp_stream_out *strq, *strqt;
352
353 strqt = asoc->ss_data.last_out_stream;
354 rrp_again:
355 /* Find the next stream to use */
356 if (strqt == NULL) {
357 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
358 } else {
359 strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
360 if (strq == NULL) {
361 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
362 }
363 }
364
365 /*
366 * If CMT is off, we must validate that the stream in question has
367 * the first item pointed towards are network destination requested
368 * by the caller. Note that if we turn out to be locked to a stream
369 * (assigning TSN's then we must stop, since we cannot look for
370 * another stream with data to send to that destination). In CMT's
371 * case, by skipping this check, we will send one data packet
372 * towards the requested net.
373 */
374 if (net != NULL && strq != NULL &&
375 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
376 if (TAILQ_FIRST(&strq->outqueue) &&
377 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
378 TAILQ_FIRST(&strq->outqueue)->net != net) {
379 if (strq == asoc->ss_data.last_out_stream) {
380 strq = NULL;
381 } else {
382 strqt = strq;
383 goto rrp_again;
384 }
385 }
386 }
387 asoc->ss_data.last_out_stream = strq;
388 return;
389 }
390
391 /*
392 * Priority algorithm.
393 * Always prefers streams based on their priority id.
394 */
395 static void
sctp_ss_prio_clear(struct sctp_tcb * stcb,struct sctp_association * asoc,int clear_values,int holds_lock)396 sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
397 int clear_values, int holds_lock)
398 {
399 if (holds_lock == 0) {
400 SCTP_TCB_SEND_LOCK(stcb);
401 }
402 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
403 struct sctp_stream_out *strq;
404
405 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
406 if (clear_values) {
407 strq->ss_params.prio.priority = 0;
408 }
409 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
410 strq->ss_params.prio.next_spoke.tqe_next = NULL;
411 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
412 }
413 asoc->ss_data.last_out_stream = NULL;
414 if (holds_lock == 0) {
415 SCTP_TCB_SEND_UNLOCK(stcb);
416 }
417 return;
418 }
419
420 static void
sctp_ss_prio_init_stream(struct sctp_tcb * stcb,struct sctp_stream_out * strq,struct sctp_stream_out * with_strq)421 sctp_ss_prio_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
422 {
423 if (with_strq != NULL) {
424 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
425 stcb->asoc.ss_data.locked_on_sending = strq;
426 }
427 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
428 stcb->asoc.ss_data.last_out_stream = strq;
429 }
430 }
431 strq->ss_params.prio.next_spoke.tqe_next = NULL;
432 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
433 if (with_strq != NULL) {
434 strq->ss_params.prio.priority = with_strq->ss_params.prio.priority;
435 } else {
436 strq->ss_params.prio.priority = 0;
437 }
438 return;
439 }
440
441 static void
sctp_ss_prio_add(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_stream_out * strq,struct sctp_stream_queue_pending * sp SCTP_UNUSED,int holds_lock)442 sctp_ss_prio_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
443 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
444 int holds_lock)
445 {
446 struct sctp_stream_out *strqt;
447
448 if (holds_lock == 0) {
449 SCTP_TCB_SEND_LOCK(stcb);
450 }
451 /* Add to wheel if not already on it and stream queue not empty */
452 if (!TAILQ_EMPTY(&strq->outqueue) &&
453 (strq->ss_params.prio.next_spoke.tqe_next == NULL) &&
454 (strq->ss_params.prio.next_spoke.tqe_prev == NULL)) {
455 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
456 TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
457 } else {
458 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
459 while (strqt != NULL && strqt->ss_params.prio.priority < strq->ss_params.prio.priority) {
460 strqt = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
461 }
462 if (strqt != NULL) {
463 TAILQ_INSERT_BEFORE(strqt, strq, ss_params.prio.next_spoke);
464 } else {
465 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
466 }
467 }
468 }
469 if (holds_lock == 0) {
470 SCTP_TCB_SEND_UNLOCK(stcb);
471 }
472 return;
473 }
474
475 static void
sctp_ss_prio_remove(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_stream_out * strq,struct sctp_stream_queue_pending * sp SCTP_UNUSED,int holds_lock)476 sctp_ss_prio_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
477 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
478 int holds_lock)
479 {
480 if (holds_lock == 0) {
481 SCTP_TCB_SEND_LOCK(stcb);
482 }
483 /*
484 * Remove from wheel if stream queue is empty and actually is on the
485 * wheel
486 */
487 if (TAILQ_EMPTY(&strq->outqueue) &&
488 (strq->ss_params.prio.next_spoke.tqe_next != NULL ||
489 strq->ss_params.prio.next_spoke.tqe_prev != NULL)) {
490 if (asoc->ss_data.last_out_stream == strq) {
491 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead,
492 ss_params.prio.next_spoke);
493 if (asoc->ss_data.last_out_stream == NULL) {
494 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
495 sctpwheel_listhead);
496 }
497 if (asoc->ss_data.last_out_stream == strq) {
498 asoc->ss_data.last_out_stream = NULL;
499 }
500 }
501 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
502 strq->ss_params.prio.next_spoke.tqe_next = NULL;
503 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
504 }
505 if (holds_lock == 0) {
506 SCTP_TCB_SEND_UNLOCK(stcb);
507 }
508 return;
509 }
510
511 static struct sctp_stream_out *
sctp_ss_prio_select(struct sctp_tcb * stcb SCTP_UNUSED,struct sctp_nets * net,struct sctp_association * asoc)512 sctp_ss_prio_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
513 struct sctp_association *asoc)
514 {
515 struct sctp_stream_out *strq, *strqt, *strqn;
516
517 if (asoc->ss_data.locked_on_sending) {
518 return (asoc->ss_data.locked_on_sending);
519 }
520 strqt = asoc->ss_data.last_out_stream;
521 prio_again:
522 /* Find the next stream to use */
523 if (strqt == NULL) {
524 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
525 } else {
526 strqn = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
527 if (strqn != NULL &&
528 strqn->ss_params.prio.priority == strqt->ss_params.prio.priority) {
529 strq = strqn;
530 } else {
531 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
532 }
533 }
534
535 /*
536 * If CMT is off, we must validate that the stream in question has
537 * the first item pointed towards are network destination requested
538 * by the caller. Note that if we turn out to be locked to a stream
539 * (assigning TSN's then we must stop, since we cannot look for
540 * another stream with data to send to that destination). In CMT's
541 * case, by skipping this check, we will send one data packet
542 * towards the requested net.
543 */
544 if (net != NULL && strq != NULL &&
545 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
546 if (TAILQ_FIRST(&strq->outqueue) &&
547 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
548 TAILQ_FIRST(&strq->outqueue)->net != net) {
549 if (strq == asoc->ss_data.last_out_stream) {
550 return (NULL);
551 } else {
552 strqt = strq;
553 goto prio_again;
554 }
555 }
556 }
557 return (strq);
558 }
559
560 static int
sctp_ss_prio_get_value(struct sctp_tcb * stcb SCTP_UNUSED,struct sctp_association * asoc SCTP_UNUSED,struct sctp_stream_out * strq,uint16_t * value)561 sctp_ss_prio_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
562 struct sctp_stream_out *strq, uint16_t *value)
563 {
564 if (strq == NULL) {
565 return (-1);
566 }
567 *value = strq->ss_params.prio.priority;
568 return (1);
569 }
570
571 static int
sctp_ss_prio_set_value(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_stream_out * strq,uint16_t value)572 sctp_ss_prio_set_value(struct sctp_tcb *stcb, struct sctp_association *asoc,
573 struct sctp_stream_out *strq, uint16_t value)
574 {
575 if (strq == NULL) {
576 return (-1);
577 }
578 strq->ss_params.prio.priority = value;
579 sctp_ss_prio_remove(stcb, asoc, strq, NULL, 1);
580 sctp_ss_prio_add(stcb, asoc, strq, NULL, 1);
581 return (1);
582 }
583
584 /*
585 * Fair bandwidth algorithm.
586 * Maintains an equal troughput per stream.
587 */
588 static void
sctp_ss_fb_clear(struct sctp_tcb * stcb,struct sctp_association * asoc,int clear_values,int holds_lock)589 sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
590 int clear_values, int holds_lock)
591 {
592 if (holds_lock == 0) {
593 SCTP_TCB_SEND_LOCK(stcb);
594 }
595 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
596 struct sctp_stream_out *strq;
597
598 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
599 if (clear_values) {
600 strq->ss_params.fb.rounds = -1;
601 }
602 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
603 strq->ss_params.fb.next_spoke.tqe_next = NULL;
604 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
605 }
606 asoc->ss_data.last_out_stream = NULL;
607 if (holds_lock == 0) {
608 SCTP_TCB_SEND_UNLOCK(stcb);
609 }
610 return;
611 }
612
613 static void
sctp_ss_fb_init_stream(struct sctp_tcb * stcb,struct sctp_stream_out * strq,struct sctp_stream_out * with_strq)614 sctp_ss_fb_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
615 {
616 if (with_strq != NULL) {
617 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
618 stcb->asoc.ss_data.locked_on_sending = strq;
619 }
620 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
621 stcb->asoc.ss_data.last_out_stream = strq;
622 }
623 }
624 strq->ss_params.fb.next_spoke.tqe_next = NULL;
625 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
626 if (with_strq != NULL) {
627 strq->ss_params.fb.rounds = with_strq->ss_params.fb.rounds;
628 } else {
629 strq->ss_params.fb.rounds = -1;
630 }
631 return;
632 }
633
634 static void
sctp_ss_fb_add(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_stream_out * strq,struct sctp_stream_queue_pending * sp SCTP_UNUSED,int holds_lock)635 sctp_ss_fb_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
636 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
637 int holds_lock)
638 {
639 if (holds_lock == 0) {
640 SCTP_TCB_SEND_LOCK(stcb);
641 }
642 if (!TAILQ_EMPTY(&strq->outqueue) &&
643 (strq->ss_params.fb.next_spoke.tqe_next == NULL) &&
644 (strq->ss_params.fb.next_spoke.tqe_prev == NULL)) {
645 if (strq->ss_params.fb.rounds < 0)
646 strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
647 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
648 }
649 if (holds_lock == 0) {
650 SCTP_TCB_SEND_UNLOCK(stcb);
651 }
652 return;
653 }
654
655 static void
sctp_ss_fb_remove(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_stream_out * strq,struct sctp_stream_queue_pending * sp SCTP_UNUSED,int holds_lock)656 sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
657 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
658 int holds_lock)
659 {
660 if (holds_lock == 0) {
661 SCTP_TCB_SEND_LOCK(stcb);
662 }
663 /*
664 * Remove from wheel if stream queue is empty and actually is on the
665 * wheel
666 */
667 if (TAILQ_EMPTY(&strq->outqueue) &&
668 (strq->ss_params.fb.next_spoke.tqe_next != NULL ||
669 strq->ss_params.fb.next_spoke.tqe_prev != NULL)) {
670 if (asoc->ss_data.last_out_stream == strq) {
671 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead,
672 ss_params.fb.next_spoke);
673 if (asoc->ss_data.last_out_stream == NULL) {
674 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
675 sctpwheel_listhead);
676 }
677 if (asoc->ss_data.last_out_stream == strq) {
678 asoc->ss_data.last_out_stream = NULL;
679 }
680 }
681 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
682 strq->ss_params.fb.next_spoke.tqe_next = NULL;
683 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
684 }
685 if (holds_lock == 0) {
686 SCTP_TCB_SEND_UNLOCK(stcb);
687 }
688 return;
689 }
690
691 static struct sctp_stream_out *
sctp_ss_fb_select(struct sctp_tcb * stcb SCTP_UNUSED,struct sctp_nets * net,struct sctp_association * asoc)692 sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
693 struct sctp_association *asoc)
694 {
695 struct sctp_stream_out *strq = NULL, *strqt;
696
697 if (asoc->ss_data.locked_on_sending) {
698 return (asoc->ss_data.locked_on_sending);
699 }
700 if (asoc->ss_data.last_out_stream == NULL ||
701 TAILQ_FIRST(&asoc->ss_data.out.wheel) == TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead)) {
702 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
703 } else {
704 strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.fb.next_spoke);
705 }
706 do {
707 if ((strqt != NULL) &&
708 ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) > 0) ||
709 (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0 &&
710 (net == NULL || (TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net == NULL) ||
711 (net != NULL && TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net != NULL &&
712 TAILQ_FIRST(&strqt->outqueue)->net == net))))) {
713 if ((strqt->ss_params.fb.rounds >= 0) && (strq == NULL ||
714 strqt->ss_params.fb.rounds < strq->ss_params.fb.rounds)) {
715 strq = strqt;
716 }
717 }
718 if (strqt != NULL) {
719 strqt = TAILQ_NEXT(strqt, ss_params.fb.next_spoke);
720 } else {
721 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
722 }
723 } while (strqt != strq);
724 return (strq);
725 }
726
727 static void
sctp_ss_fb_scheduled(struct sctp_tcb * stcb,struct sctp_nets * net SCTP_UNUSED,struct sctp_association * asoc,struct sctp_stream_out * strq,int moved_how_much SCTP_UNUSED)728 sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED,
729 struct sctp_association *asoc, struct sctp_stream_out *strq,
730 int moved_how_much SCTP_UNUSED)
731 {
732 struct sctp_stream_queue_pending *sp;
733 struct sctp_stream_out *strqt;
734 int subtract;
735
736 if (stcb->asoc.idata_supported == 0) {
737 sp = TAILQ_FIRST(&strq->outqueue);
738 if ((sp != NULL) && (sp->some_taken == 1)) {
739 stcb->asoc.ss_data.locked_on_sending = strq;
740 } else {
741 stcb->asoc.ss_data.locked_on_sending = NULL;
742 }
743 } else {
744 stcb->asoc.ss_data.locked_on_sending = NULL;
745 }
746 subtract = strq->ss_params.fb.rounds;
747 TAILQ_FOREACH(strqt, &asoc->ss_data.out.wheel, ss_params.fb.next_spoke) {
748 strqt->ss_params.fb.rounds -= subtract;
749 if (strqt->ss_params.fb.rounds < 0)
750 strqt->ss_params.fb.rounds = 0;
751 }
752 if (TAILQ_FIRST(&strq->outqueue)) {
753 strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
754 } else {
755 strq->ss_params.fb.rounds = -1;
756 }
757 asoc->ss_data.last_out_stream = strq;
758 return;
759 }
760
761 /*
762 * First-come, first-serve algorithm.
763 * Maintains the order provided by the application.
764 */
765 static void
766 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
767 struct sctp_stream_out *strq SCTP_UNUSED,
768 struct sctp_stream_queue_pending *sp, int holds_lock);
769
770 static void
sctp_ss_fcfs_init(struct sctp_tcb * stcb,struct sctp_association * asoc,int holds_lock)771 sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
772 int holds_lock)
773 {
774 uint32_t x, n = 0, add_more = 1;
775 struct sctp_stream_queue_pending *sp;
776 uint16_t i;
777
778 if (holds_lock == 0) {
779 SCTP_TCB_SEND_LOCK(stcb);
780 }
781 TAILQ_INIT(&asoc->ss_data.out.list);
782 /*
783 * If there is data in the stream queues already, the scheduler of
784 * an existing association has been changed. We can only cycle
785 * through the stream queues and add everything to the FCFS queue.
786 */
787 while (add_more) {
788 add_more = 0;
789 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
790 sp = TAILQ_FIRST(&stcb->asoc.strmout[i].outqueue);
791 x = 0;
792 /* Find n. message in current stream queue */
793 while (sp != NULL && x < n) {
794 sp = TAILQ_NEXT(sp, next);
795 x++;
796 }
797 if (sp != NULL) {
798 sctp_ss_fcfs_add(stcb, &stcb->asoc, &stcb->asoc.strmout[i], sp, 1);
799 add_more = 1;
800 }
801 }
802 n++;
803 }
804 if (holds_lock == 0) {
805 SCTP_TCB_SEND_UNLOCK(stcb);
806 }
807 return;
808 }
809
810 static void
sctp_ss_fcfs_clear(struct sctp_tcb * stcb,struct sctp_association * asoc,int clear_values,int holds_lock)811 sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
812 int clear_values, int holds_lock)
813 {
814 struct sctp_stream_queue_pending *sp;
815
816 if (clear_values) {
817 if (holds_lock == 0) {
818 SCTP_TCB_SEND_LOCK(stcb);
819 }
820 while (!TAILQ_EMPTY(&asoc->ss_data.out.list)) {
821 sp = TAILQ_FIRST(&asoc->ss_data.out.list);
822 TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
823 sp->ss_next.tqe_next = NULL;
824 sp->ss_next.tqe_prev = NULL;
825 }
826 if (holds_lock == 0) {
827 SCTP_TCB_SEND_UNLOCK(stcb);
828 }
829 }
830 return;
831 }
832
833 static void
sctp_ss_fcfs_init_stream(struct sctp_tcb * stcb,struct sctp_stream_out * strq,struct sctp_stream_out * with_strq)834 sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
835 {
836 if (with_strq != NULL) {
837 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
838 stcb->asoc.ss_data.locked_on_sending = strq;
839 }
840 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
841 stcb->asoc.ss_data.last_out_stream = strq;
842 }
843 }
844 strq->ss_params.fb.next_spoke.tqe_next = NULL;
845 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
846 return;
847 }
848
849 static void
sctp_ss_fcfs_add(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_stream_out * strq SCTP_UNUSED,struct sctp_stream_queue_pending * sp,int holds_lock)850 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
851 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
852 int holds_lock)
853 {
854 if (holds_lock == 0) {
855 SCTP_TCB_SEND_LOCK(stcb);
856 }
857 if (sp && (sp->ss_next.tqe_next == NULL) &&
858 (sp->ss_next.tqe_prev == NULL)) {
859 TAILQ_INSERT_TAIL(&asoc->ss_data.out.list, sp, ss_next);
860 }
861 if (holds_lock == 0) {
862 SCTP_TCB_SEND_UNLOCK(stcb);
863 }
864 return;
865 }
866
867 static int
sctp_ss_fcfs_is_empty(struct sctp_tcb * stcb SCTP_UNUSED,struct sctp_association * asoc)868 sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
869 {
870 if (TAILQ_EMPTY(&asoc->ss_data.out.list)) {
871 return (1);
872 } else {
873 return (0);
874 }
875 }
876
877 static void
sctp_ss_fcfs_remove(struct sctp_tcb * stcb,struct sctp_association * asoc,struct sctp_stream_out * strq SCTP_UNUSED,struct sctp_stream_queue_pending * sp,int holds_lock)878 sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
879 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
880 int holds_lock)
881 {
882 if (holds_lock == 0) {
883 SCTP_TCB_SEND_LOCK(stcb);
884 }
885 if (sp &&
886 ((sp->ss_next.tqe_next != NULL) ||
887 (sp->ss_next.tqe_prev != NULL))) {
888 TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
889 sp->ss_next.tqe_next = NULL;
890 sp->ss_next.tqe_prev = NULL;
891 }
892 if (holds_lock == 0) {
893 SCTP_TCB_SEND_UNLOCK(stcb);
894 }
895 return;
896 }
897
898 static struct sctp_stream_out *
sctp_ss_fcfs_select(struct sctp_tcb * stcb SCTP_UNUSED,struct sctp_nets * net,struct sctp_association * asoc)899 sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
900 struct sctp_association *asoc)
901 {
902 struct sctp_stream_out *strq;
903 struct sctp_stream_queue_pending *sp;
904
905 if (asoc->ss_data.locked_on_sending) {
906 return (asoc->ss_data.locked_on_sending);
907 }
908 sp = TAILQ_FIRST(&asoc->ss_data.out.list);
909 default_again:
910 if (sp != NULL) {
911 strq = &asoc->strmout[sp->sid];
912 } else {
913 strq = NULL;
914 }
915
916 /*
917 * If CMT is off, we must validate that the stream in question has
918 * the first item pointed towards are network destination requested
919 * by the caller. Note that if we turn out to be locked to a stream
920 * (assigning TSN's then we must stop, since we cannot look for
921 * another stream with data to send to that destination). In CMT's
922 * case, by skipping this check, we will send one data packet
923 * towards the requested net.
924 */
925 if (net != NULL && strq != NULL &&
926 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
927 if (TAILQ_FIRST(&strq->outqueue) &&
928 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
929 TAILQ_FIRST(&strq->outqueue)->net != net) {
930 sp = TAILQ_NEXT(sp, ss_next);
931 goto default_again;
932 }
933 }
934 return (strq);
935 }
936
937 const struct sctp_ss_functions sctp_ss_functions[] = {
938 /* SCTP_SS_DEFAULT */
939 {
940 .sctp_ss_init = sctp_ss_default_init,
941 .sctp_ss_clear = sctp_ss_default_clear,
942 .sctp_ss_init_stream = sctp_ss_default_init_stream,
943 .sctp_ss_add_to_stream = sctp_ss_default_add,
944 .sctp_ss_is_empty = sctp_ss_default_is_empty,
945 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
946 .sctp_ss_select_stream = sctp_ss_default_select,
947 .sctp_ss_scheduled = sctp_ss_default_scheduled,
948 .sctp_ss_packet_done = sctp_ss_default_packet_done,
949 .sctp_ss_get_value = sctp_ss_default_get_value,
950 .sctp_ss_set_value = sctp_ss_default_set_value,
951 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
952 },
953 /* SCTP_SS_ROUND_ROBIN */
954 {
955 .sctp_ss_init = sctp_ss_default_init,
956 .sctp_ss_clear = sctp_ss_default_clear,
957 .sctp_ss_init_stream = sctp_ss_default_init_stream,
958 .sctp_ss_add_to_stream = sctp_ss_rr_add,
959 .sctp_ss_is_empty = sctp_ss_default_is_empty,
960 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
961 .sctp_ss_select_stream = sctp_ss_default_select,
962 .sctp_ss_scheduled = sctp_ss_default_scheduled,
963 .sctp_ss_packet_done = sctp_ss_default_packet_done,
964 .sctp_ss_get_value = sctp_ss_default_get_value,
965 .sctp_ss_set_value = sctp_ss_default_set_value,
966 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
967 },
968 /* SCTP_SS_ROUND_ROBIN_PACKET */
969 {
970 .sctp_ss_init = sctp_ss_default_init,
971 .sctp_ss_clear = sctp_ss_default_clear,
972 .sctp_ss_init_stream = sctp_ss_default_init_stream,
973 .sctp_ss_add_to_stream = sctp_ss_rr_add,
974 .sctp_ss_is_empty = sctp_ss_default_is_empty,
975 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
976 .sctp_ss_select_stream = sctp_ss_rrp_select,
977 .sctp_ss_scheduled = sctp_ss_default_scheduled,
978 .sctp_ss_packet_done = sctp_ss_rrp_packet_done,
979 .sctp_ss_get_value = sctp_ss_default_get_value,
980 .sctp_ss_set_value = sctp_ss_default_set_value,
981 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
982 },
983 /* SCTP_SS_PRIORITY */
984 {
985 .sctp_ss_init = sctp_ss_default_init,
986 .sctp_ss_clear = sctp_ss_prio_clear,
987 .sctp_ss_init_stream = sctp_ss_prio_init_stream,
988 .sctp_ss_add_to_stream = sctp_ss_prio_add,
989 .sctp_ss_is_empty = sctp_ss_default_is_empty,
990 .sctp_ss_remove_from_stream = sctp_ss_prio_remove,
991 .sctp_ss_select_stream = sctp_ss_prio_select,
992 .sctp_ss_scheduled = sctp_ss_default_scheduled,
993 .sctp_ss_packet_done = sctp_ss_default_packet_done,
994 .sctp_ss_get_value = sctp_ss_prio_get_value,
995 .sctp_ss_set_value = sctp_ss_prio_set_value,
996 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
997 },
998 /* SCTP_SS_FAIR_BANDWITH */
999 {
1000 .sctp_ss_init = sctp_ss_default_init,
1001 .sctp_ss_clear = sctp_ss_fb_clear,
1002 .sctp_ss_init_stream = sctp_ss_fb_init_stream,
1003 .sctp_ss_add_to_stream = sctp_ss_fb_add,
1004 .sctp_ss_is_empty = sctp_ss_default_is_empty,
1005 .sctp_ss_remove_from_stream = sctp_ss_fb_remove,
1006 .sctp_ss_select_stream = sctp_ss_fb_select,
1007 .sctp_ss_scheduled = sctp_ss_fb_scheduled,
1008 .sctp_ss_packet_done = sctp_ss_default_packet_done,
1009 .sctp_ss_get_value = sctp_ss_default_get_value,
1010 .sctp_ss_set_value = sctp_ss_default_set_value,
1011 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
1012 },
1013 /* SCTP_SS_FIRST_COME */
1014 {
1015 .sctp_ss_init = sctp_ss_fcfs_init,
1016 .sctp_ss_clear = sctp_ss_fcfs_clear,
1017 .sctp_ss_init_stream = sctp_ss_fcfs_init_stream,
1018 .sctp_ss_add_to_stream = sctp_ss_fcfs_add,
1019 .sctp_ss_is_empty = sctp_ss_fcfs_is_empty,
1020 .sctp_ss_remove_from_stream = sctp_ss_fcfs_remove,
1021 .sctp_ss_select_stream = sctp_ss_fcfs_select,
1022 .sctp_ss_scheduled = sctp_ss_default_scheduled,
1023 .sctp_ss_packet_done = sctp_ss_default_packet_done,
1024 .sctp_ss_get_value = sctp_ss_default_get_value,
1025 .sctp_ss_set_value = sctp_ss_default_set_value,
1026 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
1027 }
1028 };
1029