1/*-
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.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * a) Redistributions of source code must retain the above copyright notice,
10 *    this list of conditions and the following disclaimer.
11 *
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.
15 *
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.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/11/sys/netinet/sctp_ss_functions.c 360766 2020-05-07 03:24:34Z tuexen $");
31
32#include <netinet/sctp_pcb.h>
33
34/*
35 * Default simple round-robin algorithm.
36 * Just interates the streams in the order they appear.
37 */
38
39static void
40sctp_ss_default_add(struct sctp_tcb *, struct sctp_association *,
41    struct sctp_stream_out *,
42    struct sctp_stream_queue_pending *, int);
43
44static void
45sctp_ss_default_remove(struct sctp_tcb *, struct sctp_association *,
46    struct sctp_stream_out *,
47    struct sctp_stream_queue_pending *, int);
48
49static void
50sctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
51    int holds_lock)
52{
53	uint16_t i;
54
55	if (holds_lock == 0) {
56		SCTP_TCB_SEND_LOCK(stcb);
57	}
58	asoc->ss_data.locked_on_sending = NULL;
59	asoc->ss_data.last_out_stream = NULL;
60	TAILQ_INIT(&asoc->ss_data.out.wheel);
61	/*
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.
65	 */
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],
69		    NULL, 1);
70	}
71	if (holds_lock == 0) {
72		SCTP_TCB_SEND_UNLOCK(stcb);
73	}
74	return;
75}
76
77static void
78sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
79    int clear_values SCTP_UNUSED, int holds_lock)
80{
81	if (holds_lock == 0) {
82		SCTP_TCB_SEND_LOCK(stcb);
83	}
84	while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
85		struct sctp_stream_out *strq;
86
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;
91	}
92	asoc->ss_data.last_out_stream = NULL;
93	if (holds_lock == 0) {
94		SCTP_TCB_SEND_UNLOCK(stcb);
95	}
96	return;
97}
98
99static void
100sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
101{
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;
105		}
106		if (stcb->asoc.ss_data.last_out_stream == with_strq) {
107			stcb->asoc.ss_data.last_out_stream = strq;
108		}
109	}
110	strq->ss_params.rr.next_spoke.tqe_next = NULL;
111	strq->ss_params.rr.next_spoke.tqe_prev = NULL;
112	return;
113}
114
115static void
116sctp_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)
119{
120	if (holds_lock == 0) {
121		SCTP_TCB_SEND_LOCK(stcb);
122	}
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);
129	}
130	if (holds_lock == 0) {
131		SCTP_TCB_SEND_UNLOCK(stcb);
132	}
133	return;
134}
135
136static int
137sctp_ss_default_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
138{
139	if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
140		return (1);
141	} else {
142		return (0);
143	}
144}
145
146static void
147sctp_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)
150{
151	if (holds_lock == 0) {
152		SCTP_TCB_SEND_LOCK(stcb);
153	}
154	/*
155	 * Remove from wheel if stream queue is empty and actually is on the
156	 * wheel
157	 */
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,
163			    sctpwheel_listhead,
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,
167				    sctpwheel_listhead);
168			}
169			if (asoc->ss_data.last_out_stream == strq) {
170				asoc->ss_data.last_out_stream = NULL;
171			}
172		}
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;
176	}
177	if (holds_lock == 0) {
178		SCTP_TCB_SEND_UNLOCK(stcb);
179	}
180	return;
181}
182
183
184static struct sctp_stream_out *
185sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
186    struct sctp_association *asoc)
187{
188	struct sctp_stream_out *strq, *strqt;
189
190	if (asoc->ss_data.locked_on_sending) {
191		return (asoc->ss_data.locked_on_sending);
192	}
193	strqt = asoc->ss_data.last_out_stream;
194default_again:
195	/* Find the next stream to use */
196	if (strqt == NULL) {
197		strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
198	} else {
199		strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
200		if (strq == NULL) {
201			strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
202		}
203	}
204
205	/*
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.
213	 */
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) {
220				return (NULL);
221			} else {
222				strqt = strq;
223				goto default_again;
224			}
225		}
226	}
227	return (strq);
228}
229
230static void
231sctp_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)
236{
237	struct sctp_stream_queue_pending *sp;
238
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;
244		} else {
245			stcb->asoc.ss_data.locked_on_sending = NULL;
246		}
247	} else {
248		stcb->asoc.ss_data.locked_on_sending = NULL;
249	}
250	return;
251}
252
253static void
254sctp_ss_default_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
255    struct sctp_association *asoc SCTP_UNUSED)
256{
257	/* Nothing to be done here */
258	return;
259}
260
261static int
262sctp_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)
264{
265	/* Nothing to be done here */
266	return (-1);
267}
268
269static int
270sctp_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)
272{
273	/* Nothing to be done here */
274	return (-1);
275}
276
277static int
278sctp_ss_default_is_user_msgs_incomplete(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
279{
280	struct sctp_stream_out *strq;
281	struct sctp_stream_queue_pending *sp;
282
283	if (asoc->stream_queue_cnt != 1) {
284		return (0);
285	}
286	strq = asoc->ss_data.locked_on_sending;
287	if (strq == NULL) {
288		return (0);
289	}
290	sp = TAILQ_FIRST(&strq->outqueue);
291	if (sp == NULL) {
292		return (0);
293	}
294	return (!sp->msg_is_complete);
295}
296
297/*
298 * Real round-robin algorithm.
299 * Always interates the streams in ascending order.
300 */
301static void
302sctp_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)
305{
306	struct sctp_stream_out *strqt;
307
308	if (holds_lock == 0) {
309		SCTP_TCB_SEND_LOCK(stcb);
310	}
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);
316		} else {
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);
320			}
321			if (strqt != NULL) {
322				TAILQ_INSERT_BEFORE(strqt, strq, ss_params.rr.next_spoke);
323			} else {
324				TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.rr.next_spoke);
325			}
326		}
327	}
328	if (holds_lock == 0) {
329		SCTP_TCB_SEND_UNLOCK(stcb);
330	}
331	return;
332}
333
334/*
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.
338 */
339static struct sctp_stream_out *
340sctp_ss_rrp_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
341    struct sctp_association *asoc)
342{
343	return (asoc->ss_data.last_out_stream);
344}
345
346static void
347sctp_ss_rrp_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
348    struct sctp_association *asoc)
349{
350	struct sctp_stream_out *strq, *strqt;
351
352	strqt = asoc->ss_data.last_out_stream;
353rrp_again:
354	/* Find the next stream to use */
355	if (strqt == NULL) {
356		strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
357	} else {
358		strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke);
359		if (strq == NULL) {
360			strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
361		}
362	}
363
364	/*
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.
372	 */
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) {
379				strq = NULL;
380			} else {
381				strqt = strq;
382				goto rrp_again;
383			}
384		}
385	}
386	asoc->ss_data.last_out_stream = strq;
387	return;
388}
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	}
414	asoc->ss_data.last_out_stream = NULL;
415	if (holds_lock == 0) {
416		SCTP_TCB_SEND_UNLOCK(stcb);
417	}
418	return;
419}
420
421static void
422sctp_ss_prio_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
423{
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;
427		}
428		if (stcb->asoc.ss_data.last_out_stream == with_strq) {
429			stcb->asoc.ss_data.last_out_stream = strq;
430		}
431	}
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;
436	} else {
437		strq->ss_params.prio.priority = 0;
438	}
439	return;
440}
441
442static void
443sctp_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,
445    int holds_lock)
446{
447	struct sctp_stream_out *strqt;
448
449	if (holds_lock == 0) {
450		SCTP_TCB_SEND_LOCK(stcb);
451	}
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);
458		} else {
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);
462			}
463			if (strqt != NULL) {
464				TAILQ_INSERT_BEFORE(strqt, strq, ss_params.prio.next_spoke);
465			} else {
466				TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.prio.next_spoke);
467			}
468		}
469	}
470	if (holds_lock == 0) {
471		SCTP_TCB_SEND_UNLOCK(stcb);
472	}
473	return;
474}
475
476static void
477sctp_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,
479    int holds_lock)
480{
481	if (holds_lock == 0) {
482		SCTP_TCB_SEND_LOCK(stcb);
483	}
484	/*
485	 * Remove from wheel if stream queue is empty and actually is on the
486	 * wheel
487	 */
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,
496				    sctpwheel_listhead);
497			}
498			if (asoc->ss_data.last_out_stream == strq) {
499				asoc->ss_data.last_out_stream = NULL;
500			}
501		}
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;
505	}
506	if (holds_lock == 0) {
507		SCTP_TCB_SEND_UNLOCK(stcb);
508	}
509	return;
510}
511
512static struct sctp_stream_out *
513sctp_ss_prio_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
514    struct sctp_association *asoc)
515{
516	struct sctp_stream_out *strq, *strqt, *strqn;
517
518	if (asoc->ss_data.locked_on_sending) {
519		return (asoc->ss_data.locked_on_sending);
520	}
521	strqt = asoc->ss_data.last_out_stream;
522prio_again:
523	/* Find the next stream to use */
524	if (strqt == NULL) {
525		strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
526	} else {
527		strqn = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
528		if (strqn != NULL &&
529		    strqn->ss_params.prio.priority == strqt->ss_params.prio.priority) {
530			strq = strqn;
531		} else {
532			strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
533		}
534	}
535
536	/*
537	 * If CMT is off, we must validate that the stream in question has
538	 * the first item pointed towards are network destination requested
539	 * by the caller. Note that if we turn out to be locked to a stream
540	 * (assigning TSN's then we must stop, since we cannot look for
541	 * another stream with data to send to that destination). In CMT's
542	 * case, by skipping this check, we will send one data packet
543	 * towards the requested net.
544	 */
545	if (net != NULL && strq != NULL &&
546	    SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
547		if (TAILQ_FIRST(&strq->outqueue) &&
548		    TAILQ_FIRST(&strq->outqueue)->net != NULL &&
549		    TAILQ_FIRST(&strq->outqueue)->net != net) {
550			if (strq == asoc->ss_data.last_out_stream) {
551				return (NULL);
552			} else {
553				strqt = strq;
554				goto prio_again;
555			}
556		}
557	}
558	return (strq);
559}
560
561static int
562sctp_ss_prio_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
563    struct sctp_stream_out *strq, uint16_t *value)
564{
565	if (strq == NULL) {
566		return (-1);
567	}
568	*value = strq->ss_params.prio.priority;
569	return (1);
570}
571
572static int
573sctp_ss_prio_set_value(struct sctp_tcb *stcb, struct sctp_association *asoc,
574    struct sctp_stream_out *strq, uint16_t value)
575{
576	if (strq == NULL) {
577		return (-1);
578	}
579	strq->ss_params.prio.priority = value;
580	sctp_ss_prio_remove(stcb, asoc, strq, NULL, 1);
581	sctp_ss_prio_add(stcb, asoc, strq, NULL, 1);
582	return (1);
583}
584
585/*
586 * Fair bandwidth algorithm.
587 * Maintains an equal troughput per stream.
588 */
589static void
590sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
591    int clear_values, int holds_lock)
592{
593	if (holds_lock == 0) {
594		SCTP_TCB_SEND_LOCK(stcb);
595	}
596	while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
597		struct sctp_stream_out *strq;
598
599		strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
600		if (clear_values) {
601			strq->ss_params.fb.rounds = -1;
602		}
603		TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
604		strq->ss_params.fb.next_spoke.tqe_next = NULL;
605		strq->ss_params.fb.next_spoke.tqe_prev = NULL;
606	}
607	asoc->ss_data.last_out_stream = NULL;
608	if (holds_lock == 0) {
609		SCTP_TCB_SEND_UNLOCK(stcb);
610	}
611	return;
612}
613
614static void
615sctp_ss_fb_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
616{
617	if (with_strq != NULL) {
618		if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
619			stcb->asoc.ss_data.locked_on_sending = strq;
620		}
621		if (stcb->asoc.ss_data.last_out_stream == with_strq) {
622			stcb->asoc.ss_data.last_out_stream = strq;
623		}
624	}
625	strq->ss_params.fb.next_spoke.tqe_next = NULL;
626	strq->ss_params.fb.next_spoke.tqe_prev = NULL;
627	if (with_strq != NULL) {
628		strq->ss_params.fb.rounds = with_strq->ss_params.fb.rounds;
629	} else {
630		strq->ss_params.fb.rounds = -1;
631	}
632	return;
633}
634
635static void
636sctp_ss_fb_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
637    struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
638    int holds_lock)
639{
640	if (holds_lock == 0) {
641		SCTP_TCB_SEND_LOCK(stcb);
642	}
643	if (!TAILQ_EMPTY(&strq->outqueue) &&
644	    (strq->ss_params.fb.next_spoke.tqe_next == NULL) &&
645	    (strq->ss_params.fb.next_spoke.tqe_prev == NULL)) {
646		if (strq->ss_params.fb.rounds < 0)
647			strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
648		TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
649	}
650	if (holds_lock == 0) {
651		SCTP_TCB_SEND_UNLOCK(stcb);
652	}
653	return;
654}
655
656static void
657sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
658    struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
659    int holds_lock)
660{
661	if (holds_lock == 0) {
662		SCTP_TCB_SEND_LOCK(stcb);
663	}
664	/*
665	 * Remove from wheel if stream queue is empty and actually is on the
666	 * wheel
667	 */
668	if (TAILQ_EMPTY(&strq->outqueue) &&
669	    (strq->ss_params.fb.next_spoke.tqe_next != NULL ||
670	    strq->ss_params.fb.next_spoke.tqe_prev != NULL)) {
671		if (asoc->ss_data.last_out_stream == strq) {
672			asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead,
673			    ss_params.fb.next_spoke);
674			if (asoc->ss_data.last_out_stream == NULL) {
675				asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
676				    sctpwheel_listhead);
677			}
678			if (asoc->ss_data.last_out_stream == strq) {
679				asoc->ss_data.last_out_stream = NULL;
680			}
681		}
682		TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
683		strq->ss_params.fb.next_spoke.tqe_next = NULL;
684		strq->ss_params.fb.next_spoke.tqe_prev = NULL;
685	}
686	if (holds_lock == 0) {
687		SCTP_TCB_SEND_UNLOCK(stcb);
688	}
689	return;
690}
691
692static struct sctp_stream_out *
693sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
694    struct sctp_association *asoc)
695{
696	struct sctp_stream_out *strq = NULL, *strqt;
697
698	if (asoc->ss_data.locked_on_sending) {
699		return (asoc->ss_data.locked_on_sending);
700	}
701	if (asoc->ss_data.last_out_stream == NULL ||
702	    TAILQ_FIRST(&asoc->ss_data.out.wheel) == TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead)) {
703		strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
704	} else {
705		strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.fb.next_spoke);
706	}
707	do {
708		if ((strqt != NULL) &&
709		    ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) > 0) ||
710		    (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0 &&
711		    (net == NULL || (TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net == NULL) ||
712		    (net != NULL && TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net != NULL &&
713		    TAILQ_FIRST(&strqt->outqueue)->net == net))))) {
714			if ((strqt->ss_params.fb.rounds >= 0) && (strq == NULL ||
715			    strqt->ss_params.fb.rounds < strq->ss_params.fb.rounds)) {
716				strq = strqt;
717			}
718		}
719		if (strqt != NULL) {
720			strqt = TAILQ_NEXT(strqt, ss_params.fb.next_spoke);
721		} else {
722			strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
723		}
724	} while (strqt != strq);
725	return (strq);
726}
727
728static void
729sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED,
730    struct sctp_association *asoc, struct sctp_stream_out *strq,
731    int moved_how_much SCTP_UNUSED)
732{
733	struct sctp_stream_queue_pending *sp;
734	struct sctp_stream_out *strqt;
735	int subtract;
736
737	if (stcb->asoc.idata_supported == 0) {
738		sp = TAILQ_FIRST(&strq->outqueue);
739		if ((sp != NULL) && (sp->some_taken == 1)) {
740			stcb->asoc.ss_data.locked_on_sending = strq;
741		} else {
742			stcb->asoc.ss_data.locked_on_sending = NULL;
743		}
744	} else {
745		stcb->asoc.ss_data.locked_on_sending = NULL;
746	}
747	subtract = strq->ss_params.fb.rounds;
748	TAILQ_FOREACH(strqt, &asoc->ss_data.out.wheel, ss_params.fb.next_spoke) {
749		strqt->ss_params.fb.rounds -= subtract;
750		if (strqt->ss_params.fb.rounds < 0)
751			strqt->ss_params.fb.rounds = 0;
752	}
753	if (TAILQ_FIRST(&strq->outqueue)) {
754		strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
755	} else {
756		strq->ss_params.fb.rounds = -1;
757	}
758	asoc->ss_data.last_out_stream = strq;
759	return;
760}
761
762/*
763 * First-come, first-serve algorithm.
764 * Maintains the order provided by the application.
765 */
766static void
767sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
768    struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp,
769    int holds_lock);
770
771static void
772sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
773    int holds_lock)
774{
775	uint32_t x, n = 0, add_more = 1;
776	struct sctp_stream_queue_pending *sp;
777	uint16_t i;
778
779	if (holds_lock == 0) {
780		SCTP_TCB_SEND_LOCK(stcb);
781	}
782	TAILQ_INIT(&asoc->ss_data.out.list);
783	/*
784	 * If there is data in the stream queues already, the scheduler of
785	 * an existing association has been changed. We can only cycle
786	 * through the stream queues and add everything to the FCFS queue.
787	 */
788	while (add_more) {
789		add_more = 0;
790		for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
791			sp = TAILQ_FIRST(&stcb->asoc.strmout[i].outqueue);
792			x = 0;
793			/* Find n. message in current stream queue */
794			while (sp != NULL && x < n) {
795				sp = TAILQ_NEXT(sp, next);
796				x++;
797			}
798			if (sp != NULL) {
799				sctp_ss_fcfs_add(stcb, &stcb->asoc, &stcb->asoc.strmout[i], sp, 1);
800				add_more = 1;
801			}
802		}
803		n++;
804	}
805	if (holds_lock == 0) {
806		SCTP_TCB_SEND_UNLOCK(stcb);
807	}
808	return;
809}
810
811static void
812sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
813    int clear_values, int holds_lock)
814{
815	struct sctp_stream_queue_pending *sp;
816
817	if (clear_values) {
818		if (holds_lock == 0) {
819			SCTP_TCB_SEND_LOCK(stcb);
820		}
821		while (!TAILQ_EMPTY(&asoc->ss_data.out.list)) {
822			sp = TAILQ_FIRST(&asoc->ss_data.out.list);
823			TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
824			sp->ss_next.tqe_next = NULL;
825			sp->ss_next.tqe_prev = NULL;
826		}
827		if (holds_lock == 0) {
828			SCTP_TCB_SEND_UNLOCK(stcb);
829		}
830	}
831	return;
832}
833
834static void
835sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
836{
837	if (with_strq != NULL) {
838		if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
839			stcb->asoc.ss_data.locked_on_sending = strq;
840		}
841		if (stcb->asoc.ss_data.last_out_stream == with_strq) {
842			stcb->asoc.ss_data.last_out_stream = strq;
843		}
844	}
845	strq->ss_params.fb.next_spoke.tqe_next = NULL;
846	strq->ss_params.fb.next_spoke.tqe_prev = NULL;
847	return;
848}
849
850static void
851sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
852    struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
853    int holds_lock)
854{
855	if (holds_lock == 0) {
856		SCTP_TCB_SEND_LOCK(stcb);
857	}
858	if (sp && (sp->ss_next.tqe_next == NULL) &&
859	    (sp->ss_next.tqe_prev == NULL)) {
860		TAILQ_INSERT_TAIL(&asoc->ss_data.out.list, sp, ss_next);
861	}
862	if (holds_lock == 0) {
863		SCTP_TCB_SEND_UNLOCK(stcb);
864	}
865	return;
866}
867
868static int
869sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
870{
871	if (TAILQ_EMPTY(&asoc->ss_data.out.list)) {
872		return (1);
873	} else {
874		return (0);
875	}
876}
877
878static void
879sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
880    struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
881    int holds_lock)
882{
883	if (holds_lock == 0) {
884		SCTP_TCB_SEND_LOCK(stcb);
885	}
886	if (sp &&
887	    ((sp->ss_next.tqe_next != NULL) ||
888	    (sp->ss_next.tqe_prev != NULL))) {
889		TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
890		sp->ss_next.tqe_next = NULL;
891		sp->ss_next.tqe_prev = NULL;
892	}
893	if (holds_lock == 0) {
894		SCTP_TCB_SEND_UNLOCK(stcb);
895	}
896	return;
897}
898
899
900static struct sctp_stream_out *
901sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
902    struct sctp_association *asoc)
903{
904	struct sctp_stream_out *strq;
905	struct sctp_stream_queue_pending *sp;
906
907	if (asoc->ss_data.locked_on_sending) {
908		return (asoc->ss_data.locked_on_sending);
909	}
910	sp = TAILQ_FIRST(&asoc->ss_data.out.list);
911default_again:
912	if (sp != NULL) {
913		strq = &asoc->strmout[sp->sid];
914	} else {
915		strq = NULL;
916	}
917
918	/*
919	 * If CMT is off, we must validate that the stream in question has
920	 * the first item pointed towards are network destination requested
921	 * by the caller. Note that if we turn out to be locked to a stream
922	 * (assigning TSN's then we must stop, since we cannot look for
923	 * another stream with data to send to that destination). In CMT's
924	 * case, by skipping this check, we will send one data packet
925	 * towards the requested net.
926	 */
927	if (net != NULL && strq != NULL &&
928	    SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
929		if (TAILQ_FIRST(&strq->outqueue) &&
930		    TAILQ_FIRST(&strq->outqueue)->net != NULL &&
931		    TAILQ_FIRST(&strq->outqueue)->net != net) {
932			sp = TAILQ_NEXT(sp, ss_next);
933			goto default_again;
934		}
935	}
936	return (strq);
937}
938
939const struct sctp_ss_functions sctp_ss_functions[] = {
940/* SCTP_SS_DEFAULT */
941	{
942		.sctp_ss_init = sctp_ss_default_init,
943		.sctp_ss_clear = sctp_ss_default_clear,
944		.sctp_ss_init_stream = sctp_ss_default_init_stream,
945		.sctp_ss_add_to_stream = sctp_ss_default_add,
946		.sctp_ss_is_empty = sctp_ss_default_is_empty,
947		.sctp_ss_remove_from_stream = sctp_ss_default_remove,
948		.sctp_ss_select_stream = sctp_ss_default_select,
949		.sctp_ss_scheduled = sctp_ss_default_scheduled,
950		.sctp_ss_packet_done = sctp_ss_default_packet_done,
951		.sctp_ss_get_value = sctp_ss_default_get_value,
952		.sctp_ss_set_value = sctp_ss_default_set_value,
953		.sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
954	},
955/* SCTP_SS_ROUND_ROBIN */
956	{
957		.sctp_ss_init = sctp_ss_default_init,
958		.sctp_ss_clear = sctp_ss_default_clear,
959		.sctp_ss_init_stream = sctp_ss_default_init_stream,
960		.sctp_ss_add_to_stream = sctp_ss_rr_add,
961		.sctp_ss_is_empty = sctp_ss_default_is_empty,
962		.sctp_ss_remove_from_stream = sctp_ss_default_remove,
963		.sctp_ss_select_stream = sctp_ss_default_select,
964		.sctp_ss_scheduled = sctp_ss_default_scheduled,
965		.sctp_ss_packet_done = sctp_ss_default_packet_done,
966		.sctp_ss_get_value = sctp_ss_default_get_value,
967		.sctp_ss_set_value = sctp_ss_default_set_value,
968		.sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
969	},
970/* SCTP_SS_ROUND_ROBIN_PACKET */
971	{
972		.sctp_ss_init = sctp_ss_default_init,
973		.sctp_ss_clear = sctp_ss_default_clear,
974		.sctp_ss_init_stream = sctp_ss_default_init_stream,
975		.sctp_ss_add_to_stream = sctp_ss_rr_add,
976		.sctp_ss_is_empty = sctp_ss_default_is_empty,
977		.sctp_ss_remove_from_stream = sctp_ss_default_remove,
978		.sctp_ss_select_stream = sctp_ss_rrp_select,
979		.sctp_ss_scheduled = sctp_ss_default_scheduled,
980		.sctp_ss_packet_done = sctp_ss_rrp_packet_done,
981		.sctp_ss_get_value = sctp_ss_default_get_value,
982		.sctp_ss_set_value = sctp_ss_default_set_value,
983		.sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
984	},
985/* SCTP_SS_PRIORITY */
986	{
987		.sctp_ss_init = sctp_ss_default_init,
988		.sctp_ss_clear = sctp_ss_prio_clear,
989		.sctp_ss_init_stream = sctp_ss_prio_init_stream,
990		.sctp_ss_add_to_stream = sctp_ss_prio_add,
991		.sctp_ss_is_empty = sctp_ss_default_is_empty,
992		.sctp_ss_remove_from_stream = sctp_ss_prio_remove,
993		.sctp_ss_select_stream = sctp_ss_prio_select,
994		.sctp_ss_scheduled = sctp_ss_default_scheduled,
995		.sctp_ss_packet_done = sctp_ss_default_packet_done,
996		.sctp_ss_get_value = sctp_ss_prio_get_value,
997		.sctp_ss_set_value = sctp_ss_prio_set_value,
998		.sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
999	},
1000/* SCTP_SS_FAIR_BANDWITH */
1001	{
1002		.sctp_ss_init = sctp_ss_default_init,
1003		.sctp_ss_clear = sctp_ss_fb_clear,
1004		.sctp_ss_init_stream = sctp_ss_fb_init_stream,
1005		.sctp_ss_add_to_stream = sctp_ss_fb_add,
1006		.sctp_ss_is_empty = sctp_ss_default_is_empty,
1007		.sctp_ss_remove_from_stream = sctp_ss_fb_remove,
1008		.sctp_ss_select_stream = sctp_ss_fb_select,
1009		.sctp_ss_scheduled = sctp_ss_fb_scheduled,
1010		.sctp_ss_packet_done = sctp_ss_default_packet_done,
1011		.sctp_ss_get_value = sctp_ss_default_get_value,
1012		.sctp_ss_set_value = sctp_ss_default_set_value,
1013		.sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
1014	},
1015/* SCTP_SS_FIRST_COME */
1016	{
1017		.sctp_ss_init = sctp_ss_fcfs_init,
1018		.sctp_ss_clear = sctp_ss_fcfs_clear,
1019		.sctp_ss_init_stream = sctp_ss_fcfs_init_stream,
1020		.sctp_ss_add_to_stream = sctp_ss_fcfs_add,
1021		.sctp_ss_is_empty = sctp_ss_fcfs_is_empty,
1022		.sctp_ss_remove_from_stream = sctp_ss_fcfs_remove,
1023		.sctp_ss_select_stream = sctp_ss_fcfs_select,
1024		.sctp_ss_scheduled = sctp_ss_default_scheduled,
1025		.sctp_ss_packet_done = sctp_ss_default_packet_done,
1026		.sctp_ss_get_value = sctp_ss_default_get_value,
1027		.sctp_ss_set_value = sctp_ss_default_set_value,
1028		.sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
1029	}
1030};
1031