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