2 * Copyright (c) 2010-2011, by Michael Tuexen. All rights reserved.
3 * Copyright (c) 2010-2011, by Randall Stewart. All rights reserved.
4 * Copyright (c) 2010-2011, by Robin Seggelmann. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * a) Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
12 * b) Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 * THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <netinet/sctp_pcb.h>
35 * Default simple round-robin algorithm.
36 * Just interates the streams in the order they appear.
40 sctp_ss_default_add(struct sctp_tcb *, struct sctp_association *,
41 struct sctp_stream_out *,
42 struct sctp_stream_queue_pending *, int);
45 sctp_ss_default_remove(struct sctp_tcb *, struct sctp_association *,
46 struct sctp_stream_out *,
47 struct sctp_stream_queue_pending *, int);
50 sctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
55 TAILQ_INIT(&asoc->ss_data.out_wheel);
57 * If there is data in the stream queues already, the scheduler of
58 * an existing association has been changed. We need to add all
59 * stream queues to the wheel.
61 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
62 if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) {
63 sctp_ss_default_add(stcb, &stcb->asoc,
64 &stcb->asoc.strmout[i],
72 sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
73 int clear_values, int holds_lock)
77 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
78 if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) {
79 sctp_ss_default_remove(stcb, &stcb->asoc,
80 &stcb->asoc.strmout[i],
88 sctp_ss_default_init_stream(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
90 strq->ss_params.rr.next_spoke.tqe_next = NULL;
91 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
96 sctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
97 struct sctp_stream_out *strq,
98 struct sctp_stream_queue_pending *sp, int holds_lock)
100 if (holds_lock == 0) {
101 SCTP_TCB_SEND_LOCK(stcb);
103 if ((strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
104 (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
105 TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel,
106 strq, ss_params.rr.next_spoke);
108 if (holds_lock == 0) {
109 SCTP_TCB_SEND_UNLOCK(stcb);
115 sctp_ss_default_is_empty(struct sctp_tcb *stcb, struct sctp_association *asoc)
117 if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) {
125 sctp_ss_default_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
126 struct sctp_stream_out *strq,
127 struct sctp_stream_queue_pending *sp, int holds_lock)
129 /* take off and then setup so we know it is not on the wheel */
130 if (holds_lock == 0) {
131 SCTP_TCB_SEND_LOCK(stcb);
133 if (TAILQ_EMPTY(&strq->outqueue)) {
134 if (asoc->last_out_stream == strq) {
135 asoc->last_out_stream = TAILQ_PREV(asoc->last_out_stream,
137 ss_params.rr.next_spoke);
138 if (asoc->last_out_stream == NULL) {
139 asoc->last_out_stream = TAILQ_LAST(&asoc->ss_data.out_wheel,
142 if (asoc->last_out_stream == strq) {
143 asoc->last_out_stream = NULL;
146 TAILQ_REMOVE(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke);
147 strq->ss_params.rr.next_spoke.tqe_next = NULL;
148 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
150 if (holds_lock == 0) {
151 SCTP_TCB_SEND_UNLOCK(stcb);
157 static struct sctp_stream_out *
158 sctp_ss_default_select(struct sctp_tcb *stcb, struct sctp_nets *net,
159 struct sctp_association *asoc)
161 struct sctp_stream_out *strq, *strqt;
163 strqt = asoc->last_out_stream;
165 /* Find the next stream to use */
167 strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
169 strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
171 strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
176 * If CMT is off, we must validate that the stream in question has
177 * the first item pointed towards are network destination requested
178 * by the caller. Note that if we turn out to be locked to a stream
179 * (assigning TSN's then we must stop, since we cannot look for
180 * another stream with data to send to that destination). In CMT's
181 * case, by skipping this check, we will send one data packet
182 * towards the requested net.
184 if (net != NULL && strq != NULL &&
185 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
186 if (TAILQ_FIRST(&strq->outqueue) &&
187 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
188 TAILQ_FIRST(&strq->outqueue)->net != net) {
189 if (strq == asoc->last_out_stream) {
201 sctp_ss_default_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net,
202 struct sctp_association *asoc,
203 struct sctp_stream_out *strq, int moved_how_much)
205 asoc->last_out_stream = strq;
210 sctp_ss_default_packet_done(struct sctp_tcb *stcb, struct sctp_nets *net,
211 struct sctp_association *asoc)
213 /* Nothing to be done here */
218 sctp_ss_default_get_value(struct sctp_tcb *stcb, struct sctp_association *asoc,
219 struct sctp_stream_out *strq, uint16_t * value)
221 /* Nothing to be done here */
226 sctp_ss_default_set_value(struct sctp_tcb *stcb, struct sctp_association *asoc,
227 struct sctp_stream_out *strq, uint16_t value)
229 /* Nothing to be done here */
234 * Real round-robin algorithm.
235 * Always interates the streams in ascending order.
238 sctp_ss_rr_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
239 struct sctp_stream_out *strq,
240 struct sctp_stream_queue_pending *sp, int holds_lock)
242 struct sctp_stream_out *strqt;
244 if (holds_lock == 0) {
245 SCTP_TCB_SEND_LOCK(stcb);
247 if ((strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
248 (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
249 if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) {
250 TAILQ_INSERT_HEAD(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke);
252 strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel);
253 while (strqt != NULL && (strqt->stream_no < strq->stream_no)) {
254 strqt = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
257 TAILQ_INSERT_BEFORE(strqt, strq, ss_params.rr.next_spoke);
259 TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke);
263 if (holds_lock == 0) {
264 SCTP_TCB_SEND_UNLOCK(stcb);
270 * Real round-robin per packet algorithm.
271 * Always interates the streams in ascending order and
272 * only fills messages of the same stream in a packet.
275 sctp_ss_rrp_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
276 struct sctp_stream_out *strq,
277 struct sctp_stream_queue_pending *sp, int holds_lock)
279 struct sctp_stream_out *strqt;
281 if (holds_lock == 0) {
282 SCTP_TCB_SEND_LOCK(stcb);
284 if ((strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
285 (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
286 if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) {
287 TAILQ_INSERT_HEAD(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke);
289 strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel);
290 while (strqt != NULL && strqt->stream_no < strq->stream_no) {
291 strqt = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
294 TAILQ_INSERT_BEFORE(strqt, strq, ss_params.rr.next_spoke);
296 TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke);
300 if (holds_lock == 0) {
301 SCTP_TCB_SEND_UNLOCK(stcb);
306 static struct sctp_stream_out *
307 sctp_ss_rrp_select(struct sctp_tcb *stcb, struct sctp_nets *net,
308 struct sctp_association *asoc)
310 struct sctp_stream_out *strq, *strqt;
312 strqt = asoc->last_out_stream;
313 if (strqt != NULL && !TAILQ_EMPTY(&strqt->outqueue)) {
317 /* Find the next stream to use */
319 strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
321 strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
323 strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
328 * If CMT is off, we must validate that the stream in question has
329 * the first item pointed towards are network destination requested
330 * by the caller. Note that if we turn out to be locked to a stream
331 * (assigning TSN's then we must stop, since we cannot look for
332 * another stream with data to send to that destination). In CMT's
333 * case, by skipping this check, we will send one data packet
334 * towards the requested net.
336 if (net != NULL && strq != NULL &&
337 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
338 if (TAILQ_FIRST(&strq->outqueue) &&
339 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
340 TAILQ_FIRST(&strq->outqueue)->net != net) {
341 if (strq == asoc->last_out_stream) {
353 sctp_ss_rrp_packet_done(struct sctp_tcb *stcb, struct sctp_nets *net,
354 struct sctp_association *asoc)
356 struct sctp_stream_out *strq, *strqt;
358 strqt = asoc->last_out_stream;
360 /* Find the next stream to use */
362 strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
364 strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
366 strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
371 * If CMT is off, we must validate that the stream in question has
372 * the first item pointed towards are network destination requested
373 * by the caller. Note that if we turn out to be locked to a stream
374 * (assigning TSN's then we must stop, since we cannot look for
375 * another stream with data to send to that destination). In CMT's
376 * case, by skipping this check, we will send one data packet
377 * towards the requested net.
379 if ((strq != NULL) && TAILQ_FIRST(&strq->outqueue) &&
380 (net != NULL && TAILQ_FIRST(&strq->outqueue)->net != net) &&
381 (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0)) {
382 if (strq == asoc->last_out_stream) {
389 asoc->last_out_stream = strq;
395 * Priority algorithm.
396 * Always prefers streams based on their priority id.
399 sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
400 int clear_values, int holds_lock)
404 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
405 if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) {
407 stcb->asoc.strmout[i].ss_params.prio.priority = 0;
408 sctp_ss_default_remove(stcb, &stcb->asoc, &stcb->asoc.strmout[i], NULL, holds_lock);
415 sctp_ss_prio_init_stream(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
417 strq->ss_params.prio.next_spoke.tqe_next = NULL;
418 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
419 if (with_strq != NULL) {
420 strq->ss_params.prio.priority = with_strq->ss_params.prio.priority;
422 strq->ss_params.prio.priority = 0;
428 sctp_ss_prio_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
429 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp,
432 struct sctp_stream_out *strqt;
434 if (holds_lock == 0) {
435 SCTP_TCB_SEND_LOCK(stcb);
437 if ((strq->ss_params.prio.next_spoke.tqe_next == NULL) &&
438 (strq->ss_params.prio.next_spoke.tqe_prev == NULL)) {
439 if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) {
440 TAILQ_INSERT_HEAD(&asoc->ss_data.out_wheel, strq, ss_params.prio.next_spoke);
442 strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel);
443 while (strqt != NULL && strqt->ss_params.prio.priority < strq->ss_params.prio.priority) {
444 strqt = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
447 TAILQ_INSERT_BEFORE(strqt, strq, ss_params.prio.next_spoke);
449 TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.prio.next_spoke);
453 if (holds_lock == 0) {
454 SCTP_TCB_SEND_UNLOCK(stcb);
460 sctp_ss_prio_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
461 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp,
464 /* take off and then setup so we know it is not on the wheel */
465 if (holds_lock == 0) {
466 SCTP_TCB_SEND_LOCK(stcb);
468 if (TAILQ_EMPTY(&strq->outqueue)) {
469 if (asoc->last_out_stream == strq) {
470 asoc->last_out_stream = TAILQ_PREV(asoc->last_out_stream, sctpwheel_listhead,
471 ss_params.prio.next_spoke);
472 if (asoc->last_out_stream == NULL) {
473 asoc->last_out_stream = TAILQ_LAST(&asoc->ss_data.out_wheel,
476 if (asoc->last_out_stream == strq) {
477 asoc->last_out_stream = NULL;
480 TAILQ_REMOVE(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke);
481 strq->ss_params.prio.next_spoke.tqe_next = NULL;
482 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
484 if (holds_lock == 0) {
485 SCTP_TCB_SEND_UNLOCK(stcb);
490 static struct sctp_stream_out *
491 sctp_ss_prio_select(struct sctp_tcb *stcb, struct sctp_nets *net,
492 struct sctp_association *asoc)
494 struct sctp_stream_out *strq, *strqt, *strqn;
496 strqt = asoc->last_out_stream;
498 /* Find the next stream to use */
500 strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
502 strqn = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
504 strqn->ss_params.prio.priority == strqt->ss_params.prio.priority) {
505 strq = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
507 strq = TAILQ_FIRST(&asoc->ss_data.out_wheel);
512 * If CMT is off, we must validate that the stream in question has
513 * the first item pointed towards are network destination requested
514 * by the caller. Note that if we turn out to be locked to a stream
515 * (assigning TSN's then we must stop, since we cannot look for
516 * another stream with data to send to that destination). In CMT's
517 * case, by skipping this check, we will send one data packet
518 * towards the requested net.
520 if (net != NULL && strq != NULL &&
521 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
522 if (TAILQ_FIRST(&strq->outqueue) &&
523 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
524 TAILQ_FIRST(&strq->outqueue)->net != net) {
525 if (strq == asoc->last_out_stream) {
537 sctp_ss_prio_get_value(struct sctp_tcb *stcb, struct sctp_association *asoc,
538 struct sctp_stream_out *strq, uint16_t * value)
543 *value = strq->ss_params.prio.priority;
548 sctp_ss_prio_set_value(struct sctp_tcb *stcb, struct sctp_association *asoc,
549 struct sctp_stream_out *strq, uint16_t value)
554 strq->ss_params.prio.priority = value;
555 sctp_ss_prio_remove(stcb, asoc, strq, NULL, 1);
556 sctp_ss_prio_add(stcb, asoc, strq, NULL, 1);
561 * Fair bandwidth algorithm.
562 * Maintains an equal troughput per stream.
565 sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
566 int clear_values, int holds_lock)
570 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
571 if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) {
573 stcb->asoc.strmout[i].ss_params.fb.rounds = -1;
575 sctp_ss_default_remove(stcb, &stcb->asoc, &stcb->asoc.strmout[i], NULL, holds_lock);
582 sctp_ss_fb_init_stream(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
584 strq->ss_params.fb.next_spoke.tqe_next = NULL;
585 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
586 if (with_strq != NULL) {
587 strq->ss_params.fb.rounds = with_strq->ss_params.fb.rounds;
589 strq->ss_params.fb.rounds = -1;
595 sctp_ss_fb_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
596 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp,
599 if (holds_lock == 0) {
600 SCTP_TCB_SEND_LOCK(stcb);
602 if ((strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
603 (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
604 if (!TAILQ_EMPTY(&strq->outqueue) && strq->ss_params.fb.rounds < 0)
605 strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
606 TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke);
608 if (holds_lock == 0) {
609 SCTP_TCB_SEND_UNLOCK(stcb);
615 sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
616 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp,
619 /* take off and then setup so we know it is not on the wheel */
620 if (holds_lock == 0) {
621 SCTP_TCB_SEND_LOCK(stcb);
623 if (TAILQ_EMPTY(&strq->outqueue)) {
624 if (asoc->last_out_stream == strq) {
625 asoc->last_out_stream = TAILQ_PREV(asoc->last_out_stream, sctpwheel_listhead,
626 ss_params.fb.next_spoke);
627 if (asoc->last_out_stream == NULL) {
628 asoc->last_out_stream = TAILQ_LAST(&asoc->ss_data.out_wheel,
631 if (asoc->last_out_stream == strq) {
632 asoc->last_out_stream = NULL;
635 strq->ss_params.fb.rounds = -1;
636 TAILQ_REMOVE(&asoc->ss_data.out_wheel, strq, ss_params.fb.next_spoke);
637 strq->ss_params.fb.next_spoke.tqe_next = NULL;
638 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
640 if (holds_lock == 0) {
641 SCTP_TCB_SEND_UNLOCK(stcb);
646 static struct sctp_stream_out *
647 sctp_ss_fb_select(struct sctp_tcb *stcb, struct sctp_nets *net,
648 struct sctp_association *asoc)
650 struct sctp_stream_out *strq = NULL, *strqt;
652 if (TAILQ_FIRST(&asoc->ss_data.out_wheel) == TAILQ_LAST(&asoc->ss_data.out_wheel, sctpwheel_listhead)) {
653 strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel);
655 if (asoc->last_out_stream != NULL) {
656 strqt = TAILQ_NEXT(asoc->last_out_stream, ss_params.fb.next_spoke);
658 strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel);
662 if ((strqt != NULL) && TAILQ_FIRST(&strqt->outqueue) &&
663 TAILQ_FIRST(&strqt->outqueue)->net != NULL &&
664 ((net == NULL || TAILQ_FIRST(&strqt->outqueue)->net == net) ||
665 (SCTP_BASE_SYSCTL(sctp_cmt_on_off) > 0))) {
666 if ((strqt->ss_params.fb.rounds >= 0) && (strq == NULL ||
667 strqt->ss_params.fb.rounds < strq->ss_params.fb.rounds)) {
672 strqt = TAILQ_NEXT(strqt, ss_params.fb.next_spoke);
674 strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel);
676 } while (strqt != strq);
681 sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net,
682 struct sctp_association *asoc, struct sctp_stream_out *strq,
685 struct sctp_stream_out *strqt;
688 subtract = strq->ss_params.fb.rounds;
689 TAILQ_FOREACH(strqt, &asoc->ss_data.out_wheel, ss_params.fb.next_spoke) {
690 strqt->ss_params.fb.rounds -= subtract;
691 if (strqt->ss_params.fb.rounds < 0)
692 strqt->ss_params.fb.rounds = 0;
694 if (TAILQ_FIRST(&strq->outqueue)) {
695 strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
697 strq->ss_params.fb.rounds = -1;
699 asoc->last_out_stream = strq;
704 * First-come, first-serve algorithm.
705 * Maintains the order provided by the application.
708 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
709 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp,
713 sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
716 uint32_t x, n = 0, add_more = 1;
717 struct sctp_stream_queue_pending *sp;
720 TAILQ_INIT(&asoc->ss_data.out_list);
722 * If there is data in the stream queues already, the scheduler of
723 * an existing association has been changed. We can only cycle
724 * through the stream queues and add everything to the FCFS queue.
728 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
729 sp = TAILQ_FIRST(&stcb->asoc.strmout[i].outqueue);
731 /* Find n. message in current stream queue */
732 while (sp != NULL && x < n) {
733 sp = TAILQ_NEXT(sp, next);
737 sctp_ss_fcfs_add(stcb, &stcb->asoc, &stcb->asoc.strmout[i], sp, holds_lock);
747 sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
748 int clear_values, int holds_lock)
751 while (!TAILQ_EMPTY(&asoc->ss_data.out_list)) {
752 TAILQ_REMOVE(&asoc->ss_data.out_list, TAILQ_FIRST(&asoc->ss_data.out_list), ss_next);
759 sctp_ss_fcfs_init_stream(struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
761 /* Nothing to be done here */
766 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
767 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp,
770 if (holds_lock == 0) {
771 SCTP_TCB_SEND_LOCK(stcb);
773 if (sp && (sp->ss_next.tqe_next == NULL) &&
774 (sp->ss_next.tqe_prev == NULL)) {
775 TAILQ_INSERT_TAIL(&asoc->ss_data.out_list, sp, ss_next);
777 if (holds_lock == 0) {
778 SCTP_TCB_SEND_UNLOCK(stcb);
784 sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb, struct sctp_association *asoc)
786 if (TAILQ_EMPTY(&asoc->ss_data.out_list)) {
794 sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
795 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp,
798 if (holds_lock == 0) {
799 SCTP_TCB_SEND_LOCK(stcb);
802 ((sp->ss_next.tqe_next != NULL) ||
803 (sp->ss_next.tqe_prev != NULL))) {
804 TAILQ_REMOVE(&asoc->ss_data.out_list, sp, ss_next);
806 if (holds_lock == 0) {
807 SCTP_TCB_SEND_UNLOCK(stcb);
813 static struct sctp_stream_out *
814 sctp_ss_fcfs_select(struct sctp_tcb *stcb, struct sctp_nets *net,
815 struct sctp_association *asoc)
817 struct sctp_stream_out *strq;
818 struct sctp_stream_queue_pending *sp;
820 sp = TAILQ_FIRST(&asoc->ss_data.out_list);
823 strq = &asoc->strmout[sp->stream];
829 * If CMT is off, we must validate that the stream in question has
830 * the first item pointed towards are network destination requested
831 * by the caller. Note that if we turn out to be locked to a stream
832 * (assigning TSN's then we must stop, since we cannot look for
833 * another stream with data to send to that destination). In CMT's
834 * case, by skipping this check, we will send one data packet
835 * towards the requested net.
837 if (net != NULL && strq != NULL &&
838 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
839 if (TAILQ_FIRST(&strq->outqueue) &&
840 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
841 TAILQ_FIRST(&strq->outqueue)->net != net) {
842 sp = TAILQ_NEXT(sp, ss_next);
849 struct sctp_ss_functions sctp_ss_functions[] = {
850 /* SCTP_SS_DEFAULT */
852 .sctp_ss_init = sctp_ss_default_init,
853 .sctp_ss_clear = sctp_ss_default_clear,
854 .sctp_ss_init_stream = sctp_ss_default_init_stream,
855 .sctp_ss_add_to_stream = sctp_ss_default_add,
856 .sctp_ss_is_empty = sctp_ss_default_is_empty,
857 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
858 .sctp_ss_select_stream = sctp_ss_default_select,
859 .sctp_ss_scheduled = sctp_ss_default_scheduled,
860 .sctp_ss_packet_done = sctp_ss_default_packet_done,
861 .sctp_ss_get_value = sctp_ss_default_get_value,
862 .sctp_ss_set_value = sctp_ss_default_set_value
864 /* SCTP_SS_ROUND_ROBIN */
866 .sctp_ss_init = sctp_ss_default_init,
867 .sctp_ss_clear = sctp_ss_default_clear,
868 .sctp_ss_init_stream = sctp_ss_default_init_stream,
869 .sctp_ss_add_to_stream = sctp_ss_rr_add,
870 .sctp_ss_is_empty = sctp_ss_default_is_empty,
871 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
872 .sctp_ss_select_stream = sctp_ss_default_select,
873 .sctp_ss_scheduled = sctp_ss_default_scheduled,
874 .sctp_ss_packet_done = sctp_ss_default_packet_done,
875 .sctp_ss_get_value = sctp_ss_default_get_value,
876 .sctp_ss_set_value = sctp_ss_default_set_value
878 /* SCTP_SS_ROUND_ROBIN_PACKET */
880 .sctp_ss_init = sctp_ss_default_init,
881 .sctp_ss_clear = sctp_ss_default_clear,
882 .sctp_ss_init_stream = sctp_ss_default_init_stream,
883 .sctp_ss_add_to_stream = sctp_ss_rrp_add,
884 .sctp_ss_is_empty = sctp_ss_default_is_empty,
885 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
886 .sctp_ss_select_stream = sctp_ss_rrp_select,
887 .sctp_ss_scheduled = sctp_ss_default_scheduled,
888 .sctp_ss_packet_done = sctp_ss_rrp_packet_done,
889 .sctp_ss_get_value = sctp_ss_default_get_value,
890 .sctp_ss_set_value = sctp_ss_default_set_value
892 /* SCTP_SS_PRIORITY */
894 .sctp_ss_init = sctp_ss_default_init,
895 .sctp_ss_clear = sctp_ss_prio_clear,
896 .sctp_ss_init_stream = sctp_ss_prio_init_stream,
897 .sctp_ss_add_to_stream = sctp_ss_prio_add,
898 .sctp_ss_is_empty = sctp_ss_default_is_empty,
899 .sctp_ss_remove_from_stream = sctp_ss_prio_remove,
900 .sctp_ss_select_stream = sctp_ss_prio_select,
901 .sctp_ss_scheduled = sctp_ss_default_scheduled,
902 .sctp_ss_packet_done = sctp_ss_default_packet_done,
903 .sctp_ss_get_value = sctp_ss_prio_get_value,
904 .sctp_ss_set_value = sctp_ss_prio_set_value
906 /* SCTP_SS_FAIR_BANDWITH */
908 .sctp_ss_init = sctp_ss_default_init,
909 .sctp_ss_clear = sctp_ss_fb_clear,
910 .sctp_ss_init_stream = sctp_ss_fb_init_stream,
911 .sctp_ss_add_to_stream = sctp_ss_fb_add,
912 .sctp_ss_is_empty = sctp_ss_default_is_empty,
913 .sctp_ss_remove_from_stream = sctp_ss_fb_remove,
914 .sctp_ss_select_stream = sctp_ss_fb_select,
915 .sctp_ss_scheduled = sctp_ss_fb_scheduled,
916 .sctp_ss_packet_done = sctp_ss_default_packet_done,
917 .sctp_ss_get_value = sctp_ss_default_get_value,
918 .sctp_ss_set_value = sctp_ss_default_set_value
920 /* SCTP_SS_FIRST_COME */
922 .sctp_ss_init = sctp_ss_fcfs_init,
923 .sctp_ss_clear = sctp_ss_fcfs_clear,
924 .sctp_ss_init_stream = sctp_ss_fcfs_init_stream,
925 .sctp_ss_add_to_stream = sctp_ss_fcfs_add,
926 .sctp_ss_is_empty = sctp_ss_fcfs_is_empty,
927 .sctp_ss_remove_from_stream = sctp_ss_fcfs_remove,
928 .sctp_ss_select_stream = sctp_ss_fcfs_select,
929 .sctp_ss_scheduled = sctp_ss_default_scheduled,
930 .sctp_ss_packet_done = sctp_ss_default_packet_done,
931 .sctp_ss_get_value = sctp_ss_default_get_value,
932 .sctp_ss_set_value = sctp_ss_default_set_value