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