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