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 if (asoc->ss_data.locked_on_sending) {
521 return (asoc->ss_data.locked_on_sending);
523 strqt = asoc->ss_data.last_out_stream;
525 /* Find the next stream to use */
527 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
529 strqn = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
531 strqn->ss_params.prio.priority == strqt->ss_params.prio.priority) {
534 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
539 * If CMT is off, we must validate that the stream in question has
540 * the first item pointed towards are network destination requested
541 * by the caller. Note that if we turn out to be locked to a stream
542 * (assigning TSN's then we must stop, since we cannot look for
543 * another stream with data to send to that destination). In CMT's
544 * case, by skipping this check, we will send one data packet
545 * towards the requested net.
547 if (net != NULL && strq != NULL &&
548 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
549 if (TAILQ_FIRST(&strq->outqueue) &&
550 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
551 TAILQ_FIRST(&strq->outqueue)->net != net) {
552 if (strq == asoc->ss_data.last_out_stream) {
564 sctp_ss_prio_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
565 struct sctp_stream_out *strq, uint16_t *value)
570 *value = strq->ss_params.prio.priority;
575 sctp_ss_prio_set_value(struct sctp_tcb *stcb, struct sctp_association *asoc,
576 struct sctp_stream_out *strq, uint16_t value)
581 strq->ss_params.prio.priority = value;
582 sctp_ss_prio_remove(stcb, asoc, strq, NULL, 1);
583 sctp_ss_prio_add(stcb, asoc, strq, NULL, 1);
588 * Fair bandwidth algorithm.
589 * Maintains an equal troughput per stream.
592 sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
593 int clear_values, int holds_lock)
595 if (holds_lock == 0) {
596 SCTP_TCB_SEND_LOCK(stcb);
598 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
599 struct sctp_stream_out *strq;
601 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
603 strq->ss_params.fb.rounds = -1;
605 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
606 strq->ss_params.fb.next_spoke.tqe_next = NULL;
607 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
609 asoc->ss_data.last_out_stream = NULL;
610 if (holds_lock == 0) {
611 SCTP_TCB_SEND_UNLOCK(stcb);
617 sctp_ss_fb_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
619 if (with_strq != NULL) {
620 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
621 stcb->asoc.ss_data.locked_on_sending = strq;
623 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
624 stcb->asoc.ss_data.last_out_stream = strq;
627 strq->ss_params.fb.next_spoke.tqe_next = NULL;
628 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
629 if (with_strq != NULL) {
630 strq->ss_params.fb.rounds = with_strq->ss_params.fb.rounds;
632 strq->ss_params.fb.rounds = -1;
638 sctp_ss_fb_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
639 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
642 if (holds_lock == 0) {
643 SCTP_TCB_SEND_LOCK(stcb);
645 if (!TAILQ_EMPTY(&strq->outqueue) &&
646 (strq->ss_params.fb.next_spoke.tqe_next == NULL) &&
647 (strq->ss_params.fb.next_spoke.tqe_prev == NULL)) {
648 if (strq->ss_params.fb.rounds < 0)
649 strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
650 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
652 if (holds_lock == 0) {
653 SCTP_TCB_SEND_UNLOCK(stcb);
659 sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
660 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
663 if (holds_lock == 0) {
664 SCTP_TCB_SEND_LOCK(stcb);
667 * Remove from wheel if stream queue is empty and actually is on the
670 if (TAILQ_EMPTY(&strq->outqueue) &&
671 (strq->ss_params.fb.next_spoke.tqe_next != NULL ||
672 strq->ss_params.fb.next_spoke.tqe_prev != NULL)) {
673 if (asoc->ss_data.last_out_stream == strq) {
674 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead,
675 ss_params.fb.next_spoke);
676 if (asoc->ss_data.last_out_stream == NULL) {
677 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
680 if (asoc->ss_data.last_out_stream == strq) {
681 asoc->ss_data.last_out_stream = NULL;
684 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
685 strq->ss_params.fb.next_spoke.tqe_next = NULL;
686 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
688 if (holds_lock == 0) {
689 SCTP_TCB_SEND_UNLOCK(stcb);
694 static struct sctp_stream_out *
695 sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
696 struct sctp_association *asoc)
698 struct sctp_stream_out *strq = NULL, *strqt;
700 if (asoc->ss_data.locked_on_sending) {
701 return (asoc->ss_data.locked_on_sending);
703 if (asoc->ss_data.last_out_stream == NULL ||
704 TAILQ_FIRST(&asoc->ss_data.out.wheel) == TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead)) {
705 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
707 strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.fb.next_spoke);
710 if ((strqt != NULL) &&
711 ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) > 0) ||
712 (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0 &&
713 (net == NULL || (TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net == NULL) ||
714 (net != NULL && TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net != NULL &&
715 TAILQ_FIRST(&strqt->outqueue)->net == net))))) {
716 if ((strqt->ss_params.fb.rounds >= 0) && (strq == NULL ||
717 strqt->ss_params.fb.rounds < strq->ss_params.fb.rounds)) {
722 strqt = TAILQ_NEXT(strqt, ss_params.fb.next_spoke);
724 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
726 } while (strqt != strq);
731 sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED,
732 struct sctp_association *asoc, struct sctp_stream_out *strq,
733 int moved_how_much SCTP_UNUSED)
735 struct sctp_stream_queue_pending *sp;
736 struct sctp_stream_out *strqt;
739 if (stcb->asoc.idata_supported == 0) {
740 sp = TAILQ_FIRST(&strq->outqueue);
741 if ((sp != NULL) && (sp->some_taken == 1)) {
742 stcb->asoc.ss_data.locked_on_sending = strq;
744 stcb->asoc.ss_data.locked_on_sending = NULL;
747 stcb->asoc.ss_data.locked_on_sending = NULL;
749 subtract = strq->ss_params.fb.rounds;
750 TAILQ_FOREACH(strqt, &asoc->ss_data.out.wheel, ss_params.fb.next_spoke) {
751 strqt->ss_params.fb.rounds -= subtract;
752 if (strqt->ss_params.fb.rounds < 0)
753 strqt->ss_params.fb.rounds = 0;
755 if (TAILQ_FIRST(&strq->outqueue)) {
756 strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
758 strq->ss_params.fb.rounds = -1;
760 asoc->ss_data.last_out_stream = strq;
765 * First-come, first-serve algorithm.
766 * Maintains the order provided by the application.
769 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
770 struct sctp_stream_out *strq SCTP_UNUSED,
771 struct sctp_stream_queue_pending *sp, int holds_lock);
774 sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
777 uint32_t x, n = 0, add_more = 1;
778 struct sctp_stream_queue_pending *sp;
781 if (holds_lock == 0) {
782 SCTP_TCB_SEND_LOCK(stcb);
784 TAILQ_INIT(&asoc->ss_data.out.list);
786 * If there is data in the stream queues already, the scheduler of
787 * an existing association has been changed. We can only cycle
788 * through the stream queues and add everything to the FCFS queue.
792 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
793 sp = TAILQ_FIRST(&stcb->asoc.strmout[i].outqueue);
795 /* Find n. message in current stream queue */
796 while (sp != NULL && x < n) {
797 sp = TAILQ_NEXT(sp, next);
801 sctp_ss_fcfs_add(stcb, &stcb->asoc, &stcb->asoc.strmout[i], sp, 1);
807 if (holds_lock == 0) {
808 SCTP_TCB_SEND_UNLOCK(stcb);
814 sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
815 int clear_values, int holds_lock)
817 struct sctp_stream_queue_pending *sp;
820 if (holds_lock == 0) {
821 SCTP_TCB_SEND_LOCK(stcb);
823 while (!TAILQ_EMPTY(&asoc->ss_data.out.list)) {
824 sp = TAILQ_FIRST(&asoc->ss_data.out.list);
825 TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
826 sp->ss_next.tqe_next = NULL;
827 sp->ss_next.tqe_prev = NULL;
829 if (holds_lock == 0) {
830 SCTP_TCB_SEND_UNLOCK(stcb);
837 sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
839 if (with_strq != NULL) {
840 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
841 stcb->asoc.ss_data.locked_on_sending = strq;
843 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
844 stcb->asoc.ss_data.last_out_stream = strq;
847 strq->ss_params.fb.next_spoke.tqe_next = NULL;
848 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
853 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
854 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
857 if (holds_lock == 0) {
858 SCTP_TCB_SEND_LOCK(stcb);
860 if (sp && (sp->ss_next.tqe_next == NULL) &&
861 (sp->ss_next.tqe_prev == NULL)) {
862 TAILQ_INSERT_TAIL(&asoc->ss_data.out.list, sp, ss_next);
864 if (holds_lock == 0) {
865 SCTP_TCB_SEND_UNLOCK(stcb);
871 sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
873 if (TAILQ_EMPTY(&asoc->ss_data.out.list)) {
881 sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
882 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
885 if (holds_lock == 0) {
886 SCTP_TCB_SEND_LOCK(stcb);
889 ((sp->ss_next.tqe_next != NULL) ||
890 (sp->ss_next.tqe_prev != NULL))) {
891 TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
892 sp->ss_next.tqe_next = NULL;
893 sp->ss_next.tqe_prev = NULL;
895 if (holds_lock == 0) {
896 SCTP_TCB_SEND_UNLOCK(stcb);
902 static struct sctp_stream_out *
903 sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
904 struct sctp_association *asoc)
906 struct sctp_stream_out *strq;
907 struct sctp_stream_queue_pending *sp;
909 if (asoc->ss_data.locked_on_sending) {
910 return (asoc->ss_data.locked_on_sending);
912 sp = TAILQ_FIRST(&asoc->ss_data.out.list);
915 strq = &asoc->strmout[sp->sid];
921 * If CMT is off, we must validate that the stream in question has
922 * the first item pointed towards are network destination requested
923 * by the caller. Note that if we turn out to be locked to a stream
924 * (assigning TSN's then we must stop, since we cannot look for
925 * another stream with data to send to that destination). In CMT's
926 * case, by skipping this check, we will send one data packet
927 * towards the requested net.
929 if (net != NULL && strq != NULL &&
930 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
931 if (TAILQ_FIRST(&strq->outqueue) &&
932 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
933 TAILQ_FIRST(&strq->outqueue)->net != net) {
934 sp = TAILQ_NEXT(sp, ss_next);
941 const struct sctp_ss_functions sctp_ss_functions[] = {
942 /* SCTP_SS_DEFAULT */
944 .sctp_ss_init = sctp_ss_default_init,
945 .sctp_ss_clear = sctp_ss_default_clear,
946 .sctp_ss_init_stream = sctp_ss_default_init_stream,
947 .sctp_ss_add_to_stream = sctp_ss_default_add,
948 .sctp_ss_is_empty = sctp_ss_default_is_empty,
949 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
950 .sctp_ss_select_stream = sctp_ss_default_select,
951 .sctp_ss_scheduled = sctp_ss_default_scheduled,
952 .sctp_ss_packet_done = sctp_ss_default_packet_done,
953 .sctp_ss_get_value = sctp_ss_default_get_value,
954 .sctp_ss_set_value = sctp_ss_default_set_value,
955 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
957 /* SCTP_SS_ROUND_ROBIN */
959 .sctp_ss_init = sctp_ss_default_init,
960 .sctp_ss_clear = sctp_ss_default_clear,
961 .sctp_ss_init_stream = sctp_ss_default_init_stream,
962 .sctp_ss_add_to_stream = sctp_ss_rr_add,
963 .sctp_ss_is_empty = sctp_ss_default_is_empty,
964 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
965 .sctp_ss_select_stream = sctp_ss_default_select,
966 .sctp_ss_scheduled = sctp_ss_default_scheduled,
967 .sctp_ss_packet_done = sctp_ss_default_packet_done,
968 .sctp_ss_get_value = sctp_ss_default_get_value,
969 .sctp_ss_set_value = sctp_ss_default_set_value,
970 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
972 /* SCTP_SS_ROUND_ROBIN_PACKET */
974 .sctp_ss_init = sctp_ss_default_init,
975 .sctp_ss_clear = sctp_ss_default_clear,
976 .sctp_ss_init_stream = sctp_ss_default_init_stream,
977 .sctp_ss_add_to_stream = sctp_ss_rr_add,
978 .sctp_ss_is_empty = sctp_ss_default_is_empty,
979 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
980 .sctp_ss_select_stream = sctp_ss_rrp_select,
981 .sctp_ss_scheduled = sctp_ss_default_scheduled,
982 .sctp_ss_packet_done = sctp_ss_rrp_packet_done,
983 .sctp_ss_get_value = sctp_ss_default_get_value,
984 .sctp_ss_set_value = sctp_ss_default_set_value,
985 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
987 /* SCTP_SS_PRIORITY */
989 .sctp_ss_init = sctp_ss_default_init,
990 .sctp_ss_clear = sctp_ss_prio_clear,
991 .sctp_ss_init_stream = sctp_ss_prio_init_stream,
992 .sctp_ss_add_to_stream = sctp_ss_prio_add,
993 .sctp_ss_is_empty = sctp_ss_default_is_empty,
994 .sctp_ss_remove_from_stream = sctp_ss_prio_remove,
995 .sctp_ss_select_stream = sctp_ss_prio_select,
996 .sctp_ss_scheduled = sctp_ss_default_scheduled,
997 .sctp_ss_packet_done = sctp_ss_default_packet_done,
998 .sctp_ss_get_value = sctp_ss_prio_get_value,
999 .sctp_ss_set_value = sctp_ss_prio_set_value,
1000 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
1002 /* SCTP_SS_FAIR_BANDWITH */
1004 .sctp_ss_init = sctp_ss_default_init,
1005 .sctp_ss_clear = sctp_ss_fb_clear,
1006 .sctp_ss_init_stream = sctp_ss_fb_init_stream,
1007 .sctp_ss_add_to_stream = sctp_ss_fb_add,
1008 .sctp_ss_is_empty = sctp_ss_default_is_empty,
1009 .sctp_ss_remove_from_stream = sctp_ss_fb_remove,
1010 .sctp_ss_select_stream = sctp_ss_fb_select,
1011 .sctp_ss_scheduled = sctp_ss_fb_scheduled,
1012 .sctp_ss_packet_done = sctp_ss_default_packet_done,
1013 .sctp_ss_get_value = sctp_ss_default_get_value,
1014 .sctp_ss_set_value = sctp_ss_default_set_value,
1015 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
1017 /* SCTP_SS_FIRST_COME */
1019 .sctp_ss_init = sctp_ss_fcfs_init,
1020 .sctp_ss_clear = sctp_ss_fcfs_clear,
1021 .sctp_ss_init_stream = sctp_ss_fcfs_init_stream,
1022 .sctp_ss_add_to_stream = sctp_ss_fcfs_add,
1023 .sctp_ss_is_empty = sctp_ss_fcfs_is_empty,
1024 .sctp_ss_remove_from_stream = sctp_ss_fcfs_remove,
1025 .sctp_ss_select_stream = sctp_ss_fcfs_select,
1026 .sctp_ss_scheduled = sctp_ss_default_scheduled,
1027 .sctp_ss_packet_done = sctp_ss_default_packet_done,
1028 .sctp_ss_get_value = sctp_ss_default_get_value,
1029 .sctp_ss_set_value = sctp_ss_default_set_value,
1030 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete