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