]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet/sctp_ss_functions.c
Merge branch 'releng/11.3' into releng-CDN/11.3
[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         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         strqt = asoc->ss_data.last_out_stream;
519 prio_again:
520         /* Find the next stream to use */
521         if (strqt == NULL) {
522                 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
523         } else {
524                 strqn = TAILQ_NEXT(strqt, ss_params.prio.next_spoke);
525                 if (strqn != NULL &&
526                     strqn->ss_params.prio.priority == strqt->ss_params.prio.priority) {
527                         strq = strqn;
528                 } else {
529                         strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
530                 }
531         }
532
533         /*
534          * If CMT is off, we must validate that the stream in question has
535          * the first item pointed towards are network destination requested
536          * by the caller. Note that if we turn out to be locked to a stream
537          * (assigning TSN's then we must stop, since we cannot look for
538          * another stream with data to send to that destination). In CMT's
539          * case, by skipping this check, we will send one data packet
540          * towards the requested net.
541          */
542         if (net != NULL && strq != NULL &&
543             SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
544                 if (TAILQ_FIRST(&strq->outqueue) &&
545                     TAILQ_FIRST(&strq->outqueue)->net != NULL &&
546                     TAILQ_FIRST(&strq->outqueue)->net != net) {
547                         if (strq == asoc->ss_data.last_out_stream) {
548                                 return (NULL);
549                         } else {
550                                 strqt = strq;
551                                 goto prio_again;
552                         }
553                 }
554         }
555         return (strq);
556 }
557
558 static int
559 sctp_ss_prio_get_value(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc SCTP_UNUSED,
560     struct sctp_stream_out *strq, uint16_t *value)
561 {
562         if (strq == NULL) {
563                 return (-1);
564         }
565         *value = strq->ss_params.prio.priority;
566         return (1);
567 }
568
569 static int
570 sctp_ss_prio_set_value(struct sctp_tcb *stcb, struct sctp_association *asoc,
571     struct sctp_stream_out *strq, uint16_t value)
572 {
573         if (strq == NULL) {
574                 return (-1);
575         }
576         strq->ss_params.prio.priority = value;
577         sctp_ss_prio_remove(stcb, asoc, strq, NULL, 1);
578         sctp_ss_prio_add(stcb, asoc, strq, NULL, 1);
579         return (1);
580 }
581
582 /*
583  * Fair bandwidth algorithm.
584  * Maintains an equal troughput per stream.
585  */
586 static void
587 sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
588     int clear_values, int holds_lock)
589 {
590         if (holds_lock == 0) {
591                 SCTP_TCB_SEND_LOCK(stcb);
592         }
593         while (!TAILQ_EMPTY(&asoc->ss_data.out.wheel)) {
594                 struct sctp_stream_out *strq;
595
596                 strq = TAILQ_FIRST(&asoc->ss_data.out.wheel);
597                 if (clear_values) {
598                         strq->ss_params.fb.rounds = -1;
599                 }
600                 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
601                 strq->ss_params.fb.next_spoke.tqe_next = NULL;
602                 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
603         }
604         asoc->ss_data.last_out_stream = NULL;
605         if (holds_lock == 0) {
606                 SCTP_TCB_SEND_UNLOCK(stcb);
607         }
608         return;
609 }
610
611 static void
612 sctp_ss_fb_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
613 {
614         if (with_strq != NULL) {
615                 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
616                         stcb->asoc.ss_data.locked_on_sending = strq;
617                 }
618                 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
619                         stcb->asoc.ss_data.last_out_stream = strq;
620                 }
621         }
622         strq->ss_params.fb.next_spoke.tqe_next = NULL;
623         strq->ss_params.fb.next_spoke.tqe_prev = NULL;
624         if (with_strq != NULL) {
625                 strq->ss_params.fb.rounds = with_strq->ss_params.fb.rounds;
626         } else {
627                 strq->ss_params.fb.rounds = -1;
628         }
629         return;
630 }
631
632 static void
633 sctp_ss_fb_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
634     struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
635     int holds_lock)
636 {
637         if (holds_lock == 0) {
638                 SCTP_TCB_SEND_LOCK(stcb);
639         }
640         if (!TAILQ_EMPTY(&strq->outqueue) &&
641             (strq->ss_params.fb.next_spoke.tqe_next == NULL) &&
642             (strq->ss_params.fb.next_spoke.tqe_prev == NULL)) {
643                 if (strq->ss_params.fb.rounds < 0)
644                         strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
645                 TAILQ_INSERT_TAIL(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
646         }
647         if (holds_lock == 0) {
648                 SCTP_TCB_SEND_UNLOCK(stcb);
649         }
650         return;
651 }
652
653 static void
654 sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
655     struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp SCTP_UNUSED,
656     int holds_lock)
657 {
658         if (holds_lock == 0) {
659                 SCTP_TCB_SEND_LOCK(stcb);
660         }
661         /*
662          * Remove from wheel if stream queue is empty and actually is on the
663          * wheel
664          */
665         if (TAILQ_EMPTY(&strq->outqueue) &&
666             (strq->ss_params.fb.next_spoke.tqe_next != NULL ||
667             strq->ss_params.fb.next_spoke.tqe_prev != NULL)) {
668                 if (asoc->ss_data.last_out_stream == strq) {
669                         asoc->ss_data.last_out_stream = TAILQ_PREV(asoc->ss_data.last_out_stream, sctpwheel_listhead,
670                             ss_params.fb.next_spoke);
671                         if (asoc->ss_data.last_out_stream == NULL) {
672                                 asoc->ss_data.last_out_stream = TAILQ_LAST(&asoc->ss_data.out.wheel,
673                                     sctpwheel_listhead);
674                         }
675                         if (asoc->ss_data.last_out_stream == strq) {
676                                 asoc->ss_data.last_out_stream = NULL;
677                         }
678                 }
679                 TAILQ_REMOVE(&asoc->ss_data.out.wheel, strq, ss_params.fb.next_spoke);
680                 strq->ss_params.fb.next_spoke.tqe_next = NULL;
681                 strq->ss_params.fb.next_spoke.tqe_prev = NULL;
682         }
683         if (holds_lock == 0) {
684                 SCTP_TCB_SEND_UNLOCK(stcb);
685         }
686         return;
687 }
688
689 static struct sctp_stream_out *
690 sctp_ss_fb_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
691     struct sctp_association *asoc)
692 {
693         struct sctp_stream_out *strq = NULL, *strqt;
694
695         if (asoc->ss_data.last_out_stream == NULL ||
696             TAILQ_FIRST(&asoc->ss_data.out.wheel) == TAILQ_LAST(&asoc->ss_data.out.wheel, sctpwheel_listhead)) {
697                 strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
698         } else {
699                 strqt = TAILQ_NEXT(asoc->ss_data.last_out_stream, ss_params.fb.next_spoke);
700         }
701         do {
702                 if ((strqt != NULL) &&
703                     ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) > 0) ||
704                     (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0 &&
705                     (net == NULL || (TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net == NULL) ||
706                     (net != NULL && TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net != NULL &&
707                     TAILQ_FIRST(&strqt->outqueue)->net == net))))) {
708                         if ((strqt->ss_params.fb.rounds >= 0) && (strq == NULL ||
709                             strqt->ss_params.fb.rounds < strq->ss_params.fb.rounds)) {
710                                 strq = strqt;
711                         }
712                 }
713                 if (strqt != NULL) {
714                         strqt = TAILQ_NEXT(strqt, ss_params.fb.next_spoke);
715                 } else {
716                         strqt = TAILQ_FIRST(&asoc->ss_data.out.wheel);
717                 }
718         } while (strqt != strq);
719         return (strq);
720 }
721
722 static void
723 sctp_ss_fb_scheduled(struct sctp_tcb *stcb, struct sctp_nets *net SCTP_UNUSED,
724     struct sctp_association *asoc, struct sctp_stream_out *strq,
725     int moved_how_much SCTP_UNUSED)
726 {
727         struct sctp_stream_queue_pending *sp;
728         struct sctp_stream_out *strqt;
729         int subtract;
730
731         if (stcb->asoc.idata_supported == 0) {
732                 sp = TAILQ_FIRST(&strq->outqueue);
733                 if ((sp != NULL) && (sp->some_taken == 1)) {
734                         stcb->asoc.ss_data.locked_on_sending = strq;
735                 } else {
736                         stcb->asoc.ss_data.locked_on_sending = NULL;
737                 }
738         } else {
739                 stcb->asoc.ss_data.locked_on_sending = NULL;
740         }
741         subtract = strq->ss_params.fb.rounds;
742         TAILQ_FOREACH(strqt, &asoc->ss_data.out.wheel, ss_params.fb.next_spoke) {
743                 strqt->ss_params.fb.rounds -= subtract;
744                 if (strqt->ss_params.fb.rounds < 0)
745                         strqt->ss_params.fb.rounds = 0;
746         }
747         if (TAILQ_FIRST(&strq->outqueue)) {
748                 strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length;
749         } else {
750                 strq->ss_params.fb.rounds = -1;
751         }
752         asoc->ss_data.last_out_stream = strq;
753         return;
754 }
755
756 /*
757  * First-come, first-serve algorithm.
758  * Maintains the order provided by the application.
759  */
760 static void
761 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
762     struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp,
763     int holds_lock);
764
765 static void
766 sctp_ss_fcfs_init(struct sctp_tcb *stcb, struct sctp_association *asoc,
767     int holds_lock)
768 {
769         uint32_t x, n = 0, add_more = 1;
770         struct sctp_stream_queue_pending *sp;
771         uint16_t i;
772
773         if (holds_lock == 0) {
774                 SCTP_TCB_SEND_LOCK(stcb);
775         }
776         TAILQ_INIT(&asoc->ss_data.out.list);
777         /*
778          * If there is data in the stream queues already, the scheduler of
779          * an existing association has been changed. We can only cycle
780          * through the stream queues and add everything to the FCFS queue.
781          */
782         while (add_more) {
783                 add_more = 0;
784                 for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
785                         sp = TAILQ_FIRST(&stcb->asoc.strmout[i].outqueue);
786                         x = 0;
787                         /* Find n. message in current stream queue */
788                         while (sp != NULL && x < n) {
789                                 sp = TAILQ_NEXT(sp, next);
790                                 x++;
791                         }
792                         if (sp != NULL) {
793                                 sctp_ss_fcfs_add(stcb, &stcb->asoc, &stcb->asoc.strmout[i], sp, 1);
794                                 add_more = 1;
795                         }
796                 }
797                 n++;
798         }
799         if (holds_lock == 0) {
800                 SCTP_TCB_SEND_UNLOCK(stcb);
801         }
802         return;
803 }
804
805 static void
806 sctp_ss_fcfs_clear(struct sctp_tcb *stcb, struct sctp_association *asoc,
807     int clear_values, int holds_lock)
808 {
809         struct sctp_stream_queue_pending *sp;
810
811         if (clear_values) {
812                 if (holds_lock == 0) {
813                         SCTP_TCB_SEND_LOCK(stcb);
814                 }
815                 while (!TAILQ_EMPTY(&asoc->ss_data.out.list)) {
816                         sp = TAILQ_FIRST(&asoc->ss_data.out.list);
817                         TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
818                         sp->ss_next.tqe_next = NULL;
819                         sp->ss_next.tqe_prev = NULL;
820                 }
821                 if (holds_lock == 0) {
822                         SCTP_TCB_SEND_UNLOCK(stcb);
823                 }
824         }
825         return;
826 }
827
828 static void
829 sctp_ss_fcfs_init_stream(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_out *with_strq)
830 {
831         if (with_strq != NULL) {
832                 if (stcb->asoc.ss_data.locked_on_sending == with_strq) {
833                         stcb->asoc.ss_data.locked_on_sending = strq;
834                 }
835                 if (stcb->asoc.ss_data.last_out_stream == with_strq) {
836                         stcb->asoc.ss_data.last_out_stream = strq;
837                 }
838         }
839         strq->ss_params.fb.next_spoke.tqe_next = NULL;
840         strq->ss_params.fb.next_spoke.tqe_prev = NULL;
841         return;
842 }
843
844 static void
845 sctp_ss_fcfs_add(struct sctp_tcb *stcb, struct sctp_association *asoc,
846     struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
847     int holds_lock)
848 {
849         if (holds_lock == 0) {
850                 SCTP_TCB_SEND_LOCK(stcb);
851         }
852         if (sp && (sp->ss_next.tqe_next == NULL) &&
853             (sp->ss_next.tqe_prev == NULL)) {
854                 TAILQ_INSERT_TAIL(&asoc->ss_data.out.list, sp, ss_next);
855         }
856         if (holds_lock == 0) {
857                 SCTP_TCB_SEND_UNLOCK(stcb);
858         }
859         return;
860 }
861
862 static int
863 sctp_ss_fcfs_is_empty(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_association *asoc)
864 {
865         if (TAILQ_EMPTY(&asoc->ss_data.out.list)) {
866                 return (1);
867         } else {
868                 return (0);
869         }
870 }
871
872 static void
873 sctp_ss_fcfs_remove(struct sctp_tcb *stcb, struct sctp_association *asoc,
874     struct sctp_stream_out *strq SCTP_UNUSED, struct sctp_stream_queue_pending *sp,
875     int holds_lock)
876 {
877         if (holds_lock == 0) {
878                 SCTP_TCB_SEND_LOCK(stcb);
879         }
880         if (sp &&
881             ((sp->ss_next.tqe_next != NULL) ||
882             (sp->ss_next.tqe_prev != NULL))) {
883                 TAILQ_REMOVE(&asoc->ss_data.out.list, sp, ss_next);
884                 sp->ss_next.tqe_next = NULL;
885                 sp->ss_next.tqe_prev = NULL;
886         }
887         if (holds_lock == 0) {
888                 SCTP_TCB_SEND_UNLOCK(stcb);
889         }
890         return;
891 }
892
893
894 static struct sctp_stream_out *
895 sctp_ss_fcfs_select(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_nets *net,
896     struct sctp_association *asoc)
897 {
898         struct sctp_stream_out *strq;
899         struct sctp_stream_queue_pending *sp;
900
901         sp = TAILQ_FIRST(&asoc->ss_data.out.list);
902 default_again:
903         if (sp != NULL) {
904                 strq = &asoc->strmout[sp->sid];
905         } else {
906                 strq = NULL;
907         }
908
909         /*
910          * If CMT is off, we must validate that the stream in question has
911          * the first item pointed towards are network destination requested
912          * by the caller. Note that if we turn out to be locked to a stream
913          * (assigning TSN's then we must stop, since we cannot look for
914          * another stream with data to send to that destination). In CMT's
915          * case, by skipping this check, we will send one data packet
916          * towards the requested net.
917          */
918         if (net != NULL && strq != NULL &&
919             SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) {
920                 if (TAILQ_FIRST(&strq->outqueue) &&
921                     TAILQ_FIRST(&strq->outqueue)->net != NULL &&
922                     TAILQ_FIRST(&strq->outqueue)->net != net) {
923                         sp = TAILQ_NEXT(sp, ss_next);
924                         goto default_again;
925                 }
926         }
927         return (strq);
928 }
929
930 const struct sctp_ss_functions sctp_ss_functions[] = {
931 /* SCTP_SS_DEFAULT */
932         {
933                 .sctp_ss_init = sctp_ss_default_init,
934                 .sctp_ss_clear = sctp_ss_default_clear,
935                 .sctp_ss_init_stream = sctp_ss_default_init_stream,
936                 .sctp_ss_add_to_stream = sctp_ss_default_add,
937                 .sctp_ss_is_empty = sctp_ss_default_is_empty,
938                 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
939                 .sctp_ss_select_stream = sctp_ss_default_select,
940                 .sctp_ss_scheduled = sctp_ss_default_scheduled,
941                 .sctp_ss_packet_done = sctp_ss_default_packet_done,
942                 .sctp_ss_get_value = sctp_ss_default_get_value,
943                 .sctp_ss_set_value = sctp_ss_default_set_value,
944                 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
945         },
946 /* SCTP_SS_ROUND_ROBIN */
947         {
948                 .sctp_ss_init = sctp_ss_default_init,
949                 .sctp_ss_clear = sctp_ss_default_clear,
950                 .sctp_ss_init_stream = sctp_ss_default_init_stream,
951                 .sctp_ss_add_to_stream = sctp_ss_rr_add,
952                 .sctp_ss_is_empty = sctp_ss_default_is_empty,
953                 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
954                 .sctp_ss_select_stream = sctp_ss_default_select,
955                 .sctp_ss_scheduled = sctp_ss_default_scheduled,
956                 .sctp_ss_packet_done = sctp_ss_default_packet_done,
957                 .sctp_ss_get_value = sctp_ss_default_get_value,
958                 .sctp_ss_set_value = sctp_ss_default_set_value,
959                 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
960         },
961 /* SCTP_SS_ROUND_ROBIN_PACKET */
962         {
963                 .sctp_ss_init = sctp_ss_default_init,
964                 .sctp_ss_clear = sctp_ss_default_clear,
965                 .sctp_ss_init_stream = sctp_ss_default_init_stream,
966                 .sctp_ss_add_to_stream = sctp_ss_rr_add,
967                 .sctp_ss_is_empty = sctp_ss_default_is_empty,
968                 .sctp_ss_remove_from_stream = sctp_ss_default_remove,
969                 .sctp_ss_select_stream = sctp_ss_rrp_select,
970                 .sctp_ss_scheduled = sctp_ss_default_scheduled,
971                 .sctp_ss_packet_done = sctp_ss_rrp_packet_done,
972                 .sctp_ss_get_value = sctp_ss_default_get_value,
973                 .sctp_ss_set_value = sctp_ss_default_set_value,
974                 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
975         },
976 /* SCTP_SS_PRIORITY */
977         {
978                 .sctp_ss_init = sctp_ss_default_init,
979                 .sctp_ss_clear = sctp_ss_prio_clear,
980                 .sctp_ss_init_stream = sctp_ss_prio_init_stream,
981                 .sctp_ss_add_to_stream = sctp_ss_prio_add,
982                 .sctp_ss_is_empty = sctp_ss_default_is_empty,
983                 .sctp_ss_remove_from_stream = sctp_ss_prio_remove,
984                 .sctp_ss_select_stream = sctp_ss_prio_select,
985                 .sctp_ss_scheduled = sctp_ss_default_scheduled,
986                 .sctp_ss_packet_done = sctp_ss_default_packet_done,
987                 .sctp_ss_get_value = sctp_ss_prio_get_value,
988                 .sctp_ss_set_value = sctp_ss_prio_set_value,
989                 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
990         },
991 /* SCTP_SS_FAIR_BANDWITH */
992         {
993                 .sctp_ss_init = sctp_ss_default_init,
994                 .sctp_ss_clear = sctp_ss_fb_clear,
995                 .sctp_ss_init_stream = sctp_ss_fb_init_stream,
996                 .sctp_ss_add_to_stream = sctp_ss_fb_add,
997                 .sctp_ss_is_empty = sctp_ss_default_is_empty,
998                 .sctp_ss_remove_from_stream = sctp_ss_fb_remove,
999                 .sctp_ss_select_stream = sctp_ss_fb_select,
1000                 .sctp_ss_scheduled = sctp_ss_fb_scheduled,
1001                 .sctp_ss_packet_done = sctp_ss_default_packet_done,
1002                 .sctp_ss_get_value = sctp_ss_default_get_value,
1003                 .sctp_ss_set_value = sctp_ss_default_set_value,
1004                 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
1005         },
1006 /* SCTP_SS_FIRST_COME */
1007         {
1008                 .sctp_ss_init = sctp_ss_fcfs_init,
1009                 .sctp_ss_clear = sctp_ss_fcfs_clear,
1010                 .sctp_ss_init_stream = sctp_ss_fcfs_init_stream,
1011                 .sctp_ss_add_to_stream = sctp_ss_fcfs_add,
1012                 .sctp_ss_is_empty = sctp_ss_fcfs_is_empty,
1013                 .sctp_ss_remove_from_stream = sctp_ss_fcfs_remove,
1014                 .sctp_ss_select_stream = sctp_ss_fcfs_select,
1015                 .sctp_ss_scheduled = sctp_ss_default_scheduled,
1016                 .sctp_ss_packet_done = sctp_ss_default_packet_done,
1017                 .sctp_ss_get_value = sctp_ss_default_get_value,
1018                 .sctp_ss_set_value = sctp_ss_default_set_value,
1019                 .sctp_ss_is_user_msgs_incomplete = sctp_ss_default_is_user_msgs_incomplete
1020         }
1021 };