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