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