xref: /freebsd/sys/netinet/sctp_ss_functions.c (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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 <netinet/sctp_os.h>
32 #include <netinet/sctp_pcb.h>
33 
34 /*
35  * Default simple round-robin algorithm.
36  * Just iterates the streams in the order they appear.
37  */
38 
39 static void
40 sctp_ss_default_add(struct sctp_tcb *, struct sctp_association *,
41     struct sctp_stream_out *,
42     struct sctp_stream_queue_pending *);
43 
44 static void
45 sctp_ss_default_remove(struct sctp_tcb *, struct sctp_association *,
46     struct sctp_stream_out *,
47     struct sctp_stream_queue_pending *);
48 
49 static void
50 sctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc)
51 {
52 	uint16_t i;
53 
54 	SCTP_TCB_LOCK_ASSERT(stcb);
55 
56 	asoc->ss_data.locked_on_sending = NULL;
57 	asoc->ss_data.last_out_stream = NULL;
58 	TAILQ_INIT(&asoc->ss_data.out.wheel);
59 	/*
60 	 * If there is data in the stream queues already, the scheduler of
61 	 * an existing association has been changed. We need to add all
62 	 * stream queues to the wheel.
63 	 */
64 	for (i = 0; i < asoc->streamoutcnt; i++) {
65 		stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, asoc,
66 		    &asoc->strmout[i],
67 		    NULL);
68 	}
69 	return;
70 }
71 
72 static void
73 sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
74     bool clear_values SCTP_UNUSED)
75 {
76 	SCTP_TCB_LOCK_ASSERT(stcb);
77 
78 	while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
79 		struct sctp_stream_out *strq;
80 
81 		strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
82 		KASSERT(strq->ss_params.scheduled, ("strq %p not scheduled", (void *)strq));
83 		TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.rr.next_spoke);
84 		strq->ss_params.scheduled = false;
85 	}
86 	asoc->ss_data.last_out_stream = NULL;
87 	return;
88 }
89 
90 static void
91 sctp_ss_default_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
92 {
93 	SCTP_TCB_LOCK_ASSERT(stcb);
94 
95 	if (with_strq != NULL) {
96 		if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
97 			stcb->asoc.ss_data.locked_on_sending = strq;
98 		}
99 		if (stcb->asoc.ss_data.last_out_stream == with_strq) {
100 			stcb->asoc.ss_data.last_out_stream = strq;
101 		}
102 	}
103 	strq->ss_params.scheduled = false;
104 	return;
105 }
106 
107 static void
108 sctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
109     struct sctp_stream_out *strq,
110     struct sctp_stream_queue_pending *sp SCTP_UNUSED)
111 {
112 	SCTP_TCB_LOCK_ASSERT(stcb);
113 
114 	/* Add to wheel if not already on it and stream queue not empty */
115 	if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) {
116 		TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel,
117 		    strq, ss_params.ss.rr.next_spoke);
118 		strq->ss_params.scheduled = true;
119 	}
120 	return;
121 }
122 
123 static bool
124 sctp_ss_default_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
125 {
126 	SCTP_TCB_LOCK_ASSERT(stcb);
127 
128 	return (TAILQ_EMPTY(&asoc->ss_data.out.wheel));
129 }
130 
131 static void
132 sctp_ss_default_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
133     struct sctp_stream_out *strq,
134     struct sctp_stream_queue_pending *sp SCTP_UNUSED)
135 {
136 	SCTP_TCB_LOCK_ASSERT(stcb);
137 
138 	/*
139 	 * Remove from wheel if stream queue is empty and actually is on the
140 	 * wheel
141 	 */
142 	if (TAILQ_EMPTY(&strq->outqueue) && strq->ss_params.scheduled) {
143 		if (asoc->ss_data.last_out_stream == strq) {
144 			asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream,
145 			    sctpwheel_listhead,
146 			    ss_params.ss.rr.next_spoke);
147 			if (asoc->ss_data.last_out_stream == NULL) {
148 				asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
149 				    sctpwheel_listhead);
150 			}
151 			if (asoc->ss_data.last_out_stream == strq) {
152 				asoc->ss_data.last_out_stream = NULL;
153 			}
154 		}
155 		if (asoc->ss_data.locked_on_sending == strq) {
156 			asoc->ss_data.locked_on_sending = NULL;
157 		}
158 		TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.rr.next_spoke);
159 		strq->ss_params.scheduled = false;
160 	}
161 	return;
162 }
163 
164 static struct sctp_stream_out *
165 sctp_ss_default_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
166     struct sctp_association *asoc)
167 {
168 	struct sctp_stream_out *strq, *strqt;
169 
170 	SCTP_TCB_LOCK_ASSERT(stcb);
171 
172 	if (asoc->ss_data.locked_on_sending != NULL) {
173 		KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled,
174 		    ("locked_on_sending %p not scheduled",
175 		    (void *)asoc->ss_data.locked_on_sending));
176 		return (asoc->ss_data.locked_on_sending);
177 	}
178 	strqt = asoc->ss_data.last_out_stream;
179 	KASSERT(strqt == NULL || strqt->ss_params.scheduled,
180 	    ("last_out_stream %p not scheduled", (void *)strqt));
181 default_again:
182 	/* Find the next stream to use */
183 	if (strqt == NULL) {
184 		strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
185 	} else {
186 		strq = TAILQ_NEXT(strqt, ss_params.ss.rr.next_spoke);
187 		if (strq == NULL) {
188 			strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
189 		}
190 	}
191 	KASSERT(strq == NULL || strq->ss_params.scheduled,
192 	    ("strq %p not scheduled", (void *)strq));
193 
194 	/*
195 	 * If CMT is off, we must validate that the stream in question has
196 	 * the first item pointed towards are network destination requested
197 	 * by the caller. Note that if we turn out to be locked to a stream
198 	 * (assigning TSN's then we must stop, since we cannot look for
199 	 * another stream with data to send to that destination). In CMT's
200 	 * case, by skipping this check, we will send one data packet
201 	 * towards the requested net.
202 	 */
203 	if (net != NULL && strq != NULL &&
204 	    SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
205 		if (TAILQ_FIRST(&strq->outqueue) &&
206 		    TAILQ_FIRST(&strq->outqueue)->net != NULL &&
207 		    TAILQ_FIRST(&strq->outqueue)->net != net) {
208 			if (strq == asoc->ss_data.last_out_stream) {
209 				return (NULL);
210 			} else {
211 				strqt = strq;
212 				goto default_again;
213 			}
214 		}
215 	}
216 	return (strq);
217 }
218 
219 static void
220 sctp_ss_default_scheduled(struct sctp_tcb *stcb,
221     struct sctp_nets *net SCTP_UNUSED,
222     struct sctp_association *asoc,
223     struct sctp_stream_out *strq,
224     int moved_how_much SCTP_UNUSED)
225 {
226 	struct sctp_stream_queue_pending *sp;
227 
228 	KASSERT(strq != NULL, ("strq is NULL"));
229 	KASSERT(strq->ss_params.scheduled, ("strq %p is not scheduled", (void *)strq));
230 	SCTP_TCB_LOCK_ASSERT(stcb);
231 
232 	asoc->ss_data.last_out_stream = strq;
233 	if (asoc->idata_supported == 0) {
234 		sp = TAILQ_FIRST(&strq->outqueue);
235 		if ((sp != NULL) && (sp->some_taken == 1)) {
236 			asoc->ss_data.locked_on_sending = strq;
237 		} else {
238 			asoc->ss_data.locked_on_sending = NULL;
239 		}
240 	} else {
241 		asoc->ss_data.locked_on_sending = NULL;
242 	}
243 	return;
244 }
245 
246 static void
247 sctp_ss_default_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
248     struct sctp_association *asoc SCTP_UNUSED)
249 {
250 	SCTP_TCB_LOCK_ASSERT(stcb);
251 
252 	/* Nothing to be done here */
253 	return;
254 }
255 
256 static int
257 sctp_ss_default_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
258     struct sctp_stream_out *strq SCTP_UNUSED, uint16_t *value SCTP_UNUSED)
259 {
260 	SCTP_TCB_LOCK_ASSERT(stcb);
261 
262 	/* Nothing to be done here */
263 	return (-1);
264 }
265 
266 static int
267 sctp_ss_default_set_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
268     struct sctp_stream_out *strq SCTP_UNUSED, uint16_t value SCTP_UNUSED)
269 {
270 	SCTP_TCB_LOCK_ASSERT(stcb);
271 
272 	/* Nothing to be done here */
273 	return (-1);
274 }
275 
276 static bool
277 sctp_ss_default_is_user_msgs_incomplete(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
278 {
279 	struct sctp_stream_out *strq;
280 	struct sctp_stream_queue_pending *sp;
281 
282 	SCTP_TCB_LOCK_ASSERT(stcb);
283 
284 	if (asoc->stream_queue_cnt != 1) {
285 		return (false);
286 	}
287 	strq = asoc->ss_data.locked_on_sending;
288 	if (strq == NULL) {
289 		return (false);
290 	}
291 	sp = TAILQ_FIRST(&strq->outqueue);
292 	if (sp == NULL) {
293 		return (false);
294 	}
295 	return (sp->msg_is_complete == 0);
296 }
297 
298 /*
299  * Real round-robin algorithm.
300  * Always iterates the streams in ascending order.
301  */
302 static void
303 sctp_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)
306 {
307 	struct sctp_stream_out *strqt;
308 
309 	SCTP_TCB_LOCK_ASSERT(stcb);
310 
311 	if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) {
312 		if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
313 			TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.ss.rr.next_spoke);
314 		} else {
315 			strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
316 			while (strqt != NULL && (strqt->sid < strq->sid)) {
317 				strqt = TAILQ_NEXT(strqt, ss_params.ss.rr.next_spoke);
318 			}
319 			if (strqt != NULL) {
320 				TAILQ_INSERT_BEFORE(strqt, strq, ss_params.ss.rr.next_spoke);
321 			} else {
322 				TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.ss.rr.next_spoke);
323 			}
324 		}
325 		strq->ss_params.scheduled = true;
326 	}
327 	return;
328 }
329 
330 /*
331  * Real round-robin per packet algorithm.
332  * Always iterates the streams in ascending order and
333  * only fills messages of the same stream in a packet.
334  */
335 static struct sctp_stream_out *
336 sctp_ss_rrp_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net SCTP_UNUSED,
337     struct sctp_association *asoc)
338 {
339 	SCTP_TCB_LOCK_ASSERT(stcb);
340 
341 	return (asoc->ss_data.last_out_stream);
342 }
343 
344 static void
345 sctp_ss_rrp_packet_done(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
346     struct sctp_association *asoc)
347 {
348 	struct sctp_stream_out *strq, *strqt;
349 
350 	SCTP_TCB_LOCK_ASSERT(stcb);
351 
352 	strqt = asoc->ss_data.last_out_stream;
353 	KASSERT(strqt == NULL || strqt->ss_params.scheduled,
354 	    ("last_out_stream %p not scheduled", (void *)strqt));
355 rrp_again:
356 	/* Find the next stream to use */
357 	if (strqt == NULL) {
358 		strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
359 	} else {
360 		strq = TAILQ_NEXT(strqt, ss_params.ss.rr.next_spoke);
361 		if (strq == NULL) {
362 			strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
363 		}
364 	}
365 	KASSERT(strq == NULL || strq->ss_params.scheduled,
366 	    ("strq %p not scheduled", (void *)strq));
367 
368 	/*
369 	 * If CMT is off, we must validate that the stream in question has
370 	 * the first item pointed towards are network destination requested
371 	 * by the caller. Note that if we turn out to be locked to a stream
372 	 * (assigning TSN's then we must stop, since we cannot look for
373 	 * another stream with data to send to that destination). In CMT's
374 	 * case, by skipping this check, we will send one data packet
375 	 * towards the requested net.
376 	 */
377 	if (net != NULL && strq != NULL &&
378 	    SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
379 		if (TAILQ_FIRST(&strq->outqueue) &&
380 		    TAILQ_FIRST(&strq->outqueue)->net != NULL &&
381 		    TAILQ_FIRST(&strq->outqueue)->net != net) {
382 			if (strq == asoc->ss_data.last_out_stream) {
383 				strq = NULL;
384 			} else {
385 				strqt = strq;
386 				goto rrp_again;
387 			}
388 		}
389 	}
390 	asoc->ss_data.last_out_stream = strq;
391 	return;
392 }
393 
394 /*
395  * Priority algorithm.
396  * Always prefers streams based on their priority id.
397  */
398 static void
399 sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
400     bool clear_values)
401 {
402 	SCTP_TCB_LOCK_ASSERT(stcb);
403 
404 	while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
405 		struct sctp_stream_out *strq;
406 
407 		strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
408 		KASSERT(strq->ss_params.scheduled, ("strq %p not scheduled", (void *)strq));
409 		if (clear_values) {
410 			strq->ss_params.ss.prio.priority = 0;
411 		}
412 		TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.prio.next_spoke);
413 		strq->ss_params.scheduled = false;
414 	}
415 	asoc->ss_data.last_out_stream = NULL;
416 	return;
417 }
418 
419 static void
420 sctp_ss_prio_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
421 {
422 	SCTP_TCB_LOCK_ASSERT(stcb);
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.scheduled = false;
433 	if (with_strq != NULL) {
434 		strq->ss_params.ss.prio.priority = with_strq->ss_params.ss.prio.priority;
435 	} else {
436 		strq->ss_params.ss.prio.priority = 0;
437 	}
438 	return;
439 }
440 
441 static void
442 sctp_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 {
445 	struct sctp_stream_out *strqt;
446 
447 	SCTP_TCB_LOCK_ASSERT(stcb);
448 
449 	/* Add to wheel if not already on it and stream queue not empty */
450 	if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) {
451 		if (TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
452 			TAILQ_INSERT_HEAD(&asoc->ss_data.out.wheel, strq, ss_params.ss.prio.next_spoke);
453 		} else {
454 			strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
455 			while (strqt != NULL && strqt->ss_params.ss.prio.priority < strq->ss_params.ss.prio.priority) {
456 				strqt = TAILQ_NEXT(strqt, ss_params.ss.prio.next_spoke);
457 			}
458 			if (strqt != NULL) {
459 				TAILQ_INSERT_BEFORE(strqt, strq, ss_params.ss.prio.next_spoke);
460 			} else {
461 				TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.ss.prio.next_spoke);
462 			}
463 		}
464 		strq->ss_params.scheduled = true;
465 	}
466 	return;
467 }
468 
469 static void
470 sctp_ss_prio_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
471     struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED)
472 {
473 	SCTP_TCB_LOCK_ASSERT(stcb);
474 
475 	/*
476 	 * Remove from wheel if stream queue is empty and actually is on the
477 	 * wheel
478 	 */
479 	if (TAILQ_EMPTY(&strq->outqueue) && strq->ss_params.scheduled) {
480 		if (asoc->ss_data.last_out_stream == strq) {
481 			asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream,
482 			    sctpwheel_listhead,
483 			    ss_params.ss.prio.next_spoke);
484 			if (asoc->ss_data.last_out_stream == NULL) {
485 				asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
486 				    sctpwheel_listhead);
487 			}
488 			if (asoc->ss_data.last_out_stream == strq) {
489 				asoc->ss_data.last_out_stream = NULL;
490 			}
491 		}
492 		if (asoc->ss_data.locked_on_sending == strq) {
493 			asoc->ss_data.locked_on_sending = NULL;
494 		}
495 		TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.prio.next_spoke);
496 		strq->ss_params.scheduled = false;
497 	}
498 	return;
499 }
500 
501 static struct sctp_stream_out *
502 sctp_ss_prio_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
503     struct sctp_association *asoc)
504 {
505 	struct sctp_stream_out *strq, *strqt, *strqn;
506 
507 	SCTP_TCB_LOCK_ASSERT(stcb);
508 
509 	if (asoc->ss_data.locked_on_sending != NULL) {
510 		KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled,
511 		    ("locked_on_sending %p not scheduled",
512 		    (void *)asoc->ss_data.locked_on_sending));
513 		return (asoc->ss_data.locked_on_sending);
514 	}
515 	strqt = asoc->ss_data.last_out_stream;
516 	KASSERT(strqt == NULL || strqt->ss_params.scheduled,
517 	    ("last_out_stream %p not scheduled", (void *)strqt));
518 prio_again:
519 	/* Find the next stream to use */
520 	if (strqt == NULL) {
521 		strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
522 	} else {
523 		strqn = TAILQ_NEXT(strqt, ss_params.ss.prio.next_spoke);
524 		if (strqn != NULL &&
525 		    strqn->ss_params.ss.prio.priority == strqt->ss_params.ss.prio.priority) {
526 			strq = strqn;
527 		} else {
528 			strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
529 		}
530 	}
531 	KASSERT(strq == NULL || strq->ss_params.scheduled,
532 	    ("strq %p not scheduled", (void *)strq));
533 
534 	/*
535 	 * If CMT is off, we must validate that the stream in question has
536 	 * the first item pointed towards are network destination requested
537 	 * by the caller. Note that if we turn out to be locked to a stream
538 	 * (assigning TSN's then we must stop, since we cannot look for
539 	 * another stream with data to send to that destination). In CMT's
540 	 * case, by skipping this check, we will send one data packet
541 	 * towards the requested net.
542 	 */
543 	if (net != NULL && strq != NULL &&
544 	    SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
545 		if (TAILQ_FIRST(&strq->outqueue) &&
546 		    TAILQ_FIRST(&strq->outqueue)->net != NULL &&
547 		    TAILQ_FIRST(&strq->outqueue)->net != net) {
548 			if (strq == asoc->ss_data.last_out_stream) {
549 				return (NULL);
550 			} else {
551 				strqt = strq;
552 				goto prio_again;
553 			}
554 		}
555 	}
556 	return (strq);
557 }
558 
559 static int
560 sctp_ss_prio_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
561     struct sctp_stream_out *strq, uint16_t *value)
562 {
563 	SCTP_TCB_LOCK_ASSERT(stcb);
564 
565 	if (strq == NULL) {
566 		return (-1);
567 	}
568 	*value = strq->ss_params.ss.prio.priority;
569 	return (1);
570 }
571 
572 static int
573 sctp_ss_prio_set_value(struct sctp_tcb *stcb, struct sctp_association *asoc,
574     struct sctp_stream_out *strq, uint16_t value)
575 {
576 	SCTP_TCB_LOCK_ASSERT(stcb);
577 
578 	if (strq == NULL) {
579 		return (-1);
580 	}
581 	strq->ss_params.ss.prio.priority = value;
582 	sctp_ss_prio_remove(stcb, asoc, strq, NULL);
583 	sctp_ss_prio_add(stcb, asoc, strq, NULL);
584 	return (1);
585 }
586 
587 /*
588  * Fair bandwidth algorithm.
589  * Maintains an equal throughput per stream.
590  */
591 static void
592 sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
593     bool clear_values)
594 {
595 	SCTP_TCB_LOCK_ASSERT(stcb);
596 
597 	while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
598 		struct sctp_stream_out *strq;
599 
600 		strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
601 		KASSERT(strq->ss_params.scheduled, ("strq %p not scheduled", (void *)strq));
602 		if (clear_values) {
603 			strq->ss_params.ss.fb.rounds = -1;
604 		}
605 		TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.fb.next_spoke);
606 		strq->ss_params.scheduled = false;
607 	}
608 	asoc->ss_data.last_out_stream = NULL;
609 	return;
610 }
611 
612 static void
613 sctp_ss_fb_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
614 {
615 	SCTP_TCB_LOCK_ASSERT(stcb);
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.scheduled = false;
626 	if (with_strq != NULL) {
627 		strq->ss_params.ss.fb.rounds = with_strq->ss_params.ss.fb.rounds;
628 	} else {
629 		strq->ss_params.ss.fb.rounds = -1;
630 	}
631 	return;
632 }
633 
634 static void
635 sctp_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 {
638 	SCTP_TCB_LOCK_ASSERT(stcb);
639 
640 	if (!TAILQ_EMPTY(&strq->outqueue) && !strq->ss_params.scheduled) {
641 		if (strq->ss_params.ss.fb.rounds < 0)
642 			strq->ss_params.ss.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
643 		TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.ss.fb.next_spoke);
644 		strq->ss_params.scheduled = true;
645 	}
646 	return;
647 }
648 
649 static void
650 sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
651     struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED)
652 {
653 	SCTP_TCB_LOCK_ASSERT(stcb);
654 
655 	/*
656 	 * Remove from wheel if stream queue is empty and actually is on the
657 	 * wheel
658 	 */
659 	if (TAILQ_EMPTY(&strq->outqueue) && strq->ss_params.scheduled) {
660 		if (asoc->ss_data.last_out_stream == strq) {
661 			asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream,
662 			    sctpwheel_listhead,
663 			    ss_params.ss.fb.next_spoke);
664 			if (asoc->ss_data.last_out_stream == NULL) {
665 				asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
666 				    sctpwheel_listhead);
667 			}
668 			if (asoc->ss_data.last_out_stream == strq) {
669 				asoc->ss_data.last_out_stream = NULL;
670 			}
671 		}
672 		if (asoc->ss_data.locked_on_sending == strq) {
673 			asoc->ss_data.locked_on_sending = NULL;
674 		}
675 		TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.ss.fb.next_spoke);
676 		strq->ss_params.scheduled = false;
677 	}
678 	return;
679 }
680 
681 static struct sctp_stream_out *
682 sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
683     struct sctp_association *asoc)
684 {
685 	struct sctp_stream_out *strq = NULL, *strqt;
686 
687 	SCTP_TCB_LOCK_ASSERT(stcb);
688 
689 	if (asoc->ss_data.locked_on_sending != NULL) {
690 		KASSERT(asoc->ss_data.locked_on_sending->ss_params.scheduled,
691 		    ("locked_on_sending %p not scheduled",
692 		    (void *)asoc->ss_data.locked_on_sending));
693 		return (asoc->ss_data.locked_on_sending);
694 	}
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);
698 	} else {
699 		strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.ss.fb.next_spoke);
700 	}
701 	do {
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.ss.fb.rounds >= 0) &&
709 			    ((strq == NULL) ||
710 			    (strqt->ss_params.ss.fb.rounds < strq->ss_params.ss.fb.rounds))) {
711 				strq = strqt;
712 			}
713 		}
714 		if (strqt != NULL) {
715 			strqt = TAILQ_NEXT(strqt, ss_params.ss.fb.next_spoke);
716 		} else {
717 			strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
718 		}
719 	} while (strqt != strq);
720 	return (strq);
721 }
722 
723 static void
724 sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED,
725     struct sctp_association *asoc, struct sctp_stream_out *strq,
726     int moved_how_much SCTP_UNUSED)
727 {
728 	struct sctp_stream_queue_pending *sp;
729 	struct sctp_stream_out *strqt;
730 	int subtract;
731 
732 	SCTP_TCB_LOCK_ASSERT(stcb);
733 
734 	if (asoc->idata_supported == 0) {
735 		sp = TAILQ_FIRST(&strq->outqueue);
736 		if ((sp != NULL) && (sp->some_taken == 1)) {
737 			asoc->ss_data.locked_on_sending = strq;
738 		} else {
739 			asoc->ss_data.locked_on_sending = NULL;
740 		}
741 	} else {
742 		asoc->ss_data.locked_on_sending = NULL;
743 	}
744 	subtract = strq->ss_params.ss.fb.rounds;
745 	TAILQ_FOREACH(strqt, &asoc->ss_data.out.wheel, ss_params.ss.fb.next_spoke) {
746 		strqt->ss_params.ss.fb.rounds -= subtract;
747 		if (strqt->ss_params.ss.fb.rounds < 0)
748 			strqt->ss_params.ss.fb.rounds = 0;
749 	}
750 	if (TAILQ_FIRST(&strq->outqueue)) {
751 		strq->ss_params.ss.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
752 	} else {
753 		strq->ss_params.ss.fb.rounds = -1;
754 	}
755 	asoc->ss_data.last_out_stream = strq;
756 	return;
757 }
758 
759 /*
760  * First-come, first-serve algorithm.
761  * Maintains the order provided by the application.
762  */
763 static void
764 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
765     struct sctp_stream_out *strq SCTP_UNUSED,
766     struct sctp_stream_queue_pending *sp);
767 
768 static void
769 sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc)
770 {
771 	uint32_t x, n = 0, add_more = 1;
772 	struct sctp_stream_queue_pending *sp;
773 	uint16_t i;
774 
775 	SCTP_TCB_LOCK_ASSERT(stcb);
776 
777 	TAILQ_INIT(&asoc->ss_data.out.list);
778 	/*
779 	 * If there is data in the stream queues already, the scheduler of
780 	 * an existing association has been changed. We can only cycle
781 	 * through the stream queues and add everything to the FCFS queue.
782 	 */
783 	while (add_more) {
784 		add_more = 0;
785 		for (i = 0; i < asoc->streamoutcnt; i++) {
786 			sp = TAILQ_FIRST(&asoc->strmout[i].outqueue);
787 			x = 0;
788 			/* Find n. message in current stream queue */
789 			while (sp != NULL && x < n) {
790 				sp = TAILQ_NEXT(sp, next);
791 				x++;
792 			}
793 			if (sp != NULL) {
794 				sctp_ss_fcfs_add(stcb, asoc, &asoc->strmout[i], sp);
795 				add_more = 1;
796 			}
797 		}
798 		n++;
799 	}
800 	return;
801 }
802 
803 static void
804 sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
805     bool clear_values SCTP_UNUSED)
806 {
807 	struct sctp_stream_queue_pending *sp;
808 
809 	SCTP_TCB_LOCK_ASSERT(stcb);
810 
811 	while (!TAILQ_EMPTY(&asoc->ss_data.out.list)) {
812 		sp = TAILQ_FIRST(&asoc->ss_data.out.list);
813 		KASSERT(sp->scheduled, ("sp %p not scheduled", (void *)sp));
814 		TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
815 		sp->scheduled = false;
816 	}
817 	asoc->ss_data.last_out_stream = NULL;
818 	return;
819 }
820 
821 static void
822 sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
823 {
824 	SCTP_TCB_LOCK_ASSERT(stcb);
825 
826 	if (with_strq != NULL) {
827 		if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
828 			stcb->asoc.ss_data.locked_on_sending = strq;
829 		}
830 		if (stcb->asoc.ss_data.last_out_stream == with_strq) {
831 			stcb->asoc.ss_data.last_out_stream = strq;
832 		}
833 	}
834 	strq->ss_params.scheduled = false;
835 	return;
836 }
837 
838 static void
839 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
840     struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp)
841 {
842 	SCTP_TCB_LOCK_ASSERT(stcb);
843 
844 	if (!sp->scheduled) {
845 		TAILQ_INSERT_TAIL(&asoc->ss_data.out.list, sp, ss_next);
846 		sp->scheduled = true;
847 	}
848 	return;
849 }
850 
851 static bool
852 sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
853 {
854 	SCTP_TCB_LOCK_ASSERT(stcb);
855 
856 	return (TAILQ_EMPTY(&asoc->ss_data.out.list));
857 }
858 
859 static void
860 sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
861     struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp)
862 {
863 	SCTP_TCB_LOCK_ASSERT(stcb);
864 
865 	if (sp->scheduled) {
866 		TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
867 		sp->scheduled = false;
868 	}
869 	return;
870 }
871 
872 static struct sctp_stream_out *
873 sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
874     struct sctp_association *asoc)
875 {
876 	struct sctp_stream_out *strq;
877 	struct sctp_stream_queue_pending *sp;
878 
879 	SCTP_TCB_LOCK_ASSERT(stcb);
880 
881 	if (asoc->ss_data.locked_on_sending) {
882 		return (asoc->ss_data.locked_on_sending);
883 	}
884 	sp = TAILQ_FIRST(&asoc->ss_data.out.list);
885 default_again:
886 	if (sp != NULL) {
887 		strq = &asoc->strmout[sp->sid];
888 	} else {
889 		strq = NULL;
890 	}
891 
892 	/*
893 	 * If CMT is off, we must validate that the stream in question has
894 	 * the first item pointed towards are network destination requested
895 	 * by the caller. Note that if we turn out to be locked to a stream
896 	 * (assigning TSN's then we must stop, since we cannot look for
897 	 * another stream with data to send to that destination). In CMT's
898 	 * case, by skipping this check, we will send one data packet
899 	 * towards the requested net.
900 	 */
901 	if (net != NULL && strq != NULL &&
902 	    SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
903 		if (TAILQ_FIRST(&strq->outqueue) &&
904 		    TAILQ_FIRST(&strq->outqueue)->net != NULL &&
905 		    TAILQ_FIRST(&strq->outqueue)->net != net) {
906 			sp = TAILQ_NEXT(sp, ss_next);
907 			goto default_again;
908 		}
909 	}
910 	return (strq);
911 }
912 
913 static void
914 sctp_ss_fcfs_scheduled(struct sctp_tcb *stcb,
915     struct sctp_nets *net SCTP_UNUSED,
916     struct sctp_association *asoc,
917     struct sctp_stream_out *strq,
918     int moved_how_much SCTP_UNUSED)
919 {
920 	struct sctp_stream_queue_pending *sp;
921 
922 	KASSERT(strq != NULL, ("strq is NULL"));
923 	asoc->ss_data.last_out_stream = strq;
924 	if (asoc->idata_supported == 0) {
925 		sp = TAILQ_FIRST(&strq->outqueue);
926 		if ((sp != NULL) && (sp->some_taken == 1)) {
927 			asoc->ss_data.locked_on_sending = strq;
928 		} else {
929 			asoc->ss_data.locked_on_sending = NULL;
930 		}
931 	} else {
932 		asoc->ss_data.locked_on_sending = NULL;
933 	}
934 	return;
935 }
936 
937 const 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_RR */
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_RR_PKT */
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_PRIO */
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_FB */
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_FCFS */
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_fcfs_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