]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet/sctp_ss_functions.c
Report the correct length when using the IPPROTO_SCTP level
[FreeBSD/FreeBSD.git] / sys / netinet / sctp_ss_functions.c
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$");
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 };