2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * a) Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
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.
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.
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <netinet/sctp_pcb.h>
37 * Default simple round-robin algorithm.
38 * Just interates the streams in the order they appear.
42 sctp_ss_default_add(struct sctp_tcb *, struct sctp_association *,
43 struct sctp_stream_out *,
44 struct sctp_stream_queue_pending *, int);
47 sctp_ss_default_remove(struct sctp_tcb *, struct sctp_association *,
48 struct sctp_stream_out *,
49 struct sctp_stream_queue_pending *, int);
52 sctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
57 asoc->ss_data.locked_on_sending = NULL;
58 asoc->ss_data.last_out_stream = NULL;
59 TAILQ_INIT(&asoc->ss_data.out.wheel);
61 * If there is data in the stream queues already, the scheduler of
62 * an existing association has been changed. We need to add all
63 * stream queues to the wheel.
65 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
66 stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, &stcb->asoc,
67 &stcb->asoc.strmout[i],
74 sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
75 int clear_values SCTP_UNUSED, int holds_lock)
77 if (holds_lock == 0) {
78 SCTP_TCB_SEND_LOCK(stcb);
80 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
81 struct sctp_stream_out *strq;
83 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
84 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
85 strq->ss_params.rr.next_spoke.tqe_next = NULL;
86 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
88 asoc->ss_data.last_out_stream = NULL;
89 if (holds_lock == 0) {
90 SCTP_TCB_SEND_UNLOCK(stcb);
96 sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
98 if (with_strq != NULL) {
99 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
100 stcb->asoc.ss_data.locked_on_sending = strq;
102 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
103 stcb->asoc.ss_data.last_out_stream = strq;
106 strq->ss_params.rr.next_spoke.tqe_next = NULL;
107 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
112 sctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
113 struct sctp_stream_out *strq,
114 struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock)
116 if (holds_lock == 0) {
117 SCTP_TCB_SEND_LOCK(stcb);
119 /* Add to wheel if not already on it and stream queue not empty */
120 if (!TAILQ_EMPTY(&strq->outqueue) &&
121 (strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
122 (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
123 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel,
124 strq, ss_params.rr.next_spoke);
126 if (holds_lock == 0) {
127 SCTP_TCB_SEND_UNLOCK(stcb);
133 sctp_ss_default_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
135 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
143 sctp_ss_default_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
144 struct sctp_stream_out *strq,
145 struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock)
147 if (holds_lock == 0) {
148 SCTP_TCB_SEND_LOCK(stcb);
151 * Remove from wheel if stream queue is empty and actually is on the
154 if (TAILQ_EMPTY(&strq->outqueue) &&
155 (strq->ss_params.rr.next_spoke.tqe_next != NULL ||
156 strq->ss_params.rr.next_spoke.tqe_prev != NULL)) {
157 if (asoc->ss_data.last_out_stream == strq) {
158 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream,
160 ss_params.rr.next_spoke);
161 if (asoc->ss_data.last_out_stream == NULL) {
162 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
165 if (asoc->ss_data.last_out_stream == strq) {
166 asoc->ss_data.last_out_stream = NULL;
169 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
170 strq->ss_params.rr.next_spoke.tqe_next = NULL;
171 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
173 if (holds_lock == 0) {
174 SCTP_TCB_SEND_UNLOCK(stcb);
180 static struct sctp_stream_out *
181 sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
182 struct sctp_association *asoc)
184 struct sctp_stream_out *strq, *strqt;
186 if (asoc->ss_data.locked_on_sending) {
187 return (asoc->ss_data.locked_on_sending);
189 strqt = asoc->ss_data.last_out_stream;
191 /* Find the next stream to use */
193 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
195 strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
197 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
202 * If CMT is off, we must validate that the stream in question has
203 * the first item pointed towards are network destination requested
204 * by the caller. Note that if we turn out to be locked to a stream
205 * (assigning TSN's then we must stop, since we cannot look for
206 * another stream with data to send to that destination). In CMT's
207 * case, by skipping this check, we will send one data packet
208 * towards the requested net.
210 if (net != NULL && strq != NULL &&
211 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
212 if (TAILQ_FIRST(&strq->outqueue) &&
213 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
214 TAILQ_FIRST(&strq->outqueue)->net != net) {
215 if (strq == asoc->ss_data.last_out_stream) {
227 sctp_ss_default_scheduled(struct sctp_tcb *stcb,
228 struct sctp_nets *net SCTP_UNUSED,
229 struct sctp_association *asoc,
230 struct sctp_stream_out *strq,
231 int moved_how_much SCTP_UNUSED)
233 struct sctp_stream_queue_pending *sp;
235 asoc->ss_data.last_out_stream = strq;
236 if (stcb->asoc.idata_supported == 0) {
237 sp = TAILQ_FIRST(&strq->outqueue);
238 if ((sp != NULL) && (sp->some_taken == 1)) {
239 stcb->asoc.ss_data.locked_on_sending = strq;
241 stcb->asoc.ss_data.locked_on_sending = NULL;
244 stcb->asoc.ss_data.locked_on_sending = NULL;
250 sctp_ss_default_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
251 struct sctp_association *asoc SCTP_UNUSED)
253 /* Nothing to be done here */
258 sctp_ss_default_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
259 struct sctp_stream_out *strq SCTP_UNUSED, uint16_t *value SCTP_UNUSED)
261 /* Nothing to be done here */
266 sctp_ss_default_set_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
267 struct sctp_stream_out *strq SCTP_UNUSED, uint16_t value SCTP_UNUSED)
269 /* Nothing to be done here */
274 sctp_ss_default_is_user_msgs_incomplete(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
276 struct sctp_stream_out *strq;
277 struct sctp_stream_queue_pending *sp;
279 if (asoc->stream_queue_cnt != 1) {
282 strq = asoc->ss_data.locked_on_sending;
286 sp = TAILQ_FIRST(&strq->outqueue);
290 return (!sp->msg_is_complete);
294 * Real round-robin algorithm.
295 * Always interates the streams in ascending order.
298 sctp_ss_rr_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
299 struct sctp_stream_out *strq,
300 struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock)
302 struct sctp_stream_out *strqt;
304 if (holds_lock == 0) {
305 SCTP_TCB_SEND_LOCK(stcb);
307 if (!TAILQ_EMPTY(&strq->outqueue) &&
308 (strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
309 (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
310 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
311 TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
313 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
314 while (strqt != NULL && (strqt->sid < strq->sid)) {
315 strqt = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
318 TAILQ_INSERT_BEFORE(strqt, strq, ss_params.rr.next_spoke);
320 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
324 if (holds_lock == 0) {
325 SCTP_TCB_SEND_UNLOCK(stcb);
331 * Real round-robin per packet algorithm.
332 * Always interates the streams in ascending order and
333 * only fills messages of the same stream in a packet.
335 static struct sctp_stream_out *
336 sctp_ss_rrp_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
337 struct sctp_association *asoc)
339 return (asoc->ss_data.last_out_stream);
343 sctp_ss_rrp_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
344 struct sctp_association *asoc)
346 struct sctp_stream_out *strq, *strqt;
348 strqt = asoc->ss_data.last_out_stream;
350 /* Find the next stream to use */
352 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
354 strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
356 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
361 * If CMT is off, we must validate that the stream in question has
362 * the first item pointed towards are network destination requested
363 * by the caller. Note that if we turn out to be locked to a stream
364 * (assigning TSN's then we must stop, since we cannot look for
365 * another stream with data to send to that destination). In CMT's
366 * case, by skipping this check, we will send one data packet
367 * towards the requested net.
369 if (net != NULL && strq != NULL &&
370 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
371 if (TAILQ_FIRST(&strq->outqueue) &&
372 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
373 TAILQ_FIRST(&strq->outqueue)->net != net) {
374 if (strq == asoc->ss_data.last_out_stream) {
382 asoc->ss_data.last_out_stream = strq;
388 * Priority algorithm.
389 * Always prefers streams based on their priority id.
392 sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
393 int clear_values, int holds_lock)
395 if (holds_lock == 0) {
396 SCTP_TCB_SEND_LOCK(stcb);
398 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
399 struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
402 strq->ss_params.prio.priority = 0;
404 TAILQ_REMOVE(&asoc->ss_data.out.wheel, TAILQ_FIRST(&asoc->ss_data.out.wheel), ss_params.prio.next_spoke);
405 strq->ss_params.prio.next_spoke.tqe_next = NULL;
406 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
409 asoc->ss_data.last_out_stream = NULL;
410 if (holds_lock == 0) {
411 SCTP_TCB_SEND_UNLOCK(stcb);
417 sctp_ss_prio_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
419 if (with_strq != NULL) {
420 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
421 stcb->asoc.ss_data.locked_on_sending = strq;
423 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
424 stcb->asoc.ss_data.last_out_stream = strq;
427 strq->ss_params.prio.next_spoke.tqe_next = NULL;
428 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
429 if (with_strq != NULL) {
430 strq->ss_params.prio.priority = with_strq->ss_params.prio.priority;
432 strq->ss_params.prio.priority = 0;
438 sctp_ss_prio_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
439 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
442 struct sctp_stream_out *strqt;
444 if (holds_lock == 0) {
445 SCTP_TCB_SEND_LOCK(stcb);
447 /* Add to wheel if not already on it and stream queue not empty */
448 if (!TAILQ_EMPTY(&strq->outqueue) &&
449 (strq->ss_params.prio.next_spoke.tqe_next == NULL) &&
450 (strq->ss_params.prio.next_spoke.tqe_prev == NULL)) {
451 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
452 TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
454 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
455 while (strqt != NULL && strqt->ss_params.prio.priority < strq->ss_params.prio.priority) {
456 strqt = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
459 TAILQ_INSERT_BEFORE(strqt, strq, ss_params.prio.next_spoke);
461 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
465 if (holds_lock == 0) {
466 SCTP_TCB_SEND_UNLOCK(stcb);
472 sctp_ss_prio_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
473 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
476 if (holds_lock == 0) {
477 SCTP_TCB_SEND_LOCK(stcb);
480 * Remove from wheel if stream queue is empty and actually is on the
483 if (TAILQ_EMPTY(&strq->outqueue) &&
484 (strq->ss_params.prio.next_spoke.tqe_next != NULL ||
485 strq->ss_params.prio.next_spoke.tqe_prev != NULL)) {
486 if (asoc->ss_data.last_out_stream == strq) {
487 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead,
488 ss_params.prio.next_spoke);
489 if (asoc->ss_data.last_out_stream == NULL) {
490 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
493 if (asoc->ss_data.last_out_stream == strq) {
494 asoc->ss_data.last_out_stream = NULL;
497 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
498 strq->ss_params.prio.next_spoke.tqe_next = NULL;
499 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
501 if (holds_lock == 0) {
502 SCTP_TCB_SEND_UNLOCK(stcb);
507 static struct sctp_stream_out *
508 sctp_ss_prio_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
509 struct sctp_association *asoc)
511 struct sctp_stream_out *strq, *strqt, *strqn;
513 strqt = asoc->ss_data.last_out_stream;
515 /* Find the next stream to use */
517 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
519 strqn = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
521 strqn->ss_params.prio.priority == strqt->ss_params.prio.priority) {
524 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
529 * If CMT is off, we must validate that the stream in question has
530 * the first item pointed towards are network destination requested
531 * by the caller. Note that if we turn out to be locked to a stream
532 * (assigning TSN's then we must stop, since we cannot look for
533 * another stream with data to send to that destination). In CMT's
534 * case, by skipping this check, we will send one data packet
535 * towards the requested net.
537 if (net != NULL && strq != NULL &&
538 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
539 if (TAILQ_FIRST(&strq->outqueue) &&
540 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
541 TAILQ_FIRST(&strq->outqueue)->net != net) {
542 if (strq == asoc->ss_data.last_out_stream) {
554 sctp_ss_prio_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
555 struct sctp_stream_out *strq, uint16_t *value)
560 *value = strq->ss_params.prio.priority;
565 sctp_ss_prio_set_value(struct sctp_tcb *stcb, struct sctp_association *asoc,
566 struct sctp_stream_out *strq, uint16_t value)
571 strq->ss_params.prio.priority = value;
572 sctp_ss_prio_remove(stcb, asoc, strq, NULL, 1);
573 sctp_ss_prio_add(stcb, asoc, strq, NULL, 1);
578 * Fair bandwidth algorithm.
579 * Maintains an equal troughput per stream.
582 sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
583 int clear_values, int holds_lock)
585 if (holds_lock == 0) {
586 SCTP_TCB_SEND_LOCK(stcb);
588 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
589 struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
592 strq->ss_params.fb.rounds = -1;
594 TAILQ_REMOVE(&asoc->ss_data.out.wheel, TAILQ_FIRST(&asoc->ss_data.out.wheel), ss_params.fb.next_spoke);
595 strq->ss_params.fb.next_spoke.tqe_next = NULL;
596 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
598 asoc->ss_data.last_out_stream = NULL;
599 if (holds_lock == 0) {
600 SCTP_TCB_SEND_UNLOCK(stcb);
606 sctp_ss_fb_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
608 if (with_strq != NULL) {
609 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
610 stcb->asoc.ss_data.locked_on_sending = strq;
612 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
613 stcb->asoc.ss_data.last_out_stream = strq;
616 strq->ss_params.fb.next_spoke.tqe_next = NULL;
617 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
618 if (with_strq != NULL) {
619 strq->ss_params.fb.rounds = with_strq->ss_params.fb.rounds;
621 strq->ss_params.fb.rounds = -1;
627 sctp_ss_fb_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
628 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
631 if (holds_lock == 0) {
632 SCTP_TCB_SEND_LOCK(stcb);
634 if (!TAILQ_EMPTY(&strq->outqueue) &&
635 (strq->ss_params.fb.next_spoke.tqe_next == NULL) &&
636 (strq->ss_params.fb.next_spoke.tqe_prev == NULL)) {
637 if (strq->ss_params.fb.rounds < 0)
638 strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
639 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
641 if (holds_lock == 0) {
642 SCTP_TCB_SEND_UNLOCK(stcb);
648 sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
649 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
652 if (holds_lock == 0) {
653 SCTP_TCB_SEND_LOCK(stcb);
656 * Remove from wheel if stream queue is empty and actually is on the
659 if (TAILQ_EMPTY(&strq->outqueue) &&
660 (strq->ss_params.fb.next_spoke.tqe_next != NULL ||
661 strq->ss_params.fb.next_spoke.tqe_prev != NULL)) {
662 if (asoc->ss_data.last_out_stream == strq) {
663 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead,
664 ss_params.fb.next_spoke);
665 if (asoc->ss_data.last_out_stream == NULL) {
666 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
669 if (asoc->ss_data.last_out_stream == strq) {
670 asoc->ss_data.last_out_stream = NULL;
673 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
674 strq->ss_params.fb.next_spoke.tqe_next = NULL;
675 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
677 if (holds_lock == 0) {
678 SCTP_TCB_SEND_UNLOCK(stcb);
683 static struct sctp_stream_out *
684 sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
685 struct sctp_association *asoc)
687 struct sctp_stream_out *strq = NULL, *strqt;
689 if (asoc->ss_data.last_out_stream == NULL ||
690 TAILQ_FIRST(&asoc->ss_data.out.wheel) == TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead)) {
691 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
693 strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.fb.next_spoke);
696 if ((strqt != NULL) &&
697 ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) > 0) ||
698 (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0 &&
699 (net == NULL || (TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net == NULL) ||
700 (net != NULL && TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net != NULL &&
701 TAILQ_FIRST(&strqt->outqueue)->net == net))))) {
702 if ((strqt->ss_params.fb.rounds >= 0) && (strq == NULL ||
703 strqt->ss_params.fb.rounds < strq->ss_params.fb.rounds)) {
708 strqt = TAILQ_NEXT(strqt, ss_params.fb.next_spoke);
710 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
712 } while (strqt != strq);
717 sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED,
718 struct sctp_association *asoc, struct sctp_stream_out *strq,
719 int moved_how_much SCTP_UNUSED)
721 struct sctp_stream_queue_pending *sp;
722 struct sctp_stream_out *strqt;
725 if (stcb->asoc.idata_supported == 0) {
726 sp = TAILQ_FIRST(&strq->outqueue);
727 if ((sp != NULL) && (sp->some_taken == 1)) {
728 stcb->asoc.ss_data.locked_on_sending = strq;
730 stcb->asoc.ss_data.locked_on_sending = NULL;
733 stcb->asoc.ss_data.locked_on_sending = NULL;
735 subtract = strq->ss_params.fb.rounds;
736 TAILQ_FOREACH(strqt, &asoc->ss_data.out.wheel, ss_params.fb.next_spoke) {
737 strqt->ss_params.fb.rounds -= subtract;
738 if (strqt->ss_params.fb.rounds < 0)
739 strqt->ss_params.fb.rounds = 0;
741 if (TAILQ_FIRST(&strq->outqueue)) {
742 strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
744 strq->ss_params.fb.rounds = -1;
746 asoc->ss_data.last_out_stream = strq;
751 * First-come, first-serve algorithm.
752 * Maintains the order provided by the application.
755 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
756 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp,
760 sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
763 uint32_t x, n = 0, add_more = 1;
764 struct sctp_stream_queue_pending *sp;
767 TAILQ_INIT(&asoc->ss_data.out.list);
769 * If there is data in the stream queues already, the scheduler of
770 * an existing association has been changed. We can only cycle
771 * through the stream queues and add everything to the FCFS queue.
775 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
776 sp = TAILQ_FIRST(&stcb->asoc.strmout[i].outqueue);
778 /* Find n. message in current stream queue */
779 while (sp != NULL && x < n) {
780 sp = TAILQ_NEXT(sp, next);
784 sctp_ss_fcfs_add(stcb, &stcb->asoc, &stcb->asoc.strmout[i], sp, holds_lock);
794 sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
795 int clear_values, int holds_lock)
797 struct sctp_stream_queue_pending *sp;
800 if (holds_lock == 0) {
801 SCTP_TCB_SEND_LOCK(stcb);
803 while (!TAILQ_EMPTY(&asoc->ss_data.out.list)) {
804 sp = TAILQ_FIRST(&asoc->ss_data.out.list);
805 TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
806 sp->ss_next.tqe_next = NULL;
807 sp->ss_next.tqe_prev = NULL;
809 if (holds_lock == 0) {
810 SCTP_TCB_SEND_UNLOCK(stcb);
817 sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
819 if (with_strq != NULL) {
820 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
821 stcb->asoc.ss_data.locked_on_sending = strq;
823 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
824 stcb->asoc.ss_data.last_out_stream = strq;
831 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
832 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
835 if (holds_lock == 0) {
836 SCTP_TCB_SEND_LOCK(stcb);
838 if (sp && (sp->ss_next.tqe_next == NULL) &&
839 (sp->ss_next.tqe_prev == NULL)) {
840 TAILQ_INSERT_TAIL(&asoc->ss_data.out.list, sp, ss_next);
842 if (holds_lock == 0) {
843 SCTP_TCB_SEND_UNLOCK(stcb);
849 sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
851 if (TAILQ_EMPTY(&asoc->ss_data.out.list)) {
859 sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
860 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
863 if (holds_lock == 0) {
864 SCTP_TCB_SEND_LOCK(stcb);
867 ((sp->ss_next.tqe_next != NULL) ||
868 (sp->ss_next.tqe_prev != NULL))) {
869 TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
870 sp->ss_next.tqe_next = NULL;
871 sp->ss_next.tqe_prev = NULL;
873 if (holds_lock == 0) {
874 SCTP_TCB_SEND_UNLOCK(stcb);
880 static struct sctp_stream_out *
881 sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
882 struct sctp_association *asoc)
884 struct sctp_stream_out *strq;
885 struct sctp_stream_queue_pending *sp;
887 sp = TAILQ_FIRST(&asoc->ss_data.out.list);
890 strq = &asoc->strmout[sp->sid];
896 * If CMT is off, we must validate that the stream in question has
897 * the first item pointed towards are network destination requested
898 * by the caller. Note that if we turn out to be locked to a stream
899 * (assigning TSN's then we must stop, since we cannot look for
900 * another stream with data to send to that destination). In CMT's
901 * case, by skipping this check, we will send one data packet
902 * towards the requested net.
904 if (net != NULL && strq != NULL &&
905 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
906 if (TAILQ_FIRST(&strq->outqueue) &&
907 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
908 TAILQ_FIRST(&strq->outqueue)->net != net) {
909 sp = TAILQ_NEXT(sp, ss_next);
916 const struct sctp_ss_functions sctp_ss_functions[] = {
917 /* SCTP_SS_DEFAULT */
919 .sctp_ss_init = sctp_ss_default_init,
920 .sctp_ss_clear = sctp_ss_default_clear,
921 .sctp_ss_init_stream = sctp_ss_default_init_stream,
922 .sctp_ss_add_to_stream = sctp_ss_default_add,
923 .sctp_ss_is_empty = sctp_ss_default_is_empty,
924 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
925 .sctp_ss_select_stream = sctp_ss_default_select,
926 .sctp_ss_scheduled = sctp_ss_default_scheduled,
927 .sctp_ss_packet_done = sctp_ss_default_packet_done,
928 .sctp_ss_get_value = sctp_ss_default_get_value,
929 .sctp_ss_set_value = sctp_ss_default_set_value,
930 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
932 /* SCTP_SS_ROUND_ROBIN */
934 .sctp_ss_init = sctp_ss_default_init,
935 .sctp_ss_clear = sctp_ss_default_clear,
936 .sctp_ss_init_stream = sctp_ss_default_init_stream,
937 .sctp_ss_add_to_stream = sctp_ss_rr_add,
938 .sctp_ss_is_empty = sctp_ss_default_is_empty,
939 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
940 .sctp_ss_select_stream = sctp_ss_default_select,
941 .sctp_ss_scheduled = sctp_ss_default_scheduled,
942 .sctp_ss_packet_done = sctp_ss_default_packet_done,
943 .sctp_ss_get_value = sctp_ss_default_get_value,
944 .sctp_ss_set_value = sctp_ss_default_set_value,
945 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
947 /* SCTP_SS_ROUND_ROBIN_PACKET */
949 .sctp_ss_init = sctp_ss_default_init,
950 .sctp_ss_clear = sctp_ss_default_clear,
951 .sctp_ss_init_stream = sctp_ss_default_init_stream,
952 .sctp_ss_add_to_stream = sctp_ss_rr_add,
953 .sctp_ss_is_empty = sctp_ss_default_is_empty,
954 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
955 .sctp_ss_select_stream = sctp_ss_rrp_select,
956 .sctp_ss_scheduled = sctp_ss_default_scheduled,
957 .sctp_ss_packet_done = sctp_ss_rrp_packet_done,
958 .sctp_ss_get_value = sctp_ss_default_get_value,
959 .sctp_ss_set_value = sctp_ss_default_set_value,
960 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
962 /* SCTP_SS_PRIORITY */
964 .sctp_ss_init = sctp_ss_default_init,
965 .sctp_ss_clear = sctp_ss_prio_clear,
966 .sctp_ss_init_stream = sctp_ss_prio_init_stream,
967 .sctp_ss_add_to_stream = sctp_ss_prio_add,
968 .sctp_ss_is_empty = sctp_ss_default_is_empty,
969 .sctp_ss_remove_from_stream = sctp_ss_prio_remove,
970 .sctp_ss_select_stream = sctp_ss_prio_select,
971 .sctp_ss_scheduled = sctp_ss_default_scheduled,
972 .sctp_ss_packet_done = sctp_ss_default_packet_done,
973 .sctp_ss_get_value = sctp_ss_prio_get_value,
974 .sctp_ss_set_value = sctp_ss_prio_set_value,
975 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
977 /* SCTP_SS_FAIR_BANDWITH */
979 .sctp_ss_init = sctp_ss_default_init,
980 .sctp_ss_clear = sctp_ss_fb_clear,
981 .sctp_ss_init_stream = sctp_ss_fb_init_stream,
982 .sctp_ss_add_to_stream = sctp_ss_fb_add,
983 .sctp_ss_is_empty = sctp_ss_default_is_empty,
984 .sctp_ss_remove_from_stream = sctp_ss_fb_remove,
985 .sctp_ss_select_stream = sctp_ss_fb_select,
986 .sctp_ss_scheduled = sctp_ss_fb_scheduled,
987 .sctp_ss_packet_done = sctp_ss_default_packet_done,
988 .sctp_ss_get_value = sctp_ss_default_get_value,
989 .sctp_ss_set_value = sctp_ss_default_set_value,
990 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
992 /* SCTP_SS_FIRST_COME */
994 .sctp_ss_init = sctp_ss_fcfs_init,
995 .sctp_ss_clear = sctp_ss_fcfs_clear,
996 .sctp_ss_init_stream = sctp_ss_fcfs_init_stream,
997 .sctp_ss_add_to_stream = sctp_ss_fcfs_add,
998 .sctp_ss_is_empty = sctp_ss_fcfs_is_empty,
999 .sctp_ss_remove_from_stream = sctp_ss_fcfs_remove,
1000 .sctp_ss_select_stream = sctp_ss_fcfs_select,
1001 .sctp_ss_scheduled = sctp_ss_default_scheduled,
1002 .sctp_ss_packet_done = sctp_ss_default_packet_done,
1003 .sctp_ss_get_value = sctp_ss_default_get_value,
1004 .sctp_ss_set_value = sctp_ss_default_set_value,
1005 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete