tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

sctp_ss_functions.c (34971B)


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