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