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