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