sctp_ss_functions.c 34 KB

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