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