netwerk/sctp/src/netinet/sctp_ss_functions.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rwxr-xr-x

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial