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);
185 static struct sctp_stream_out *
186 sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
187 struct sctp_association *asoc)
189 struct sctp_stream_out *strq, *strqt;
191 if (asoc->ss_data.locked_on_sending) {
192 return (asoc->ss_data.locked_on_sending);
194 strqt = asoc->ss_data.last_out_stream;
196 /* Find the next stream to use */
198 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
200 strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
202 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
207 * If CMT is off, we must validate that the stream in question has
208 * the first item pointed towards are network destination requested
209 * by the caller. Note that if we turn out to be locked to a stream
210 * (assigning TSN's then we must stop, since we cannot look for
211 * another stream with data to send to that destination). In CMT's
212 * case, by skipping this check, we will send one data packet
213 * towards the requested net.
215 if (net != NULL && strq != NULL &&
216 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
217 if (TAILQ_FIRST(&strq->outqueue) &&
218 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
219 TAILQ_FIRST(&strq->outqueue)->net != net) {
220 if (strq == asoc->ss_data.last_out_stream) {
232 sctp_ss_default_scheduled(struct sctp_tcb *stcb,
233 struct sctp_nets *net SCTP_UNUSED,
234 struct sctp_association *asoc,
235 struct sctp_stream_out *strq,
236 int moved_how_much SCTP_UNUSED)
238 struct sctp_stream_queue_pending *sp;
240 asoc->ss_data.last_out_stream = strq;
241 if (stcb->asoc.idata_supported == 0) {
242 sp = TAILQ_FIRST(&strq->outqueue);
243 if ((sp != NULL) && (sp->some_taken == 1)) {
244 stcb->asoc.ss_data.locked_on_sending = strq;
246 stcb->asoc.ss_data.locked_on_sending = NULL;
249 stcb->asoc.ss_data.locked_on_sending = NULL;
255 sctp_ss_default_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
256 struct sctp_association *asoc SCTP_UNUSED)
258 /* Nothing to be done here */
263 sctp_ss_default_get_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_set_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
272 struct sctp_stream_out *strq SCTP_UNUSED, uint16_t value SCTP_UNUSED)
274 /* Nothing to be done here */
279 sctp_ss_default_is_user_msgs_incomplete(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
281 struct sctp_stream_out *strq;
282 struct sctp_stream_queue_pending *sp;
284 if (asoc->stream_queue_cnt != 1) {
287 strq = asoc->ss_data.locked_on_sending;
291 sp = TAILQ_FIRST(&strq->outqueue);
295 return (!sp->msg_is_complete);
299 * Real round-robin algorithm.
300 * Always interates the streams in ascending order.
303 sctp_ss_rr_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
304 struct sctp_stream_out *strq,
305 struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock)
307 struct sctp_stream_out *strqt;
309 if (holds_lock == 0) {
310 SCTP_TCB_SEND_LOCK(stcb);
312 if (!TAILQ_EMPTY(&strq->outqueue) &&
313 (strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
314 (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
315 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
316 TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
318 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
319 while (strqt != NULL && (strqt->sid < strq->sid)) {
320 strqt = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
323 TAILQ_INSERT_BEFORE(strqt, strq, ss_params.rr.next_spoke);
325 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
329 if (holds_lock == 0) {
330 SCTP_TCB_SEND_UNLOCK(stcb);
336 * Real round-robin per packet algorithm.
337 * Always interates the streams in ascending order and
338 * only fills messages of the same stream in a packet.
340 static struct sctp_stream_out *
341 sctp_ss_rrp_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
342 struct sctp_association *asoc)
344 return (asoc->ss_data.last_out_stream);
348 sctp_ss_rrp_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
349 struct sctp_association *asoc)
351 struct sctp_stream_out *strq, *strqt;
353 strqt = asoc->ss_data.last_out_stream;
355 /* Find the next stream to use */
357 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
359 strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
361 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
366 * If CMT is off, we must validate that the stream in question has
367 * the first item pointed towards are network destination requested
368 * by the caller. Note that if we turn out to be locked to a stream
369 * (assigning TSN's then we must stop, since we cannot look for
370 * another stream with data to send to that destination). In CMT's
371 * case, by skipping this check, we will send one data packet
372 * towards the requested net.
374 if (net != NULL && strq != NULL &&
375 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
376 if (TAILQ_FIRST(&strq->outqueue) &&
377 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
378 TAILQ_FIRST(&strq->outqueue)->net != net) {
379 if (strq == asoc->ss_data.last_out_stream) {
387 asoc->ss_data.last_out_stream = strq;
392 * Priority algorithm.
393 * Always prefers streams based on their priority id.
396 sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
397 int clear_values, int holds_lock)
399 if (holds_lock == 0) {
400 SCTP_TCB_SEND_LOCK(stcb);
402 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
403 struct sctp_stream_out *strq;
405 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
407 strq->ss_params.prio.priority = 0;
409 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
410 strq->ss_params.prio.next_spoke.tqe_next = NULL;
411 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
413 asoc->ss_data.last_out_stream = NULL;
414 if (holds_lock == 0) {
415 SCTP_TCB_SEND_UNLOCK(stcb);
421 sctp_ss_prio_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
423 if (with_strq != NULL) {
424 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
425 stcb->asoc.ss_data.locked_on_sending = strq;
427 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
428 stcb->asoc.ss_data.last_out_stream = strq;
431 strq->ss_params.prio.next_spoke.tqe_next = NULL;
432 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
433 if (with_strq != NULL) {
434 strq->ss_params.prio.priority = with_strq->ss_params.prio.priority;
436 strq->ss_params.prio.priority = 0;
442 sctp_ss_prio_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
443 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
446 struct sctp_stream_out *strqt;
448 if (holds_lock == 0) {
449 SCTP_TCB_SEND_LOCK(stcb);
451 /* Add to wheel if not already on it and stream queue not empty */
452 if (!TAILQ_EMPTY(&strq->outqueue) &&
453 (strq->ss_params.prio.next_spoke.tqe_next == NULL) &&
454 (strq->ss_params.prio.next_spoke.tqe_prev == NULL)) {
455 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
456 TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
458 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
459 while (strqt != NULL && strqt->ss_params.prio.priority < strq->ss_params.prio.priority) {
460 strqt = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
463 TAILQ_INSERT_BEFORE(strqt, strq, ss_params.prio.next_spoke);
465 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
469 if (holds_lock == 0) {
470 SCTP_TCB_SEND_UNLOCK(stcb);
476 sctp_ss_prio_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
477 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
480 if (holds_lock == 0) {
481 SCTP_TCB_SEND_LOCK(stcb);
484 * Remove from wheel if stream queue is empty and actually is on the
487 if (TAILQ_EMPTY(&strq->outqueue) &&
488 (strq->ss_params.prio.next_spoke.tqe_next != NULL ||
489 strq->ss_params.prio.next_spoke.tqe_prev != NULL)) {
490 if (asoc->ss_data.last_out_stream == strq) {
491 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead,
492 ss_params.prio.next_spoke);
493 if (asoc->ss_data.last_out_stream == NULL) {
494 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
497 if (asoc->ss_data.last_out_stream == strq) {
498 asoc->ss_data.last_out_stream = NULL;
501 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
502 strq->ss_params.prio.next_spoke.tqe_next = NULL;
503 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
505 if (holds_lock == 0) {
506 SCTP_TCB_SEND_UNLOCK(stcb);
511 static struct sctp_stream_out *
512 sctp_ss_prio_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
513 struct sctp_association *asoc)
515 struct sctp_stream_out *strq, *strqt, *strqn;
517 if (asoc->ss_data.locked_on_sending) {
518 return (asoc->ss_data.locked_on_sending);
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.locked_on_sending) {
698 return (asoc->ss_data.locked_on_sending);
700 if (asoc->ss_data.last_out_stream == NULL ||
701 TAILQ_FIRST(&asoc->ss_data.out.wheel) == TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead)) {
702 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
704 strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.fb.next_spoke);
707 if ((strqt != NULL) &&
708 ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) > 0) ||
709 (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0 &&
710 (net == NULL || (TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net == NULL) ||
711 (net != NULL && TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net != NULL &&
712 TAILQ_FIRST(&strqt->outqueue)->net == net))))) {
713 if ((strqt->ss_params.fb.rounds >= 0) && (strq == NULL ||
714 strqt->ss_params.fb.rounds < strq->ss_params.fb.rounds)) {
719 strqt = TAILQ_NEXT(strqt, ss_params.fb.next_spoke);
721 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
723 } while (strqt != strq);
728 sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED,
729 struct sctp_association *asoc, struct sctp_stream_out *strq,
730 int moved_how_much SCTP_UNUSED)
732 struct sctp_stream_queue_pending *sp;
733 struct sctp_stream_out *strqt;
736 if (stcb->asoc.idata_supported == 0) {
737 sp = TAILQ_FIRST(&strq->outqueue);
738 if ((sp != NULL) && (sp->some_taken == 1)) {
739 stcb->asoc.ss_data.locked_on_sending = strq;
741 stcb->asoc.ss_data.locked_on_sending = NULL;
744 stcb->asoc.ss_data.locked_on_sending = NULL;
746 subtract = strq->ss_params.fb.rounds;
747 TAILQ_FOREACH(strqt, &asoc->ss_data.out.wheel, ss_params.fb.next_spoke) {
748 strqt->ss_params.fb.rounds -= subtract;
749 if (strqt->ss_params.fb.rounds < 0)
750 strqt->ss_params.fb.rounds = 0;
752 if (TAILQ_FIRST(&strq->outqueue)) {
753 strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
755 strq->ss_params.fb.rounds = -1;
757 asoc->ss_data.last_out_stream = strq;
762 * First-come, first-serve algorithm.
763 * Maintains the order provided by the application.
766 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
767 struct sctp_stream_out *strq SCTP_UNUSED,
768 struct sctp_stream_queue_pending *sp, int holds_lock);
771 sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
774 uint32_t x, n = 0, add_more = 1;
775 struct sctp_stream_queue_pending *sp;
778 if (holds_lock == 0) {
779 SCTP_TCB_SEND_LOCK(stcb);
781 TAILQ_INIT(&asoc->ss_data.out.list);
783 * If there is data in the stream queues already, the scheduler of
784 * an existing association has been changed. We can only cycle
785 * through the stream queues and add everything to the FCFS queue.
789 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
790 sp = TAILQ_FIRST(&stcb->asoc.strmout[i].outqueue);
792 /* Find n. message in current stream queue */
793 while (sp != NULL && x < n) {
794 sp = TAILQ_NEXT(sp, next);
798 sctp_ss_fcfs_add(stcb, &stcb->asoc, &stcb->asoc.strmout[i], sp, 1);
804 if (holds_lock == 0) {
805 SCTP_TCB_SEND_UNLOCK(stcb);
811 sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
812 int clear_values, int holds_lock)
814 struct sctp_stream_queue_pending *sp;
817 if (holds_lock == 0) {
818 SCTP_TCB_SEND_LOCK(stcb);
820 while (!TAILQ_EMPTY(&asoc->ss_data.out.list)) {
821 sp = TAILQ_FIRST(&asoc->ss_data.out.list);
822 TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
823 sp->ss_next.tqe_next = NULL;
824 sp->ss_next.tqe_prev = NULL;
826 if (holds_lock == 0) {
827 SCTP_TCB_SEND_UNLOCK(stcb);
834 sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
836 if (with_strq != NULL) {
837 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
838 stcb->asoc.ss_data.locked_on_sending = strq;
840 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
841 stcb->asoc.ss_data.last_out_stream = strq;
844 strq->ss_params.fb.next_spoke.tqe_next = NULL;
845 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
850 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
851 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
854 if (holds_lock == 0) {
855 SCTP_TCB_SEND_LOCK(stcb);
857 if (sp && (sp->ss_next.tqe_next == NULL) &&
858 (sp->ss_next.tqe_prev == NULL)) {
859 TAILQ_INSERT_TAIL(&asoc->ss_data.out.list, sp, ss_next);
861 if (holds_lock == 0) {
862 SCTP_TCB_SEND_UNLOCK(stcb);
868 sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
870 if (TAILQ_EMPTY(&asoc->ss_data.out.list)) {
878 sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
879 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
882 if (holds_lock == 0) {
883 SCTP_TCB_SEND_LOCK(stcb);
886 ((sp->ss_next.tqe_next != NULL) ||
887 (sp->ss_next.tqe_prev != NULL))) {
888 TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
889 sp->ss_next.tqe_next = NULL;
890 sp->ss_next.tqe_prev = NULL;
892 if (holds_lock == 0) {
893 SCTP_TCB_SEND_UNLOCK(stcb);
898 static struct sctp_stream_out *
899 sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
900 struct sctp_association *asoc)
902 struct sctp_stream_out *strq;
903 struct sctp_stream_queue_pending *sp;
905 if (asoc->ss_data.locked_on_sending) {
906 return (asoc->ss_data.locked_on_sending);
908 sp = TAILQ_FIRST(&asoc->ss_data.out.list);
911 strq = &asoc->strmout[sp->sid];
917 * If CMT is off, we must validate that the stream in question has
918 * the first item pointed towards are network destination requested
919 * by the caller. Note that if we turn out to be locked to a stream
920 * (assigning TSN's then we must stop, since we cannot look for
921 * another stream with data to send to that destination). In CMT's
922 * case, by skipping this check, we will send one data packet
923 * towards the requested net.
925 if (net != NULL && strq != NULL &&
926 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
927 if (TAILQ_FIRST(&strq->outqueue) &&
928 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
929 TAILQ_FIRST(&strq->outqueue)->net != net) {
930 sp = TAILQ_NEXT(sp, ss_next);
937 const struct sctp_ss_functions sctp_ss_functions[] = {
938 /* SCTP_SS_DEFAULT */
940 .sctp_ss_init = sctp_ss_default_init,
941 .sctp_ss_clear = sctp_ss_default_clear,
942 .sctp_ss_init_stream = sctp_ss_default_init_stream,
943 .sctp_ss_add_to_stream = sctp_ss_default_add,
944 .sctp_ss_is_empty = sctp_ss_default_is_empty,
945 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
946 .sctp_ss_select_stream = sctp_ss_default_select,
947 .sctp_ss_scheduled = sctp_ss_default_scheduled,
948 .sctp_ss_packet_done = sctp_ss_default_packet_done,
949 .sctp_ss_get_value = sctp_ss_default_get_value,
950 .sctp_ss_set_value = sctp_ss_default_set_value,
951 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
953 /* SCTP_SS_ROUND_ROBIN */
955 .sctp_ss_init = sctp_ss_default_init,
956 .sctp_ss_clear = sctp_ss_default_clear,
957 .sctp_ss_init_stream = sctp_ss_default_init_stream,
958 .sctp_ss_add_to_stream = sctp_ss_rr_add,
959 .sctp_ss_is_empty = sctp_ss_default_is_empty,
960 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
961 .sctp_ss_select_stream = sctp_ss_default_select,
962 .sctp_ss_scheduled = sctp_ss_default_scheduled,
963 .sctp_ss_packet_done = sctp_ss_default_packet_done,
964 .sctp_ss_get_value = sctp_ss_default_get_value,
965 .sctp_ss_set_value = sctp_ss_default_set_value,
966 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
968 /* SCTP_SS_ROUND_ROBIN_PACKET */
970 .sctp_ss_init = sctp_ss_default_init,
971 .sctp_ss_clear = sctp_ss_default_clear,
972 .sctp_ss_init_stream = sctp_ss_default_init_stream,
973 .sctp_ss_add_to_stream = sctp_ss_rr_add,
974 .sctp_ss_is_empty = sctp_ss_default_is_empty,
975 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
976 .sctp_ss_select_stream = sctp_ss_rrp_select,
977 .sctp_ss_scheduled = sctp_ss_default_scheduled,
978 .sctp_ss_packet_done = sctp_ss_rrp_packet_done,
979 .sctp_ss_get_value = sctp_ss_default_get_value,
980 .sctp_ss_set_value = sctp_ss_default_set_value,
981 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
983 /* SCTP_SS_PRIORITY */
985 .sctp_ss_init = sctp_ss_default_init,
986 .sctp_ss_clear = sctp_ss_prio_clear,
987 .sctp_ss_init_stream = sctp_ss_prio_init_stream,
988 .sctp_ss_add_to_stream = sctp_ss_prio_add,
989 .sctp_ss_is_empty = sctp_ss_default_is_empty,
990 .sctp_ss_remove_from_stream = sctp_ss_prio_remove,
991 .sctp_ss_select_stream = sctp_ss_prio_select,
992 .sctp_ss_scheduled = sctp_ss_default_scheduled,
993 .sctp_ss_packet_done = sctp_ss_default_packet_done,
994 .sctp_ss_get_value = sctp_ss_prio_get_value,
995 .sctp_ss_set_value = sctp_ss_prio_set_value,
996 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
998 /* SCTP_SS_FAIR_BANDWITH */
1000 .sctp_ss_init = sctp_ss_default_init,
1001 .sctp_ss_clear = sctp_ss_fb_clear,
1002 .sctp_ss_init_stream = sctp_ss_fb_init_stream,
1003 .sctp_ss_add_to_stream = sctp_ss_fb_add,
1004 .sctp_ss_is_empty = sctp_ss_default_is_empty,
1005 .sctp_ss_remove_from_stream = sctp_ss_fb_remove,
1006 .sctp_ss_select_stream = sctp_ss_fb_select,
1007 .sctp_ss_scheduled = sctp_ss_fb_scheduled,
1008 .sctp_ss_packet_done = sctp_ss_default_packet_done,
1009 .sctp_ss_get_value = sctp_ss_default_get_value,
1010 .sctp_ss_set_value = sctp_ss_default_set_value,
1011 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
1013 /* SCTP_SS_FIRST_COME */
1015 .sctp_ss_init = sctp_ss_fcfs_init,
1016 .sctp_ss_clear = sctp_ss_fcfs_clear,
1017 .sctp_ss_init_stream = sctp_ss_fcfs_init_stream,
1018 .sctp_ss_add_to_stream = sctp_ss_fcfs_add,
1019 .sctp_ss_is_empty = sctp_ss_fcfs_is_empty,
1020 .sctp_ss_remove_from_stream = sctp_ss_fcfs_remove,
1021 .sctp_ss_select_stream = sctp_ss_fcfs_select,
1022 .sctp_ss_scheduled = sctp_ss_default_scheduled,
1023 .sctp_ss_packet_done = sctp_ss_default_packet_done,
1024 .sctp_ss_get_value = sctp_ss_default_get_value,
1025 .sctp_ss_set_value = sctp_ss_default_set_value,
1026 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete