Coverage Report

Created: 2026-02-14 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
};