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 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 troughput 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.last_out_stream == NULL || 698 TAILQ_FIRST(&asoc->ss_data.out.wheel) == TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead)) { 699 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel); 700 } else { 701 strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.fb.next_spoke); 702 } 703 do { 704 if ((strqt != NULL) && 705 ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) > 0) || 706 (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0 && 707 (net == NULL || (TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net == NULL) || 708 (net != NULL && TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net != NULL && 709 TAILQ_FIRST(&strqt->outqueue)->net == net))))) { 710 if ((strqt->ss_params.fb.rounds >= 0) && (strq == NULL || 711 strqt->ss_params.fb.rounds < strq->ss_params.fb.rounds)) { 712 strq = strqt; 713 } 714 } 715 if (strqt != NULL) { 716 strqt = TAILQ_NEXT(strqt, ss_params.fb.next_spoke); 717 } else { 718 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel); 719 } 720 } while (strqt != strq); 721 return (strq); 722 } 723 724 static void 725 sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED, 726 struct sctp_association *asoc, struct sctp_stream_out *strq, 727 int moved_how_much SCTP_UNUSED) 728 { 729 struct sctp_stream_queue_pending *sp; 730 struct sctp_stream_out *strqt; 731 int subtract; 732 733 if (stcb->asoc.idata_supported == 0) { 734 sp = TAILQ_FIRST(&strq->outqueue); 735 if ((sp != NULL) && (sp->some_taken == 1)) { 736 stcb->asoc.ss_data.locked_on_sending = strq; 737 } else { 738 stcb->asoc.ss_data.locked_on_sending = NULL; 739 } 740 } else { 741 stcb->asoc.ss_data.locked_on_sending = NULL; 742 } 743 subtract = strq->ss_params.fb.rounds; 744 TAILQ_FOREACH(strqt, &asoc->ss_data.out.wheel, ss_params.fb.next_spoke) { 745 strqt->ss_params.fb.rounds -= subtract; 746 if (strqt->ss_params.fb.rounds < 0) 747 strqt->ss_params.fb.rounds = 0; 748 } 749 if (TAILQ_FIRST(&strq->outqueue)) { 750 strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length; 751 } else { 752 strq->ss_params.fb.rounds = -1; 753 } 754 asoc->ss_data.last_out_stream = strq; 755 return; 756 } 757 758 /* 759 * First-come, first-serve algorithm. 760 * Maintains the order provided by the application. 761 */ 762 static void 763 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc, 764 struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp, 765 int holds_lock); 766 767 static void 768 sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc, 769 int holds_lock) 770 { 771 uint32_t x, n = 0, add_more = 1; 772 struct sctp_stream_queue_pending *sp; 773 uint16_t i; 774 775 if (holds_lock == 0) { 776 SCTP_TCB_SEND_LOCK(stcb); 777 } 778 TAILQ_INIT(&asoc->ss_data.out.list); 779 /* 780 * If there is data in the stream queues already, the scheduler of 781 * an existing association has been changed. We can only cycle 782 * through the stream queues and add everything to the FCFS queue. 783 */ 784 while (add_more) { 785 add_more = 0; 786 for (i = 0; i < stcb->asoc.streamoutcnt; i++) { 787 sp = TAILQ_FIRST(&stcb->asoc.strmout[i].outqueue); 788 x = 0; 789 /* Find n. message in current stream queue */ 790 while (sp != NULL && x < n) { 791 sp = TAILQ_NEXT(sp, next); 792 x++; 793 } 794 if (sp != NULL) { 795 sctp_ss_fcfs_add(stcb, &stcb->asoc, &stcb->asoc.strmout[i], sp, 1); 796 add_more = 1; 797 } 798 } 799 n++; 800 } 801 if (holds_lock == 0) { 802 SCTP_TCB_SEND_UNLOCK(stcb); 803 } 804 return; 805 } 806 807 static void 808 sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, 809 int clear_values, int holds_lock) 810 { 811 struct sctp_stream_queue_pending *sp; 812 813 if (clear_values) { 814 if (holds_lock == 0) { 815 SCTP_TCB_SEND_LOCK(stcb); 816 } 817 while (!TAILQ_EMPTY(&asoc->ss_data.out.list)) { 818 sp = TAILQ_FIRST(&asoc->ss_data.out.list); 819 TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next); 820 sp->ss_next.tqe_next = NULL; 821 sp->ss_next.tqe_prev = NULL; 822 } 823 if (holds_lock == 0) { 824 SCTP_TCB_SEND_UNLOCK(stcb); 825 } 826 } 827 return; 828 } 829 830 static void 831 sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq) 832 { 833 if (with_strq != NULL) { 834 if (stcb->asoc.ss_data.locked_on_sending == with_strq) { 835 stcb->asoc.ss_data.locked_on_sending = strq; 836 } 837 if (stcb->asoc.ss_data.last_out_stream == with_strq) { 838 stcb->asoc.ss_data.last_out_stream = strq; 839 } 840 } 841 strq->ss_params.fb.next_spoke.tqe_next = NULL; 842 strq->ss_params.fb.next_spoke.tqe_prev = NULL; 843 return; 844 } 845 846 static void 847 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc, 848 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp, 849 int holds_lock) 850 { 851 if (holds_lock == 0) { 852 SCTP_TCB_SEND_LOCK(stcb); 853 } 854 if (sp && (sp->ss_next.tqe_next == NULL) && 855 (sp->ss_next.tqe_prev == NULL)) { 856 TAILQ_INSERT_TAIL(&asoc->ss_data.out.list, sp, ss_next); 857 } 858 if (holds_lock == 0) { 859 SCTP_TCB_SEND_UNLOCK(stcb); 860 } 861 return; 862 } 863 864 static int 865 sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc) 866 { 867 if (TAILQ_EMPTY(&asoc->ss_data.out.list)) { 868 return (1); 869 } else { 870 return (0); 871 } 872 } 873 874 static void 875 sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc, 876 struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp, 877 int holds_lock) 878 { 879 if (holds_lock == 0) { 880 SCTP_TCB_SEND_LOCK(stcb); 881 } 882 if (sp && 883 ((sp->ss_next.tqe_next != NULL) || 884 (sp->ss_next.tqe_prev != NULL))) { 885 TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next); 886 sp->ss_next.tqe_next = NULL; 887 sp->ss_next.tqe_prev = NULL; 888 } 889 if (holds_lock == 0) { 890 SCTP_TCB_SEND_UNLOCK(stcb); 891 } 892 return; 893 } 894 895 896 static struct sctp_stream_out * 897 sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net, 898 struct sctp_association *asoc) 899 { 900 struct sctp_stream_out *strq; 901 struct sctp_stream_queue_pending *sp; 902 903 sp = TAILQ_FIRST(&asoc->ss_data.out.list); 904 default_again: 905 if (sp != NULL) { 906 strq = &asoc->strmout[sp->sid]; 907 } else { 908 strq = NULL; 909 } 910 911 /* 912 * If CMT is off, we must validate that the stream in question has 913 * the first item pointed towards are network destination requested 914 * by the caller. Note that if we turn out to be locked to a stream 915 * (assigning TSN's then we must stop, since we cannot look for 916 * another stream with data to send to that destination). In CMT's 917 * case, by skipping this check, we will send one data packet 918 * towards the requested net. 919 */ 920 if (net != NULL && strq != NULL && 921 SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) { 922 if (TAILQ_FIRST(&strq->outqueue) && 923 TAILQ_FIRST(&strq->outqueue)->net != NULL && 924 TAILQ_FIRST(&strq->outqueue)->net != net) { 925 sp = TAILQ_NEXT(sp, ss_next); 926 goto default_again; 927 } 928 } 929 return (strq); 930 } 931 932 const struct sctp_ss_functions sctp_ss_functions[] = { 933 /* SCTP_SS_DEFAULT */ 934 { 935 .sctp_ss_init = sctp_ss_default_init, 936 .sctp_ss_clear = sctp_ss_default_clear, 937 .sctp_ss_init_stream = sctp_ss_default_init_stream, 938 .sctp_ss_add_to_stream = sctp_ss_default_add, 939 .sctp_ss_is_empty = sctp_ss_default_is_empty, 940 .sctp_ss_remove_from_stream = sctp_ss_default_remove, 941 .sctp_ss_select_stream = sctp_ss_default_select, 942 .sctp_ss_scheduled = sctp_ss_default_scheduled, 943 .sctp_ss_packet_done = sctp_ss_default_packet_done, 944 .sctp_ss_get_value = sctp_ss_default_get_value, 945 .sctp_ss_set_value = sctp_ss_default_set_value, 946 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete 947 }, 948 /* SCTP_SS_ROUND_ROBIN */ 949 { 950 .sctp_ss_init = sctp_ss_default_init, 951 .sctp_ss_clear = sctp_ss_default_clear, 952 .sctp_ss_init_stream = sctp_ss_default_init_stream, 953 .sctp_ss_add_to_stream = sctp_ss_rr_add, 954 .sctp_ss_is_empty = sctp_ss_default_is_empty, 955 .sctp_ss_remove_from_stream = sctp_ss_default_remove, 956 .sctp_ss_select_stream = sctp_ss_default_select, 957 .sctp_ss_scheduled = sctp_ss_default_scheduled, 958 .sctp_ss_packet_done = sctp_ss_default_packet_done, 959 .sctp_ss_get_value = sctp_ss_default_get_value, 960 .sctp_ss_set_value = sctp_ss_default_set_value, 961 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete 962 }, 963 /* SCTP_SS_ROUND_ROBIN_PACKET */ 964 { 965 .sctp_ss_init = sctp_ss_default_init, 966 .sctp_ss_clear = sctp_ss_default_clear, 967 .sctp_ss_init_stream = sctp_ss_default_init_stream, 968 .sctp_ss_add_to_stream = sctp_ss_rr_add, 969 .sctp_ss_is_empty = sctp_ss_default_is_empty, 970 .sctp_ss_remove_from_stream = sctp_ss_default_remove, 971 .sctp_ss_select_stream = sctp_ss_rrp_select, 972 .sctp_ss_scheduled = sctp_ss_default_scheduled, 973 .sctp_ss_packet_done = sctp_ss_rrp_packet_done, 974 .sctp_ss_get_value = sctp_ss_default_get_value, 975 .sctp_ss_set_value = sctp_ss_default_set_value, 976 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete 977 }, 978 /* SCTP_SS_PRIORITY */ 979 { 980 .sctp_ss_init = sctp_ss_default_init, 981 .sctp_ss_clear = sctp_ss_prio_clear, 982 .sctp_ss_init_stream = sctp_ss_prio_init_stream, 983 .sctp_ss_add_to_stream = sctp_ss_prio_add, 984 .sctp_ss_is_empty = sctp_ss_default_is_empty, 985 .sctp_ss_remove_from_stream = sctp_ss_prio_remove, 986 .sctp_ss_select_stream = sctp_ss_prio_select, 987 .sctp_ss_scheduled = sctp_ss_default_scheduled, 988 .sctp_ss_packet_done = sctp_ss_default_packet_done, 989 .sctp_ss_get_value = sctp_ss_prio_get_value, 990 .sctp_ss_set_value = sctp_ss_prio_set_value, 991 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete 992 }, 993 /* SCTP_SS_FAIR_BANDWITH */ 994 { 995 .sctp_ss_init = sctp_ss_default_init, 996 .sctp_ss_clear = sctp_ss_fb_clear, 997 .sctp_ss_init_stream = sctp_ss_fb_init_stream, 998 .sctp_ss_add_to_stream = sctp_ss_fb_add, 999 .sctp_ss_is_empty = sctp_ss_default_is_empty, 1000 .sctp_ss_remove_from_stream = sctp_ss_fb_remove, 1001 .sctp_ss_select_stream = sctp_ss_fb_select, 1002 .sctp_ss_scheduled = sctp_ss_fb_scheduled, 1003 .sctp_ss_packet_done = sctp_ss_default_packet_done, 1004 .sctp_ss_get_value = sctp_ss_default_get_value, 1005 .sctp_ss_set_value = sctp_ss_default_set_value, 1006 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete 1007 }, 1008 /* SCTP_SS_FIRST_COME */ 1009 { 1010 .sctp_ss_init = sctp_ss_fcfs_init, 1011 .sctp_ss_clear = sctp_ss_fcfs_clear, 1012 .sctp_ss_init_stream = sctp_ss_fcfs_init_stream, 1013 .sctp_ss_add_to_stream = sctp_ss_fcfs_add, 1014 .sctp_ss_is_empty = sctp_ss_fcfs_is_empty, 1015 .sctp_ss_remove_from_stream = sctp_ss_fcfs_remove, 1016 .sctp_ss_select_stream = sctp_ss_fcfs_select, 1017 .sctp_ss_scheduled = sctp_ss_default_scheduled, 1018 .sctp_ss_packet_done = sctp_ss_default_packet_done, 1019 .sctp_ss_get_value = sctp_ss_default_get_value, 1020 .sctp_ss_set_value = sctp_ss_default_set_value, 1021 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete 1022 } 1023 }; 1024