2 * Copyright (c) 2010-2012, by Michael Tuexen. All rights reserved.
3 * Copyright (c) 2010-2012, by Randall Stewart. All rights reserved.
4 * Copyright (c) 2010-2012, by Robin Seggelmann. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * a) Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
12 * b) Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 * THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <netinet/sctp_pcb.h>
35 * Default simple round-robin algorithm.
36 * Just interates the streams in the order they appear.
40 sctp_ss_default_add(struct sctp_tcb *, struct sctp_association *,
41 struct sctp_stream_out *,
42 struct sctp_stream_queue_pending *, int);
45 sctp_ss_default_remove(struct sctp_tcb *, struct sctp_association *,
46 struct sctp_stream_out *,
47 struct sctp_stream_queue_pending *, int);
50 sctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
55 asoc->ss_data.locked_on_sending = NULL;
56 asoc->ss_data.last_out_stream = NULL;
57 TAILQ_INIT(&asoc->ss_data.out.wheel);
59 * If there is data in the stream queues already, the scheduler of
60 * an existing association has been changed. We need to add all
61 * stream queues to the wheel.
63 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
64 stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, &stcb->asoc,
65 &stcb->asoc.strmout[i],
72 sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
73 int clear_values SCTP_UNUSED, int holds_lock)
75 if (holds_lock == 0) {
76 SCTP_TCB_SEND_LOCK(stcb);
78 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
79 struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
81 TAILQ_REMOVE(&asoc->ss_data.out.wheel, TAILQ_FIRST(&asoc->ss_data.out.wheel), ss_params.rr.next_spoke);
82 strq->ss_params.rr.next_spoke.tqe_next = NULL;
83 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
85 asoc->ss_data.last_out_stream = NULL;
86 if (holds_lock == 0) {
87 SCTP_TCB_SEND_UNLOCK(stcb);
93 sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
95 if (with_strq != NULL) {
96 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
97 stcb->asoc.ss_data.locked_on_sending = strq;
99 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
100 stcb->asoc.ss_data.last_out_stream = strq;
103 strq->ss_params.rr.next_spoke.tqe_next = NULL;
104 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
109 sctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
110 struct sctp_stream_out *strq,
111 struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock)
113 if (holds_lock == 0) {
114 SCTP_TCB_SEND_LOCK(stcb);
116 /* Add to wheel if not already on it and stream queue not empty */
117 if (!TAILQ_EMPTY(&strq->outqueue) &&
118 (strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
119 (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
120 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel,
121 strq, ss_params.rr.next_spoke);
123 if (holds_lock == 0) {
124 SCTP_TCB_SEND_UNLOCK(stcb);
130 sctp_ss_default_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
132 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
140 sctp_ss_default_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
141 struct sctp_stream_out *strq,
142 struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock)
144 if (holds_lock == 0) {
145 SCTP_TCB_SEND_LOCK(stcb);
148 * Remove from wheel if stream queue is empty and actually is on the
151 if (TAILQ_EMPTY(&strq->outqueue) &&
152 (strq->ss_params.rr.next_spoke.tqe_next != NULL ||
153 strq->ss_params.rr.next_spoke.tqe_prev != NULL)) {
154 if (asoc->ss_data.last_out_stream == strq) {
155 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream,
157 ss_params.rr.next_spoke);
158 if (asoc->ss_data.last_out_stream == NULL) {
159 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
162 if (asoc->ss_data.last_out_stream == strq) {
163 asoc->ss_data.last_out_stream = NULL;
166 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
167 strq->ss_params.rr.next_spoke.tqe_next = NULL;
168 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
170 if (holds_lock == 0) {
171 SCTP_TCB_SEND_UNLOCK(stcb);
177 static struct sctp_stream_out *
178 sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
179 struct sctp_association *asoc)
181 struct sctp_stream_out *strq, *strqt;
183 if (asoc->ss_data.locked_on_sending) {
184 return (asoc->ss_data.locked_on_sending);
186 strqt = asoc->ss_data.last_out_stream;
188 /* Find the next stream to use */
190 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
192 strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
194 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
199 * If CMT is off, we must validate that the stream in question has
200 * the first item pointed towards are network destination requested
201 * by the caller. Note that if we turn out to be locked to a stream
202 * (assigning TSN's then we must stop, since we cannot look for
203 * another stream with data to send to that destination). In CMT's
204 * case, by skipping this check, we will send one data packet
205 * towards the requested net.
207 if (net != NULL && strq != NULL &&
208 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
209 if (TAILQ_FIRST(&strq->outqueue) &&
210 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
211 TAILQ_FIRST(&strq->outqueue)->net != net) {
212 if (strq == asoc->ss_data.last_out_stream) {
224 sctp_ss_default_scheduled(struct sctp_tcb *stcb,
225 struct sctp_nets *net SCTP_UNUSED,
226 struct sctp_association *asoc,
227 struct sctp_stream_out *strq,
228 int moved_how_much SCTP_UNUSED)
230 struct sctp_stream_queue_pending *sp;
232 asoc->ss_data.last_out_stream = strq;
233 if (stcb->asoc.idata_supported == 0) {
234 sp = TAILQ_FIRST(&strq->outqueue);
235 if ((sp != NULL) && (sp->some_taken == 1)) {
236 stcb->asoc.ss_data.locked_on_sending = strq;
238 stcb->asoc.ss_data.locked_on_sending = NULL;
241 stcb->asoc.ss_data.locked_on_sending = NULL;
247 sctp_ss_default_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
248 struct sctp_association *asoc SCTP_UNUSED)
250 /* Nothing to be done here */
255 sctp_ss_default_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
256 struct sctp_stream_out *strq SCTP_UNUSED, uint16_t *value SCTP_UNUSED)
258 /* Nothing to be done here */
263 sctp_ss_default_set_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)
266 /* Nothing to be done here */
271 sctp_ss_default_is_user_msgs_incomplete(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
273 struct sctp_stream_out *strq;
274 struct sctp_stream_queue_pending *sp;
276 if (asoc->stream_queue_cnt != 1) {
279 strq = asoc->ss_data.locked_on_sending;
283 sp = TAILQ_FIRST(&strq->outqueue);
287 return (!sp->msg_is_complete);
291 * Real round-robin algorithm.
292 * Always interates the streams in ascending order.
295 sctp_ss_rr_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
296 struct sctp_stream_out *strq,
297 struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock)
299 struct sctp_stream_out *strqt;
301 if (holds_lock == 0) {
302 SCTP_TCB_SEND_LOCK(stcb);
304 if (!TAILQ_EMPTY(&strq->outqueue) &&
305 (strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
306 (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
307 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
308 TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
310 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
311 while (strqt != NULL && (strqt->sid < strq->sid)) {
312 strqt = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
315 TAILQ_INSERT_BEFORE(strqt, strq, ss_params.rr.next_spoke);
317 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
321 if (holds_lock == 0) {
322 SCTP_TCB_SEND_UNLOCK(stcb);
328 * Real round-robin per packet algorithm.
329 * Always interates the streams in ascending order and
330 * only fills messages of the same stream in a packet.
332 static struct sctp_stream_out *
333 sctp_ss_rrp_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
334 struct sctp_association *asoc)
336 return (asoc->ss_data.last_out_stream);
340 sctp_ss_rrp_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
341 struct sctp_association *asoc)
343 struct sctp_stream_out *strq, *strqt;
345 strqt = asoc->ss_data.last_out_stream;
347 /* Find the next stream to use */
349 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
351 strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
353 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
358 * If CMT is off, we must validate that the stream in question has
359 * the first item pointed towards are network destination requested
360 * by the caller. Note that if we turn out to be locked to a stream
361 * (assigning TSN's then we must stop, since we cannot look for
362 * another stream with data to send to that destination). In CMT's
363 * case, by skipping this check, we will send one data packet
364 * towards the requested net.
366 if (net != NULL && strq != NULL &&
367 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
368 if (TAILQ_FIRST(&strq->outqueue) &&
369 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
370 TAILQ_FIRST(&strq->outqueue)->net != net) {
371 if (strq == asoc->ss_data.last_out_stream) {
379 asoc->ss_data.last_out_stream = strq;
385 * Priority algorithm.
386 * Always prefers streams based on their priority id.
389 sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
390 int clear_values, int holds_lock)
392 if (holds_lock == 0) {
393 SCTP_TCB_SEND_LOCK(stcb);
395 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
396 struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
399 strq->ss_params.prio.priority = 0;
401 TAILQ_REMOVE(&asoc->ss_data.out.wheel, TAILQ_FIRST(&asoc->ss_data.out.wheel), ss_params.prio.next_spoke);
402 strq->ss_params.prio.next_spoke.tqe_next = NULL;
403 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
406 asoc->ss_data.last_out_stream = NULL;
407 if (holds_lock == 0) {
408 SCTP_TCB_SEND_UNLOCK(stcb);
414 sctp_ss_prio_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
416 if (with_strq != NULL) {
417 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
418 stcb->asoc.ss_data.locked_on_sending = strq;
420 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
421 stcb->asoc.ss_data.last_out_stream = strq;
424 strq->ss_params.prio.next_spoke.tqe_next = NULL;
425 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
426 if (with_strq != NULL) {
427 strq->ss_params.prio.priority = with_strq->ss_params.prio.priority;
429 strq->ss_params.prio.priority = 0;
435 sctp_ss_prio_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
436 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
439 struct sctp_stream_out *strqt;
441 if (holds_lock == 0) {
442 SCTP_TCB_SEND_LOCK(stcb);
444 /* Add to wheel if not already on it and stream queue not empty */
445 if (!TAILQ_EMPTY(&strq->outqueue) &&
446 (strq->ss_params.prio.next_spoke.tqe_next == NULL) &&
447 (strq->ss_params.prio.next_spoke.tqe_prev == NULL)) {
448 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
449 TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
451 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
452 while (strqt != NULL && strqt->ss_params.prio.priority < strq->ss_params.prio.priority) {
453 strqt = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
456 TAILQ_INSERT_BEFORE(strqt, strq, ss_params.prio.next_spoke);
458 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
462 if (holds_lock == 0) {
463 SCTP_TCB_SEND_UNLOCK(stcb);
469 sctp_ss_prio_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
470 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
473 if (holds_lock == 0) {
474 SCTP_TCB_SEND_LOCK(stcb);
477 * Remove from wheel if stream queue is empty and actually is on the
480 if (TAILQ_EMPTY(&strq->outqueue) &&
481 (strq->ss_params.prio.next_spoke.tqe_next != NULL ||
482 strq->ss_params.prio.next_spoke.tqe_prev != NULL)) {
483 if (asoc->ss_data.last_out_stream == strq) {
484 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead,
485 ss_params.prio.next_spoke);
486 if (asoc->ss_data.last_out_stream == NULL) {
487 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
490 if (asoc->ss_data.last_out_stream == strq) {
491 asoc->ss_data.last_out_stream = NULL;
494 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
495 strq->ss_params.prio.next_spoke.tqe_next = NULL;
496 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
498 if (holds_lock == 0) {
499 SCTP_TCB_SEND_UNLOCK(stcb);
504 static struct sctp_stream_out *
505 sctp_ss_prio_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
506 struct sctp_association *asoc)
508 struct sctp_stream_out *strq, *strqt, *strqn;
510 strqt = asoc->ss_data.last_out_stream;
512 /* Find the next stream to use */
514 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
516 strqn = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
518 strqn->ss_params.prio.priority == strqt->ss_params.prio.priority) {
521 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
526 * If CMT is off, we must validate that the stream in question has
527 * the first item pointed towards are network destination requested
528 * by the caller. Note that if we turn out to be locked to a stream
529 * (assigning TSN's then we must stop, since we cannot look for
530 * another stream with data to send to that destination). In CMT's
531 * case, by skipping this check, we will send one data packet
532 * towards the requested net.
534 if (net != NULL && strq != NULL &&
535 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
536 if (TAILQ_FIRST(&strq->outqueue) &&
537 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
538 TAILQ_FIRST(&strq->outqueue)->net != net) {
539 if (strq == asoc->ss_data.last_out_stream) {
551 sctp_ss_prio_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
552 struct sctp_stream_out *strq, uint16_t *value)
557 *value = strq->ss_params.prio.priority;
562 sctp_ss_prio_set_value(struct sctp_tcb *stcb, struct sctp_association *asoc,
563 struct sctp_stream_out *strq, uint16_t value)
568 strq->ss_params.prio.priority = value;
569 sctp_ss_prio_remove(stcb, asoc, strq, NULL, 1);
570 sctp_ss_prio_add(stcb, asoc, strq, NULL, 1);
575 * Fair bandwidth algorithm.
576 * Maintains an equal troughput per stream.
579 sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
580 int clear_values, int holds_lock)
582 if (holds_lock == 0) {
583 SCTP_TCB_SEND_LOCK(stcb);
585 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
586 struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
589 strq->ss_params.fb.rounds = -1;
591 TAILQ_REMOVE(&asoc->ss_data.out.wheel, TAILQ_FIRST(&asoc->ss_data.out.wheel), ss_params.fb.next_spoke);
592 strq->ss_params.fb.next_spoke.tqe_next = NULL;
593 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
595 asoc->ss_data.last_out_stream = NULL;
596 if (holds_lock == 0) {
597 SCTP_TCB_SEND_UNLOCK(stcb);
603 sctp_ss_fb_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
605 if (with_strq != NULL) {
606 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
607 stcb->asoc.ss_data.locked_on_sending = strq;
609 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
610 stcb->asoc.ss_data.last_out_stream = strq;
613 strq->ss_params.fb.next_spoke.tqe_next = NULL;
614 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
615 if (with_strq != NULL) {
616 strq->ss_params.fb.rounds = with_strq->ss_params.fb.rounds;
618 strq->ss_params.fb.rounds = -1;
624 sctp_ss_fb_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
625 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
628 if (holds_lock == 0) {
629 SCTP_TCB_SEND_LOCK(stcb);
631 if (!TAILQ_EMPTY(&strq->outqueue) &&
632 (strq->ss_params.fb.next_spoke.tqe_next == NULL) &&
633 (strq->ss_params.fb.next_spoke.tqe_prev == NULL)) {
634 if (strq->ss_params.fb.rounds < 0)
635 strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
636 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
638 if (holds_lock == 0) {
639 SCTP_TCB_SEND_UNLOCK(stcb);
645 sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
646 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
649 if (holds_lock == 0) {
650 SCTP_TCB_SEND_LOCK(stcb);
653 * Remove from wheel if stream queue is empty and actually is on the
656 if (TAILQ_EMPTY(&strq->outqueue) &&
657 (strq->ss_params.fb.next_spoke.tqe_next != NULL ||
658 strq->ss_params.fb.next_spoke.tqe_prev != NULL)) {
659 if (asoc->ss_data.last_out_stream == strq) {
660 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead,
661 ss_params.fb.next_spoke);
662 if (asoc->ss_data.last_out_stream == NULL) {
663 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
666 if (asoc->ss_data.last_out_stream == strq) {
667 asoc->ss_data.last_out_stream = NULL;
670 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
671 strq->ss_params.fb.next_spoke.tqe_next = NULL;
672 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
674 if (holds_lock == 0) {
675 SCTP_TCB_SEND_UNLOCK(stcb);
680 static struct sctp_stream_out *
681 sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
682 struct sctp_association *asoc)
684 struct sctp_stream_out *strq = NULL, *strqt;
686 if (asoc->ss_data.last_out_stream == NULL ||
687 TAILQ_FIRST(&asoc->ss_data.out.wheel) == TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead)) {
688 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
690 strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.fb.next_spoke);
693 if ((strqt != NULL) &&
694 ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) > 0) ||
695 (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0 &&
696 (net == NULL || (TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net == NULL) ||
697 (net != NULL && TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net != NULL &&
698 TAILQ_FIRST(&strqt->outqueue)->net == net))))) {
699 if ((strqt->ss_params.fb.rounds >= 0) && (strq == NULL ||
700 strqt->ss_params.fb.rounds < strq->ss_params.fb.rounds)) {
705 strqt = TAILQ_NEXT(strqt, ss_params.fb.next_spoke);
707 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
709 } while (strqt != strq);
714 sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED,
715 struct sctp_association *asoc, struct sctp_stream_out *strq,
716 int moved_how_much SCTP_UNUSED)
718 struct sctp_stream_queue_pending *sp;
719 struct sctp_stream_out *strqt;
722 if (stcb->asoc.idata_supported == 0) {
723 sp = TAILQ_FIRST(&strq->outqueue);
724 if ((sp != NULL) && (sp->some_taken == 1)) {
725 stcb->asoc.ss_data.locked_on_sending = strq;
727 stcb->asoc.ss_data.locked_on_sending = NULL;
730 stcb->asoc.ss_data.locked_on_sending = NULL;
732 subtract = strq->ss_params.fb.rounds;
733 TAILQ_FOREACH(strqt, &asoc->ss_data.out.wheel, ss_params.fb.next_spoke) {
734 strqt->ss_params.fb.rounds -= subtract;
735 if (strqt->ss_params.fb.rounds < 0)
736 strqt->ss_params.fb.rounds = 0;
738 if (TAILQ_FIRST(&strq->outqueue)) {
739 strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
741 strq->ss_params.fb.rounds = -1;
743 asoc->ss_data.last_out_stream = strq;
748 * First-come, first-serve algorithm.
749 * Maintains the order provided by the application.
752 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
753 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp,
757 sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
760 uint32_t x, n = 0, add_more = 1;
761 struct sctp_stream_queue_pending *sp;
764 TAILQ_INIT(&asoc->ss_data.out.list);
766 * If there is data in the stream queues already, the scheduler of
767 * an existing association has been changed. We can only cycle
768 * through the stream queues and add everything to the FCFS queue.
772 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
773 sp = TAILQ_FIRST(&stcb->asoc.strmout[i].outqueue);
775 /* Find n. message in current stream queue */
776 while (sp != NULL && x < n) {
777 sp = TAILQ_NEXT(sp, next);
781 sctp_ss_fcfs_add(stcb, &stcb->asoc, &stcb->asoc.strmout[i], sp, holds_lock);
791 sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
792 int clear_values, int holds_lock)
795 if (holds_lock == 0) {
796 SCTP_TCB_SEND_LOCK(stcb);
798 while (!TAILQ_EMPTY(&asoc->ss_data.out.list)) {
799 TAILQ_REMOVE(&asoc->ss_data.out.list, TAILQ_FIRST(&asoc->ss_data.out.list), ss_next);
801 if (holds_lock == 0) {
802 SCTP_TCB_SEND_UNLOCK(stcb);
809 sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
811 if (with_strq != NULL) {
812 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
813 stcb->asoc.ss_data.locked_on_sending = strq;
815 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
816 stcb->asoc.ss_data.last_out_stream = strq;
823 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
824 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
827 if (holds_lock == 0) {
828 SCTP_TCB_SEND_LOCK(stcb);
830 if (sp && (sp->ss_next.tqe_next == NULL) &&
831 (sp->ss_next.tqe_prev == NULL)) {
832 TAILQ_INSERT_TAIL(&asoc->ss_data.out.list, sp, ss_next);
834 if (holds_lock == 0) {
835 SCTP_TCB_SEND_UNLOCK(stcb);
841 sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
843 if (TAILQ_EMPTY(&asoc->ss_data.out.list)) {
851 sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
852 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
855 if (holds_lock == 0) {
856 SCTP_TCB_SEND_LOCK(stcb);
859 ((sp->ss_next.tqe_next != NULL) ||
860 (sp->ss_next.tqe_prev != NULL))) {
861 TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
863 if (holds_lock == 0) {
864 SCTP_TCB_SEND_UNLOCK(stcb);
870 static struct sctp_stream_out *
871 sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
872 struct sctp_association *asoc)
874 struct sctp_stream_out *strq;
875 struct sctp_stream_queue_pending *sp;
877 sp = TAILQ_FIRST(&asoc->ss_data.out.list);
880 strq = &asoc->strmout[sp->sid];
886 * If CMT is off, we must validate that the stream in question has
887 * the first item pointed towards are network destination requested
888 * by the caller. Note that if we turn out to be locked to a stream
889 * (assigning TSN's then we must stop, since we cannot look for
890 * another stream with data to send to that destination). In CMT's
891 * case, by skipping this check, we will send one data packet
892 * towards the requested net.
894 if (net != NULL && strq != NULL &&
895 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
896 if (TAILQ_FIRST(&strq->outqueue) &&
897 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
898 TAILQ_FIRST(&strq->outqueue)->net != net) {
899 sp = TAILQ_NEXT(sp, ss_next);
906 const struct sctp_ss_functions sctp_ss_functions[] = {
907 /* SCTP_SS_DEFAULT */
909 .sctp_ss_init = sctp_ss_default_init,
910 .sctp_ss_clear = sctp_ss_default_clear,
911 .sctp_ss_init_stream = sctp_ss_default_init_stream,
912 .sctp_ss_add_to_stream = sctp_ss_default_add,
913 .sctp_ss_is_empty = sctp_ss_default_is_empty,
914 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
915 .sctp_ss_select_stream = sctp_ss_default_select,
916 .sctp_ss_scheduled = sctp_ss_default_scheduled,
917 .sctp_ss_packet_done = sctp_ss_default_packet_done,
918 .sctp_ss_get_value = sctp_ss_default_get_value,
919 .sctp_ss_set_value = sctp_ss_default_set_value,
920 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
922 /* SCTP_SS_ROUND_ROBIN */
924 .sctp_ss_init = sctp_ss_default_init,
925 .sctp_ss_clear = sctp_ss_default_clear,
926 .sctp_ss_init_stream = sctp_ss_default_init_stream,
927 .sctp_ss_add_to_stream = sctp_ss_rr_add,
928 .sctp_ss_is_empty = sctp_ss_default_is_empty,
929 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
930 .sctp_ss_select_stream = sctp_ss_default_select,
931 .sctp_ss_scheduled = sctp_ss_default_scheduled,
932 .sctp_ss_packet_done = sctp_ss_default_packet_done,
933 .sctp_ss_get_value = sctp_ss_default_get_value,
934 .sctp_ss_set_value = sctp_ss_default_set_value,
935 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
937 /* SCTP_SS_ROUND_ROBIN_PACKET */
939 .sctp_ss_init = sctp_ss_default_init,
940 .sctp_ss_clear = sctp_ss_default_clear,
941 .sctp_ss_init_stream = sctp_ss_default_init_stream,
942 .sctp_ss_add_to_stream = sctp_ss_rr_add,
943 .sctp_ss_is_empty = sctp_ss_default_is_empty,
944 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
945 .sctp_ss_select_stream = sctp_ss_rrp_select,
946 .sctp_ss_scheduled = sctp_ss_default_scheduled,
947 .sctp_ss_packet_done = sctp_ss_rrp_packet_done,
948 .sctp_ss_get_value = sctp_ss_default_get_value,
949 .sctp_ss_set_value = sctp_ss_default_set_value,
950 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
952 /* SCTP_SS_PRIORITY */
954 .sctp_ss_init = sctp_ss_default_init,
955 .sctp_ss_clear = sctp_ss_prio_clear,
956 .sctp_ss_init_stream = sctp_ss_prio_init_stream,
957 .sctp_ss_add_to_stream = sctp_ss_prio_add,
958 .sctp_ss_is_empty = sctp_ss_default_is_empty,
959 .sctp_ss_remove_from_stream = sctp_ss_prio_remove,
960 .sctp_ss_select_stream = sctp_ss_prio_select,
961 .sctp_ss_scheduled = sctp_ss_default_scheduled,
962 .sctp_ss_packet_done = sctp_ss_default_packet_done,
963 .sctp_ss_get_value = sctp_ss_prio_get_value,
964 .sctp_ss_set_value = sctp_ss_prio_set_value,
965 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
967 /* SCTP_SS_FAIR_BANDWITH */
969 .sctp_ss_init = sctp_ss_default_init,
970 .sctp_ss_clear = sctp_ss_fb_clear,
971 .sctp_ss_init_stream = sctp_ss_fb_init_stream,
972 .sctp_ss_add_to_stream = sctp_ss_fb_add,
973 .sctp_ss_is_empty = sctp_ss_default_is_empty,
974 .sctp_ss_remove_from_stream = sctp_ss_fb_remove,
975 .sctp_ss_select_stream = sctp_ss_fb_select,
976 .sctp_ss_scheduled = sctp_ss_fb_scheduled,
977 .sctp_ss_packet_done = sctp_ss_default_packet_done,
978 .sctp_ss_get_value = sctp_ss_default_get_value,
979 .sctp_ss_set_value = sctp_ss_default_set_value,
980 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
982 /* SCTP_SS_FIRST_COME */
984 .sctp_ss_init = sctp_ss_fcfs_init,
985 .sctp_ss_clear = sctp_ss_fcfs_clear,
986 .sctp_ss_init_stream = sctp_ss_fcfs_init_stream,
987 .sctp_ss_add_to_stream = sctp_ss_fcfs_add,
988 .sctp_ss_is_empty = sctp_ss_fcfs_is_empty,
989 .sctp_ss_remove_from_stream = sctp_ss_fcfs_remove,
990 .sctp_ss_select_stream = sctp_ss_fcfs_select,
991 .sctp_ss_scheduled = sctp_ss_default_scheduled,
992 .sctp_ss_packet_done = sctp_ss_default_packet_done,
993 .sctp_ss_get_value = sctp_ss_default_get_value,
994 .sctp_ss_set_value = sctp_ss_default_set_value,
995 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete