2 * Copyright (c) 2010-2012, by Michael Tuexen. All rights reserved.
3 * Copyright (c) 2010-2012, by Randall Stewart. All rights reserved.
4 * Copyright (c) 2010-2012, 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 asoc->ss_data.locked_on_sending = NULL;
56 asoc->ss_data.last_out_stream = NULL;
57 TAILQ_INIT(&asoc->ss_data.out.wheel);
59 * If there is data in the stream queues already, the scheduler of
60 * an existing association has been changed. We need to add all
61 * stream queues to the wheel.
63 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
64 stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, &stcb->asoc,
65 &stcb->asoc.strmout[i],
72 sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
73 int clear_values SCTP_UNUSED, int holds_lock)
75 if (holds_lock == 0) {
76 SCTP_TCB_SEND_LOCK(stcb);
78 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
79 struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
81 TAILQ_REMOVE(&asoc->ss_data.out.wheel, TAILQ_FIRST(&asoc->ss_data.out.wheel), ss_params.rr.next_spoke);
82 strq->ss_params.rr.next_spoke.tqe_next = NULL;
83 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
85 asoc->ss_data.last_out_stream = NULL;
86 if (holds_lock == 0) {
87 SCTP_TCB_SEND_UNLOCK(stcb);
93 sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
95 if (with_strq != NULL) {
96 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
97 stcb->asoc.ss_data.locked_on_sending = strq;
99 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
100 stcb->asoc.ss_data.last_out_stream = strq;
103 strq->ss_params.rr.next_spoke.tqe_next = NULL;
104 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
109 sctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
110 struct sctp_stream_out *strq,
111 struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock)
113 if (holds_lock == 0) {
114 SCTP_TCB_SEND_LOCK(stcb);
116 /* Add to wheel if not already on it and stream queue not empty */
117 if (!TAILQ_EMPTY(&strq->outqueue) &&
118 (strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
119 (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
120 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel,
121 strq, ss_params.rr.next_spoke);
123 if (holds_lock == 0) {
124 SCTP_TCB_SEND_UNLOCK(stcb);
130 sctp_ss_default_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
132 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
140 sctp_ss_default_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
141 struct sctp_stream_out *strq,
142 struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock)
144 if (holds_lock == 0) {
145 SCTP_TCB_SEND_LOCK(stcb);
148 * Remove from wheel if stream queue is empty and actually is on the
151 if (TAILQ_EMPTY(&strq->outqueue) &&
152 (strq->ss_params.rr.next_spoke.tqe_next != NULL ||
153 strq->ss_params.rr.next_spoke.tqe_prev != NULL)) {
154 if (asoc->ss_data.last_out_stream == strq) {
155 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream,
157 ss_params.rr.next_spoke);
158 if (asoc->ss_data.last_out_stream == NULL) {
159 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
162 if (asoc->ss_data.last_out_stream == strq) {
163 asoc->ss_data.last_out_stream = NULL;
166 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
167 strq->ss_params.rr.next_spoke.tqe_next = NULL;
168 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
170 if (holds_lock == 0) {
171 SCTP_TCB_SEND_UNLOCK(stcb);
177 static struct sctp_stream_out *
178 sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
179 struct sctp_association *asoc)
181 struct sctp_stream_out *strq, *strqt;
183 if (asoc->ss_data.locked_on_sending) {
184 return (asoc->ss_data.locked_on_sending);
186 strqt = asoc->ss_data.last_out_stream;
188 /* Find the next stream to use */
190 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
192 strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
194 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
199 * If CMT is off, we must validate that the stream in question has
200 * the first item pointed towards are network destination requested
201 * by the caller. Note that if we turn out to be locked to a stream
202 * (assigning TSN's then we must stop, since we cannot look for
203 * another stream with data to send to that destination). In CMT's
204 * case, by skipping this check, we will send one data packet
205 * towards the requested net.
207 if (net != NULL && strq != NULL &&
208 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
209 if (TAILQ_FIRST(&strq->outqueue) &&
210 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
211 TAILQ_FIRST(&strq->outqueue)->net != net) {
212 if (strq == asoc->ss_data.last_out_stream) {
224 sctp_ss_default_scheduled(struct sctp_tcb *stcb,
225 struct sctp_nets *net SCTP_UNUSED,
226 struct sctp_association *asoc,
227 struct sctp_stream_out *strq,
228 int moved_how_much SCTP_UNUSED)
230 struct sctp_stream_queue_pending *sp;
232 asoc->ss_data.last_out_stream = strq;
233 if (stcb->asoc.idata_supported == 0) {
234 sp = TAILQ_FIRST(&strq->outqueue);
235 if ((sp != NULL) && (sp->some_taken == 1)) {
236 stcb->asoc.ss_data.locked_on_sending = strq;
238 stcb->asoc.ss_data.locked_on_sending = NULL;
241 stcb->asoc.ss_data.locked_on_sending = NULL;
247 sctp_ss_default_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
248 struct sctp_association *asoc SCTP_UNUSED)
250 /* Nothing to be done here */
255 sctp_ss_default_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
256 struct sctp_stream_out *strq SCTP_UNUSED, uint16_t *value SCTP_UNUSED)
258 /* Nothing to be done here */
263 sctp_ss_default_set_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_is_user_msgs_incomplete(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED)
277 * Real round-robin algorithm.
278 * Always interates the streams in ascending order.
281 sctp_ss_rr_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
282 struct sctp_stream_out *strq,
283 struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock)
285 struct sctp_stream_out *strqt;
287 if (holds_lock == 0) {
288 SCTP_TCB_SEND_LOCK(stcb);
290 if (!TAILQ_EMPTY(&strq->outqueue) &&
291 (strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
292 (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
293 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
294 TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
296 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
297 while (strqt != NULL && (strqt->sid < strq->sid)) {
298 strqt = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
301 TAILQ_INSERT_BEFORE(strqt, strq, ss_params.rr.next_spoke);
303 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
307 if (holds_lock == 0) {
308 SCTP_TCB_SEND_UNLOCK(stcb);
314 * Real round-robin per packet algorithm.
315 * Always interates the streams in ascending order and
316 * only fills messages of the same stream in a packet.
318 static struct sctp_stream_out *
319 sctp_ss_rrp_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
320 struct sctp_association *asoc)
322 return (asoc->ss_data.last_out_stream);
326 sctp_ss_rrp_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
327 struct sctp_association *asoc)
329 struct sctp_stream_out *strq, *strqt;
331 strqt = asoc->ss_data.last_out_stream;
333 /* Find the next stream to use */
335 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
337 strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
339 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
344 * If CMT is off, we must validate that the stream in question has
345 * the first item pointed towards are network destination requested
346 * by the caller. Note that if we turn out to be locked to a stream
347 * (assigning TSN's then we must stop, since we cannot look for
348 * another stream with data to send to that destination). In CMT's
349 * case, by skipping this check, we will send one data packet
350 * towards the requested net.
352 if (net != NULL && strq != NULL &&
353 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
354 if (TAILQ_FIRST(&strq->outqueue) &&
355 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
356 TAILQ_FIRST(&strq->outqueue)->net != net) {
357 if (strq == asoc->ss_data.last_out_stream) {
365 asoc->ss_data.last_out_stream = strq;
371 * Priority algorithm.
372 * Always prefers streams based on their priority id.
375 sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
376 int clear_values, int holds_lock)
378 if (holds_lock == 0) {
379 SCTP_TCB_SEND_LOCK(stcb);
381 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
382 struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
385 strq->ss_params.prio.priority = 0;
387 TAILQ_REMOVE(&asoc->ss_data.out.wheel, TAILQ_FIRST(&asoc->ss_data.out.wheel), ss_params.prio.next_spoke);
388 strq->ss_params.prio.next_spoke.tqe_next = NULL;
389 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
392 asoc->ss_data.last_out_stream = NULL;
393 if (holds_lock == 0) {
394 SCTP_TCB_SEND_UNLOCK(stcb);
400 sctp_ss_prio_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
402 if (with_strq != NULL) {
403 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
404 stcb->asoc.ss_data.locked_on_sending = strq;
406 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
407 stcb->asoc.ss_data.last_out_stream = strq;
410 strq->ss_params.prio.next_spoke.tqe_next = NULL;
411 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
412 if (with_strq != NULL) {
413 strq->ss_params.prio.priority = with_strq->ss_params.prio.priority;
415 strq->ss_params.prio.priority = 0;
421 sctp_ss_prio_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
422 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
425 struct sctp_stream_out *strqt;
427 if (holds_lock == 0) {
428 SCTP_TCB_SEND_LOCK(stcb);
430 /* Add to wheel if not already on it and stream queue not empty */
431 if (!TAILQ_EMPTY(&strq->outqueue) &&
432 (strq->ss_params.prio.next_spoke.tqe_next == NULL) &&
433 (strq->ss_params.prio.next_spoke.tqe_prev == NULL)) {
434 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
435 TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
437 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
438 while (strqt != NULL && strqt->ss_params.prio.priority < strq->ss_params.prio.priority) {
439 strqt = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
442 TAILQ_INSERT_BEFORE(strqt, strq, ss_params.prio.next_spoke);
444 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
448 if (holds_lock == 0) {
449 SCTP_TCB_SEND_UNLOCK(stcb);
455 sctp_ss_prio_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
456 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
459 if (holds_lock == 0) {
460 SCTP_TCB_SEND_LOCK(stcb);
463 * Remove from wheel if stream queue is empty and actually is on the
466 if (TAILQ_EMPTY(&strq->outqueue) &&
467 (strq->ss_params.prio.next_spoke.tqe_next != NULL ||
468 strq->ss_params.prio.next_spoke.tqe_prev != NULL)) {
469 if (asoc->ss_data.last_out_stream == strq) {
470 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead,
471 ss_params.prio.next_spoke);
472 if (asoc->ss_data.last_out_stream == NULL) {
473 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
476 if (asoc->ss_data.last_out_stream == strq) {
477 asoc->ss_data.last_out_stream = NULL;
480 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.prio.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 SCTP_UNUSED, struct sctp_nets *net,
492 struct sctp_association *asoc)
494 struct sctp_stream_out *strq, *strqt, *strqn;
496 strqt = asoc->ss_data.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) {
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->ss_data.last_out_stream) {
537 sctp_ss_prio_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
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)
568 if (holds_lock == 0) {
569 SCTP_TCB_SEND_LOCK(stcb);
571 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
572 struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
575 strq->ss_params.fb.rounds = -1;
577 TAILQ_REMOVE(&asoc->ss_data.out.wheel, TAILQ_FIRST(&asoc->ss_data.out.wheel), ss_params.fb.next_spoke);
578 strq->ss_params.fb.next_spoke.tqe_next = NULL;
579 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
581 asoc->ss_data.last_out_stream = NULL;
582 if (holds_lock == 0) {
583 SCTP_TCB_SEND_UNLOCK(stcb);
589 sctp_ss_fb_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
591 if (with_strq != NULL) {
592 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
593 stcb->asoc.ss_data.locked_on_sending = strq;
595 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
596 stcb->asoc.ss_data.last_out_stream = strq;
599 strq->ss_params.fb.next_spoke.tqe_next = NULL;
600 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
601 if (with_strq != NULL) {
602 strq->ss_params.fb.rounds = with_strq->ss_params.fb.rounds;
604 strq->ss_params.fb.rounds = -1;
610 sctp_ss_fb_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
611 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
614 if (holds_lock == 0) {
615 SCTP_TCB_SEND_LOCK(stcb);
617 if (!TAILQ_EMPTY(&strq->outqueue) &&
618 (strq->ss_params.fb.next_spoke.tqe_next == NULL) &&
619 (strq->ss_params.fb.next_spoke.tqe_prev == NULL)) {
620 if (strq->ss_params.fb.rounds < 0)
621 strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
622 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
624 if (holds_lock == 0) {
625 SCTP_TCB_SEND_UNLOCK(stcb);
631 sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
632 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
635 if (holds_lock == 0) {
636 SCTP_TCB_SEND_LOCK(stcb);
639 * Remove from wheel if stream queue is empty and actually is on the
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 (asoc->ss_data.last_out_stream == strq) {
646 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead,
647 ss_params.fb.next_spoke);
648 if (asoc->ss_data.last_out_stream == NULL) {
649 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
652 if (asoc->ss_data.last_out_stream == strq) {
653 asoc->ss_data.last_out_stream = NULL;
656 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
657 strq->ss_params.fb.next_spoke.tqe_next = NULL;
658 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
660 if (holds_lock == 0) {
661 SCTP_TCB_SEND_UNLOCK(stcb);
666 static struct sctp_stream_out *
667 sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
668 struct sctp_association *asoc)
670 struct sctp_stream_out *strq = NULL, *strqt;
672 if (asoc->ss_data.last_out_stream == NULL ||
673 TAILQ_FIRST(&asoc->ss_data.out.wheel) == TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead)) {
674 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
676 strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.fb.next_spoke);
679 if ((strqt != NULL) &&
680 ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) > 0) ||
681 (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0 &&
682 (net == NULL || (TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net == NULL) ||
683 (net != NULL && TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net != NULL &&
684 TAILQ_FIRST(&strqt->outqueue)->net == net))))) {
685 if ((strqt->ss_params.fb.rounds >= 0) && (strq == NULL ||
686 strqt->ss_params.fb.rounds < strq->ss_params.fb.rounds)) {
691 strqt = TAILQ_NEXT(strqt, ss_params.fb.next_spoke);
693 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
695 } while (strqt != strq);
700 sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED,
701 struct sctp_association *asoc, struct sctp_stream_out *strq,
702 int moved_how_much SCTP_UNUSED)
704 struct sctp_stream_queue_pending *sp;
705 struct sctp_stream_out *strqt;
708 if (stcb->asoc.idata_supported == 0) {
709 sp = TAILQ_FIRST(&strq->outqueue);
710 if ((sp != NULL) && (sp->some_taken == 1)) {
711 stcb->asoc.ss_data.locked_on_sending = strq;
713 stcb->asoc.ss_data.locked_on_sending = NULL;
716 stcb->asoc.ss_data.locked_on_sending = NULL;
718 subtract = strq->ss_params.fb.rounds;
719 TAILQ_FOREACH(strqt, &asoc->ss_data.out.wheel, ss_params.fb.next_spoke) {
720 strqt->ss_params.fb.rounds -= subtract;
721 if (strqt->ss_params.fb.rounds < 0)
722 strqt->ss_params.fb.rounds = 0;
724 if (TAILQ_FIRST(&strq->outqueue)) {
725 strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
727 strq->ss_params.fb.rounds = -1;
729 asoc->ss_data.last_out_stream = strq;
734 * First-come, first-serve algorithm.
735 * Maintains the order provided by the application.
738 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
739 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp,
743 sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
746 uint32_t x, n = 0, add_more = 1;
747 struct sctp_stream_queue_pending *sp;
750 TAILQ_INIT(&asoc->ss_data.out.list);
752 * If there is data in the stream queues already, the scheduler of
753 * an existing association has been changed. We can only cycle
754 * through the stream queues and add everything to the FCFS queue.
758 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
759 sp = TAILQ_FIRST(&stcb->asoc.strmout[i].outqueue);
761 /* Find n. message in current stream queue */
762 while (sp != NULL && x < n) {
763 sp = TAILQ_NEXT(sp, next);
767 sctp_ss_fcfs_add(stcb, &stcb->asoc, &stcb->asoc.strmout[i], sp, holds_lock);
777 sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
778 int clear_values, int holds_lock)
781 if (holds_lock == 0) {
782 SCTP_TCB_SEND_LOCK(stcb);
784 while (!TAILQ_EMPTY(&asoc->ss_data.out.list)) {
785 TAILQ_REMOVE(&asoc->ss_data.out.list, TAILQ_FIRST(&asoc->ss_data.out.list), ss_next);
787 if (holds_lock == 0) {
788 SCTP_TCB_SEND_UNLOCK(stcb);
795 sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
797 if (with_strq != NULL) {
798 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
799 stcb->asoc.ss_data.locked_on_sending = strq;
801 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
802 stcb->asoc.ss_data.last_out_stream = strq;
809 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
810 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
813 if (holds_lock == 0) {
814 SCTP_TCB_SEND_LOCK(stcb);
816 if (sp && (sp->ss_next.tqe_next == NULL) &&
817 (sp->ss_next.tqe_prev == NULL)) {
818 TAILQ_INSERT_TAIL(&asoc->ss_data.out.list, sp, ss_next);
820 if (holds_lock == 0) {
821 SCTP_TCB_SEND_UNLOCK(stcb);
827 sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
829 if (TAILQ_EMPTY(&asoc->ss_data.out.list)) {
837 sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
838 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
841 if (holds_lock == 0) {
842 SCTP_TCB_SEND_LOCK(stcb);
845 ((sp->ss_next.tqe_next != NULL) ||
846 (sp->ss_next.tqe_prev != NULL))) {
847 TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
849 if (holds_lock == 0) {
850 SCTP_TCB_SEND_UNLOCK(stcb);
856 static struct sctp_stream_out *
857 sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
858 struct sctp_association *asoc)
860 struct sctp_stream_out *strq;
861 struct sctp_stream_queue_pending *sp;
863 sp = TAILQ_FIRST(&asoc->ss_data.out.list);
866 strq = &asoc->strmout[sp->sid];
872 * If CMT is off, we must validate that the stream in question has
873 * the first item pointed towards are network destination requested
874 * by the caller. Note that if we turn out to be locked to a stream
875 * (assigning TSN's then we must stop, since we cannot look for
876 * another stream with data to send to that destination). In CMT's
877 * case, by skipping this check, we will send one data packet
878 * towards the requested net.
880 if (net != NULL && strq != NULL &&
881 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
882 if (TAILQ_FIRST(&strq->outqueue) &&
883 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
884 TAILQ_FIRST(&strq->outqueue)->net != net) {
885 sp = TAILQ_NEXT(sp, ss_next);
892 const struct sctp_ss_functions sctp_ss_functions[] = {
893 /* SCTP_SS_DEFAULT */
895 .sctp_ss_init = sctp_ss_default_init,
896 .sctp_ss_clear = sctp_ss_default_clear,
897 .sctp_ss_init_stream = sctp_ss_default_init_stream,
898 .sctp_ss_add_to_stream = sctp_ss_default_add,
899 .sctp_ss_is_empty = sctp_ss_default_is_empty,
900 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
901 .sctp_ss_select_stream = sctp_ss_default_select,
902 .sctp_ss_scheduled = sctp_ss_default_scheduled,
903 .sctp_ss_packet_done = sctp_ss_default_packet_done,
904 .sctp_ss_get_value = sctp_ss_default_get_value,
905 .sctp_ss_set_value = sctp_ss_default_set_value,
906 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
908 /* SCTP_SS_ROUND_ROBIN */
910 .sctp_ss_init = sctp_ss_default_init,
911 .sctp_ss_clear = sctp_ss_default_clear,
912 .sctp_ss_init_stream = sctp_ss_default_init_stream,
913 .sctp_ss_add_to_stream = sctp_ss_rr_add,
914 .sctp_ss_is_empty = sctp_ss_default_is_empty,
915 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
916 .sctp_ss_select_stream = sctp_ss_default_select,
917 .sctp_ss_scheduled = sctp_ss_default_scheduled,
918 .sctp_ss_packet_done = sctp_ss_default_packet_done,
919 .sctp_ss_get_value = sctp_ss_default_get_value,
920 .sctp_ss_set_value = sctp_ss_default_set_value,
921 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
923 /* SCTP_SS_ROUND_ROBIN_PACKET */
925 .sctp_ss_init = sctp_ss_default_init,
926 .sctp_ss_clear = sctp_ss_default_clear,
927 .sctp_ss_init_stream = sctp_ss_default_init_stream,
928 .sctp_ss_add_to_stream = sctp_ss_rr_add,
929 .sctp_ss_is_empty = sctp_ss_default_is_empty,
930 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
931 .sctp_ss_select_stream = sctp_ss_rrp_select,
932 .sctp_ss_scheduled = sctp_ss_default_scheduled,
933 .sctp_ss_packet_done = sctp_ss_rrp_packet_done,
934 .sctp_ss_get_value = sctp_ss_default_get_value,
935 .sctp_ss_set_value = sctp_ss_default_set_value,
936 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
938 /* SCTP_SS_PRIORITY */
940 .sctp_ss_init = sctp_ss_default_init,
941 .sctp_ss_clear = sctp_ss_prio_clear,
942 .sctp_ss_init_stream = sctp_ss_prio_init_stream,
943 .sctp_ss_add_to_stream = sctp_ss_prio_add,
944 .sctp_ss_is_empty = sctp_ss_default_is_empty,
945 .sctp_ss_remove_from_stream = sctp_ss_prio_remove,
946 .sctp_ss_select_stream = sctp_ss_prio_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_prio_get_value,
950 .sctp_ss_set_value = sctp_ss_prio_set_value,
951 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
953 /* SCTP_SS_FAIR_BANDWITH */
955 .sctp_ss_init = sctp_ss_default_init,
956 .sctp_ss_clear = sctp_ss_fb_clear,
957 .sctp_ss_init_stream = sctp_ss_fb_init_stream,
958 .sctp_ss_add_to_stream = sctp_ss_fb_add,
959 .sctp_ss_is_empty = sctp_ss_default_is_empty,
960 .sctp_ss_remove_from_stream = sctp_ss_fb_remove,
961 .sctp_ss_select_stream = sctp_ss_fb_select,
962 .sctp_ss_scheduled = sctp_ss_fb_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_FIRST_COME */
970 .sctp_ss_init = sctp_ss_fcfs_init,
971 .sctp_ss_clear = sctp_ss_fcfs_clear,
972 .sctp_ss_init_stream = sctp_ss_fcfs_init_stream,
973 .sctp_ss_add_to_stream = sctp_ss_fcfs_add,
974 .sctp_ss_is_empty = sctp_ss_fcfs_is_empty,
975 .sctp_ss_remove_from_stream = sctp_ss_fcfs_remove,
976 .sctp_ss_select_stream = sctp_ss_fcfs_select,
977 .sctp_ss_scheduled = sctp_ss_default_scheduled,
978 .sctp_ss_packet_done = sctp_ss_default_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