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 if (holds_lock == 0) {
58 SCTP_TCB_SEND_LOCK(stcb);
60 asoc->ss_data.locked_on_sending = NULL;
61 asoc->ss_data.last_out_stream = NULL;
62 TAILQ_INIT(&asoc->ss_data.out.wheel);
64 * If there is data in the stream queues already, the scheduler of
65 * an existing association has been changed. We need to add all
66 * stream queues to the wheel.
68 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
69 stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, &stcb->asoc,
70 &stcb->asoc.strmout[i],
73 if (holds_lock == 0) {
74 SCTP_TCB_SEND_UNLOCK(stcb);
80 sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
81 int clear_values SCTP_UNUSED, int holds_lock)
83 if (holds_lock == 0) {
84 SCTP_TCB_SEND_LOCK(stcb);
86 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
87 struct sctp_stream_out *strq;
89 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
90 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
91 strq->ss_params.rr.next_spoke.tqe_next = NULL;
92 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
94 asoc->ss_data.last_out_stream = NULL;
95 if (holds_lock == 0) {
96 SCTP_TCB_SEND_UNLOCK(stcb);
102 sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
104 if (with_strq != NULL) {
105 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
106 stcb->asoc.ss_data.locked_on_sending = strq;
108 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
109 stcb->asoc.ss_data.last_out_stream = strq;
112 strq->ss_params.rr.next_spoke.tqe_next = NULL;
113 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
118 sctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
119 struct sctp_stream_out *strq,
120 struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock)
122 if (holds_lock == 0) {
123 SCTP_TCB_SEND_LOCK(stcb);
125 /* Add to wheel if not already on it and stream queue not empty */
126 if (!TAILQ_EMPTY(&strq->outqueue) &&
127 (strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
128 (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
129 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel,
130 strq, ss_params.rr.next_spoke);
132 if (holds_lock == 0) {
133 SCTP_TCB_SEND_UNLOCK(stcb);
139 sctp_ss_default_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
141 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
149 sctp_ss_default_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
150 struct sctp_stream_out *strq,
151 struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock)
153 if (holds_lock == 0) {
154 SCTP_TCB_SEND_LOCK(stcb);
157 * Remove from wheel if stream queue is empty and actually is on the
160 if (TAILQ_EMPTY(&strq->outqueue) &&
161 (strq->ss_params.rr.next_spoke.tqe_next != NULL ||
162 strq->ss_params.rr.next_spoke.tqe_prev != NULL)) {
163 if (asoc->ss_data.last_out_stream == strq) {
164 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream,
166 ss_params.rr.next_spoke);
167 if (asoc->ss_data.last_out_stream == NULL) {
168 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
171 if (asoc->ss_data.last_out_stream == strq) {
172 asoc->ss_data.last_out_stream = NULL;
175 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
176 strq->ss_params.rr.next_spoke.tqe_next = NULL;
177 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
179 if (holds_lock == 0) {
180 SCTP_TCB_SEND_UNLOCK(stcb);
186 static struct sctp_stream_out *
187 sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
188 struct sctp_association *asoc)
190 struct sctp_stream_out *strq, *strqt;
192 if (asoc->ss_data.locked_on_sending) {
193 return (asoc->ss_data.locked_on_sending);
195 strqt = asoc->ss_data.last_out_stream;
197 /* Find the next stream to use */
199 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
201 strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
203 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
208 * If CMT is off, we must validate that the stream in question has
209 * the first item pointed towards are network destination requested
210 * by the caller. Note that if we turn out to be locked to a stream
211 * (assigning TSN's then we must stop, since we cannot look for
212 * another stream with data to send to that destination). In CMT's
213 * case, by skipping this check, we will send one data packet
214 * towards the requested net.
216 if (net != NULL && strq != NULL &&
217 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
218 if (TAILQ_FIRST(&strq->outqueue) &&
219 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
220 TAILQ_FIRST(&strq->outqueue)->net != net) {
221 if (strq == asoc->ss_data.last_out_stream) {
233 sctp_ss_default_scheduled(struct sctp_tcb *stcb,
234 struct sctp_nets *net SCTP_UNUSED,
235 struct sctp_association *asoc,
236 struct sctp_stream_out *strq,
237 int moved_how_much SCTP_UNUSED)
239 struct sctp_stream_queue_pending *sp;
241 asoc->ss_data.last_out_stream = strq;
242 if (stcb->asoc.idata_supported == 0) {
243 sp = TAILQ_FIRST(&strq->outqueue);
244 if ((sp != NULL) && (sp->some_taken == 1)) {
245 stcb->asoc.ss_data.locked_on_sending = strq;
247 stcb->asoc.ss_data.locked_on_sending = NULL;
250 stcb->asoc.ss_data.locked_on_sending = NULL;
256 sctp_ss_default_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
257 struct sctp_association *asoc SCTP_UNUSED)
259 /* Nothing to be done here */
264 sctp_ss_default_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
265 struct sctp_stream_out *strq SCTP_UNUSED, uint16_t *value SCTP_UNUSED)
267 /* Nothing to be done here */
272 sctp_ss_default_set_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
273 struct sctp_stream_out *strq SCTP_UNUSED, uint16_t value SCTP_UNUSED)
275 /* Nothing to be done here */
280 sctp_ss_default_is_user_msgs_incomplete(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
282 struct sctp_stream_out *strq;
283 struct sctp_stream_queue_pending *sp;
285 if (asoc->stream_queue_cnt != 1) {
288 strq = asoc->ss_data.locked_on_sending;
292 sp = TAILQ_FIRST(&strq->outqueue);
296 return (!sp->msg_is_complete);
300 * Real round-robin algorithm.
301 * Always interates the streams in ascending order.
304 sctp_ss_rr_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
305 struct sctp_stream_out *strq,
306 struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock)
308 struct sctp_stream_out *strqt;
310 if (holds_lock == 0) {
311 SCTP_TCB_SEND_LOCK(stcb);
313 if (!TAILQ_EMPTY(&strq->outqueue) &&
314 (strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
315 (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
316 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
317 TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
319 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
320 while (strqt != NULL && (strqt->sid < strq->sid)) {
321 strqt = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
324 TAILQ_INSERT_BEFORE(strqt, strq, ss_params.rr.next_spoke);
326 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
330 if (holds_lock == 0) {
331 SCTP_TCB_SEND_UNLOCK(stcb);
337 * Real round-robin per packet algorithm.
338 * Always interates the streams in ascending order and
339 * only fills messages of the same stream in a packet.
341 static struct sctp_stream_out *
342 sctp_ss_rrp_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
343 struct sctp_association *asoc)
345 return (asoc->ss_data.last_out_stream);
349 sctp_ss_rrp_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
350 struct sctp_association *asoc)
352 struct sctp_stream_out *strq, *strqt;
354 strqt = asoc->ss_data.last_out_stream;
356 /* Find the next stream to use */
358 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
360 strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
362 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
367 * If CMT is off, we must validate that the stream in question has
368 * the first item pointed towards are network destination requested
369 * by the caller. Note that if we turn out to be locked to a stream
370 * (assigning TSN's then we must stop, since we cannot look for
371 * another stream with data to send to that destination). In CMT's
372 * case, by skipping this check, we will send one data packet
373 * towards the requested net.
375 if (net != NULL && strq != NULL &&
376 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
377 if (TAILQ_FIRST(&strq->outqueue) &&
378 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
379 TAILQ_FIRST(&strq->outqueue)->net != net) {
380 if (strq == asoc->ss_data.last_out_stream) {
388 asoc->ss_data.last_out_stream = strq;
394 * Priority algorithm.
395 * Always prefers streams based on their priority id.
398 sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
399 int clear_values, int holds_lock)
401 if (holds_lock == 0) {
402 SCTP_TCB_SEND_LOCK(stcb);
404 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
405 struct sctp_stream_out *strq;
407 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
409 strq->ss_params.prio.priority = 0;
411 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
412 strq->ss_params.prio.next_spoke.tqe_next = NULL;
413 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
416 asoc->ss_data.last_out_stream = NULL;
417 if (holds_lock == 0) {
418 SCTP_TCB_SEND_UNLOCK(stcb);
424 sctp_ss_prio_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
426 if (with_strq != NULL) {
427 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
428 stcb->asoc.ss_data.locked_on_sending = strq;
430 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
431 stcb->asoc.ss_data.last_out_stream = strq;
434 strq->ss_params.prio.next_spoke.tqe_next = NULL;
435 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
436 if (with_strq != NULL) {
437 strq->ss_params.prio.priority = with_strq->ss_params.prio.priority;
439 strq->ss_params.prio.priority = 0;
445 sctp_ss_prio_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
446 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
449 struct sctp_stream_out *strqt;
451 if (holds_lock == 0) {
452 SCTP_TCB_SEND_LOCK(stcb);
454 /* Add to wheel if not already on it and stream queue not empty */
455 if (!TAILQ_EMPTY(&strq->outqueue) &&
456 (strq->ss_params.prio.next_spoke.tqe_next == NULL) &&
457 (strq->ss_params.prio.next_spoke.tqe_prev == NULL)) {
458 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
459 TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
461 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
462 while (strqt != NULL && strqt->ss_params.prio.priority < strq->ss_params.prio.priority) {
463 strqt = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
466 TAILQ_INSERT_BEFORE(strqt, strq, ss_params.prio.next_spoke);
468 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
472 if (holds_lock == 0) {
473 SCTP_TCB_SEND_UNLOCK(stcb);
479 sctp_ss_prio_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
480 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
483 if (holds_lock == 0) {
484 SCTP_TCB_SEND_LOCK(stcb);
487 * Remove from wheel if stream queue is empty and actually is on the
490 if (TAILQ_EMPTY(&strq->outqueue) &&
491 (strq->ss_params.prio.next_spoke.tqe_next != NULL ||
492 strq->ss_params.prio.next_spoke.tqe_prev != NULL)) {
493 if (asoc->ss_data.last_out_stream == strq) {
494 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead,
495 ss_params.prio.next_spoke);
496 if (asoc->ss_data.last_out_stream == NULL) {
497 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
500 if (asoc->ss_data.last_out_stream == strq) {
501 asoc->ss_data.last_out_stream = NULL;
504 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
505 strq->ss_params.prio.next_spoke.tqe_next = NULL;
506 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
508 if (holds_lock == 0) {
509 SCTP_TCB_SEND_UNLOCK(stcb);
514 static struct sctp_stream_out *
515 sctp_ss_prio_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
516 struct sctp_association *asoc)
518 struct sctp_stream_out *strq, *strqt, *strqn;
520 strqt = asoc->ss_data.last_out_stream;
522 /* Find the next stream to use */
524 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
526 strqn = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
528 strqn->ss_params.prio.priority == strqt->ss_params.prio.priority) {
531 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
536 * If CMT is off, we must validate that the stream in question has
537 * the first item pointed towards are network destination requested
538 * by the caller. Note that if we turn out to be locked to a stream
539 * (assigning TSN's then we must stop, since we cannot look for
540 * another stream with data to send to that destination). In CMT's
541 * case, by skipping this check, we will send one data packet
542 * towards the requested net.
544 if (net != NULL && strq != NULL &&
545 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
546 if (TAILQ_FIRST(&strq->outqueue) &&
547 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
548 TAILQ_FIRST(&strq->outqueue)->net != net) {
549 if (strq == asoc->ss_data.last_out_stream) {
561 sctp_ss_prio_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
562 struct sctp_stream_out *strq, uint16_t *value)
567 *value = strq->ss_params.prio.priority;
572 sctp_ss_prio_set_value(struct sctp_tcb *stcb, struct sctp_association *asoc,
573 struct sctp_stream_out *strq, uint16_t value)
578 strq->ss_params.prio.priority = value;
579 sctp_ss_prio_remove(stcb, asoc, strq, NULL, 1);
580 sctp_ss_prio_add(stcb, asoc, strq, NULL, 1);
585 * Fair bandwidth algorithm.
586 * Maintains an equal troughput per stream.
589 sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
590 int clear_values, int holds_lock)
592 if (holds_lock == 0) {
593 SCTP_TCB_SEND_LOCK(stcb);
595 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
596 struct sctp_stream_out *strq;
598 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
600 strq->ss_params.fb.rounds = -1;
602 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
603 strq->ss_params.fb.next_spoke.tqe_next = NULL;
604 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
606 asoc->ss_data.last_out_stream = NULL;
607 if (holds_lock == 0) {
608 SCTP_TCB_SEND_UNLOCK(stcb);
614 sctp_ss_fb_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
616 if (with_strq != NULL) {
617 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
618 stcb->asoc.ss_data.locked_on_sending = strq;
620 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
621 stcb->asoc.ss_data.last_out_stream = strq;
624 strq->ss_params.fb.next_spoke.tqe_next = NULL;
625 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
626 if (with_strq != NULL) {
627 strq->ss_params.fb.rounds = with_strq->ss_params.fb.rounds;
629 strq->ss_params.fb.rounds = -1;
635 sctp_ss_fb_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
636 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
639 if (holds_lock == 0) {
640 SCTP_TCB_SEND_LOCK(stcb);
642 if (!TAILQ_EMPTY(&strq->outqueue) &&
643 (strq->ss_params.fb.next_spoke.tqe_next == NULL) &&
644 (strq->ss_params.fb.next_spoke.tqe_prev == NULL)) {
645 if (strq->ss_params.fb.rounds < 0)
646 strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
647 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
649 if (holds_lock == 0) {
650 SCTP_TCB_SEND_UNLOCK(stcb);
656 sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
657 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
660 if (holds_lock == 0) {
661 SCTP_TCB_SEND_LOCK(stcb);
664 * Remove from wheel if stream queue is empty and actually is on the
667 if (TAILQ_EMPTY(&strq->outqueue) &&
668 (strq->ss_params.fb.next_spoke.tqe_next != NULL ||
669 strq->ss_params.fb.next_spoke.tqe_prev != NULL)) {
670 if (asoc->ss_data.last_out_stream == strq) {
671 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead,
672 ss_params.fb.next_spoke);
673 if (asoc->ss_data.last_out_stream == NULL) {
674 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
677 if (asoc->ss_data.last_out_stream == strq) {
678 asoc->ss_data.last_out_stream = NULL;
681 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
682 strq->ss_params.fb.next_spoke.tqe_next = NULL;
683 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
685 if (holds_lock == 0) {
686 SCTP_TCB_SEND_UNLOCK(stcb);
691 static struct sctp_stream_out *
692 sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
693 struct sctp_association *asoc)
695 struct sctp_stream_out *strq = NULL, *strqt;
697 if (asoc->ss_data.last_out_stream == NULL ||
698 TAILQ_FIRST(&asoc->ss_data.out.wheel) == TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead)) {
699 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
701 strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.fb.next_spoke);
704 if ((strqt != NULL) &&
705 ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) > 0) ||
706 (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0 &&
707 (net == NULL || (TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net == NULL) ||
708 (net != NULL && TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net != NULL &&
709 TAILQ_FIRST(&strqt->outqueue)->net == net))))) {
710 if ((strqt->ss_params.fb.rounds >= 0) && (strq == NULL ||
711 strqt->ss_params.fb.rounds < strq->ss_params.fb.rounds)) {
716 strqt = TAILQ_NEXT(strqt, ss_params.fb.next_spoke);
718 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
720 } while (strqt != strq);
725 sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED,
726 struct sctp_association *asoc, struct sctp_stream_out *strq,
727 int moved_how_much SCTP_UNUSED)
729 struct sctp_stream_queue_pending *sp;
730 struct sctp_stream_out *strqt;
733 if (stcb->asoc.idata_supported == 0) {
734 sp = TAILQ_FIRST(&strq->outqueue);
735 if ((sp != NULL) && (sp->some_taken == 1)) {
736 stcb->asoc.ss_data.locked_on_sending = strq;
738 stcb->asoc.ss_data.locked_on_sending = NULL;
741 stcb->asoc.ss_data.locked_on_sending = NULL;
743 subtract = strq->ss_params.fb.rounds;
744 TAILQ_FOREACH(strqt, &asoc->ss_data.out.wheel, ss_params.fb.next_spoke) {
745 strqt->ss_params.fb.rounds -= subtract;
746 if (strqt->ss_params.fb.rounds < 0)
747 strqt->ss_params.fb.rounds = 0;
749 if (TAILQ_FIRST(&strq->outqueue)) {
750 strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
752 strq->ss_params.fb.rounds = -1;
754 asoc->ss_data.last_out_stream = strq;
759 * First-come, first-serve algorithm.
760 * Maintains the order provided by the application.
763 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
764 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp,
768 sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
771 uint32_t x, n = 0, add_more = 1;
772 struct sctp_stream_queue_pending *sp;
775 if (holds_lock == 0) {
776 SCTP_TCB_SEND_LOCK(stcb);
778 TAILQ_INIT(&asoc->ss_data.out.list);
780 * If there is data in the stream queues already, the scheduler of
781 * an existing association has been changed. We can only cycle
782 * through the stream queues and add everything to the FCFS queue.
786 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
787 sp = TAILQ_FIRST(&stcb->asoc.strmout[i].outqueue);
789 /* Find n. message in current stream queue */
790 while (sp != NULL && x < n) {
791 sp = TAILQ_NEXT(sp, next);
795 sctp_ss_fcfs_add(stcb, &stcb->asoc, &stcb->asoc.strmout[i], sp, 1);
801 if (holds_lock == 0) {
802 SCTP_TCB_SEND_UNLOCK(stcb);
808 sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
809 int clear_values, int holds_lock)
811 struct sctp_stream_queue_pending *sp;
814 if (holds_lock == 0) {
815 SCTP_TCB_SEND_LOCK(stcb);
817 while (!TAILQ_EMPTY(&asoc->ss_data.out.list)) {
818 sp = TAILQ_FIRST(&asoc->ss_data.out.list);
819 TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
820 sp->ss_next.tqe_next = NULL;
821 sp->ss_next.tqe_prev = NULL;
823 if (holds_lock == 0) {
824 SCTP_TCB_SEND_UNLOCK(stcb);
831 sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
833 if (with_strq != NULL) {
834 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
835 stcb->asoc.ss_data.locked_on_sending = strq;
837 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
838 stcb->asoc.ss_data.last_out_stream = strq;
841 strq->ss_params.fb.next_spoke.tqe_next = NULL;
842 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
847 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
848 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
851 if (holds_lock == 0) {
852 SCTP_TCB_SEND_LOCK(stcb);
854 if (sp && (sp->ss_next.tqe_next == NULL) &&
855 (sp->ss_next.tqe_prev == NULL)) {
856 TAILQ_INSERT_TAIL(&asoc->ss_data.out.list, sp, ss_next);
858 if (holds_lock == 0) {
859 SCTP_TCB_SEND_UNLOCK(stcb);
865 sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
867 if (TAILQ_EMPTY(&asoc->ss_data.out.list)) {
875 sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
876 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
879 if (holds_lock == 0) {
880 SCTP_TCB_SEND_LOCK(stcb);
883 ((sp->ss_next.tqe_next != NULL) ||
884 (sp->ss_next.tqe_prev != NULL))) {
885 TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
886 sp->ss_next.tqe_next = NULL;
887 sp->ss_next.tqe_prev = NULL;
889 if (holds_lock == 0) {
890 SCTP_TCB_SEND_UNLOCK(stcb);
896 static struct sctp_stream_out *
897 sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
898 struct sctp_association *asoc)
900 struct sctp_stream_out *strq;
901 struct sctp_stream_queue_pending *sp;
903 sp = TAILQ_FIRST(&asoc->ss_data.out.list);
906 strq = &asoc->strmout[sp->sid];
912 * If CMT is off, we must validate that the stream in question has
913 * the first item pointed towards are network destination requested
914 * by the caller. Note that if we turn out to be locked to a stream
915 * (assigning TSN's then we must stop, since we cannot look for
916 * another stream with data to send to that destination). In CMT's
917 * case, by skipping this check, we will send one data packet
918 * towards the requested net.
920 if (net != NULL && strq != NULL &&
921 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
922 if (TAILQ_FIRST(&strq->outqueue) &&
923 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
924 TAILQ_FIRST(&strq->outqueue)->net != net) {
925 sp = TAILQ_NEXT(sp, ss_next);
932 const struct sctp_ss_functions sctp_ss_functions[] = {
933 /* SCTP_SS_DEFAULT */
935 .sctp_ss_init = sctp_ss_default_init,
936 .sctp_ss_clear = sctp_ss_default_clear,
937 .sctp_ss_init_stream = sctp_ss_default_init_stream,
938 .sctp_ss_add_to_stream = sctp_ss_default_add,
939 .sctp_ss_is_empty = sctp_ss_default_is_empty,
940 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
941 .sctp_ss_select_stream = sctp_ss_default_select,
942 .sctp_ss_scheduled = sctp_ss_default_scheduled,
943 .sctp_ss_packet_done = sctp_ss_default_packet_done,
944 .sctp_ss_get_value = sctp_ss_default_get_value,
945 .sctp_ss_set_value = sctp_ss_default_set_value,
946 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
948 /* SCTP_SS_ROUND_ROBIN */
950 .sctp_ss_init = sctp_ss_default_init,
951 .sctp_ss_clear = sctp_ss_default_clear,
952 .sctp_ss_init_stream = sctp_ss_default_init_stream,
953 .sctp_ss_add_to_stream = sctp_ss_rr_add,
954 .sctp_ss_is_empty = sctp_ss_default_is_empty,
955 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
956 .sctp_ss_select_stream = sctp_ss_default_select,
957 .sctp_ss_scheduled = sctp_ss_default_scheduled,
958 .sctp_ss_packet_done = sctp_ss_default_packet_done,
959 .sctp_ss_get_value = sctp_ss_default_get_value,
960 .sctp_ss_set_value = sctp_ss_default_set_value,
961 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
963 /* SCTP_SS_ROUND_ROBIN_PACKET */
965 .sctp_ss_init = sctp_ss_default_init,
966 .sctp_ss_clear = sctp_ss_default_clear,
967 .sctp_ss_init_stream = sctp_ss_default_init_stream,
968 .sctp_ss_add_to_stream = sctp_ss_rr_add,
969 .sctp_ss_is_empty = sctp_ss_default_is_empty,
970 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
971 .sctp_ss_select_stream = sctp_ss_rrp_select,
972 .sctp_ss_scheduled = sctp_ss_default_scheduled,
973 .sctp_ss_packet_done = sctp_ss_rrp_packet_done,
974 .sctp_ss_get_value = sctp_ss_default_get_value,
975 .sctp_ss_set_value = sctp_ss_default_set_value,
976 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
978 /* SCTP_SS_PRIORITY */
980 .sctp_ss_init = sctp_ss_default_init,
981 .sctp_ss_clear = sctp_ss_prio_clear,
982 .sctp_ss_init_stream = sctp_ss_prio_init_stream,
983 .sctp_ss_add_to_stream = sctp_ss_prio_add,
984 .sctp_ss_is_empty = sctp_ss_default_is_empty,
985 .sctp_ss_remove_from_stream = sctp_ss_prio_remove,
986 .sctp_ss_select_stream = sctp_ss_prio_select,
987 .sctp_ss_scheduled = sctp_ss_default_scheduled,
988 .sctp_ss_packet_done = sctp_ss_default_packet_done,
989 .sctp_ss_get_value = sctp_ss_prio_get_value,
990 .sctp_ss_set_value = sctp_ss_prio_set_value,
991 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
993 /* SCTP_SS_FAIR_BANDWITH */
995 .sctp_ss_init = sctp_ss_default_init,
996 .sctp_ss_clear = sctp_ss_fb_clear,
997 .sctp_ss_init_stream = sctp_ss_fb_init_stream,
998 .sctp_ss_add_to_stream = sctp_ss_fb_add,
999 .sctp_ss_is_empty = sctp_ss_default_is_empty,
1000 .sctp_ss_remove_from_stream = sctp_ss_fb_remove,
1001 .sctp_ss_select_stream = sctp_ss_fb_select,
1002 .sctp_ss_scheduled = sctp_ss_fb_scheduled,
1003 .sctp_ss_packet_done = sctp_ss_default_packet_done,
1004 .sctp_ss_get_value = sctp_ss_default_get_value,
1005 .sctp_ss_set_value = sctp_ss_default_set_value,
1006 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
1008 /* SCTP_SS_FIRST_COME */
1010 .sctp_ss_init = sctp_ss_fcfs_init,
1011 .sctp_ss_clear = sctp_ss_fcfs_clear,
1012 .sctp_ss_init_stream = sctp_ss_fcfs_init_stream,
1013 .sctp_ss_add_to_stream = sctp_ss_fcfs_add,
1014 .sctp_ss_is_empty = sctp_ss_fcfs_is_empty,
1015 .sctp_ss_remove_from_stream = sctp_ss_fcfs_remove,
1016 .sctp_ss_select_stream = sctp_ss_fcfs_select,
1017 .sctp_ss_scheduled = sctp_ss_default_scheduled,
1018 .sctp_ss_packet_done = sctp_ss_default_packet_done,
1019 .sctp_ss_get_value = sctp_ss_default_get_value,
1020 .sctp_ss_set_value = sctp_ss_default_set_value,
1021 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete