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