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