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