1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
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.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * a) Redistributions of source code must retain the above copyright notice,
12 *    this list of conditions and the following disclaimer.
13 *
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.
17 *
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.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD$");
33
34#include <netinet/sctp_pcb.h>
35
36/*
37 * Default simple round-robin algorithm.
38 * Just interates the streams in the order they appear.
39 */
40
41static void
42sctp_ss_default_add(struct sctp_tcb *, struct sctp_association *,
43    struct sctp_stream_out *,
44    struct sctp_stream_queue_pending *, int);
45
46static void
47sctp_ss_default_remove(struct sctp_tcb *, struct sctp_association *,
48    struct sctp_stream_out *,
49    struct sctp_stream_queue_pending *, int);
50
51static void
52sctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
53    int holds_lock)
54{
55	uint16_t i;
56
57	if (holds_lock == 0) {
58		SCTP_TCB_SEND_LOCK(stcb);
59	}
60	asoc->ss_data.locked_on_sending = NULL;
61	asoc->ss_data.last_out_stream = NULL;
62	TAILQ_INIT(&asoc->ss_data.out.wheel);
63	/*
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.
67	 */
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],
71		    NULL, 1);
72	}
73	if (holds_lock == 0) {
74		SCTP_TCB_SEND_UNLOCK(stcb);
75	}
76	return;
77}
78
79static void
80sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
81    int clear_values SCTP_UNUSED, int holds_lock)
82{
83	if (holds_lock == 0) {
84		SCTP_TCB_SEND_LOCK(stcb);
85	}
86	while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
87		struct sctp_stream_out *strq;
88
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;
93	}
94	asoc->ss_data.last_out_stream = NULL;
95	if (holds_lock == 0) {
96		SCTP_TCB_SEND_UNLOCK(stcb);
97	}
98	return;
99}
100
101static void
102sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
103{
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;
107		}
108		if (stcb->asoc.ss_data.last_out_stream == with_strq) {
109			stcb->asoc.ss_data.last_out_stream = strq;
110		}
111	}
112	strq->ss_params.rr.next_spoke.tqe_next = NULL;
113	strq->ss_params.rr.next_spoke.tqe_prev = NULL;
114	return;
115}
116
117static void
118sctp_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)
121{
122	if (holds_lock == 0) {
123		SCTP_TCB_SEND_LOCK(stcb);
124	}
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);
131	}
132	if (holds_lock == 0) {
133		SCTP_TCB_SEND_UNLOCK(stcb);
134	}
135	return;
136}
137
138static int
139sctp_ss_default_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
140{
141	if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
142		return (1);
143	} else {
144		return (0);
145	}
146}
147
148static void
149sctp_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)
152{
153	if (holds_lock == 0) {
154		SCTP_TCB_SEND_LOCK(stcb);
155	}
156	/*
157	 * Remove from wheel if stream queue is empty and actually is on the
158	 * wheel
159	 */
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,
165			    sctpwheel_listhead,
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,
169				    sctpwheel_listhead);
170			}
171			if (asoc->ss_data.last_out_stream == strq) {
172				asoc->ss_data.last_out_stream = NULL;
173			}
174		}
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;
178	}
179	if (holds_lock == 0) {
180		SCTP_TCB_SEND_UNLOCK(stcb);
181	}
182	return;
183}
184
185static struct sctp_stream_out *
186sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
187    struct sctp_association *asoc)
188{
189	struct sctp_stream_out *strq, *strqt;
190
191	if (asoc->ss_data.locked_on_sending) {
192		return (asoc->ss_data.locked_on_sending);
193	}
194	strqt = asoc->ss_data.last_out_stream;
195default_again:
196	/* Find the next stream to use */
197	if (strqt == NULL) {
198		strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
199	} else {
200		strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
201		if (strq == NULL) {
202			strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
203		}
204	}
205
206	/*
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.
214	 */
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) {
221				return (NULL);
222			} else {
223				strqt = strq;
224				goto default_again;
225			}
226		}
227	}
228	return (strq);
229}
230
231static void
232sctp_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)
237{
238	struct sctp_stream_queue_pending *sp;
239
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;
245		} else {
246			stcb->asoc.ss_data.locked_on_sending = NULL;
247		}
248	} else {
249		stcb->asoc.ss_data.locked_on_sending = NULL;
250	}
251	return;
252}
253
254static void
255sctp_ss_default_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
256    struct sctp_association *asoc SCTP_UNUSED)
257{
258	/* Nothing to be done here */
259	return;
260}
261
262static int
263sctp_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)
265{
266	/* Nothing to be done here */
267	return (-1);
268}
269
270static int
271sctp_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)
273{
274	/* Nothing to be done here */
275	return (-1);
276}
277
278static int
279sctp_ss_default_is_user_msgs_incomplete(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
280{
281	struct sctp_stream_out *strq;
282	struct sctp_stream_queue_pending *sp;
283
284	if (asoc->stream_queue_cnt != 1) {
285		return (0);
286	}
287	strq = asoc->ss_data.locked_on_sending;
288	if (strq == NULL) {
289		return (0);
290	}
291	sp = TAILQ_FIRST(&strq->outqueue);
292	if (sp == NULL) {
293		return (0);
294	}
295	return (!sp->msg_is_complete);
296}
297
298/*
299 * Real round-robin algorithm.
300 * Always interates the streams in ascending order.
301 */
302static void
303sctp_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)
306{
307	struct sctp_stream_out *strqt;
308
309	if (holds_lock == 0) {
310		SCTP_TCB_SEND_LOCK(stcb);
311	}
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);
317		} else {
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);
321			}
322			if (strqt != NULL) {
323				TAILQ_INSERT_BEFORE(strqt, strq, ss_params.rr.next_spoke);
324			} else {
325				TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
326			}
327		}
328	}
329	if (holds_lock == 0) {
330		SCTP_TCB_SEND_UNLOCK(stcb);
331	}
332	return;
333}
334
335/*
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.
339 */
340static struct sctp_stream_out *
341sctp_ss_rrp_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
342    struct sctp_association *asoc)
343{
344	return (asoc->ss_data.last_out_stream);
345}
346
347static void
348sctp_ss_rrp_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
349    struct sctp_association *asoc)
350{
351	struct sctp_stream_out *strq, *strqt;
352
353	strqt = asoc->ss_data.last_out_stream;
354rrp_again:
355	/* Find the next stream to use */
356	if (strqt == NULL) {
357		strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
358	} else {
359		strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
360		if (strq == NULL) {
361			strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
362		}
363	}
364
365	/*
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.
373	 */
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) {
380				strq = NULL;
381			} else {
382				strqt = strq;
383				goto rrp_again;
384			}
385		}
386	}
387	asoc->ss_data.last_out_stream = strq;
388	return;
389}
390
391/*
392 * Priority algorithm.
393 * Always prefers streams based on their priority id.
394 */
395static void
396sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
397    int clear_values, int holds_lock)
398{
399	if (holds_lock == 0) {
400		SCTP_TCB_SEND_LOCK(stcb);
401	}
402	while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
403		struct sctp_stream_out *strq;
404
405		strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
406		if (clear_values) {
407			strq->ss_params.prio.priority = 0;
408		}
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;
412	}
413	asoc->ss_data.last_out_stream = NULL;
414	if (holds_lock == 0) {
415		SCTP_TCB_SEND_UNLOCK(stcb);
416	}
417	return;
418}
419
420static void
421sctp_ss_prio_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
422{
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;
426		}
427		if (stcb->asoc.ss_data.last_out_stream == with_strq) {
428			stcb->asoc.ss_data.last_out_stream = strq;
429		}
430	}
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;
435	} else {
436		strq->ss_params.prio.priority = 0;
437	}
438	return;
439}
440
441static void
442sctp_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,
444    int holds_lock)
445{
446	struct sctp_stream_out *strqt;
447
448	if (holds_lock == 0) {
449		SCTP_TCB_SEND_LOCK(stcb);
450	}
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);
457		} else {
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);
461			}
462			if (strqt != NULL) {
463				TAILQ_INSERT_BEFORE(strqt, strq, ss_params.prio.next_spoke);
464			} else {
465				TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
466			}
467		}
468	}
469	if (holds_lock == 0) {
470		SCTP_TCB_SEND_UNLOCK(stcb);
471	}
472	return;
473}
474
475static void
476sctp_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,
478    int holds_lock)
479{
480	if (holds_lock == 0) {
481		SCTP_TCB_SEND_LOCK(stcb);
482	}
483	/*
484	 * Remove from wheel if stream queue is empty and actually is on the
485	 * wheel
486	 */
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,
495				    sctpwheel_listhead);
496			}
497			if (asoc->ss_data.last_out_stream == strq) {
498				asoc->ss_data.last_out_stream = NULL;
499			}
500		}
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;
504	}
505	if (holds_lock == 0) {
506		SCTP_TCB_SEND_UNLOCK(stcb);
507	}
508	return;
509}
510
511static struct sctp_stream_out *
512sctp_ss_prio_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
513    struct sctp_association *asoc)
514{
515	struct sctp_stream_out *strq, *strqt, *strqn;
516
517	if (asoc->ss_data.locked_on_sending) {
518		return (asoc->ss_data.locked_on_sending);
519	}
520	strqt = asoc->ss_data.last_out_stream;
521prio_again:
522	/* Find the next stream to use */
523	if (strqt == NULL) {
524		strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
525	} else {
526		strqn = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
527		if (strqn != NULL &&
528		    strqn->ss_params.prio.priority == strqt->ss_params.prio.priority) {
529			strq = strqn;
530		} else {
531			strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
532		}
533	}
534
535	/*
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.
543	 */
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) {
550				return (NULL);
551			} else {
552				strqt = strq;
553				goto prio_again;
554			}
555		}
556	}
557	return (strq);
558}
559
560static int
561sctp_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)
563{
564	if (strq == NULL) {
565		return (-1);
566	}
567	*value = strq->ss_params.prio.priority;
568	return (1);
569}
570
571static int
572sctp_ss_prio_set_value(struct sctp_tcb *stcb, struct sctp_association *asoc,
573    struct sctp_stream_out *strq, uint16_t value)
574{
575	if (strq == NULL) {
576		return (-1);
577	}
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);
581	return (1);
582}
583
584/*
585 * Fair bandwidth algorithm.
586 * Maintains an equal throughput per stream.
587 */
588static void
589sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
590    int clear_values, int holds_lock)
591{
592	if (holds_lock == 0) {
593		SCTP_TCB_SEND_LOCK(stcb);
594	}
595	while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
596		struct sctp_stream_out *strq;
597
598		strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
599		if (clear_values) {
600			strq->ss_params.fb.rounds = -1;
601		}
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;
605	}
606	asoc->ss_data.last_out_stream = NULL;
607	if (holds_lock == 0) {
608		SCTP_TCB_SEND_UNLOCK(stcb);
609	}
610	return;
611}
612
613static void
614sctp_ss_fb_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
615{
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;
619		}
620		if (stcb->asoc.ss_data.last_out_stream == with_strq) {
621			stcb->asoc.ss_data.last_out_stream = strq;
622		}
623	}
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;
628	} else {
629		strq->ss_params.fb.rounds = -1;
630	}
631	return;
632}
633
634static void
635sctp_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,
637    int holds_lock)
638{
639	if (holds_lock == 0) {
640		SCTP_TCB_SEND_LOCK(stcb);
641	}
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);
648	}
649	if (holds_lock == 0) {
650		SCTP_TCB_SEND_UNLOCK(stcb);
651	}
652	return;
653}
654
655static void
656sctp_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,
658    int holds_lock)
659{
660	if (holds_lock == 0) {
661		SCTP_TCB_SEND_LOCK(stcb);
662	}
663	/*
664	 * Remove from wheel if stream queue is empty and actually is on the
665	 * wheel
666	 */
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,
675				    sctpwheel_listhead);
676			}
677			if (asoc->ss_data.last_out_stream == strq) {
678				asoc->ss_data.last_out_stream = NULL;
679			}
680		}
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;
684	}
685	if (holds_lock == 0) {
686		SCTP_TCB_SEND_UNLOCK(stcb);
687	}
688	return;
689}
690
691static struct sctp_stream_out *
692sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
693    struct sctp_association *asoc)
694{
695	struct sctp_stream_out *strq = NULL, *strqt;
696
697	if (asoc->ss_data.locked_on_sending) {
698		return (asoc->ss_data.locked_on_sending);
699	}
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);
703	} else {
704		strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.fb.next_spoke);
705	}
706	do {
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)) {
715				strq = strqt;
716			}
717		}
718		if (strqt != NULL) {
719			strqt = TAILQ_NEXT(strqt, ss_params.fb.next_spoke);
720		} else {
721			strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
722		}
723	} while (strqt != strq);
724	return (strq);
725}
726
727static void
728sctp_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)
731{
732	struct sctp_stream_queue_pending *sp;
733	struct sctp_stream_out *strqt;
734	int subtract;
735
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;
740		} else {
741			stcb->asoc.ss_data.locked_on_sending = NULL;
742		}
743	} else {
744		stcb->asoc.ss_data.locked_on_sending = NULL;
745	}
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;
751	}
752	if (TAILQ_FIRST(&strq->outqueue)) {
753		strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
754	} else {
755		strq->ss_params.fb.rounds = -1;
756	}
757	asoc->ss_data.last_out_stream = strq;
758	return;
759}
760
761/*
762 * First-come, first-serve algorithm.
763 * Maintains the order provided by the application.
764 */
765static void
766sctp_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);
769
770static void
771sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
772    int holds_lock)
773{
774	uint32_t x, n = 0, add_more = 1;
775	struct sctp_stream_queue_pending *sp;
776	uint16_t i;
777
778	if (holds_lock == 0) {
779		SCTP_TCB_SEND_LOCK(stcb);
780	}
781	TAILQ_INIT(&asoc->ss_data.out.list);
782	/*
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.
786	 */
787	while (add_more) {
788		add_more = 0;
789		for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
790			sp = TAILQ_FIRST(&stcb->asoc.strmout[i].outqueue);
791			x = 0;
792			/* Find n. message in current stream queue */
793			while (sp != NULL && x < n) {
794				sp = TAILQ_NEXT(sp, next);
795				x++;
796			}
797			if (sp != NULL) {
798				sctp_ss_fcfs_add(stcb, &stcb->asoc, &stcb->asoc.strmout[i], sp, 1);
799				add_more = 1;
800			}
801		}
802		n++;
803	}
804	if (holds_lock == 0) {
805		SCTP_TCB_SEND_UNLOCK(stcb);
806	}
807	return;
808}
809
810static void
811sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
812    int clear_values, int holds_lock)
813{
814	struct sctp_stream_queue_pending *sp;
815
816	if (clear_values) {
817		if (holds_lock == 0) {
818			SCTP_TCB_SEND_LOCK(stcb);
819		}
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;
825		}
826		if (holds_lock == 0) {
827			SCTP_TCB_SEND_UNLOCK(stcb);
828		}
829	}
830	return;
831}
832
833static void
834sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
835{
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;
839		}
840		if (stcb->asoc.ss_data.last_out_stream == with_strq) {
841			stcb->asoc.ss_data.last_out_stream = strq;
842		}
843	}
844	strq->ss_params.fb.next_spoke.tqe_next = NULL;
845	strq->ss_params.fb.next_spoke.tqe_prev = NULL;
846	return;
847}
848
849static void
850sctp_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,
852    int holds_lock)
853{
854	if (holds_lock == 0) {
855		SCTP_TCB_SEND_LOCK(stcb);
856	}
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);
860	}
861	if (holds_lock == 0) {
862		SCTP_TCB_SEND_UNLOCK(stcb);
863	}
864	return;
865}
866
867static int
868sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
869{
870	if (TAILQ_EMPTY(&asoc->ss_data.out.list)) {
871		return (1);
872	} else {
873		return (0);
874	}
875}
876
877static void
878sctp_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,
880    int holds_lock)
881{
882	if (holds_lock == 0) {
883		SCTP_TCB_SEND_LOCK(stcb);
884	}
885	if (sp &&
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;
891	}
892	if (holds_lock == 0) {
893		SCTP_TCB_SEND_UNLOCK(stcb);
894	}
895	return;
896}
897
898static struct sctp_stream_out *
899sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
900    struct sctp_association *asoc)
901{
902	struct sctp_stream_out *strq;
903	struct sctp_stream_queue_pending *sp;
904
905	if (asoc->ss_data.locked_on_sending) {
906		return (asoc->ss_data.locked_on_sending);
907	}
908	sp = TAILQ_FIRST(&asoc->ss_data.out.list);
909default_again:
910	if (sp != NULL) {
911		strq = &asoc->strmout[sp->sid];
912	} else {
913		strq = NULL;
914	}
915
916	/*
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.
924	 */
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);
931			goto default_again;
932		}
933	}
934	return (strq);
935}
936
937const struct sctp_ss_functions sctp_ss_functions[] = {
938/* SCTP_SS_DEFAULT */
939	{
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
952	},
953/* SCTP_SS_ROUND_ROBIN */
954	{
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
967	},
968/* SCTP_SS_ROUND_ROBIN_PACKET */
969	{
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
982	},
983/* SCTP_SS_PRIORITY */
984	{
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
997	},
998/* SCTP_SS_FAIR_BANDWITH */
999	{
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
1012	},
1013/* SCTP_SS_FIRST_COME */
1014	{
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
1027	}
1028};
1029