sctp_ss_functions.c revision 217760
1217760Stuexen/*- 2217760Stuexen * Copyright (c) 2010, by Randall Stewart & Michael Tuexen, 3217760Stuexen * All rights reserved. 4217760Stuexen * 5217760Stuexen * Redistribution and use in source and binary forms, with or without 6217760Stuexen * modification, are permitted provided that the following conditions are met: 7217760Stuexen * 8217760Stuexen * a) Redistributions of source code must retain the above copyright notice, 9217760Stuexen * this list of conditions and the following disclaimer. 10217760Stuexen * 11217760Stuexen * b) Redistributions in binary form must reproduce the above copyright 12217760Stuexen * notice, this list of conditions and the following disclaimer in 13217760Stuexen * the documentation and/or other materials provided with the distribution. 14217760Stuexen * 15217760Stuexen * c) Neither the name of Cisco Systems, Inc. nor the names of its 16217760Stuexen * contributors may be used to endorse or promote products derived 17217760Stuexen * from this software without specific prior written permission. 18217760Stuexen * 19217760Stuexen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20217760Stuexen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21217760Stuexen * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22217760Stuexen * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23217760Stuexen * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24217760Stuexen * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25217760Stuexen * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26217760Stuexen * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27217760Stuexen * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28217760Stuexen * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 29217760Stuexen * THE POSSIBILITY OF SUCH DAMAGE. 30217760Stuexen */ 31217760Stuexen 32217760Stuexen#include <sys/cdefs.h> 33217760Stuexen__FBSDID("$FreeBSD: head/sys/netinet/sctp_ss_functions.c 217760 2011-01-23 19:36:28Z tuexen $"); 34217760Stuexen 35217760Stuexen#include <netinet/sctp_pcb.h> 36217760Stuexen 37217760Stuexen/* 38217760Stuexen * Default simple round-robin algorithm. 39217760Stuexen * Just interates the streams in the order they appear. 40217760Stuexen */ 41217760Stuexen 42217760Stuexenstatic void 43217760Stuexensctp_ss_default_add(struct sctp_tcb *, struct sctp_association *, 44217760Stuexen struct sctp_stream_out *, 45217760Stuexen struct sctp_stream_queue_pending *, int); 46217760Stuexen 47217760Stuexenstatic void 48217760Stuexensctp_ss_default_remove(struct sctp_tcb *, struct sctp_association *, 49217760Stuexen struct sctp_stream_out *, 50217760Stuexen struct sctp_stream_queue_pending *, int); 51217760Stuexen 52217760Stuexenstatic void 53217760Stuexensctp_ss_default_init(struct sctp_tcb *stcb, struct sctp_association *asoc, 54217760Stuexen int holds_lock) 55217760Stuexen{ 56217760Stuexen uint16_t i; 57217760Stuexen 58217760Stuexen TAILQ_INIT(&asoc->ss_data.out_wheel); 59217760Stuexen for (i = 0; i < stcb->asoc.streamoutcnt; i++) { 60217760Stuexen if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { 61217760Stuexen sctp_ss_default_add(stcb, &stcb->asoc, 62217760Stuexen &stcb->asoc.strmout[i], 63217760Stuexen NULL, holds_lock); 64217760Stuexen } 65217760Stuexen } 66217760Stuexen return; 67217760Stuexen} 68217760Stuexen 69217760Stuexenstatic void 70217760Stuexensctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, 71217760Stuexen int clear_values, int holds_lock) 72217760Stuexen{ 73217760Stuexen uint16_t i; 74217760Stuexen 75217760Stuexen for (i = 0; i < stcb->asoc.streamoutcnt; i++) { 76217760Stuexen if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { 77217760Stuexen sctp_ss_default_remove(stcb, &stcb->asoc, 78217760Stuexen &stcb->asoc.strmout[i], 79217760Stuexen NULL, holds_lock); 80217760Stuexen } 81217760Stuexen } 82217760Stuexen return; 83217760Stuexen} 84217760Stuexen 85217760Stuexenstatic void 86217760Stuexensctp_ss_default_init_stream(struct sctp_stream_out *strq) 87217760Stuexen{ 88217760Stuexen strq->ss_params.rr.next_spoke.tqe_next = NULL; 89217760Stuexen strq->ss_params.rr.next_spoke.tqe_prev = NULL; 90217760Stuexen return; 91217760Stuexen} 92217760Stuexen 93217760Stuexenstatic void 94217760Stuexensctp_ss_default_add(struct sctp_tcb *stcb, struct sctp_association *asoc, 95217760Stuexen struct sctp_stream_out *strq, 96217760Stuexen struct sctp_stream_queue_pending *sp, int holds_lock) 97217760Stuexen{ 98217760Stuexen if (holds_lock == 0) { 99217760Stuexen SCTP_TCB_SEND_LOCK(stcb); 100217760Stuexen } 101217760Stuexen if ((strq->ss_params.rr.next_spoke.tqe_next == NULL) && 102217760Stuexen (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) { 103217760Stuexen TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, 104217760Stuexen strq, ss_params.rr.next_spoke); 105217760Stuexen } 106217760Stuexen if (holds_lock == 0) { 107217760Stuexen SCTP_TCB_SEND_UNLOCK(stcb); 108217760Stuexen } 109217760Stuexen return; 110217760Stuexen} 111217760Stuexen 112217760Stuexenstatic int 113217760Stuexensctp_ss_default_is_empty(struct sctp_tcb *stcb, struct sctp_association *asoc) 114217760Stuexen{ 115217760Stuexen if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) { 116217760Stuexen return (1); 117217760Stuexen } else { 118217760Stuexen return (0); 119217760Stuexen } 120217760Stuexen} 121217760Stuexen 122217760Stuexenstatic void 123217760Stuexensctp_ss_default_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, 124217760Stuexen struct sctp_stream_out *strq, 125217760Stuexen struct sctp_stream_queue_pending *sp, int holds_lock) 126217760Stuexen{ 127217760Stuexen /* take off and then setup so we know it is not on the wheel */ 128217760Stuexen if (holds_lock == 0) { 129217760Stuexen SCTP_TCB_SEND_LOCK(stcb); 130217760Stuexen } 131217760Stuexen if (TAILQ_EMPTY(&strq->outqueue)) { 132217760Stuexen if (asoc->last_out_stream == strq) { 133217760Stuexen asoc->last_out_stream = TAILQ_PREV(asoc->last_out_stream, 134217760Stuexen sctpwheel_listhead, 135217760Stuexen ss_params.rr.next_spoke); 136217760Stuexen if (asoc->last_out_stream == NULL) { 137217760Stuexen asoc->last_out_stream = TAILQ_LAST(&asoc->ss_data.out_wheel, 138217760Stuexen sctpwheel_listhead); 139217760Stuexen } 140217760Stuexen if (asoc->last_out_stream == strq) { 141217760Stuexen asoc->last_out_stream = NULL; 142217760Stuexen } 143217760Stuexen } 144217760Stuexen TAILQ_REMOVE(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke); 145217760Stuexen strq->ss_params.rr.next_spoke.tqe_next = NULL; 146217760Stuexen strq->ss_params.rr.next_spoke.tqe_prev = NULL; 147217760Stuexen } 148217760Stuexen if (holds_lock == 0) { 149217760Stuexen SCTP_TCB_SEND_UNLOCK(stcb); 150217760Stuexen } 151217760Stuexen return; 152217760Stuexen} 153217760Stuexen 154217760Stuexen 155217760Stuexenstatic struct sctp_stream_out * 156217760Stuexensctp_ss_default_select(struct sctp_tcb *stcb, struct sctp_nets *net, 157217760Stuexen struct sctp_association *asoc) 158217760Stuexen{ 159217760Stuexen struct sctp_stream_out *strq, *strqt; 160217760Stuexen 161217760Stuexen strqt = asoc->last_out_stream; 162217760Stuexendefault_again: 163217760Stuexen /* Find the next stream to use */ 164217760Stuexen if (strqt == NULL) { 165217760Stuexen strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); 166217760Stuexen } else { 167217760Stuexen strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke); 168217760Stuexen if (strq == NULL) { 169217760Stuexen strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); 170217760Stuexen } 171217760Stuexen } 172217760Stuexen 173217760Stuexen /* 174217760Stuexen * If CMT is off, we must validate that the stream in question has 175217760Stuexen * the first item pointed towards are network destionation requested 176217760Stuexen * by the caller. Note that if we turn out to be locked to a stream 177217760Stuexen * (assigning TSN's then we must stop, since we cannot look for 178217760Stuexen * another stream with data to send to that destination). In CMT's 179217760Stuexen * case, by skipping this check, we will send one data packet 180217760Stuexen * towards the requested net. 181217760Stuexen */ 182217760Stuexen if (net != NULL && strq != NULL && 183217760Stuexen SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) { 184217760Stuexen if (TAILQ_FIRST(&strq->outqueue) && 185217760Stuexen TAILQ_FIRST(&strq->outqueue)->net != NULL && 186217760Stuexen TAILQ_FIRST(&strq->outqueue)->net != net) { 187217760Stuexen if (strq == asoc->last_out_stream) { 188217760Stuexen return (NULL); 189217760Stuexen } else { 190217760Stuexen strqt = strq; 191217760Stuexen goto default_again; 192217760Stuexen } 193217760Stuexen } 194217760Stuexen } 195217760Stuexen return (strq); 196217760Stuexen} 197217760Stuexen 198217760Stuexenstatic void 199217760Stuexensctp_ss_default_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net, 200217760Stuexen struct sctp_association *asoc, 201217760Stuexen struct sctp_stream_out *strq, int moved_how_much) 202217760Stuexen{ 203217760Stuexen asoc->last_out_stream = strq; 204217760Stuexen return; 205217760Stuexen} 206217760Stuexen 207217760Stuexenstatic void 208217760Stuexensctp_ss_default_packet_done(struct sctp_tcb *stcb, struct sctp_nets *net, 209217760Stuexen struct sctp_association *asoc) 210217760Stuexen{ 211217760Stuexen /* Nothing to be done here */ 212217760Stuexen return; 213217760Stuexen} 214217760Stuexen 215217760Stuexenstatic int 216217760Stuexensctp_ss_default_get_value(struct sctp_tcb *stcb, struct sctp_association *asoc, 217217760Stuexen struct sctp_stream_out *strq, uint16_t * value) 218217760Stuexen{ 219217760Stuexen /* Nothing to be done here */ 220217760Stuexen return (-1); 221217760Stuexen} 222217760Stuexen 223217760Stuexenstatic int 224217760Stuexensctp_ss_default_set_value(struct sctp_tcb *stcb, struct sctp_association *asoc, 225217760Stuexen struct sctp_stream_out *strq, uint16_t value) 226217760Stuexen{ 227217760Stuexen /* Nothing to be done here */ 228217760Stuexen return (-1); 229217760Stuexen} 230217760Stuexen 231217760Stuexen/* 232217760Stuexen * Real round-robin algorithm. 233217760Stuexen * Always interates the streams in ascending order. 234217760Stuexen */ 235217760Stuexenstatic void 236217760Stuexensctp_ss_rr_add(struct sctp_tcb *stcb, struct sctp_association *asoc, 237217760Stuexen struct sctp_stream_out *strq, 238217760Stuexen struct sctp_stream_queue_pending *sp, int holds_lock) 239217760Stuexen{ 240217760Stuexen struct sctp_stream_out *strqt; 241217760Stuexen 242217760Stuexen if (holds_lock == 0) { 243217760Stuexen SCTP_TCB_SEND_LOCK(stcb); 244217760Stuexen } 245217760Stuexen if ((strq->ss_params.rr.next_spoke.tqe_next == NULL) && 246217760Stuexen (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) { 247217760Stuexen if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) { 248217760Stuexen TAILQ_INSERT_HEAD(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke); 249217760Stuexen } else { 250217760Stuexen strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel); 251217760Stuexen while (strqt != NULL && (strqt->stream_no < strq->stream_no)) { 252217760Stuexen strqt = TAILQ_NEXT(strqt, ss_params.rr.next_spoke); 253217760Stuexen } 254217760Stuexen if (strqt != NULL) { 255217760Stuexen TAILQ_INSERT_BEFORE(strqt, strq, ss_params.rr.next_spoke); 256217760Stuexen } else { 257217760Stuexen TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke); 258217760Stuexen } 259217760Stuexen } 260217760Stuexen } 261217760Stuexen if (holds_lock == 0) { 262217760Stuexen SCTP_TCB_SEND_UNLOCK(stcb); 263217760Stuexen } 264217760Stuexen return; 265217760Stuexen} 266217760Stuexen 267217760Stuexen/* 268217760Stuexen * Real round-robin per packet algorithm. 269217760Stuexen * Always interates the streams in ascending order and 270217760Stuexen * only fills messages of the same stream in a packet. 271217760Stuexen */ 272217760Stuexenstatic void 273217760Stuexensctp_ss_rrp_add(struct sctp_tcb *stcb, struct sctp_association *asoc, 274217760Stuexen struct sctp_stream_out *strq, 275217760Stuexen struct sctp_stream_queue_pending *sp, int holds_lock) 276217760Stuexen{ 277217760Stuexen struct sctp_stream_out *strqt; 278217760Stuexen 279217760Stuexen if (holds_lock == 0) { 280217760Stuexen SCTP_TCB_SEND_LOCK(stcb); 281217760Stuexen } 282217760Stuexen if ((strq->ss_params.rr.next_spoke.tqe_next == NULL) && 283217760Stuexen (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) { 284217760Stuexen 285217760Stuexen if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) { 286217760Stuexen TAILQ_INSERT_HEAD(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke); 287217760Stuexen } else { 288217760Stuexen strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel); 289217760Stuexen while (strqt != NULL && strqt->stream_no < strq->stream_no) { 290217760Stuexen strqt = TAILQ_NEXT(strqt, ss_params.rr.next_spoke); 291217760Stuexen } 292217760Stuexen if (strqt != NULL) { 293217760Stuexen TAILQ_INSERT_BEFORE(strqt, strq, ss_params.rr.next_spoke); 294217760Stuexen } else { 295217760Stuexen TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke); 296217760Stuexen } 297217760Stuexen } 298217760Stuexen } 299217760Stuexen if (holds_lock == 0) { 300217760Stuexen SCTP_TCB_SEND_UNLOCK(stcb); 301217760Stuexen } 302217760Stuexen return; 303217760Stuexen} 304217760Stuexen 305217760Stuexenstatic struct sctp_stream_out * 306217760Stuexensctp_ss_rrp_select(struct sctp_tcb *stcb, struct sctp_nets *net, 307217760Stuexen struct sctp_association *asoc) 308217760Stuexen{ 309217760Stuexen struct sctp_stream_out *strq, *strqt; 310217760Stuexen 311217760Stuexen strqt = asoc->last_out_stream; 312217760Stuexen if (strqt != NULL && !TAILQ_EMPTY(&strqt->outqueue)) { 313217760Stuexen return (strqt); 314217760Stuexen } 315217760Stuexenrrp_again: 316217760Stuexen /* Find the next stream to use */ 317217760Stuexen if (strqt == NULL) { 318217760Stuexen strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); 319217760Stuexen } else { 320217760Stuexen strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke); 321217760Stuexen if (strq == NULL) { 322217760Stuexen strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); 323217760Stuexen } 324217760Stuexen } 325217760Stuexen 326217760Stuexen /* 327217760Stuexen * If CMT is off, we must validate that the stream in question has 328217760Stuexen * the first item pointed towards are network destionation requested 329217760Stuexen * by the caller. Note that if we turn out to be locked to a stream 330217760Stuexen * (assigning TSN's then we must stop, since we cannot look for 331217760Stuexen * another stream with data to send to that destination). In CMT's 332217760Stuexen * case, by skipping this check, we will send one data packet 333217760Stuexen * towards the requested net. 334217760Stuexen */ 335217760Stuexen if (net != NULL && strq != NULL && 336217760Stuexen SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) { 337217760Stuexen if (TAILQ_FIRST(&strq->outqueue) && 338217760Stuexen TAILQ_FIRST(&strq->outqueue)->net != NULL && 339217760Stuexen TAILQ_FIRST(&strq->outqueue)->net != net) { 340217760Stuexen if (strq == asoc->last_out_stream) { 341217760Stuexen return (NULL); 342217760Stuexen } else { 343217760Stuexen strqt = strq; 344217760Stuexen goto rrp_again; 345217760Stuexen } 346217760Stuexen } 347217760Stuexen } 348217760Stuexen return (strq); 349217760Stuexen} 350217760Stuexen 351217760Stuexenstatic void 352217760Stuexensctp_ss_rrp_packet_done(struct sctp_tcb *stcb, struct sctp_nets *net, 353217760Stuexen struct sctp_association *asoc) 354217760Stuexen{ 355217760Stuexen struct sctp_stream_out *strq, *strqt; 356217760Stuexen 357217760Stuexen strqt = asoc->last_out_stream; 358217760Stuexenrrp_pd_again: 359217760Stuexen /* Find the next stream to use */ 360217760Stuexen if (strqt == NULL) { 361217760Stuexen strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); 362217760Stuexen } else { 363217760Stuexen strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke); 364217760Stuexen if (strq == NULL) { 365217760Stuexen strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); 366217760Stuexen } 367217760Stuexen } 368217760Stuexen 369217760Stuexen /* 370217760Stuexen * If CMT is off, we must validate that the stream in question has 371217760Stuexen * the first item pointed towards are network destionation requested 372217760Stuexen * by the caller. Note that if we turn out to be locked to a stream 373217760Stuexen * (assigning TSN's then we must stop, since we cannot look for 374217760Stuexen * another stream with data to send to that destination). In CMT's 375217760Stuexen * case, by skipping this check, we will send one data packet 376217760Stuexen * towards the requested net. 377217760Stuexen */ 378217760Stuexen if ((strq != NULL) && TAILQ_FIRST(&strq->outqueue) && 379217760Stuexen (net != NULL && TAILQ_FIRST(&strq->outqueue)->net != net) && 380217760Stuexen (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0)) { 381217760Stuexen if (strq == asoc->last_out_stream) { 382217760Stuexen strq = NULL; 383217760Stuexen } else { 384217760Stuexen strqt = strq; 385217760Stuexen goto rrp_pd_again; 386217760Stuexen } 387217760Stuexen } 388217760Stuexen asoc->last_out_stream = strq; 389217760Stuexen return; 390217760Stuexen} 391217760Stuexen 392217760Stuexen 393217760Stuexen/* 394217760Stuexen * Priority algorithm. 395217760Stuexen * Always prefers streams based on their priority id. 396217760Stuexen */ 397217760Stuexenstatic void 398217760Stuexensctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, 399217760Stuexen int clear_values, int holds_lock) 400217760Stuexen{ 401217760Stuexen uint16_t i; 402217760Stuexen 403217760Stuexen for (i = 0; i < stcb->asoc.streamoutcnt; i++) { 404217760Stuexen if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { 405217760Stuexen if (clear_values) 406217760Stuexen stcb->asoc.strmout[i].ss_params.prio.priority = 0; 407217760Stuexen sctp_ss_default_remove(stcb, &stcb->asoc, &stcb->asoc.strmout[i], NULL, holds_lock); 408217760Stuexen } 409217760Stuexen } 410217760Stuexen return; 411217760Stuexen} 412217760Stuexen 413217760Stuexenstatic void 414217760Stuexensctp_ss_prio_init_stream(struct sctp_stream_out *strq) 415217760Stuexen{ 416217760Stuexen strq->ss_params.prio.next_spoke.tqe_next = NULL; 417217760Stuexen strq->ss_params.prio.next_spoke.tqe_prev = NULL; 418217760Stuexen strq->ss_params.prio.priority = 0; 419217760Stuexen return; 420217760Stuexen} 421217760Stuexen 422217760Stuexenstatic void 423217760Stuexensctp_ss_prio_add(struct sctp_tcb *stcb, struct sctp_association *asoc, 424217760Stuexen struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp, 425217760Stuexen int holds_lock) 426217760Stuexen{ 427217760Stuexen struct sctp_stream_out *strqt; 428217760Stuexen 429217760Stuexen if (holds_lock == 0) { 430217760Stuexen SCTP_TCB_SEND_LOCK(stcb); 431217760Stuexen } 432217760Stuexen if ((strq->ss_params.prio.next_spoke.tqe_next == NULL) && 433217760Stuexen (strq->ss_params.prio.next_spoke.tqe_prev == NULL)) { 434217760Stuexen 435217760Stuexen if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) { 436217760Stuexen TAILQ_INSERT_HEAD(&asoc->ss_data.out_wheel, strq, ss_params.prio.next_spoke); 437217760Stuexen } else { 438217760Stuexen strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel); 439217760Stuexen while (strqt != NULL && strqt->ss_params.prio.priority < strq->ss_params.prio.priority) { 440217760Stuexen strqt = TAILQ_NEXT(strqt, ss_params.prio.next_spoke); 441217760Stuexen } 442217760Stuexen if (strqt != NULL) { 443217760Stuexen TAILQ_INSERT_BEFORE(strqt, strq, ss_params.prio.next_spoke); 444217760Stuexen } else { 445217760Stuexen TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.prio.next_spoke); 446217760Stuexen } 447217760Stuexen } 448217760Stuexen } 449217760Stuexen if (holds_lock == 0) { 450217760Stuexen SCTP_TCB_SEND_UNLOCK(stcb); 451217760Stuexen } 452217760Stuexen return; 453217760Stuexen} 454217760Stuexen 455217760Stuexenstatic void 456217760Stuexensctp_ss_prio_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, 457217760Stuexen struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp, 458217760Stuexen int holds_lock) 459217760Stuexen{ 460217760Stuexen /* take off and then setup so we know it is not on the wheel */ 461217760Stuexen if (holds_lock == 0) { 462217760Stuexen SCTP_TCB_SEND_LOCK(stcb); 463217760Stuexen } 464217760Stuexen if (TAILQ_EMPTY(&strq->outqueue)) { 465217760Stuexen if (asoc->last_out_stream == strq) { 466217760Stuexen asoc->last_out_stream = TAILQ_PREV(asoc->last_out_stream, sctpwheel_listhead, 467217760Stuexen ss_params.prio.next_spoke); 468217760Stuexen if (asoc->last_out_stream == NULL) { 469217760Stuexen asoc->last_out_stream = TAILQ_LAST(&asoc->ss_data.out_wheel, 470217760Stuexen sctpwheel_listhead); 471217760Stuexen } 472217760Stuexen if (asoc->last_out_stream == strq) { 473217760Stuexen asoc->last_out_stream = NULL; 474217760Stuexen } 475217760Stuexen } 476217760Stuexen TAILQ_REMOVE(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke); 477217760Stuexen strq->ss_params.prio.next_spoke.tqe_next = NULL; 478217760Stuexen strq->ss_params.prio.next_spoke.tqe_prev = NULL; 479217760Stuexen } 480217760Stuexen if (holds_lock == 0) { 481217760Stuexen SCTP_TCB_SEND_UNLOCK(stcb); 482217760Stuexen } 483217760Stuexen return; 484217760Stuexen} 485217760Stuexen 486217760Stuexenstatic struct sctp_stream_out * 487217760Stuexensctp_ss_prio_select(struct sctp_tcb *stcb, struct sctp_nets *net, 488217760Stuexen struct sctp_association *asoc) 489217760Stuexen{ 490217760Stuexen struct sctp_stream_out *strq, *strqt, *strqn; 491217760Stuexen 492217760Stuexen strqt = asoc->last_out_stream; 493217760Stuexenprio_again: 494217760Stuexen /* Find the next stream to use */ 495217760Stuexen if (strqt == NULL) { 496217760Stuexen strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); 497217760Stuexen } else { 498217760Stuexen strqn = TAILQ_NEXT(strqt, ss_params.prio.next_spoke); 499217760Stuexen if (strqn != NULL && 500217760Stuexen strqn->ss_params.prio.priority == strqt->ss_params.prio.priority) { 501217760Stuexen strq = TAILQ_NEXT(strqt, ss_params.prio.next_spoke); 502217760Stuexen } else { 503217760Stuexen strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); 504217760Stuexen } 505217760Stuexen } 506217760Stuexen 507217760Stuexen /* 508217760Stuexen * If CMT is off, we must validate that the stream in question has 509217760Stuexen * the first item pointed towards are network destionation requested 510217760Stuexen * by the caller. Note that if we turn out to be locked to a stream 511217760Stuexen * (assigning TSN's then we must stop, since we cannot look for 512217760Stuexen * another stream with data to send to that destination). In CMT's 513217760Stuexen * case, by skipping this check, we will send one data packet 514217760Stuexen * towards the requested net. 515217760Stuexen */ 516217760Stuexen if (net != NULL && strq != NULL && 517217760Stuexen SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) { 518217760Stuexen if (TAILQ_FIRST(&strq->outqueue) && 519217760Stuexen TAILQ_FIRST(&strq->outqueue)->net != NULL && 520217760Stuexen TAILQ_FIRST(&strq->outqueue)->net != net) { 521217760Stuexen if (strq == asoc->last_out_stream) { 522217760Stuexen return (NULL); 523217760Stuexen } else { 524217760Stuexen strqt = strq; 525217760Stuexen goto prio_again; 526217760Stuexen } 527217760Stuexen } 528217760Stuexen } 529217760Stuexen return (strq); 530217760Stuexen} 531217760Stuexen 532217760Stuexenstatic int 533217760Stuexensctp_ss_prio_get_value(struct sctp_tcb *stcb, struct sctp_association *asoc, 534217760Stuexen struct sctp_stream_out *strq, uint16_t * value) 535217760Stuexen{ 536217760Stuexen if (strq == NULL) { 537217760Stuexen return (-1); 538217760Stuexen } 539217760Stuexen *value = strq->ss_params.prio.priority; 540217760Stuexen return (1); 541217760Stuexen} 542217760Stuexen 543217760Stuexenstatic int 544217760Stuexensctp_ss_prio_set_value(struct sctp_tcb *stcb, struct sctp_association *asoc, 545217760Stuexen struct sctp_stream_out *strq, uint16_t value) 546217760Stuexen{ 547217760Stuexen if (strq == NULL) { 548217760Stuexen return (-1); 549217760Stuexen } 550217760Stuexen strq->ss_params.prio.priority = value; 551217760Stuexen sctp_ss_prio_remove(stcb, asoc, strq, NULL, 1); 552217760Stuexen sctp_ss_prio_add(stcb, asoc, strq, NULL, 1); 553217760Stuexen return (1); 554217760Stuexen} 555217760Stuexen 556217760Stuexen/* 557217760Stuexen * Fair bandwidth algorithm. 558217760Stuexen * Maintains an equal troughput per stream. 559217760Stuexen */ 560217760Stuexenstatic void 561217760Stuexensctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, 562217760Stuexen int clear_values, int holds_lock) 563217760Stuexen{ 564217760Stuexen uint16_t i; 565217760Stuexen 566217760Stuexen for (i = 0; i < stcb->asoc.streamoutcnt; i++) { 567217760Stuexen if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { 568217760Stuexen if (clear_values) { 569217760Stuexen stcb->asoc.strmout[i].ss_params.fb.rounds = -1; 570217760Stuexen } 571217760Stuexen sctp_ss_default_remove(stcb, &stcb->asoc, &stcb->asoc.strmout[i], NULL, holds_lock); 572217760Stuexen } 573217760Stuexen } 574217760Stuexen return; 575217760Stuexen} 576217760Stuexen 577217760Stuexenstatic void 578217760Stuexensctp_ss_fb_init_stream(struct sctp_stream_out *strq) 579217760Stuexen{ 580217760Stuexen strq->ss_params.fb.next_spoke.tqe_next = NULL; 581217760Stuexen strq->ss_params.fb.next_spoke.tqe_prev = NULL; 582217760Stuexen strq->ss_params.fb.rounds = -1; 583217760Stuexen return; 584217760Stuexen} 585217760Stuexen 586217760Stuexenstatic void 587217760Stuexensctp_ss_fb_add(struct sctp_tcb *stcb, struct sctp_association *asoc, 588217760Stuexen struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp, 589217760Stuexen int holds_lock) 590217760Stuexen{ 591217760Stuexen if (holds_lock == 0) { 592217760Stuexen SCTP_TCB_SEND_LOCK(stcb); 593217760Stuexen } 594217760Stuexen if ((strq->ss_params.rr.next_spoke.tqe_next == NULL) && 595217760Stuexen (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) { 596217760Stuexen if (!TAILQ_EMPTY(&strq->outqueue) && strq->ss_params.fb.rounds < 0) 597217760Stuexen strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length; 598217760Stuexen TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke); 599217760Stuexen } 600217760Stuexen if (holds_lock == 0) { 601217760Stuexen SCTP_TCB_SEND_UNLOCK(stcb); 602217760Stuexen } 603217760Stuexen return; 604217760Stuexen} 605217760Stuexen 606217760Stuexenstatic void 607217760Stuexensctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, 608217760Stuexen struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp, 609217760Stuexen int holds_lock) 610217760Stuexen{ 611217760Stuexen /* take off and then setup so we know it is not on the wheel */ 612217760Stuexen if (holds_lock == 0) { 613217760Stuexen SCTP_TCB_SEND_LOCK(stcb); 614217760Stuexen } 615217760Stuexen if (TAILQ_EMPTY(&strq->outqueue)) { 616217760Stuexen if (asoc->last_out_stream == strq) { 617217760Stuexen asoc->last_out_stream = TAILQ_PREV(asoc->last_out_stream, sctpwheel_listhead, 618217760Stuexen ss_params.fb.next_spoke); 619217760Stuexen if (asoc->last_out_stream == NULL) { 620217760Stuexen asoc->last_out_stream = TAILQ_LAST(&asoc->ss_data.out_wheel, 621217760Stuexen sctpwheel_listhead); 622217760Stuexen } 623217760Stuexen if (asoc->last_out_stream == strq) { 624217760Stuexen asoc->last_out_stream = NULL; 625217760Stuexen } 626217760Stuexen } 627217760Stuexen strq->ss_params.fb.rounds = -1; 628217760Stuexen TAILQ_REMOVE(&asoc->ss_data.out_wheel, strq, ss_params.fb.next_spoke); 629217760Stuexen strq->ss_params.fb.next_spoke.tqe_next = NULL; 630217760Stuexen strq->ss_params.fb.next_spoke.tqe_prev = NULL; 631217760Stuexen } 632217760Stuexen if (holds_lock == 0) { 633217760Stuexen SCTP_TCB_SEND_UNLOCK(stcb); 634217760Stuexen } 635217760Stuexen return; 636217760Stuexen} 637217760Stuexen 638217760Stuexenstatic struct sctp_stream_out * 639217760Stuexensctp_ss_fb_select(struct sctp_tcb *stcb, struct sctp_nets *net, 640217760Stuexen struct sctp_association *asoc) 641217760Stuexen{ 642217760Stuexen struct sctp_stream_out *strq = NULL, *strqt; 643217760Stuexen 644217760Stuexen if (TAILQ_FIRST(&asoc->ss_data.out_wheel) == TAILQ_LAST(&asoc->ss_data.out_wheel, sctpwheel_listhead)) { 645217760Stuexen strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel); 646217760Stuexen } else { 647217760Stuexen if (asoc->last_out_stream != NULL) { 648217760Stuexen strqt = TAILQ_NEXT(asoc->last_out_stream, ss_params.fb.next_spoke); 649217760Stuexen } else { 650217760Stuexen strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel); 651217760Stuexen } 652217760Stuexen } 653217760Stuexen do { 654217760Stuexen if ((strqt != NULL) && TAILQ_FIRST(&strqt->outqueue) && 655217760Stuexen TAILQ_FIRST(&strqt->outqueue)->net != NULL && 656217760Stuexen ((net == NULL || TAILQ_FIRST(&strqt->outqueue)->net == net) || 657217760Stuexen (SCTP_BASE_SYSCTL(sctp_cmt_on_off) > 0))) { 658217760Stuexen if ((strqt->ss_params.fb.rounds >= 0) && (strq == NULL || 659217760Stuexen strqt->ss_params.fb.rounds < strq->ss_params.fb.rounds)) { 660217760Stuexen strq = strqt; 661217760Stuexen } 662217760Stuexen } 663217760Stuexen if (strqt != NULL) { 664217760Stuexen strqt = TAILQ_NEXT(strqt, ss_params.fb.next_spoke); 665217760Stuexen } else { 666217760Stuexen strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel); 667217760Stuexen } 668217760Stuexen } while (strqt != strq); 669217760Stuexen return (strq); 670217760Stuexen} 671217760Stuexen 672217760Stuexenstatic void 673217760Stuexensctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net, 674217760Stuexen struct sctp_association *asoc, struct sctp_stream_out *strq, 675217760Stuexen int moved_how_much) 676217760Stuexen{ 677217760Stuexen struct sctp_stream_out *strqt; 678217760Stuexen int subtract; 679217760Stuexen 680217760Stuexen subtract = strq->ss_params.fb.rounds; 681217760Stuexen TAILQ_FOREACH(strqt, &asoc->ss_data.out_wheel, ss_params.fb.next_spoke) { 682217760Stuexen strqt->ss_params.fb.rounds -= subtract; 683217760Stuexen if (strqt->ss_params.fb.rounds < 0) 684217760Stuexen strqt->ss_params.fb.rounds = 0; 685217760Stuexen } 686217760Stuexen if (TAILQ_FIRST(&strq->outqueue)) { 687217760Stuexen strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length; 688217760Stuexen } else { 689217760Stuexen strq->ss_params.fb.rounds = -1; 690217760Stuexen } 691217760Stuexen asoc->last_out_stream = strq; 692217760Stuexen return; 693217760Stuexen} 694217760Stuexen 695217760Stuexen/* 696217760Stuexen * First-come, first-serve algorithm. 697217760Stuexen * Maintains the order provided by the application. 698217760Stuexen */ 699217760Stuexenstatic void 700217760Stuexensctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc, 701217760Stuexen int holds_lock) 702217760Stuexen{ 703217760Stuexen int x, element = 0, add_more = 1; 704217760Stuexen struct sctp_stream_queue_pending *sp; 705217760Stuexen uint16_t i; 706217760Stuexen 707217760Stuexen TAILQ_INIT(&asoc->ss_data.out_list); 708217760Stuexen while (add_more) { 709217760Stuexen add_more = 0; 710217760Stuexen for (i = 0; i < stcb->asoc.streamoutcnt; i++) { 711217760Stuexen sp = TAILQ_FIRST(&asoc->ss_data.out_list); 712217760Stuexen x = element; 713217760Stuexen while (sp != NULL && x > 0) { 714217760Stuexen sp = TAILQ_NEXT(sp, next); 715217760Stuexen } 716217760Stuexen if (sp != NULL) { 717217760Stuexen sctp_ss_default_add(stcb, &stcb->asoc, &stcb->asoc.strmout[i], NULL, holds_lock); 718217760Stuexen add_more = 1; 719217760Stuexen } 720217760Stuexen } 721217760Stuexen element++; 722217760Stuexen } 723217760Stuexen return; 724217760Stuexen} 725217760Stuexen 726217760Stuexenstatic void 727217760Stuexensctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, 728217760Stuexen int clear_values, int holds_lock) 729217760Stuexen{ 730217760Stuexen if (clear_values) { 731217760Stuexen while (!TAILQ_EMPTY(&asoc->ss_data.out_list)) { 732217760Stuexen TAILQ_REMOVE(&asoc->ss_data.out_list, TAILQ_FIRST(&asoc->ss_data.out_list), next); 733217760Stuexen } 734217760Stuexen } 735217760Stuexen return; 736217760Stuexen} 737217760Stuexen 738217760Stuexenstatic void 739217760Stuexensctp_ss_fcfs_init_stream(struct sctp_stream_out *strq) 740217760Stuexen{ 741217760Stuexen /* Nothing to be done here */ 742217760Stuexen return; 743217760Stuexen} 744217760Stuexen 745217760Stuexenstatic void 746217760Stuexensctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc, 747217760Stuexen struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp, 748217760Stuexen int holds_lock) 749217760Stuexen{ 750217760Stuexen if (holds_lock == 0) { 751217760Stuexen SCTP_TCB_SEND_LOCK(stcb); 752217760Stuexen } 753217760Stuexen if (sp && (sp->next.tqe_next == NULL) && 754217760Stuexen (sp->next.tqe_prev == NULL)) { 755217760Stuexen TAILQ_INSERT_TAIL(&asoc->ss_data.out_list, sp, next); 756217760Stuexen } 757217760Stuexen if (holds_lock == 0) { 758217760Stuexen SCTP_TCB_SEND_UNLOCK(stcb); 759217760Stuexen } 760217760Stuexen return; 761217760Stuexen} 762217760Stuexen 763217760Stuexenstatic int 764217760Stuexensctp_ss_fcfs_is_empty(struct sctp_tcb *stcb, struct sctp_association *asoc) 765217760Stuexen{ 766217760Stuexen if (TAILQ_EMPTY(&asoc->ss_data.out_list)) { 767217760Stuexen return (1); 768217760Stuexen } else { 769217760Stuexen return (0); 770217760Stuexen } 771217760Stuexen} 772217760Stuexen 773217760Stuexenstatic void 774217760Stuexensctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, 775217760Stuexen struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp, 776217760Stuexen int holds_lock) 777217760Stuexen{ 778217760Stuexen if (holds_lock == 0) { 779217760Stuexen SCTP_TCB_SEND_LOCK(stcb); 780217760Stuexen } 781217760Stuexen if (sp && 782217760Stuexen ((sp->next.tqe_next != NULL) || 783217760Stuexen (sp->next.tqe_prev != NULL))) { 784217760Stuexen TAILQ_REMOVE(&asoc->ss_data.out_list, sp, next); 785217760Stuexen } 786217760Stuexen if (holds_lock == 0) { 787217760Stuexen SCTP_TCB_SEND_UNLOCK(stcb); 788217760Stuexen } 789217760Stuexen return; 790217760Stuexen} 791217760Stuexen 792217760Stuexen 793217760Stuexenstatic struct sctp_stream_out * 794217760Stuexensctp_ss_fcfs_select(struct sctp_tcb *stcb, struct sctp_nets *net, 795217760Stuexen struct sctp_association *asoc) 796217760Stuexen{ 797217760Stuexen struct sctp_stream_out *strq; 798217760Stuexen struct sctp_stream_queue_pending *sp; 799217760Stuexen 800217760Stuexen sp = TAILQ_FIRST(&asoc->ss_data.out_list); 801217760Stuexendefault_again: 802217760Stuexen if (sp != NULL) { 803217760Stuexen strq = &asoc->strmout[sp->stream]; 804217760Stuexen } else { 805217760Stuexen strq = NULL; 806217760Stuexen } 807217760Stuexen 808217760Stuexen /* 809217760Stuexen * If CMT is off, we must validate that the stream in question has 810217760Stuexen * the first item pointed towards are network destionation requested 811217760Stuexen * by the caller. Note that if we turn out to be locked to a stream 812217760Stuexen * (assigning TSN's then we must stop, since we cannot look for 813217760Stuexen * another stream with data to send to that destination). In CMT's 814217760Stuexen * case, by skipping this check, we will send one data packet 815217760Stuexen * towards the requested net. 816217760Stuexen */ 817217760Stuexen if (net != NULL && strq != NULL && 818217760Stuexen SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) { 819217760Stuexen if (TAILQ_FIRST(&strq->outqueue) && 820217760Stuexen TAILQ_FIRST(&strq->outqueue)->net != NULL && 821217760Stuexen TAILQ_FIRST(&strq->outqueue)->net != net) { 822217760Stuexen sp = TAILQ_NEXT(sp, next); 823217760Stuexen goto default_again; 824217760Stuexen } 825217760Stuexen } 826217760Stuexen return (strq); 827217760Stuexen} 828217760Stuexen 829217760Stuexenstruct sctp_ss_functions sctp_ss_functions[] = { 830217760Stuexen/* SCTP_SS_DEFAULT */ 831217760Stuexen { 832217760Stuexen .sctp_ss_init = sctp_ss_default_init, 833217760Stuexen .sctp_ss_clear = sctp_ss_default_clear, 834217760Stuexen .sctp_ss_init_stream = sctp_ss_default_init_stream, 835217760Stuexen .sctp_ss_add_to_stream = sctp_ss_default_add, 836217760Stuexen .sctp_ss_is_empty = sctp_ss_default_is_empty, 837217760Stuexen .sctp_ss_remove_from_stream = sctp_ss_default_remove, 838217760Stuexen .sctp_ss_select_stream = sctp_ss_default_select, 839217760Stuexen .sctp_ss_scheduled = sctp_ss_default_scheduled, 840217760Stuexen .sctp_ss_packet_done = sctp_ss_default_packet_done, 841217760Stuexen .sctp_ss_get_value = sctp_ss_default_get_value, 842217760Stuexen .sctp_ss_set_value = sctp_ss_default_set_value 843217760Stuexen }, 844217760Stuexen/* SCTP_SS_ROUND_ROBIN */ 845217760Stuexen { 846217760Stuexen .sctp_ss_init = sctp_ss_default_init, 847217760Stuexen .sctp_ss_clear = sctp_ss_default_clear, 848217760Stuexen .sctp_ss_init_stream = sctp_ss_default_init_stream, 849217760Stuexen .sctp_ss_add_to_stream = sctp_ss_rr_add, 850217760Stuexen .sctp_ss_is_empty = sctp_ss_default_is_empty, 851217760Stuexen .sctp_ss_remove_from_stream = sctp_ss_default_remove, 852217760Stuexen .sctp_ss_select_stream = sctp_ss_default_select, 853217760Stuexen .sctp_ss_scheduled = sctp_ss_default_scheduled, 854217760Stuexen .sctp_ss_packet_done = sctp_ss_default_packet_done, 855217760Stuexen .sctp_ss_get_value = sctp_ss_default_get_value, 856217760Stuexen .sctp_ss_set_value = sctp_ss_default_set_value 857217760Stuexen }, 858217760Stuexen/* SCTP_SS_ROUND_ROBIN_PACKET */ 859217760Stuexen { 860217760Stuexen .sctp_ss_init = sctp_ss_default_init, 861217760Stuexen .sctp_ss_clear = sctp_ss_default_clear, 862217760Stuexen .sctp_ss_init_stream = sctp_ss_default_init_stream, 863217760Stuexen .sctp_ss_add_to_stream = sctp_ss_rrp_add, 864217760Stuexen .sctp_ss_is_empty = sctp_ss_default_is_empty, 865217760Stuexen .sctp_ss_remove_from_stream = sctp_ss_default_remove, 866217760Stuexen .sctp_ss_select_stream = sctp_ss_rrp_select, 867217760Stuexen .sctp_ss_scheduled = sctp_ss_default_scheduled, 868217760Stuexen .sctp_ss_packet_done = sctp_ss_rrp_packet_done, 869217760Stuexen .sctp_ss_get_value = sctp_ss_default_get_value, 870217760Stuexen .sctp_ss_set_value = sctp_ss_default_set_value 871217760Stuexen }, 872217760Stuexen/* SCTP_SS_PRIORITY */ 873217760Stuexen { 874217760Stuexen .sctp_ss_init = sctp_ss_default_init, 875217760Stuexen .sctp_ss_clear = sctp_ss_prio_clear, 876217760Stuexen .sctp_ss_init_stream = sctp_ss_prio_init_stream, 877217760Stuexen .sctp_ss_add_to_stream = sctp_ss_prio_add, 878217760Stuexen .sctp_ss_is_empty = sctp_ss_default_is_empty, 879217760Stuexen .sctp_ss_remove_from_stream = sctp_ss_prio_remove, 880217760Stuexen .sctp_ss_select_stream = sctp_ss_prio_select, 881217760Stuexen .sctp_ss_scheduled = sctp_ss_default_scheduled, 882217760Stuexen .sctp_ss_packet_done = sctp_ss_default_packet_done, 883217760Stuexen .sctp_ss_get_value = sctp_ss_prio_get_value, 884217760Stuexen .sctp_ss_set_value = sctp_ss_prio_set_value 885217760Stuexen }, 886217760Stuexen/* SCTP_SS_FAIR_BANDWITH */ 887217760Stuexen { 888217760Stuexen .sctp_ss_init = sctp_ss_default_init, 889217760Stuexen .sctp_ss_clear = sctp_ss_fb_clear, 890217760Stuexen .sctp_ss_init_stream = sctp_ss_fb_init_stream, 891217760Stuexen .sctp_ss_add_to_stream = sctp_ss_fb_add, 892217760Stuexen .sctp_ss_is_empty = sctp_ss_default_is_empty, 893217760Stuexen .sctp_ss_remove_from_stream = sctp_ss_fb_remove, 894217760Stuexen .sctp_ss_select_stream = sctp_ss_fb_select, 895217760Stuexen .sctp_ss_scheduled = sctp_ss_fb_scheduled, 896217760Stuexen .sctp_ss_packet_done = sctp_ss_default_packet_done, 897217760Stuexen .sctp_ss_get_value = sctp_ss_default_get_value, 898217760Stuexen .sctp_ss_set_value = sctp_ss_default_set_value 899217760Stuexen }, 900217760Stuexen/* SCTP_SS_FIRST_COME */ 901217760Stuexen { 902217760Stuexen .sctp_ss_init = sctp_ss_fcfs_init, 903217760Stuexen .sctp_ss_clear = sctp_ss_fcfs_clear, 904217760Stuexen .sctp_ss_init_stream = sctp_ss_fcfs_init_stream, 905217760Stuexen .sctp_ss_add_to_stream = sctp_ss_fcfs_add, 906217760Stuexen .sctp_ss_is_empty = sctp_ss_fcfs_is_empty, 907217760Stuexen .sctp_ss_remove_from_stream = sctp_ss_fcfs_remove, 908217760Stuexen .sctp_ss_select_stream = sctp_ss_fcfs_select, 909217760Stuexen .sctp_ss_scheduled = sctp_ss_default_scheduled, 910217760Stuexen .sctp_ss_packet_done = sctp_ss_default_packet_done, 911217760Stuexen .sctp_ss_get_value = sctp_ss_default_get_value, 912217760Stuexen .sctp_ss_set_value = sctp_ss_default_set_value 913217760Stuexen } 914217760Stuexen}; 915