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