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