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 if (holds_lock == 0) {
56 SCTP_TCB_SEND_LOCK(stcb);
58 asoc->ss_data.locked_on_sending = NULL;
59 asoc->ss_data.last_out_stream = NULL;
60 TAILQ_INIT(&asoc->ss_data.out.wheel);
62 * If there is data in the stream queues already, the scheduler of
63 * an existing association has been changed. We need to add all
64 * stream queues to the wheel.
66 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
67 stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, &stcb->asoc,
68 &stcb->asoc.strmout[i],
71 if (holds_lock == 0) {
72 SCTP_TCB_SEND_UNLOCK(stcb);
78 sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
79 int clear_values SCTP_UNUSED, int holds_lock)
81 if (holds_lock == 0) {
82 SCTP_TCB_SEND_LOCK(stcb);
84 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
85 struct sctp_stream_out *strq;
87 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
88 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
89 strq->ss_params.rr.next_spoke.tqe_next = NULL;
90 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
92 asoc->ss_data.last_out_stream = NULL;
93 if (holds_lock == 0) {
94 SCTP_TCB_SEND_UNLOCK(stcb);
100 sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
102 if (with_strq != NULL) {
103 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
104 stcb->asoc.ss_data.locked_on_sending = strq;
106 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
107 stcb->asoc.ss_data.last_out_stream = strq;
110 strq->ss_params.rr.next_spoke.tqe_next = NULL;
111 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
116 sctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
117 struct sctp_stream_out *strq,
118 struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock)
120 if (holds_lock == 0) {
121 SCTP_TCB_SEND_LOCK(stcb);
123 /* Add to wheel if not already on it and stream queue not empty */
124 if (!TAILQ_EMPTY(&strq->outqueue) &&
125 (strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
126 (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
127 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel,
128 strq, ss_params.rr.next_spoke);
130 if (holds_lock == 0) {
131 SCTP_TCB_SEND_UNLOCK(stcb);
137 sctp_ss_default_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
139 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
147 sctp_ss_default_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
148 struct sctp_stream_out *strq,
149 struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock)
151 if (holds_lock == 0) {
152 SCTP_TCB_SEND_LOCK(stcb);
155 * Remove from wheel if stream queue is empty and actually is on the
158 if (TAILQ_EMPTY(&strq->outqueue) &&
159 (strq->ss_params.rr.next_spoke.tqe_next != NULL ||
160 strq->ss_params.rr.next_spoke.tqe_prev != NULL)) {
161 if (asoc->ss_data.last_out_stream == strq) {
162 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream,
164 ss_params.rr.next_spoke);
165 if (asoc->ss_data.last_out_stream == NULL) {
166 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
169 if (asoc->ss_data.last_out_stream == strq) {
170 asoc->ss_data.last_out_stream = NULL;
173 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
174 strq->ss_params.rr.next_spoke.tqe_next = NULL;
175 strq->ss_params.rr.next_spoke.tqe_prev = NULL;
177 if (holds_lock == 0) {
178 SCTP_TCB_SEND_UNLOCK(stcb);
184 static struct sctp_stream_out *
185 sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
186 struct sctp_association *asoc)
188 struct sctp_stream_out *strq, *strqt;
190 if (asoc->ss_data.locked_on_sending) {
191 return (asoc->ss_data.locked_on_sending);
193 strqt = asoc->ss_data.last_out_stream;
195 /* Find the next stream to use */
197 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
199 strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
201 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
206 * If CMT is off, we must validate that the stream in question has
207 * the first item pointed towards are network destination requested
208 * by the caller. Note that if we turn out to be locked to a stream
209 * (assigning TSN's then we must stop, since we cannot look for
210 * another stream with data to send to that destination). In CMT's
211 * case, by skipping this check, we will send one data packet
212 * towards the requested net.
214 if (net != NULL && strq != NULL &&
215 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
216 if (TAILQ_FIRST(&strq->outqueue) &&
217 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
218 TAILQ_FIRST(&strq->outqueue)->net != net) {
219 if (strq == asoc->ss_data.last_out_stream) {
231 sctp_ss_default_scheduled(struct sctp_tcb *stcb,
232 struct sctp_nets *net SCTP_UNUSED,
233 struct sctp_association *asoc,
234 struct sctp_stream_out *strq,
235 int moved_how_much SCTP_UNUSED)
237 struct sctp_stream_queue_pending *sp;
239 asoc->ss_data.last_out_stream = strq;
240 if (stcb->asoc.idata_supported == 0) {
241 sp = TAILQ_FIRST(&strq->outqueue);
242 if ((sp != NULL) && (sp->some_taken == 1)) {
243 stcb->asoc.ss_data.locked_on_sending = strq;
245 stcb->asoc.ss_data.locked_on_sending = NULL;
248 stcb->asoc.ss_data.locked_on_sending = NULL;
254 sctp_ss_default_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
255 struct sctp_association *asoc SCTP_UNUSED)
257 /* Nothing to be done here */
262 sctp_ss_default_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
263 struct sctp_stream_out *strq SCTP_UNUSED, uint16_t *value SCTP_UNUSED)
265 /* Nothing to be done here */
270 sctp_ss_default_set_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
271 struct sctp_stream_out *strq SCTP_UNUSED, uint16_t value SCTP_UNUSED)
273 /* Nothing to be done here */
278 sctp_ss_default_is_user_msgs_incomplete(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
280 struct sctp_stream_out *strq;
281 struct sctp_stream_queue_pending *sp;
283 if (asoc->stream_queue_cnt != 1) {
286 strq = asoc->ss_data.locked_on_sending;
290 sp = TAILQ_FIRST(&strq->outqueue);
294 return (!sp->msg_is_complete);
298 * Real round-robin algorithm.
299 * Always interates the streams in ascending order.
302 sctp_ss_rr_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
303 struct sctp_stream_out *strq,
304 struct sctp_stream_queue_pending *sp SCTP_UNUSED, int holds_lock)
306 struct sctp_stream_out *strqt;
308 if (holds_lock == 0) {
309 SCTP_TCB_SEND_LOCK(stcb);
311 if (!TAILQ_EMPTY(&strq->outqueue) &&
312 (strq->ss_params.rr.next_spoke.tqe_next == NULL) &&
313 (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) {
314 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
315 TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
317 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
318 while (strqt != NULL && (strqt->sid < strq->sid)) {
319 strqt = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
322 TAILQ_INSERT_BEFORE(strqt, strq, ss_params.rr.next_spoke);
324 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
328 if (holds_lock == 0) {
329 SCTP_TCB_SEND_UNLOCK(stcb);
335 * Real round-robin per packet algorithm.
336 * Always interates the streams in ascending order and
337 * only fills messages of the same stream in a packet.
339 static struct sctp_stream_out *
340 sctp_ss_rrp_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
341 struct sctp_association *asoc)
343 return (asoc->ss_data.last_out_stream);
347 sctp_ss_rrp_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
348 struct sctp_association *asoc)
350 struct sctp_stream_out *strq, *strqt;
352 strqt = asoc->ss_data.last_out_stream;
354 /* Find the next stream to use */
356 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
358 strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
360 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
365 * If CMT is off, we must validate that the stream in question has
366 * the first item pointed towards are network destination requested
367 * by the caller. Note that if we turn out to be locked to a stream
368 * (assigning TSN's then we must stop, since we cannot look for
369 * another stream with data to send to that destination). In CMT's
370 * case, by skipping this check, we will send one data packet
371 * towards the requested net.
373 if (net != NULL && strq != NULL &&
374 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
375 if (TAILQ_FIRST(&strq->outqueue) &&
376 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
377 TAILQ_FIRST(&strq->outqueue)->net != net) {
378 if (strq == asoc->ss_data.last_out_stream) {
386 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;
414 asoc->ss_data.last_out_stream = NULL;
415 if (holds_lock == 0) {
416 SCTP_TCB_SEND_UNLOCK(stcb);
422 sctp_ss_prio_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
424 if (with_strq != NULL) {
425 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
426 stcb->asoc.ss_data.locked_on_sending = strq;
428 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
429 stcb->asoc.ss_data.last_out_stream = strq;
432 strq->ss_params.prio.next_spoke.tqe_next = NULL;
433 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
434 if (with_strq != NULL) {
435 strq->ss_params.prio.priority = with_strq->ss_params.prio.priority;
437 strq->ss_params.prio.priority = 0;
443 sctp_ss_prio_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
444 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
447 struct sctp_stream_out *strqt;
449 if (holds_lock == 0) {
450 SCTP_TCB_SEND_LOCK(stcb);
452 /* Add to wheel if not already on it and stream queue not empty */
453 if (!TAILQ_EMPTY(&strq->outqueue) &&
454 (strq->ss_params.prio.next_spoke.tqe_next == NULL) &&
455 (strq->ss_params.prio.next_spoke.tqe_prev == NULL)) {
456 if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
457 TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
459 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
460 while (strqt != NULL && strqt->ss_params.prio.priority < strq->ss_params.prio.priority) {
461 strqt = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
464 TAILQ_INSERT_BEFORE(strqt, strq, ss_params.prio.next_spoke);
466 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
470 if (holds_lock == 0) {
471 SCTP_TCB_SEND_UNLOCK(stcb);
477 sctp_ss_prio_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
478 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
481 if (holds_lock == 0) {
482 SCTP_TCB_SEND_LOCK(stcb);
485 * Remove from wheel if stream queue is empty and actually is on the
488 if (TAILQ_EMPTY(&strq->outqueue) &&
489 (strq->ss_params.prio.next_spoke.tqe_next != NULL ||
490 strq->ss_params.prio.next_spoke.tqe_prev != NULL)) {
491 if (asoc->ss_data.last_out_stream == strq) {
492 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead,
493 ss_params.prio.next_spoke);
494 if (asoc->ss_data.last_out_stream == NULL) {
495 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
498 if (asoc->ss_data.last_out_stream == strq) {
499 asoc->ss_data.last_out_stream = NULL;
502 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
503 strq->ss_params.prio.next_spoke.tqe_next = NULL;
504 strq->ss_params.prio.next_spoke.tqe_prev = NULL;
506 if (holds_lock == 0) {
507 SCTP_TCB_SEND_UNLOCK(stcb);
512 static struct sctp_stream_out *
513 sctp_ss_prio_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
514 struct sctp_association *asoc)
516 struct sctp_stream_out *strq, *strqt, *strqn;
518 strqt = asoc->ss_data.last_out_stream;
520 /* Find the next stream to use */
522 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
524 strqn = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
526 strqn->ss_params.prio.priority == strqt->ss_params.prio.priority) {
529 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
534 * If CMT is off, we must validate that the stream in question has
535 * the first item pointed towards are network destination requested
536 * by the caller. Note that if we turn out to be locked to a stream
537 * (assigning TSN's then we must stop, since we cannot look for
538 * another stream with data to send to that destination). In CMT's
539 * case, by skipping this check, we will send one data packet
540 * towards the requested net.
542 if (net != NULL && strq != NULL &&
543 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
544 if (TAILQ_FIRST(&strq->outqueue) &&
545 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
546 TAILQ_FIRST(&strq->outqueue)->net != net) {
547 if (strq == asoc->ss_data.last_out_stream) {
559 sctp_ss_prio_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
560 struct sctp_stream_out *strq, uint16_t *value)
565 *value = strq->ss_params.prio.priority;
570 sctp_ss_prio_set_value(struct sctp_tcb *stcb, struct sctp_association *asoc,
571 struct sctp_stream_out *strq, uint16_t value)
576 strq->ss_params.prio.priority = value;
577 sctp_ss_prio_remove(stcb, asoc, strq, NULL, 1);
578 sctp_ss_prio_add(stcb, asoc, strq, NULL, 1);
583 * Fair bandwidth algorithm.
584 * Maintains an equal troughput per stream.
587 sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
588 int clear_values, int holds_lock)
590 if (holds_lock == 0) {
591 SCTP_TCB_SEND_LOCK(stcb);
593 while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
594 struct sctp_stream_out *strq;
596 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
598 strq->ss_params.fb.rounds = -1;
600 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
601 strq->ss_params.fb.next_spoke.tqe_next = NULL;
602 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
604 asoc->ss_data.last_out_stream = NULL;
605 if (holds_lock == 0) {
606 SCTP_TCB_SEND_UNLOCK(stcb);
612 sctp_ss_fb_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
614 if (with_strq != NULL) {
615 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
616 stcb->asoc.ss_data.locked_on_sending = strq;
618 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
619 stcb->asoc.ss_data.last_out_stream = strq;
622 strq->ss_params.fb.next_spoke.tqe_next = NULL;
623 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
624 if (with_strq != NULL) {
625 strq->ss_params.fb.rounds = with_strq->ss_params.fb.rounds;
627 strq->ss_params.fb.rounds = -1;
633 sctp_ss_fb_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
634 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
637 if (holds_lock == 0) {
638 SCTP_TCB_SEND_LOCK(stcb);
640 if (!TAILQ_EMPTY(&strq->outqueue) &&
641 (strq->ss_params.fb.next_spoke.tqe_next == NULL) &&
642 (strq->ss_params.fb.next_spoke.tqe_prev == NULL)) {
643 if (strq->ss_params.fb.rounds < 0)
644 strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
645 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
647 if (holds_lock == 0) {
648 SCTP_TCB_SEND_UNLOCK(stcb);
654 sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
655 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
658 if (holds_lock == 0) {
659 SCTP_TCB_SEND_LOCK(stcb);
662 * Remove from wheel if stream queue is empty and actually is on the
665 if (TAILQ_EMPTY(&strq->outqueue) &&
666 (strq->ss_params.fb.next_spoke.tqe_next != NULL ||
667 strq->ss_params.fb.next_spoke.tqe_prev != NULL)) {
668 if (asoc->ss_data.last_out_stream == strq) {
669 asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead,
670 ss_params.fb.next_spoke);
671 if (asoc->ss_data.last_out_stream == NULL) {
672 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
675 if (asoc->ss_data.last_out_stream == strq) {
676 asoc->ss_data.last_out_stream = NULL;
679 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
680 strq->ss_params.fb.next_spoke.tqe_next = NULL;
681 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
683 if (holds_lock == 0) {
684 SCTP_TCB_SEND_UNLOCK(stcb);
689 static struct sctp_stream_out *
690 sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
691 struct sctp_association *asoc)
693 struct sctp_stream_out *strq = NULL, *strqt;
695 if (asoc->ss_data.last_out_stream == NULL ||
696 TAILQ_FIRST(&asoc->ss_data.out.wheel) == TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead)) {
697 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
699 strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.fb.next_spoke);
702 if ((strqt != NULL) &&
703 ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) > 0) ||
704 (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0 &&
705 (net == NULL || (TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net == NULL) ||
706 (net != NULL && TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net != NULL &&
707 TAILQ_FIRST(&strqt->outqueue)->net == net))))) {
708 if ((strqt->ss_params.fb.rounds >= 0) && (strq == NULL ||
709 strqt->ss_params.fb.rounds < strq->ss_params.fb.rounds)) {
714 strqt = TAILQ_NEXT(strqt, ss_params.fb.next_spoke);
716 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
718 } while (strqt != strq);
723 sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED,
724 struct sctp_association *asoc, struct sctp_stream_out *strq,
725 int moved_how_much SCTP_UNUSED)
727 struct sctp_stream_queue_pending *sp;
728 struct sctp_stream_out *strqt;
731 if (stcb->asoc.idata_supported == 0) {
732 sp = TAILQ_FIRST(&strq->outqueue);
733 if ((sp != NULL) && (sp->some_taken == 1)) {
734 stcb->asoc.ss_data.locked_on_sending = strq;
736 stcb->asoc.ss_data.locked_on_sending = NULL;
739 stcb->asoc.ss_data.locked_on_sending = NULL;
741 subtract = strq->ss_params.fb.rounds;
742 TAILQ_FOREACH(strqt, &asoc->ss_data.out.wheel, ss_params.fb.next_spoke) {
743 strqt->ss_params.fb.rounds -= subtract;
744 if (strqt->ss_params.fb.rounds < 0)
745 strqt->ss_params.fb.rounds = 0;
747 if (TAILQ_FIRST(&strq->outqueue)) {
748 strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
750 strq->ss_params.fb.rounds = -1;
752 asoc->ss_data.last_out_stream = strq;
757 * First-come, first-serve algorithm.
758 * Maintains the order provided by the application.
761 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
762 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp,
766 sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
769 uint32_t x, n = 0, add_more = 1;
770 struct sctp_stream_queue_pending *sp;
773 if (holds_lock == 0) {
774 SCTP_TCB_SEND_LOCK(stcb);
776 TAILQ_INIT(&asoc->ss_data.out.list);
778 * If there is data in the stream queues already, the scheduler of
779 * an existing association has been changed. We can only cycle
780 * through the stream queues and add everything to the FCFS queue.
784 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
785 sp = TAILQ_FIRST(&stcb->asoc.strmout[i].outqueue);
787 /* Find n. message in current stream queue */
788 while (sp != NULL && x < n) {
789 sp = TAILQ_NEXT(sp, next);
793 sctp_ss_fcfs_add(stcb, &stcb->asoc, &stcb->asoc.strmout[i], sp, 1);
799 if (holds_lock == 0) {
800 SCTP_TCB_SEND_UNLOCK(stcb);
806 sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
807 int clear_values, int holds_lock)
809 struct sctp_stream_queue_pending *sp;
812 if (holds_lock == 0) {
813 SCTP_TCB_SEND_LOCK(stcb);
815 while (!TAILQ_EMPTY(&asoc->ss_data.out.list)) {
816 sp = TAILQ_FIRST(&asoc->ss_data.out.list);
817 TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
818 sp->ss_next.tqe_next = NULL;
819 sp->ss_next.tqe_prev = NULL;
821 if (holds_lock == 0) {
822 SCTP_TCB_SEND_UNLOCK(stcb);
829 sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
831 if (with_strq != NULL) {
832 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
833 stcb->asoc.ss_data.locked_on_sending = strq;
835 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
836 stcb->asoc.ss_data.last_out_stream = strq;
839 strq->ss_params.fb.next_spoke.tqe_next = NULL;
840 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
845 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
846 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
849 if (holds_lock == 0) {
850 SCTP_TCB_SEND_LOCK(stcb);
852 if (sp && (sp->ss_next.tqe_next == NULL) &&
853 (sp->ss_next.tqe_prev == NULL)) {
854 TAILQ_INSERT_TAIL(&asoc->ss_data.out.list, sp, ss_next);
856 if (holds_lock == 0) {
857 SCTP_TCB_SEND_UNLOCK(stcb);
863 sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
865 if (TAILQ_EMPTY(&asoc->ss_data.out.list)) {
873 sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
874 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
877 if (holds_lock == 0) {
878 SCTP_TCB_SEND_LOCK(stcb);
881 ((sp->ss_next.tqe_next != NULL) ||
882 (sp->ss_next.tqe_prev != NULL))) {
883 TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
884 sp->ss_next.tqe_next = NULL;
885 sp->ss_next.tqe_prev = NULL;
887 if (holds_lock == 0) {
888 SCTP_TCB_SEND_UNLOCK(stcb);
894 static struct sctp_stream_out *
895 sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
896 struct sctp_association *asoc)
898 struct sctp_stream_out *strq;
899 struct sctp_stream_queue_pending *sp;
901 sp = TAILQ_FIRST(&asoc->ss_data.out.list);
904 strq = &asoc->strmout[sp->sid];
910 * If CMT is off, we must validate that the stream in question has
911 * the first item pointed towards are network destination requested
912 * by the caller. Note that if we turn out to be locked to a stream
913 * (assigning TSN's then we must stop, since we cannot look for
914 * another stream with data to send to that destination). In CMT's
915 * case, by skipping this check, we will send one data packet
916 * towards the requested net.
918 if (net != NULL && strq != NULL &&
919 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
920 if (TAILQ_FIRST(&strq->outqueue) &&
921 TAILQ_FIRST(&strq->outqueue)->net != NULL &&
922 TAILQ_FIRST(&strq->outqueue)->net != net) {
923 sp = TAILQ_NEXT(sp, ss_next);
930 const struct sctp_ss_functions sctp_ss_functions[] = {
931 /* SCTP_SS_DEFAULT */
933 .sctp_ss_init = sctp_ss_default_init,
934 .sctp_ss_clear = sctp_ss_default_clear,
935 .sctp_ss_init_stream = sctp_ss_default_init_stream,
936 .sctp_ss_add_to_stream = sctp_ss_default_add,
937 .sctp_ss_is_empty = sctp_ss_default_is_empty,
938 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
939 .sctp_ss_select_stream = sctp_ss_default_select,
940 .sctp_ss_scheduled = sctp_ss_default_scheduled,
941 .sctp_ss_packet_done = sctp_ss_default_packet_done,
942 .sctp_ss_get_value = sctp_ss_default_get_value,
943 .sctp_ss_set_value = sctp_ss_default_set_value,
944 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
946 /* SCTP_SS_ROUND_ROBIN */
948 .sctp_ss_init = sctp_ss_default_init,
949 .sctp_ss_clear = sctp_ss_default_clear,
950 .sctp_ss_init_stream = sctp_ss_default_init_stream,
951 .sctp_ss_add_to_stream = sctp_ss_rr_add,
952 .sctp_ss_is_empty = sctp_ss_default_is_empty,
953 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
954 .sctp_ss_select_stream = sctp_ss_default_select,
955 .sctp_ss_scheduled = sctp_ss_default_scheduled,
956 .sctp_ss_packet_done = sctp_ss_default_packet_done,
957 .sctp_ss_get_value = sctp_ss_default_get_value,
958 .sctp_ss_set_value = sctp_ss_default_set_value,
959 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
961 /* SCTP_SS_ROUND_ROBIN_PACKET */
963 .sctp_ss_init = sctp_ss_default_init,
964 .sctp_ss_clear = sctp_ss_default_clear,
965 .sctp_ss_init_stream = sctp_ss_default_init_stream,
966 .sctp_ss_add_to_stream = sctp_ss_rr_add,
967 .sctp_ss_is_empty = sctp_ss_default_is_empty,
968 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
969 .sctp_ss_select_stream = sctp_ss_rrp_select,
970 .sctp_ss_scheduled = sctp_ss_default_scheduled,
971 .sctp_ss_packet_done = sctp_ss_rrp_packet_done,
972 .sctp_ss_get_value = sctp_ss_default_get_value,
973 .sctp_ss_set_value = sctp_ss_default_set_value,
974 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
976 /* SCTP_SS_PRIORITY */
978 .sctp_ss_init = sctp_ss_default_init,
979 .sctp_ss_clear = sctp_ss_prio_clear,
980 .sctp_ss_init_stream = sctp_ss_prio_init_stream,
981 .sctp_ss_add_to_stream = sctp_ss_prio_add,
982 .sctp_ss_is_empty = sctp_ss_default_is_empty,
983 .sctp_ss_remove_from_stream = sctp_ss_prio_remove,
984 .sctp_ss_select_stream = sctp_ss_prio_select,
985 .sctp_ss_scheduled = sctp_ss_default_scheduled,
986 .sctp_ss_packet_done = sctp_ss_default_packet_done,
987 .sctp_ss_get_value = sctp_ss_prio_get_value,
988 .sctp_ss_set_value = sctp_ss_prio_set_value,
989 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
991 /* SCTP_SS_FAIR_BANDWITH */
993 .sctp_ss_init = sctp_ss_default_init,
994 .sctp_ss_clear = sctp_ss_fb_clear,
995 .sctp_ss_init_stream = sctp_ss_fb_init_stream,
996 .sctp_ss_add_to_stream = sctp_ss_fb_add,
997 .sctp_ss_is_empty = sctp_ss_default_is_empty,
998 .sctp_ss_remove_from_stream = sctp_ss_fb_remove,
999 .sctp_ss_select_stream = sctp_ss_fb_select,
1000 .sctp_ss_scheduled = sctp_ss_fb_scheduled,
1001 .sctp_ss_packet_done = sctp_ss_default_packet_done,
1002 .sctp_ss_get_value = sctp_ss_default_get_value,
1003 .sctp_ss_set_value = sctp_ss_default_set_value,
1004 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
1006 /* SCTP_SS_FIRST_COME */
1008 .sctp_ss_init = sctp_ss_fcfs_init,
1009 .sctp_ss_clear = sctp_ss_fcfs_clear,
1010 .sctp_ss_init_stream = sctp_ss_fcfs_init_stream,
1011 .sctp_ss_add_to_stream = sctp_ss_fcfs_add,
1012 .sctp_ss_is_empty = sctp_ss_fcfs_is_empty,
1013 .sctp_ss_remove_from_stream = sctp_ss_fcfs_remove,
1014 .sctp_ss_select_stream = sctp_ss_fcfs_select,
1015 .sctp_ss_scheduled = sctp_ss_default_scheduled,
1016 .sctp_ss_packet_done = sctp_ss_default_packet_done,
1017 .sctp_ss_get_value = sctp_ss_default_get_value,
1018 .sctp_ss_set_value = sctp_ss_default_set_value,
1019 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete