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