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