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