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