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