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