LCOV - code coverage report
Current view: top level - netwerk/sctp/src/netinet - sctp_ss_functions.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 349 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 34 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13