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