/src/usrsctp/usrsctplib/netinet/sctp_output.c
Line | Count | Source |
1 | | /*- |
2 | | * SPDX-License-Identifier: BSD-3-Clause |
3 | | * |
4 | | * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. |
5 | | * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. |
6 | | * Copyright (c) 2008-2012, by Michael Tuexen. 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 | | * c) Neither the name of Cisco Systems, Inc. nor the names of its |
19 | | * contributors may be used to endorse or promote products derived |
20 | | * from this software without specific prior written permission. |
21 | | * |
22 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
23 | | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
24 | | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
26 | | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
27 | | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
28 | | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
29 | | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
30 | | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
31 | | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
32 | | * THE POSSIBILITY OF SUCH DAMAGE. |
33 | | */ |
34 | | |
35 | | #include <netinet/sctp_os.h> |
36 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
37 | | #include <sys/proc.h> |
38 | | #endif |
39 | | #include <netinet/sctp_var.h> |
40 | | #include <netinet/sctp_sysctl.h> |
41 | | #include <netinet/sctp_header.h> |
42 | | #include <netinet/sctp_pcb.h> |
43 | | #include <netinet/sctputil.h> |
44 | | #include <netinet/sctp_output.h> |
45 | | #include <netinet/sctp_uio.h> |
46 | | #include <netinet/sctputil.h> |
47 | | #include <netinet/sctp_auth.h> |
48 | | #include <netinet/sctp_timer.h> |
49 | | #include <netinet/sctp_asconf.h> |
50 | | #include <netinet/sctp_indata.h> |
51 | | #include <netinet/sctp_bsd_addr.h> |
52 | | #include <netinet/sctp_input.h> |
53 | | #include <netinet/sctp_crc32.h> |
54 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
55 | | #include <netinet/sctp_kdtrace.h> |
56 | | #endif |
57 | | #if defined(__linux__) |
58 | | #define __FAVOR_BSD /* (on Ubuntu at least) enables UDP header field names like BSD in RFC 768 */ |
59 | | #endif |
60 | | #if defined(INET) || defined(INET6) |
61 | | #if !defined(_WIN32) |
62 | | #include <netinet/udp.h> |
63 | | #endif |
64 | | #endif |
65 | | #if !defined(__Userspace__) |
66 | | #if defined(__APPLE__) |
67 | | #include <netinet/in.h> |
68 | | #endif |
69 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
70 | | #include <netinet/udp_var.h> |
71 | | #include <machine/in_cksum.h> |
72 | | #endif |
73 | | #endif |
74 | | #if defined(__Userspace__) && defined(INET6) |
75 | | #include <netinet6/sctp6_var.h> |
76 | | #endif |
77 | | #if defined(__APPLE__) && !defined(__Userspace__) |
78 | | #if !(defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD)) |
79 | | #define SCTP_MAX_LINKHDR 16 |
80 | | #endif |
81 | | #endif |
82 | | |
83 | | #define SCTP_MAX_GAPS_INARRAY 4 |
84 | | struct sack_track { |
85 | | uint8_t right_edge; /* mergable on the right edge */ |
86 | | uint8_t left_edge; /* mergable on the left edge */ |
87 | | uint8_t num_entries; |
88 | | uint8_t spare; |
89 | | struct sctp_gap_ack_block gaps[SCTP_MAX_GAPS_INARRAY]; |
90 | | }; |
91 | | |
92 | | const struct sack_track sack_array[256] = { |
93 | | {0, 0, 0, 0, /* 0x00 */ |
94 | | {{0, 0}, |
95 | | {0, 0}, |
96 | | {0, 0}, |
97 | | {0, 0} |
98 | | } |
99 | | }, |
100 | | {1, 0, 1, 0, /* 0x01 */ |
101 | | {{0, 0}, |
102 | | {0, 0}, |
103 | | {0, 0}, |
104 | | {0, 0} |
105 | | } |
106 | | }, |
107 | | {0, 0, 1, 0, /* 0x02 */ |
108 | | {{1, 1}, |
109 | | {0, 0}, |
110 | | {0, 0}, |
111 | | {0, 0} |
112 | | } |
113 | | }, |
114 | | {1, 0, 1, 0, /* 0x03 */ |
115 | | {{0, 1}, |
116 | | {0, 0}, |
117 | | {0, 0}, |
118 | | {0, 0} |
119 | | } |
120 | | }, |
121 | | {0, 0, 1, 0, /* 0x04 */ |
122 | | {{2, 2}, |
123 | | {0, 0}, |
124 | | {0, 0}, |
125 | | {0, 0} |
126 | | } |
127 | | }, |
128 | | {1, 0, 2, 0, /* 0x05 */ |
129 | | {{0, 0}, |
130 | | {2, 2}, |
131 | | {0, 0}, |
132 | | {0, 0} |
133 | | } |
134 | | }, |
135 | | {0, 0, 1, 0, /* 0x06 */ |
136 | | {{1, 2}, |
137 | | {0, 0}, |
138 | | {0, 0}, |
139 | | {0, 0} |
140 | | } |
141 | | }, |
142 | | {1, 0, 1, 0, /* 0x07 */ |
143 | | {{0, 2}, |
144 | | {0, 0}, |
145 | | {0, 0}, |
146 | | {0, 0} |
147 | | } |
148 | | }, |
149 | | {0, 0, 1, 0, /* 0x08 */ |
150 | | {{3, 3}, |
151 | | {0, 0}, |
152 | | {0, 0}, |
153 | | {0, 0} |
154 | | } |
155 | | }, |
156 | | {1, 0, 2, 0, /* 0x09 */ |
157 | | {{0, 0}, |
158 | | {3, 3}, |
159 | | {0, 0}, |
160 | | {0, 0} |
161 | | } |
162 | | }, |
163 | | {0, 0, 2, 0, /* 0x0a */ |
164 | | {{1, 1}, |
165 | | {3, 3}, |
166 | | {0, 0}, |
167 | | {0, 0} |
168 | | } |
169 | | }, |
170 | | {1, 0, 2, 0, /* 0x0b */ |
171 | | {{0, 1}, |
172 | | {3, 3}, |
173 | | {0, 0}, |
174 | | {0, 0} |
175 | | } |
176 | | }, |
177 | | {0, 0, 1, 0, /* 0x0c */ |
178 | | {{2, 3}, |
179 | | {0, 0}, |
180 | | {0, 0}, |
181 | | {0, 0} |
182 | | } |
183 | | }, |
184 | | {1, 0, 2, 0, /* 0x0d */ |
185 | | {{0, 0}, |
186 | | {2, 3}, |
187 | | {0, 0}, |
188 | | {0, 0} |
189 | | } |
190 | | }, |
191 | | {0, 0, 1, 0, /* 0x0e */ |
192 | | {{1, 3}, |
193 | | {0, 0}, |
194 | | {0, 0}, |
195 | | {0, 0} |
196 | | } |
197 | | }, |
198 | | {1, 0, 1, 0, /* 0x0f */ |
199 | | {{0, 3}, |
200 | | {0, 0}, |
201 | | {0, 0}, |
202 | | {0, 0} |
203 | | } |
204 | | }, |
205 | | {0, 0, 1, 0, /* 0x10 */ |
206 | | {{4, 4}, |
207 | | {0, 0}, |
208 | | {0, 0}, |
209 | | {0, 0} |
210 | | } |
211 | | }, |
212 | | {1, 0, 2, 0, /* 0x11 */ |
213 | | {{0, 0}, |
214 | | {4, 4}, |
215 | | {0, 0}, |
216 | | {0, 0} |
217 | | } |
218 | | }, |
219 | | {0, 0, 2, 0, /* 0x12 */ |
220 | | {{1, 1}, |
221 | | {4, 4}, |
222 | | {0, 0}, |
223 | | {0, 0} |
224 | | } |
225 | | }, |
226 | | {1, 0, 2, 0, /* 0x13 */ |
227 | | {{0, 1}, |
228 | | {4, 4}, |
229 | | {0, 0}, |
230 | | {0, 0} |
231 | | } |
232 | | }, |
233 | | {0, 0, 2, 0, /* 0x14 */ |
234 | | {{2, 2}, |
235 | | {4, 4}, |
236 | | {0, 0}, |
237 | | {0, 0} |
238 | | } |
239 | | }, |
240 | | {1, 0, 3, 0, /* 0x15 */ |
241 | | {{0, 0}, |
242 | | {2, 2}, |
243 | | {4, 4}, |
244 | | {0, 0} |
245 | | } |
246 | | }, |
247 | | {0, 0, 2, 0, /* 0x16 */ |
248 | | {{1, 2}, |
249 | | {4, 4}, |
250 | | {0, 0}, |
251 | | {0, 0} |
252 | | } |
253 | | }, |
254 | | {1, 0, 2, 0, /* 0x17 */ |
255 | | {{0, 2}, |
256 | | {4, 4}, |
257 | | {0, 0}, |
258 | | {0, 0} |
259 | | } |
260 | | }, |
261 | | {0, 0, 1, 0, /* 0x18 */ |
262 | | {{3, 4}, |
263 | | {0, 0}, |
264 | | {0, 0}, |
265 | | {0, 0} |
266 | | } |
267 | | }, |
268 | | {1, 0, 2, 0, /* 0x19 */ |
269 | | {{0, 0}, |
270 | | {3, 4}, |
271 | | {0, 0}, |
272 | | {0, 0} |
273 | | } |
274 | | }, |
275 | | {0, 0, 2, 0, /* 0x1a */ |
276 | | {{1, 1}, |
277 | | {3, 4}, |
278 | | {0, 0}, |
279 | | {0, 0} |
280 | | } |
281 | | }, |
282 | | {1, 0, 2, 0, /* 0x1b */ |
283 | | {{0, 1}, |
284 | | {3, 4}, |
285 | | {0, 0}, |
286 | | {0, 0} |
287 | | } |
288 | | }, |
289 | | {0, 0, 1, 0, /* 0x1c */ |
290 | | {{2, 4}, |
291 | | {0, 0}, |
292 | | {0, 0}, |
293 | | {0, 0} |
294 | | } |
295 | | }, |
296 | | {1, 0, 2, 0, /* 0x1d */ |
297 | | {{0, 0}, |
298 | | {2, 4}, |
299 | | {0, 0}, |
300 | | {0, 0} |
301 | | } |
302 | | }, |
303 | | {0, 0, 1, 0, /* 0x1e */ |
304 | | {{1, 4}, |
305 | | {0, 0}, |
306 | | {0, 0}, |
307 | | {0, 0} |
308 | | } |
309 | | }, |
310 | | {1, 0, 1, 0, /* 0x1f */ |
311 | | {{0, 4}, |
312 | | {0, 0}, |
313 | | {0, 0}, |
314 | | {0, 0} |
315 | | } |
316 | | }, |
317 | | {0, 0, 1, 0, /* 0x20 */ |
318 | | {{5, 5}, |
319 | | {0, 0}, |
320 | | {0, 0}, |
321 | | {0, 0} |
322 | | } |
323 | | }, |
324 | | {1, 0, 2, 0, /* 0x21 */ |
325 | | {{0, 0}, |
326 | | {5, 5}, |
327 | | {0, 0}, |
328 | | {0, 0} |
329 | | } |
330 | | }, |
331 | | {0, 0, 2, 0, /* 0x22 */ |
332 | | {{1, 1}, |
333 | | {5, 5}, |
334 | | {0, 0}, |
335 | | {0, 0} |
336 | | } |
337 | | }, |
338 | | {1, 0, 2, 0, /* 0x23 */ |
339 | | {{0, 1}, |
340 | | {5, 5}, |
341 | | {0, 0}, |
342 | | {0, 0} |
343 | | } |
344 | | }, |
345 | | {0, 0, 2, 0, /* 0x24 */ |
346 | | {{2, 2}, |
347 | | {5, 5}, |
348 | | {0, 0}, |
349 | | {0, 0} |
350 | | } |
351 | | }, |
352 | | {1, 0, 3, 0, /* 0x25 */ |
353 | | {{0, 0}, |
354 | | {2, 2}, |
355 | | {5, 5}, |
356 | | {0, 0} |
357 | | } |
358 | | }, |
359 | | {0, 0, 2, 0, /* 0x26 */ |
360 | | {{1, 2}, |
361 | | {5, 5}, |
362 | | {0, 0}, |
363 | | {0, 0} |
364 | | } |
365 | | }, |
366 | | {1, 0, 2, 0, /* 0x27 */ |
367 | | {{0, 2}, |
368 | | {5, 5}, |
369 | | {0, 0}, |
370 | | {0, 0} |
371 | | } |
372 | | }, |
373 | | {0, 0, 2, 0, /* 0x28 */ |
374 | | {{3, 3}, |
375 | | {5, 5}, |
376 | | {0, 0}, |
377 | | {0, 0} |
378 | | } |
379 | | }, |
380 | | {1, 0, 3, 0, /* 0x29 */ |
381 | | {{0, 0}, |
382 | | {3, 3}, |
383 | | {5, 5}, |
384 | | {0, 0} |
385 | | } |
386 | | }, |
387 | | {0, 0, 3, 0, /* 0x2a */ |
388 | | {{1, 1}, |
389 | | {3, 3}, |
390 | | {5, 5}, |
391 | | {0, 0} |
392 | | } |
393 | | }, |
394 | | {1, 0, 3, 0, /* 0x2b */ |
395 | | {{0, 1}, |
396 | | {3, 3}, |
397 | | {5, 5}, |
398 | | {0, 0} |
399 | | } |
400 | | }, |
401 | | {0, 0, 2, 0, /* 0x2c */ |
402 | | {{2, 3}, |
403 | | {5, 5}, |
404 | | {0, 0}, |
405 | | {0, 0} |
406 | | } |
407 | | }, |
408 | | {1, 0, 3, 0, /* 0x2d */ |
409 | | {{0, 0}, |
410 | | {2, 3}, |
411 | | {5, 5}, |
412 | | {0, 0} |
413 | | } |
414 | | }, |
415 | | {0, 0, 2, 0, /* 0x2e */ |
416 | | {{1, 3}, |
417 | | {5, 5}, |
418 | | {0, 0}, |
419 | | {0, 0} |
420 | | } |
421 | | }, |
422 | | {1, 0, 2, 0, /* 0x2f */ |
423 | | {{0, 3}, |
424 | | {5, 5}, |
425 | | {0, 0}, |
426 | | {0, 0} |
427 | | } |
428 | | }, |
429 | | {0, 0, 1, 0, /* 0x30 */ |
430 | | {{4, 5}, |
431 | | {0, 0}, |
432 | | {0, 0}, |
433 | | {0, 0} |
434 | | } |
435 | | }, |
436 | | {1, 0, 2, 0, /* 0x31 */ |
437 | | {{0, 0}, |
438 | | {4, 5}, |
439 | | {0, 0}, |
440 | | {0, 0} |
441 | | } |
442 | | }, |
443 | | {0, 0, 2, 0, /* 0x32 */ |
444 | | {{1, 1}, |
445 | | {4, 5}, |
446 | | {0, 0}, |
447 | | {0, 0} |
448 | | } |
449 | | }, |
450 | | {1, 0, 2, 0, /* 0x33 */ |
451 | | {{0, 1}, |
452 | | {4, 5}, |
453 | | {0, 0}, |
454 | | {0, 0} |
455 | | } |
456 | | }, |
457 | | {0, 0, 2, 0, /* 0x34 */ |
458 | | {{2, 2}, |
459 | | {4, 5}, |
460 | | {0, 0}, |
461 | | {0, 0} |
462 | | } |
463 | | }, |
464 | | {1, 0, 3, 0, /* 0x35 */ |
465 | | {{0, 0}, |
466 | | {2, 2}, |
467 | | {4, 5}, |
468 | | {0, 0} |
469 | | } |
470 | | }, |
471 | | {0, 0, 2, 0, /* 0x36 */ |
472 | | {{1, 2}, |
473 | | {4, 5}, |
474 | | {0, 0}, |
475 | | {0, 0} |
476 | | } |
477 | | }, |
478 | | {1, 0, 2, 0, /* 0x37 */ |
479 | | {{0, 2}, |
480 | | {4, 5}, |
481 | | {0, 0}, |
482 | | {0, 0} |
483 | | } |
484 | | }, |
485 | | {0, 0, 1, 0, /* 0x38 */ |
486 | | {{3, 5}, |
487 | | {0, 0}, |
488 | | {0, 0}, |
489 | | {0, 0} |
490 | | } |
491 | | }, |
492 | | {1, 0, 2, 0, /* 0x39 */ |
493 | | {{0, 0}, |
494 | | {3, 5}, |
495 | | {0, 0}, |
496 | | {0, 0} |
497 | | } |
498 | | }, |
499 | | {0, 0, 2, 0, /* 0x3a */ |
500 | | {{1, 1}, |
501 | | {3, 5}, |
502 | | {0, 0}, |
503 | | {0, 0} |
504 | | } |
505 | | }, |
506 | | {1, 0, 2, 0, /* 0x3b */ |
507 | | {{0, 1}, |
508 | | {3, 5}, |
509 | | {0, 0}, |
510 | | {0, 0} |
511 | | } |
512 | | }, |
513 | | {0, 0, 1, 0, /* 0x3c */ |
514 | | {{2, 5}, |
515 | | {0, 0}, |
516 | | {0, 0}, |
517 | | {0, 0} |
518 | | } |
519 | | }, |
520 | | {1, 0, 2, 0, /* 0x3d */ |
521 | | {{0, 0}, |
522 | | {2, 5}, |
523 | | {0, 0}, |
524 | | {0, 0} |
525 | | } |
526 | | }, |
527 | | {0, 0, 1, 0, /* 0x3e */ |
528 | | {{1, 5}, |
529 | | {0, 0}, |
530 | | {0, 0}, |
531 | | {0, 0} |
532 | | } |
533 | | }, |
534 | | {1, 0, 1, 0, /* 0x3f */ |
535 | | {{0, 5}, |
536 | | {0, 0}, |
537 | | {0, 0}, |
538 | | {0, 0} |
539 | | } |
540 | | }, |
541 | | {0, 0, 1, 0, /* 0x40 */ |
542 | | {{6, 6}, |
543 | | {0, 0}, |
544 | | {0, 0}, |
545 | | {0, 0} |
546 | | } |
547 | | }, |
548 | | {1, 0, 2, 0, /* 0x41 */ |
549 | | {{0, 0}, |
550 | | {6, 6}, |
551 | | {0, 0}, |
552 | | {0, 0} |
553 | | } |
554 | | }, |
555 | | {0, 0, 2, 0, /* 0x42 */ |
556 | | {{1, 1}, |
557 | | {6, 6}, |
558 | | {0, 0}, |
559 | | {0, 0} |
560 | | } |
561 | | }, |
562 | | {1, 0, 2, 0, /* 0x43 */ |
563 | | {{0, 1}, |
564 | | {6, 6}, |
565 | | {0, 0}, |
566 | | {0, 0} |
567 | | } |
568 | | }, |
569 | | {0, 0, 2, 0, /* 0x44 */ |
570 | | {{2, 2}, |
571 | | {6, 6}, |
572 | | {0, 0}, |
573 | | {0, 0} |
574 | | } |
575 | | }, |
576 | | {1, 0, 3, 0, /* 0x45 */ |
577 | | {{0, 0}, |
578 | | {2, 2}, |
579 | | {6, 6}, |
580 | | {0, 0} |
581 | | } |
582 | | }, |
583 | | {0, 0, 2, 0, /* 0x46 */ |
584 | | {{1, 2}, |
585 | | {6, 6}, |
586 | | {0, 0}, |
587 | | {0, 0} |
588 | | } |
589 | | }, |
590 | | {1, 0, 2, 0, /* 0x47 */ |
591 | | {{0, 2}, |
592 | | {6, 6}, |
593 | | {0, 0}, |
594 | | {0, 0} |
595 | | } |
596 | | }, |
597 | | {0, 0, 2, 0, /* 0x48 */ |
598 | | {{3, 3}, |
599 | | {6, 6}, |
600 | | {0, 0}, |
601 | | {0, 0} |
602 | | } |
603 | | }, |
604 | | {1, 0, 3, 0, /* 0x49 */ |
605 | | {{0, 0}, |
606 | | {3, 3}, |
607 | | {6, 6}, |
608 | | {0, 0} |
609 | | } |
610 | | }, |
611 | | {0, 0, 3, 0, /* 0x4a */ |
612 | | {{1, 1}, |
613 | | {3, 3}, |
614 | | {6, 6}, |
615 | | {0, 0} |
616 | | } |
617 | | }, |
618 | | {1, 0, 3, 0, /* 0x4b */ |
619 | | {{0, 1}, |
620 | | {3, 3}, |
621 | | {6, 6}, |
622 | | {0, 0} |
623 | | } |
624 | | }, |
625 | | {0, 0, 2, 0, /* 0x4c */ |
626 | | {{2, 3}, |
627 | | {6, 6}, |
628 | | {0, 0}, |
629 | | {0, 0} |
630 | | } |
631 | | }, |
632 | | {1, 0, 3, 0, /* 0x4d */ |
633 | | {{0, 0}, |
634 | | {2, 3}, |
635 | | {6, 6}, |
636 | | {0, 0} |
637 | | } |
638 | | }, |
639 | | {0, 0, 2, 0, /* 0x4e */ |
640 | | {{1, 3}, |
641 | | {6, 6}, |
642 | | {0, 0}, |
643 | | {0, 0} |
644 | | } |
645 | | }, |
646 | | {1, 0, 2, 0, /* 0x4f */ |
647 | | {{0, 3}, |
648 | | {6, 6}, |
649 | | {0, 0}, |
650 | | {0, 0} |
651 | | } |
652 | | }, |
653 | | {0, 0, 2, 0, /* 0x50 */ |
654 | | {{4, 4}, |
655 | | {6, 6}, |
656 | | {0, 0}, |
657 | | {0, 0} |
658 | | } |
659 | | }, |
660 | | {1, 0, 3, 0, /* 0x51 */ |
661 | | {{0, 0}, |
662 | | {4, 4}, |
663 | | {6, 6}, |
664 | | {0, 0} |
665 | | } |
666 | | }, |
667 | | {0, 0, 3, 0, /* 0x52 */ |
668 | | {{1, 1}, |
669 | | {4, 4}, |
670 | | {6, 6}, |
671 | | {0, 0} |
672 | | } |
673 | | }, |
674 | | {1, 0, 3, 0, /* 0x53 */ |
675 | | {{0, 1}, |
676 | | {4, 4}, |
677 | | {6, 6}, |
678 | | {0, 0} |
679 | | } |
680 | | }, |
681 | | {0, 0, 3, 0, /* 0x54 */ |
682 | | {{2, 2}, |
683 | | {4, 4}, |
684 | | {6, 6}, |
685 | | {0, 0} |
686 | | } |
687 | | }, |
688 | | {1, 0, 4, 0, /* 0x55 */ |
689 | | {{0, 0}, |
690 | | {2, 2}, |
691 | | {4, 4}, |
692 | | {6, 6} |
693 | | } |
694 | | }, |
695 | | {0, 0, 3, 0, /* 0x56 */ |
696 | | {{1, 2}, |
697 | | {4, 4}, |
698 | | {6, 6}, |
699 | | {0, 0} |
700 | | } |
701 | | }, |
702 | | {1, 0, 3, 0, /* 0x57 */ |
703 | | {{0, 2}, |
704 | | {4, 4}, |
705 | | {6, 6}, |
706 | | {0, 0} |
707 | | } |
708 | | }, |
709 | | {0, 0, 2, 0, /* 0x58 */ |
710 | | {{3, 4}, |
711 | | {6, 6}, |
712 | | {0, 0}, |
713 | | {0, 0} |
714 | | } |
715 | | }, |
716 | | {1, 0, 3, 0, /* 0x59 */ |
717 | | {{0, 0}, |
718 | | {3, 4}, |
719 | | {6, 6}, |
720 | | {0, 0} |
721 | | } |
722 | | }, |
723 | | {0, 0, 3, 0, /* 0x5a */ |
724 | | {{1, 1}, |
725 | | {3, 4}, |
726 | | {6, 6}, |
727 | | {0, 0} |
728 | | } |
729 | | }, |
730 | | {1, 0, 3, 0, /* 0x5b */ |
731 | | {{0, 1}, |
732 | | {3, 4}, |
733 | | {6, 6}, |
734 | | {0, 0} |
735 | | } |
736 | | }, |
737 | | {0, 0, 2, 0, /* 0x5c */ |
738 | | {{2, 4}, |
739 | | {6, 6}, |
740 | | {0, 0}, |
741 | | {0, 0} |
742 | | } |
743 | | }, |
744 | | {1, 0, 3, 0, /* 0x5d */ |
745 | | {{0, 0}, |
746 | | {2, 4}, |
747 | | {6, 6}, |
748 | | {0, 0} |
749 | | } |
750 | | }, |
751 | | {0, 0, 2, 0, /* 0x5e */ |
752 | | {{1, 4}, |
753 | | {6, 6}, |
754 | | {0, 0}, |
755 | | {0, 0} |
756 | | } |
757 | | }, |
758 | | {1, 0, 2, 0, /* 0x5f */ |
759 | | {{0, 4}, |
760 | | {6, 6}, |
761 | | {0, 0}, |
762 | | {0, 0} |
763 | | } |
764 | | }, |
765 | | {0, 0, 1, 0, /* 0x60 */ |
766 | | {{5, 6}, |
767 | | {0, 0}, |
768 | | {0, 0}, |
769 | | {0, 0} |
770 | | } |
771 | | }, |
772 | | {1, 0, 2, 0, /* 0x61 */ |
773 | | {{0, 0}, |
774 | | {5, 6}, |
775 | | {0, 0}, |
776 | | {0, 0} |
777 | | } |
778 | | }, |
779 | | {0, 0, 2, 0, /* 0x62 */ |
780 | | {{1, 1}, |
781 | | {5, 6}, |
782 | | {0, 0}, |
783 | | {0, 0} |
784 | | } |
785 | | }, |
786 | | {1, 0, 2, 0, /* 0x63 */ |
787 | | {{0, 1}, |
788 | | {5, 6}, |
789 | | {0, 0}, |
790 | | {0, 0} |
791 | | } |
792 | | }, |
793 | | {0, 0, 2, 0, /* 0x64 */ |
794 | | {{2, 2}, |
795 | | {5, 6}, |
796 | | {0, 0}, |
797 | | {0, 0} |
798 | | } |
799 | | }, |
800 | | {1, 0, 3, 0, /* 0x65 */ |
801 | | {{0, 0}, |
802 | | {2, 2}, |
803 | | {5, 6}, |
804 | | {0, 0} |
805 | | } |
806 | | }, |
807 | | {0, 0, 2, 0, /* 0x66 */ |
808 | | {{1, 2}, |
809 | | {5, 6}, |
810 | | {0, 0}, |
811 | | {0, 0} |
812 | | } |
813 | | }, |
814 | | {1, 0, 2, 0, /* 0x67 */ |
815 | | {{0, 2}, |
816 | | {5, 6}, |
817 | | {0, 0}, |
818 | | {0, 0} |
819 | | } |
820 | | }, |
821 | | {0, 0, 2, 0, /* 0x68 */ |
822 | | {{3, 3}, |
823 | | {5, 6}, |
824 | | {0, 0}, |
825 | | {0, 0} |
826 | | } |
827 | | }, |
828 | | {1, 0, 3, 0, /* 0x69 */ |
829 | | {{0, 0}, |
830 | | {3, 3}, |
831 | | {5, 6}, |
832 | | {0, 0} |
833 | | } |
834 | | }, |
835 | | {0, 0, 3, 0, /* 0x6a */ |
836 | | {{1, 1}, |
837 | | {3, 3}, |
838 | | {5, 6}, |
839 | | {0, 0} |
840 | | } |
841 | | }, |
842 | | {1, 0, 3, 0, /* 0x6b */ |
843 | | {{0, 1}, |
844 | | {3, 3}, |
845 | | {5, 6}, |
846 | | {0, 0} |
847 | | } |
848 | | }, |
849 | | {0, 0, 2, 0, /* 0x6c */ |
850 | | {{2, 3}, |
851 | | {5, 6}, |
852 | | {0, 0}, |
853 | | {0, 0} |
854 | | } |
855 | | }, |
856 | | {1, 0, 3, 0, /* 0x6d */ |
857 | | {{0, 0}, |
858 | | {2, 3}, |
859 | | {5, 6}, |
860 | | {0, 0} |
861 | | } |
862 | | }, |
863 | | {0, 0, 2, 0, /* 0x6e */ |
864 | | {{1, 3}, |
865 | | {5, 6}, |
866 | | {0, 0}, |
867 | | {0, 0} |
868 | | } |
869 | | }, |
870 | | {1, 0, 2, 0, /* 0x6f */ |
871 | | {{0, 3}, |
872 | | {5, 6}, |
873 | | {0, 0}, |
874 | | {0, 0} |
875 | | } |
876 | | }, |
877 | | {0, 0, 1, 0, /* 0x70 */ |
878 | | {{4, 6}, |
879 | | {0, 0}, |
880 | | {0, 0}, |
881 | | {0, 0} |
882 | | } |
883 | | }, |
884 | | {1, 0, 2, 0, /* 0x71 */ |
885 | | {{0, 0}, |
886 | | {4, 6}, |
887 | | {0, 0}, |
888 | | {0, 0} |
889 | | } |
890 | | }, |
891 | | {0, 0, 2, 0, /* 0x72 */ |
892 | | {{1, 1}, |
893 | | {4, 6}, |
894 | | {0, 0}, |
895 | | {0, 0} |
896 | | } |
897 | | }, |
898 | | {1, 0, 2, 0, /* 0x73 */ |
899 | | {{0, 1}, |
900 | | {4, 6}, |
901 | | {0, 0}, |
902 | | {0, 0} |
903 | | } |
904 | | }, |
905 | | {0, 0, 2, 0, /* 0x74 */ |
906 | | {{2, 2}, |
907 | | {4, 6}, |
908 | | {0, 0}, |
909 | | {0, 0} |
910 | | } |
911 | | }, |
912 | | {1, 0, 3, 0, /* 0x75 */ |
913 | | {{0, 0}, |
914 | | {2, 2}, |
915 | | {4, 6}, |
916 | | {0, 0} |
917 | | } |
918 | | }, |
919 | | {0, 0, 2, 0, /* 0x76 */ |
920 | | {{1, 2}, |
921 | | {4, 6}, |
922 | | {0, 0}, |
923 | | {0, 0} |
924 | | } |
925 | | }, |
926 | | {1, 0, 2, 0, /* 0x77 */ |
927 | | {{0, 2}, |
928 | | {4, 6}, |
929 | | {0, 0}, |
930 | | {0, 0} |
931 | | } |
932 | | }, |
933 | | {0, 0, 1, 0, /* 0x78 */ |
934 | | {{3, 6}, |
935 | | {0, 0}, |
936 | | {0, 0}, |
937 | | {0, 0} |
938 | | } |
939 | | }, |
940 | | {1, 0, 2, 0, /* 0x79 */ |
941 | | {{0, 0}, |
942 | | {3, 6}, |
943 | | {0, 0}, |
944 | | {0, 0} |
945 | | } |
946 | | }, |
947 | | {0, 0, 2, 0, /* 0x7a */ |
948 | | {{1, 1}, |
949 | | {3, 6}, |
950 | | {0, 0}, |
951 | | {0, 0} |
952 | | } |
953 | | }, |
954 | | {1, 0, 2, 0, /* 0x7b */ |
955 | | {{0, 1}, |
956 | | {3, 6}, |
957 | | {0, 0}, |
958 | | {0, 0} |
959 | | } |
960 | | }, |
961 | | {0, 0, 1, 0, /* 0x7c */ |
962 | | {{2, 6}, |
963 | | {0, 0}, |
964 | | {0, 0}, |
965 | | {0, 0} |
966 | | } |
967 | | }, |
968 | | {1, 0, 2, 0, /* 0x7d */ |
969 | | {{0, 0}, |
970 | | {2, 6}, |
971 | | {0, 0}, |
972 | | {0, 0} |
973 | | } |
974 | | }, |
975 | | {0, 0, 1, 0, /* 0x7e */ |
976 | | {{1, 6}, |
977 | | {0, 0}, |
978 | | {0, 0}, |
979 | | {0, 0} |
980 | | } |
981 | | }, |
982 | | {1, 0, 1, 0, /* 0x7f */ |
983 | | {{0, 6}, |
984 | | {0, 0}, |
985 | | {0, 0}, |
986 | | {0, 0} |
987 | | } |
988 | | }, |
989 | | {0, 1, 1, 0, /* 0x80 */ |
990 | | {{7, 7}, |
991 | | {0, 0}, |
992 | | {0, 0}, |
993 | | {0, 0} |
994 | | } |
995 | | }, |
996 | | {1, 1, 2, 0, /* 0x81 */ |
997 | | {{0, 0}, |
998 | | {7, 7}, |
999 | | {0, 0}, |
1000 | | {0, 0} |
1001 | | } |
1002 | | }, |
1003 | | {0, 1, 2, 0, /* 0x82 */ |
1004 | | {{1, 1}, |
1005 | | {7, 7}, |
1006 | | {0, 0}, |
1007 | | {0, 0} |
1008 | | } |
1009 | | }, |
1010 | | {1, 1, 2, 0, /* 0x83 */ |
1011 | | {{0, 1}, |
1012 | | {7, 7}, |
1013 | | {0, 0}, |
1014 | | {0, 0} |
1015 | | } |
1016 | | }, |
1017 | | {0, 1, 2, 0, /* 0x84 */ |
1018 | | {{2, 2}, |
1019 | | {7, 7}, |
1020 | | {0, 0}, |
1021 | | {0, 0} |
1022 | | } |
1023 | | }, |
1024 | | {1, 1, 3, 0, /* 0x85 */ |
1025 | | {{0, 0}, |
1026 | | {2, 2}, |
1027 | | {7, 7}, |
1028 | | {0, 0} |
1029 | | } |
1030 | | }, |
1031 | | {0, 1, 2, 0, /* 0x86 */ |
1032 | | {{1, 2}, |
1033 | | {7, 7}, |
1034 | | {0, 0}, |
1035 | | {0, 0} |
1036 | | } |
1037 | | }, |
1038 | | {1, 1, 2, 0, /* 0x87 */ |
1039 | | {{0, 2}, |
1040 | | {7, 7}, |
1041 | | {0, 0}, |
1042 | | {0, 0} |
1043 | | } |
1044 | | }, |
1045 | | {0, 1, 2, 0, /* 0x88 */ |
1046 | | {{3, 3}, |
1047 | | {7, 7}, |
1048 | | {0, 0}, |
1049 | | {0, 0} |
1050 | | } |
1051 | | }, |
1052 | | {1, 1, 3, 0, /* 0x89 */ |
1053 | | {{0, 0}, |
1054 | | {3, 3}, |
1055 | | {7, 7}, |
1056 | | {0, 0} |
1057 | | } |
1058 | | }, |
1059 | | {0, 1, 3, 0, /* 0x8a */ |
1060 | | {{1, 1}, |
1061 | | {3, 3}, |
1062 | | {7, 7}, |
1063 | | {0, 0} |
1064 | | } |
1065 | | }, |
1066 | | {1, 1, 3, 0, /* 0x8b */ |
1067 | | {{0, 1}, |
1068 | | {3, 3}, |
1069 | | {7, 7}, |
1070 | | {0, 0} |
1071 | | } |
1072 | | }, |
1073 | | {0, 1, 2, 0, /* 0x8c */ |
1074 | | {{2, 3}, |
1075 | | {7, 7}, |
1076 | | {0, 0}, |
1077 | | {0, 0} |
1078 | | } |
1079 | | }, |
1080 | | {1, 1, 3, 0, /* 0x8d */ |
1081 | | {{0, 0}, |
1082 | | {2, 3}, |
1083 | | {7, 7}, |
1084 | | {0, 0} |
1085 | | } |
1086 | | }, |
1087 | | {0, 1, 2, 0, /* 0x8e */ |
1088 | | {{1, 3}, |
1089 | | {7, 7}, |
1090 | | {0, 0}, |
1091 | | {0, 0} |
1092 | | } |
1093 | | }, |
1094 | | {1, 1, 2, 0, /* 0x8f */ |
1095 | | {{0, 3}, |
1096 | | {7, 7}, |
1097 | | {0, 0}, |
1098 | | {0, 0} |
1099 | | } |
1100 | | }, |
1101 | | {0, 1, 2, 0, /* 0x90 */ |
1102 | | {{4, 4}, |
1103 | | {7, 7}, |
1104 | | {0, 0}, |
1105 | | {0, 0} |
1106 | | } |
1107 | | }, |
1108 | | {1, 1, 3, 0, /* 0x91 */ |
1109 | | {{0, 0}, |
1110 | | {4, 4}, |
1111 | | {7, 7}, |
1112 | | {0, 0} |
1113 | | } |
1114 | | }, |
1115 | | {0, 1, 3, 0, /* 0x92 */ |
1116 | | {{1, 1}, |
1117 | | {4, 4}, |
1118 | | {7, 7}, |
1119 | | {0, 0} |
1120 | | } |
1121 | | }, |
1122 | | {1, 1, 3, 0, /* 0x93 */ |
1123 | | {{0, 1}, |
1124 | | {4, 4}, |
1125 | | {7, 7}, |
1126 | | {0, 0} |
1127 | | } |
1128 | | }, |
1129 | | {0, 1, 3, 0, /* 0x94 */ |
1130 | | {{2, 2}, |
1131 | | {4, 4}, |
1132 | | {7, 7}, |
1133 | | {0, 0} |
1134 | | } |
1135 | | }, |
1136 | | {1, 1, 4, 0, /* 0x95 */ |
1137 | | {{0, 0}, |
1138 | | {2, 2}, |
1139 | | {4, 4}, |
1140 | | {7, 7} |
1141 | | } |
1142 | | }, |
1143 | | {0, 1, 3, 0, /* 0x96 */ |
1144 | | {{1, 2}, |
1145 | | {4, 4}, |
1146 | | {7, 7}, |
1147 | | {0, 0} |
1148 | | } |
1149 | | }, |
1150 | | {1, 1, 3, 0, /* 0x97 */ |
1151 | | {{0, 2}, |
1152 | | {4, 4}, |
1153 | | {7, 7}, |
1154 | | {0, 0} |
1155 | | } |
1156 | | }, |
1157 | | {0, 1, 2, 0, /* 0x98 */ |
1158 | | {{3, 4}, |
1159 | | {7, 7}, |
1160 | | {0, 0}, |
1161 | | {0, 0} |
1162 | | } |
1163 | | }, |
1164 | | {1, 1, 3, 0, /* 0x99 */ |
1165 | | {{0, 0}, |
1166 | | {3, 4}, |
1167 | | {7, 7}, |
1168 | | {0, 0} |
1169 | | } |
1170 | | }, |
1171 | | {0, 1, 3, 0, /* 0x9a */ |
1172 | | {{1, 1}, |
1173 | | {3, 4}, |
1174 | | {7, 7}, |
1175 | | {0, 0} |
1176 | | } |
1177 | | }, |
1178 | | {1, 1, 3, 0, /* 0x9b */ |
1179 | | {{0, 1}, |
1180 | | {3, 4}, |
1181 | | {7, 7}, |
1182 | | {0, 0} |
1183 | | } |
1184 | | }, |
1185 | | {0, 1, 2, 0, /* 0x9c */ |
1186 | | {{2, 4}, |
1187 | | {7, 7}, |
1188 | | {0, 0}, |
1189 | | {0, 0} |
1190 | | } |
1191 | | }, |
1192 | | {1, 1, 3, 0, /* 0x9d */ |
1193 | | {{0, 0}, |
1194 | | {2, 4}, |
1195 | | {7, 7}, |
1196 | | {0, 0} |
1197 | | } |
1198 | | }, |
1199 | | {0, 1, 2, 0, /* 0x9e */ |
1200 | | {{1, 4}, |
1201 | | {7, 7}, |
1202 | | {0, 0}, |
1203 | | {0, 0} |
1204 | | } |
1205 | | }, |
1206 | | {1, 1, 2, 0, /* 0x9f */ |
1207 | | {{0, 4}, |
1208 | | {7, 7}, |
1209 | | {0, 0}, |
1210 | | {0, 0} |
1211 | | } |
1212 | | }, |
1213 | | {0, 1, 2, 0, /* 0xa0 */ |
1214 | | {{5, 5}, |
1215 | | {7, 7}, |
1216 | | {0, 0}, |
1217 | | {0, 0} |
1218 | | } |
1219 | | }, |
1220 | | {1, 1, 3, 0, /* 0xa1 */ |
1221 | | {{0, 0}, |
1222 | | {5, 5}, |
1223 | | {7, 7}, |
1224 | | {0, 0} |
1225 | | } |
1226 | | }, |
1227 | | {0, 1, 3, 0, /* 0xa2 */ |
1228 | | {{1, 1}, |
1229 | | {5, 5}, |
1230 | | {7, 7}, |
1231 | | {0, 0} |
1232 | | } |
1233 | | }, |
1234 | | {1, 1, 3, 0, /* 0xa3 */ |
1235 | | {{0, 1}, |
1236 | | {5, 5}, |
1237 | | {7, 7}, |
1238 | | {0, 0} |
1239 | | } |
1240 | | }, |
1241 | | {0, 1, 3, 0, /* 0xa4 */ |
1242 | | {{2, 2}, |
1243 | | {5, 5}, |
1244 | | {7, 7}, |
1245 | | {0, 0} |
1246 | | } |
1247 | | }, |
1248 | | {1, 1, 4, 0, /* 0xa5 */ |
1249 | | {{0, 0}, |
1250 | | {2, 2}, |
1251 | | {5, 5}, |
1252 | | {7, 7} |
1253 | | } |
1254 | | }, |
1255 | | {0, 1, 3, 0, /* 0xa6 */ |
1256 | | {{1, 2}, |
1257 | | {5, 5}, |
1258 | | {7, 7}, |
1259 | | {0, 0} |
1260 | | } |
1261 | | }, |
1262 | | {1, 1, 3, 0, /* 0xa7 */ |
1263 | | {{0, 2}, |
1264 | | {5, 5}, |
1265 | | {7, 7}, |
1266 | | {0, 0} |
1267 | | } |
1268 | | }, |
1269 | | {0, 1, 3, 0, /* 0xa8 */ |
1270 | | {{3, 3}, |
1271 | | {5, 5}, |
1272 | | {7, 7}, |
1273 | | {0, 0} |
1274 | | } |
1275 | | }, |
1276 | | {1, 1, 4, 0, /* 0xa9 */ |
1277 | | {{0, 0}, |
1278 | | {3, 3}, |
1279 | | {5, 5}, |
1280 | | {7, 7} |
1281 | | } |
1282 | | }, |
1283 | | {0, 1, 4, 0, /* 0xaa */ |
1284 | | {{1, 1}, |
1285 | | {3, 3}, |
1286 | | {5, 5}, |
1287 | | {7, 7} |
1288 | | } |
1289 | | }, |
1290 | | {1, 1, 4, 0, /* 0xab */ |
1291 | | {{0, 1}, |
1292 | | {3, 3}, |
1293 | | {5, 5}, |
1294 | | {7, 7} |
1295 | | } |
1296 | | }, |
1297 | | {0, 1, 3, 0, /* 0xac */ |
1298 | | {{2, 3}, |
1299 | | {5, 5}, |
1300 | | {7, 7}, |
1301 | | {0, 0} |
1302 | | } |
1303 | | }, |
1304 | | {1, 1, 4, 0, /* 0xad */ |
1305 | | {{0, 0}, |
1306 | | {2, 3}, |
1307 | | {5, 5}, |
1308 | | {7, 7} |
1309 | | } |
1310 | | }, |
1311 | | {0, 1, 3, 0, /* 0xae */ |
1312 | | {{1, 3}, |
1313 | | {5, 5}, |
1314 | | {7, 7}, |
1315 | | {0, 0} |
1316 | | } |
1317 | | }, |
1318 | | {1, 1, 3, 0, /* 0xaf */ |
1319 | | {{0, 3}, |
1320 | | {5, 5}, |
1321 | | {7, 7}, |
1322 | | {0, 0} |
1323 | | } |
1324 | | }, |
1325 | | {0, 1, 2, 0, /* 0xb0 */ |
1326 | | {{4, 5}, |
1327 | | {7, 7}, |
1328 | | {0, 0}, |
1329 | | {0, 0} |
1330 | | } |
1331 | | }, |
1332 | | {1, 1, 3, 0, /* 0xb1 */ |
1333 | | {{0, 0}, |
1334 | | {4, 5}, |
1335 | | {7, 7}, |
1336 | | {0, 0} |
1337 | | } |
1338 | | }, |
1339 | | {0, 1, 3, 0, /* 0xb2 */ |
1340 | | {{1, 1}, |
1341 | | {4, 5}, |
1342 | | {7, 7}, |
1343 | | {0, 0} |
1344 | | } |
1345 | | }, |
1346 | | {1, 1, 3, 0, /* 0xb3 */ |
1347 | | {{0, 1}, |
1348 | | {4, 5}, |
1349 | | {7, 7}, |
1350 | | {0, 0} |
1351 | | } |
1352 | | }, |
1353 | | {0, 1, 3, 0, /* 0xb4 */ |
1354 | | {{2, 2}, |
1355 | | {4, 5}, |
1356 | | {7, 7}, |
1357 | | {0, 0} |
1358 | | } |
1359 | | }, |
1360 | | {1, 1, 4, 0, /* 0xb5 */ |
1361 | | {{0, 0}, |
1362 | | {2, 2}, |
1363 | | {4, 5}, |
1364 | | {7, 7} |
1365 | | } |
1366 | | }, |
1367 | | {0, 1, 3, 0, /* 0xb6 */ |
1368 | | {{1, 2}, |
1369 | | {4, 5}, |
1370 | | {7, 7}, |
1371 | | {0, 0} |
1372 | | } |
1373 | | }, |
1374 | | {1, 1, 3, 0, /* 0xb7 */ |
1375 | | {{0, 2}, |
1376 | | {4, 5}, |
1377 | | {7, 7}, |
1378 | | {0, 0} |
1379 | | } |
1380 | | }, |
1381 | | {0, 1, 2, 0, /* 0xb8 */ |
1382 | | {{3, 5}, |
1383 | | {7, 7}, |
1384 | | {0, 0}, |
1385 | | {0, 0} |
1386 | | } |
1387 | | }, |
1388 | | {1, 1, 3, 0, /* 0xb9 */ |
1389 | | {{0, 0}, |
1390 | | {3, 5}, |
1391 | | {7, 7}, |
1392 | | {0, 0} |
1393 | | } |
1394 | | }, |
1395 | | {0, 1, 3, 0, /* 0xba */ |
1396 | | {{1, 1}, |
1397 | | {3, 5}, |
1398 | | {7, 7}, |
1399 | | {0, 0} |
1400 | | } |
1401 | | }, |
1402 | | {1, 1, 3, 0, /* 0xbb */ |
1403 | | {{0, 1}, |
1404 | | {3, 5}, |
1405 | | {7, 7}, |
1406 | | {0, 0} |
1407 | | } |
1408 | | }, |
1409 | | {0, 1, 2, 0, /* 0xbc */ |
1410 | | {{2, 5}, |
1411 | | {7, 7}, |
1412 | | {0, 0}, |
1413 | | {0, 0} |
1414 | | } |
1415 | | }, |
1416 | | {1, 1, 3, 0, /* 0xbd */ |
1417 | | {{0, 0}, |
1418 | | {2, 5}, |
1419 | | {7, 7}, |
1420 | | {0, 0} |
1421 | | } |
1422 | | }, |
1423 | | {0, 1, 2, 0, /* 0xbe */ |
1424 | | {{1, 5}, |
1425 | | {7, 7}, |
1426 | | {0, 0}, |
1427 | | {0, 0} |
1428 | | } |
1429 | | }, |
1430 | | {1, 1, 2, 0, /* 0xbf */ |
1431 | | {{0, 5}, |
1432 | | {7, 7}, |
1433 | | {0, 0}, |
1434 | | {0, 0} |
1435 | | } |
1436 | | }, |
1437 | | {0, 1, 1, 0, /* 0xc0 */ |
1438 | | {{6, 7}, |
1439 | | {0, 0}, |
1440 | | {0, 0}, |
1441 | | {0, 0} |
1442 | | } |
1443 | | }, |
1444 | | {1, 1, 2, 0, /* 0xc1 */ |
1445 | | {{0, 0}, |
1446 | | {6, 7}, |
1447 | | {0, 0}, |
1448 | | {0, 0} |
1449 | | } |
1450 | | }, |
1451 | | {0, 1, 2, 0, /* 0xc2 */ |
1452 | | {{1, 1}, |
1453 | | {6, 7}, |
1454 | | {0, 0}, |
1455 | | {0, 0} |
1456 | | } |
1457 | | }, |
1458 | | {1, 1, 2, 0, /* 0xc3 */ |
1459 | | {{0, 1}, |
1460 | | {6, 7}, |
1461 | | {0, 0}, |
1462 | | {0, 0} |
1463 | | } |
1464 | | }, |
1465 | | {0, 1, 2, 0, /* 0xc4 */ |
1466 | | {{2, 2}, |
1467 | | {6, 7}, |
1468 | | {0, 0}, |
1469 | | {0, 0} |
1470 | | } |
1471 | | }, |
1472 | | {1, 1, 3, 0, /* 0xc5 */ |
1473 | | {{0, 0}, |
1474 | | {2, 2}, |
1475 | | {6, 7}, |
1476 | | {0, 0} |
1477 | | } |
1478 | | }, |
1479 | | {0, 1, 2, 0, /* 0xc6 */ |
1480 | | {{1, 2}, |
1481 | | {6, 7}, |
1482 | | {0, 0}, |
1483 | | {0, 0} |
1484 | | } |
1485 | | }, |
1486 | | {1, 1, 2, 0, /* 0xc7 */ |
1487 | | {{0, 2}, |
1488 | | {6, 7}, |
1489 | | {0, 0}, |
1490 | | {0, 0} |
1491 | | } |
1492 | | }, |
1493 | | {0, 1, 2, 0, /* 0xc8 */ |
1494 | | {{3, 3}, |
1495 | | {6, 7}, |
1496 | | {0, 0}, |
1497 | | {0, 0} |
1498 | | } |
1499 | | }, |
1500 | | {1, 1, 3, 0, /* 0xc9 */ |
1501 | | {{0, 0}, |
1502 | | {3, 3}, |
1503 | | {6, 7}, |
1504 | | {0, 0} |
1505 | | } |
1506 | | }, |
1507 | | {0, 1, 3, 0, /* 0xca */ |
1508 | | {{1, 1}, |
1509 | | {3, 3}, |
1510 | | {6, 7}, |
1511 | | {0, 0} |
1512 | | } |
1513 | | }, |
1514 | | {1, 1, 3, 0, /* 0xcb */ |
1515 | | {{0, 1}, |
1516 | | {3, 3}, |
1517 | | {6, 7}, |
1518 | | {0, 0} |
1519 | | } |
1520 | | }, |
1521 | | {0, 1, 2, 0, /* 0xcc */ |
1522 | | {{2, 3}, |
1523 | | {6, 7}, |
1524 | | {0, 0}, |
1525 | | {0, 0} |
1526 | | } |
1527 | | }, |
1528 | | {1, 1, 3, 0, /* 0xcd */ |
1529 | | {{0, 0}, |
1530 | | {2, 3}, |
1531 | | {6, 7}, |
1532 | | {0, 0} |
1533 | | } |
1534 | | }, |
1535 | | {0, 1, 2, 0, /* 0xce */ |
1536 | | {{1, 3}, |
1537 | | {6, 7}, |
1538 | | {0, 0}, |
1539 | | {0, 0} |
1540 | | } |
1541 | | }, |
1542 | | {1, 1, 2, 0, /* 0xcf */ |
1543 | | {{0, 3}, |
1544 | | {6, 7}, |
1545 | | {0, 0}, |
1546 | | {0, 0} |
1547 | | } |
1548 | | }, |
1549 | | {0, 1, 2, 0, /* 0xd0 */ |
1550 | | {{4, 4}, |
1551 | | {6, 7}, |
1552 | | {0, 0}, |
1553 | | {0, 0} |
1554 | | } |
1555 | | }, |
1556 | | {1, 1, 3, 0, /* 0xd1 */ |
1557 | | {{0, 0}, |
1558 | | {4, 4}, |
1559 | | {6, 7}, |
1560 | | {0, 0} |
1561 | | } |
1562 | | }, |
1563 | | {0, 1, 3, 0, /* 0xd2 */ |
1564 | | {{1, 1}, |
1565 | | {4, 4}, |
1566 | | {6, 7}, |
1567 | | {0, 0} |
1568 | | } |
1569 | | }, |
1570 | | {1, 1, 3, 0, /* 0xd3 */ |
1571 | | {{0, 1}, |
1572 | | {4, 4}, |
1573 | | {6, 7}, |
1574 | | {0, 0} |
1575 | | } |
1576 | | }, |
1577 | | {0, 1, 3, 0, /* 0xd4 */ |
1578 | | {{2, 2}, |
1579 | | {4, 4}, |
1580 | | {6, 7}, |
1581 | | {0, 0} |
1582 | | } |
1583 | | }, |
1584 | | {1, 1, 4, 0, /* 0xd5 */ |
1585 | | {{0, 0}, |
1586 | | {2, 2}, |
1587 | | {4, 4}, |
1588 | | {6, 7} |
1589 | | } |
1590 | | }, |
1591 | | {0, 1, 3, 0, /* 0xd6 */ |
1592 | | {{1, 2}, |
1593 | | {4, 4}, |
1594 | | {6, 7}, |
1595 | | {0, 0} |
1596 | | } |
1597 | | }, |
1598 | | {1, 1, 3, 0, /* 0xd7 */ |
1599 | | {{0, 2}, |
1600 | | {4, 4}, |
1601 | | {6, 7}, |
1602 | | {0, 0} |
1603 | | } |
1604 | | }, |
1605 | | {0, 1, 2, 0, /* 0xd8 */ |
1606 | | {{3, 4}, |
1607 | | {6, 7}, |
1608 | | {0, 0}, |
1609 | | {0, 0} |
1610 | | } |
1611 | | }, |
1612 | | {1, 1, 3, 0, /* 0xd9 */ |
1613 | | {{0, 0}, |
1614 | | {3, 4}, |
1615 | | {6, 7}, |
1616 | | {0, 0} |
1617 | | } |
1618 | | }, |
1619 | | {0, 1, 3, 0, /* 0xda */ |
1620 | | {{1, 1}, |
1621 | | {3, 4}, |
1622 | | {6, 7}, |
1623 | | {0, 0} |
1624 | | } |
1625 | | }, |
1626 | | {1, 1, 3, 0, /* 0xdb */ |
1627 | | {{0, 1}, |
1628 | | {3, 4}, |
1629 | | {6, 7}, |
1630 | | {0, 0} |
1631 | | } |
1632 | | }, |
1633 | | {0, 1, 2, 0, /* 0xdc */ |
1634 | | {{2, 4}, |
1635 | | {6, 7}, |
1636 | | {0, 0}, |
1637 | | {0, 0} |
1638 | | } |
1639 | | }, |
1640 | | {1, 1, 3, 0, /* 0xdd */ |
1641 | | {{0, 0}, |
1642 | | {2, 4}, |
1643 | | {6, 7}, |
1644 | | {0, 0} |
1645 | | } |
1646 | | }, |
1647 | | {0, 1, 2, 0, /* 0xde */ |
1648 | | {{1, 4}, |
1649 | | {6, 7}, |
1650 | | {0, 0}, |
1651 | | {0, 0} |
1652 | | } |
1653 | | }, |
1654 | | {1, 1, 2, 0, /* 0xdf */ |
1655 | | {{0, 4}, |
1656 | | {6, 7}, |
1657 | | {0, 0}, |
1658 | | {0, 0} |
1659 | | } |
1660 | | }, |
1661 | | {0, 1, 1, 0, /* 0xe0 */ |
1662 | | {{5, 7}, |
1663 | | {0, 0}, |
1664 | | {0, 0}, |
1665 | | {0, 0} |
1666 | | } |
1667 | | }, |
1668 | | {1, 1, 2, 0, /* 0xe1 */ |
1669 | | {{0, 0}, |
1670 | | {5, 7}, |
1671 | | {0, 0}, |
1672 | | {0, 0} |
1673 | | } |
1674 | | }, |
1675 | | {0, 1, 2, 0, /* 0xe2 */ |
1676 | | {{1, 1}, |
1677 | | {5, 7}, |
1678 | | {0, 0}, |
1679 | | {0, 0} |
1680 | | } |
1681 | | }, |
1682 | | {1, 1, 2, 0, /* 0xe3 */ |
1683 | | {{0, 1}, |
1684 | | {5, 7}, |
1685 | | {0, 0}, |
1686 | | {0, 0} |
1687 | | } |
1688 | | }, |
1689 | | {0, 1, 2, 0, /* 0xe4 */ |
1690 | | {{2, 2}, |
1691 | | {5, 7}, |
1692 | | {0, 0}, |
1693 | | {0, 0} |
1694 | | } |
1695 | | }, |
1696 | | {1, 1, 3, 0, /* 0xe5 */ |
1697 | | {{0, 0}, |
1698 | | {2, 2}, |
1699 | | {5, 7}, |
1700 | | {0, 0} |
1701 | | } |
1702 | | }, |
1703 | | {0, 1, 2, 0, /* 0xe6 */ |
1704 | | {{1, 2}, |
1705 | | {5, 7}, |
1706 | | {0, 0}, |
1707 | | {0, 0} |
1708 | | } |
1709 | | }, |
1710 | | {1, 1, 2, 0, /* 0xe7 */ |
1711 | | {{0, 2}, |
1712 | | {5, 7}, |
1713 | | {0, 0}, |
1714 | | {0, 0} |
1715 | | } |
1716 | | }, |
1717 | | {0, 1, 2, 0, /* 0xe8 */ |
1718 | | {{3, 3}, |
1719 | | {5, 7}, |
1720 | | {0, 0}, |
1721 | | {0, 0} |
1722 | | } |
1723 | | }, |
1724 | | {1, 1, 3, 0, /* 0xe9 */ |
1725 | | {{0, 0}, |
1726 | | {3, 3}, |
1727 | | {5, 7}, |
1728 | | {0, 0} |
1729 | | } |
1730 | | }, |
1731 | | {0, 1, 3, 0, /* 0xea */ |
1732 | | {{1, 1}, |
1733 | | {3, 3}, |
1734 | | {5, 7}, |
1735 | | {0, 0} |
1736 | | } |
1737 | | }, |
1738 | | {1, 1, 3, 0, /* 0xeb */ |
1739 | | {{0, 1}, |
1740 | | {3, 3}, |
1741 | | {5, 7}, |
1742 | | {0, 0} |
1743 | | } |
1744 | | }, |
1745 | | {0, 1, 2, 0, /* 0xec */ |
1746 | | {{2, 3}, |
1747 | | {5, 7}, |
1748 | | {0, 0}, |
1749 | | {0, 0} |
1750 | | } |
1751 | | }, |
1752 | | {1, 1, 3, 0, /* 0xed */ |
1753 | | {{0, 0}, |
1754 | | {2, 3}, |
1755 | | {5, 7}, |
1756 | | {0, 0} |
1757 | | } |
1758 | | }, |
1759 | | {0, 1, 2, 0, /* 0xee */ |
1760 | | {{1, 3}, |
1761 | | {5, 7}, |
1762 | | {0, 0}, |
1763 | | {0, 0} |
1764 | | } |
1765 | | }, |
1766 | | {1, 1, 2, 0, /* 0xef */ |
1767 | | {{0, 3}, |
1768 | | {5, 7}, |
1769 | | {0, 0}, |
1770 | | {0, 0} |
1771 | | } |
1772 | | }, |
1773 | | {0, 1, 1, 0, /* 0xf0 */ |
1774 | | {{4, 7}, |
1775 | | {0, 0}, |
1776 | | {0, 0}, |
1777 | | {0, 0} |
1778 | | } |
1779 | | }, |
1780 | | {1, 1, 2, 0, /* 0xf1 */ |
1781 | | {{0, 0}, |
1782 | | {4, 7}, |
1783 | | {0, 0}, |
1784 | | {0, 0} |
1785 | | } |
1786 | | }, |
1787 | | {0, 1, 2, 0, /* 0xf2 */ |
1788 | | {{1, 1}, |
1789 | | {4, 7}, |
1790 | | {0, 0}, |
1791 | | {0, 0} |
1792 | | } |
1793 | | }, |
1794 | | {1, 1, 2, 0, /* 0xf3 */ |
1795 | | {{0, 1}, |
1796 | | {4, 7}, |
1797 | | {0, 0}, |
1798 | | {0, 0} |
1799 | | } |
1800 | | }, |
1801 | | {0, 1, 2, 0, /* 0xf4 */ |
1802 | | {{2, 2}, |
1803 | | {4, 7}, |
1804 | | {0, 0}, |
1805 | | {0, 0} |
1806 | | } |
1807 | | }, |
1808 | | {1, 1, 3, 0, /* 0xf5 */ |
1809 | | {{0, 0}, |
1810 | | {2, 2}, |
1811 | | {4, 7}, |
1812 | | {0, 0} |
1813 | | } |
1814 | | }, |
1815 | | {0, 1, 2, 0, /* 0xf6 */ |
1816 | | {{1, 2}, |
1817 | | {4, 7}, |
1818 | | {0, 0}, |
1819 | | {0, 0} |
1820 | | } |
1821 | | }, |
1822 | | {1, 1, 2, 0, /* 0xf7 */ |
1823 | | {{0, 2}, |
1824 | | {4, 7}, |
1825 | | {0, 0}, |
1826 | | {0, 0} |
1827 | | } |
1828 | | }, |
1829 | | {0, 1, 1, 0, /* 0xf8 */ |
1830 | | {{3, 7}, |
1831 | | {0, 0}, |
1832 | | {0, 0}, |
1833 | | {0, 0} |
1834 | | } |
1835 | | }, |
1836 | | {1, 1, 2, 0, /* 0xf9 */ |
1837 | | {{0, 0}, |
1838 | | {3, 7}, |
1839 | | {0, 0}, |
1840 | | {0, 0} |
1841 | | } |
1842 | | }, |
1843 | | {0, 1, 2, 0, /* 0xfa */ |
1844 | | {{1, 1}, |
1845 | | {3, 7}, |
1846 | | {0, 0}, |
1847 | | {0, 0} |
1848 | | } |
1849 | | }, |
1850 | | {1, 1, 2, 0, /* 0xfb */ |
1851 | | {{0, 1}, |
1852 | | {3, 7}, |
1853 | | {0, 0}, |
1854 | | {0, 0} |
1855 | | } |
1856 | | }, |
1857 | | {0, 1, 1, 0, /* 0xfc */ |
1858 | | {{2, 7}, |
1859 | | {0, 0}, |
1860 | | {0, 0}, |
1861 | | {0, 0} |
1862 | | } |
1863 | | }, |
1864 | | {1, 1, 2, 0, /* 0xfd */ |
1865 | | {{0, 0}, |
1866 | | {2, 7}, |
1867 | | {0, 0}, |
1868 | | {0, 0} |
1869 | | } |
1870 | | }, |
1871 | | {0, 1, 1, 0, /* 0xfe */ |
1872 | | {{1, 7}, |
1873 | | {0, 0}, |
1874 | | {0, 0}, |
1875 | | {0, 0} |
1876 | | } |
1877 | | }, |
1878 | | {1, 1, 1, 0, /* 0xff */ |
1879 | | {{0, 7}, |
1880 | | {0, 0}, |
1881 | | {0, 0}, |
1882 | | {0, 0} |
1883 | | } |
1884 | | } |
1885 | | }; |
1886 | | |
1887 | | int |
1888 | | sctp_is_address_in_scope(struct sctp_ifa *ifa, |
1889 | | struct sctp_scoping *scope, |
1890 | | int do_update) |
1891 | 0 | { |
1892 | 0 | if ((scope->loopback_scope == 0) && |
1893 | 0 | (ifa->ifn_p) && SCTP_IFN_IS_IFT_LOOP(ifa->ifn_p)) { |
1894 | | /* |
1895 | | * skip loopback if not in scope * |
1896 | | */ |
1897 | 0 | return (0); |
1898 | 0 | } |
1899 | 0 | switch (ifa->address.sa.sa_family) { |
1900 | 0 | #ifdef INET |
1901 | 0 | case AF_INET: |
1902 | 0 | if (scope->ipv4_addr_legal) { |
1903 | 0 | struct sockaddr_in *sin; |
1904 | |
|
1905 | 0 | sin = &ifa->address.sin; |
1906 | 0 | if (sin->sin_addr.s_addr == 0) { |
1907 | | /* not in scope , unspecified */ |
1908 | 0 | return (0); |
1909 | 0 | } |
1910 | 0 | if ((scope->ipv4_local_scope == 0) && |
1911 | 0 | (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { |
1912 | | /* private address not in scope */ |
1913 | 0 | return (0); |
1914 | 0 | } |
1915 | 0 | } else { |
1916 | 0 | return (0); |
1917 | 0 | } |
1918 | 0 | break; |
1919 | 0 | #endif |
1920 | 0 | #ifdef INET6 |
1921 | 0 | case AF_INET6: |
1922 | 0 | if (scope->ipv6_addr_legal) { |
1923 | 0 | struct sockaddr_in6 *sin6; |
1924 | | |
1925 | | /* Must update the flags, bummer, which |
1926 | | * means any IFA locks must now be applied HERE <-> |
1927 | | */ |
1928 | 0 | if (do_update) { |
1929 | 0 | sctp_gather_internal_ifa_flags(ifa); |
1930 | 0 | } |
1931 | 0 | if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) { |
1932 | 0 | return (0); |
1933 | 0 | } |
1934 | | /* ok to use deprecated addresses? */ |
1935 | 0 | sin6 = &ifa->address.sin6; |
1936 | 0 | if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { |
1937 | | /* skip unspecified addresses */ |
1938 | 0 | return (0); |
1939 | 0 | } |
1940 | 0 | if ( /* (local_scope == 0) && */ |
1941 | 0 | (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) { |
1942 | 0 | return (0); |
1943 | 0 | } |
1944 | 0 | if ((scope->site_scope == 0) && |
1945 | 0 | (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { |
1946 | 0 | return (0); |
1947 | 0 | } |
1948 | 0 | } else { |
1949 | 0 | return (0); |
1950 | 0 | } |
1951 | 0 | break; |
1952 | 0 | #endif |
1953 | 0 | #if defined(__Userspace__) |
1954 | 0 | case AF_CONN: |
1955 | 0 | if (!scope->conn_addr_legal) { |
1956 | 0 | return (0); |
1957 | 0 | } |
1958 | 0 | break; |
1959 | 0 | #endif |
1960 | 0 | default: |
1961 | 0 | return (0); |
1962 | 0 | } |
1963 | 0 | return (1); |
1964 | 0 | } |
1965 | | |
1966 | | static struct mbuf * |
1967 | | sctp_add_addr_to_mbuf(struct mbuf *m, struct sctp_ifa *ifa, uint16_t *len) |
1968 | 0 | { |
1969 | 0 | #if defined(INET) || defined(INET6) |
1970 | 0 | struct sctp_paramhdr *paramh; |
1971 | 0 | struct mbuf *mret; |
1972 | 0 | uint16_t plen; |
1973 | 0 | #endif |
1974 | |
|
1975 | 0 | switch (ifa->address.sa.sa_family) { |
1976 | 0 | #ifdef INET |
1977 | 0 | case AF_INET: |
1978 | 0 | plen = (uint16_t)sizeof(struct sctp_ipv4addr_param); |
1979 | 0 | break; |
1980 | 0 | #endif |
1981 | 0 | #ifdef INET6 |
1982 | 0 | case AF_INET6: |
1983 | 0 | plen = (uint16_t)sizeof(struct sctp_ipv6addr_param); |
1984 | 0 | break; |
1985 | 0 | #endif |
1986 | 0 | default: |
1987 | 0 | return (m); |
1988 | 0 | } |
1989 | 0 | #if defined(INET) || defined(INET6) |
1990 | 0 | if (M_TRAILINGSPACE(m) >= plen) { |
1991 | | /* easy side we just drop it on the end */ |
1992 | 0 | paramh = (struct sctp_paramhdr *)(SCTP_BUF_AT(m, SCTP_BUF_LEN(m))); |
1993 | 0 | mret = m; |
1994 | 0 | } else { |
1995 | | /* Need more space */ |
1996 | 0 | mret = m; |
1997 | 0 | while (SCTP_BUF_NEXT(mret) != NULL) { |
1998 | 0 | mret = SCTP_BUF_NEXT(mret); |
1999 | 0 | } |
2000 | 0 | SCTP_BUF_NEXT(mret) = sctp_get_mbuf_for_msg(plen, 0, M_NOWAIT, 1, MT_DATA); |
2001 | 0 | if (SCTP_BUF_NEXT(mret) == NULL) { |
2002 | | /* We are hosed, can't add more addresses */ |
2003 | 0 | return (m); |
2004 | 0 | } |
2005 | 0 | mret = SCTP_BUF_NEXT(mret); |
2006 | 0 | paramh = mtod(mret, struct sctp_paramhdr *); |
2007 | 0 | } |
2008 | | /* now add the parameter */ |
2009 | 0 | switch (ifa->address.sa.sa_family) { |
2010 | 0 | #ifdef INET |
2011 | 0 | case AF_INET: |
2012 | 0 | { |
2013 | 0 | struct sctp_ipv4addr_param *ipv4p; |
2014 | 0 | struct sockaddr_in *sin; |
2015 | |
|
2016 | 0 | sin = &ifa->address.sin; |
2017 | 0 | ipv4p = (struct sctp_ipv4addr_param *)paramh; |
2018 | 0 | paramh->param_type = htons(SCTP_IPV4_ADDRESS); |
2019 | 0 | paramh->param_length = htons(plen); |
2020 | 0 | ipv4p->addr = sin->sin_addr.s_addr; |
2021 | 0 | SCTP_BUF_LEN(mret) += plen; |
2022 | 0 | break; |
2023 | 0 | } |
2024 | 0 | #endif |
2025 | 0 | #ifdef INET6 |
2026 | 0 | case AF_INET6: |
2027 | 0 | { |
2028 | 0 | struct sctp_ipv6addr_param *ipv6p; |
2029 | 0 | struct sockaddr_in6 *sin6; |
2030 | |
|
2031 | 0 | sin6 = &ifa->address.sin6; |
2032 | 0 | ipv6p = (struct sctp_ipv6addr_param *)paramh; |
2033 | 0 | paramh->param_type = htons(SCTP_IPV6_ADDRESS); |
2034 | 0 | paramh->param_length = htons(plen); |
2035 | 0 | memcpy(ipv6p->addr, &sin6->sin6_addr, |
2036 | 0 | sizeof(ipv6p->addr)); |
2037 | | #if defined(SCTP_EMBEDDED_V6_SCOPE) |
2038 | | /* clear embedded scope in the address */ |
2039 | | in6_clearscope((struct in6_addr *)ipv6p->addr); |
2040 | | #endif |
2041 | 0 | SCTP_BUF_LEN(mret) += plen; |
2042 | 0 | break; |
2043 | 0 | } |
2044 | 0 | #endif |
2045 | 0 | default: |
2046 | 0 | return (m); |
2047 | 0 | } |
2048 | 0 | if (len != NULL) { |
2049 | 0 | *len += plen; |
2050 | 0 | } |
2051 | 0 | return (mret); |
2052 | 0 | #endif |
2053 | 0 | } |
2054 | | |
2055 | | struct mbuf * |
2056 | | sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp, struct sctp_tcb *stcb, |
2057 | | struct sctp_scoping *scope, |
2058 | | struct mbuf *m_at, int cnt_inits_to, |
2059 | | uint16_t *padding_len, uint16_t *chunk_len) |
2060 | 1.60k | { |
2061 | 1.60k | struct sctp_vrf *vrf = NULL; |
2062 | 1.60k | int cnt, limit_out = 0, total_count; |
2063 | 1.60k | uint32_t vrf_id; |
2064 | | |
2065 | 1.60k | vrf_id = inp->def_vrf_id; |
2066 | 1.60k | SCTP_IPI_ADDR_RLOCK(); |
2067 | 1.60k | vrf = sctp_find_vrf(vrf_id); |
2068 | 1.60k | if (vrf == NULL) { |
2069 | 0 | SCTP_IPI_ADDR_RUNLOCK(); |
2070 | 0 | return (m_at); |
2071 | 0 | } |
2072 | 1.60k | if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { |
2073 | 0 | struct sctp_ifa *sctp_ifap; |
2074 | 0 | struct sctp_ifn *sctp_ifnp; |
2075 | |
|
2076 | 0 | cnt = cnt_inits_to; |
2077 | 0 | if (vrf->total_ifa_count > SCTP_COUNT_LIMIT) { |
2078 | 0 | limit_out = 1; |
2079 | 0 | cnt = SCTP_ADDRESS_LIMIT; |
2080 | 0 | goto skip_count; |
2081 | 0 | } |
2082 | 0 | LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) { |
2083 | 0 | if ((scope->loopback_scope == 0) && |
2084 | 0 | SCTP_IFN_IS_IFT_LOOP(sctp_ifnp)) { |
2085 | | /* |
2086 | | * Skip loopback devices if loopback_scope |
2087 | | * not set |
2088 | | */ |
2089 | 0 | continue; |
2090 | 0 | } |
2091 | 0 | LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) { |
2092 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
2093 | | #ifdef INET |
2094 | | if ((sctp_ifap->address.sa.sa_family == AF_INET) && |
2095 | | (prison_check_ip4(inp->ip_inp.inp.inp_cred, |
2096 | | &sctp_ifap->address.sin.sin_addr) != 0)) { |
2097 | | continue; |
2098 | | } |
2099 | | #endif |
2100 | | #ifdef INET6 |
2101 | | if ((sctp_ifap->address.sa.sa_family == AF_INET6) && |
2102 | | (prison_check_ip6(inp->ip_inp.inp.inp_cred, |
2103 | | &sctp_ifap->address.sin6.sin6_addr) != 0)) { |
2104 | | continue; |
2105 | | } |
2106 | | #endif |
2107 | | #endif |
2108 | 0 | if (sctp_is_addr_restricted(stcb, sctp_ifap)) { |
2109 | 0 | continue; |
2110 | 0 | } |
2111 | 0 | #if defined(__Userspace__) |
2112 | 0 | if (sctp_ifap->address.sa.sa_family == AF_CONN) { |
2113 | 0 | continue; |
2114 | 0 | } |
2115 | 0 | #endif |
2116 | 0 | if (sctp_is_address_in_scope(sctp_ifap, scope, 1) == 0) { |
2117 | 0 | continue; |
2118 | 0 | } |
2119 | 0 | cnt++; |
2120 | 0 | if (cnt > SCTP_ADDRESS_LIMIT) { |
2121 | 0 | break; |
2122 | 0 | } |
2123 | 0 | } |
2124 | 0 | if (cnt > SCTP_ADDRESS_LIMIT) { |
2125 | 0 | break; |
2126 | 0 | } |
2127 | 0 | } |
2128 | 0 | skip_count: |
2129 | 0 | if (cnt > 1) { |
2130 | 0 | total_count = 0; |
2131 | 0 | LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) { |
2132 | 0 | cnt = 0; |
2133 | 0 | if ((scope->loopback_scope == 0) && |
2134 | 0 | SCTP_IFN_IS_IFT_LOOP(sctp_ifnp)) { |
2135 | | /* |
2136 | | * Skip loopback devices if |
2137 | | * loopback_scope not set |
2138 | | */ |
2139 | 0 | continue; |
2140 | 0 | } |
2141 | 0 | LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) { |
2142 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
2143 | | #ifdef INET |
2144 | | if ((sctp_ifap->address.sa.sa_family == AF_INET) && |
2145 | | (prison_check_ip4(inp->ip_inp.inp.inp_cred, |
2146 | | &sctp_ifap->address.sin.sin_addr) != 0)) { |
2147 | | continue; |
2148 | | } |
2149 | | #endif |
2150 | | #ifdef INET6 |
2151 | | if ((sctp_ifap->address.sa.sa_family == AF_INET6) && |
2152 | | (prison_check_ip6(inp->ip_inp.inp.inp_cred, |
2153 | | &sctp_ifap->address.sin6.sin6_addr) != 0)) { |
2154 | | continue; |
2155 | | } |
2156 | | #endif |
2157 | | #endif |
2158 | 0 | if (sctp_is_addr_restricted(stcb, sctp_ifap)) { |
2159 | 0 | continue; |
2160 | 0 | } |
2161 | 0 | #if defined(__Userspace__) |
2162 | 0 | if (sctp_ifap->address.sa.sa_family == AF_CONN) { |
2163 | 0 | continue; |
2164 | 0 | } |
2165 | 0 | #endif |
2166 | 0 | if (sctp_is_address_in_scope(sctp_ifap, |
2167 | 0 | scope, 0) == 0) { |
2168 | 0 | continue; |
2169 | 0 | } |
2170 | 0 | if ((chunk_len != NULL) && |
2171 | 0 | (padding_len != NULL) && |
2172 | 0 | (*padding_len > 0)) { |
2173 | 0 | memset(mtod(m_at, caddr_t) + *chunk_len, 0, *padding_len); |
2174 | 0 | SCTP_BUF_LEN(m_at) += *padding_len; |
2175 | 0 | *chunk_len += *padding_len; |
2176 | 0 | *padding_len = 0; |
2177 | 0 | } |
2178 | 0 | m_at = sctp_add_addr_to_mbuf(m_at, sctp_ifap, chunk_len); |
2179 | 0 | if (limit_out) { |
2180 | 0 | cnt++; |
2181 | 0 | total_count++; |
2182 | 0 | if (cnt >= 2) { |
2183 | | /* two from each address */ |
2184 | 0 | break; |
2185 | 0 | } |
2186 | 0 | if (total_count > SCTP_ADDRESS_LIMIT) { |
2187 | | /* No more addresses */ |
2188 | 0 | break; |
2189 | 0 | } |
2190 | 0 | } |
2191 | 0 | } |
2192 | 0 | } |
2193 | 0 | } |
2194 | 1.60k | } else { |
2195 | 1.60k | struct sctp_laddr *laddr; |
2196 | | |
2197 | 1.60k | cnt = cnt_inits_to; |
2198 | | /* First, how many ? */ |
2199 | 1.60k | LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { |
2200 | 1.60k | if (laddr->ifa == NULL) { |
2201 | 0 | continue; |
2202 | 0 | } |
2203 | 1.60k | if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) |
2204 | | /* Address being deleted by the system, dont |
2205 | | * list. |
2206 | | */ |
2207 | 0 | continue; |
2208 | 1.60k | if (laddr->action == SCTP_DEL_IP_ADDRESS) { |
2209 | | /* Address being deleted on this ep |
2210 | | * don't list. |
2211 | | */ |
2212 | 0 | continue; |
2213 | 0 | } |
2214 | 1.60k | #if defined(__Userspace__) |
2215 | 1.60k | if (laddr->ifa->address.sa.sa_family == AF_CONN) { |
2216 | 1.60k | continue; |
2217 | 1.60k | } |
2218 | 0 | #endif |
2219 | 0 | if (sctp_is_address_in_scope(laddr->ifa, |
2220 | 0 | scope, 1) == 0) { |
2221 | 0 | continue; |
2222 | 0 | } |
2223 | 0 | cnt++; |
2224 | 0 | } |
2225 | | /* |
2226 | | * To get through a NAT we only list addresses if we have |
2227 | | * more than one. That way if you just bind a single address |
2228 | | * we let the source of the init dictate our address. |
2229 | | */ |
2230 | 1.60k | if (cnt > 1) { |
2231 | 0 | cnt = cnt_inits_to; |
2232 | 0 | LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { |
2233 | 0 | if (laddr->ifa == NULL) { |
2234 | 0 | continue; |
2235 | 0 | } |
2236 | 0 | if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED) { |
2237 | 0 | continue; |
2238 | 0 | } |
2239 | 0 | #if defined(__Userspace__) |
2240 | 0 | if (laddr->ifa->address.sa.sa_family == AF_CONN) { |
2241 | 0 | continue; |
2242 | 0 | } |
2243 | 0 | #endif |
2244 | 0 | if (sctp_is_address_in_scope(laddr->ifa, |
2245 | 0 | scope, 0) == 0) { |
2246 | 0 | continue; |
2247 | 0 | } |
2248 | 0 | if ((chunk_len != NULL) && |
2249 | 0 | (padding_len != NULL) && |
2250 | 0 | (*padding_len > 0)) { |
2251 | 0 | memset(mtod(m_at, caddr_t) + *chunk_len, 0, *padding_len); |
2252 | 0 | SCTP_BUF_LEN(m_at) += *padding_len; |
2253 | 0 | *chunk_len += *padding_len; |
2254 | 0 | *padding_len = 0; |
2255 | 0 | } |
2256 | 0 | m_at = sctp_add_addr_to_mbuf(m_at, laddr->ifa, chunk_len); |
2257 | 0 | cnt++; |
2258 | 0 | if (cnt >= SCTP_ADDRESS_LIMIT) { |
2259 | 0 | break; |
2260 | 0 | } |
2261 | 0 | } |
2262 | 0 | } |
2263 | 1.60k | } |
2264 | 1.60k | SCTP_IPI_ADDR_RUNLOCK(); |
2265 | 1.60k | return (m_at); |
2266 | 1.60k | } |
2267 | | |
2268 | | static struct sctp_ifa * |
2269 | | sctp_is_ifa_addr_preferred(struct sctp_ifa *ifa, |
2270 | | uint8_t dest_is_loop, |
2271 | | uint8_t dest_is_priv, |
2272 | | sa_family_t fam) |
2273 | 0 | { |
2274 | 0 | uint8_t dest_is_global = 0; |
2275 | | /* dest_is_priv is true if destination is a private address */ |
2276 | | /* dest_is_loop is true if destination is a loopback addresses */ |
2277 | | |
2278 | | /** |
2279 | | * Here we determine if its a preferred address. A preferred address |
2280 | | * means it is the same scope or higher scope then the destination. |
2281 | | * L = loopback, P = private, G = global |
2282 | | * ----------------------------------------- |
2283 | | * src | dest | result |
2284 | | * ---------------------------------------- |
2285 | | * L | L | yes |
2286 | | * ----------------------------------------- |
2287 | | * P | L | yes-v4 no-v6 |
2288 | | * ----------------------------------------- |
2289 | | * G | L | yes-v4 no-v6 |
2290 | | * ----------------------------------------- |
2291 | | * L | P | no |
2292 | | * ----------------------------------------- |
2293 | | * P | P | yes |
2294 | | * ----------------------------------------- |
2295 | | * G | P | no |
2296 | | * ----------------------------------------- |
2297 | | * L | G | no |
2298 | | * ----------------------------------------- |
2299 | | * P | G | no |
2300 | | * ----------------------------------------- |
2301 | | * G | G | yes |
2302 | | * ----------------------------------------- |
2303 | | */ |
2304 | |
|
2305 | 0 | if (ifa->address.sa.sa_family != fam) { |
2306 | | /* forget mis-matched family */ |
2307 | 0 | return (NULL); |
2308 | 0 | } |
2309 | 0 | if ((dest_is_priv == 0) && (dest_is_loop == 0)) { |
2310 | 0 | dest_is_global = 1; |
2311 | 0 | } |
2312 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2, "Is destination preferred:"); |
2313 | 0 | SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &ifa->address.sa); |
2314 | | /* Ok the address may be ok */ |
2315 | 0 | #ifdef INET6 |
2316 | 0 | if (fam == AF_INET6) { |
2317 | | /* ok to use deprecated addresses? no lets not! */ |
2318 | 0 | if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) { |
2319 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:1\n"); |
2320 | 0 | return (NULL); |
2321 | 0 | } |
2322 | 0 | if (ifa->src_is_priv && !ifa->src_is_loop) { |
2323 | 0 | if (dest_is_loop) { |
2324 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:2\n"); |
2325 | 0 | return (NULL); |
2326 | 0 | } |
2327 | 0 | } |
2328 | 0 | if (ifa->src_is_glob) { |
2329 | 0 | if (dest_is_loop) { |
2330 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:3\n"); |
2331 | 0 | return (NULL); |
2332 | 0 | } |
2333 | 0 | } |
2334 | 0 | } |
2335 | 0 | #endif |
2336 | | /* Now that we know what is what, implement or table |
2337 | | * this could in theory be done slicker (it used to be), but this |
2338 | | * is straightforward and easier to validate :-) |
2339 | | */ |
2340 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "src_loop:%d src_priv:%d src_glob:%d\n", |
2341 | 0 | ifa->src_is_loop, ifa->src_is_priv, ifa->src_is_glob); |
2342 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "dest_loop:%d dest_priv:%d dest_glob:%d\n", |
2343 | 0 | dest_is_loop, dest_is_priv, dest_is_global); |
2344 | |
|
2345 | 0 | if ((ifa->src_is_loop) && (dest_is_priv)) { |
2346 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:4\n"); |
2347 | 0 | return (NULL); |
2348 | 0 | } |
2349 | 0 | if ((ifa->src_is_glob) && (dest_is_priv)) { |
2350 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:5\n"); |
2351 | 0 | return (NULL); |
2352 | 0 | } |
2353 | 0 | if ((ifa->src_is_loop) && (dest_is_global)) { |
2354 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:6\n"); |
2355 | 0 | return (NULL); |
2356 | 0 | } |
2357 | 0 | if ((ifa->src_is_priv) && (dest_is_global)) { |
2358 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:7\n"); |
2359 | 0 | return (NULL); |
2360 | 0 | } |
2361 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "YES\n"); |
2362 | | /* its a preferred address */ |
2363 | 0 | return (ifa); |
2364 | 0 | } |
2365 | | |
2366 | | static struct sctp_ifa * |
2367 | | sctp_is_ifa_addr_acceptable(struct sctp_ifa *ifa, |
2368 | | uint8_t dest_is_loop, |
2369 | | uint8_t dest_is_priv, |
2370 | | sa_family_t fam) |
2371 | 0 | { |
2372 | 0 | uint8_t dest_is_global = 0; |
2373 | | |
2374 | | /** |
2375 | | * Here we determine if its a acceptable address. A acceptable |
2376 | | * address means it is the same scope or higher scope but we can |
2377 | | * allow for NAT which means its ok to have a global dest and a |
2378 | | * private src. |
2379 | | * |
2380 | | * L = loopback, P = private, G = global |
2381 | | * ----------------------------------------- |
2382 | | * src | dest | result |
2383 | | * ----------------------------------------- |
2384 | | * L | L | yes |
2385 | | * ----------------------------------------- |
2386 | | * P | L | yes-v4 no-v6 |
2387 | | * ----------------------------------------- |
2388 | | * G | L | yes |
2389 | | * ----------------------------------------- |
2390 | | * L | P | no |
2391 | | * ----------------------------------------- |
2392 | | * P | P | yes |
2393 | | * ----------------------------------------- |
2394 | | * G | P | yes - May not work |
2395 | | * ----------------------------------------- |
2396 | | * L | G | no |
2397 | | * ----------------------------------------- |
2398 | | * P | G | yes - May not work |
2399 | | * ----------------------------------------- |
2400 | | * G | G | yes |
2401 | | * ----------------------------------------- |
2402 | | */ |
2403 | |
|
2404 | 0 | if (ifa->address.sa.sa_family != fam) { |
2405 | | /* forget non matching family */ |
2406 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "ifa_fam:%d fam:%d\n", |
2407 | 0 | ifa->address.sa.sa_family, fam); |
2408 | 0 | return (NULL); |
2409 | 0 | } |
2410 | | /* Ok the address may be ok */ |
2411 | 0 | SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT3, &ifa->address.sa); |
2412 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "dst_is_loop:%d dest_is_priv:%d\n", |
2413 | 0 | dest_is_loop, dest_is_priv); |
2414 | 0 | if ((dest_is_loop == 0) && (dest_is_priv == 0)) { |
2415 | 0 | dest_is_global = 1; |
2416 | 0 | } |
2417 | 0 | #ifdef INET6 |
2418 | 0 | if (fam == AF_INET6) { |
2419 | | /* ok to use deprecated addresses? */ |
2420 | 0 | if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) { |
2421 | 0 | return (NULL); |
2422 | 0 | } |
2423 | 0 | if (ifa->src_is_priv) { |
2424 | | /* Special case, linklocal to loop */ |
2425 | 0 | if (dest_is_loop) |
2426 | 0 | return (NULL); |
2427 | 0 | } |
2428 | 0 | } |
2429 | 0 | #endif |
2430 | | /* |
2431 | | * Now that we know what is what, implement our table. |
2432 | | * This could in theory be done slicker (it used to be), but this |
2433 | | * is straightforward and easier to validate :-) |
2434 | | */ |
2435 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "ifa->src_is_loop:%d dest_is_priv:%d\n", |
2436 | 0 | ifa->src_is_loop, |
2437 | 0 | dest_is_priv); |
2438 | 0 | if ((ifa->src_is_loop == 1) && (dest_is_priv)) { |
2439 | 0 | return (NULL); |
2440 | 0 | } |
2441 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "ifa->src_is_loop:%d dest_is_glob:%d\n", |
2442 | 0 | ifa->src_is_loop, |
2443 | 0 | dest_is_global); |
2444 | 0 | if ((ifa->src_is_loop == 1) && (dest_is_global)) { |
2445 | 0 | return (NULL); |
2446 | 0 | } |
2447 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "address is acceptable\n"); |
2448 | | /* its an acceptable address */ |
2449 | 0 | return (ifa); |
2450 | 0 | } |
2451 | | |
2452 | | int |
2453 | | sctp_is_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa) |
2454 | 369k | { |
2455 | 369k | struct sctp_laddr *laddr; |
2456 | | |
2457 | 369k | if (stcb == NULL) { |
2458 | | /* There are no restrictions, no TCB :-) */ |
2459 | 0 | return (0); |
2460 | 0 | } |
2461 | 369k | LIST_FOREACH(laddr, &stcb->asoc.sctp_restricted_addrs, sctp_nxt_addr) { |
2462 | 0 | if (laddr->ifa == NULL) { |
2463 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n", |
2464 | 0 | __func__); |
2465 | 0 | continue; |
2466 | 0 | } |
2467 | 0 | if (laddr->ifa == ifa) { |
2468 | | /* Yes it is on the list */ |
2469 | 0 | return (1); |
2470 | 0 | } |
2471 | 0 | } |
2472 | 369k | return (0); |
2473 | 369k | } |
2474 | | |
2475 | | int |
2476 | | sctp_is_addr_in_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa) |
2477 | 0 | { |
2478 | 0 | struct sctp_laddr *laddr; |
2479 | |
|
2480 | 0 | if (ifa == NULL) |
2481 | 0 | return (0); |
2482 | 0 | LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { |
2483 | 0 | if (laddr->ifa == NULL) { |
2484 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n", |
2485 | 0 | __func__); |
2486 | 0 | continue; |
2487 | 0 | } |
2488 | 0 | if ((laddr->ifa == ifa) && laddr->action == 0) |
2489 | | /* same pointer */ |
2490 | 0 | return (1); |
2491 | 0 | } |
2492 | 0 | return (0); |
2493 | 0 | } |
2494 | | |
2495 | | static struct sctp_ifa * |
2496 | | sctp_choose_boundspecific_inp(struct sctp_inpcb *inp, |
2497 | | sctp_route_t *ro, |
2498 | | uint32_t vrf_id, |
2499 | | int non_asoc_addr_ok, |
2500 | | uint8_t dest_is_priv, |
2501 | | uint8_t dest_is_loop, |
2502 | | sa_family_t fam) |
2503 | 0 | { |
2504 | 0 | struct sctp_laddr *laddr, *starting_point; |
2505 | 0 | void *ifn; |
2506 | 0 | int resettotop = 0; |
2507 | 0 | struct sctp_ifn *sctp_ifn; |
2508 | 0 | struct sctp_ifa *sctp_ifa, *sifa; |
2509 | 0 | struct sctp_vrf *vrf; |
2510 | 0 | uint32_t ifn_index; |
2511 | |
|
2512 | 0 | vrf = sctp_find_vrf(vrf_id); |
2513 | 0 | if (vrf == NULL) |
2514 | 0 | return (NULL); |
2515 | | |
2516 | 0 | ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro); |
2517 | 0 | ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro); |
2518 | 0 | sctp_ifn = sctp_find_ifn(ifn, ifn_index); |
2519 | | /* |
2520 | | * first question, is the ifn we will emit on in our list, if so, we |
2521 | | * want such an address. Note that we first looked for a |
2522 | | * preferred address. |
2523 | | */ |
2524 | 0 | if (sctp_ifn) { |
2525 | | /* is a preferred one on the interface we route out? */ |
2526 | 0 | LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { |
2527 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
2528 | | #ifdef INET |
2529 | | if ((sctp_ifa->address.sa.sa_family == AF_INET) && |
2530 | | (prison_check_ip4(inp->ip_inp.inp.inp_cred, |
2531 | | &sctp_ifa->address.sin.sin_addr) != 0)) { |
2532 | | continue; |
2533 | | } |
2534 | | #endif |
2535 | | #ifdef INET6 |
2536 | | if ((sctp_ifa->address.sa.sa_family == AF_INET6) && |
2537 | | (prison_check_ip6(inp->ip_inp.inp.inp_cred, |
2538 | | &sctp_ifa->address.sin6.sin6_addr) != 0)) { |
2539 | | continue; |
2540 | | } |
2541 | | #endif |
2542 | | #endif |
2543 | 0 | if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && |
2544 | 0 | (non_asoc_addr_ok == 0)) |
2545 | 0 | continue; |
2546 | 0 | sifa = sctp_is_ifa_addr_preferred(sctp_ifa, |
2547 | 0 | dest_is_loop, |
2548 | 0 | dest_is_priv, fam); |
2549 | 0 | if (sifa == NULL) |
2550 | 0 | continue; |
2551 | 0 | if (sctp_is_addr_in_ep(inp, sifa)) { |
2552 | 0 | atomic_add_int(&sifa->refcount, 1); |
2553 | 0 | return (sifa); |
2554 | 0 | } |
2555 | 0 | } |
2556 | 0 | } |
2557 | | /* |
2558 | | * ok, now we now need to find one on the list of the addresses. |
2559 | | * We can't get one on the emitting interface so let's find first |
2560 | | * a preferred one. If not that an acceptable one otherwise... |
2561 | | * we return NULL. |
2562 | | */ |
2563 | 0 | starting_point = inp->next_addr_touse; |
2564 | 0 | once_again: |
2565 | 0 | if (inp->next_addr_touse == NULL) { |
2566 | 0 | inp->next_addr_touse = LIST_FIRST(&inp->sctp_addr_list); |
2567 | 0 | resettotop = 1; |
2568 | 0 | } |
2569 | 0 | for (laddr = inp->next_addr_touse; laddr; |
2570 | 0 | laddr = LIST_NEXT(laddr, sctp_nxt_addr)) { |
2571 | 0 | if (laddr->ifa == NULL) { |
2572 | | /* address has been removed */ |
2573 | 0 | continue; |
2574 | 0 | } |
2575 | 0 | if (laddr->action == SCTP_DEL_IP_ADDRESS) { |
2576 | | /* address is being deleted */ |
2577 | 0 | continue; |
2578 | 0 | } |
2579 | 0 | sifa = sctp_is_ifa_addr_preferred(laddr->ifa, dest_is_loop, |
2580 | 0 | dest_is_priv, fam); |
2581 | 0 | if (sifa == NULL) |
2582 | 0 | continue; |
2583 | 0 | atomic_add_int(&sifa->refcount, 1); |
2584 | 0 | return (sifa); |
2585 | 0 | } |
2586 | 0 | if (resettotop == 0) { |
2587 | 0 | inp->next_addr_touse = NULL; |
2588 | 0 | goto once_again; |
2589 | 0 | } |
2590 | | |
2591 | 0 | inp->next_addr_touse = starting_point; |
2592 | 0 | resettotop = 0; |
2593 | 0 | once_again_too: |
2594 | 0 | if (inp->next_addr_touse == NULL) { |
2595 | 0 | inp->next_addr_touse = LIST_FIRST(&inp->sctp_addr_list); |
2596 | 0 | resettotop = 1; |
2597 | 0 | } |
2598 | | |
2599 | | /* ok, what about an acceptable address in the inp */ |
2600 | 0 | for (laddr = inp->next_addr_touse; laddr; |
2601 | 0 | laddr = LIST_NEXT(laddr, sctp_nxt_addr)) { |
2602 | 0 | if (laddr->ifa == NULL) { |
2603 | | /* address has been removed */ |
2604 | 0 | continue; |
2605 | 0 | } |
2606 | 0 | if (laddr->action == SCTP_DEL_IP_ADDRESS) { |
2607 | | /* address is being deleted */ |
2608 | 0 | continue; |
2609 | 0 | } |
2610 | 0 | sifa = sctp_is_ifa_addr_acceptable(laddr->ifa, dest_is_loop, |
2611 | 0 | dest_is_priv, fam); |
2612 | 0 | if (sifa == NULL) |
2613 | 0 | continue; |
2614 | 0 | atomic_add_int(&sifa->refcount, 1); |
2615 | 0 | return (sifa); |
2616 | 0 | } |
2617 | 0 | if (resettotop == 0) { |
2618 | 0 | inp->next_addr_touse = NULL; |
2619 | 0 | goto once_again_too; |
2620 | 0 | } |
2621 | | |
2622 | | /* |
2623 | | * no address bound can be a source for the destination we are in |
2624 | | * trouble |
2625 | | */ |
2626 | 0 | return (NULL); |
2627 | 0 | } |
2628 | | |
2629 | | static struct sctp_ifa * |
2630 | | sctp_choose_boundspecific_stcb(struct sctp_inpcb *inp, |
2631 | | struct sctp_tcb *stcb, |
2632 | | sctp_route_t *ro, |
2633 | | uint32_t vrf_id, |
2634 | | uint8_t dest_is_priv, |
2635 | | uint8_t dest_is_loop, |
2636 | | int non_asoc_addr_ok, |
2637 | | sa_family_t fam) |
2638 | 0 | { |
2639 | 0 | struct sctp_laddr *laddr, *starting_point; |
2640 | 0 | void *ifn; |
2641 | 0 | struct sctp_ifn *sctp_ifn; |
2642 | 0 | struct sctp_ifa *sctp_ifa, *sifa; |
2643 | 0 | uint8_t start_at_beginning = 0; |
2644 | 0 | struct sctp_vrf *vrf; |
2645 | 0 | uint32_t ifn_index; |
2646 | | |
2647 | | /* |
2648 | | * first question, is the ifn we will emit on in our list, if so, we |
2649 | | * want that one. |
2650 | | */ |
2651 | 0 | vrf = sctp_find_vrf(vrf_id); |
2652 | 0 | if (vrf == NULL) |
2653 | 0 | return (NULL); |
2654 | | |
2655 | 0 | ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro); |
2656 | 0 | ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro); |
2657 | 0 | sctp_ifn = sctp_find_ifn(ifn, ifn_index); |
2658 | | |
2659 | | /* |
2660 | | * first question, is the ifn we will emit on in our list? If so, |
2661 | | * we want that one. First we look for a preferred. Second, we go |
2662 | | * for an acceptable. |
2663 | | */ |
2664 | 0 | if (sctp_ifn) { |
2665 | | /* first try for a preferred address on the ep */ |
2666 | 0 | LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { |
2667 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
2668 | | #ifdef INET |
2669 | | if ((sctp_ifa->address.sa.sa_family == AF_INET) && |
2670 | | (prison_check_ip4(inp->ip_inp.inp.inp_cred, |
2671 | | &sctp_ifa->address.sin.sin_addr) != 0)) { |
2672 | | continue; |
2673 | | } |
2674 | | #endif |
2675 | | #ifdef INET6 |
2676 | | if ((sctp_ifa->address.sa.sa_family == AF_INET6) && |
2677 | | (prison_check_ip6(inp->ip_inp.inp.inp_cred, |
2678 | | &sctp_ifa->address.sin6.sin6_addr) != 0)) { |
2679 | | continue; |
2680 | | } |
2681 | | #endif |
2682 | | #endif |
2683 | 0 | if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0)) |
2684 | 0 | continue; |
2685 | 0 | if (sctp_is_addr_in_ep(inp, sctp_ifa)) { |
2686 | 0 | sifa = sctp_is_ifa_addr_preferred(sctp_ifa, dest_is_loop, dest_is_priv, fam); |
2687 | 0 | if (sifa == NULL) |
2688 | 0 | continue; |
2689 | 0 | if (((non_asoc_addr_ok == 0) && |
2690 | 0 | (sctp_is_addr_restricted(stcb, sifa))) || |
2691 | 0 | (non_asoc_addr_ok && |
2692 | 0 | (sctp_is_addr_restricted(stcb, sifa)) && |
2693 | 0 | (!sctp_is_addr_pending(stcb, sifa)))) { |
2694 | | /* on the no-no list */ |
2695 | 0 | continue; |
2696 | 0 | } |
2697 | 0 | atomic_add_int(&sifa->refcount, 1); |
2698 | 0 | return (sifa); |
2699 | 0 | } |
2700 | 0 | } |
2701 | | /* next try for an acceptable address on the ep */ |
2702 | 0 | LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { |
2703 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
2704 | | #ifdef INET |
2705 | | if ((sctp_ifa->address.sa.sa_family == AF_INET) && |
2706 | | (prison_check_ip4(inp->ip_inp.inp.inp_cred, |
2707 | | &sctp_ifa->address.sin.sin_addr) != 0)) { |
2708 | | continue; |
2709 | | } |
2710 | | #endif |
2711 | | #ifdef INET6 |
2712 | | if ((sctp_ifa->address.sa.sa_family == AF_INET6) && |
2713 | | (prison_check_ip6(inp->ip_inp.inp.inp_cred, |
2714 | | &sctp_ifa->address.sin6.sin6_addr) != 0)) { |
2715 | | continue; |
2716 | | } |
2717 | | #endif |
2718 | | #endif |
2719 | 0 | if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0)) |
2720 | 0 | continue; |
2721 | 0 | if (sctp_is_addr_in_ep(inp, sctp_ifa)) { |
2722 | 0 | sifa= sctp_is_ifa_addr_acceptable(sctp_ifa, dest_is_loop, dest_is_priv,fam); |
2723 | 0 | if (sifa == NULL) |
2724 | 0 | continue; |
2725 | 0 | if (((non_asoc_addr_ok == 0) && |
2726 | 0 | (sctp_is_addr_restricted(stcb, sifa))) || |
2727 | 0 | (non_asoc_addr_ok && |
2728 | 0 | (sctp_is_addr_restricted(stcb, sifa)) && |
2729 | 0 | (!sctp_is_addr_pending(stcb, sifa)))) { |
2730 | | /* on the no-no list */ |
2731 | 0 | continue; |
2732 | 0 | } |
2733 | 0 | atomic_add_int(&sifa->refcount, 1); |
2734 | 0 | return (sifa); |
2735 | 0 | } |
2736 | 0 | } |
2737 | 0 | } |
2738 | | /* |
2739 | | * if we can't find one like that then we must look at all |
2740 | | * addresses bound to pick one at first preferable then |
2741 | | * secondly acceptable. |
2742 | | */ |
2743 | 0 | starting_point = stcb->asoc.last_used_address; |
2744 | 0 | sctp_from_the_top: |
2745 | 0 | if (stcb->asoc.last_used_address == NULL) { |
2746 | 0 | start_at_beginning = 1; |
2747 | 0 | stcb->asoc.last_used_address = LIST_FIRST(&inp->sctp_addr_list); |
2748 | 0 | } |
2749 | | /* search beginning with the last used address */ |
2750 | 0 | for (laddr = stcb->asoc.last_used_address; laddr; |
2751 | 0 | laddr = LIST_NEXT(laddr, sctp_nxt_addr)) { |
2752 | 0 | if (laddr->ifa == NULL) { |
2753 | | /* address has been removed */ |
2754 | 0 | continue; |
2755 | 0 | } |
2756 | 0 | if (laddr->action == SCTP_DEL_IP_ADDRESS) { |
2757 | | /* address is being deleted */ |
2758 | 0 | continue; |
2759 | 0 | } |
2760 | 0 | sifa = sctp_is_ifa_addr_preferred(laddr->ifa, dest_is_loop, dest_is_priv, fam); |
2761 | 0 | if (sifa == NULL) |
2762 | 0 | continue; |
2763 | 0 | if (((non_asoc_addr_ok == 0) && |
2764 | 0 | (sctp_is_addr_restricted(stcb, sifa))) || |
2765 | 0 | (non_asoc_addr_ok && |
2766 | 0 | (sctp_is_addr_restricted(stcb, sifa)) && |
2767 | 0 | (!sctp_is_addr_pending(stcb, sifa)))) { |
2768 | | /* on the no-no list */ |
2769 | 0 | continue; |
2770 | 0 | } |
2771 | 0 | stcb->asoc.last_used_address = laddr; |
2772 | 0 | atomic_add_int(&sifa->refcount, 1); |
2773 | 0 | return (sifa); |
2774 | 0 | } |
2775 | 0 | if (start_at_beginning == 0) { |
2776 | 0 | stcb->asoc.last_used_address = NULL; |
2777 | 0 | goto sctp_from_the_top; |
2778 | 0 | } |
2779 | | /* now try for any higher scope than the destination */ |
2780 | 0 | stcb->asoc.last_used_address = starting_point; |
2781 | 0 | start_at_beginning = 0; |
2782 | 0 | sctp_from_the_top2: |
2783 | 0 | if (stcb->asoc.last_used_address == NULL) { |
2784 | 0 | start_at_beginning = 1; |
2785 | 0 | stcb->asoc.last_used_address = LIST_FIRST(&inp->sctp_addr_list); |
2786 | 0 | } |
2787 | | /* search beginning with the last used address */ |
2788 | 0 | for (laddr = stcb->asoc.last_used_address; laddr; |
2789 | 0 | laddr = LIST_NEXT(laddr, sctp_nxt_addr)) { |
2790 | 0 | if (laddr->ifa == NULL) { |
2791 | | /* address has been removed */ |
2792 | 0 | continue; |
2793 | 0 | } |
2794 | 0 | if (laddr->action == SCTP_DEL_IP_ADDRESS) { |
2795 | | /* address is being deleted */ |
2796 | 0 | continue; |
2797 | 0 | } |
2798 | 0 | sifa = sctp_is_ifa_addr_acceptable(laddr->ifa, dest_is_loop, |
2799 | 0 | dest_is_priv, fam); |
2800 | 0 | if (sifa == NULL) |
2801 | 0 | continue; |
2802 | 0 | if (((non_asoc_addr_ok == 0) && |
2803 | 0 | (sctp_is_addr_restricted(stcb, sifa))) || |
2804 | 0 | (non_asoc_addr_ok && |
2805 | 0 | (sctp_is_addr_restricted(stcb, sifa)) && |
2806 | 0 | (!sctp_is_addr_pending(stcb, sifa)))) { |
2807 | | /* on the no-no list */ |
2808 | 0 | continue; |
2809 | 0 | } |
2810 | 0 | stcb->asoc.last_used_address = laddr; |
2811 | 0 | atomic_add_int(&sifa->refcount, 1); |
2812 | 0 | return (sifa); |
2813 | 0 | } |
2814 | 0 | if (start_at_beginning == 0) { |
2815 | 0 | stcb->asoc.last_used_address = NULL; |
2816 | 0 | goto sctp_from_the_top2; |
2817 | 0 | } |
2818 | 0 | return (NULL); |
2819 | 0 | } |
2820 | | |
2821 | | static struct sctp_ifa * |
2822 | | sctp_select_nth_preferred_addr_from_ifn_boundall(struct sctp_ifn *ifn, |
2823 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
2824 | | struct sctp_inpcb *inp, |
2825 | | #else |
2826 | | struct sctp_inpcb *inp SCTP_UNUSED, |
2827 | | #endif |
2828 | | struct sctp_tcb *stcb, |
2829 | | int non_asoc_addr_ok, |
2830 | | uint8_t dest_is_loop, |
2831 | | uint8_t dest_is_priv, |
2832 | | int addr_wanted, |
2833 | | sa_family_t fam, |
2834 | | sctp_route_t *ro) |
2835 | 0 | { |
2836 | 0 | struct sctp_ifa *ifa, *sifa; |
2837 | 0 | int num_eligible_addr = 0; |
2838 | 0 | #ifdef INET6 |
2839 | | #ifdef SCTP_EMBEDDED_V6_SCOPE |
2840 | | struct sockaddr_in6 sin6, lsa6; |
2841 | | |
2842 | | if (fam == AF_INET6) { |
2843 | | memcpy(&sin6, &ro->ro_dst, sizeof(struct sockaddr_in6)); |
2844 | | #ifdef SCTP_KAME |
2845 | | (void)sa6_recoverscope(&sin6); |
2846 | | #else |
2847 | | (void)in6_recoverscope(&sin6, &sin6.sin6_addr, NULL); |
2848 | | #endif /* SCTP_KAME */ |
2849 | | } |
2850 | | #endif /* SCTP_EMBEDDED_V6_SCOPE */ |
2851 | 0 | #endif /* INET6 */ |
2852 | 0 | LIST_FOREACH(ifa, &ifn->ifalist, next_ifa) { |
2853 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
2854 | | #ifdef INET |
2855 | | if ((ifa->address.sa.sa_family == AF_INET) && |
2856 | | (prison_check_ip4(inp->ip_inp.inp.inp_cred, |
2857 | | &ifa->address.sin.sin_addr) != 0)) { |
2858 | | continue; |
2859 | | } |
2860 | | #endif |
2861 | | #ifdef INET6 |
2862 | | if ((ifa->address.sa.sa_family == AF_INET6) && |
2863 | | (prison_check_ip6(inp->ip_inp.inp.inp_cred, |
2864 | | &ifa->address.sin6.sin6_addr) != 0)) { |
2865 | | continue; |
2866 | | } |
2867 | | #endif |
2868 | | #endif |
2869 | 0 | if ((ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && |
2870 | 0 | (non_asoc_addr_ok == 0)) |
2871 | 0 | continue; |
2872 | 0 | sifa = sctp_is_ifa_addr_preferred(ifa, dest_is_loop, |
2873 | 0 | dest_is_priv, fam); |
2874 | 0 | if (sifa == NULL) |
2875 | 0 | continue; |
2876 | 0 | #ifdef INET6 |
2877 | 0 | if (fam == AF_INET6 && |
2878 | 0 | dest_is_loop && |
2879 | 0 | sifa->src_is_loop && sifa->src_is_priv) { |
2880 | | /* don't allow fe80::1 to be a src on loop ::1, we don't list it |
2881 | | * to the peer so we will get an abort. |
2882 | | */ |
2883 | 0 | continue; |
2884 | 0 | } |
2885 | | #ifdef SCTP_EMBEDDED_V6_SCOPE |
2886 | | if (fam == AF_INET6 && |
2887 | | IN6_IS_ADDR_LINKLOCAL(&sifa->address.sin6.sin6_addr) && |
2888 | | IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) { |
2889 | | /* link-local <-> link-local must belong to the same scope. */ |
2890 | | memcpy(&lsa6, &sifa->address.sin6, sizeof(struct sockaddr_in6)); |
2891 | | #ifdef SCTP_KAME |
2892 | | (void)sa6_recoverscope(&lsa6); |
2893 | | #else |
2894 | | (void)in6_recoverscope(&lsa6, &lsa6.sin6_addr, NULL); |
2895 | | #endif /* SCTP_KAME */ |
2896 | | if (sin6.sin6_scope_id != lsa6.sin6_scope_id) { |
2897 | | continue; |
2898 | | } |
2899 | | } |
2900 | | #endif /* SCTP_EMBEDDED_V6_SCOPE */ |
2901 | 0 | #endif /* INET6 */ |
2902 | | |
2903 | 0 | #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__) |
2904 | | /* Check if the IPv6 address matches to next-hop. |
2905 | | In the mobile case, old IPv6 address may be not deleted |
2906 | | from the interface. Then, the interface has previous and |
2907 | | new addresses. We should use one corresponding to the |
2908 | | next-hop. (by micchie) |
2909 | | */ |
2910 | 0 | #ifdef INET6 |
2911 | 0 | if (stcb && fam == AF_INET6 && |
2912 | 0 | sctp_is_mobility_feature_on(stcb->sctp_ep, SCTP_MOBILITY_BASE)) { |
2913 | 0 | if (sctp_v6src_match_nexthop(&sifa->address.sin6, ro) == 0) { |
2914 | 0 | continue; |
2915 | 0 | } |
2916 | 0 | } |
2917 | 0 | #endif |
2918 | 0 | #ifdef INET |
2919 | | /* Avoid topologically incorrect IPv4 address */ |
2920 | 0 | if (stcb && fam == AF_INET && |
2921 | 0 | sctp_is_mobility_feature_on(stcb->sctp_ep, SCTP_MOBILITY_BASE)) { |
2922 | 0 | if (sctp_v4src_match_nexthop(sifa, ro) == 0) { |
2923 | 0 | continue; |
2924 | 0 | } |
2925 | 0 | } |
2926 | 0 | #endif |
2927 | 0 | #endif |
2928 | 0 | if (stcb) { |
2929 | 0 | if (sctp_is_address_in_scope(ifa, &stcb->asoc.scope, 0) == 0) { |
2930 | 0 | continue; |
2931 | 0 | } |
2932 | 0 | if (((non_asoc_addr_ok == 0) && |
2933 | 0 | (sctp_is_addr_restricted(stcb, sifa))) || |
2934 | 0 | (non_asoc_addr_ok && |
2935 | 0 | (sctp_is_addr_restricted(stcb, sifa)) && |
2936 | 0 | (!sctp_is_addr_pending(stcb, sifa)))) { |
2937 | | /* |
2938 | | * It is restricted for some reason.. |
2939 | | * probably not yet added. |
2940 | | */ |
2941 | 0 | continue; |
2942 | 0 | } |
2943 | 0 | } |
2944 | 0 | if (num_eligible_addr >= addr_wanted) { |
2945 | 0 | return (sifa); |
2946 | 0 | } |
2947 | 0 | num_eligible_addr++; |
2948 | 0 | } |
2949 | 0 | return (NULL); |
2950 | 0 | } |
2951 | | |
2952 | | static int |
2953 | | sctp_count_num_preferred_boundall(struct sctp_ifn *ifn, |
2954 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
2955 | | struct sctp_inpcb *inp, |
2956 | | #else |
2957 | | struct sctp_inpcb *inp SCTP_UNUSED, |
2958 | | #endif |
2959 | | struct sctp_tcb *stcb, |
2960 | | int non_asoc_addr_ok, |
2961 | | uint8_t dest_is_loop, |
2962 | | uint8_t dest_is_priv, |
2963 | | sa_family_t fam) |
2964 | 0 | { |
2965 | 0 | struct sctp_ifa *ifa, *sifa; |
2966 | 0 | int num_eligible_addr = 0; |
2967 | |
|
2968 | 0 | LIST_FOREACH(ifa, &ifn->ifalist, next_ifa) { |
2969 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
2970 | | #ifdef INET |
2971 | | if ((ifa->address.sa.sa_family == AF_INET) && |
2972 | | (prison_check_ip4(inp->ip_inp.inp.inp_cred, |
2973 | | &ifa->address.sin.sin_addr) != 0)) { |
2974 | | continue; |
2975 | | } |
2976 | | #endif |
2977 | | #ifdef INET6 |
2978 | | if ((ifa->address.sa.sa_family == AF_INET6) && |
2979 | | (stcb != NULL) && |
2980 | | (prison_check_ip6(inp->ip_inp.inp.inp_cred, |
2981 | | &ifa->address.sin6.sin6_addr) != 0)) { |
2982 | | continue; |
2983 | | } |
2984 | | #endif |
2985 | | #endif |
2986 | 0 | if ((ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && |
2987 | 0 | (non_asoc_addr_ok == 0)) { |
2988 | 0 | continue; |
2989 | 0 | } |
2990 | 0 | sifa = sctp_is_ifa_addr_preferred(ifa, dest_is_loop, |
2991 | 0 | dest_is_priv, fam); |
2992 | 0 | if (sifa == NULL) { |
2993 | 0 | continue; |
2994 | 0 | } |
2995 | 0 | if (stcb) { |
2996 | 0 | if (sctp_is_address_in_scope(ifa, &stcb->asoc.scope, 0) == 0) { |
2997 | 0 | continue; |
2998 | 0 | } |
2999 | 0 | if (((non_asoc_addr_ok == 0) && |
3000 | 0 | (sctp_is_addr_restricted(stcb, sifa))) || |
3001 | 0 | (non_asoc_addr_ok && |
3002 | 0 | (sctp_is_addr_restricted(stcb, sifa)) && |
3003 | 0 | (!sctp_is_addr_pending(stcb, sifa)))) { |
3004 | | /* |
3005 | | * It is restricted for some reason.. |
3006 | | * probably not yet added. |
3007 | | */ |
3008 | 0 | continue; |
3009 | 0 | } |
3010 | 0 | } |
3011 | 0 | num_eligible_addr++; |
3012 | 0 | } |
3013 | 0 | return (num_eligible_addr); |
3014 | 0 | } |
3015 | | |
3016 | | static struct sctp_ifa * |
3017 | | sctp_choose_boundall(struct sctp_inpcb *inp, |
3018 | | struct sctp_tcb *stcb, |
3019 | | struct sctp_nets *net, |
3020 | | sctp_route_t *ro, |
3021 | | uint32_t vrf_id, |
3022 | | uint8_t dest_is_priv, |
3023 | | uint8_t dest_is_loop, |
3024 | | int non_asoc_addr_ok, |
3025 | | sa_family_t fam) |
3026 | 0 | { |
3027 | 0 | int cur_addr_num = 0, num_preferred = 0; |
3028 | 0 | void *ifn; |
3029 | 0 | struct sctp_ifn *sctp_ifn, *looked_at = NULL, *emit_ifn; |
3030 | 0 | struct sctp_ifa *sctp_ifa, *sifa; |
3031 | 0 | uint32_t ifn_index; |
3032 | 0 | struct sctp_vrf *vrf; |
3033 | 0 | #ifdef INET |
3034 | 0 | int retried = 0; |
3035 | 0 | #endif |
3036 | | |
3037 | | /*- |
3038 | | * For boundall we can use any address in the association. |
3039 | | * If non_asoc_addr_ok is set we can use any address (at least in |
3040 | | * theory). So we look for preferred addresses first. If we find one, |
3041 | | * we use it. Otherwise we next try to get an address on the |
3042 | | * interface, which we should be able to do (unless non_asoc_addr_ok |
3043 | | * is false and we are routed out that way). In these cases where we |
3044 | | * can't use the address of the interface we go through all the |
3045 | | * ifn's looking for an address we can use and fill that in. Punting |
3046 | | * means we send back address 0, which will probably cause problems |
3047 | | * actually since then IP will fill in the address of the route ifn, |
3048 | | * which means we probably already rejected it.. i.e. here comes an |
3049 | | * abort :-<. |
3050 | | */ |
3051 | 0 | vrf = sctp_find_vrf(vrf_id); |
3052 | 0 | if (vrf == NULL) |
3053 | 0 | return (NULL); |
3054 | | |
3055 | 0 | ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro); |
3056 | 0 | ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro); |
3057 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2,"ifn from route:%p ifn_index:%d\n", ifn, ifn_index); |
3058 | 0 | emit_ifn = looked_at = sctp_ifn = sctp_find_ifn(ifn, ifn_index); |
3059 | 0 | if (sctp_ifn == NULL) { |
3060 | | /* ?? We don't have this guy ?? */ |
3061 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2,"No ifn emit interface?\n"); |
3062 | 0 | goto bound_all_plan_b; |
3063 | 0 | } |
3064 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2,"ifn_index:%d name:%s is emit interface\n", |
3065 | 0 | ifn_index, sctp_ifn->ifn_name); |
3066 | |
|
3067 | 0 | if (net) { |
3068 | 0 | cur_addr_num = net->indx_of_eligible_next_to_use; |
3069 | 0 | } |
3070 | 0 | num_preferred = sctp_count_num_preferred_boundall(sctp_ifn, |
3071 | 0 | inp, stcb, |
3072 | 0 | non_asoc_addr_ok, |
3073 | 0 | dest_is_loop, |
3074 | 0 | dest_is_priv, fam); |
3075 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2, "Found %d preferred source addresses for intf:%s\n", |
3076 | 0 | num_preferred, sctp_ifn->ifn_name); |
3077 | 0 | if (num_preferred == 0) { |
3078 | | /* |
3079 | | * no eligible addresses, we must use some other interface |
3080 | | * address if we can find one. |
3081 | | */ |
3082 | 0 | goto bound_all_plan_b; |
3083 | 0 | } |
3084 | | /* |
3085 | | * Ok we have num_eligible_addr set with how many we can use, this |
3086 | | * may vary from call to call due to addresses being deprecated |
3087 | | * etc.. |
3088 | | */ |
3089 | 0 | if (cur_addr_num >= num_preferred) { |
3090 | 0 | cur_addr_num = 0; |
3091 | 0 | } |
3092 | | /* |
3093 | | * select the nth address from the list (where cur_addr_num is the |
3094 | | * nth) and 0 is the first one, 1 is the second one etc... |
3095 | | */ |
3096 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2, "cur_addr_num:%d\n", cur_addr_num); |
3097 | |
|
3098 | 0 | sctp_ifa = sctp_select_nth_preferred_addr_from_ifn_boundall(sctp_ifn, inp, stcb, non_asoc_addr_ok, dest_is_loop, |
3099 | 0 | dest_is_priv, cur_addr_num, fam, ro); |
3100 | | |
3101 | | /* if sctp_ifa is NULL something changed??, fall to plan b. */ |
3102 | 0 | if (sctp_ifa) { |
3103 | 0 | atomic_add_int(&sctp_ifa->refcount, 1); |
3104 | 0 | if (net) { |
3105 | | /* save off where the next one we will want */ |
3106 | 0 | net->indx_of_eligible_next_to_use = cur_addr_num + 1; |
3107 | 0 | } |
3108 | 0 | return (sctp_ifa); |
3109 | 0 | } |
3110 | | /* |
3111 | | * plan_b: Look at all interfaces and find a preferred address. If |
3112 | | * no preferred fall through to plan_c. |
3113 | | */ |
3114 | 0 | bound_all_plan_b: |
3115 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2, "Trying Plan B\n"); |
3116 | 0 | LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { |
3117 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2, "Examine interface %s\n", |
3118 | 0 | sctp_ifn->ifn_name); |
3119 | 0 | if (dest_is_loop == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { |
3120 | | /* wrong base scope */ |
3121 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2, "skip\n"); |
3122 | 0 | continue; |
3123 | 0 | } |
3124 | 0 | if ((sctp_ifn == looked_at) && looked_at) { |
3125 | | /* already looked at this guy */ |
3126 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2, "already seen\n"); |
3127 | 0 | continue; |
3128 | 0 | } |
3129 | 0 | num_preferred = sctp_count_num_preferred_boundall(sctp_ifn, inp, stcb, non_asoc_addr_ok, |
3130 | 0 | dest_is_loop, dest_is_priv, fam); |
3131 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2, |
3132 | 0 | "Found ifn:%p %d preferred source addresses\n", |
3133 | 0 | ifn, num_preferred); |
3134 | 0 | if (num_preferred == 0) { |
3135 | | /* None on this interface. */ |
3136 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2, "No preferred -- skipping to next\n"); |
3137 | 0 | continue; |
3138 | 0 | } |
3139 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2, |
3140 | 0 | "num preferred:%d on interface:%p cur_addr_num:%d\n", |
3141 | 0 | num_preferred, (void *)sctp_ifn, cur_addr_num); |
3142 | | |
3143 | | /* |
3144 | | * Ok we have num_eligible_addr set with how many we can |
3145 | | * use, this may vary from call to call due to addresses |
3146 | | * being deprecated etc.. |
3147 | | */ |
3148 | 0 | if (cur_addr_num >= num_preferred) { |
3149 | 0 | cur_addr_num = 0; |
3150 | 0 | } |
3151 | 0 | sifa = sctp_select_nth_preferred_addr_from_ifn_boundall(sctp_ifn, inp, stcb, non_asoc_addr_ok, dest_is_loop, |
3152 | 0 | dest_is_priv, cur_addr_num, fam, ro); |
3153 | 0 | if (sifa == NULL) |
3154 | 0 | continue; |
3155 | 0 | if (net) { |
3156 | 0 | net->indx_of_eligible_next_to_use = cur_addr_num + 1; |
3157 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2, "we selected %d\n", |
3158 | 0 | cur_addr_num); |
3159 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2, "Source:"); |
3160 | 0 | SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &sifa->address.sa); |
3161 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2, "Dest:"); |
3162 | 0 | SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &net->ro._l_addr.sa); |
3163 | 0 | } |
3164 | 0 | atomic_add_int(&sifa->refcount, 1); |
3165 | 0 | return (sifa); |
3166 | 0 | } |
3167 | 0 | #ifdef INET |
3168 | 0 | again_with_private_addresses_allowed: |
3169 | 0 | #endif |
3170 | | /* plan_c: do we have an acceptable address on the emit interface */ |
3171 | 0 | sifa = NULL; |
3172 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2,"Trying Plan C: find acceptable on interface\n"); |
3173 | 0 | if (emit_ifn == NULL) { |
3174 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2,"Jump to Plan D - no emit_ifn\n"); |
3175 | 0 | goto plan_d; |
3176 | 0 | } |
3177 | 0 | LIST_FOREACH(sctp_ifa, &emit_ifn->ifalist, next_ifa) { |
3178 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2, "ifa:%p\n", (void *)sctp_ifa); |
3179 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
3180 | | #ifdef INET |
3181 | | if ((sctp_ifa->address.sa.sa_family == AF_INET) && |
3182 | | (prison_check_ip4(inp->ip_inp.inp.inp_cred, |
3183 | | &sctp_ifa->address.sin.sin_addr) != 0)) { |
3184 | | SCTPDBG(SCTP_DEBUG_OUTPUT2,"Jailed\n"); |
3185 | | continue; |
3186 | | } |
3187 | | #endif |
3188 | | #ifdef INET6 |
3189 | | if ((sctp_ifa->address.sa.sa_family == AF_INET6) && |
3190 | | (prison_check_ip6(inp->ip_inp.inp.inp_cred, |
3191 | | &sctp_ifa->address.sin6.sin6_addr) != 0)) { |
3192 | | SCTPDBG(SCTP_DEBUG_OUTPUT2,"Jailed\n"); |
3193 | | continue; |
3194 | | } |
3195 | | #endif |
3196 | | #endif |
3197 | 0 | if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && |
3198 | 0 | (non_asoc_addr_ok == 0)) { |
3199 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2,"Defer\n"); |
3200 | 0 | continue; |
3201 | 0 | } |
3202 | 0 | sifa = sctp_is_ifa_addr_acceptable(sctp_ifa, dest_is_loop, |
3203 | 0 | dest_is_priv, fam); |
3204 | 0 | if (sifa == NULL) { |
3205 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2, "IFA not acceptable\n"); |
3206 | 0 | continue; |
3207 | 0 | } |
3208 | 0 | if (stcb) { |
3209 | 0 | if (sctp_is_address_in_scope(sifa, &stcb->asoc.scope, 0) == 0) { |
3210 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2, "NOT in scope\n"); |
3211 | 0 | sifa = NULL; |
3212 | 0 | continue; |
3213 | 0 | } |
3214 | 0 | if (((non_asoc_addr_ok == 0) && |
3215 | 0 | (sctp_is_addr_restricted(stcb, sifa))) || |
3216 | 0 | (non_asoc_addr_ok && |
3217 | 0 | (sctp_is_addr_restricted(stcb, sifa)) && |
3218 | 0 | (!sctp_is_addr_pending(stcb, sifa)))) { |
3219 | | /* |
3220 | | * It is restricted for some |
3221 | | * reason.. probably not yet added. |
3222 | | */ |
3223 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2, "Its restricted\n"); |
3224 | 0 | sifa = NULL; |
3225 | 0 | continue; |
3226 | 0 | } |
3227 | 0 | } |
3228 | 0 | atomic_add_int(&sifa->refcount, 1); |
3229 | 0 | goto out; |
3230 | 0 | } |
3231 | 0 | plan_d: |
3232 | | /* |
3233 | | * plan_d: We are in trouble. No preferred address on the emit |
3234 | | * interface. And not even a preferred address on all interfaces. |
3235 | | * Go out and see if we can find an acceptable address somewhere |
3236 | | * amongst all interfaces. |
3237 | | */ |
3238 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2, "Trying Plan D looked_at is %p\n", (void *)looked_at); |
3239 | 0 | LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { |
3240 | 0 | if (dest_is_loop == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { |
3241 | | /* wrong base scope */ |
3242 | 0 | continue; |
3243 | 0 | } |
3244 | 0 | LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { |
3245 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
3246 | | #ifdef INET |
3247 | | if ((sctp_ifa->address.sa.sa_family == AF_INET) && |
3248 | | (prison_check_ip4(inp->ip_inp.inp.inp_cred, |
3249 | | &sctp_ifa->address.sin.sin_addr) != 0)) { |
3250 | | continue; |
3251 | | } |
3252 | | #endif |
3253 | | #ifdef INET6 |
3254 | | if ((sctp_ifa->address.sa.sa_family == AF_INET6) && |
3255 | | (prison_check_ip6(inp->ip_inp.inp.inp_cred, |
3256 | | &sctp_ifa->address.sin6.sin6_addr) != 0)) { |
3257 | | continue; |
3258 | | } |
3259 | | #endif |
3260 | | #endif |
3261 | 0 | if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && |
3262 | 0 | (non_asoc_addr_ok == 0)) |
3263 | 0 | continue; |
3264 | 0 | sifa = sctp_is_ifa_addr_acceptable(sctp_ifa, |
3265 | 0 | dest_is_loop, |
3266 | 0 | dest_is_priv, fam); |
3267 | 0 | if (sifa == NULL) |
3268 | 0 | continue; |
3269 | 0 | if (stcb) { |
3270 | 0 | if (sctp_is_address_in_scope(sifa, &stcb->asoc.scope, 0) == 0) { |
3271 | 0 | sifa = NULL; |
3272 | 0 | continue; |
3273 | 0 | } |
3274 | 0 | if (((non_asoc_addr_ok == 0) && |
3275 | 0 | (sctp_is_addr_restricted(stcb, sifa))) || |
3276 | 0 | (non_asoc_addr_ok && |
3277 | 0 | (sctp_is_addr_restricted(stcb, sifa)) && |
3278 | 0 | (!sctp_is_addr_pending(stcb, sifa)))) { |
3279 | | /* |
3280 | | * It is restricted for some |
3281 | | * reason.. probably not yet added. |
3282 | | */ |
3283 | 0 | sifa = NULL; |
3284 | 0 | continue; |
3285 | 0 | } |
3286 | 0 | } |
3287 | 0 | goto out; |
3288 | 0 | } |
3289 | 0 | } |
3290 | 0 | #ifdef INET |
3291 | 0 | if (stcb) { |
3292 | 0 | if ((retried == 0) && (stcb->asoc.scope.ipv4_local_scope == 0)) { |
3293 | 0 | stcb->asoc.scope.ipv4_local_scope = 1; |
3294 | 0 | retried = 1; |
3295 | 0 | goto again_with_private_addresses_allowed; |
3296 | 0 | } else if (retried == 1) { |
3297 | 0 | stcb->asoc.scope.ipv4_local_scope = 0; |
3298 | 0 | } |
3299 | 0 | } |
3300 | 0 | #endif |
3301 | 0 | out: |
3302 | 0 | #ifdef INET |
3303 | 0 | if (sifa) { |
3304 | 0 | if (retried == 1) { |
3305 | 0 | LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { |
3306 | 0 | if (dest_is_loop == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { |
3307 | | /* wrong base scope */ |
3308 | 0 | continue; |
3309 | 0 | } |
3310 | 0 | LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { |
3311 | 0 | struct sctp_ifa *tmp_sifa; |
3312 | |
|
3313 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
3314 | | #ifdef INET |
3315 | | if ((sctp_ifa->address.sa.sa_family == AF_INET) && |
3316 | | (prison_check_ip4(inp->ip_inp.inp.inp_cred, |
3317 | | &sctp_ifa->address.sin.sin_addr) != 0)) { |
3318 | | continue; |
3319 | | } |
3320 | | #endif |
3321 | | #ifdef INET6 |
3322 | | if ((sctp_ifa->address.sa.sa_family == AF_INET6) && |
3323 | | (prison_check_ip6(inp->ip_inp.inp.inp_cred, |
3324 | | &sctp_ifa->address.sin6.sin6_addr) != 0)) { |
3325 | | continue; |
3326 | | } |
3327 | | #endif |
3328 | | #endif |
3329 | 0 | if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && |
3330 | 0 | (non_asoc_addr_ok == 0)) |
3331 | 0 | continue; |
3332 | 0 | tmp_sifa = sctp_is_ifa_addr_acceptable(sctp_ifa, |
3333 | 0 | dest_is_loop, |
3334 | 0 | dest_is_priv, fam); |
3335 | 0 | if (tmp_sifa == NULL) { |
3336 | 0 | continue; |
3337 | 0 | } |
3338 | 0 | if (tmp_sifa == sifa) { |
3339 | 0 | continue; |
3340 | 0 | } |
3341 | 0 | if (stcb) { |
3342 | 0 | if (sctp_is_address_in_scope(tmp_sifa, |
3343 | 0 | &stcb->asoc.scope, 0) == 0) { |
3344 | 0 | continue; |
3345 | 0 | } |
3346 | 0 | if (((non_asoc_addr_ok == 0) && |
3347 | 0 | (sctp_is_addr_restricted(stcb, tmp_sifa))) || |
3348 | 0 | (non_asoc_addr_ok && |
3349 | 0 | (sctp_is_addr_restricted(stcb, tmp_sifa)) && |
3350 | 0 | (!sctp_is_addr_pending(stcb, tmp_sifa)))) { |
3351 | | /* |
3352 | | * It is restricted for some |
3353 | | * reason.. probably not yet added. |
3354 | | */ |
3355 | 0 | continue; |
3356 | 0 | } |
3357 | 0 | } |
3358 | 0 | if ((tmp_sifa->address.sin.sin_family == AF_INET) && |
3359 | 0 | (IN4_ISPRIVATE_ADDRESS(&(tmp_sifa->address.sin.sin_addr)))) { |
3360 | 0 | sctp_add_local_addr_restricted(stcb, tmp_sifa); |
3361 | 0 | } |
3362 | 0 | } |
3363 | 0 | } |
3364 | 0 | } |
3365 | 0 | atomic_add_int(&sifa->refcount, 1); |
3366 | 0 | } |
3367 | 0 | #endif |
3368 | 0 | return (sifa); |
3369 | 0 | } |
3370 | | |
3371 | | /* tcb may be NULL */ |
3372 | | struct sctp_ifa * |
3373 | | sctp_source_address_selection(struct sctp_inpcb *inp, |
3374 | | struct sctp_tcb *stcb, |
3375 | | sctp_route_t *ro, |
3376 | | struct sctp_nets *net, |
3377 | | int non_asoc_addr_ok, uint32_t vrf_id) |
3378 | 0 | { |
3379 | 0 | struct sctp_ifa *answer; |
3380 | 0 | uint8_t dest_is_priv, dest_is_loop; |
3381 | 0 | sa_family_t fam; |
3382 | 0 | #ifdef INET |
3383 | 0 | struct sockaddr_in *to = (struct sockaddr_in *)&ro->ro_dst; |
3384 | 0 | #endif |
3385 | 0 | #ifdef INET6 |
3386 | 0 | struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)&ro->ro_dst; |
3387 | 0 | #endif |
3388 | | |
3389 | | /** |
3390 | | * Rules: |
3391 | | * - Find the route if needed, cache if I can. |
3392 | | * - Look at interface address in route, Is it in the bound list. If so we |
3393 | | * have the best source. |
3394 | | * - If not we must rotate amongst the addresses. |
3395 | | * |
3396 | | * Caveats and issues |
3397 | | * |
3398 | | * Do we need to pay attention to scope. We can have a private address |
3399 | | * or a global address we are sourcing or sending to. So if we draw |
3400 | | * it out |
3401 | | * zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz |
3402 | | * For V4 |
3403 | | * ------------------------------------------ |
3404 | | * source * dest * result |
3405 | | * ----------------------------------------- |
3406 | | * <a> Private * Global * NAT |
3407 | | * ----------------------------------------- |
3408 | | * <b> Private * Private * No problem |
3409 | | * ----------------------------------------- |
3410 | | * <c> Global * Private * Huh, How will this work? |
3411 | | * ----------------------------------------- |
3412 | | * <d> Global * Global * No Problem |
3413 | | *------------------------------------------ |
3414 | | * zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz |
3415 | | * For V6 |
3416 | | *------------------------------------------ |
3417 | | * source * dest * result |
3418 | | * ----------------------------------------- |
3419 | | * <a> Linklocal * Global * |
3420 | | * ----------------------------------------- |
3421 | | * <b> Linklocal * Linklocal * No problem |
3422 | | * ----------------------------------------- |
3423 | | * <c> Global * Linklocal * Huh, How will this work? |
3424 | | * ----------------------------------------- |
3425 | | * <d> Global * Global * No Problem |
3426 | | *------------------------------------------ |
3427 | | * zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz |
3428 | | * |
3429 | | * And then we add to that what happens if there are multiple addresses |
3430 | | * assigned to an interface. Remember the ifa on a ifn is a linked |
3431 | | * list of addresses. So one interface can have more than one IP |
3432 | | * address. What happens if we have both a private and a global |
3433 | | * address? Do we then use context of destination to sort out which |
3434 | | * one is best? And what about NAT's sending P->G may get you a NAT |
3435 | | * translation, or should you select the G thats on the interface in |
3436 | | * preference. |
3437 | | * |
3438 | | * Decisions: |
3439 | | * |
3440 | | * - count the number of addresses on the interface. |
3441 | | * - if it is one, no problem except case <c>. |
3442 | | * For <a> we will assume a NAT out there. |
3443 | | * - if there are more than one, then we need to worry about scope P |
3444 | | * or G. We should prefer G -> G and P -> P if possible. |
3445 | | * Then as a secondary fall back to mixed types G->P being a last |
3446 | | * ditch one. |
3447 | | * - The above all works for bound all, but bound specific we need to |
3448 | | * use the same concept but instead only consider the bound |
3449 | | * addresses. If the bound set is NOT assigned to the interface then |
3450 | | * we must use rotation amongst the bound addresses.. |
3451 | | */ |
3452 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
3453 | | if (ro->ro_nh == NULL) { |
3454 | | #else |
3455 | 0 | if (ro->ro_rt == NULL) { |
3456 | 0 | #endif |
3457 | | /* |
3458 | | * Need a route to cache. |
3459 | | */ |
3460 | 0 | SCTP_RTALLOC(ro, vrf_id, inp->fibnum); |
3461 | 0 | } |
3462 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
3463 | | if (ro->ro_nh == NULL) { |
3464 | | #else |
3465 | 0 | if (ro->ro_rt == NULL) { |
3466 | 0 | #endif |
3467 | 0 | return (NULL); |
3468 | 0 | } |
3469 | | #if defined(_WIN32) |
3470 | | /* On Windows the sa_family is U_SHORT or ADDRESS_FAMILY */ |
3471 | | fam = (sa_family_t)ro->ro_dst.sa_family; |
3472 | | #else |
3473 | 0 | fam = ro->ro_dst.sa_family; |
3474 | 0 | #endif |
3475 | 0 | dest_is_priv = dest_is_loop = 0; |
3476 | | /* Setup our scopes for the destination */ |
3477 | 0 | switch (fam) { |
3478 | 0 | #ifdef INET |
3479 | 0 | case AF_INET: |
3480 | | /* Scope based on outbound address */ |
3481 | 0 | if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) { |
3482 | 0 | dest_is_loop = 1; |
3483 | 0 | if (net != NULL) { |
3484 | | /* mark it as local */ |
3485 | 0 | net->addr_is_local = 1; |
3486 | 0 | } |
3487 | 0 | } else if ((IN4_ISPRIVATE_ADDRESS(&to->sin_addr))) { |
3488 | 0 | dest_is_priv = 1; |
3489 | 0 | } |
3490 | 0 | break; |
3491 | 0 | #endif |
3492 | 0 | #ifdef INET6 |
3493 | 0 | case AF_INET6: |
3494 | | /* Scope based on outbound address */ |
3495 | | #if defined(_WIN32) |
3496 | | if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) { |
3497 | | #else |
3498 | 0 | if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr) || |
3499 | 0 | SCTP_ROUTE_IS_REAL_LOOP(ro)) { |
3500 | 0 | #endif |
3501 | | /* |
3502 | | * If the address is a loopback address, which |
3503 | | * consists of "::1" OR "fe80::1%lo0", we are loopback |
3504 | | * scope. But we don't use dest_is_priv (link local |
3505 | | * addresses). |
3506 | | */ |
3507 | 0 | dest_is_loop = 1; |
3508 | 0 | if (net != NULL) { |
3509 | | /* mark it as local */ |
3510 | 0 | net->addr_is_local = 1; |
3511 | 0 | } |
3512 | 0 | } else if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) { |
3513 | 0 | dest_is_priv = 1; |
3514 | 0 | } |
3515 | 0 | break; |
3516 | 0 | #endif |
3517 | 0 | } |
3518 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT2, "Select source addr for:"); |
3519 | 0 | SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)&ro->ro_dst); |
3520 | 0 | SCTP_IPI_ADDR_RLOCK(); |
3521 | 0 | if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { |
3522 | | /* |
3523 | | * Bound all case |
3524 | | */ |
3525 | 0 | answer = sctp_choose_boundall(inp, stcb, net, ro, vrf_id, |
3526 | 0 | dest_is_priv, dest_is_loop, |
3527 | 0 | non_asoc_addr_ok, fam); |
3528 | 0 | SCTP_IPI_ADDR_RUNLOCK(); |
3529 | 0 | return (answer); |
3530 | 0 | } |
3531 | | /* |
3532 | | * Subset bound case |
3533 | | */ |
3534 | 0 | if (stcb) { |
3535 | 0 | answer = sctp_choose_boundspecific_stcb(inp, stcb, ro, |
3536 | 0 | vrf_id, dest_is_priv, |
3537 | 0 | dest_is_loop, |
3538 | 0 | non_asoc_addr_ok, fam); |
3539 | 0 | } else { |
3540 | 0 | answer = sctp_choose_boundspecific_inp(inp, ro, vrf_id, |
3541 | 0 | non_asoc_addr_ok, |
3542 | 0 | dest_is_priv, |
3543 | 0 | dest_is_loop, fam); |
3544 | 0 | } |
3545 | 0 | SCTP_IPI_ADDR_RUNLOCK(); |
3546 | 0 | return (answer); |
3547 | 0 | } |
3548 | | |
3549 | | static bool |
3550 | | sctp_find_cmsg(int c_type, void *data, struct mbuf *control, size_t cpsize) |
3551 | 0 | { |
3552 | | #if defined(_WIN32) |
3553 | | WSACMSGHDR cmh; |
3554 | | #else |
3555 | 0 | struct cmsghdr cmh; |
3556 | 0 | #endif |
3557 | 0 | struct sctp_sndinfo sndinfo; |
3558 | 0 | struct sctp_prinfo prinfo; |
3559 | 0 | struct sctp_authinfo authinfo; |
3560 | 0 | int tot_len, rem_len, cmsg_data_len, cmsg_data_off, off; |
3561 | 0 | bool found; |
3562 | | |
3563 | | /* |
3564 | | * Independent of how many mbufs, find the c_type inside the control |
3565 | | * structure and copy out the data. |
3566 | | */ |
3567 | 0 | found = false; |
3568 | 0 | tot_len = SCTP_BUF_LEN(control); |
3569 | 0 | for (off = 0; off < tot_len; off += CMSG_ALIGN(cmh.cmsg_len)) { |
3570 | 0 | rem_len = tot_len - off; |
3571 | 0 | if (rem_len < (int)CMSG_ALIGN(sizeof(cmh))) { |
3572 | | /* There is not enough room for one more. */ |
3573 | 0 | return (found); |
3574 | 0 | } |
3575 | 0 | m_copydata(control, off, sizeof(cmh), (caddr_t)&cmh); |
3576 | 0 | if (cmh.cmsg_len < CMSG_ALIGN(sizeof(cmh))) { |
3577 | | /* We dont't have a complete CMSG header. */ |
3578 | 0 | return (found); |
3579 | 0 | } |
3580 | 0 | if ((cmh.cmsg_len > INT_MAX) || ((int)cmh.cmsg_len > rem_len)) { |
3581 | | /* We don't have the complete CMSG. */ |
3582 | 0 | return (found); |
3583 | 0 | } |
3584 | 0 | cmsg_data_len = (int)cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh)); |
3585 | 0 | cmsg_data_off = off + CMSG_ALIGN(sizeof(cmh)); |
3586 | 0 | if ((cmh.cmsg_level == IPPROTO_SCTP) && |
3587 | 0 | ((c_type == cmh.cmsg_type) || |
3588 | 0 | ((c_type == SCTP_SNDRCV) && |
3589 | 0 | ((cmh.cmsg_type == SCTP_SNDINFO) || |
3590 | 0 | (cmh.cmsg_type == SCTP_PRINFO) || |
3591 | 0 | (cmh.cmsg_type == SCTP_AUTHINFO))))) { |
3592 | 0 | if (c_type == cmh.cmsg_type) { |
3593 | 0 | if (cpsize > INT_MAX) { |
3594 | 0 | return (found); |
3595 | 0 | } |
3596 | 0 | if (cmsg_data_len < (int)cpsize) { |
3597 | 0 | return (found); |
3598 | 0 | } |
3599 | | /* It is exactly what we want. Copy it out. */ |
3600 | 0 | m_copydata(control, cmsg_data_off, (int)cpsize, (caddr_t)data); |
3601 | 0 | return (1); |
3602 | 0 | } else { |
3603 | 0 | struct sctp_sndrcvinfo *sndrcvinfo; |
3604 | |
|
3605 | 0 | sndrcvinfo = (struct sctp_sndrcvinfo *)data; |
3606 | 0 | if (!found) { |
3607 | 0 | if (cpsize < sizeof(struct sctp_sndrcvinfo)) { |
3608 | 0 | return (found); |
3609 | 0 | } |
3610 | 0 | memset(sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo)); |
3611 | 0 | } |
3612 | 0 | switch (cmh.cmsg_type) { |
3613 | 0 | case SCTP_SNDINFO: |
3614 | 0 | if (cmsg_data_len < (int)sizeof(struct sctp_sndinfo)) { |
3615 | 0 | return (found); |
3616 | 0 | } |
3617 | 0 | m_copydata(control, cmsg_data_off, sizeof(struct sctp_sndinfo), (caddr_t)&sndinfo); |
3618 | 0 | sndrcvinfo->sinfo_stream = sndinfo.snd_sid; |
3619 | 0 | sndrcvinfo->sinfo_flags = sndinfo.snd_flags; |
3620 | 0 | sndrcvinfo->sinfo_ppid = sndinfo.snd_ppid; |
3621 | 0 | sndrcvinfo->sinfo_context = sndinfo.snd_context; |
3622 | 0 | sndrcvinfo->sinfo_assoc_id = sndinfo.snd_assoc_id; |
3623 | 0 | break; |
3624 | 0 | case SCTP_PRINFO: |
3625 | 0 | if (cmsg_data_len < (int)sizeof(struct sctp_prinfo)) { |
3626 | 0 | return (found); |
3627 | 0 | } |
3628 | 0 | m_copydata(control, cmsg_data_off, sizeof(struct sctp_prinfo), (caddr_t)&prinfo); |
3629 | 0 | if (prinfo.pr_policy != SCTP_PR_SCTP_NONE) { |
3630 | 0 | sndrcvinfo->sinfo_timetolive = prinfo.pr_value; |
3631 | 0 | } else { |
3632 | 0 | sndrcvinfo->sinfo_timetolive = 0; |
3633 | 0 | } |
3634 | 0 | sndrcvinfo->sinfo_flags |= prinfo.pr_policy; |
3635 | 0 | break; |
3636 | 0 | case SCTP_AUTHINFO: |
3637 | 0 | if (cmsg_data_len < (int)sizeof(struct sctp_authinfo)) { |
3638 | 0 | return (found); |
3639 | 0 | } |
3640 | 0 | m_copydata(control, cmsg_data_off, sizeof(struct sctp_authinfo), (caddr_t)&authinfo); |
3641 | 0 | sndrcvinfo->sinfo_keynumber_valid = 1; |
3642 | 0 | sndrcvinfo->sinfo_keynumber = authinfo.auth_keynumber; |
3643 | 0 | break; |
3644 | 0 | default: |
3645 | 0 | return (found); |
3646 | 0 | } |
3647 | 0 | found = true; |
3648 | 0 | } |
3649 | 0 | } |
3650 | 0 | } |
3651 | 0 | return (found); |
3652 | 0 | } |
3653 | | |
3654 | | static int |
3655 | | sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *error) |
3656 | 0 | { |
3657 | | #if defined(_WIN32) |
3658 | | WSACMSGHDR cmh; |
3659 | | #else |
3660 | 0 | struct cmsghdr cmh; |
3661 | 0 | #endif |
3662 | 0 | struct sctp_initmsg initmsg; |
3663 | 0 | #ifdef INET |
3664 | 0 | struct sockaddr_in sin; |
3665 | 0 | #endif |
3666 | 0 | #ifdef INET6 |
3667 | 0 | struct sockaddr_in6 sin6; |
3668 | 0 | #endif |
3669 | 0 | int tot_len, rem_len, cmsg_data_len, cmsg_data_off, off; |
3670 | |
|
3671 | 0 | tot_len = SCTP_BUF_LEN(control); |
3672 | 0 | for (off = 0; off < tot_len; off += CMSG_ALIGN(cmh.cmsg_len)) { |
3673 | 0 | rem_len = tot_len - off; |
3674 | 0 | if (rem_len < (int)CMSG_ALIGN(sizeof(cmh))) { |
3675 | | /* There is not enough room for one more. */ |
3676 | 0 | *error = EINVAL; |
3677 | 0 | return (1); |
3678 | 0 | } |
3679 | 0 | m_copydata(control, off, sizeof(cmh), (caddr_t)&cmh); |
3680 | 0 | if (cmh.cmsg_len < CMSG_ALIGN(sizeof(cmh))) { |
3681 | | /* We dont't have a complete CMSG header. */ |
3682 | 0 | *error = EINVAL; |
3683 | 0 | return (1); |
3684 | 0 | } |
3685 | 0 | if ((cmh.cmsg_len > INT_MAX) || ((int)cmh.cmsg_len > rem_len)) { |
3686 | | /* We don't have the complete CMSG. */ |
3687 | 0 | *error = EINVAL; |
3688 | 0 | return (1); |
3689 | 0 | } |
3690 | 0 | cmsg_data_len = (int)cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh)); |
3691 | 0 | cmsg_data_off = off + CMSG_ALIGN(sizeof(cmh)); |
3692 | 0 | if (cmh.cmsg_level == IPPROTO_SCTP) { |
3693 | 0 | switch (cmh.cmsg_type) { |
3694 | 0 | case SCTP_INIT: |
3695 | 0 | if (cmsg_data_len < (int)sizeof(struct sctp_initmsg)) { |
3696 | 0 | *error = EINVAL; |
3697 | 0 | return (1); |
3698 | 0 | } |
3699 | 0 | m_copydata(control, cmsg_data_off, sizeof(struct sctp_initmsg), (caddr_t)&initmsg); |
3700 | 0 | if (initmsg.sinit_max_attempts) |
3701 | 0 | stcb->asoc.max_init_times = initmsg.sinit_max_attempts; |
3702 | 0 | if (initmsg.sinit_num_ostreams) |
3703 | 0 | stcb->asoc.pre_open_streams = initmsg.sinit_num_ostreams; |
3704 | 0 | if (initmsg.sinit_max_instreams) |
3705 | 0 | stcb->asoc.max_inbound_streams = initmsg.sinit_max_instreams; |
3706 | 0 | if (initmsg.sinit_max_init_timeo) |
3707 | 0 | stcb->asoc.initial_init_rto_max = initmsg.sinit_max_init_timeo; |
3708 | 0 | if (stcb->asoc.streamoutcnt < stcb->asoc.pre_open_streams) { |
3709 | 0 | struct sctp_stream_out *tmp_str; |
3710 | 0 | unsigned int i; |
3711 | | #if defined(SCTP_DETAILED_STR_STATS) |
3712 | | int j; |
3713 | | #endif |
3714 | | |
3715 | | /* Default is NOT correct */ |
3716 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Ok, default:%d pre_open:%d\n", |
3717 | 0 | stcb->asoc.streamoutcnt, stcb->asoc.pre_open_streams); |
3718 | 0 | SCTP_TCB_UNLOCK(stcb); |
3719 | 0 | SCTP_MALLOC(tmp_str, |
3720 | 0 | struct sctp_stream_out *, |
3721 | 0 | (stcb->asoc.pre_open_streams * sizeof(struct sctp_stream_out)), |
3722 | 0 | SCTP_M_STRMO); |
3723 | 0 | SCTP_TCB_LOCK(stcb); |
3724 | 0 | if (tmp_str != NULL) { |
3725 | 0 | SCTP_FREE(stcb->asoc.strmout, SCTP_M_STRMO); |
3726 | 0 | stcb->asoc.strmout = tmp_str; |
3727 | 0 | stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt = stcb->asoc.pre_open_streams; |
3728 | 0 | } else { |
3729 | 0 | stcb->asoc.pre_open_streams = stcb->asoc.streamoutcnt; |
3730 | 0 | } |
3731 | 0 | for (i = 0; i < stcb->asoc.streamoutcnt; i++) { |
3732 | 0 | TAILQ_INIT(&stcb->asoc.strmout[i].outqueue); |
3733 | 0 | stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], NULL); |
3734 | 0 | stcb->asoc.strmout[i].chunks_on_queues = 0; |
3735 | | #if defined(SCTP_DETAILED_STR_STATS) |
3736 | | for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) { |
3737 | | stcb->asoc.strmout[i].abandoned_sent[j] = 0; |
3738 | | stcb->asoc.strmout[i].abandoned_unsent[j] = 0; |
3739 | | } |
3740 | | #else |
3741 | 0 | stcb->asoc.strmout[i].abandoned_sent[0] = 0; |
3742 | 0 | stcb->asoc.strmout[i].abandoned_unsent[0] = 0; |
3743 | 0 | #endif |
3744 | 0 | stcb->asoc.strmout[i].next_mid_ordered = 0; |
3745 | 0 | stcb->asoc.strmout[i].next_mid_unordered = 0; |
3746 | 0 | stcb->asoc.strmout[i].sid = i; |
3747 | 0 | stcb->asoc.strmout[i].last_msg_incomplete = 0; |
3748 | 0 | stcb->asoc.strmout[i].state = SCTP_STREAM_OPENING; |
3749 | 0 | } |
3750 | 0 | } |
3751 | 0 | break; |
3752 | 0 | #ifdef INET |
3753 | 0 | case SCTP_DSTADDRV4: |
3754 | 0 | if (cmsg_data_len < (int)sizeof(struct in_addr)) { |
3755 | 0 | *error = EINVAL; |
3756 | 0 | return (1); |
3757 | 0 | } |
3758 | 0 | memset(&sin, 0, sizeof(struct sockaddr_in)); |
3759 | 0 | sin.sin_family = AF_INET; |
3760 | | #ifdef HAVE_SIN_LEN |
3761 | | sin.sin_len = sizeof(struct sockaddr_in); |
3762 | | #endif |
3763 | 0 | sin.sin_port = stcb->rport; |
3764 | 0 | m_copydata(control, cmsg_data_off, sizeof(struct in_addr), (caddr_t)&sin.sin_addr); |
3765 | 0 | if (in_broadcast(sin.sin_addr) || |
3766 | 0 | IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) { |
3767 | 0 | *error = EINVAL; |
3768 | 0 | return (1); |
3769 | 0 | } |
3770 | 0 | if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL, stcb->asoc.port, |
3771 | 0 | SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { |
3772 | 0 | *error = ENOBUFS; |
3773 | 0 | return (1); |
3774 | 0 | } |
3775 | 0 | break; |
3776 | 0 | #endif |
3777 | 0 | #ifdef INET6 |
3778 | 0 | case SCTP_DSTADDRV6: |
3779 | 0 | if (cmsg_data_len < (int)sizeof(struct in6_addr)) { |
3780 | 0 | *error = EINVAL; |
3781 | 0 | return (1); |
3782 | 0 | } |
3783 | 0 | memset(&sin6, 0, sizeof(struct sockaddr_in6)); |
3784 | 0 | sin6.sin6_family = AF_INET6; |
3785 | | #ifdef HAVE_SIN6_LEN |
3786 | | sin6.sin6_len = sizeof(struct sockaddr_in6); |
3787 | | #endif |
3788 | 0 | sin6.sin6_port = stcb->rport; |
3789 | 0 | m_copydata(control, cmsg_data_off, sizeof(struct in6_addr), (caddr_t)&sin6.sin6_addr); |
3790 | 0 | if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr) || |
3791 | 0 | IN6_IS_ADDR_MULTICAST(&sin6.sin6_addr)) { |
3792 | 0 | *error = EINVAL; |
3793 | 0 | return (1); |
3794 | 0 | } |
3795 | 0 | #ifdef INET |
3796 | 0 | if (IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) { |
3797 | 0 | in6_sin6_2_sin(&sin, &sin6); |
3798 | 0 | if (in_broadcast(sin.sin_addr) || |
3799 | 0 | IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) { |
3800 | 0 | *error = EINVAL; |
3801 | 0 | return (1); |
3802 | 0 | } |
3803 | 0 | if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL, stcb->asoc.port, |
3804 | 0 | SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { |
3805 | 0 | *error = ENOBUFS; |
3806 | 0 | return (1); |
3807 | 0 | } |
3808 | 0 | } else |
3809 | 0 | #endif |
3810 | 0 | if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin6, NULL, stcb->asoc.port, |
3811 | 0 | SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { |
3812 | 0 | *error = ENOBUFS; |
3813 | 0 | return (1); |
3814 | 0 | } |
3815 | 0 | break; |
3816 | 0 | #endif |
3817 | 0 | default: |
3818 | 0 | break; |
3819 | 0 | } |
3820 | 0 | } |
3821 | 0 | } |
3822 | 0 | return (0); |
3823 | 0 | } |
3824 | | |
3825 | | #if defined(INET) || defined(INET6) |
3826 | | static struct sctp_tcb * |
3827 | | sctp_findassociation_cmsgs(struct sctp_inpcb **inp_p, |
3828 | | uint16_t port, |
3829 | | struct mbuf *control, |
3830 | | struct sctp_nets **net_p, |
3831 | | int *error) |
3832 | 0 | { |
3833 | | #if defined(_WIN32) |
3834 | | WSACMSGHDR cmh; |
3835 | | #else |
3836 | 0 | struct cmsghdr cmh; |
3837 | 0 | #endif |
3838 | 0 | struct sctp_tcb *stcb; |
3839 | 0 | struct sockaddr *addr; |
3840 | 0 | #ifdef INET |
3841 | 0 | struct sockaddr_in sin; |
3842 | 0 | #endif |
3843 | 0 | #ifdef INET6 |
3844 | 0 | struct sockaddr_in6 sin6; |
3845 | 0 | #endif |
3846 | 0 | int tot_len, rem_len, cmsg_data_len, cmsg_data_off, off; |
3847 | |
|
3848 | 0 | tot_len = SCTP_BUF_LEN(control); |
3849 | 0 | for (off = 0; off < tot_len; off += CMSG_ALIGN(cmh.cmsg_len)) { |
3850 | 0 | rem_len = tot_len - off; |
3851 | 0 | if (rem_len < (int)CMSG_ALIGN(sizeof(cmh))) { |
3852 | | /* There is not enough room for one more. */ |
3853 | 0 | *error = EINVAL; |
3854 | 0 | return (NULL); |
3855 | 0 | } |
3856 | 0 | m_copydata(control, off, sizeof(cmh), (caddr_t)&cmh); |
3857 | 0 | if (cmh.cmsg_len < CMSG_ALIGN(sizeof(cmh))) { |
3858 | | /* We dont't have a complete CMSG header. */ |
3859 | 0 | *error = EINVAL; |
3860 | 0 | return (NULL); |
3861 | 0 | } |
3862 | 0 | if ((cmh.cmsg_len > INT_MAX) || ((int)cmh.cmsg_len > rem_len)) { |
3863 | | /* We don't have the complete CMSG. */ |
3864 | 0 | *error = EINVAL; |
3865 | 0 | return (NULL); |
3866 | 0 | } |
3867 | 0 | cmsg_data_len = (int)cmh.cmsg_len - CMSG_ALIGN(sizeof(cmh)); |
3868 | 0 | cmsg_data_off = off + CMSG_ALIGN(sizeof(cmh)); |
3869 | 0 | if (cmh.cmsg_level == IPPROTO_SCTP) { |
3870 | 0 | switch (cmh.cmsg_type) { |
3871 | 0 | #ifdef INET |
3872 | 0 | case SCTP_DSTADDRV4: |
3873 | 0 | if (cmsg_data_len < (int)sizeof(struct in_addr)) { |
3874 | 0 | *error = EINVAL; |
3875 | 0 | return (NULL); |
3876 | 0 | } |
3877 | 0 | memset(&sin, 0, sizeof(struct sockaddr_in)); |
3878 | 0 | sin.sin_family = AF_INET; |
3879 | | #ifdef HAVE_SIN_LEN |
3880 | | sin.sin_len = sizeof(struct sockaddr_in); |
3881 | | #endif |
3882 | 0 | sin.sin_port = port; |
3883 | 0 | m_copydata(control, cmsg_data_off, sizeof(struct in_addr), (caddr_t)&sin.sin_addr); |
3884 | 0 | addr = (struct sockaddr *)&sin; |
3885 | 0 | break; |
3886 | 0 | #endif |
3887 | 0 | #ifdef INET6 |
3888 | 0 | case SCTP_DSTADDRV6: |
3889 | 0 | if (cmsg_data_len < (int)sizeof(struct in6_addr)) { |
3890 | 0 | *error = EINVAL; |
3891 | 0 | return (NULL); |
3892 | 0 | } |
3893 | 0 | memset(&sin6, 0, sizeof(struct sockaddr_in6)); |
3894 | 0 | sin6.sin6_family = AF_INET6; |
3895 | | #ifdef HAVE_SIN6_LEN |
3896 | | sin6.sin6_len = sizeof(struct sockaddr_in6); |
3897 | | #endif |
3898 | 0 | sin6.sin6_port = port; |
3899 | 0 | m_copydata(control, cmsg_data_off, sizeof(struct in6_addr), (caddr_t)&sin6.sin6_addr); |
3900 | 0 | #ifdef INET |
3901 | 0 | if (IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) { |
3902 | 0 | in6_sin6_2_sin(&sin, &sin6); |
3903 | 0 | addr = (struct sockaddr *)&sin; |
3904 | 0 | } else |
3905 | 0 | #endif |
3906 | 0 | addr = (struct sockaddr *)&sin6; |
3907 | 0 | break; |
3908 | 0 | #endif |
3909 | 0 | default: |
3910 | 0 | addr = NULL; |
3911 | 0 | break; |
3912 | 0 | } |
3913 | 0 | if (addr) { |
3914 | 0 | stcb = sctp_findassociation_ep_addr(inp_p, addr, net_p, NULL, NULL); |
3915 | 0 | if (stcb != NULL) { |
3916 | 0 | return (stcb); |
3917 | 0 | } |
3918 | 0 | } |
3919 | 0 | } |
3920 | 0 | } |
3921 | 0 | return (NULL); |
3922 | 0 | } |
3923 | | #endif |
3924 | | |
3925 | | static struct mbuf * |
3926 | | sctp_add_cookie(struct mbuf *init, int init_offset, |
3927 | | struct mbuf *initack, int initack_offset, struct sctp_state_cookie *stc_in, uint8_t **signature) |
3928 | 0 | { |
3929 | 0 | struct mbuf *copy_init, *copy_initack, *m_at, *sig, *mret; |
3930 | 0 | struct sctp_state_cookie *stc; |
3931 | 0 | struct sctp_paramhdr *ph; |
3932 | 0 | uint16_t cookie_sz; |
3933 | |
|
3934 | 0 | mret = sctp_get_mbuf_for_msg((sizeof(struct sctp_state_cookie) + |
3935 | 0 | sizeof(struct sctp_paramhdr)), 0, |
3936 | 0 | M_NOWAIT, 1, MT_DATA); |
3937 | 0 | if (mret == NULL) { |
3938 | 0 | return (NULL); |
3939 | 0 | } |
3940 | 0 | copy_init = SCTP_M_COPYM(init, init_offset, M_COPYALL, M_NOWAIT); |
3941 | 0 | if (copy_init == NULL) { |
3942 | 0 | sctp_m_freem(mret); |
3943 | 0 | return (NULL); |
3944 | 0 | } |
3945 | | #ifdef SCTP_MBUF_LOGGING |
3946 | | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { |
3947 | | sctp_log_mbc(copy_init, SCTP_MBUF_ICOPY); |
3948 | | } |
3949 | | #endif |
3950 | 0 | copy_initack = SCTP_M_COPYM(initack, initack_offset, M_COPYALL, |
3951 | 0 | M_NOWAIT); |
3952 | 0 | if (copy_initack == NULL) { |
3953 | 0 | sctp_m_freem(mret); |
3954 | 0 | sctp_m_freem(copy_init); |
3955 | 0 | return (NULL); |
3956 | 0 | } |
3957 | | #ifdef SCTP_MBUF_LOGGING |
3958 | | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { |
3959 | | sctp_log_mbc(copy_initack, SCTP_MBUF_ICOPY); |
3960 | | } |
3961 | | #endif |
3962 | | /* easy side we just drop it on the end */ |
3963 | 0 | ph = mtod(mret, struct sctp_paramhdr *); |
3964 | 0 | SCTP_BUF_LEN(mret) = sizeof(struct sctp_state_cookie) + |
3965 | 0 | sizeof(struct sctp_paramhdr); |
3966 | 0 | stc = (struct sctp_state_cookie *)((caddr_t)ph + |
3967 | 0 | sizeof(struct sctp_paramhdr)); |
3968 | 0 | ph->param_type = htons(SCTP_STATE_COOKIE); |
3969 | 0 | ph->param_length = 0; /* fill in at the end */ |
3970 | | /* Fill in the stc cookie data */ |
3971 | 0 | memcpy(stc, stc_in, sizeof(struct sctp_state_cookie)); |
3972 | | |
3973 | | /* tack the INIT and then the INIT-ACK onto the chain */ |
3974 | 0 | cookie_sz = 0; |
3975 | 0 | for (m_at = mret; m_at; m_at = SCTP_BUF_NEXT(m_at)) { |
3976 | 0 | cookie_sz += SCTP_BUF_LEN(m_at); |
3977 | 0 | if (SCTP_BUF_NEXT(m_at) == NULL) { |
3978 | 0 | SCTP_BUF_NEXT(m_at) = copy_init; |
3979 | 0 | break; |
3980 | 0 | } |
3981 | 0 | } |
3982 | 0 | for (m_at = copy_init; m_at; m_at = SCTP_BUF_NEXT(m_at)) { |
3983 | 0 | cookie_sz += SCTP_BUF_LEN(m_at); |
3984 | 0 | if (SCTP_BUF_NEXT(m_at) == NULL) { |
3985 | 0 | SCTP_BUF_NEXT(m_at) = copy_initack; |
3986 | 0 | break; |
3987 | 0 | } |
3988 | 0 | } |
3989 | 0 | for (m_at = copy_initack; m_at; m_at = SCTP_BUF_NEXT(m_at)) { |
3990 | 0 | cookie_sz += SCTP_BUF_LEN(m_at); |
3991 | 0 | if (SCTP_BUF_NEXT(m_at) == NULL) { |
3992 | 0 | break; |
3993 | 0 | } |
3994 | 0 | } |
3995 | 0 | sig = sctp_get_mbuf_for_msg(SCTP_SIGNATURE_SIZE, 0, M_NOWAIT, 1, MT_DATA); |
3996 | 0 | if (sig == NULL) { |
3997 | | /* no space, so free the entire chain */ |
3998 | 0 | sctp_m_freem(mret); |
3999 | 0 | return (NULL); |
4000 | 0 | } |
4001 | 0 | SCTP_BUF_NEXT(m_at) = sig; |
4002 | 0 | SCTP_BUF_LEN(sig) = SCTP_SIGNATURE_SIZE; |
4003 | 0 | cookie_sz += SCTP_SIGNATURE_SIZE; |
4004 | 0 | ph->param_length = htons(cookie_sz); |
4005 | 0 | *signature = (uint8_t *)mtod(sig, caddr_t); |
4006 | 0 | memset(*signature, 0, SCTP_SIGNATURE_SIZE); |
4007 | 0 | return (mret); |
4008 | 0 | } |
4009 | | |
4010 | | static uint8_t |
4011 | | sctp_get_ect(struct sctp_tcb *stcb) |
4012 | 4.32k | { |
4013 | 4.32k | if ((stcb != NULL) && (stcb->asoc.ecn_supported == 1)) { |
4014 | 4.32k | return (SCTP_ECT0_BIT); |
4015 | 4.32k | } else { |
4016 | 0 | return (0); |
4017 | 0 | } |
4018 | 4.32k | } |
4019 | | |
4020 | | #if defined(INET) || defined(INET6) |
4021 | | static void |
4022 | | sctp_handle_no_route(struct sctp_tcb *stcb, |
4023 | | struct sctp_nets *net, |
4024 | | int so_locked) |
4025 | 0 | { |
4026 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "dropped packet - no valid source addr\n"); |
4027 | |
|
4028 | 0 | if (net) { |
4029 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Destination was "); |
4030 | 0 | SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT1, &net->ro._l_addr.sa); |
4031 | 0 | if (net->dest_state & SCTP_ADDR_CONFIRMED) { |
4032 | 0 | if ((net->dest_state & SCTP_ADDR_REACHABLE) && stcb) { |
4033 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "no route takes interface %p down\n", (void *)net); |
4034 | 0 | sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, |
4035 | 0 | stcb, 0, |
4036 | 0 | (void *)net, |
4037 | 0 | so_locked); |
4038 | 0 | net->dest_state &= ~SCTP_ADDR_REACHABLE; |
4039 | 0 | net->dest_state &= ~SCTP_ADDR_PF; |
4040 | 0 | } |
4041 | 0 | } |
4042 | 0 | if (stcb) { |
4043 | 0 | if (net == stcb->asoc.primary_destination) { |
4044 | | /* need a new primary */ |
4045 | 0 | struct sctp_nets *alt; |
4046 | |
|
4047 | 0 | alt = sctp_find_alternate_net(stcb, net, 0); |
4048 | 0 | if (alt != net) { |
4049 | 0 | if (stcb->asoc.alternate) { |
4050 | 0 | sctp_free_remote_addr(stcb->asoc.alternate); |
4051 | 0 | } |
4052 | 0 | stcb->asoc.alternate = alt; |
4053 | 0 | atomic_add_int(&stcb->asoc.alternate->ref_count, 1); |
4054 | 0 | if (net->ro._s_addr) { |
4055 | 0 | sctp_free_ifa(net->ro._s_addr); |
4056 | 0 | net->ro._s_addr = NULL; |
4057 | 0 | } |
4058 | 0 | net->src_addr_selected = 0; |
4059 | 0 | } |
4060 | 0 | } |
4061 | 0 | } |
4062 | 0 | } |
4063 | 0 | } |
4064 | | #endif |
4065 | | |
4066 | | static int |
4067 | | sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, |
4068 | | struct sctp_tcb *stcb, /* may be NULL */ |
4069 | | struct sctp_nets *net, |
4070 | | struct sockaddr *to, |
4071 | | struct mbuf *m, |
4072 | | uint32_t auth_offset, |
4073 | | struct sctp_auth_chunk *auth, |
4074 | | uint16_t auth_keyid, |
4075 | | int nofragment_flag, |
4076 | | int ecn_ok, |
4077 | | int out_of_asoc_ok, |
4078 | | uint16_t src_port, |
4079 | | uint16_t dest_port, |
4080 | | uint32_t v_tag, |
4081 | | uint16_t port, |
4082 | | union sctp_sockstore *over_addr, |
4083 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4084 | | uint8_t mflowtype, uint32_t mflowid, |
4085 | | #endif |
4086 | | bool use_zero_crc, |
4087 | | int so_locked) |
4088 | | /* nofragment_flag to tell if IP_DF should be set (IPv4 only) */ |
4089 | 9.13k | { |
4090 | | /** |
4091 | | * Given a mbuf chain (via SCTP_BUF_NEXT()) that holds a packet header |
4092 | | * WITH an SCTPHDR but no IP header, endpoint inp and sa structure: |
4093 | | * - fill in the HMAC digest of any AUTH chunk in the packet. |
4094 | | * - calculate and fill in the SCTP checksum. |
4095 | | * - prepend an IP address header. |
4096 | | * - if boundall use INADDR_ANY. |
4097 | | * - if boundspecific do source address selection. |
4098 | | * - set fragmentation option for ipV4. |
4099 | | * - On return from IP output, check/adjust mtu size of output |
4100 | | * interface and smallest_mtu size as well. |
4101 | | */ |
4102 | | /* Will need ifdefs around this */ |
4103 | 9.13k | struct mbuf *newm; |
4104 | 9.13k | struct sctphdr *sctphdr; |
4105 | 9.13k | int packet_length; |
4106 | 9.13k | int ret; |
4107 | 9.13k | #if defined(INET) || defined(INET6) |
4108 | 9.13k | uint32_t vrf_id; |
4109 | 9.13k | #endif |
4110 | 9.13k | #if defined(INET) || defined(INET6) |
4111 | 9.13k | struct mbuf *o_pak; |
4112 | 9.13k | sctp_route_t *ro = NULL; |
4113 | 9.13k | struct udphdr *udp = NULL; |
4114 | 9.13k | #endif |
4115 | 9.13k | uint8_t tos_value; |
4116 | | #if defined(__APPLE__) && !defined(__Userspace__) |
4117 | | struct socket *so = NULL; |
4118 | | #endif |
4119 | | |
4120 | | #if defined(__APPLE__) && !defined(__Userspace__) |
4121 | | if (so_locked) { |
4122 | | sctp_lock_assert(SCTP_INP_SO(inp)); |
4123 | | SCTP_TCB_LOCK_ASSERT(stcb); |
4124 | | } else { |
4125 | | sctp_unlock_assert(SCTP_INP_SO(inp)); |
4126 | | } |
4127 | | #endif |
4128 | 9.13k | if ((net) && (net->dest_state & SCTP_ADDR_OUT_OF_SCOPE)) { |
4129 | 0 | SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EFAULT); |
4130 | 0 | sctp_m_freem(m); |
4131 | 0 | return (EFAULT); |
4132 | 0 | } |
4133 | 9.13k | #if defined(INET) || defined(INET6) |
4134 | 9.13k | if (stcb) { |
4135 | 9.13k | vrf_id = stcb->asoc.vrf_id; |
4136 | 9.13k | } else { |
4137 | 0 | vrf_id = inp->def_vrf_id; |
4138 | 0 | } |
4139 | 9.13k | #endif |
4140 | | /* fill in the HMAC digest for any AUTH chunk in the packet */ |
4141 | 9.13k | if ((auth != NULL) && (stcb != NULL)) { |
4142 | 0 | sctp_fill_hmac_digest_m(m, auth_offset, auth, stcb, auth_keyid); |
4143 | 0 | } |
4144 | | |
4145 | 9.13k | if (net) { |
4146 | 9.13k | tos_value = net->dscp; |
4147 | 9.13k | } else if (stcb) { |
4148 | 0 | tos_value = stcb->asoc.default_dscp; |
4149 | 0 | } else { |
4150 | 0 | tos_value = inp->sctp_ep.default_dscp; |
4151 | 0 | } |
4152 | | |
4153 | 9.13k | switch (to->sa_family) { |
4154 | 0 | #ifdef INET |
4155 | 0 | case AF_INET: |
4156 | 0 | { |
4157 | 0 | struct ip *ip = NULL; |
4158 | 0 | sctp_route_t iproute; |
4159 | 0 | int len; |
4160 | |
|
4161 | 0 | len = SCTP_MIN_V4_OVERHEAD; |
4162 | 0 | if (port) { |
4163 | 0 | len += sizeof(struct udphdr); |
4164 | 0 | } |
4165 | 0 | newm = sctp_get_mbuf_for_msg(len, 1, M_NOWAIT, 1, MT_DATA); |
4166 | 0 | if (newm == NULL) { |
4167 | 0 | sctp_m_freem(m); |
4168 | 0 | SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
4169 | 0 | return (ENOMEM); |
4170 | 0 | } |
4171 | 0 | SCTP_ALIGN_TO_END(newm, len); |
4172 | 0 | SCTP_BUF_LEN(newm) = len; |
4173 | 0 | SCTP_BUF_NEXT(newm) = m; |
4174 | 0 | m = newm; |
4175 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4176 | | if (net != NULL) { |
4177 | | m->m_pkthdr.flowid = net->flowid; |
4178 | | M_HASHTYPE_SET(m, net->flowtype); |
4179 | | } else { |
4180 | | m->m_pkthdr.flowid = mflowid; |
4181 | | M_HASHTYPE_SET(m, mflowtype); |
4182 | | } |
4183 | | #endif |
4184 | 0 | packet_length = sctp_calculate_len(m); |
4185 | 0 | ip = mtod(m, struct ip *); |
4186 | 0 | ip->ip_v = IPVERSION; |
4187 | 0 | ip->ip_hl = (sizeof(struct ip) >> 2); |
4188 | 0 | if (tos_value == 0) { |
4189 | | /* |
4190 | | * This means especially, that it is not set at the |
4191 | | * SCTP layer. So use the value from the IP layer. |
4192 | | */ |
4193 | 0 | tos_value = inp->ip_inp.inp.inp_ip_tos; |
4194 | 0 | } |
4195 | 0 | tos_value &= 0xfc; |
4196 | 0 | if (ecn_ok) { |
4197 | 0 | tos_value |= sctp_get_ect(stcb); |
4198 | 0 | } |
4199 | 0 | if ((nofragment_flag) && (port == 0)) { |
4200 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4201 | | ip->ip_off = htons(IP_DF); |
4202 | | #elif defined(WITH_CONVERT_IP_OFF) || defined(__APPLE__) |
4203 | | ip->ip_off = IP_DF; |
4204 | | #else |
4205 | 0 | ip->ip_off = htons(IP_DF); |
4206 | 0 | #endif |
4207 | 0 | } else { |
4208 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4209 | | ip->ip_off = htons(0); |
4210 | | #else |
4211 | 0 | ip->ip_off = 0; |
4212 | 0 | #endif |
4213 | 0 | } |
4214 | 0 | #if defined(__Userspace__) |
4215 | 0 | ip->ip_id = htons(SCTP_IP_ID(inp)++); |
4216 | | #elif defined(__FreeBSD__) |
4217 | | /* FreeBSD has a function for ip_id's */ |
4218 | | ip_fillid(ip, V_ip_random_id); |
4219 | | #elif defined(__APPLE__) |
4220 | | #if RANDOM_IP_ID |
4221 | | ip->ip_id = ip_randomid(); |
4222 | | #else |
4223 | | ip->ip_id = htons(ip_id++); |
4224 | | #endif |
4225 | | #else |
4226 | | ip->ip_id = SCTP_IP_ID(inp)++; |
4227 | | #endif |
4228 | |
|
4229 | 0 | ip->ip_ttl = inp->ip_inp.inp.inp_ip_ttl; |
4230 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4231 | | ip->ip_len = htons(packet_length); |
4232 | | #else |
4233 | 0 | ip->ip_len = packet_length; |
4234 | 0 | #endif |
4235 | 0 | ip->ip_tos = tos_value; |
4236 | 0 | if (port) { |
4237 | 0 | ip->ip_p = IPPROTO_UDP; |
4238 | 0 | } else { |
4239 | 0 | ip->ip_p = IPPROTO_SCTP; |
4240 | 0 | } |
4241 | 0 | ip->ip_sum = 0; |
4242 | 0 | if (net == NULL) { |
4243 | 0 | ro = &iproute; |
4244 | 0 | memset(&iproute, 0, sizeof(iproute)); |
4245 | | #ifdef HAVE_SA_LEN |
4246 | | memcpy(&ro->ro_dst, to, to->sa_len); |
4247 | | #else |
4248 | 0 | memcpy(&ro->ro_dst, to, sizeof(struct sockaddr_in)); |
4249 | 0 | #endif |
4250 | 0 | } else { |
4251 | 0 | ro = (sctp_route_t *)&net->ro; |
4252 | 0 | } |
4253 | | /* Now the address selection part */ |
4254 | 0 | ip->ip_dst.s_addr = ((struct sockaddr_in *)to)->sin_addr.s_addr; |
4255 | | |
4256 | | /* call the routine to select the src address */ |
4257 | 0 | if (net && out_of_asoc_ok == 0) { |
4258 | 0 | if (net->ro._s_addr && (net->ro._s_addr->localifa_flags & (SCTP_BEING_DELETED|SCTP_ADDR_IFA_UNUSEABLE))) { |
4259 | 0 | sctp_free_ifa(net->ro._s_addr); |
4260 | 0 | net->ro._s_addr = NULL; |
4261 | 0 | net->src_addr_selected = 0; |
4262 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4263 | | RO_NHFREE(ro); |
4264 | | #else |
4265 | 0 | if (ro->ro_rt) { |
4266 | 0 | RTFREE(ro->ro_rt); |
4267 | 0 | ro->ro_rt = NULL; |
4268 | 0 | } |
4269 | 0 | #endif |
4270 | 0 | } |
4271 | 0 | if (net->src_addr_selected == 0) { |
4272 | | /* Cache the source address */ |
4273 | 0 | net->ro._s_addr = sctp_source_address_selection(inp,stcb, |
4274 | 0 | ro, net, 0, |
4275 | 0 | vrf_id); |
4276 | 0 | net->src_addr_selected = 1; |
4277 | 0 | } |
4278 | 0 | if (net->ro._s_addr == NULL) { |
4279 | | /* No route to host */ |
4280 | 0 | net->src_addr_selected = 0; |
4281 | 0 | sctp_handle_no_route(stcb, net, so_locked); |
4282 | 0 | SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EHOSTUNREACH); |
4283 | 0 | sctp_m_freem(m); |
4284 | 0 | return (EHOSTUNREACH); |
4285 | 0 | } |
4286 | 0 | ip->ip_src = net->ro._s_addr->address.sin.sin_addr; |
4287 | 0 | } else { |
4288 | 0 | if (over_addr == NULL) { |
4289 | 0 | struct sctp_ifa *_lsrc; |
4290 | |
|
4291 | 0 | _lsrc = sctp_source_address_selection(inp, stcb, ro, |
4292 | 0 | net, |
4293 | 0 | out_of_asoc_ok, |
4294 | 0 | vrf_id); |
4295 | 0 | if (_lsrc == NULL) { |
4296 | 0 | sctp_handle_no_route(stcb, net, so_locked); |
4297 | 0 | SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EHOSTUNREACH); |
4298 | 0 | sctp_m_freem(m); |
4299 | 0 | return (EHOSTUNREACH); |
4300 | 0 | } |
4301 | 0 | ip->ip_src = _lsrc->address.sin.sin_addr; |
4302 | 0 | sctp_free_ifa(_lsrc); |
4303 | 0 | } else { |
4304 | 0 | ip->ip_src = over_addr->sin.sin_addr; |
4305 | 0 | SCTP_RTALLOC(ro, vrf_id, inp->fibnum); |
4306 | 0 | } |
4307 | 0 | } |
4308 | 0 | if (port) { |
4309 | 0 | if (htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)) == 0) { |
4310 | 0 | sctp_handle_no_route(stcb, net, so_locked); |
4311 | 0 | SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EHOSTUNREACH); |
4312 | 0 | sctp_m_freem(m); |
4313 | 0 | return (EHOSTUNREACH); |
4314 | 0 | } |
4315 | 0 | udp = (struct udphdr *)((caddr_t)ip + sizeof(struct ip)); |
4316 | 0 | udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); |
4317 | 0 | udp->uh_dport = port; |
4318 | 0 | udp->uh_ulen = htons((uint16_t)(packet_length - sizeof(struct ip))); |
4319 | | #if !defined(__Userspace__) |
4320 | | #if defined(__FreeBSD__) |
4321 | | if (V_udp_cksum) { |
4322 | | udp->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); |
4323 | | } else { |
4324 | | udp->uh_sum = 0; |
4325 | | } |
4326 | | #else |
4327 | | udp->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); |
4328 | | #endif |
4329 | | #else |
4330 | 0 | udp->uh_sum = 0; |
4331 | 0 | #endif |
4332 | 0 | sctphdr = (struct sctphdr *)((caddr_t)udp + sizeof(struct udphdr)); |
4333 | 0 | } else { |
4334 | 0 | sctphdr = (struct sctphdr *)((caddr_t)ip + sizeof(struct ip)); |
4335 | 0 | } |
4336 | | |
4337 | 0 | sctphdr->src_port = src_port; |
4338 | 0 | sctphdr->dest_port = dest_port; |
4339 | 0 | sctphdr->v_tag = v_tag; |
4340 | 0 | sctphdr->checksum = 0; |
4341 | | |
4342 | | /* |
4343 | | * If source address selection fails and we find no route |
4344 | | * then the ip_output should fail as well with a |
4345 | | * NO_ROUTE_TO_HOST type error. We probably should catch |
4346 | | * that somewhere and abort the association right away |
4347 | | * (assuming this is an INIT being sent). |
4348 | | */ |
4349 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4350 | | if (ro->ro_nh == NULL) { |
4351 | | #else |
4352 | 0 | if (ro->ro_rt == NULL) { |
4353 | 0 | #endif |
4354 | | /* |
4355 | | * src addr selection failed to find a route (or |
4356 | | * valid source addr), so we can't get there from |
4357 | | * here (yet)! |
4358 | | */ |
4359 | 0 | sctp_handle_no_route(stcb, net, so_locked); |
4360 | 0 | SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EHOSTUNREACH); |
4361 | 0 | sctp_m_freem(m); |
4362 | 0 | return (EHOSTUNREACH); |
4363 | 0 | } |
4364 | 0 | if (ro != &iproute) { |
4365 | 0 | memcpy(&iproute, ro, sizeof(*ro)); |
4366 | 0 | } |
4367 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "Calling ipv4 output routine from low level src addr:%x\n", |
4368 | 0 | (uint32_t) (ntohl(ip->ip_src.s_addr))); |
4369 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "Destination is %x\n", |
4370 | 0 | (uint32_t)(ntohl(ip->ip_dst.s_addr))); |
4371 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4372 | | SCTPDBG(SCTP_DEBUG_OUTPUT3, "RTP route is %p through\n", |
4373 | | (void *)ro->ro_nh); |
4374 | | #else |
4375 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "RTP route is %p through\n", |
4376 | 0 | (void *)ro->ro_rt); |
4377 | 0 | #endif |
4378 | |
|
4379 | 0 | if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) { |
4380 | | /* failed to prepend data, give up */ |
4381 | 0 | SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
4382 | 0 | sctp_m_freem(m); |
4383 | 0 | return (ENOMEM); |
4384 | 0 | } |
4385 | 0 | SCTP_ATTACH_CHAIN(o_pak, m, packet_length); |
4386 | 0 | if (port) { |
4387 | 0 | if (use_zero_crc) { |
4388 | 0 | SCTP_STAT_INCR(sctps_sendzerocrc); |
4389 | 0 | } else { |
4390 | 0 | sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip) + sizeof(struct udphdr)); |
4391 | 0 | SCTP_STAT_INCR(sctps_sendswcrc); |
4392 | 0 | } |
4393 | | #if !defined(__Userspace__) |
4394 | | #if defined(__FreeBSD__) |
4395 | | if (V_udp_cksum) { |
4396 | | SCTP_ENABLE_UDP_CSUM(o_pak); |
4397 | | } |
4398 | | #else |
4399 | | SCTP_ENABLE_UDP_CSUM(o_pak); |
4400 | | #endif |
4401 | | #endif |
4402 | 0 | } else { |
4403 | 0 | if (use_zero_crc) { |
4404 | 0 | SCTP_STAT_INCR(sctps_sendzerocrc); |
4405 | 0 | } else { |
4406 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4407 | | m->m_pkthdr.csum_flags = CSUM_SCTP; |
4408 | | m->m_pkthdr.csum_data = offsetof(struct sctphdr, checksum); |
4409 | | SCTP_STAT_INCR(sctps_sendhwcrc); |
4410 | | #else |
4411 | 0 | if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && |
4412 | 0 | (stcb) && (stcb->asoc.scope.loopback_scope))) { |
4413 | 0 | sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip)); |
4414 | 0 | SCTP_STAT_INCR(sctps_sendswcrc); |
4415 | 0 | } else { |
4416 | 0 | SCTP_STAT_INCR(sctps_sendhwcrc); |
4417 | 0 | } |
4418 | 0 | #endif |
4419 | 0 | } |
4420 | 0 | } |
4421 | | #ifdef SCTP_PACKET_LOGGING |
4422 | | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) |
4423 | | sctp_packet_log(o_pak); |
4424 | | #endif |
4425 | | /* send it out. table id is taken from stcb */ |
4426 | | #if defined(__APPLE__) && !defined(__Userspace__) |
4427 | | if ((SCTP_BASE_SYSCTL(sctp_output_unlocked)) && (so_locked)) { |
4428 | | so = SCTP_INP_SO(inp); |
4429 | | SCTP_SOCKET_UNLOCK(so, 0); |
4430 | | } |
4431 | | #endif |
4432 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4433 | | SCTP_PROBE5(send, NULL, stcb, ip, stcb, sctphdr); |
4434 | | #endif |
4435 | 0 | SCTP_IP_OUTPUT(ret, o_pak, ro, inp, vrf_id); |
4436 | | #if defined(__APPLE__) && !defined(__Userspace__) |
4437 | | if ((SCTP_BASE_SYSCTL(sctp_output_unlocked)) && (so_locked)) { |
4438 | | atomic_add_int(&stcb->asoc.refcnt, 1); |
4439 | | SCTP_TCB_UNLOCK(stcb); |
4440 | | SCTP_SOCKET_LOCK(so, 0); |
4441 | | SCTP_TCB_LOCK(stcb); |
4442 | | atomic_subtract_int(&stcb->asoc.refcnt, 1); |
4443 | | } |
4444 | | #endif |
4445 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4446 | | if (port) { |
4447 | | UDPSTAT_INC(udps_opackets); |
4448 | | } |
4449 | | #endif |
4450 | 0 | SCTP_STAT_INCR(sctps_sendpackets); |
4451 | 0 | SCTP_STAT_INCR_COUNTER64(sctps_outpackets); |
4452 | 0 | if (ret) |
4453 | 0 | SCTP_STAT_INCR(sctps_senderrors); |
4454 | |
|
4455 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "IP output returns %d\n", ret); |
4456 | 0 | if (net == NULL) { |
4457 | | /* free tempy routes */ |
4458 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4459 | | RO_NHFREE(ro); |
4460 | | #else |
4461 | 0 | if (ro->ro_rt) { |
4462 | 0 | RTFREE(ro->ro_rt); |
4463 | 0 | ro->ro_rt = NULL; |
4464 | 0 | } |
4465 | 0 | #endif |
4466 | 0 | } else { |
4467 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4468 | | if ((ro->ro_nh != NULL) && (net->ro._s_addr) && |
4469 | | #else |
4470 | 0 | if ((ro->ro_rt != NULL) && (net->ro._s_addr) && |
4471 | 0 | #endif |
4472 | 0 | ((net->dest_state & SCTP_ADDR_NO_PMTUD) == 0)) { |
4473 | 0 | uint32_t mtu; |
4474 | |
|
4475 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4476 | | mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_nh); |
4477 | | #else |
4478 | 0 | mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_rt); |
4479 | 0 | #endif |
4480 | 0 | if (mtu > 0) { |
4481 | 0 | if (net->port) { |
4482 | 0 | mtu -= sizeof(struct udphdr); |
4483 | 0 | } |
4484 | 0 | if (mtu < net->mtu) { |
4485 | 0 | net->mtu = mtu; |
4486 | 0 | if ((stcb != NULL) && (stcb->asoc.smallest_mtu > mtu)) { |
4487 | 0 | sctp_pathmtu_adjustment(stcb, mtu, true); |
4488 | 0 | } |
4489 | 0 | } |
4490 | 0 | } |
4491 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4492 | | } else if (ro->ro_nh == NULL) { |
4493 | | #else |
4494 | 0 | } else if (ro->ro_rt == NULL) { |
4495 | 0 | #endif |
4496 | | /* route was freed */ |
4497 | 0 | if (net->ro._s_addr && |
4498 | 0 | net->src_addr_selected) { |
4499 | 0 | sctp_free_ifa(net->ro._s_addr); |
4500 | 0 | net->ro._s_addr = NULL; |
4501 | 0 | } |
4502 | 0 | net->src_addr_selected = 0; |
4503 | 0 | } |
4504 | 0 | } |
4505 | 0 | return (ret); |
4506 | 0 | } |
4507 | 0 | #endif |
4508 | 0 | #ifdef INET6 |
4509 | 0 | case AF_INET6: |
4510 | 0 | { |
4511 | 0 | uint32_t flowlabel, flowinfo; |
4512 | 0 | struct ip6_hdr *ip6h; |
4513 | 0 | struct route_in6 ip6route; |
4514 | | #if !defined(__Userspace__) |
4515 | | struct ifnet *ifp; |
4516 | | #endif |
4517 | 0 | struct sockaddr_in6 *sin6, tmp, *lsa6, lsa6_tmp; |
4518 | 0 | int prev_scope = 0; |
4519 | | #ifdef SCTP_EMBEDDED_V6_SCOPE |
4520 | | struct sockaddr_in6 lsa6_storage; |
4521 | | int error; |
4522 | | #endif |
4523 | 0 | u_short prev_port = 0; |
4524 | 0 | int len; |
4525 | |
|
4526 | 0 | if (net) { |
4527 | 0 | flowlabel = net->flowlabel; |
4528 | 0 | } else if (stcb) { |
4529 | 0 | flowlabel = stcb->asoc.default_flowlabel; |
4530 | 0 | } else { |
4531 | 0 | flowlabel = inp->sctp_ep.default_flowlabel; |
4532 | 0 | } |
4533 | 0 | if (flowlabel == 0) { |
4534 | | /* |
4535 | | * This means especially, that it is not set at the |
4536 | | * SCTP layer. So use the value from the IP layer. |
4537 | | */ |
4538 | | #if defined(__APPLE__) && !defined(__Userspace__) && (!defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION)) |
4539 | | flowlabel = ntohl(inp->ip_inp.inp.inp_flow); |
4540 | | #else |
4541 | 0 | flowlabel = ntohl(((struct inpcb *)inp)->inp_flow); |
4542 | 0 | #endif |
4543 | 0 | } |
4544 | 0 | flowlabel &= 0x000fffff; |
4545 | 0 | len = SCTP_MIN_OVERHEAD; |
4546 | 0 | if (port) { |
4547 | 0 | len += sizeof(struct udphdr); |
4548 | 0 | } |
4549 | 0 | newm = sctp_get_mbuf_for_msg(len, 1, M_NOWAIT, 1, MT_DATA); |
4550 | 0 | if (newm == NULL) { |
4551 | 0 | sctp_m_freem(m); |
4552 | 0 | SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
4553 | 0 | return (ENOMEM); |
4554 | 0 | } |
4555 | 0 | SCTP_ALIGN_TO_END(newm, len); |
4556 | 0 | SCTP_BUF_LEN(newm) = len; |
4557 | 0 | SCTP_BUF_NEXT(newm) = m; |
4558 | 0 | m = newm; |
4559 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4560 | | if (net != NULL) { |
4561 | | m->m_pkthdr.flowid = net->flowid; |
4562 | | M_HASHTYPE_SET(m, net->flowtype); |
4563 | | } else { |
4564 | | m->m_pkthdr.flowid = mflowid; |
4565 | | M_HASHTYPE_SET(m, mflowtype); |
4566 | | } |
4567 | | #endif |
4568 | 0 | packet_length = sctp_calculate_len(m); |
4569 | |
|
4570 | 0 | ip6h = mtod(m, struct ip6_hdr *); |
4571 | | /* protect *sin6 from overwrite */ |
4572 | 0 | sin6 = (struct sockaddr_in6 *)to; |
4573 | 0 | tmp = *sin6; |
4574 | 0 | sin6 = &tmp; |
4575 | |
|
4576 | | #ifdef SCTP_EMBEDDED_V6_SCOPE |
4577 | | /* KAME hack: embed scopeid */ |
4578 | | #if defined(__APPLE__) && !defined(__Userspace__) |
4579 | | #if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) |
4580 | | if (in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL) != 0) |
4581 | | #else |
4582 | | if (in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL, NULL) != 0) |
4583 | | #endif |
4584 | | #elif defined(SCTP_KAME) |
4585 | | if (sa6_embedscope(sin6, MODULE_GLOBAL(ip6_use_defzone)) != 0) |
4586 | | #else |
4587 | | if (in6_embedscope(&sin6->sin6_addr, sin6) != 0) |
4588 | | #endif |
4589 | | { |
4590 | | SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); |
4591 | | sctp_m_freem(m); |
4592 | | return (EINVAL); |
4593 | | } |
4594 | | #endif /* SCTP_EMBEDDED_V6_SCOPE */ |
4595 | 0 | if (net == NULL) { |
4596 | 0 | memset(&ip6route, 0, sizeof(ip6route)); |
4597 | 0 | ro = (sctp_route_t *)&ip6route; |
4598 | | #ifdef HAVE_SIN6_LEN |
4599 | | memcpy(&ro->ro_dst, sin6, sin6->sin6_len); |
4600 | | #else |
4601 | 0 | memcpy(&ro->ro_dst, sin6, sizeof(struct sockaddr_in6)); |
4602 | 0 | #endif |
4603 | 0 | } else { |
4604 | 0 | ro = (sctp_route_t *)&net->ro; |
4605 | 0 | } |
4606 | | /* |
4607 | | * We assume here that inp_flow is in host byte order within |
4608 | | * the TCB! |
4609 | | */ |
4610 | 0 | if (tos_value == 0) { |
4611 | | /* |
4612 | | * This means especially, that it is not set at the |
4613 | | * SCTP layer. So use the value from the IP layer. |
4614 | | */ |
4615 | | #if defined(__APPLE__) && !defined(__Userspace__) && (!defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION)) |
4616 | | tos_value = (ntohl(inp->ip_inp.inp.inp_flow) >> 20) & 0xff; |
4617 | | #else |
4618 | 0 | tos_value = (ntohl(((struct inpcb *)inp)->inp_flow) >> 20) & 0xff; |
4619 | 0 | #endif |
4620 | 0 | } |
4621 | 0 | tos_value &= 0xfc; |
4622 | 0 | if (ecn_ok) { |
4623 | 0 | tos_value |= sctp_get_ect(stcb); |
4624 | 0 | } |
4625 | 0 | flowinfo = 0x06; |
4626 | 0 | flowinfo <<= 8; |
4627 | 0 | flowinfo |= tos_value; |
4628 | 0 | flowinfo <<= 20; |
4629 | 0 | flowinfo |= flowlabel; |
4630 | 0 | ip6h->ip6_flow = htonl(flowinfo); |
4631 | 0 | if (port) { |
4632 | 0 | ip6h->ip6_nxt = IPPROTO_UDP; |
4633 | 0 | } else { |
4634 | 0 | ip6h->ip6_nxt = IPPROTO_SCTP; |
4635 | 0 | } |
4636 | 0 | ip6h->ip6_plen = htons((uint16_t)(packet_length - sizeof(struct ip6_hdr))); |
4637 | 0 | ip6h->ip6_dst = sin6->sin6_addr; |
4638 | | |
4639 | | /* |
4640 | | * Add SRC address selection here: we can only reuse to a |
4641 | | * limited degree the kame src-addr-sel, since we can try |
4642 | | * their selection but it may not be bound. |
4643 | | */ |
4644 | 0 | memset(&lsa6_tmp, 0, sizeof(lsa6_tmp)); |
4645 | 0 | lsa6_tmp.sin6_family = AF_INET6; |
4646 | | #ifdef HAVE_SIN6_LEN |
4647 | | lsa6_tmp.sin6_len = sizeof(lsa6_tmp); |
4648 | | #endif |
4649 | 0 | lsa6 = &lsa6_tmp; |
4650 | 0 | if (net && out_of_asoc_ok == 0) { |
4651 | 0 | if (net->ro._s_addr && (net->ro._s_addr->localifa_flags & (SCTP_BEING_DELETED|SCTP_ADDR_IFA_UNUSEABLE))) { |
4652 | 0 | sctp_free_ifa(net->ro._s_addr); |
4653 | 0 | net->ro._s_addr = NULL; |
4654 | 0 | net->src_addr_selected = 0; |
4655 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4656 | | RO_NHFREE(ro); |
4657 | | #else |
4658 | 0 | if (ro->ro_rt) { |
4659 | 0 | RTFREE(ro->ro_rt); |
4660 | 0 | ro->ro_rt = NULL; |
4661 | 0 | } |
4662 | 0 | #endif |
4663 | 0 | } |
4664 | 0 | if (net->src_addr_selected == 0) { |
4665 | | #ifdef SCTP_EMBEDDED_V6_SCOPE |
4666 | | sin6 = (struct sockaddr_in6 *)&net->ro._l_addr; |
4667 | | /* KAME hack: embed scopeid */ |
4668 | | #if defined(__APPLE__) && !defined(__Userspace__) |
4669 | | #if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) |
4670 | | if (in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL) != 0) |
4671 | | #else |
4672 | | if (in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL, NULL) != 0) |
4673 | | #endif |
4674 | | #elif defined(SCTP_KAME) |
4675 | | if (sa6_embedscope(sin6, MODULE_GLOBAL(ip6_use_defzone)) != 0) |
4676 | | #else |
4677 | | if (in6_embedscope(&sin6->sin6_addr, sin6) != 0) |
4678 | | #endif |
4679 | | { |
4680 | | SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); |
4681 | | sctp_m_freem(m); |
4682 | | return (EINVAL); |
4683 | | } |
4684 | | #endif /* SCTP_EMBEDDED_V6_SCOPE */ |
4685 | | /* Cache the source address */ |
4686 | 0 | net->ro._s_addr = sctp_source_address_selection(inp, |
4687 | 0 | stcb, |
4688 | 0 | ro, |
4689 | 0 | net, |
4690 | 0 | 0, |
4691 | 0 | vrf_id); |
4692 | | #ifdef SCTP_EMBEDDED_V6_SCOPE |
4693 | | #ifdef SCTP_KAME |
4694 | | (void)sa6_recoverscope(sin6); |
4695 | | #else |
4696 | | (void)in6_recoverscope(sin6, &sin6->sin6_addr, NULL); |
4697 | | #endif /* SCTP_KAME */ |
4698 | | #endif /* SCTP_EMBEDDED_V6_SCOPE */ |
4699 | 0 | net->src_addr_selected = 1; |
4700 | 0 | } |
4701 | 0 | if (net->ro._s_addr == NULL) { |
4702 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "V6:No route to host\n"); |
4703 | 0 | net->src_addr_selected = 0; |
4704 | 0 | sctp_handle_no_route(stcb, net, so_locked); |
4705 | 0 | SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EHOSTUNREACH); |
4706 | 0 | sctp_m_freem(m); |
4707 | 0 | return (EHOSTUNREACH); |
4708 | 0 | } |
4709 | 0 | lsa6->sin6_addr = net->ro._s_addr->address.sin6.sin6_addr; |
4710 | 0 | } else { |
4711 | | #ifdef SCTP_EMBEDDED_V6_SCOPE |
4712 | | sin6 = (struct sockaddr_in6 *)&ro->ro_dst; |
4713 | | /* KAME hack: embed scopeid */ |
4714 | | #if defined(__APPLE__) && !defined(__Userspace__) |
4715 | | #if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) |
4716 | | if (in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL) != 0) |
4717 | | #else |
4718 | | if (in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL, NULL) != 0) |
4719 | | #endif |
4720 | | #elif defined(SCTP_KAME) |
4721 | | if (sa6_embedscope(sin6, MODULE_GLOBAL(ip6_use_defzone)) != 0) |
4722 | | #else |
4723 | | if (in6_embedscope(&sin6->sin6_addr, sin6) != 0) |
4724 | | #endif |
4725 | | { |
4726 | | SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); |
4727 | | sctp_m_freem(m); |
4728 | | return (EINVAL); |
4729 | | } |
4730 | | #endif /* SCTP_EMBEDDED_V6_SCOPE */ |
4731 | 0 | if (over_addr == NULL) { |
4732 | 0 | struct sctp_ifa *_lsrc; |
4733 | |
|
4734 | 0 | _lsrc = sctp_source_address_selection(inp, stcb, ro, |
4735 | 0 | net, |
4736 | 0 | out_of_asoc_ok, |
4737 | 0 | vrf_id); |
4738 | 0 | if (_lsrc == NULL) { |
4739 | 0 | sctp_handle_no_route(stcb, net, so_locked); |
4740 | 0 | SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EHOSTUNREACH); |
4741 | 0 | sctp_m_freem(m); |
4742 | 0 | return (EHOSTUNREACH); |
4743 | 0 | } |
4744 | 0 | lsa6->sin6_addr = _lsrc->address.sin6.sin6_addr; |
4745 | 0 | sctp_free_ifa(_lsrc); |
4746 | 0 | } else { |
4747 | 0 | lsa6->sin6_addr = over_addr->sin6.sin6_addr; |
4748 | 0 | SCTP_RTALLOC(ro, vrf_id, inp->fibnum); |
4749 | 0 | } |
4750 | | #ifdef SCTP_EMBEDDED_V6_SCOPE |
4751 | | #ifdef SCTP_KAME |
4752 | | (void)sa6_recoverscope(sin6); |
4753 | | #else |
4754 | | (void)in6_recoverscope(sin6, &sin6->sin6_addr, NULL); |
4755 | | #endif /* SCTP_KAME */ |
4756 | | #endif /* SCTP_EMBEDDED_V6_SCOPE */ |
4757 | 0 | } |
4758 | 0 | lsa6->sin6_port = inp->sctp_lport; |
4759 | |
|
4760 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4761 | | if (ro->ro_nh == NULL) { |
4762 | | #else |
4763 | 0 | if (ro->ro_rt == NULL) { |
4764 | 0 | #endif |
4765 | | /* |
4766 | | * src addr selection failed to find a route (or |
4767 | | * valid source addr), so we can't get there from |
4768 | | * here! |
4769 | | */ |
4770 | 0 | sctp_handle_no_route(stcb, net, so_locked); |
4771 | 0 | SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EHOSTUNREACH); |
4772 | 0 | sctp_m_freem(m); |
4773 | 0 | return (EHOSTUNREACH); |
4774 | 0 | } |
4775 | 0 | #ifndef SCOPEDROUTING |
4776 | | #ifdef SCTP_EMBEDDED_V6_SCOPE |
4777 | | /* |
4778 | | * XXX: sa6 may not have a valid sin6_scope_id in the |
4779 | | * non-SCOPEDROUTING case. |
4780 | | */ |
4781 | | memset(&lsa6_storage, 0, sizeof(lsa6_storage)); |
4782 | | lsa6_storage.sin6_family = AF_INET6; |
4783 | | #ifdef HAVE_SIN6_LEN |
4784 | | lsa6_storage.sin6_len = sizeof(lsa6_storage); |
4785 | | #endif |
4786 | | #ifdef SCTP_KAME |
4787 | | lsa6_storage.sin6_addr = lsa6->sin6_addr; |
4788 | | if ((error = sa6_recoverscope(&lsa6_storage)) != 0) { |
4789 | | #else |
4790 | | if ((error = in6_recoverscope(&lsa6_storage, &lsa6->sin6_addr, |
4791 | | NULL)) != 0) { |
4792 | | #endif /* SCTP_KAME */ |
4793 | | SCTPDBG(SCTP_DEBUG_OUTPUT3, "recover scope fails error %d\n", error); |
4794 | | sctp_m_freem(m); |
4795 | | return (error); |
4796 | | } |
4797 | | /* XXX */ |
4798 | | lsa6_storage.sin6_addr = lsa6->sin6_addr; |
4799 | | lsa6_storage.sin6_port = inp->sctp_lport; |
4800 | | lsa6 = &lsa6_storage; |
4801 | | #endif /* SCTP_EMBEDDED_V6_SCOPE */ |
4802 | 0 | #endif /* SCOPEDROUTING */ |
4803 | 0 | ip6h->ip6_src = lsa6->sin6_addr; |
4804 | |
|
4805 | 0 | if (port) { |
4806 | 0 | if (htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)) == 0) { |
4807 | 0 | sctp_handle_no_route(stcb, net, so_locked); |
4808 | 0 | SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EHOSTUNREACH); |
4809 | 0 | sctp_m_freem(m); |
4810 | 0 | return (EHOSTUNREACH); |
4811 | 0 | } |
4812 | 0 | udp = (struct udphdr *)((caddr_t)ip6h + sizeof(struct ip6_hdr)); |
4813 | 0 | udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); |
4814 | 0 | udp->uh_dport = port; |
4815 | 0 | udp->uh_ulen = htons((uint16_t)(packet_length - sizeof(struct ip6_hdr))); |
4816 | 0 | udp->uh_sum = 0; |
4817 | 0 | sctphdr = (struct sctphdr *)((caddr_t)udp + sizeof(struct udphdr)); |
4818 | 0 | } else { |
4819 | 0 | sctphdr = (struct sctphdr *)((caddr_t)ip6h + sizeof(struct ip6_hdr)); |
4820 | 0 | } |
4821 | | |
4822 | 0 | sctphdr->src_port = src_port; |
4823 | 0 | sctphdr->dest_port = dest_port; |
4824 | 0 | sctphdr->v_tag = v_tag; |
4825 | 0 | sctphdr->checksum = 0; |
4826 | | |
4827 | | /* |
4828 | | * We set the hop limit now since there is a good chance |
4829 | | * that our ro pointer is now filled |
4830 | | */ |
4831 | 0 | ip6h->ip6_hlim = SCTP_GET_HLIM(inp, ro); |
4832 | | #if !defined(__Userspace__) |
4833 | | ifp = SCTP_GET_IFN_VOID_FROM_ROUTE(ro); |
4834 | | #endif |
4835 | |
|
4836 | | #ifdef SCTP_DEBUG |
4837 | | /* Copy to be sure something bad is not happening */ |
4838 | | sin6->sin6_addr = ip6h->ip6_dst; |
4839 | | lsa6->sin6_addr = ip6h->ip6_src; |
4840 | | #endif |
4841 | |
|
4842 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "Calling ipv6 output routine from low level\n"); |
4843 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "src: "); |
4844 | 0 | SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT3, (struct sockaddr *)lsa6); |
4845 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "dst: "); |
4846 | 0 | SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT3, (struct sockaddr *)sin6); |
4847 | 0 | if (net) { |
4848 | 0 | sin6 = (struct sockaddr_in6 *)&net->ro._l_addr; |
4849 | | /* preserve the port and scope for link local send */ |
4850 | 0 | prev_scope = sin6->sin6_scope_id; |
4851 | 0 | prev_port = sin6->sin6_port; |
4852 | 0 | } |
4853 | |
|
4854 | 0 | if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) { |
4855 | | /* failed to prepend data, give up */ |
4856 | 0 | sctp_m_freem(m); |
4857 | 0 | SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
4858 | 0 | return (ENOMEM); |
4859 | 0 | } |
4860 | 0 | SCTP_ATTACH_CHAIN(o_pak, m, packet_length); |
4861 | 0 | if (port) { |
4862 | 0 | sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr)); |
4863 | 0 | SCTP_STAT_INCR(sctps_sendswcrc); |
4864 | | #if !defined(__Userspace__) |
4865 | | #if defined(_WIN32) |
4866 | | udp->uh_sum = 0; |
4867 | | #else |
4868 | | if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), packet_length - sizeof(struct ip6_hdr))) == 0) { |
4869 | | udp->uh_sum = 0xffff; |
4870 | | } |
4871 | | #endif |
4872 | | #endif |
4873 | 0 | } else { |
4874 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4875 | | m->m_pkthdr.csum_flags = CSUM_SCTP_IPV6; |
4876 | | m->m_pkthdr.csum_data = offsetof(struct sctphdr, checksum); |
4877 | | SCTP_STAT_INCR(sctps_sendhwcrc); |
4878 | | #else |
4879 | 0 | if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && |
4880 | 0 | (stcb) && (stcb->asoc.scope.loopback_scope))) { |
4881 | 0 | sctphdr->checksum = sctp_calculate_cksum(m, sizeof(struct ip6_hdr)); |
4882 | 0 | SCTP_STAT_INCR(sctps_sendswcrc); |
4883 | 0 | } else { |
4884 | 0 | SCTP_STAT_INCR(sctps_sendhwcrc); |
4885 | 0 | } |
4886 | 0 | #endif |
4887 | 0 | } |
4888 | | /* send it out. table id is taken from stcb */ |
4889 | | #if defined(__APPLE__) && !defined(__Userspace__) |
4890 | | if ((SCTP_BASE_SYSCTL(sctp_output_unlocked)) && (so_locked)) { |
4891 | | so = SCTP_INP_SO(inp); |
4892 | | SCTP_SOCKET_UNLOCK(so, 0); |
4893 | | } |
4894 | | #endif |
4895 | | #ifdef SCTP_PACKET_LOGGING |
4896 | | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) |
4897 | | sctp_packet_log(o_pak); |
4898 | | #endif |
4899 | | #if !defined(__Userspace__) |
4900 | | #if defined(__FreeBSD__) |
4901 | | SCTP_PROBE5(send, NULL, stcb, ip6h, stcb, sctphdr); |
4902 | | #endif |
4903 | | SCTP_IP6_OUTPUT(ret, o_pak, (struct route_in6 *)ro, &ifp, inp, vrf_id); |
4904 | | #else |
4905 | 0 | SCTP_IP6_OUTPUT(ret, o_pak, (struct route_in6 *)ro, NULL, inp, vrf_id); |
4906 | 0 | #endif |
4907 | | #if defined(__APPLE__) && !defined(__Userspace__) |
4908 | | if ((SCTP_BASE_SYSCTL(sctp_output_unlocked)) && (so_locked)) { |
4909 | | atomic_add_int(&stcb->asoc.refcnt, 1); |
4910 | | SCTP_TCB_UNLOCK(stcb); |
4911 | | SCTP_SOCKET_LOCK(so, 0); |
4912 | | SCTP_TCB_LOCK(stcb); |
4913 | | atomic_subtract_int(&stcb->asoc.refcnt, 1); |
4914 | | } |
4915 | | #endif |
4916 | 0 | if (net) { |
4917 | | /* for link local this must be done */ |
4918 | 0 | sin6->sin6_scope_id = prev_scope; |
4919 | 0 | sin6->sin6_port = prev_port; |
4920 | 0 | } |
4921 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "return from send is %d\n", ret); |
4922 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4923 | | if (port) { |
4924 | | UDPSTAT_INC(udps_opackets); |
4925 | | } |
4926 | | #endif |
4927 | 0 | SCTP_STAT_INCR(sctps_sendpackets); |
4928 | 0 | SCTP_STAT_INCR_COUNTER64(sctps_outpackets); |
4929 | 0 | if (ret) { |
4930 | 0 | SCTP_STAT_INCR(sctps_senderrors); |
4931 | 0 | } |
4932 | 0 | if (net == NULL) { |
4933 | | /* Now if we had a temp route free it */ |
4934 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4935 | | RO_NHFREE(ro); |
4936 | | #else |
4937 | 0 | if (ro->ro_rt) { |
4938 | 0 | RTFREE(ro->ro_rt); |
4939 | 0 | ro->ro_rt = NULL; |
4940 | 0 | } |
4941 | 0 | #endif |
4942 | 0 | } else { |
4943 | | /* PMTU check versus smallest asoc MTU goes here */ |
4944 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4945 | | if (ro->ro_nh == NULL) { |
4946 | | #else |
4947 | 0 | if (ro->ro_rt == NULL) { |
4948 | 0 | #endif |
4949 | | /* Route was freed */ |
4950 | 0 | if (net->ro._s_addr && |
4951 | 0 | net->src_addr_selected) { |
4952 | 0 | sctp_free_ifa(net->ro._s_addr); |
4953 | 0 | net->ro._s_addr = NULL; |
4954 | 0 | } |
4955 | 0 | net->src_addr_selected = 0; |
4956 | 0 | } |
4957 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4958 | | if ((ro->ro_nh != NULL) && (net->ro._s_addr) && |
4959 | | #else |
4960 | 0 | if ((ro->ro_rt != NULL) && (net->ro._s_addr) && |
4961 | 0 | #endif |
4962 | 0 | ((net->dest_state & SCTP_ADDR_NO_PMTUD) == 0)) { |
4963 | 0 | uint32_t mtu; |
4964 | |
|
4965 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
4966 | | mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_nh); |
4967 | | #else |
4968 | 0 | mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_rt); |
4969 | 0 | #endif |
4970 | 0 | if (mtu > 0) { |
4971 | 0 | if (net->port) { |
4972 | 0 | mtu -= sizeof(struct udphdr); |
4973 | 0 | } |
4974 | 0 | if (mtu < net->mtu) { |
4975 | 0 | net->mtu = mtu; |
4976 | 0 | if ((stcb != NULL) && (stcb->asoc.smallest_mtu > mtu)) { |
4977 | 0 | sctp_pathmtu_adjustment(stcb, mtu, false); |
4978 | 0 | } |
4979 | 0 | } |
4980 | 0 | } |
4981 | 0 | } |
4982 | | #if !defined(__Userspace__) |
4983 | | else if (ifp != NULL) { |
4984 | | #if defined(_WIN32) |
4985 | | #define ND_IFINFO(ifp) (ifp) |
4986 | | #define linkmtu if_mtu |
4987 | | #endif |
4988 | | if ((ND_IFINFO(ifp)->linkmtu > 0) && |
4989 | | (stcb->asoc.smallest_mtu > ND_IFINFO(ifp)->linkmtu)) { |
4990 | | sctp_pathmtu_adjustment(stcb, ND_IFINFO(ifp)->linkmtu, false); |
4991 | | } |
4992 | | } |
4993 | | #endif |
4994 | 0 | } |
4995 | 0 | return (ret); |
4996 | 0 | } |
4997 | 0 | #endif |
4998 | 0 | #if defined(__Userspace__) |
4999 | 9.13k | case AF_CONN: |
5000 | 9.13k | { |
5001 | 9.13k | char *buffer; |
5002 | 9.13k | struct sockaddr_conn *sconn; |
5003 | 9.13k | int len; |
5004 | | |
5005 | 9.13k | sconn = (struct sockaddr_conn *)to; |
5006 | 9.13k | len = sizeof(struct sctphdr); |
5007 | 9.13k | newm = sctp_get_mbuf_for_msg(len, 1, M_NOWAIT, 1, MT_DATA); |
5008 | 9.13k | if (newm == NULL) { |
5009 | 0 | sctp_m_freem(m); |
5010 | 0 | SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
5011 | 0 | return (ENOMEM); |
5012 | 0 | } |
5013 | 9.13k | SCTP_ALIGN_TO_END(newm, len); |
5014 | 9.13k | SCTP_BUF_LEN(newm) = len; |
5015 | 9.13k | SCTP_BUF_NEXT(newm) = m; |
5016 | 9.13k | m = newm; |
5017 | 9.13k | packet_length = sctp_calculate_len(m); |
5018 | 9.13k | m->m_pkthdr.len = packet_length; |
5019 | 9.13k | sctphdr = mtod(m, struct sctphdr *); |
5020 | 9.13k | sctphdr->src_port = src_port; |
5021 | 9.13k | sctphdr->dest_port = dest_port; |
5022 | 9.13k | sctphdr->v_tag = v_tag; |
5023 | 9.13k | sctphdr->checksum = 0; |
5024 | 9.13k | if (use_zero_crc) { |
5025 | 0 | SCTP_STAT_INCR(sctps_sendzerocrc); |
5026 | 9.13k | } else if (SCTP_BASE_VAR(crc32c_offloaded) == 0) { |
5027 | 0 | sctphdr->checksum = sctp_calculate_cksum(m, 0); |
5028 | 0 | SCTP_STAT_INCR(sctps_sendswcrc); |
5029 | 9.13k | } else { |
5030 | 9.13k | SCTP_STAT_INCR(sctps_sendhwcrc); |
5031 | 9.13k | } |
5032 | 9.13k | if (tos_value == 0) { |
5033 | 9.13k | tos_value = inp->ip_inp.inp.inp_ip_tos; |
5034 | 9.13k | } |
5035 | 9.13k | tos_value &= 0xfc; |
5036 | 9.13k | if (ecn_ok) { |
5037 | 4.32k | tos_value |= sctp_get_ect(stcb); |
5038 | 4.32k | } |
5039 | | /* Don't alloc/free for each packet */ |
5040 | 9.13k | if ((buffer = malloc(packet_length)) != NULL) { |
5041 | 9.13k | m_copydata(m, 0, packet_length, buffer); |
5042 | 9.13k | ret = SCTP_BASE_VAR(conn_output)(sconn->sconn_addr, buffer, packet_length, tos_value, nofragment_flag); |
5043 | 9.13k | free(buffer); |
5044 | 9.13k | } else { |
5045 | 0 | ret = ENOMEM; |
5046 | 0 | } |
5047 | 9.13k | sctp_m_freem(m); |
5048 | 9.13k | return (ret); |
5049 | 9.13k | } |
5050 | 0 | #endif |
5051 | 0 | default: |
5052 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Unknown protocol (TSNH) type %d\n", |
5053 | 0 | ((struct sockaddr *)to)->sa_family); |
5054 | 0 | sctp_m_freem(m); |
5055 | 0 | SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EFAULT); |
5056 | 0 | return (EFAULT); |
5057 | 9.13k | } |
5058 | 9.13k | } |
5059 | | |
5060 | | void |
5061 | | sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked) |
5062 | 1.60k | { |
5063 | 1.60k | struct mbuf *m, *m_last; |
5064 | 1.60k | struct sctp_nets *net; |
5065 | 1.60k | struct sctp_init_chunk *init; |
5066 | 1.60k | struct sctp_supported_addr_param *sup_addr; |
5067 | 1.60k | struct sctp_adaptation_layer_indication *ali; |
5068 | 1.60k | struct sctp_zero_checksum_acceptable *zero_chksum; |
5069 | 1.60k | struct sctp_supported_chunk_types_param *pr_supported; |
5070 | 1.60k | struct sctp_paramhdr *ph; |
5071 | 1.60k | int cnt_inits_to = 0; |
5072 | 1.60k | int error; |
5073 | 1.60k | uint16_t num_ext, chunk_len, padding_len, parameter_len; |
5074 | | |
5075 | | #if defined(__APPLE__) && !defined(__Userspace__) |
5076 | | if (so_locked) { |
5077 | | sctp_lock_assert(SCTP_INP_SO(inp)); |
5078 | | } else { |
5079 | | sctp_unlock_assert(SCTP_INP_SO(inp)); |
5080 | | } |
5081 | | #endif |
5082 | | /* INIT's always go to the primary (and usually ONLY address) */ |
5083 | 1.60k | net = stcb->asoc.primary_destination; |
5084 | 1.60k | if (net == NULL) { |
5085 | 0 | net = TAILQ_FIRST(&stcb->asoc.nets); |
5086 | 0 | if (net == NULL) { |
5087 | | /* TSNH */ |
5088 | 0 | return; |
5089 | 0 | } |
5090 | | /* we confirm any address we send an INIT to */ |
5091 | 0 | net->dest_state &= ~SCTP_ADDR_UNCONFIRMED; |
5092 | 0 | (void)sctp_set_primary_addr(stcb, NULL, net); |
5093 | 1.60k | } else { |
5094 | | /* we confirm any address we send an INIT to */ |
5095 | 1.60k | net->dest_state &= ~SCTP_ADDR_UNCONFIRMED; |
5096 | 1.60k | } |
5097 | 1.60k | SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT\n"); |
5098 | 1.60k | #ifdef INET6 |
5099 | 1.60k | if (net->ro._l_addr.sa.sa_family == AF_INET6) { |
5100 | | /* |
5101 | | * special hook, if we are sending to link local it will not |
5102 | | * show up in our private address count. |
5103 | | */ |
5104 | 0 | if (IN6_IS_ADDR_LINKLOCAL(&net->ro._l_addr.sin6.sin6_addr)) |
5105 | 0 | cnt_inits_to = 1; |
5106 | 0 | } |
5107 | 1.60k | #endif |
5108 | 1.60k | if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { |
5109 | | /* This case should not happen */ |
5110 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - failed timer?\n"); |
5111 | 0 | return; |
5112 | 0 | } |
5113 | | /* start the INIT timer */ |
5114 | 1.60k | sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, net); |
5115 | | |
5116 | 1.60k | m = sctp_get_mbuf_for_msg(MCLBYTES, 1, M_NOWAIT, 1, MT_DATA); |
5117 | 1.60k | if (m == NULL) { |
5118 | | /* No memory, INIT timer will re-attempt. */ |
5119 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - mbuf?\n"); |
5120 | 0 | return; |
5121 | 0 | } |
5122 | 1.60k | chunk_len = (uint16_t)sizeof(struct sctp_init_chunk); |
5123 | 1.60k | padding_len = 0; |
5124 | | /* Now lets put the chunk header in place */ |
5125 | 1.60k | init = mtod(m, struct sctp_init_chunk *); |
5126 | | /* now the chunk header */ |
5127 | 1.60k | init->ch.chunk_type = SCTP_INITIATION; |
5128 | 1.60k | init->ch.chunk_flags = 0; |
5129 | | /* fill in later from mbuf we build */ |
5130 | 1.60k | init->ch.chunk_length = 0; |
5131 | | /* place in my tag */ |
5132 | 1.60k | init->init.initiate_tag = htonl(stcb->asoc.my_vtag); |
5133 | | /* set up some of the credits. */ |
5134 | 1.60k | init->init.a_rwnd = htonl(max(inp->sctp_socket?SCTP_SB_LIMIT_RCV(inp->sctp_socket):0, |
5135 | 1.60k | SCTP_MINIMAL_RWND)); |
5136 | 1.60k | init->init.num_outbound_streams = htons(stcb->asoc.pre_open_streams); |
5137 | 1.60k | init->init.num_inbound_streams = htons(stcb->asoc.max_inbound_streams); |
5138 | 1.60k | init->init.initial_tsn = htonl(stcb->asoc.init_seq_number); |
5139 | | |
5140 | | /* Adaptation layer indication parameter */ |
5141 | 1.60k | if (inp->sctp_ep.adaptation_layer_indicator_provided) { |
5142 | 0 | parameter_len = (uint16_t)sizeof(struct sctp_adaptation_layer_indication); |
5143 | 0 | ali = (struct sctp_adaptation_layer_indication *)(mtod(m, caddr_t) + chunk_len); |
5144 | 0 | ali->ph.param_type = htons(SCTP_ULP_ADAPTATION); |
5145 | 0 | ali->ph.param_length = htons(parameter_len); |
5146 | 0 | ali->indication = htonl(inp->sctp_ep.adaptation_layer_indicator); |
5147 | 0 | chunk_len += parameter_len; |
5148 | 0 | } |
5149 | | |
5150 | | /* ECN parameter */ |
5151 | 1.60k | if (stcb->asoc.ecn_supported == 1) { |
5152 | 1.60k | parameter_len = (uint16_t)sizeof(struct sctp_paramhdr); |
5153 | 1.60k | ph = (struct sctp_paramhdr *)(mtod(m, caddr_t) + chunk_len); |
5154 | 1.60k | ph->param_type = htons(SCTP_ECN_CAPABLE); |
5155 | 1.60k | ph->param_length = htons(parameter_len); |
5156 | 1.60k | chunk_len += parameter_len; |
5157 | 1.60k | } |
5158 | | |
5159 | | /* PR-SCTP supported parameter */ |
5160 | 1.60k | if (stcb->asoc.prsctp_supported == 1) { |
5161 | 1.60k | parameter_len = (uint16_t)sizeof(struct sctp_paramhdr); |
5162 | 1.60k | ph = (struct sctp_paramhdr *)(mtod(m, caddr_t) + chunk_len); |
5163 | 1.60k | ph->param_type = htons(SCTP_PRSCTP_SUPPORTED); |
5164 | 1.60k | ph->param_length = htons(parameter_len); |
5165 | 1.60k | chunk_len += parameter_len; |
5166 | 1.60k | } |
5167 | | |
5168 | | /* Zero checksum acceptable parameter */ |
5169 | 1.60k | if (stcb->asoc.rcv_edmid != SCTP_EDMID_NONE) { |
5170 | 0 | parameter_len = (uint16_t)sizeof(struct sctp_zero_checksum_acceptable); |
5171 | 0 | zero_chksum = (struct sctp_zero_checksum_acceptable *)(mtod(m, caddr_t) + chunk_len); |
5172 | 0 | zero_chksum->ph.param_type = htons(SCTP_ZERO_CHECKSUM_ACCEPTABLE); |
5173 | 0 | zero_chksum->ph.param_length = htons(parameter_len); |
5174 | 0 | zero_chksum->edmid = htonl(stcb->asoc.rcv_edmid); |
5175 | 0 | chunk_len += parameter_len; |
5176 | 0 | } |
5177 | | |
5178 | | /* Add NAT friendly parameter. */ |
5179 | 1.60k | if (SCTP_BASE_SYSCTL(sctp_inits_include_nat_friendly)) { |
5180 | 0 | parameter_len = (uint16_t)sizeof(struct sctp_paramhdr); |
5181 | 0 | ph = (struct sctp_paramhdr *)(mtod(m, caddr_t) + chunk_len); |
5182 | 0 | ph->param_type = htons(SCTP_HAS_NAT_SUPPORT); |
5183 | 0 | ph->param_length = htons(parameter_len); |
5184 | 0 | chunk_len += parameter_len; |
5185 | 0 | } |
5186 | | |
5187 | | /* And now tell the peer which extensions we support */ |
5188 | 1.60k | num_ext = 0; |
5189 | 1.60k | pr_supported = (struct sctp_supported_chunk_types_param *)(mtod(m, caddr_t) + chunk_len); |
5190 | 1.60k | if (stcb->asoc.prsctp_supported == 1) { |
5191 | 1.60k | pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN; |
5192 | 1.60k | if (stcb->asoc.idata_supported) { |
5193 | 166 | pr_supported->chunk_types[num_ext++] = SCTP_IFORWARD_CUM_TSN; |
5194 | 166 | } |
5195 | 1.60k | } |
5196 | 1.60k | if (stcb->asoc.auth_supported == 1) { |
5197 | 1.60k | pr_supported->chunk_types[num_ext++] = SCTP_AUTHENTICATION; |
5198 | 1.60k | } |
5199 | 1.60k | if (stcb->asoc.asconf_supported == 1) { |
5200 | 1.60k | pr_supported->chunk_types[num_ext++] = SCTP_ASCONF; |
5201 | 1.60k | pr_supported->chunk_types[num_ext++] = SCTP_ASCONF_ACK; |
5202 | 1.60k | } |
5203 | 1.60k | if (stcb->asoc.reconfig_supported == 1) { |
5204 | 1.60k | pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET; |
5205 | 1.60k | } |
5206 | 1.60k | if (stcb->asoc.idata_supported) { |
5207 | 166 | pr_supported->chunk_types[num_ext++] = SCTP_IDATA; |
5208 | 166 | } |
5209 | 1.60k | if (stcb->asoc.nrsack_supported == 1) { |
5210 | 1.60k | pr_supported->chunk_types[num_ext++] = SCTP_NR_SELECTIVE_ACK; |
5211 | 1.60k | } |
5212 | 1.60k | if (stcb->asoc.pktdrop_supported == 1) { |
5213 | 1.60k | pr_supported->chunk_types[num_ext++] = SCTP_PACKET_DROPPED; |
5214 | 1.60k | } |
5215 | 1.60k | if (num_ext > 0) { |
5216 | 1.60k | parameter_len = (uint16_t)sizeof(struct sctp_supported_chunk_types_param) + num_ext; |
5217 | 1.60k | pr_supported->ph.param_type = htons(SCTP_SUPPORTED_CHUNK_EXT); |
5218 | 1.60k | pr_supported->ph.param_length = htons(parameter_len); |
5219 | 1.60k | padding_len = SCTP_SIZE32(parameter_len) - parameter_len; |
5220 | 1.60k | chunk_len += parameter_len; |
5221 | 1.60k | } |
5222 | | /* add authentication parameters */ |
5223 | 1.60k | if (stcb->asoc.auth_supported) { |
5224 | | /* attach RANDOM parameter, if available */ |
5225 | 1.60k | if (stcb->asoc.authinfo.random != NULL) { |
5226 | 1.60k | struct sctp_auth_random *randp; |
5227 | | |
5228 | 1.60k | if (padding_len > 0) { |
5229 | 1.60k | memset(mtod(m, caddr_t) + chunk_len, 0, padding_len); |
5230 | 1.60k | chunk_len += padding_len; |
5231 | 1.60k | padding_len = 0; |
5232 | 1.60k | } |
5233 | 1.60k | randp = (struct sctp_auth_random *)(mtod(m, caddr_t) + chunk_len); |
5234 | 1.60k | parameter_len = (uint16_t)sizeof(struct sctp_auth_random) + stcb->asoc.authinfo.random_len; |
5235 | | /* random key already contains the header */ |
5236 | 1.60k | memcpy(randp, stcb->asoc.authinfo.random->key, parameter_len); |
5237 | 1.60k | padding_len = SCTP_SIZE32(parameter_len) - parameter_len; |
5238 | 1.60k | chunk_len += parameter_len; |
5239 | 1.60k | } |
5240 | | /* add HMAC_ALGO parameter */ |
5241 | 1.60k | if (stcb->asoc.local_hmacs != NULL) { |
5242 | 1.60k | struct sctp_auth_hmac_algo *hmacs; |
5243 | | |
5244 | 1.60k | if (padding_len > 0) { |
5245 | 0 | memset(mtod(m, caddr_t) + chunk_len, 0, padding_len); |
5246 | 0 | chunk_len += padding_len; |
5247 | 0 | padding_len = 0; |
5248 | 0 | } |
5249 | 1.60k | hmacs = (struct sctp_auth_hmac_algo *)(mtod(m, caddr_t) + chunk_len); |
5250 | 1.60k | parameter_len = (uint16_t)(sizeof(struct sctp_auth_hmac_algo) + |
5251 | 1.60k | stcb->asoc.local_hmacs->num_algo * sizeof(uint16_t)); |
5252 | 1.60k | hmacs->ph.param_type = htons(SCTP_HMAC_LIST); |
5253 | 1.60k | hmacs->ph.param_length = htons(parameter_len); |
5254 | 1.60k | sctp_serialize_hmaclist(stcb->asoc.local_hmacs, (uint8_t *)hmacs->hmac_ids); |
5255 | 1.60k | padding_len = SCTP_SIZE32(parameter_len) - parameter_len; |
5256 | 1.60k | chunk_len += parameter_len; |
5257 | 1.60k | } |
5258 | | /* add CHUNKS parameter */ |
5259 | 1.60k | if (stcb->asoc.local_auth_chunks != NULL) { |
5260 | 1.60k | struct sctp_auth_chunk_list *chunks; |
5261 | | |
5262 | 1.60k | if (padding_len > 0) { |
5263 | 1.60k | memset(mtod(m, caddr_t) + chunk_len, 0, padding_len); |
5264 | 1.60k | chunk_len += padding_len; |
5265 | 1.60k | padding_len = 0; |
5266 | 1.60k | } |
5267 | 1.60k | chunks = (struct sctp_auth_chunk_list *)(mtod(m, caddr_t) + chunk_len); |
5268 | 1.60k | parameter_len = (uint16_t)(sizeof(struct sctp_auth_chunk_list) + |
5269 | 1.60k | sctp_auth_get_chklist_size(stcb->asoc.local_auth_chunks)); |
5270 | 1.60k | chunks->ph.param_type = htons(SCTP_CHUNK_LIST); |
5271 | 1.60k | chunks->ph.param_length = htons(parameter_len); |
5272 | 1.60k | sctp_serialize_auth_chunks(stcb->asoc.local_auth_chunks, chunks->chunk_types); |
5273 | 1.60k | padding_len = SCTP_SIZE32(parameter_len) - parameter_len; |
5274 | 1.60k | chunk_len += parameter_len; |
5275 | 1.60k | } |
5276 | 1.60k | } |
5277 | | |
5278 | | /* now any cookie time extensions */ |
5279 | 1.60k | if (stcb->asoc.cookie_preserve_req > 0) { |
5280 | 0 | struct sctp_cookie_perserve_param *cookie_preserve; |
5281 | |
|
5282 | 0 | if (padding_len > 0) { |
5283 | 0 | memset(mtod(m, caddr_t) + chunk_len, 0, padding_len); |
5284 | 0 | chunk_len += padding_len; |
5285 | 0 | padding_len = 0; |
5286 | 0 | } |
5287 | 0 | parameter_len = (uint16_t)sizeof(struct sctp_cookie_perserve_param); |
5288 | 0 | cookie_preserve = (struct sctp_cookie_perserve_param *)(mtod(m, caddr_t) + chunk_len); |
5289 | 0 | cookie_preserve->ph.param_type = htons(SCTP_COOKIE_PRESERVE); |
5290 | 0 | cookie_preserve->ph.param_length = htons(parameter_len); |
5291 | 0 | cookie_preserve->time = htonl(stcb->asoc.cookie_preserve_req); |
5292 | 0 | stcb->asoc.cookie_preserve_req = 0; |
5293 | 0 | chunk_len += parameter_len; |
5294 | 0 | } |
5295 | | |
5296 | 1.60k | if (stcb->asoc.scope.ipv4_addr_legal || stcb->asoc.scope.ipv6_addr_legal) { |
5297 | 0 | uint8_t i; |
5298 | |
|
5299 | 0 | if (padding_len > 0) { |
5300 | 0 | memset(mtod(m, caddr_t) + chunk_len, 0, padding_len); |
5301 | 0 | chunk_len += padding_len; |
5302 | 0 | padding_len = 0; |
5303 | 0 | } |
5304 | 0 | parameter_len = (uint16_t)sizeof(struct sctp_paramhdr); |
5305 | 0 | if (stcb->asoc.scope.ipv4_addr_legal) { |
5306 | 0 | parameter_len += (uint16_t)sizeof(uint16_t); |
5307 | 0 | } |
5308 | 0 | if (stcb->asoc.scope.ipv6_addr_legal) { |
5309 | 0 | parameter_len += (uint16_t)sizeof(uint16_t); |
5310 | 0 | } |
5311 | 0 | sup_addr = (struct sctp_supported_addr_param *)(mtod(m, caddr_t) + chunk_len); |
5312 | 0 | sup_addr->ph.param_type = htons(SCTP_SUPPORTED_ADDRTYPE); |
5313 | 0 | sup_addr->ph.param_length = htons(parameter_len); |
5314 | 0 | i = 0; |
5315 | 0 | if (stcb->asoc.scope.ipv4_addr_legal) { |
5316 | 0 | sup_addr->addr_type[i++] = htons(SCTP_IPV4_ADDRESS); |
5317 | 0 | } |
5318 | 0 | if (stcb->asoc.scope.ipv6_addr_legal) { |
5319 | 0 | sup_addr->addr_type[i++] = htons(SCTP_IPV6_ADDRESS); |
5320 | 0 | } |
5321 | 0 | padding_len = 4 - 2 * i; |
5322 | 0 | chunk_len += parameter_len; |
5323 | 0 | } |
5324 | | |
5325 | 1.60k | SCTP_BUF_LEN(m) = chunk_len; |
5326 | | /* now the addresses */ |
5327 | | /* To optimize this we could put the scoping stuff |
5328 | | * into a structure and remove the individual uint8's from |
5329 | | * the assoc structure. Then we could just sifa in the |
5330 | | * address within the stcb. But for now this is a quick |
5331 | | * hack to get the address stuff teased apart. |
5332 | | */ |
5333 | 1.60k | m_last = sctp_add_addresses_to_i_ia(inp, stcb, &stcb->asoc.scope, |
5334 | 1.60k | m, cnt_inits_to, |
5335 | 1.60k | &padding_len, &chunk_len); |
5336 | | |
5337 | 1.60k | init->ch.chunk_length = htons(chunk_len); |
5338 | 1.60k | if (padding_len > 0) { |
5339 | 1.60k | if (sctp_add_pad_tombuf(m_last, padding_len) == NULL) { |
5340 | 0 | sctp_m_freem(m); |
5341 | 0 | return; |
5342 | 0 | } |
5343 | 1.60k | } |
5344 | 1.60k | SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - calls lowlevel_output\n"); |
5345 | 1.60k | if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, |
5346 | 1.60k | (struct sockaddr *)&net->ro._l_addr, |
5347 | 1.60k | m, 0, NULL, 0, 0, 0, 0, |
5348 | 1.60k | inp->sctp_lport, stcb->rport, htonl(0), |
5349 | 1.60k | net->port, NULL, |
5350 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
5351 | | 0, 0, |
5352 | | #endif |
5353 | 1.60k | false, so_locked))) { |
5354 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak send error %d\n", error); |
5355 | 0 | if (error == ENOBUFS) { |
5356 | 0 | stcb->asoc.ifp_had_enobuf = 1; |
5357 | 0 | SCTP_STAT_INCR(sctps_lowlevelerr); |
5358 | 0 | } |
5359 | 1.60k | } else { |
5360 | 1.60k | stcb->asoc.ifp_had_enobuf = 0; |
5361 | 1.60k | } |
5362 | 1.60k | SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); |
5363 | 1.60k | (void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time); |
5364 | 1.60k | } |
5365 | | |
5366 | | struct mbuf * |
5367 | | sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, |
5368 | | int param_offset, int *abort_processing, |
5369 | | struct sctp_chunkhdr *cp, |
5370 | | int *nat_friendly, |
5371 | | int *cookie_found, |
5372 | | uint32_t *edmid) |
5373 | 1.60k | { |
5374 | | /* |
5375 | | * Given a mbuf containing an INIT or INIT-ACK with the param_offset |
5376 | | * being equal to the beginning of the params i.e. (iphlen + |
5377 | | * sizeof(struct sctp_init_msg) parse through the parameters to the |
5378 | | * end of the mbuf verifying that all parameters are known. |
5379 | | * |
5380 | | * For unknown parameters build and return a mbuf with |
5381 | | * UNRECOGNIZED_PARAMETER errors. If the flags indicate to stop |
5382 | | * processing this chunk stop, and set *abort_processing to 1. |
5383 | | * |
5384 | | * By having param_offset be pre-set to where parameters begin it is |
5385 | | * hoped that this routine may be reused in the future by new |
5386 | | * features. |
5387 | | */ |
5388 | 1.60k | struct sctp_zero_checksum_acceptable zero_chksum, *zero_chksum_p; |
5389 | 1.60k | struct sctp_paramhdr *phdr, params; |
5390 | 1.60k | struct mbuf *mat, *m_tmp, *op_err, *op_err_last; |
5391 | 1.60k | int at, limit, pad_needed; |
5392 | 1.60k | uint16_t ptype, plen, padded_size; |
5393 | | |
5394 | 1.60k | *abort_processing = 0; |
5395 | 1.60k | if (cookie_found != NULL) { |
5396 | 1.60k | *cookie_found = 0; |
5397 | 1.60k | } |
5398 | 1.60k | if (edmid != NULL) { |
5399 | 0 | *edmid = SCTP_EDMID_NONE; |
5400 | 0 | } |
5401 | 1.60k | mat = in_initpkt; |
5402 | 1.60k | limit = ntohs(cp->chunk_length) - sizeof(struct sctp_init_chunk); |
5403 | 1.60k | at = param_offset; |
5404 | 1.60k | op_err = NULL; |
5405 | 1.60k | op_err_last = NULL; |
5406 | 1.60k | pad_needed = 0; |
5407 | 1.60k | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Check for unrecognized param's\n"); |
5408 | 1.60k | phdr = sctp_get_next_param(mat, at, ¶ms, sizeof(params)); |
5409 | 14.4k | while ((phdr != NULL) && ((size_t)limit >= sizeof(struct sctp_paramhdr))) { |
5410 | 12.8k | ptype = ntohs(phdr->param_type); |
5411 | 12.8k | plen = ntohs(phdr->param_length); |
5412 | 12.8k | if ((plen > limit) || (plen < sizeof(struct sctp_paramhdr))) { |
5413 | | /* wacked parameter */ |
5414 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error %d\n", plen); |
5415 | 0 | goto invalid_size; |
5416 | 0 | } |
5417 | 12.8k | limit -= SCTP_SIZE32(plen); |
5418 | | /*- |
5419 | | * All parameters for all chunks that we know/understand are |
5420 | | * listed here. We process them other places and make |
5421 | | * appropriate stop actions per the upper bits. However this |
5422 | | * is the generic routine processor's can call to get back |
5423 | | * an operr.. to either incorporate (init-ack) or send. |
5424 | | */ |
5425 | 12.8k | padded_size = SCTP_SIZE32(plen); |
5426 | 12.8k | switch (ptype) { |
5427 | | /* Param's with variable size */ |
5428 | 0 | case SCTP_HEARTBEAT_INFO: |
5429 | 0 | case SCTP_UNRECOG_PARAM: |
5430 | 0 | case SCTP_ERROR_CAUSE_IND: |
5431 | | /* ok skip fwd */ |
5432 | 0 | at += padded_size; |
5433 | 0 | break; |
5434 | 1.60k | case SCTP_STATE_COOKIE: |
5435 | 1.60k | if (cookie_found != NULL) { |
5436 | 1.60k | *cookie_found = 1; |
5437 | 1.60k | } |
5438 | 1.60k | at += padded_size; |
5439 | 1.60k | break; |
5440 | | /* Param's with variable size within a range */ |
5441 | 1.60k | case SCTP_CHUNK_LIST: |
5442 | 3.21k | case SCTP_SUPPORTED_CHUNK_EXT: |
5443 | 3.21k | if (padded_size > (sizeof(struct sctp_supported_chunk_types_param) + (sizeof(uint8_t) * SCTP_MAX_SUPPORTED_EXT))) { |
5444 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error chklist %d\n", plen); |
5445 | 0 | goto invalid_size; |
5446 | 0 | } |
5447 | 3.21k | at += padded_size; |
5448 | 3.21k | break; |
5449 | 0 | case SCTP_SUPPORTED_ADDRTYPE: |
5450 | 0 | if (padded_size > SCTP_MAX_ADDR_PARAMS_SIZE) { |
5451 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error supaddrtype %d\n", plen); |
5452 | 0 | goto invalid_size; |
5453 | 0 | } |
5454 | 0 | at += padded_size; |
5455 | 0 | break; |
5456 | 0 | case SCTP_ZERO_CHECKSUM_ACCEPTABLE: |
5457 | 0 | if (padded_size != sizeof(struct sctp_zero_checksum_acceptable)) { |
5458 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error checksum acceptable %d\n", plen); |
5459 | 0 | goto invalid_size; |
5460 | 0 | } |
5461 | 0 | if (edmid != NULL) { |
5462 | 0 | phdr = sctp_get_next_param(mat, at, |
5463 | 0 | (struct sctp_paramhdr *)&zero_chksum, |
5464 | 0 | sizeof(struct sctp_zero_checksum_acceptable)); |
5465 | 0 | if (phdr != NULL) { |
5466 | 0 | zero_chksum_p = (struct sctp_zero_checksum_acceptable *)phdr; |
5467 | 0 | *edmid = ntohl(zero_chksum_p->edmid); |
5468 | 0 | } |
5469 | 0 | } |
5470 | 0 | at += padded_size; |
5471 | 0 | break; |
5472 | 1.60k | case SCTP_RANDOM: |
5473 | 1.60k | if (padded_size > (sizeof(struct sctp_auth_random) + SCTP_RANDOM_MAX_SIZE)) { |
5474 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error random %d\n", plen); |
5475 | 0 | goto invalid_size; |
5476 | 0 | } |
5477 | 1.60k | at += padded_size; |
5478 | 1.60k | break; |
5479 | 0 | case SCTP_SET_PRIM_ADDR: |
5480 | 0 | case SCTP_DEL_IP_ADDRESS: |
5481 | 0 | case SCTP_ADD_IP_ADDRESS: |
5482 | 0 | if ((padded_size != sizeof(struct sctp_asconf_addrv4_param)) && |
5483 | 0 | (padded_size != sizeof(struct sctp_asconf_addr_param))) { |
5484 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error setprim %d\n", plen); |
5485 | 0 | goto invalid_size; |
5486 | 0 | } |
5487 | 0 | at += padded_size; |
5488 | 0 | break; |
5489 | | /* Param's with a fixed size */ |
5490 | 0 | case SCTP_IPV4_ADDRESS: |
5491 | 0 | if (padded_size != sizeof(struct sctp_ipv4addr_param)) { |
5492 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error ipv4 addr %d\n", plen); |
5493 | 0 | goto invalid_size; |
5494 | 0 | } |
5495 | 0 | at += padded_size; |
5496 | 0 | break; |
5497 | 0 | case SCTP_IPV6_ADDRESS: |
5498 | 0 | if (padded_size != sizeof(struct sctp_ipv6addr_param)) { |
5499 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error ipv6 addr %d\n", plen); |
5500 | 0 | goto invalid_size; |
5501 | 0 | } |
5502 | 0 | at += padded_size; |
5503 | 0 | break; |
5504 | 0 | case SCTP_COOKIE_PRESERVE: |
5505 | 0 | if (padded_size != sizeof(struct sctp_cookie_perserve_param)) { |
5506 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error cookie-preserve %d\n", plen); |
5507 | 0 | goto invalid_size; |
5508 | 0 | } |
5509 | 0 | at += padded_size; |
5510 | 0 | break; |
5511 | 0 | case SCTP_HAS_NAT_SUPPORT: |
5512 | 0 | if (padded_size != sizeof(struct sctp_paramhdr)) { |
5513 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error nat support %d\n", plen); |
5514 | 0 | goto invalid_size; |
5515 | 0 | } |
5516 | 0 | *nat_friendly = 1; |
5517 | 0 | at += padded_size; |
5518 | 0 | break; |
5519 | 1.60k | case SCTP_PRSCTP_SUPPORTED: |
5520 | 1.60k | if (padded_size != sizeof(struct sctp_paramhdr)) { |
5521 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error prsctp %d\n", plen); |
5522 | 0 | goto invalid_size; |
5523 | 0 | } |
5524 | 1.60k | at += padded_size; |
5525 | 1.60k | break; |
5526 | 1.60k | case SCTP_ECN_CAPABLE: |
5527 | 1.60k | if (padded_size != sizeof(struct sctp_paramhdr)) { |
5528 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error ecn %d\n", plen); |
5529 | 0 | goto invalid_size; |
5530 | 0 | } |
5531 | 1.60k | at += padded_size; |
5532 | 1.60k | break; |
5533 | 1.60k | case SCTP_ULP_ADAPTATION: |
5534 | 1.60k | if (padded_size != sizeof(struct sctp_adaptation_layer_indication)) { |
5535 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error adapatation %d\n", plen); |
5536 | 0 | goto invalid_size; |
5537 | 0 | } |
5538 | 1.60k | at += padded_size; |
5539 | 1.60k | break; |
5540 | 0 | case SCTP_SUCCESS_REPORT: |
5541 | 0 | if (padded_size != sizeof(struct sctp_asconf_paramhdr)) { |
5542 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error success %d\n", plen); |
5543 | 0 | goto invalid_size; |
5544 | 0 | } |
5545 | 0 | at += padded_size; |
5546 | 0 | break; |
5547 | 0 | case SCTP_HOSTNAME_ADDRESS: |
5548 | 0 | { |
5549 | | /* Hostname parameters are deprecated. */ |
5550 | 0 | struct sctp_gen_error_cause *cause; |
5551 | 0 | int l_len; |
5552 | |
|
5553 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Can't handle hostname addresses.. abort processing\n"); |
5554 | 0 | *abort_processing = 1; |
5555 | 0 | sctp_m_freem(op_err); |
5556 | 0 | op_err = NULL; |
5557 | 0 | op_err_last = NULL; |
5558 | 0 | #ifdef INET6 |
5559 | 0 | l_len = SCTP_MIN_OVERHEAD; |
5560 | | #else |
5561 | | l_len = SCTP_MIN_V4_OVERHEAD; |
5562 | | #endif |
5563 | 0 | l_len += sizeof(struct sctp_chunkhdr); |
5564 | 0 | l_len += sizeof(struct sctp_gen_error_cause); |
5565 | 0 | op_err = sctp_get_mbuf_for_msg(l_len, 0, M_NOWAIT, 1, MT_DATA); |
5566 | 0 | if (op_err != NULL) { |
5567 | | /* |
5568 | | * Pre-reserve space for IP, SCTP, and |
5569 | | * chunk header. |
5570 | | */ |
5571 | 0 | #ifdef INET6 |
5572 | 0 | SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); |
5573 | | #else |
5574 | | SCTP_BUF_RESV_UF(op_err, sizeof(struct ip)); |
5575 | | #endif |
5576 | 0 | SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); |
5577 | 0 | SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); |
5578 | 0 | SCTP_BUF_LEN(op_err) = sizeof(struct sctp_gen_error_cause); |
5579 | 0 | cause = mtod(op_err, struct sctp_gen_error_cause *); |
5580 | 0 | cause->code = htons(SCTP_CAUSE_UNRESOLVABLE_ADDR); |
5581 | 0 | cause->length = htons((uint16_t)(sizeof(struct sctp_gen_error_cause) + plen)); |
5582 | 0 | SCTP_BUF_NEXT(op_err) = SCTP_M_COPYM(mat, at, plen, M_NOWAIT); |
5583 | 0 | if (SCTP_BUF_NEXT(op_err) == NULL) { |
5584 | 0 | sctp_m_freem(op_err); |
5585 | 0 | op_err = NULL; |
5586 | 0 | op_err_last = NULL; |
5587 | 0 | } |
5588 | 0 | } |
5589 | 0 | return (op_err); |
5590 | 0 | } |
5591 | 1.60k | default: |
5592 | | /* |
5593 | | * we do not recognize the parameter figure out what |
5594 | | * we do. |
5595 | | */ |
5596 | 1.60k | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Hit default param %x\n", ptype); |
5597 | 1.60k | if ((ptype & 0x4000) == 0x4000) { |
5598 | | /* Report bit is set?? */ |
5599 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "report op err\n"); |
5600 | 0 | if (op_err == NULL) { |
5601 | 0 | int l_len; |
5602 | | /* Ok need to try to get an mbuf */ |
5603 | 0 | #ifdef INET6 |
5604 | 0 | l_len = SCTP_MIN_OVERHEAD; |
5605 | | #else |
5606 | | l_len = SCTP_MIN_V4_OVERHEAD; |
5607 | | #endif |
5608 | 0 | l_len += sizeof(struct sctp_chunkhdr); |
5609 | 0 | l_len += sizeof(struct sctp_paramhdr); |
5610 | 0 | op_err = sctp_get_mbuf_for_msg(l_len, 0, M_NOWAIT, 1, MT_DATA); |
5611 | 0 | if (op_err) { |
5612 | 0 | SCTP_BUF_LEN(op_err) = 0; |
5613 | 0 | #ifdef INET6 |
5614 | 0 | SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); |
5615 | | #else |
5616 | | SCTP_BUF_RESV_UF(op_err, sizeof(struct ip)); |
5617 | | #endif |
5618 | 0 | SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); |
5619 | 0 | SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); |
5620 | 0 | op_err_last = op_err; |
5621 | 0 | } |
5622 | 0 | } |
5623 | 0 | if (op_err != NULL) { |
5624 | | /* If we have space */ |
5625 | 0 | struct sctp_paramhdr *param; |
5626 | |
|
5627 | 0 | if (pad_needed > 0) { |
5628 | 0 | op_err_last = sctp_add_pad_tombuf(op_err_last, pad_needed); |
5629 | 0 | } |
5630 | 0 | if (op_err_last == NULL) { |
5631 | 0 | sctp_m_freem(op_err); |
5632 | 0 | op_err = NULL; |
5633 | 0 | op_err_last = NULL; |
5634 | 0 | goto more_processing; |
5635 | 0 | } |
5636 | 0 | if (M_TRAILINGSPACE(op_err_last) < (int)sizeof(struct sctp_paramhdr)) { |
5637 | 0 | m_tmp = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA); |
5638 | 0 | if (m_tmp == NULL) { |
5639 | 0 | sctp_m_freem(op_err); |
5640 | 0 | op_err = NULL; |
5641 | 0 | op_err_last = NULL; |
5642 | 0 | goto more_processing; |
5643 | 0 | } |
5644 | 0 | SCTP_BUF_LEN(m_tmp) = 0; |
5645 | 0 | SCTP_BUF_NEXT(m_tmp) = NULL; |
5646 | 0 | SCTP_BUF_NEXT(op_err_last) = m_tmp; |
5647 | 0 | op_err_last = m_tmp; |
5648 | 0 | } |
5649 | 0 | param = (struct sctp_paramhdr *)(mtod(op_err_last, caddr_t) + SCTP_BUF_LEN(op_err_last)); |
5650 | 0 | param->param_type = htons(SCTP_UNRECOG_PARAM); |
5651 | 0 | param->param_length = htons((uint16_t)sizeof(struct sctp_paramhdr) + plen); |
5652 | 0 | SCTP_BUF_LEN(op_err_last) += sizeof(struct sctp_paramhdr); |
5653 | 0 | SCTP_BUF_NEXT(op_err_last) = SCTP_M_COPYM(mat, at, plen, M_NOWAIT); |
5654 | 0 | if (SCTP_BUF_NEXT(op_err_last) == NULL) { |
5655 | 0 | sctp_m_freem(op_err); |
5656 | 0 | op_err = NULL; |
5657 | 0 | op_err_last = NULL; |
5658 | 0 | goto more_processing; |
5659 | 0 | } else { |
5660 | 0 | while (SCTP_BUF_NEXT(op_err_last) != NULL) { |
5661 | 0 | op_err_last = SCTP_BUF_NEXT(op_err_last); |
5662 | 0 | } |
5663 | 0 | } |
5664 | 0 | if (plen % 4 != 0) { |
5665 | 0 | pad_needed = 4 - (plen % 4); |
5666 | 0 | } else { |
5667 | 0 | pad_needed = 0; |
5668 | 0 | } |
5669 | 0 | } |
5670 | 0 | } |
5671 | 1.60k | more_processing: |
5672 | 1.60k | if ((ptype & 0x8000) == 0x0000) { |
5673 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "stop proc\n"); |
5674 | 0 | return (op_err); |
5675 | 1.60k | } else { |
5676 | | /* skip this chunk and continue processing */ |
5677 | 1.60k | SCTPDBG(SCTP_DEBUG_OUTPUT1, "move on\n"); |
5678 | 1.60k | at += SCTP_SIZE32(plen); |
5679 | 1.60k | } |
5680 | 1.60k | break; |
5681 | 12.8k | } |
5682 | 12.8k | phdr = sctp_get_next_param(mat, at, ¶ms, sizeof(params)); |
5683 | 12.8k | } |
5684 | 1.60k | return (op_err); |
5685 | 0 | invalid_size: |
5686 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "abort flag set\n"); |
5687 | 0 | *abort_processing = 1; |
5688 | 0 | sctp_m_freem(op_err); |
5689 | 0 | op_err = NULL; |
5690 | 0 | op_err_last = NULL; |
5691 | 0 | if (phdr != NULL) { |
5692 | 0 | struct sctp_paramhdr *param; |
5693 | 0 | int l_len; |
5694 | 0 | #ifdef INET6 |
5695 | 0 | l_len = SCTP_MIN_OVERHEAD; |
5696 | | #else |
5697 | | l_len = SCTP_MIN_V4_OVERHEAD; |
5698 | | #endif |
5699 | 0 | l_len += sizeof(struct sctp_chunkhdr); |
5700 | 0 | l_len += (2 * sizeof(struct sctp_paramhdr)); |
5701 | 0 | op_err = sctp_get_mbuf_for_msg(l_len, 0, M_NOWAIT, 1, MT_DATA); |
5702 | 0 | if (op_err) { |
5703 | 0 | SCTP_BUF_LEN(op_err) = 0; |
5704 | 0 | #ifdef INET6 |
5705 | 0 | SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); |
5706 | | #else |
5707 | | SCTP_BUF_RESV_UF(op_err, sizeof(struct ip)); |
5708 | | #endif |
5709 | 0 | SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); |
5710 | 0 | SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); |
5711 | 0 | SCTP_BUF_LEN(op_err) = 2 * sizeof(struct sctp_paramhdr); |
5712 | 0 | param = mtod(op_err, struct sctp_paramhdr *); |
5713 | 0 | param->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); |
5714 | 0 | param->param_length = htons(2 * sizeof(struct sctp_paramhdr)); |
5715 | 0 | param++; |
5716 | 0 | param->param_type = htons(ptype); |
5717 | 0 | param->param_length = htons(plen); |
5718 | 0 | } |
5719 | 0 | } |
5720 | 0 | return (op_err); |
5721 | 1.60k | } |
5722 | | |
5723 | | /* |
5724 | | * Given a INIT chunk, look through the parameters to verify that there |
5725 | | * are no new addresses. |
5726 | | * Return true, if there is a new address or there is a problem parsing |
5727 | | the parameters. Provide an optional error cause used when sending an ABORT. |
5728 | | * Return false, if there are no new addresses and there is no problem in |
5729 | | parameter processing. |
5730 | | */ |
5731 | | static bool |
5732 | | sctp_are_there_new_addresses(struct sctp_association *asoc, |
5733 | | struct mbuf *in_initpkt, int offset, int limit, struct sockaddr *src, |
5734 | | struct mbuf **op_err) |
5735 | 0 | { |
5736 | 0 | struct sockaddr *sa_touse; |
5737 | 0 | struct sockaddr *sa; |
5738 | 0 | struct sctp_paramhdr *phdr, params; |
5739 | 0 | struct sctp_nets *net; |
5740 | 0 | #ifdef INET |
5741 | 0 | struct sockaddr_in sin4, *sa4; |
5742 | 0 | #endif |
5743 | 0 | #ifdef INET6 |
5744 | 0 | struct sockaddr_in6 sin6, *sa6; |
5745 | 0 | #endif |
5746 | 0 | #if defined(__Userspace__) |
5747 | 0 | struct sockaddr_conn *sac; |
5748 | 0 | #endif |
5749 | 0 | uint16_t ptype, plen; |
5750 | 0 | bool fnd, check_src; |
5751 | |
|
5752 | 0 | *op_err = NULL; |
5753 | 0 | #ifdef INET |
5754 | 0 | memset(&sin4, 0, sizeof(sin4)); |
5755 | 0 | sin4.sin_family = AF_INET; |
5756 | | #ifdef HAVE_SIN_LEN |
5757 | | sin4.sin_len = sizeof(sin4); |
5758 | | #endif |
5759 | 0 | #endif |
5760 | 0 | #ifdef INET6 |
5761 | 0 | memset(&sin6, 0, sizeof(sin6)); |
5762 | 0 | sin6.sin6_family = AF_INET6; |
5763 | | #ifdef HAVE_SIN6_LEN |
5764 | | sin6.sin6_len = sizeof(sin6); |
5765 | | #endif |
5766 | 0 | #endif |
5767 | | /* First what about the src address of the pkt ? */ |
5768 | 0 | check_src = false; |
5769 | 0 | switch (src->sa_family) { |
5770 | 0 | #ifdef INET |
5771 | 0 | case AF_INET: |
5772 | 0 | if (asoc->scope.ipv4_addr_legal) { |
5773 | 0 | check_src = true; |
5774 | 0 | } |
5775 | 0 | break; |
5776 | 0 | #endif |
5777 | 0 | #ifdef INET6 |
5778 | 0 | case AF_INET6: |
5779 | 0 | if (asoc->scope.ipv6_addr_legal) { |
5780 | 0 | check_src = true; |
5781 | 0 | } |
5782 | 0 | break; |
5783 | 0 | #endif |
5784 | 0 | #if defined(__Userspace__) |
5785 | 0 | case AF_CONN: |
5786 | 0 | if (asoc->scope.conn_addr_legal) { |
5787 | 0 | check_src = true; |
5788 | 0 | } |
5789 | 0 | break; |
5790 | 0 | #endif |
5791 | 0 | default: |
5792 | | /* TSNH */ |
5793 | 0 | break; |
5794 | 0 | } |
5795 | 0 | if (check_src) { |
5796 | 0 | fnd = false; |
5797 | 0 | TAILQ_FOREACH(net, &asoc->nets, sctp_next) { |
5798 | 0 | sa = (struct sockaddr *)&net->ro._l_addr; |
5799 | 0 | if (sa->sa_family == src->sa_family) { |
5800 | 0 | #ifdef INET |
5801 | 0 | if (sa->sa_family == AF_INET) { |
5802 | 0 | struct sockaddr_in *src4; |
5803 | |
|
5804 | 0 | sa4 = (struct sockaddr_in *)sa; |
5805 | 0 | src4 = (struct sockaddr_in *)src; |
5806 | 0 | if (sa4->sin_addr.s_addr == src4->sin_addr.s_addr) { |
5807 | 0 | fnd = true; |
5808 | 0 | break; |
5809 | 0 | } |
5810 | 0 | } |
5811 | 0 | #endif |
5812 | 0 | #ifdef INET6 |
5813 | 0 | if (sa->sa_family == AF_INET6) { |
5814 | 0 | struct sockaddr_in6 *src6; |
5815 | |
|
5816 | 0 | sa6 = (struct sockaddr_in6 *)sa; |
5817 | 0 | src6 = (struct sockaddr_in6 *)src; |
5818 | 0 | if (SCTP6_ARE_ADDR_EQUAL(sa6, src6)) { |
5819 | 0 | fnd = true; |
5820 | 0 | break; |
5821 | 0 | } |
5822 | 0 | } |
5823 | 0 | #endif |
5824 | 0 | #if defined(__Userspace__) |
5825 | 0 | if (sa->sa_family == AF_CONN) { |
5826 | 0 | struct sockaddr_conn *srcc; |
5827 | |
|
5828 | 0 | sac = (struct sockaddr_conn *)sa; |
5829 | 0 | srcc = (struct sockaddr_conn *)src; |
5830 | 0 | if (sac->sconn_addr == srcc->sconn_addr) { |
5831 | 0 | fnd = true; |
5832 | 0 | break; |
5833 | 0 | } |
5834 | 0 | } |
5835 | 0 | #endif |
5836 | 0 | } |
5837 | 0 | } |
5838 | 0 | if (!fnd) { |
5839 | | /* |
5840 | | * If sending an ABORT in case of an additional address, |
5841 | | * don't use the new address error cause. |
5842 | | * This looks no different than if no listener was |
5843 | | * present. |
5844 | | */ |
5845 | 0 | *op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), "Address added"); |
5846 | 0 | return (true); |
5847 | 0 | } |
5848 | 0 | } |
5849 | | /* Ok so far lets munge through the rest of the packet */ |
5850 | 0 | offset += sizeof(struct sctp_init_chunk); |
5851 | 0 | phdr = sctp_get_next_param(in_initpkt, offset, ¶ms, sizeof(params)); |
5852 | 0 | while (phdr) { |
5853 | 0 | sa_touse = NULL; |
5854 | 0 | ptype = ntohs(phdr->param_type); |
5855 | 0 | plen = ntohs(phdr->param_length); |
5856 | 0 | if (offset + plen > limit) { |
5857 | 0 | *op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, "Partial parameter"); |
5858 | 0 | return (true); |
5859 | 0 | } |
5860 | 0 | if (plen < sizeof(struct sctp_paramhdr)) { |
5861 | 0 | *op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, "Parameter length too small"); |
5862 | 0 | return (true); |
5863 | 0 | } |
5864 | 0 | switch (ptype) { |
5865 | 0 | #ifdef INET |
5866 | 0 | case SCTP_IPV4_ADDRESS: |
5867 | 0 | { |
5868 | 0 | struct sctp_ipv4addr_param *p4, p4_buf; |
5869 | |
|
5870 | 0 | if (plen != sizeof(struct sctp_ipv4addr_param)) { |
5871 | 0 | *op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, "Parameter length illegal"); |
5872 | 0 | return (true); |
5873 | 0 | } |
5874 | 0 | phdr = sctp_get_next_param(in_initpkt, offset, |
5875 | 0 | (struct sctp_paramhdr *)&p4_buf, sizeof(p4_buf)); |
5876 | 0 | if (phdr == NULL) { |
5877 | 0 | *op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, ""); |
5878 | 0 | return (true); |
5879 | 0 | } |
5880 | 0 | if (asoc->scope.ipv4_addr_legal) { |
5881 | 0 | p4 = (struct sctp_ipv4addr_param *)phdr; |
5882 | 0 | sin4.sin_addr.s_addr = p4->addr; |
5883 | 0 | sa_touse = (struct sockaddr *)&sin4; |
5884 | 0 | } |
5885 | 0 | break; |
5886 | 0 | } |
5887 | 0 | #endif |
5888 | 0 | #ifdef INET6 |
5889 | 0 | case SCTP_IPV6_ADDRESS: |
5890 | 0 | { |
5891 | 0 | struct sctp_ipv6addr_param *p6, p6_buf; |
5892 | |
|
5893 | 0 | if (plen != sizeof(struct sctp_ipv6addr_param)) { |
5894 | 0 | *op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, "Parameter length illegal"); |
5895 | 0 | return (true); |
5896 | 0 | } |
5897 | 0 | phdr = sctp_get_next_param(in_initpkt, offset, |
5898 | 0 | (struct sctp_paramhdr *)&p6_buf, sizeof(p6_buf)); |
5899 | 0 | if (phdr == NULL) { |
5900 | 0 | *op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, ""); |
5901 | 0 | return (true); |
5902 | 0 | } |
5903 | 0 | if (asoc->scope.ipv6_addr_legal) { |
5904 | 0 | p6 = (struct sctp_ipv6addr_param *)phdr; |
5905 | 0 | memcpy((caddr_t)&sin6.sin6_addr, p6->addr, |
5906 | 0 | sizeof(p6->addr)); |
5907 | 0 | sa_touse = (struct sockaddr *)&sin6; |
5908 | 0 | } |
5909 | 0 | break; |
5910 | 0 | } |
5911 | 0 | #endif |
5912 | 0 | default: |
5913 | 0 | sa_touse = NULL; |
5914 | 0 | break; |
5915 | 0 | } |
5916 | 0 | if (sa_touse) { |
5917 | | /* ok, sa_touse points to one to check */ |
5918 | 0 | fnd = false; |
5919 | 0 | TAILQ_FOREACH(net, &asoc->nets, sctp_next) { |
5920 | 0 | sa = (struct sockaddr *)&net->ro._l_addr; |
5921 | 0 | if (sa->sa_family != sa_touse->sa_family) { |
5922 | 0 | continue; |
5923 | 0 | } |
5924 | 0 | #ifdef INET |
5925 | 0 | if (sa->sa_family == AF_INET) { |
5926 | 0 | sa4 = (struct sockaddr_in *)sa; |
5927 | 0 | if (sa4->sin_addr.s_addr == |
5928 | 0 | sin4.sin_addr.s_addr) { |
5929 | 0 | fnd = true; |
5930 | 0 | break; |
5931 | 0 | } |
5932 | 0 | } |
5933 | 0 | #endif |
5934 | 0 | #ifdef INET6 |
5935 | 0 | if (sa->sa_family == AF_INET6) { |
5936 | 0 | sa6 = (struct sockaddr_in6 *)sa; |
5937 | 0 | if (SCTP6_ARE_ADDR_EQUAL( |
5938 | 0 | sa6, &sin6)) { |
5939 | 0 | fnd = true; |
5940 | 0 | break; |
5941 | 0 | } |
5942 | 0 | } |
5943 | 0 | #endif |
5944 | 0 | } |
5945 | 0 | if (!fnd) { |
5946 | | /* |
5947 | | * If sending an ABORT in case of an additional |
5948 | | * address, don't use the new address error |
5949 | | * cause. |
5950 | | * This looks no different than if no listener |
5951 | | * was present. |
5952 | | */ |
5953 | 0 | *op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), "Address added"); |
5954 | 0 | return (true); |
5955 | 0 | } |
5956 | 0 | } |
5957 | 0 | offset += SCTP_SIZE32(plen); |
5958 | 0 | if (offset >= limit) { |
5959 | 0 | break; |
5960 | 0 | } |
5961 | 0 | phdr = sctp_get_next_param(in_initpkt, offset, ¶ms, sizeof(params)); |
5962 | 0 | } |
5963 | 0 | return (false); |
5964 | 0 | } |
5965 | | |
5966 | | /* |
5967 | | * Given a MBUF chain that was sent into us containing an INIT. Build a |
5968 | | * INIT-ACK with COOKIE and send back. We assume that the in_initpkt has done |
5969 | | * a pullup to include IPv6/4header, SCTP header and initial part of INIT |
5970 | | * message (i.e. the struct sctp_init_msg). |
5971 | | */ |
5972 | | void |
5973 | | sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, |
5974 | | struct sctp_nets *src_net, struct mbuf *init_pkt, |
5975 | | int iphlen, int offset, |
5976 | | struct sockaddr *src, struct sockaddr *dst, |
5977 | | struct sctphdr *sh, struct sctp_init_chunk *init_chk, |
5978 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
5979 | | uint8_t mflowtype, uint32_t mflowid, |
5980 | | #endif |
5981 | | uint32_t vrf_id, uint16_t port) |
5982 | 0 | { |
5983 | 0 | struct sctp_association *asoc; |
5984 | 0 | struct mbuf *m, *m_tmp, *m_last, *m_cookie, *op_err; |
5985 | 0 | struct sctp_init_ack_chunk *initack; |
5986 | 0 | struct sctp_adaptation_layer_indication *ali; |
5987 | 0 | struct sctp_zero_checksum_acceptable *zero_chksum; |
5988 | 0 | struct sctp_supported_chunk_types_param *pr_supported; |
5989 | 0 | struct sctp_paramhdr *ph; |
5990 | 0 | union sctp_sockstore *over_addr; |
5991 | 0 | struct sctp_scoping scp; |
5992 | 0 | struct timeval now; |
5993 | 0 | #ifdef INET |
5994 | 0 | struct sockaddr_in *dst4 = (struct sockaddr_in *)dst; |
5995 | 0 | struct sockaddr_in *src4 = (struct sockaddr_in *)src; |
5996 | 0 | struct sockaddr_in *sin; |
5997 | 0 | #endif |
5998 | 0 | #ifdef INET6 |
5999 | 0 | struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)dst; |
6000 | 0 | struct sockaddr_in6 *src6 = (struct sockaddr_in6 *)src; |
6001 | 0 | struct sockaddr_in6 *sin6; |
6002 | 0 | #endif |
6003 | 0 | #if defined(__Userspace__) |
6004 | 0 | struct sockaddr_conn *dstconn = (struct sockaddr_conn *)dst; |
6005 | 0 | struct sockaddr_conn *srcconn = (struct sockaddr_conn *)src; |
6006 | 0 | struct sockaddr_conn *sconn; |
6007 | 0 | #endif |
6008 | 0 | struct sockaddr *to; |
6009 | 0 | struct sctp_state_cookie stc; |
6010 | 0 | struct sctp_nets *net = NULL; |
6011 | 0 | uint8_t *signature = NULL; |
6012 | 0 | int cnt_inits_to = 0; |
6013 | 0 | uint16_t his_limit, i_want; |
6014 | 0 | int abort_flag; |
6015 | 0 | int nat_friendly = 0; |
6016 | 0 | int error; |
6017 | 0 | struct socket *so; |
6018 | 0 | uint32_t edmid; |
6019 | 0 | uint16_t num_ext, chunk_len, padding_len, parameter_len; |
6020 | 0 | bool use_zero_crc; |
6021 | |
|
6022 | 0 | if (stcb) { |
6023 | 0 | asoc = &stcb->asoc; |
6024 | 0 | } else { |
6025 | 0 | asoc = NULL; |
6026 | 0 | } |
6027 | 0 | if ((asoc != NULL) && |
6028 | 0 | (SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT)) { |
6029 | 0 | if (sctp_are_there_new_addresses(asoc, init_pkt, offset, offset + ntohs(init_chk->ch.chunk_length), src, &op_err)) { |
6030 | | /* |
6031 | | * new addresses, out of here in non-cookie-wait states |
6032 | | */ |
6033 | 0 | sctp_send_abort(init_pkt, iphlen, src, dst, sh, 0, op_err, |
6034 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
6035 | | mflowtype, mflowid, inp->fibnum, |
6036 | | #endif |
6037 | 0 | vrf_id, port); |
6038 | 0 | return; |
6039 | 0 | } |
6040 | 0 | if (src_net != NULL && (src_net->port != port)) { |
6041 | | /* |
6042 | | * change of remote encapsulation port, out of here in |
6043 | | * non-cookie-wait states |
6044 | | * |
6045 | | * Send an ABORT, without an specific error cause. |
6046 | | * This looks no different than if no listener |
6047 | | * was present. |
6048 | | */ |
6049 | 0 | op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), |
6050 | 0 | "Remote encapsulation port changed"); |
6051 | 0 | sctp_send_abort(init_pkt, iphlen, src, dst, sh, 0, op_err, |
6052 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
6053 | | mflowtype, mflowid, inp->fibnum, |
6054 | | #endif |
6055 | 0 | vrf_id, port); |
6056 | 0 | return; |
6057 | 0 | } |
6058 | 0 | } |
6059 | 0 | abort_flag = 0; |
6060 | 0 | op_err = sctp_arethere_unrecognized_parameters(init_pkt, |
6061 | 0 | (offset + sizeof(struct sctp_init_chunk)), |
6062 | 0 | &abort_flag, |
6063 | 0 | (struct sctp_chunkhdr *)init_chk, |
6064 | 0 | &nat_friendly, NULL, &edmid); |
6065 | 0 | if (abort_flag) { |
6066 | 0 | do_a_abort: |
6067 | 0 | if (op_err == NULL) { |
6068 | 0 | char msg[SCTP_DIAG_INFO_LEN]; |
6069 | |
|
6070 | 0 | SCTP_SNPRINTF(msg, sizeof(msg), "%s:%d at %s", __FILE__, __LINE__, __func__); |
6071 | 0 | op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), |
6072 | 0 | msg); |
6073 | 0 | } |
6074 | 0 | sctp_send_abort(init_pkt, iphlen, src, dst, sh, |
6075 | 0 | init_chk->init.initiate_tag, op_err, |
6076 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
6077 | | mflowtype, mflowid, inp->fibnum, |
6078 | | #endif |
6079 | 0 | vrf_id, port); |
6080 | 0 | return; |
6081 | 0 | } |
6082 | 0 | m = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); |
6083 | 0 | if (m == NULL) { |
6084 | | /* No memory, INIT timer will re-attempt. */ |
6085 | 0 | sctp_m_freem(op_err); |
6086 | 0 | return; |
6087 | 0 | } |
6088 | 0 | chunk_len = (uint16_t)sizeof(struct sctp_init_ack_chunk); |
6089 | 0 | padding_len = 0; |
6090 | | |
6091 | | /* |
6092 | | * We might not overwrite the identification[] completely and on |
6093 | | * some platforms time_entered will contain some padding. |
6094 | | * Therefore zero out the cookie to avoid putting |
6095 | | * uninitialized memory on the wire. |
6096 | | */ |
6097 | 0 | memset(&stc, 0, sizeof(struct sctp_state_cookie)); |
6098 | | |
6099 | | /* the time I built cookie */ |
6100 | 0 | (void)SCTP_GETTIME_TIMEVAL(&now); |
6101 | 0 | stc.time_entered.tv_sec = now.tv_sec; |
6102 | 0 | stc.time_entered.tv_usec = now.tv_usec; |
6103 | | |
6104 | | /* populate any tie tags */ |
6105 | 0 | if (asoc != NULL) { |
6106 | | /* unlock before tag selections */ |
6107 | 0 | stc.tie_tag_my_vtag = asoc->my_vtag_nonce; |
6108 | 0 | stc.tie_tag_peer_vtag = asoc->peer_vtag_nonce; |
6109 | 0 | stc.cookie_life = asoc->cookie_life; |
6110 | 0 | net = asoc->primary_destination; |
6111 | 0 | } else { |
6112 | 0 | stc.tie_tag_my_vtag = 0; |
6113 | 0 | stc.tie_tag_peer_vtag = 0; |
6114 | | /* life I will award this cookie */ |
6115 | 0 | stc.cookie_life = inp->sctp_ep.def_cookie_life; |
6116 | 0 | } |
6117 | | |
6118 | | /* copy in the ports for later check */ |
6119 | 0 | stc.myport = sh->dest_port; |
6120 | 0 | stc.peerport = sh->src_port; |
6121 | | |
6122 | | /* |
6123 | | * If we wanted to honor cookie life extensions, we would add to |
6124 | | * stc.cookie_life. For now we should NOT honor any extension |
6125 | | */ |
6126 | 0 | stc.site_scope = stc.local_scope = stc.loopback_scope = 0; |
6127 | 0 | if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { |
6128 | 0 | stc.ipv6_addr_legal = 1; |
6129 | 0 | if (SCTP_IPV6_V6ONLY(inp)) { |
6130 | 0 | stc.ipv4_addr_legal = 0; |
6131 | 0 | } else { |
6132 | 0 | stc.ipv4_addr_legal = 1; |
6133 | 0 | } |
6134 | 0 | #if defined(__Userspace__) |
6135 | 0 | stc.conn_addr_legal = 0; |
6136 | 0 | #endif |
6137 | 0 | } else { |
6138 | 0 | stc.ipv6_addr_legal = 0; |
6139 | 0 | #if defined(__Userspace__) |
6140 | 0 | if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) { |
6141 | 0 | stc.conn_addr_legal = 1; |
6142 | 0 | stc.ipv4_addr_legal = 0; |
6143 | 0 | } else { |
6144 | 0 | stc.conn_addr_legal = 0; |
6145 | 0 | stc.ipv4_addr_legal = 1; |
6146 | 0 | } |
6147 | | #else |
6148 | | stc.ipv4_addr_legal = 1; |
6149 | | #endif |
6150 | 0 | } |
6151 | 0 | stc.ipv4_scope = 0; |
6152 | 0 | if (net == NULL) { |
6153 | 0 | to = src; |
6154 | 0 | switch (dst->sa_family) { |
6155 | 0 | #ifdef INET |
6156 | 0 | case AF_INET: |
6157 | 0 | { |
6158 | | /* lookup address */ |
6159 | 0 | stc.address[0] = src4->sin_addr.s_addr; |
6160 | 0 | stc.address[1] = 0; |
6161 | 0 | stc.address[2] = 0; |
6162 | 0 | stc.address[3] = 0; |
6163 | 0 | stc.addr_type = SCTP_IPV4_ADDRESS; |
6164 | | /* local from address */ |
6165 | 0 | stc.laddress[0] = dst4->sin_addr.s_addr; |
6166 | 0 | stc.laddress[1] = 0; |
6167 | 0 | stc.laddress[2] = 0; |
6168 | 0 | stc.laddress[3] = 0; |
6169 | 0 | stc.laddr_type = SCTP_IPV4_ADDRESS; |
6170 | | /* scope_id is only for v6 */ |
6171 | 0 | stc.scope_id = 0; |
6172 | 0 | if ((IN4_ISPRIVATE_ADDRESS(&src4->sin_addr)) || |
6173 | 0 | (IN4_ISPRIVATE_ADDRESS(&dst4->sin_addr))) { |
6174 | 0 | stc.ipv4_scope = 1; |
6175 | 0 | } |
6176 | | /* Must use the address in this case */ |
6177 | 0 | if (sctp_is_address_on_local_host(src, vrf_id)) { |
6178 | 0 | stc.loopback_scope = 1; |
6179 | 0 | stc.ipv4_scope = 1; |
6180 | 0 | stc.site_scope = 1; |
6181 | 0 | stc.local_scope = 0; |
6182 | 0 | } |
6183 | 0 | break; |
6184 | 0 | } |
6185 | 0 | #endif |
6186 | 0 | #ifdef INET6 |
6187 | 0 | case AF_INET6: |
6188 | 0 | { |
6189 | 0 | stc.addr_type = SCTP_IPV6_ADDRESS; |
6190 | 0 | memcpy(&stc.address, &src6->sin6_addr, sizeof(struct in6_addr)); |
6191 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
6192 | | stc.scope_id = ntohs(in6_getscope(&src6->sin6_addr)); |
6193 | | #else |
6194 | 0 | stc.scope_id = 0; |
6195 | 0 | #endif |
6196 | 0 | if (sctp_is_address_on_local_host(src, vrf_id)) { |
6197 | 0 | stc.loopback_scope = 1; |
6198 | 0 | stc.local_scope = 0; |
6199 | 0 | stc.site_scope = 1; |
6200 | 0 | stc.ipv4_scope = 1; |
6201 | 0 | } else if (IN6_IS_ADDR_LINKLOCAL(&src6->sin6_addr) || |
6202 | 0 | IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr)) { |
6203 | | /* |
6204 | | * If the new destination or source is a |
6205 | | * LINK_LOCAL we must have common both site and |
6206 | | * local scope. Don't set local scope though |
6207 | | * since we must depend on the source to be |
6208 | | * added implicitly. We cannot assure just |
6209 | | * because we share one link that all links are |
6210 | | * common. |
6211 | | */ |
6212 | | #if defined(__APPLE__) && !defined(__Userspace__) |
6213 | | /* Mac OS X currently doesn't have in6_getscope() */ |
6214 | | stc.scope_id = src6->sin6_addr.s6_addr16[1]; |
6215 | | #endif |
6216 | 0 | stc.local_scope = 0; |
6217 | 0 | stc.site_scope = 1; |
6218 | 0 | stc.ipv4_scope = 1; |
6219 | | /* |
6220 | | * we start counting for the private address |
6221 | | * stuff at 1. since the link local we |
6222 | | * source from won't show up in our scoped |
6223 | | * count. |
6224 | | */ |
6225 | 0 | cnt_inits_to = 1; |
6226 | | /* pull out the scope_id from incoming pkt */ |
6227 | 0 | } else if (IN6_IS_ADDR_SITELOCAL(&src6->sin6_addr) || |
6228 | 0 | IN6_IS_ADDR_SITELOCAL(&dst6->sin6_addr)) { |
6229 | | /* |
6230 | | * If the new destination or source is |
6231 | | * SITE_LOCAL then we must have site scope in |
6232 | | * common. |
6233 | | */ |
6234 | 0 | stc.site_scope = 1; |
6235 | 0 | } |
6236 | 0 | memcpy(&stc.laddress, &dst6->sin6_addr, sizeof(struct in6_addr)); |
6237 | 0 | stc.laddr_type = SCTP_IPV6_ADDRESS; |
6238 | 0 | break; |
6239 | 0 | } |
6240 | 0 | #endif |
6241 | 0 | #if defined(__Userspace__) |
6242 | 0 | case AF_CONN: |
6243 | 0 | { |
6244 | | /* lookup address */ |
6245 | 0 | stc.address[0] = 0; |
6246 | 0 | stc.address[1] = 0; |
6247 | 0 | stc.address[2] = 0; |
6248 | 0 | stc.address[3] = 0; |
6249 | 0 | memcpy(&stc.address, &srcconn->sconn_addr, sizeof(void *)); |
6250 | 0 | stc.addr_type = SCTP_CONN_ADDRESS; |
6251 | | /* local from address */ |
6252 | 0 | stc.laddress[0] = 0; |
6253 | 0 | stc.laddress[1] = 0; |
6254 | 0 | stc.laddress[2] = 0; |
6255 | 0 | stc.laddress[3] = 0; |
6256 | 0 | memcpy(&stc.laddress, &dstconn->sconn_addr, sizeof(void *)); |
6257 | 0 | stc.laddr_type = SCTP_CONN_ADDRESS; |
6258 | | /* scope_id is only for v6 */ |
6259 | 0 | stc.scope_id = 0; |
6260 | 0 | break; |
6261 | 0 | } |
6262 | 0 | #endif |
6263 | 0 | default: |
6264 | | /* TSNH */ |
6265 | 0 | goto do_a_abort; |
6266 | 0 | break; |
6267 | 0 | } |
6268 | 0 | } else { |
6269 | | /* set the scope per the existing tcb */ |
6270 | |
|
6271 | 0 | #ifdef INET6 |
6272 | 0 | struct sctp_nets *lnet; |
6273 | 0 | #endif |
6274 | |
|
6275 | 0 | stc.loopback_scope = asoc->scope.loopback_scope; |
6276 | 0 | stc.ipv4_scope = asoc->scope.ipv4_local_scope; |
6277 | 0 | stc.site_scope = asoc->scope.site_scope; |
6278 | 0 | stc.local_scope = asoc->scope.local_scope; |
6279 | 0 | #ifdef INET6 |
6280 | | /* Why do we not consider IPv4 LL addresses? */ |
6281 | 0 | TAILQ_FOREACH(lnet, &asoc->nets, sctp_next) { |
6282 | 0 | if (lnet->ro._l_addr.sin6.sin6_family == AF_INET6) { |
6283 | 0 | if (IN6_IS_ADDR_LINKLOCAL(&lnet->ro._l_addr.sin6.sin6_addr)) { |
6284 | | /* |
6285 | | * if we have a LL address, start |
6286 | | * counting at 1. |
6287 | | */ |
6288 | 0 | cnt_inits_to = 1; |
6289 | 0 | } |
6290 | 0 | } |
6291 | 0 | } |
6292 | 0 | #endif |
6293 | | /* use the net pointer */ |
6294 | 0 | to = (struct sockaddr *)&net->ro._l_addr; |
6295 | 0 | switch (to->sa_family) { |
6296 | 0 | #ifdef INET |
6297 | 0 | case AF_INET: |
6298 | 0 | sin = (struct sockaddr_in *)to; |
6299 | 0 | stc.address[0] = sin->sin_addr.s_addr; |
6300 | 0 | stc.address[1] = 0; |
6301 | 0 | stc.address[2] = 0; |
6302 | 0 | stc.address[3] = 0; |
6303 | 0 | stc.addr_type = SCTP_IPV4_ADDRESS; |
6304 | 0 | if (net->src_addr_selected == 0) { |
6305 | | /* |
6306 | | * strange case here, the INIT should have |
6307 | | * did the selection. |
6308 | | */ |
6309 | 0 | net->ro._s_addr = sctp_source_address_selection(inp, |
6310 | 0 | stcb, (sctp_route_t *)&net->ro, |
6311 | 0 | net, 0, vrf_id); |
6312 | 0 | if (net->ro._s_addr == NULL) { |
6313 | 0 | sctp_m_freem(op_err); |
6314 | 0 | sctp_m_freem(m); |
6315 | 0 | return; |
6316 | 0 | } |
6317 | | |
6318 | 0 | net->src_addr_selected = 1; |
6319 | 0 | } |
6320 | 0 | stc.laddress[0] = net->ro._s_addr->address.sin.sin_addr.s_addr; |
6321 | 0 | stc.laddress[1] = 0; |
6322 | 0 | stc.laddress[2] = 0; |
6323 | 0 | stc.laddress[3] = 0; |
6324 | 0 | stc.laddr_type = SCTP_IPV4_ADDRESS; |
6325 | | /* scope_id is only for v6 */ |
6326 | 0 | stc.scope_id = 0; |
6327 | 0 | break; |
6328 | 0 | #endif |
6329 | 0 | #ifdef INET6 |
6330 | 0 | case AF_INET6: |
6331 | 0 | sin6 = (struct sockaddr_in6 *)to; |
6332 | 0 | memcpy(&stc.address, &sin6->sin6_addr, |
6333 | 0 | sizeof(struct in6_addr)); |
6334 | 0 | stc.addr_type = SCTP_IPV6_ADDRESS; |
6335 | 0 | stc.scope_id = sin6->sin6_scope_id; |
6336 | 0 | if (net->src_addr_selected == 0) { |
6337 | | /* |
6338 | | * strange case here, the INIT should have |
6339 | | * done the selection. |
6340 | | */ |
6341 | 0 | net->ro._s_addr = sctp_source_address_selection(inp, |
6342 | 0 | stcb, (sctp_route_t *)&net->ro, |
6343 | 0 | net, 0, vrf_id); |
6344 | 0 | if (net->ro._s_addr == NULL) { |
6345 | 0 | sctp_m_freem(op_err); |
6346 | 0 | sctp_m_freem(m); |
6347 | 0 | return; |
6348 | 0 | } |
6349 | | |
6350 | 0 | net->src_addr_selected = 1; |
6351 | 0 | } |
6352 | 0 | memcpy(&stc.laddress, &net->ro._s_addr->address.sin6.sin6_addr, |
6353 | 0 | sizeof(struct in6_addr)); |
6354 | 0 | stc.laddr_type = SCTP_IPV6_ADDRESS; |
6355 | 0 | break; |
6356 | 0 | #endif |
6357 | 0 | #if defined(__Userspace__) |
6358 | 0 | case AF_CONN: |
6359 | 0 | sconn = (struct sockaddr_conn *)to; |
6360 | 0 | stc.address[0] = 0; |
6361 | 0 | stc.address[1] = 0; |
6362 | 0 | stc.address[2] = 0; |
6363 | 0 | stc.address[3] = 0; |
6364 | 0 | memcpy(&stc.address, &sconn->sconn_addr, sizeof(void *)); |
6365 | 0 | stc.addr_type = SCTP_CONN_ADDRESS; |
6366 | 0 | stc.laddress[0] = 0; |
6367 | 0 | stc.laddress[1] = 0; |
6368 | 0 | stc.laddress[2] = 0; |
6369 | 0 | stc.laddress[3] = 0; |
6370 | 0 | memcpy(&stc.laddress, &sconn->sconn_addr, sizeof(void *)); |
6371 | 0 | stc.laddr_type = SCTP_CONN_ADDRESS; |
6372 | 0 | stc.scope_id = 0; |
6373 | 0 | break; |
6374 | 0 | #endif |
6375 | 0 | } |
6376 | 0 | } |
6377 | 0 | if (asoc != NULL) { |
6378 | 0 | stc.rcv_edmid = asoc->rcv_edmid; |
6379 | 0 | } else { |
6380 | 0 | stc.rcv_edmid = inp->rcv_edmid; |
6381 | 0 | } |
6382 | | /* Now lets put the SCTP header in place */ |
6383 | 0 | initack = mtod(m, struct sctp_init_ack_chunk *); |
6384 | | /* Save it off for quick ref */ |
6385 | 0 | stc.peers_vtag = ntohl(init_chk->init.initiate_tag); |
6386 | | /* who are we */ |
6387 | 0 | memcpy(stc.identification, SCTP_VERSION_STRING, |
6388 | 0 | min(strlen(SCTP_VERSION_STRING), sizeof(stc.identification))); |
6389 | 0 | memset(stc.reserved, 0, SCTP_RESERVE_SPACE); |
6390 | | /* now the chunk header */ |
6391 | 0 | initack->ch.chunk_type = SCTP_INITIATION_ACK; |
6392 | 0 | initack->ch.chunk_flags = 0; |
6393 | | /* fill in later from mbuf we build */ |
6394 | 0 | initack->ch.chunk_length = 0; |
6395 | | /* place in my tag */ |
6396 | 0 | if ((asoc != NULL) && |
6397 | 0 | ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || |
6398 | 0 | (SCTP_GET_STATE(stcb) == SCTP_STATE_INUSE) || |
6399 | 0 | (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED))) { |
6400 | | /* re-use the v-tags and init-seq here */ |
6401 | 0 | initack->init.initiate_tag = htonl(asoc->my_vtag); |
6402 | 0 | initack->init.initial_tsn = htonl(asoc->init_seq_number); |
6403 | 0 | } else { |
6404 | 0 | uint32_t vtag, itsn; |
6405 | |
|
6406 | 0 | if (asoc) { |
6407 | 0 | atomic_add_int(&asoc->refcnt, 1); |
6408 | 0 | SCTP_TCB_UNLOCK(stcb); |
6409 | 0 | new_tag: |
6410 | 0 | SCTP_INP_INFO_RLOCK(); |
6411 | 0 | vtag = sctp_select_a_tag(inp, inp->sctp_lport, sh->src_port, 1); |
6412 | 0 | SCTP_INP_INFO_RUNLOCK(); |
6413 | 0 | if ((asoc->peer_supports_nat) && (vtag == asoc->my_vtag)) { |
6414 | | /* Got a duplicate vtag on some guy behind a nat |
6415 | | * make sure we don't use it. |
6416 | | */ |
6417 | 0 | goto new_tag; |
6418 | 0 | } |
6419 | 0 | initack->init.initiate_tag = htonl(vtag); |
6420 | | /* get a TSN to use too */ |
6421 | 0 | itsn = sctp_select_initial_TSN(&inp->sctp_ep); |
6422 | 0 | initack->init.initial_tsn = htonl(itsn); |
6423 | 0 | SCTP_TCB_LOCK(stcb); |
6424 | 0 | atomic_subtract_int(&asoc->refcnt, 1); |
6425 | 0 | } else { |
6426 | 0 | SCTP_INP_INCR_REF(inp); |
6427 | 0 | SCTP_INP_RUNLOCK(inp); |
6428 | 0 | SCTP_INP_INFO_RLOCK(); |
6429 | 0 | vtag = sctp_select_a_tag(inp, inp->sctp_lport, sh->src_port, 1); |
6430 | 0 | SCTP_INP_INFO_RUNLOCK(); |
6431 | 0 | initack->init.initiate_tag = htonl(vtag); |
6432 | | /* get a TSN to use too */ |
6433 | 0 | initack->init.initial_tsn = htonl(sctp_select_initial_TSN(&inp->sctp_ep)); |
6434 | 0 | SCTP_INP_RLOCK(inp); |
6435 | 0 | SCTP_INP_DECR_REF(inp); |
6436 | 0 | } |
6437 | 0 | } |
6438 | | /* save away my tag to */ |
6439 | 0 | stc.my_vtag = initack->init.initiate_tag; |
6440 | | |
6441 | | /* set up some of the credits. */ |
6442 | 0 | so = inp->sctp_socket; |
6443 | 0 | if (so == NULL) { |
6444 | | /* memory problem */ |
6445 | 0 | sctp_m_freem(op_err); |
6446 | 0 | sctp_m_freem(m); |
6447 | 0 | return; |
6448 | 0 | } else { |
6449 | 0 | initack->init.a_rwnd = htonl(max(SCTP_SB_LIMIT_RCV(so), SCTP_MINIMAL_RWND)); |
6450 | 0 | } |
6451 | | /* set what I want */ |
6452 | 0 | his_limit = ntohs(init_chk->init.num_inbound_streams); |
6453 | | /* choose what I want */ |
6454 | 0 | if (asoc != NULL) { |
6455 | 0 | if (asoc->streamoutcnt > asoc->pre_open_streams) { |
6456 | 0 | i_want = asoc->streamoutcnt; |
6457 | 0 | } else { |
6458 | 0 | i_want = asoc->pre_open_streams; |
6459 | 0 | } |
6460 | 0 | } else { |
6461 | 0 | i_want = inp->sctp_ep.pre_open_stream_count; |
6462 | 0 | } |
6463 | 0 | if (his_limit < i_want) { |
6464 | | /* I Want more :< */ |
6465 | 0 | initack->init.num_outbound_streams = init_chk->init.num_inbound_streams; |
6466 | 0 | } else { |
6467 | | /* I can have what I want :> */ |
6468 | 0 | initack->init.num_outbound_streams = htons(i_want); |
6469 | 0 | } |
6470 | | /* tell him his limit. */ |
6471 | 0 | initack->init.num_inbound_streams = |
6472 | 0 | htons(inp->sctp_ep.max_open_streams_intome); |
6473 | | |
6474 | | /* adaptation layer indication parameter */ |
6475 | 0 | if (inp->sctp_ep.adaptation_layer_indicator_provided) { |
6476 | 0 | parameter_len = (uint16_t)sizeof(struct sctp_adaptation_layer_indication); |
6477 | 0 | ali = (struct sctp_adaptation_layer_indication *)(mtod(m, caddr_t) + chunk_len); |
6478 | 0 | ali->ph.param_type = htons(SCTP_ULP_ADAPTATION); |
6479 | 0 | ali->ph.param_length = htons(parameter_len); |
6480 | 0 | ali->indication = htonl(inp->sctp_ep.adaptation_layer_indicator); |
6481 | 0 | chunk_len += parameter_len; |
6482 | 0 | } |
6483 | | |
6484 | | /* ECN parameter */ |
6485 | 0 | if (((asoc != NULL) && (asoc->ecn_supported == 1)) || |
6486 | 0 | ((asoc == NULL) && (inp->ecn_supported == 1))) { |
6487 | 0 | parameter_len = (uint16_t)sizeof(struct sctp_paramhdr); |
6488 | 0 | ph = (struct sctp_paramhdr *)(mtod(m, caddr_t) + chunk_len); |
6489 | 0 | ph->param_type = htons(SCTP_ECN_CAPABLE); |
6490 | 0 | ph->param_length = htons(parameter_len); |
6491 | 0 | chunk_len += parameter_len; |
6492 | 0 | } |
6493 | | |
6494 | | /* PR-SCTP supported parameter */ |
6495 | 0 | if (((asoc != NULL) && (asoc->prsctp_supported == 1)) || |
6496 | 0 | ((asoc == NULL) && (inp->prsctp_supported == 1))) { |
6497 | 0 | parameter_len = (uint16_t)sizeof(struct sctp_paramhdr); |
6498 | 0 | ph = (struct sctp_paramhdr *)(mtod(m, caddr_t) + chunk_len); |
6499 | 0 | ph->param_type = htons(SCTP_PRSCTP_SUPPORTED); |
6500 | 0 | ph->param_length = htons(parameter_len); |
6501 | 0 | chunk_len += parameter_len; |
6502 | 0 | } |
6503 | | |
6504 | | /* Zero checksum acceptable parameter */ |
6505 | 0 | if (((asoc != NULL) && (asoc->rcv_edmid != SCTP_EDMID_NONE)) || |
6506 | 0 | ((asoc == NULL) && (inp->rcv_edmid != SCTP_EDMID_NONE))) { |
6507 | 0 | parameter_len = (uint16_t)sizeof(struct sctp_zero_checksum_acceptable); |
6508 | 0 | zero_chksum = (struct sctp_zero_checksum_acceptable *)(mtod(m, caddr_t) + chunk_len); |
6509 | 0 | zero_chksum->ph.param_type = htons(SCTP_ZERO_CHECKSUM_ACCEPTABLE); |
6510 | 0 | zero_chksum->ph.param_length = htons(parameter_len); |
6511 | 0 | if (asoc != NULL) { |
6512 | 0 | zero_chksum->edmid = htonl(asoc->rcv_edmid); |
6513 | 0 | } else { |
6514 | 0 | zero_chksum->edmid = htonl(inp->rcv_edmid); |
6515 | 0 | } |
6516 | 0 | chunk_len += parameter_len; |
6517 | 0 | } |
6518 | | |
6519 | | /* Add NAT friendly parameter */ |
6520 | 0 | if (nat_friendly) { |
6521 | 0 | parameter_len = (uint16_t)sizeof(struct sctp_paramhdr); |
6522 | 0 | ph = (struct sctp_paramhdr *)(mtod(m, caddr_t) + chunk_len); |
6523 | 0 | ph->param_type = htons(SCTP_HAS_NAT_SUPPORT); |
6524 | 0 | ph->param_length = htons(parameter_len); |
6525 | 0 | chunk_len += parameter_len; |
6526 | 0 | } |
6527 | | |
6528 | | /* And now tell the peer which extensions we support */ |
6529 | 0 | num_ext = 0; |
6530 | 0 | pr_supported = (struct sctp_supported_chunk_types_param *)(mtod(m, caddr_t) + chunk_len); |
6531 | 0 | if (((asoc != NULL) && (asoc->prsctp_supported == 1)) || |
6532 | 0 | ((asoc == NULL) && (inp->prsctp_supported == 1))) { |
6533 | 0 | pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN; |
6534 | 0 | if (((asoc != NULL) && (asoc->idata_supported == 1)) || |
6535 | 0 | ((asoc == NULL) && (inp->idata_supported == 1))) { |
6536 | 0 | pr_supported->chunk_types[num_ext++] = SCTP_IFORWARD_CUM_TSN; |
6537 | 0 | } |
6538 | 0 | } |
6539 | 0 | if (((asoc != NULL) && (asoc->auth_supported == 1)) || |
6540 | 0 | ((asoc == NULL) && (inp->auth_supported == 1))) { |
6541 | 0 | pr_supported->chunk_types[num_ext++] = SCTP_AUTHENTICATION; |
6542 | 0 | } |
6543 | 0 | if (((asoc != NULL) && (asoc->asconf_supported == 1)) || |
6544 | 0 | ((asoc == NULL) && (inp->asconf_supported == 1))) { |
6545 | 0 | pr_supported->chunk_types[num_ext++] = SCTP_ASCONF; |
6546 | 0 | pr_supported->chunk_types[num_ext++] = SCTP_ASCONF_ACK; |
6547 | 0 | } |
6548 | 0 | if (((asoc != NULL) && (asoc->reconfig_supported == 1)) || |
6549 | 0 | ((asoc == NULL) && (inp->reconfig_supported == 1))) { |
6550 | 0 | pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET; |
6551 | 0 | } |
6552 | 0 | if (((asoc != NULL) && (asoc->idata_supported == 1)) || |
6553 | 0 | ((asoc == NULL) && (inp->idata_supported == 1))) { |
6554 | 0 | pr_supported->chunk_types[num_ext++] = SCTP_IDATA; |
6555 | 0 | } |
6556 | 0 | if (((asoc != NULL) && (asoc->nrsack_supported == 1)) || |
6557 | 0 | ((asoc == NULL) && (inp->nrsack_supported == 1))) { |
6558 | 0 | pr_supported->chunk_types[num_ext++] = SCTP_NR_SELECTIVE_ACK; |
6559 | 0 | } |
6560 | 0 | if (((asoc != NULL) && (asoc->pktdrop_supported == 1)) || |
6561 | 0 | ((asoc == NULL) && (inp->pktdrop_supported == 1))) { |
6562 | 0 | pr_supported->chunk_types[num_ext++] = SCTP_PACKET_DROPPED; |
6563 | 0 | } |
6564 | 0 | if (num_ext > 0) { |
6565 | 0 | parameter_len = (uint16_t)sizeof(struct sctp_supported_chunk_types_param) + num_ext; |
6566 | 0 | pr_supported->ph.param_type = htons(SCTP_SUPPORTED_CHUNK_EXT); |
6567 | 0 | pr_supported->ph.param_length = htons(parameter_len); |
6568 | 0 | padding_len = SCTP_SIZE32(parameter_len) - parameter_len; |
6569 | 0 | chunk_len += parameter_len; |
6570 | 0 | } |
6571 | | |
6572 | | /* add authentication parameters */ |
6573 | 0 | if (((asoc != NULL) && (asoc->auth_supported == 1)) || |
6574 | 0 | ((asoc == NULL) && (inp->auth_supported == 1))) { |
6575 | 0 | struct sctp_auth_random *randp; |
6576 | 0 | struct sctp_auth_hmac_algo *hmacs; |
6577 | 0 | struct sctp_auth_chunk_list *chunks; |
6578 | |
|
6579 | 0 | if (padding_len > 0) { |
6580 | 0 | memset(mtod(m, caddr_t) + chunk_len, 0, padding_len); |
6581 | 0 | chunk_len += padding_len; |
6582 | 0 | padding_len = 0; |
6583 | 0 | } |
6584 | | /* generate and add RANDOM parameter */ |
6585 | 0 | randp = (struct sctp_auth_random *)(mtod(m, caddr_t) + chunk_len); |
6586 | 0 | parameter_len = (uint16_t)sizeof(struct sctp_auth_random) + |
6587 | 0 | SCTP_AUTH_RANDOM_SIZE_DEFAULT; |
6588 | 0 | randp->ph.param_type = htons(SCTP_RANDOM); |
6589 | 0 | randp->ph.param_length = htons(parameter_len); |
6590 | 0 | SCTP_READ_RANDOM(randp->random_data, SCTP_AUTH_RANDOM_SIZE_DEFAULT); |
6591 | 0 | padding_len = SCTP_SIZE32(parameter_len) - parameter_len; |
6592 | 0 | chunk_len += parameter_len; |
6593 | |
|
6594 | 0 | if (padding_len > 0) { |
6595 | 0 | memset(mtod(m, caddr_t) + chunk_len, 0, padding_len); |
6596 | 0 | chunk_len += padding_len; |
6597 | 0 | padding_len = 0; |
6598 | 0 | } |
6599 | | /* add HMAC_ALGO parameter */ |
6600 | 0 | hmacs = (struct sctp_auth_hmac_algo *)(mtod(m, caddr_t) + chunk_len); |
6601 | 0 | parameter_len = (uint16_t)sizeof(struct sctp_auth_hmac_algo) + |
6602 | 0 | sctp_serialize_hmaclist(inp->sctp_ep.local_hmacs, |
6603 | 0 | (uint8_t *)hmacs->hmac_ids); |
6604 | 0 | hmacs->ph.param_type = htons(SCTP_HMAC_LIST); |
6605 | 0 | hmacs->ph.param_length = htons(parameter_len); |
6606 | 0 | padding_len = SCTP_SIZE32(parameter_len) - parameter_len; |
6607 | 0 | chunk_len += parameter_len; |
6608 | |
|
6609 | 0 | if (padding_len > 0) { |
6610 | 0 | memset(mtod(m, caddr_t) + chunk_len, 0, padding_len); |
6611 | 0 | chunk_len += padding_len; |
6612 | 0 | padding_len = 0; |
6613 | 0 | } |
6614 | | /* add CHUNKS parameter */ |
6615 | 0 | chunks = (struct sctp_auth_chunk_list *)(mtod(m, caddr_t) + chunk_len); |
6616 | 0 | parameter_len = (uint16_t)sizeof(struct sctp_auth_chunk_list) + |
6617 | 0 | sctp_serialize_auth_chunks(inp->sctp_ep.local_auth_chunks, |
6618 | 0 | chunks->chunk_types); |
6619 | 0 | chunks->ph.param_type = htons(SCTP_CHUNK_LIST); |
6620 | 0 | chunks->ph.param_length = htons(parameter_len); |
6621 | 0 | padding_len = SCTP_SIZE32(parameter_len) - parameter_len; |
6622 | 0 | chunk_len += parameter_len; |
6623 | 0 | } |
6624 | 0 | SCTP_BUF_LEN(m) = chunk_len; |
6625 | 0 | m_last = m; |
6626 | | /* now the addresses */ |
6627 | | /* To optimize this we could put the scoping stuff |
6628 | | * into a structure and remove the individual uint8's from |
6629 | | * the stc structure. Then we could just sifa in the |
6630 | | * address within the stc.. but for now this is a quick |
6631 | | * hack to get the address stuff teased apart. |
6632 | | */ |
6633 | 0 | scp.ipv4_addr_legal = stc.ipv4_addr_legal; |
6634 | 0 | scp.ipv6_addr_legal = stc.ipv6_addr_legal; |
6635 | 0 | #if defined(__Userspace__) |
6636 | 0 | scp.conn_addr_legal = stc.conn_addr_legal; |
6637 | 0 | #endif |
6638 | 0 | scp.loopback_scope = stc.loopback_scope; |
6639 | 0 | scp.ipv4_local_scope = stc.ipv4_scope; |
6640 | 0 | scp.local_scope = stc.local_scope; |
6641 | 0 | scp.site_scope = stc.site_scope; |
6642 | 0 | m_last = sctp_add_addresses_to_i_ia(inp, stcb, &scp, m_last, |
6643 | 0 | cnt_inits_to, |
6644 | 0 | &padding_len, &chunk_len); |
6645 | | /* padding_len can only be positive, if no addresses have been added */ |
6646 | 0 | if (padding_len > 0) { |
6647 | 0 | memset(mtod(m, caddr_t) + chunk_len, 0, padding_len); |
6648 | 0 | chunk_len += padding_len; |
6649 | 0 | SCTP_BUF_LEN(m) += padding_len; |
6650 | 0 | padding_len = 0; |
6651 | 0 | } |
6652 | | |
6653 | | /* tack on the operational error if present */ |
6654 | 0 | if (op_err) { |
6655 | 0 | parameter_len = 0; |
6656 | 0 | for (m_tmp = op_err; m_tmp != NULL; m_tmp = SCTP_BUF_NEXT(m_tmp)) { |
6657 | 0 | parameter_len += SCTP_BUF_LEN(m_tmp); |
6658 | 0 | } |
6659 | 0 | padding_len = SCTP_SIZE32(parameter_len) - parameter_len; |
6660 | 0 | SCTP_BUF_NEXT(m_last) = op_err; |
6661 | 0 | while (SCTP_BUF_NEXT(m_last) != NULL) { |
6662 | 0 | m_last = SCTP_BUF_NEXT(m_last); |
6663 | 0 | } |
6664 | 0 | chunk_len += parameter_len; |
6665 | 0 | } |
6666 | 0 | if (padding_len > 0) { |
6667 | 0 | m_last = sctp_add_pad_tombuf(m_last, padding_len); |
6668 | 0 | if (m_last == NULL) { |
6669 | | /* Houston we have a problem, no space */ |
6670 | 0 | sctp_m_freem(m); |
6671 | 0 | return; |
6672 | 0 | } |
6673 | 0 | chunk_len += padding_len; |
6674 | 0 | padding_len = 0; |
6675 | 0 | } |
6676 | | /* Now we must build a cookie */ |
6677 | 0 | m_cookie = sctp_add_cookie(init_pkt, offset, m, 0, &stc, &signature); |
6678 | 0 | if (m_cookie == NULL) { |
6679 | | /* memory problem */ |
6680 | 0 | sctp_m_freem(m); |
6681 | 0 | return; |
6682 | 0 | } |
6683 | | /* Now append the cookie to the end and update the space/size */ |
6684 | 0 | SCTP_BUF_NEXT(m_last) = m_cookie; |
6685 | 0 | parameter_len = 0; |
6686 | 0 | for (m_tmp = m_cookie; m_tmp != NULL; m_tmp = SCTP_BUF_NEXT(m_tmp)) { |
6687 | 0 | parameter_len += SCTP_BUF_LEN(m_tmp); |
6688 | 0 | if (SCTP_BUF_NEXT(m_tmp) == NULL) { |
6689 | 0 | m_last = m_tmp; |
6690 | 0 | } |
6691 | 0 | } |
6692 | 0 | padding_len = SCTP_SIZE32(parameter_len) - parameter_len; |
6693 | 0 | chunk_len += parameter_len; |
6694 | | |
6695 | | /* Place in the size, but we don't include |
6696 | | * the last pad (if any) in the INIT-ACK. |
6697 | | */ |
6698 | 0 | initack->ch.chunk_length = htons(chunk_len); |
6699 | | |
6700 | | /* Time to sign the cookie, we don't sign over the cookie |
6701 | | * signature though thus we set trailer. |
6702 | | */ |
6703 | 0 | (void)sctp_hmac_m(SCTP_HMAC, |
6704 | 0 | (uint8_t *)inp->sctp_ep.secret_key[(int)(inp->sctp_ep.current_secret_number)], |
6705 | 0 | SCTP_SECRET_SIZE, m_cookie, sizeof(struct sctp_paramhdr), |
6706 | 0 | (uint8_t *)signature, SCTP_SIGNATURE_SIZE); |
6707 | 0 | #if defined(__Userspace__) |
6708 | | /* |
6709 | | * Don't put AF_CONN addresses on the wire, in case this is critical |
6710 | | * for the application. However, they are protected by the HMAC and |
6711 | | * need to be reconstructed before checking the HMAC. |
6712 | | * Clearing is only done in the mbuf chain, since the local stc is |
6713 | | * not used anymore. |
6714 | | */ |
6715 | 0 | if (stc.addr_type == SCTP_CONN_ADDRESS) { |
6716 | 0 | const void *p = NULL; |
6717 | |
|
6718 | 0 | m_copyback(m_cookie, sizeof(struct sctp_paramhdr) + offsetof(struct sctp_state_cookie, address), |
6719 | 0 | (int)sizeof(void *), (caddr_t)&p); |
6720 | 0 | } |
6721 | 0 | if (stc.laddr_type == SCTP_CONN_ADDRESS) { |
6722 | 0 | const void *p = NULL; |
6723 | |
|
6724 | 0 | m_copyback(m_cookie, sizeof(struct sctp_paramhdr) + offsetof(struct sctp_state_cookie, laddress), |
6725 | 0 | (int)sizeof(void *), (caddr_t)&p); |
6726 | 0 | } |
6727 | 0 | #endif |
6728 | | /* |
6729 | | * We sifa 0 here to NOT set IP_DF if its IPv4, we ignore the return |
6730 | | * here since the timer will drive a retranmission. |
6731 | | */ |
6732 | 0 | if (padding_len > 0) { |
6733 | 0 | if (sctp_add_pad_tombuf(m_last, padding_len) == NULL) { |
6734 | 0 | sctp_m_freem(m); |
6735 | 0 | return; |
6736 | 0 | } |
6737 | 0 | } |
6738 | 0 | if (stc.loopback_scope) { |
6739 | 0 | over_addr = (union sctp_sockstore *)dst; |
6740 | 0 | } else { |
6741 | 0 | over_addr = NULL; |
6742 | 0 | } |
6743 | |
|
6744 | 0 | if (asoc != NULL) { |
6745 | 0 | use_zero_crc = (asoc->rcv_edmid != SCTP_EDMID_NONE) && (asoc->rcv_edmid == edmid); |
6746 | 0 | } else { |
6747 | 0 | use_zero_crc = (inp->rcv_edmid != SCTP_EDMID_NONE) && (inp->rcv_edmid == edmid); |
6748 | 0 | } |
6749 | |
|
6750 | 0 | if ((error = sctp_lowlevel_chunk_output(inp, NULL, NULL, to, m, 0, NULL, 0, 0, |
6751 | 0 | 0, 0, |
6752 | 0 | inp->sctp_lport, sh->src_port, init_chk->init.initiate_tag, |
6753 | 0 | port, over_addr, |
6754 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
6755 | | mflowtype, mflowid, |
6756 | | #endif |
6757 | 0 | use_zero_crc, |
6758 | 0 | SCTP_SO_NOT_LOCKED))) { |
6759 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak send error %d\n", error); |
6760 | 0 | if (error == ENOBUFS) { |
6761 | 0 | if (asoc != NULL) { |
6762 | 0 | asoc->ifp_had_enobuf = 1; |
6763 | 0 | } |
6764 | 0 | SCTP_STAT_INCR(sctps_lowlevelerr); |
6765 | 0 | } |
6766 | 0 | } else { |
6767 | 0 | if (asoc != NULL) { |
6768 | 0 | asoc->ifp_had_enobuf = 0; |
6769 | 0 | } |
6770 | 0 | } |
6771 | 0 | SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); |
6772 | 0 | } |
6773 | | |
6774 | | static void |
6775 | | sctp_prune_prsctp(struct sctp_tcb *stcb, |
6776 | | struct sctp_association *asoc, |
6777 | | struct sctp_nonpad_sndrcvinfo *srcv, |
6778 | | int dataout) |
6779 | 0 | { |
6780 | 0 | int freed_spc = 0; |
6781 | 0 | struct sctp_tmit_chunk *chk, *nchk; |
6782 | |
|
6783 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
6784 | 0 | if ((asoc->prsctp_supported) && |
6785 | 0 | (asoc->sent_queue_cnt_removeable > 0)) { |
6786 | 0 | TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { |
6787 | | /* |
6788 | | * Look for chunks marked with the PR_SCTP flag AND |
6789 | | * the buffer space flag. If the one being sent is |
6790 | | * equal or greater priority then purge the old one |
6791 | | * and free some space. |
6792 | | */ |
6793 | 0 | if (PR_SCTP_BUF_ENABLED(chk->flags)) { |
6794 | | /* |
6795 | | * This one is PR-SCTP AND buffer space |
6796 | | * limited type |
6797 | | */ |
6798 | 0 | if (chk->rec.data.timetodrop.tv_sec > (long)srcv->sinfo_timetolive) { |
6799 | | /* |
6800 | | * Lower numbers equates to higher |
6801 | | * priority. So if the one we are |
6802 | | * looking at has a larger priority, |
6803 | | * we want to drop the data and NOT |
6804 | | * retransmit it. |
6805 | | */ |
6806 | 0 | if (chk->data) { |
6807 | | /* |
6808 | | * We release the book_size |
6809 | | * if the mbuf is here |
6810 | | */ |
6811 | 0 | int ret_spc; |
6812 | 0 | uint8_t sent; |
6813 | |
|
6814 | 0 | if (chk->sent > SCTP_DATAGRAM_UNSENT) |
6815 | 0 | sent = 1; |
6816 | 0 | else |
6817 | 0 | sent = 0; |
6818 | 0 | ret_spc = sctp_release_pr_sctp_chunk(stcb, chk, |
6819 | 0 | sent, |
6820 | 0 | SCTP_SO_LOCKED); |
6821 | 0 | freed_spc += ret_spc; |
6822 | 0 | if (freed_spc >= dataout) { |
6823 | 0 | return; |
6824 | 0 | } |
6825 | 0 | } /* if chunk was present */ |
6826 | 0 | } /* if of sufficient priority */ |
6827 | 0 | } /* if chunk has enabled */ |
6828 | 0 | } /* tailqforeach */ |
6829 | | |
6830 | 0 | TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) { |
6831 | | /* Here we must move to the sent queue and mark */ |
6832 | 0 | if (PR_SCTP_BUF_ENABLED(chk->flags)) { |
6833 | 0 | if (chk->rec.data.timetodrop.tv_sec > (long)srcv->sinfo_timetolive) { |
6834 | 0 | if (chk->data) { |
6835 | | /* |
6836 | | * We release the book_size |
6837 | | * if the mbuf is here |
6838 | | */ |
6839 | 0 | int ret_spc; |
6840 | |
|
6841 | 0 | ret_spc = sctp_release_pr_sctp_chunk(stcb, chk, |
6842 | 0 | 0, SCTP_SO_LOCKED); |
6843 | |
|
6844 | 0 | freed_spc += ret_spc; |
6845 | 0 | if (freed_spc >= dataout) { |
6846 | 0 | return; |
6847 | 0 | } |
6848 | 0 | } /* end if chk->data */ |
6849 | 0 | } /* end if right class */ |
6850 | 0 | } /* end if chk pr-sctp */ |
6851 | 0 | } /* tailqforeachsafe (chk) */ |
6852 | 0 | } /* if enabled in asoc */ |
6853 | 0 | } |
6854 | | |
6855 | | uint32_t |
6856 | | sctp_get_frag_point(struct sctp_tcb *stcb) |
6857 | 21.4k | { |
6858 | 21.4k | struct sctp_association *asoc; |
6859 | 21.4k | uint32_t frag_point, overhead; |
6860 | | |
6861 | 21.4k | asoc = &stcb->asoc; |
6862 | | /* Consider IP header and SCTP common header. */ |
6863 | 21.4k | if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { |
6864 | 0 | overhead = SCTP_MIN_OVERHEAD; |
6865 | 21.4k | } else { |
6866 | 21.4k | #if defined(__Userspace__) |
6867 | 21.4k | if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) { |
6868 | 21.4k | overhead = sizeof(struct sctphdr); |
6869 | 21.4k | } else { |
6870 | 0 | overhead = SCTP_MIN_V4_OVERHEAD; |
6871 | 0 | } |
6872 | | #else |
6873 | | overhead = SCTP_MIN_V4_OVERHEAD; |
6874 | | #endif |
6875 | 21.4k | } |
6876 | | /* Consider DATA/IDATA chunk header and AUTH header, if needed. */ |
6877 | 21.4k | if (asoc->idata_supported) { |
6878 | 1.30k | overhead += sizeof(struct sctp_idata_chunk); |
6879 | 1.30k | if (sctp_auth_is_required_chunk(SCTP_IDATA, asoc->peer_auth_chunks)) { |
6880 | 0 | overhead += sctp_get_auth_chunk_len(asoc->peer_hmac_id); |
6881 | 0 | } |
6882 | 20.1k | } else { |
6883 | 20.1k | overhead += sizeof(struct sctp_data_chunk); |
6884 | 20.1k | if (sctp_auth_is_required_chunk(SCTP_DATA, asoc->peer_auth_chunks)) { |
6885 | 0 | overhead += sctp_get_auth_chunk_len(asoc->peer_hmac_id); |
6886 | 0 | } |
6887 | 20.1k | } |
6888 | 21.4k | KASSERT(overhead % 4 == 0, |
6889 | 21.4k | ("overhead (%u) not a multiple of 4", overhead)); |
6890 | | /* Consider padding. */ |
6891 | 21.4k | if (asoc->smallest_mtu % 4 > 0) { |
6892 | 0 | overhead += (asoc->smallest_mtu % 4); |
6893 | 0 | } |
6894 | 21.4k | KASSERT(asoc->smallest_mtu > overhead, |
6895 | 21.4k | ("Association MTU (%u) too small for overhead (%u)", |
6896 | 21.4k | asoc->smallest_mtu, overhead)); |
6897 | 21.4k | frag_point = asoc->smallest_mtu - overhead; |
6898 | 21.4k | KASSERT(frag_point % 4 == 0, |
6899 | 21.4k | ("frag_point (%u) not a multiple of 4", frag_point)); |
6900 | | /* Honor MAXSEG socket option. */ |
6901 | 21.4k | if ((asoc->sctp_frag_point > 0) && |
6902 | 0 | (asoc->sctp_frag_point < frag_point)) { |
6903 | 0 | frag_point = asoc->sctp_frag_point; |
6904 | 0 | } |
6905 | 21.4k | return (frag_point); |
6906 | 21.4k | } |
6907 | | |
6908 | | static void |
6909 | | sctp_set_prsctp_policy(struct sctp_stream_queue_pending *sp) |
6910 | 18.0k | { |
6911 | | /* |
6912 | | * We assume that the user wants PR_SCTP_TTL if the user |
6913 | | * provides a positive lifetime but does not specify any |
6914 | | * PR_SCTP policy. |
6915 | | */ |
6916 | 18.0k | if (PR_SCTP_ENABLED(sp->sinfo_flags)) { |
6917 | 0 | sp->act_flags |= PR_SCTP_POLICY(sp->sinfo_flags); |
6918 | 18.0k | } else if (sp->timetolive > 0) { |
6919 | 0 | sp->sinfo_flags |= SCTP_PR_SCTP_TTL; |
6920 | 0 | sp->act_flags |= PR_SCTP_POLICY(sp->sinfo_flags); |
6921 | 18.0k | } else { |
6922 | 18.0k | return; |
6923 | 18.0k | } |
6924 | 0 | switch (PR_SCTP_POLICY(sp->sinfo_flags)) { |
6925 | 0 | case CHUNK_FLAGS_PR_SCTP_BUF: |
6926 | | /* |
6927 | | * Time to live is a priority stored in tv_sec when |
6928 | | * doing the buffer drop thing. |
6929 | | */ |
6930 | 0 | sp->ts.tv_sec = sp->timetolive; |
6931 | 0 | sp->ts.tv_usec = 0; |
6932 | 0 | break; |
6933 | 0 | case CHUNK_FLAGS_PR_SCTP_TTL: |
6934 | 0 | { |
6935 | 0 | struct timeval tv; |
6936 | 0 | (void)SCTP_GETTIME_TIMEVAL(&sp->ts); |
6937 | 0 | tv.tv_sec = sp->timetolive / 1000; |
6938 | 0 | tv.tv_usec = (sp->timetolive * 1000) % 1000000; |
6939 | | /* TODO sctp_constants.h needs alternative time macros when |
6940 | | * _KERNEL is undefined. |
6941 | | */ |
6942 | 0 | #if !(defined(__FreeBSD__) && !defined(__Userspace__)) |
6943 | 0 | timeradd(&sp->ts, &tv, &sp->ts); |
6944 | | #else |
6945 | | timevaladd(&sp->ts, &tv); |
6946 | | #endif |
6947 | 0 | } |
6948 | 0 | break; |
6949 | 0 | case CHUNK_FLAGS_PR_SCTP_RTX: |
6950 | | /* |
6951 | | * Time to live is a the number or retransmissions |
6952 | | * stored in tv_sec. |
6953 | | */ |
6954 | 0 | sp->ts.tv_sec = sp->timetolive; |
6955 | 0 | sp->ts.tv_usec = 0; |
6956 | 0 | break; |
6957 | 0 | default: |
6958 | 0 | SCTPDBG(SCTP_DEBUG_USRREQ1, |
6959 | 0 | "Unknown PR_SCTP policy %u.\n", |
6960 | 0 | PR_SCTP_POLICY(sp->sinfo_flags)); |
6961 | 0 | break; |
6962 | 0 | } |
6963 | 0 | } |
6964 | | |
6965 | | static int |
6966 | | sctp_msg_append(struct sctp_tcb *stcb, |
6967 | | struct sctp_nets *net, |
6968 | | struct mbuf *m, |
6969 | | struct sctp_nonpad_sndrcvinfo *srcv) |
6970 | 0 | { |
6971 | 0 | int error = 0; |
6972 | 0 | struct mbuf *at; |
6973 | 0 | struct sctp_stream_queue_pending *sp = NULL; |
6974 | 0 | struct sctp_stream_out *strm; |
6975 | |
|
6976 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
6977 | | |
6978 | | /* Given an mbuf chain, put it |
6979 | | * into the association send queue and |
6980 | | * place it on the wheel |
6981 | | */ |
6982 | 0 | if (srcv->sinfo_stream >= stcb->asoc.streamoutcnt) { |
6983 | | /* Invalid stream number */ |
6984 | 0 | SCTP_LTRACE_ERR_RET_PKT(m, NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); |
6985 | 0 | error = EINVAL; |
6986 | 0 | goto out_now; |
6987 | 0 | } |
6988 | 0 | if ((stcb->asoc.stream_locked) && |
6989 | 0 | (stcb->asoc.stream_locked_on != srcv->sinfo_stream)) { |
6990 | 0 | SCTP_LTRACE_ERR_RET_PKT(m, NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); |
6991 | 0 | error = EINVAL; |
6992 | 0 | goto out_now; |
6993 | 0 | } |
6994 | 0 | if ((stcb->asoc.strmout[srcv->sinfo_stream].state != SCTP_STREAM_OPEN) && |
6995 | 0 | (stcb->asoc.strmout[srcv->sinfo_stream].state != SCTP_STREAM_OPENING)) { |
6996 | | /* |
6997 | | * Can't queue any data while stream reset is underway. |
6998 | | */ |
6999 | 0 | if (stcb->asoc.strmout[srcv->sinfo_stream].state > SCTP_STREAM_OPEN) { |
7000 | 0 | error = EAGAIN; |
7001 | 0 | } else { |
7002 | 0 | error = EINVAL; |
7003 | 0 | } |
7004 | 0 | goto out_now; |
7005 | 0 | } |
7006 | | /* Now can we send this? */ |
7007 | 0 | if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_SENT) || |
7008 | 0 | (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_ACK_SENT) || |
7009 | 0 | (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED) || |
7010 | 0 | (stcb->asoc.state & SCTP_STATE_SHUTDOWN_PENDING)) { |
7011 | | /* got data while shutting down */ |
7012 | 0 | SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EPIPE); |
7013 | 0 | error = EPIPE; |
7014 | 0 | goto out_now; |
7015 | 0 | } |
7016 | 0 | sctp_alloc_a_strmoq(stcb, sp); |
7017 | 0 | if (sp == NULL) { |
7018 | 0 | SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
7019 | 0 | error = ENOMEM; |
7020 | 0 | goto out_now; |
7021 | 0 | } |
7022 | 0 | sp->sinfo_flags = srcv->sinfo_flags; |
7023 | 0 | sp->timetolive = srcv->sinfo_timetolive; |
7024 | 0 | sp->ppid = srcv->sinfo_ppid; |
7025 | 0 | sp->context = srcv->sinfo_context; |
7026 | 0 | sp->fsn = 0; |
7027 | 0 | if (sp->sinfo_flags & SCTP_ADDR_OVER) { |
7028 | 0 | sp->net = net; |
7029 | 0 | atomic_add_int(&sp->net->ref_count, 1); |
7030 | 0 | } else { |
7031 | 0 | sp->net = NULL; |
7032 | 0 | } |
7033 | 0 | (void)SCTP_GETTIME_TIMEVAL(&sp->ts); |
7034 | 0 | sp->sid = srcv->sinfo_stream; |
7035 | 0 | sp->msg_is_complete = 1; |
7036 | 0 | sp->sender_all_done = 1; |
7037 | 0 | sp->some_taken = 0; |
7038 | 0 | sp->data = m; |
7039 | 0 | sp->tail_mbuf = NULL; |
7040 | 0 | sctp_set_prsctp_policy(sp); |
7041 | | /* We could in theory (for sendall) sifa the length |
7042 | | * in, but we would still have to hunt through the |
7043 | | * chain since we need to setup the tail_mbuf |
7044 | | */ |
7045 | 0 | sp->length = 0; |
7046 | 0 | for (at = m; at; at = SCTP_BUF_NEXT(at)) { |
7047 | 0 | if (SCTP_BUF_NEXT(at) == NULL) |
7048 | 0 | sp->tail_mbuf = at; |
7049 | 0 | sp->length += SCTP_BUF_LEN(at); |
7050 | 0 | } |
7051 | 0 | if (srcv->sinfo_keynumber_valid) { |
7052 | 0 | sp->auth_keyid = srcv->sinfo_keynumber; |
7053 | 0 | } else { |
7054 | 0 | sp->auth_keyid = stcb->asoc.authinfo.active_keyid; |
7055 | 0 | } |
7056 | 0 | if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) { |
7057 | 0 | sctp_auth_key_acquire(stcb, sp->auth_keyid); |
7058 | 0 | sp->holds_key_ref = 1; |
7059 | 0 | } |
7060 | 0 | strm = &stcb->asoc.strmout[srcv->sinfo_stream]; |
7061 | 0 | sctp_snd_sb_alloc(stcb, sp->length); |
7062 | 0 | atomic_add_int(&stcb->asoc.stream_queue_cnt, 1); |
7063 | 0 | TAILQ_INSERT_TAIL(&strm->outqueue, sp, next); |
7064 | 0 | stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, &stcb->asoc, strm, sp); |
7065 | 0 | m = NULL; |
7066 | 0 | out_now: |
7067 | 0 | if (m) { |
7068 | 0 | sctp_m_freem(m); |
7069 | 0 | } |
7070 | 0 | return (error); |
7071 | 0 | } |
7072 | | |
7073 | | static struct mbuf * |
7074 | | sctp_copy_mbufchain(struct mbuf *clonechain, |
7075 | | struct mbuf *outchain, |
7076 | | struct mbuf **endofchain, |
7077 | | int can_take_mbuf, |
7078 | | int sizeofcpy, |
7079 | | uint8_t copy_by_ref) |
7080 | 5.92k | { |
7081 | 5.92k | struct mbuf *m; |
7082 | 5.92k | struct mbuf *appendchain; |
7083 | 5.92k | caddr_t cp; |
7084 | 5.92k | int len; |
7085 | | |
7086 | 5.92k | if (endofchain == NULL) { |
7087 | | /* error */ |
7088 | 0 | error_out: |
7089 | 0 | if (outchain) |
7090 | 0 | sctp_m_freem(outchain); |
7091 | 0 | return (NULL); |
7092 | 0 | } |
7093 | 5.92k | if (can_take_mbuf) { |
7094 | 1 | appendchain = clonechain; |
7095 | 5.92k | } else { |
7096 | 5.92k | if (!copy_by_ref && |
7097 | 1.60k | (sizeofcpy <= (int)((((SCTP_BASE_SYSCTL(sctp_mbuf_threshold_count) - 1) * MLEN) + MHLEN)))) { |
7098 | | /* Its not in a cluster */ |
7099 | 1.60k | if (*endofchain == NULL) { |
7100 | | /* lets get a mbuf cluster */ |
7101 | 1.60k | if (outchain == NULL) { |
7102 | | /* This is the general case */ |
7103 | 1.60k | new_mbuf: |
7104 | 1.60k | outchain = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_HEADER); |
7105 | 1.60k | if (outchain == NULL) { |
7106 | 0 | goto error_out; |
7107 | 0 | } |
7108 | 1.60k | SCTP_BUF_LEN(outchain) = 0; |
7109 | 1.60k | *endofchain = outchain; |
7110 | | /* get the prepend space */ |
7111 | 1.60k | SCTP_BUF_RESV_UF(outchain, (SCTP_FIRST_MBUF_RESV+4)); |
7112 | 1.60k | } else { |
7113 | | /* We really should not get a NULL in endofchain */ |
7114 | | /* find end */ |
7115 | 0 | m = outchain; |
7116 | 0 | while (m) { |
7117 | 0 | if (SCTP_BUF_NEXT(m) == NULL) { |
7118 | 0 | *endofchain = m; |
7119 | 0 | break; |
7120 | 0 | } |
7121 | 0 | m = SCTP_BUF_NEXT(m); |
7122 | 0 | } |
7123 | | /* sanity */ |
7124 | 0 | if (*endofchain == NULL) { |
7125 | | /* huh, TSNH XXX maybe we should panic */ |
7126 | 0 | sctp_m_freem(outchain); |
7127 | 0 | goto new_mbuf; |
7128 | 0 | } |
7129 | 0 | } |
7130 | | /* get the new end of length */ |
7131 | 1.60k | len = (int)M_TRAILINGSPACE(*endofchain); |
7132 | 1.60k | } else { |
7133 | | /* how much is left at the end? */ |
7134 | 0 | len = (int)M_TRAILINGSPACE(*endofchain); |
7135 | 0 | } |
7136 | | /* Find the end of the data, for appending */ |
7137 | 1.60k | cp = (mtod((*endofchain), caddr_t) + SCTP_BUF_LEN((*endofchain))); |
7138 | | |
7139 | | /* Now lets copy it out */ |
7140 | 1.60k | if (len >= sizeofcpy) { |
7141 | | /* It all fits, copy it in */ |
7142 | 1.60k | m_copydata(clonechain, 0, sizeofcpy, cp); |
7143 | 1.60k | SCTP_BUF_LEN((*endofchain)) += sizeofcpy; |
7144 | 1.60k | } else { |
7145 | | /* fill up the end of the chain */ |
7146 | 0 | if (len > 0) { |
7147 | 0 | m_copydata(clonechain, 0, len, cp); |
7148 | 0 | SCTP_BUF_LEN((*endofchain)) += len; |
7149 | | /* now we need another one */ |
7150 | 0 | sizeofcpy -= len; |
7151 | 0 | } |
7152 | 0 | m = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_HEADER); |
7153 | 0 | if (m == NULL) { |
7154 | | /* We failed */ |
7155 | 0 | goto error_out; |
7156 | 0 | } |
7157 | 0 | SCTP_BUF_NEXT((*endofchain)) = m; |
7158 | 0 | *endofchain = m; |
7159 | 0 | cp = mtod((*endofchain), caddr_t); |
7160 | 0 | m_copydata(clonechain, len, sizeofcpy, cp); |
7161 | 0 | SCTP_BUF_LEN((*endofchain)) += sizeofcpy; |
7162 | 0 | } |
7163 | 1.60k | return (outchain); |
7164 | 4.32k | } else { |
7165 | | /* copy the old fashion way */ |
7166 | 4.32k | appendchain = SCTP_M_COPYM(clonechain, 0, M_COPYALL, M_NOWAIT); |
7167 | | #ifdef SCTP_MBUF_LOGGING |
7168 | | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { |
7169 | | sctp_log_mbc(appendchain, SCTP_MBUF_ICOPY); |
7170 | | } |
7171 | | #endif |
7172 | 4.32k | } |
7173 | 5.92k | } |
7174 | 4.32k | if (appendchain == NULL) { |
7175 | | /* error */ |
7176 | 0 | if (outchain) |
7177 | 0 | sctp_m_freem(outchain); |
7178 | 0 | return (NULL); |
7179 | 0 | } |
7180 | 4.32k | if (outchain) { |
7181 | | /* tack on to the end */ |
7182 | 0 | if (*endofchain != NULL) { |
7183 | 0 | SCTP_BUF_NEXT(((*endofchain))) = appendchain; |
7184 | 0 | } else { |
7185 | 0 | m = outchain; |
7186 | 0 | while (m) { |
7187 | 0 | if (SCTP_BUF_NEXT(m) == NULL) { |
7188 | 0 | SCTP_BUF_NEXT(m) = appendchain; |
7189 | 0 | break; |
7190 | 0 | } |
7191 | 0 | m = SCTP_BUF_NEXT(m); |
7192 | 0 | } |
7193 | 0 | } |
7194 | | /* |
7195 | | * save off the end and update the end-chain |
7196 | | * position |
7197 | | */ |
7198 | 0 | m = appendchain; |
7199 | 0 | while (m) { |
7200 | 0 | if (SCTP_BUF_NEXT(m) == NULL) { |
7201 | 0 | *endofchain = m; |
7202 | 0 | break; |
7203 | 0 | } |
7204 | 0 | m = SCTP_BUF_NEXT(m); |
7205 | 0 | } |
7206 | 0 | return (outchain); |
7207 | 4.32k | } else { |
7208 | | /* save off the end and update the end-chain position */ |
7209 | 4.32k | m = appendchain; |
7210 | 10.0k | while (m) { |
7211 | 10.0k | if (SCTP_BUF_NEXT(m) == NULL) { |
7212 | 4.32k | *endofchain = m; |
7213 | 4.32k | break; |
7214 | 4.32k | } |
7215 | 5.76k | m = SCTP_BUF_NEXT(m); |
7216 | 5.76k | } |
7217 | 4.32k | return (appendchain); |
7218 | 4.32k | } |
7219 | 4.32k | } |
7220 | | |
7221 | | static int |
7222 | | sctp_med_chunk_output(struct sctp_inpcb *inp, |
7223 | | struct sctp_tcb *stcb, |
7224 | | struct sctp_association *asoc, |
7225 | | int *num_out, |
7226 | | int *reason_code, |
7227 | | int control_only, int from_where, |
7228 | | struct timeval *now, int *now_filled, |
7229 | | uint32_t frag_point, int so_locked); |
7230 | | |
7231 | | static void |
7232 | | sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, |
7233 | | uint32_t val SCTP_UNUSED) |
7234 | 0 | { |
7235 | 0 | struct sctp_copy_all *ca; |
7236 | 0 | struct mbuf *m; |
7237 | 0 | int ret = 0; |
7238 | 0 | int added_control = 0; |
7239 | 0 | int un_sent, do_chunk_output = 1; |
7240 | 0 | struct sctp_association *asoc; |
7241 | 0 | struct sctp_nets *net; |
7242 | |
|
7243 | 0 | ca = (struct sctp_copy_all *)ptr; |
7244 | 0 | if (ca->m == NULL) { |
7245 | 0 | return; |
7246 | 0 | } |
7247 | 0 | if (ca->inp != inp) { |
7248 | | /* TSNH */ |
7249 | 0 | return; |
7250 | 0 | } |
7251 | 0 | if (ca->sndlen > 0) { |
7252 | 0 | m = SCTP_M_COPYM(ca->m, 0, M_COPYALL, M_NOWAIT); |
7253 | 0 | if (m == NULL) { |
7254 | | /* can't copy so we are done */ |
7255 | 0 | ca->cnt_failed++; |
7256 | 0 | return; |
7257 | 0 | } |
7258 | | #ifdef SCTP_MBUF_LOGGING |
7259 | | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { |
7260 | | sctp_log_mbc(m, SCTP_MBUF_ICOPY); |
7261 | | } |
7262 | | #endif |
7263 | 0 | } else { |
7264 | 0 | m = NULL; |
7265 | 0 | } |
7266 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
7267 | 0 | if (stcb->asoc.alternate) { |
7268 | 0 | net = stcb->asoc.alternate; |
7269 | 0 | } else { |
7270 | 0 | net = stcb->asoc.primary_destination; |
7271 | 0 | } |
7272 | 0 | if (ca->sndrcv.sinfo_flags & SCTP_ABORT) { |
7273 | | /* Abort this assoc with m as the user defined reason */ |
7274 | 0 | if (m != NULL) { |
7275 | 0 | SCTP_BUF_PREPEND(m, sizeof(struct sctp_paramhdr), M_NOWAIT); |
7276 | 0 | } else { |
7277 | 0 | m = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), |
7278 | 0 | 0, M_NOWAIT, 1, MT_DATA); |
7279 | 0 | if (m != NULL) { |
7280 | 0 | SCTP_BUF_LEN(m) = sizeof(struct sctp_paramhdr); |
7281 | 0 | } |
7282 | 0 | } |
7283 | 0 | if (m != NULL) { |
7284 | 0 | struct sctp_paramhdr *ph; |
7285 | |
|
7286 | 0 | ph = mtod(m, struct sctp_paramhdr *); |
7287 | 0 | ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); |
7288 | 0 | ph->param_length = htons((uint16_t)(sizeof(struct sctp_paramhdr) + ca->sndlen)); |
7289 | 0 | } |
7290 | | /* We add one here to keep the assoc from |
7291 | | * dis-appearing on us. |
7292 | | */ |
7293 | 0 | atomic_add_int(&stcb->asoc.refcnt, 1); |
7294 | 0 | sctp_abort_an_association(inp, stcb, m, false, SCTP_SO_NOT_LOCKED); |
7295 | | /* sctp_abort_an_association calls sctp_free_asoc() |
7296 | | * free association will NOT free it since we |
7297 | | * incremented the refcnt .. we do this to prevent |
7298 | | * it being freed and things getting tricky since |
7299 | | * we could end up (from free_asoc) calling inpcb_free |
7300 | | * which would get a recursive lock call to the |
7301 | | * iterator lock.. But as a consequence of that the |
7302 | | * stcb will return to us un-locked.. since free_asoc |
7303 | | * returns with either no TCB or the TCB unlocked, we |
7304 | | * must relock.. to unlock in the iterator timer :-0 |
7305 | | */ |
7306 | 0 | SCTP_TCB_LOCK(stcb); |
7307 | 0 | atomic_subtract_int(&stcb->asoc.refcnt, 1); |
7308 | 0 | goto no_chunk_output; |
7309 | 0 | } else { |
7310 | 0 | if (m != NULL) { |
7311 | 0 | ret = sctp_msg_append(stcb, net, m, &ca->sndrcv); |
7312 | 0 | } |
7313 | 0 | asoc = &stcb->asoc; |
7314 | 0 | if (ca->sndrcv.sinfo_flags & SCTP_EOF) { |
7315 | | /* shutdown this assoc */ |
7316 | 0 | if (TAILQ_EMPTY(&asoc->send_queue) && |
7317 | 0 | TAILQ_EMPTY(&asoc->sent_queue) && |
7318 | 0 | sctp_is_there_unsent_data(stcb, SCTP_SO_NOT_LOCKED) == 0) { |
7319 | 0 | if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { |
7320 | 0 | goto abort_anyway; |
7321 | 0 | } |
7322 | | /* there is nothing queued to send, so I'm done... */ |
7323 | 0 | if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) && |
7324 | 0 | (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_RECEIVED) && |
7325 | 0 | (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { |
7326 | | /* only send SHUTDOWN the first time through */ |
7327 | 0 | if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) { |
7328 | 0 | SCTP_STAT_DECR_GAUGE32(sctps_currestab); |
7329 | 0 | } |
7330 | 0 | SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT); |
7331 | 0 | sctp_stop_timers_for_shutdown(stcb); |
7332 | 0 | sctp_send_shutdown(stcb, net); |
7333 | 0 | sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, |
7334 | 0 | net); |
7335 | 0 | sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, |
7336 | 0 | NULL); |
7337 | 0 | added_control = 1; |
7338 | 0 | do_chunk_output = 0; |
7339 | 0 | } |
7340 | 0 | } else { |
7341 | | /* |
7342 | | * we still got (or just got) data to send, so set |
7343 | | * SHUTDOWN_PENDING |
7344 | | */ |
7345 | | /* |
7346 | | * XXX sockets draft says that SCTP_EOF should be |
7347 | | * sent with no data. currently, we will allow user |
7348 | | * data to be sent first and move to |
7349 | | * SHUTDOWN-PENDING |
7350 | | */ |
7351 | 0 | if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) && |
7352 | 0 | (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_RECEIVED) && |
7353 | 0 | (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { |
7354 | 0 | if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { |
7355 | 0 | SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT); |
7356 | 0 | } |
7357 | 0 | SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING); |
7358 | 0 | if (TAILQ_EMPTY(&asoc->send_queue) && |
7359 | 0 | TAILQ_EMPTY(&asoc->sent_queue) && |
7360 | 0 | (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { |
7361 | 0 | struct mbuf *op_err; |
7362 | 0 | char msg[SCTP_DIAG_INFO_LEN]; |
7363 | |
|
7364 | 0 | abort_anyway: |
7365 | 0 | SCTP_SNPRINTF(msg, sizeof(msg), |
7366 | 0 | "%s:%d at %s", __FILE__, __LINE__, __func__); |
7367 | 0 | op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), |
7368 | 0 | msg); |
7369 | 0 | atomic_add_int(&stcb->asoc.refcnt, 1); |
7370 | 0 | sctp_abort_an_association(stcb->sctp_ep, stcb, |
7371 | 0 | op_err, false, SCTP_SO_NOT_LOCKED); |
7372 | 0 | atomic_subtract_int(&stcb->asoc.refcnt, 1); |
7373 | 0 | goto no_chunk_output; |
7374 | 0 | } |
7375 | 0 | } |
7376 | 0 | } |
7377 | 0 | } |
7378 | 0 | } |
7379 | 0 | un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) + |
7380 | 0 | (stcb->asoc.stream_queue_cnt * SCTP_DATA_CHUNK_OVERHEAD(stcb))); |
7381 | |
|
7382 | 0 | if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) && |
7383 | 0 | (stcb->asoc.total_flight > 0) && |
7384 | 0 | (un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD))) { |
7385 | 0 | do_chunk_output = 0; |
7386 | 0 | } |
7387 | 0 | if (do_chunk_output) |
7388 | 0 | sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_NOT_LOCKED); |
7389 | 0 | else if (added_control) { |
7390 | 0 | struct timeval now; |
7391 | 0 | int num_out, reason, now_filled = 0; |
7392 | |
|
7393 | 0 | (void)sctp_med_chunk_output(inp, stcb, &stcb->asoc, &num_out, |
7394 | 0 | &reason, 1, 1, &now, &now_filled, |
7395 | 0 | sctp_get_frag_point(stcb), |
7396 | 0 | SCTP_SO_NOT_LOCKED); |
7397 | 0 | } |
7398 | 0 | no_chunk_output: |
7399 | 0 | if (ret) { |
7400 | 0 | ca->cnt_failed++; |
7401 | 0 | } else { |
7402 | 0 | ca->cnt_sent++; |
7403 | 0 | } |
7404 | 0 | } |
7405 | | |
7406 | | static void |
7407 | | sctp_sendall_completes(void *ptr, uint32_t val SCTP_UNUSED) |
7408 | 0 | { |
7409 | 0 | struct sctp_copy_all *ca; |
7410 | |
|
7411 | 0 | ca = (struct sctp_copy_all *)ptr; |
7412 | | /* |
7413 | | * Do a notify here? Kacheong suggests that the notify be done at |
7414 | | * the send time.. so you would push up a notification if any send |
7415 | | * failed. Don't know if this is feasible since the only failures we |
7416 | | * have is "memory" related and if you cannot get an mbuf to send |
7417 | | * the data you surely can't get an mbuf to send up to notify the |
7418 | | * user you can't send the data :-> |
7419 | | */ |
7420 | | |
7421 | | /* now free everything */ |
7422 | 0 | if (ca->inp) { |
7423 | | /* Lets clear the flag to allow others to run. */ |
7424 | 0 | SCTP_INP_WLOCK(ca->inp); |
7425 | 0 | ca->inp->sctp_flags &= ~SCTP_PCB_FLAGS_SND_ITERATOR_UP; |
7426 | 0 | SCTP_INP_WUNLOCK(ca->inp); |
7427 | 0 | } |
7428 | 0 | sctp_m_freem(ca->m); |
7429 | 0 | SCTP_FREE(ca, SCTP_M_COPYAL); |
7430 | 0 | } |
7431 | | |
7432 | | static struct mbuf * |
7433 | | sctp_copy_out_all(struct uio *uio, ssize_t len) |
7434 | 0 | { |
7435 | 0 | struct mbuf *ret, *at; |
7436 | 0 | ssize_t left, willcpy, cancpy, error; |
7437 | |
|
7438 | 0 | ret = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_WAITOK, 1, MT_DATA); |
7439 | 0 | if (ret == NULL) { |
7440 | | /* TSNH */ |
7441 | 0 | return (NULL); |
7442 | 0 | } |
7443 | 0 | left = len; |
7444 | 0 | SCTP_BUF_LEN(ret) = 0; |
7445 | | /* save space for the data chunk header */ |
7446 | 0 | cancpy = (int)M_TRAILINGSPACE(ret); |
7447 | 0 | willcpy = min(cancpy, left); |
7448 | 0 | at = ret; |
7449 | 0 | while (left > 0) { |
7450 | | /* Align data to the end */ |
7451 | 0 | error = uiomove(mtod(at, caddr_t), (int)willcpy, uio); |
7452 | 0 | if (error) { |
7453 | 0 | err_out_now: |
7454 | 0 | sctp_m_freem(at); |
7455 | 0 | return (NULL); |
7456 | 0 | } |
7457 | 0 | SCTP_BUF_LEN(at) = (int)willcpy; |
7458 | 0 | SCTP_BUF_NEXT_PKT(at) = SCTP_BUF_NEXT(at) = 0; |
7459 | 0 | left -= willcpy; |
7460 | 0 | if (left > 0) { |
7461 | 0 | SCTP_BUF_NEXT(at) = sctp_get_mbuf_for_msg((unsigned int)left, 0, M_WAITOK, 1, MT_DATA); |
7462 | 0 | if (SCTP_BUF_NEXT(at) == NULL) { |
7463 | 0 | goto err_out_now; |
7464 | 0 | } |
7465 | 0 | at = SCTP_BUF_NEXT(at); |
7466 | 0 | SCTP_BUF_LEN(at) = 0; |
7467 | 0 | cancpy = (int)M_TRAILINGSPACE(at); |
7468 | 0 | willcpy = min(cancpy, left); |
7469 | 0 | } |
7470 | 0 | } |
7471 | 0 | return (ret); |
7472 | 0 | } |
7473 | | |
7474 | | static int |
7475 | | sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m, |
7476 | | struct sctp_nonpad_sndrcvinfo *srcv) |
7477 | 0 | { |
7478 | 0 | struct sctp_copy_all *ca; |
7479 | 0 | struct mbuf *mat; |
7480 | 0 | ssize_t sndlen; |
7481 | 0 | int ret; |
7482 | |
|
7483 | 0 | if (uio != NULL) { |
7484 | | #if defined(__APPLE__) && !defined(__Userspace__) |
7485 | | #if defined(APPLE_LEOPARD) |
7486 | | sndlen = uio->uio_resid; |
7487 | | #else |
7488 | | sndlen = uio_resid(uio); |
7489 | | #endif |
7490 | | #else |
7491 | 0 | sndlen = uio->uio_resid; |
7492 | 0 | #endif |
7493 | 0 | } else { |
7494 | 0 | sndlen = 0; |
7495 | 0 | for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) { |
7496 | 0 | sndlen += SCTP_BUF_LEN(mat); |
7497 | 0 | } |
7498 | 0 | } |
7499 | 0 | if (sndlen > (ssize_t)SCTP_BASE_SYSCTL(sctp_sendall_limit)) { |
7500 | | /* You must not be larger than the limit! */ |
7501 | 0 | return (EMSGSIZE); |
7502 | 0 | } |
7503 | 0 | SCTP_MALLOC(ca, struct sctp_copy_all *, sizeof(struct sctp_copy_all), |
7504 | 0 | SCTP_M_COPYAL); |
7505 | 0 | if (ca == NULL) { |
7506 | 0 | sctp_m_freem(m); |
7507 | 0 | SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
7508 | 0 | return (ENOMEM); |
7509 | 0 | } |
7510 | 0 | memset(ca, 0, sizeof(struct sctp_copy_all)); |
7511 | 0 | ca->inp = inp; |
7512 | 0 | if (srcv != NULL) { |
7513 | 0 | memcpy(&ca->sndrcv, srcv, sizeof(struct sctp_nonpad_sndrcvinfo)); |
7514 | 0 | } |
7515 | | /* Serialize. */ |
7516 | 0 | SCTP_INP_WLOCK(inp); |
7517 | 0 | if ((inp->sctp_flags & SCTP_PCB_FLAGS_SND_ITERATOR_UP) != 0) { |
7518 | 0 | SCTP_INP_WUNLOCK(inp); |
7519 | 0 | sctp_m_freem(m); |
7520 | 0 | SCTP_FREE(ca, SCTP_M_COPYAL); |
7521 | 0 | return (EBUSY); |
7522 | 0 | } |
7523 | 0 | inp->sctp_flags |= SCTP_PCB_FLAGS_SND_ITERATOR_UP; |
7524 | 0 | SCTP_INP_WUNLOCK(inp); |
7525 | | /* |
7526 | | * take off the sendall flag, it would be bad if we failed to do |
7527 | | * this :-0 |
7528 | | */ |
7529 | 0 | ca->sndrcv.sinfo_flags &= ~SCTP_SENDALL; |
7530 | | /* get length and mbuf chain */ |
7531 | 0 | ca->sndlen = sndlen; |
7532 | 0 | if (uio != NULL) { |
7533 | | #if defined(__APPLE__) && !defined(__Userspace__) |
7534 | | SCTP_SOCKET_UNLOCK(SCTP_INP_SO(inp), 0); |
7535 | | #endif |
7536 | 0 | ca->m = sctp_copy_out_all(uio, ca->sndlen); |
7537 | | #if defined(__APPLE__) && !defined(__Userspace__) |
7538 | | SCTP_SOCKET_LOCK(SCTP_INP_SO(inp), 0); |
7539 | | #endif |
7540 | 0 | if (ca->m == NULL) { |
7541 | 0 | SCTP_FREE(ca, SCTP_M_COPYAL); |
7542 | 0 | sctp_m_freem(m); |
7543 | 0 | SCTP_INP_WLOCK(inp); |
7544 | 0 | inp->sctp_flags &= ~SCTP_PCB_FLAGS_SND_ITERATOR_UP; |
7545 | 0 | SCTP_INP_WUNLOCK(inp); |
7546 | 0 | SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
7547 | 0 | return (ENOMEM); |
7548 | 0 | } |
7549 | 0 | } else { |
7550 | 0 | ca->m = m; |
7551 | 0 | } |
7552 | 0 | ret = sctp_initiate_iterator(NULL, sctp_sendall_iterator, NULL, |
7553 | 0 | SCTP_PCB_ANY_FLAGS, SCTP_PCB_ANY_FEATURES, |
7554 | 0 | SCTP_ASOC_ANY_STATE, |
7555 | 0 | (void *)ca, 0, |
7556 | 0 | sctp_sendall_completes, inp, 1); |
7557 | 0 | if (ret != 0) { |
7558 | 0 | SCTP_INP_WLOCK(inp); |
7559 | 0 | inp->sctp_flags &= ~SCTP_PCB_FLAGS_SND_ITERATOR_UP; |
7560 | 0 | SCTP_INP_WUNLOCK(inp); |
7561 | 0 | SCTP_FREE(ca, SCTP_M_COPYAL); |
7562 | 0 | SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT); |
7563 | 0 | return (EFAULT); |
7564 | 0 | } |
7565 | 0 | return (0); |
7566 | 0 | } |
7567 | | |
7568 | | void |
7569 | | sctp_toss_old_cookies(struct sctp_tcb *stcb, struct sctp_association *asoc) |
7570 | 1.60k | { |
7571 | 1.60k | struct sctp_tmit_chunk *chk, *nchk; |
7572 | | |
7573 | 1.60k | TAILQ_FOREACH_SAFE(chk, &asoc->control_send_queue, sctp_next, nchk) { |
7574 | 1.60k | if (chk->rec.chunk_id.id == SCTP_COOKIE_ECHO) { |
7575 | 1.60k | TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next); |
7576 | 1.60k | asoc->ctrl_queue_cnt--; |
7577 | 1.60k | if (chk->data) { |
7578 | 1.60k | sctp_m_freem(chk->data); |
7579 | 1.60k | chk->data = NULL; |
7580 | 1.60k | } |
7581 | 1.60k | sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); |
7582 | 1.60k | } |
7583 | 1.60k | } |
7584 | 1.60k | } |
7585 | | |
7586 | | void |
7587 | | sctp_toss_old_asconf(struct sctp_tcb *stcb) |
7588 | 0 | { |
7589 | 0 | struct sctp_association *asoc; |
7590 | 0 | struct sctp_tmit_chunk *chk, *nchk; |
7591 | 0 | struct sctp_asconf_chunk *acp; |
7592 | |
|
7593 | 0 | asoc = &stcb->asoc; |
7594 | 0 | TAILQ_FOREACH_SAFE(chk, &asoc->asconf_send_queue, sctp_next, nchk) { |
7595 | | /* find SCTP_ASCONF chunk in queue */ |
7596 | 0 | if (chk->rec.chunk_id.id == SCTP_ASCONF) { |
7597 | 0 | if (chk->data) { |
7598 | 0 | acp = mtod(chk->data, struct sctp_asconf_chunk *); |
7599 | 0 | if (SCTP_TSN_GT(ntohl(acp->serial_number), asoc->asconf_seq_out_acked)) { |
7600 | | /* Not Acked yet */ |
7601 | 0 | break; |
7602 | 0 | } |
7603 | 0 | } |
7604 | 0 | TAILQ_REMOVE(&asoc->asconf_send_queue, chk, sctp_next); |
7605 | 0 | asoc->ctrl_queue_cnt--; |
7606 | 0 | if (chk->data) { |
7607 | 0 | sctp_m_freem(chk->data); |
7608 | 0 | chk->data = NULL; |
7609 | 0 | } |
7610 | 0 | sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); |
7611 | 0 | } |
7612 | 0 | } |
7613 | 0 | } |
7614 | | |
7615 | | static void |
7616 | | sctp_clean_up_datalist(struct sctp_tcb *stcb, |
7617 | | struct sctp_association *asoc, |
7618 | | struct sctp_tmit_chunk **data_list, |
7619 | | int bundle_at, |
7620 | | struct sctp_nets *net) |
7621 | 4.32k | { |
7622 | 4.32k | int i; |
7623 | 4.32k | struct sctp_tmit_chunk *tp1; |
7624 | | |
7625 | 8.64k | for (i = 0; i < bundle_at; i++) { |
7626 | | /* off of the send queue */ |
7627 | 4.32k | TAILQ_REMOVE(&asoc->send_queue, data_list[i], sctp_next); |
7628 | 4.32k | asoc->send_queue_cnt--; |
7629 | 4.32k | if (i > 0) { |
7630 | | /* |
7631 | | * Any chunk NOT 0 you zap the time chunk 0 gets |
7632 | | * zapped or set based on if a RTO measurement is |
7633 | | * needed. |
7634 | | */ |
7635 | 0 | data_list[i]->do_rtt = 0; |
7636 | 0 | } |
7637 | | /* record time */ |
7638 | 4.32k | data_list[i]->sent_rcv_time = net->last_sent_time; |
7639 | 4.32k | data_list[i]->rec.data.cwnd_at_send = net->cwnd; |
7640 | 4.32k | data_list[i]->rec.data.fast_retran_tsn = data_list[i]->rec.data.tsn; |
7641 | 4.32k | if (data_list[i]->whoTo == NULL) { |
7642 | 4.32k | data_list[i]->whoTo = net; |
7643 | 4.32k | atomic_add_int(&net->ref_count, 1); |
7644 | 4.32k | } |
7645 | | /* on to the sent queue */ |
7646 | 4.32k | tp1 = TAILQ_LAST(&asoc->sent_queue, sctpchunk_listhead); |
7647 | 4.32k | if ((tp1) && SCTP_TSN_GT(tp1->rec.data.tsn, data_list[i]->rec.data.tsn)) { |
7648 | 0 | struct sctp_tmit_chunk *tpp; |
7649 | | |
7650 | | /* need to move back */ |
7651 | 0 | back_up_more: |
7652 | 0 | tpp = TAILQ_PREV(tp1, sctpchunk_listhead, sctp_next); |
7653 | 0 | if (tpp == NULL) { |
7654 | 0 | TAILQ_INSERT_BEFORE(tp1, data_list[i], sctp_next); |
7655 | 0 | goto all_done; |
7656 | 0 | } |
7657 | 0 | tp1 = tpp; |
7658 | 0 | if (SCTP_TSN_GT(tp1->rec.data.tsn, data_list[i]->rec.data.tsn)) { |
7659 | 0 | goto back_up_more; |
7660 | 0 | } |
7661 | 0 | TAILQ_INSERT_AFTER(&asoc->sent_queue, tp1, data_list[i], sctp_next); |
7662 | 4.32k | } else { |
7663 | 4.32k | TAILQ_INSERT_TAIL(&asoc->sent_queue, |
7664 | 4.32k | data_list[i], |
7665 | 4.32k | sctp_next); |
7666 | 4.32k | } |
7667 | 4.32k | all_done: |
7668 | | /* This does not lower until the cum-ack passes it */ |
7669 | 4.32k | asoc->sent_queue_cnt++; |
7670 | 4.32k | if ((asoc->peers_rwnd <= 0) && |
7671 | 0 | (asoc->total_flight == 0) && |
7672 | 0 | (bundle_at == 1)) { |
7673 | | /* Mark the chunk as being a window probe */ |
7674 | 0 | SCTP_STAT_INCR(sctps_windowprobed); |
7675 | 0 | } |
7676 | | #ifdef SCTP_AUDITING_ENABLED |
7677 | | sctp_audit_log(0xC2, 3); |
7678 | | #endif |
7679 | 4.32k | data_list[i]->sent = SCTP_DATAGRAM_SENT; |
7680 | 4.32k | data_list[i]->snd_count = 1; |
7681 | 4.32k | data_list[i]->rec.data.chunk_was_revoked = 0; |
7682 | 4.32k | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { |
7683 | 0 | sctp_misc_ints(SCTP_FLIGHT_LOG_UP, |
7684 | 0 | data_list[i]->whoTo->flight_size, |
7685 | 0 | data_list[i]->book_size, |
7686 | 0 | (uint32_t)(uintptr_t)data_list[i]->whoTo, |
7687 | 0 | data_list[i]->rec.data.tsn); |
7688 | 0 | } |
7689 | 4.32k | sctp_flight_size_increase(data_list[i]); |
7690 | 4.32k | sctp_total_flight_increase(stcb, data_list[i]); |
7691 | 4.32k | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) { |
7692 | 0 | sctp_log_rwnd(SCTP_DECREASE_PEER_RWND, |
7693 | 0 | asoc->peers_rwnd, data_list[i]->send_size, SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)); |
7694 | 0 | } |
7695 | 4.32k | asoc->peers_rwnd = sctp_sbspace_sub(asoc->peers_rwnd, |
7696 | 4.32k | (uint32_t) (data_list[i]->send_size + SCTP_BASE_SYSCTL(sctp_peer_chunk_oh))); |
7697 | 4.32k | if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { |
7698 | | /* SWS sender side engages */ |
7699 | 0 | asoc->peers_rwnd = 0; |
7700 | 0 | } |
7701 | 4.32k | } |
7702 | 4.32k | if (asoc->cc_functions.sctp_cwnd_update_packet_transmitted) { |
7703 | 0 | (*asoc->cc_functions.sctp_cwnd_update_packet_transmitted)(stcb, net); |
7704 | 0 | } |
7705 | 4.32k | } |
7706 | | |
7707 | | static void |
7708 | | sctp_clean_up_ctl(struct sctp_tcb *stcb, struct sctp_association *asoc, int so_locked) |
7709 | 7.53k | { |
7710 | 7.53k | struct sctp_tmit_chunk *chk, *nchk; |
7711 | | |
7712 | 7.53k | TAILQ_FOREACH_SAFE(chk, &asoc->control_send_queue, sctp_next, nchk) { |
7713 | 3.21k | if ((chk->rec.chunk_id.id == SCTP_SELECTIVE_ACK) || |
7714 | 3.21k | (chk->rec.chunk_id.id == SCTP_NR_SELECTIVE_ACK) || /* EY */ |
7715 | 3.21k | (chk->rec.chunk_id.id == SCTP_HEARTBEAT_REQUEST) || |
7716 | 3.21k | (chk->rec.chunk_id.id == SCTP_HEARTBEAT_ACK) || |
7717 | 3.21k | (chk->rec.chunk_id.id == SCTP_FORWARD_CUM_TSN) || |
7718 | 3.21k | (chk->rec.chunk_id.id == SCTP_SHUTDOWN) || |
7719 | 3.21k | (chk->rec.chunk_id.id == SCTP_SHUTDOWN_ACK) || |
7720 | 3.21k | (chk->rec.chunk_id.id == SCTP_OPERATION_ERROR) || |
7721 | 3.21k | (chk->rec.chunk_id.id == SCTP_PACKET_DROPPED) || |
7722 | 3.21k | (chk->rec.chunk_id.id == SCTP_COOKIE_ACK) || |
7723 | 3.21k | (chk->rec.chunk_id.id == SCTP_ECN_CWR) || |
7724 | 3.21k | (chk->rec.chunk_id.id == SCTP_ASCONF_ACK)) { |
7725 | | /* Stray chunks must be cleaned up */ |
7726 | 1 | clean_up_anyway: |
7727 | 1 | TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next); |
7728 | 1 | asoc->ctrl_queue_cnt--; |
7729 | 1 | if (chk->data) { |
7730 | 0 | sctp_m_freem(chk->data); |
7731 | 0 | chk->data = NULL; |
7732 | 0 | } |
7733 | 1 | if (chk->rec.chunk_id.id == SCTP_FORWARD_CUM_TSN) { |
7734 | 0 | asoc->fwd_tsn_cnt--; |
7735 | 0 | } |
7736 | 1 | sctp_free_a_chunk(stcb, chk, so_locked); |
7737 | 3.21k | } else if (chk->rec.chunk_id.id == SCTP_STREAM_RESET) { |
7738 | | /* special handling, we must look into the param */ |
7739 | 0 | if (chk != asoc->str_reset) { |
7740 | 0 | goto clean_up_anyway; |
7741 | 0 | } |
7742 | 0 | } |
7743 | 3.21k | } |
7744 | 7.53k | } |
7745 | | |
7746 | | static uint32_t |
7747 | | sctp_can_we_split_this(struct sctp_tcb *stcb, uint32_t length, |
7748 | | uint32_t space_left, uint32_t frag_point, int eeor_on) |
7749 | 0 | { |
7750 | | /* Make a decision on if I should split a |
7751 | | * msg into multiple parts. This is only asked of |
7752 | | * incomplete messages. |
7753 | | */ |
7754 | 0 | if (eeor_on) { |
7755 | | /* If we are doing EEOR we need to always send |
7756 | | * it if its the entire thing, since it might |
7757 | | * be all the guy is putting in the hopper. |
7758 | | */ |
7759 | 0 | if (space_left >= length) { |
7760 | | /*- |
7761 | | * If we have data outstanding, |
7762 | | * we get another chance when the sack |
7763 | | * arrives to transmit - wait for more data |
7764 | | */ |
7765 | 0 | if (stcb->asoc.total_flight == 0) { |
7766 | | /* If nothing is in flight, we zero |
7767 | | * the packet counter. |
7768 | | */ |
7769 | 0 | return (length); |
7770 | 0 | } |
7771 | 0 | return (0); |
7772 | |
|
7773 | 0 | } else { |
7774 | | /* You can fill the rest */ |
7775 | 0 | return (space_left); |
7776 | 0 | } |
7777 | 0 | } |
7778 | | /*- |
7779 | | * For those strange folk that make the send buffer |
7780 | | * smaller than our fragmentation point, we can't |
7781 | | * get a full msg in so we have to allow splitting. |
7782 | | */ |
7783 | 0 | if (SCTP_SB_LIMIT_SND(stcb->sctp_socket) < frag_point) { |
7784 | 0 | return (length); |
7785 | 0 | } |
7786 | 0 | if ((length <= space_left) || |
7787 | 0 | ((length - space_left) < SCTP_BASE_SYSCTL(sctp_min_residual))) { |
7788 | | /* Sub-optimal residual don't split in non-eeor mode. */ |
7789 | 0 | return (0); |
7790 | 0 | } |
7791 | | /* If we reach here length is larger |
7792 | | * than the space_left. Do we wish to split |
7793 | | * it for the sake of packet putting together? |
7794 | | */ |
7795 | 0 | if (space_left >= min(SCTP_BASE_SYSCTL(sctp_min_split_point), frag_point)) { |
7796 | | /* Its ok to split it */ |
7797 | 0 | return (min(space_left, frag_point)); |
7798 | 0 | } |
7799 | | /* Nope, can't split */ |
7800 | 0 | return (0); |
7801 | 0 | } |
7802 | | |
7803 | | static uint32_t |
7804 | | sctp_move_to_outqueue(struct sctp_tcb *stcb, |
7805 | | struct sctp_nets *net, |
7806 | | struct sctp_stream_out *strq, |
7807 | | uint32_t space_left, |
7808 | | uint32_t frag_point, |
7809 | | int *giveup, |
7810 | | int eeor_mode, |
7811 | | int *bail, |
7812 | | int so_locked) |
7813 | 4.32k | { |
7814 | | /* Move from the stream to the send_queue keeping track of the total */ |
7815 | 4.32k | struct sctp_association *asoc; |
7816 | 4.32k | struct sctp_stream_queue_pending *sp; |
7817 | 4.32k | struct sctp_tmit_chunk *chk; |
7818 | 4.32k | struct sctp_data_chunk *dchkh=NULL; |
7819 | 4.32k | struct sctp_idata_chunk *ndchkh=NULL; |
7820 | 4.32k | uint32_t to_move, length; |
7821 | 4.32k | int leading; |
7822 | 4.32k | uint8_t rcv_flags = 0; |
7823 | 4.32k | uint8_t some_taken; |
7824 | | |
7825 | 4.32k | SCTP_TCB_LOCK_ASSERT(stcb); |
7826 | 4.32k | asoc = &stcb->asoc; |
7827 | 4.32k | one_more_time: |
7828 | | /*sa_ignore FREED_MEMORY*/ |
7829 | 4.32k | sp = TAILQ_FIRST(&strq->outqueue); |
7830 | 4.32k | if (sp == NULL) { |
7831 | 0 | sp = TAILQ_FIRST(&strq->outqueue); |
7832 | 0 | if (sp) { |
7833 | 0 | goto one_more_time; |
7834 | 0 | } |
7835 | 0 | if ((sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_EXPLICIT_EOR) == 0) && |
7836 | 0 | (stcb->asoc.idata_supported == 0) && |
7837 | 0 | (strq->last_msg_incomplete)) { |
7838 | 0 | SCTP_PRINTF("Huh? Stream:%d lm_in_c=%d but queue is NULL\n", |
7839 | 0 | strq->sid, |
7840 | 0 | strq->last_msg_incomplete); |
7841 | 0 | strq->last_msg_incomplete = 0; |
7842 | 0 | } |
7843 | 0 | to_move = 0; |
7844 | 0 | goto out_of; |
7845 | 0 | } |
7846 | 4.32k | if ((sp->msg_is_complete) && (sp->length == 0)) { |
7847 | 0 | if (sp->sender_all_done) { |
7848 | | /* We are doing deferred cleanup. Last |
7849 | | * time through when we took all the data |
7850 | | * the sender_all_done was not set. |
7851 | | */ |
7852 | 0 | if ((sp->put_last_out == 0) && (sp->discard_rest == 0)) { |
7853 | 0 | SCTP_PRINTF("Gak, put out entire msg with NO end!-1\n"); |
7854 | 0 | SCTP_PRINTF("sender_done:%d len:%d msg_comp:%d put_last_out:%d\n", |
7855 | 0 | sp->sender_all_done, |
7856 | 0 | sp->length, |
7857 | 0 | sp->msg_is_complete, |
7858 | 0 | sp->put_last_out); |
7859 | 0 | } |
7860 | 0 | atomic_subtract_int(&asoc->stream_queue_cnt, 1); |
7861 | 0 | TAILQ_REMOVE(&strq->outqueue, sp, next); |
7862 | 0 | stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, strq, sp); |
7863 | 0 | if ((strq->state == SCTP_STREAM_RESET_PENDING) && |
7864 | 0 | (strq->chunks_on_queues == 0) && |
7865 | 0 | TAILQ_EMPTY(&strq->outqueue)) { |
7866 | 0 | stcb->asoc.trigger_reset = 1; |
7867 | 0 | } |
7868 | 0 | if (sp->net) { |
7869 | 0 | sctp_free_remote_addr(sp->net); |
7870 | 0 | sp->net = NULL; |
7871 | 0 | } |
7872 | 0 | if (sp->data) { |
7873 | 0 | sctp_m_freem(sp->data); |
7874 | 0 | sp->data = NULL; |
7875 | 0 | } |
7876 | 0 | sctp_free_a_strmoq(stcb, sp, so_locked); |
7877 | | /* back to get the next msg */ |
7878 | 0 | goto one_more_time; |
7879 | 0 | } else { |
7880 | | /* sender just finished this but |
7881 | | * still holds a reference |
7882 | | */ |
7883 | 0 | *giveup = 1; |
7884 | 0 | to_move = 0; |
7885 | 0 | goto out_of; |
7886 | 0 | } |
7887 | 4.32k | } else { |
7888 | | /* is there some to get */ |
7889 | 4.32k | if (sp->length == 0) { |
7890 | | /* no */ |
7891 | 0 | *giveup = 1; |
7892 | 0 | to_move = 0; |
7893 | 0 | goto out_of; |
7894 | 4.32k | } else if (sp->discard_rest) { |
7895 | | /* Whack down the size */ |
7896 | 0 | atomic_subtract_int(&stcb->asoc.total_output_queue_size, sp->length); |
7897 | 0 | if ((stcb->sctp_socket != NULL) && |
7898 | 0 | ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
7899 | 0 | (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { |
7900 | 0 | SCTP_SB_DECR(&stcb->sctp_socket->so_snd, sp->length); |
7901 | 0 | } |
7902 | 0 | if (sp->data) { |
7903 | 0 | sctp_m_freem(sp->data); |
7904 | 0 | sp->data = NULL; |
7905 | 0 | sp->tail_mbuf = NULL; |
7906 | 0 | } |
7907 | 0 | sp->length = 0; |
7908 | 0 | sp->some_taken = 1; |
7909 | 0 | *giveup = 1; |
7910 | 0 | to_move = 0; |
7911 | 0 | goto out_of; |
7912 | 0 | } |
7913 | 4.32k | } |
7914 | 4.32k | some_taken = sp->some_taken; |
7915 | 4.32k | length = sp->length; |
7916 | 4.32k | if (sp->msg_is_complete) { |
7917 | | /* The message is complete */ |
7918 | 4.32k | to_move = min(length, frag_point); |
7919 | 4.32k | if (to_move == length) { |
7920 | | /* All of it fits in the MTU */ |
7921 | 0 | if (sp->some_taken) { |
7922 | 0 | rcv_flags |= SCTP_DATA_LAST_FRAG; |
7923 | 0 | } else { |
7924 | 0 | rcv_flags |= SCTP_DATA_NOT_FRAG; |
7925 | 0 | } |
7926 | 0 | sp->put_last_out = 1; |
7927 | 0 | if (sp->sinfo_flags & SCTP_SACK_IMMEDIATELY) { |
7928 | 0 | rcv_flags |= SCTP_DATA_SACK_IMMEDIATELY; |
7929 | 0 | } |
7930 | 4.32k | } else { |
7931 | | /* Not all of it fits, we fragment */ |
7932 | 4.32k | if (sp->some_taken == 0) { |
7933 | 1.44k | rcv_flags |= SCTP_DATA_FIRST_FRAG; |
7934 | 1.44k | } |
7935 | 4.32k | sp->some_taken = 1; |
7936 | 4.32k | } |
7937 | 4.32k | } else { |
7938 | 0 | to_move = sctp_can_we_split_this(stcb, length, space_left, frag_point, eeor_mode); |
7939 | 0 | if (to_move > 0) { |
7940 | 0 | if (to_move >= length) { |
7941 | 0 | to_move = length; |
7942 | 0 | } |
7943 | 0 | if (sp->some_taken == 0) { |
7944 | 0 | rcv_flags |= SCTP_DATA_FIRST_FRAG; |
7945 | 0 | sp->some_taken = 1; |
7946 | 0 | } |
7947 | 0 | } else { |
7948 | | /* Nothing to take. */ |
7949 | 0 | *giveup = 1; |
7950 | 0 | to_move = 0; |
7951 | 0 | goto out_of; |
7952 | 0 | } |
7953 | 0 | } |
7954 | | |
7955 | | /* If we reach here, we can copy out a chunk */ |
7956 | 4.32k | sctp_alloc_a_chunk(stcb, chk); |
7957 | 4.32k | if (chk == NULL) { |
7958 | | /* No chunk memory */ |
7959 | 0 | *giveup = 1; |
7960 | 0 | to_move = 0; |
7961 | 0 | goto out_of; |
7962 | 0 | } |
7963 | | /* Setup for unordered if needed by looking |
7964 | | * at the user sent info flags. |
7965 | | */ |
7966 | 4.32k | if (sp->sinfo_flags & SCTP_UNORDERED) { |
7967 | 0 | rcv_flags |= SCTP_DATA_UNORDERED; |
7968 | 0 | } |
7969 | 4.32k | if (SCTP_BASE_SYSCTL(sctp_enable_sack_immediately) && |
7970 | 4.32k | (sp->sinfo_flags & SCTP_EOF) == SCTP_EOF) { |
7971 | 0 | rcv_flags |= SCTP_DATA_SACK_IMMEDIATELY; |
7972 | 0 | } |
7973 | | /* clear out the chunk before setting up */ |
7974 | 4.32k | memset(chk, 0, sizeof(*chk)); |
7975 | 4.32k | chk->rec.data.rcv_flags = rcv_flags; |
7976 | | |
7977 | 4.32k | if (to_move >= length) { |
7978 | | /* we think we can steal the whole thing */ |
7979 | 0 | if (to_move < sp->length) { |
7980 | | /* bail, it changed */ |
7981 | 0 | goto dont_do_it; |
7982 | 0 | } |
7983 | 0 | chk->data = sp->data; |
7984 | 0 | chk->last_mbuf = sp->tail_mbuf; |
7985 | | /* register the stealing */ |
7986 | 0 | sp->data = sp->tail_mbuf = NULL; |
7987 | 4.32k | } else { |
7988 | 4.32k | struct mbuf *m; |
7989 | 4.32k | dont_do_it: |
7990 | 4.32k | chk->data = SCTP_M_COPYM(sp->data, 0, to_move, M_NOWAIT); |
7991 | 4.32k | chk->last_mbuf = NULL; |
7992 | 4.32k | if (chk->data == NULL) { |
7993 | 0 | sp->some_taken = some_taken; |
7994 | 0 | sctp_free_a_chunk(stcb, chk, so_locked); |
7995 | 0 | *bail = 1; |
7996 | 0 | to_move = 0; |
7997 | 0 | goto out_of; |
7998 | 0 | } |
7999 | | #ifdef SCTP_MBUF_LOGGING |
8000 | | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { |
8001 | | sctp_log_mbc(chk->data, SCTP_MBUF_ICOPY); |
8002 | | } |
8003 | | #endif |
8004 | | /* Pull off the data */ |
8005 | 4.32k | m_adj(sp->data, to_move); |
8006 | | /* Now lets work our way down and compact it */ |
8007 | 4.32k | m = sp->data; |
8008 | 5.76k | while (m && (SCTP_BUF_LEN(m) == 0)) { |
8009 | 1.44k | sp->data = SCTP_BUF_NEXT(m); |
8010 | 1.44k | SCTP_BUF_NEXT(m) = NULL; |
8011 | 1.44k | if (sp->tail_mbuf == m) { |
8012 | | /*- |
8013 | | * Freeing tail? TSNH since |
8014 | | * we supposedly were taking less |
8015 | | * than the sp->length. |
8016 | | */ |
8017 | 0 | #ifdef INVARIANTS |
8018 | 0 | panic("Huh, freeing tail? - TSNH"); |
8019 | | #else |
8020 | | SCTP_PRINTF("Huh, freeing tail? - TSNH\n"); |
8021 | | sp->tail_mbuf = sp->data = NULL; |
8022 | | sp->length = 0; |
8023 | | #endif |
8024 | 0 | } |
8025 | 1.44k | sctp_m_free(m); |
8026 | 1.44k | m = sp->data; |
8027 | 1.44k | } |
8028 | 4.32k | } |
8029 | 4.32k | if (SCTP_BUF_IS_EXTENDED(chk->data)) { |
8030 | 4.32k | chk->copy_by_ref = 1; |
8031 | 4.32k | } else { |
8032 | 0 | chk->copy_by_ref = 0; |
8033 | 0 | } |
8034 | | /* get last_mbuf and counts of mb usage |
8035 | | * This is ugly but hopefully its only one mbuf. |
8036 | | */ |
8037 | 4.32k | if (chk->last_mbuf == NULL) { |
8038 | 4.32k | chk->last_mbuf = chk->data; |
8039 | 5.76k | while (SCTP_BUF_NEXT(chk->last_mbuf) != NULL) { |
8040 | 1.44k | chk->last_mbuf = SCTP_BUF_NEXT(chk->last_mbuf); |
8041 | 1.44k | } |
8042 | 4.32k | } |
8043 | | |
8044 | 4.32k | if (to_move > length) { |
8045 | | /*- This should not happen either |
8046 | | * since we always lower to_move to the size |
8047 | | * of sp->length if its larger. |
8048 | | */ |
8049 | 0 | #ifdef INVARIANTS |
8050 | 0 | panic("Huh, how can to_move be larger?"); |
8051 | | #else |
8052 | | SCTP_PRINTF("Huh, how can to_move be larger?\n"); |
8053 | | sp->length = 0; |
8054 | | #endif |
8055 | 4.32k | } else { |
8056 | 4.32k | atomic_subtract_int(&sp->length, to_move); |
8057 | 4.32k | } |
8058 | 4.32k | leading = SCTP_DATA_CHUNK_OVERHEAD(stcb); |
8059 | 4.32k | if (M_LEADINGSPACE(chk->data) < leading) { |
8060 | | /* Not enough room for a chunk header, get some */ |
8061 | 4.32k | struct mbuf *m; |
8062 | | |
8063 | 4.32k | m = sctp_get_mbuf_for_msg(1, 0, M_NOWAIT, 1, MT_DATA); |
8064 | 4.32k | if (m == NULL) { |
8065 | | /* |
8066 | | * we're in trouble here. _PREPEND below will free |
8067 | | * all the data if there is no leading space, so we |
8068 | | * must put the data back and restore. |
8069 | | */ |
8070 | 0 | if (sp->data == NULL) { |
8071 | | /* unsteal the data */ |
8072 | 0 | sp->data = chk->data; |
8073 | 0 | sp->tail_mbuf = chk->last_mbuf; |
8074 | 0 | } else { |
8075 | 0 | struct mbuf *m_tmp; |
8076 | | /* reassemble the data */ |
8077 | 0 | m_tmp = sp->data; |
8078 | 0 | sp->data = chk->data; |
8079 | 0 | SCTP_BUF_NEXT(chk->last_mbuf) = m_tmp; |
8080 | 0 | } |
8081 | 0 | sp->some_taken = some_taken; |
8082 | 0 | atomic_add_int(&sp->length, to_move); |
8083 | 0 | chk->data = NULL; |
8084 | 0 | *bail = 1; |
8085 | 0 | sctp_free_a_chunk(stcb, chk, so_locked); |
8086 | 0 | to_move = 0; |
8087 | 0 | goto out_of; |
8088 | 4.32k | } else { |
8089 | 4.32k | SCTP_BUF_LEN(m) = 0; |
8090 | 4.32k | SCTP_BUF_NEXT(m) = chk->data; |
8091 | 4.32k | chk->data = m; |
8092 | 4.32k | M_ALIGN(chk->data, 4); |
8093 | 4.32k | } |
8094 | 4.32k | } |
8095 | 4.32k | SCTP_BUF_PREPEND(chk->data, SCTP_DATA_CHUNK_OVERHEAD(stcb), M_NOWAIT); |
8096 | 4.32k | if (chk->data == NULL) { |
8097 | | /* HELP, TSNH since we assured it would not above? */ |
8098 | 0 | #ifdef INVARIANTS |
8099 | 0 | panic("prepend fails HELP?"); |
8100 | | #else |
8101 | | SCTP_PRINTF("prepend fails HELP?\n"); |
8102 | | sctp_free_a_chunk(stcb, chk, so_locked); |
8103 | | #endif |
8104 | 0 | *bail = 1; |
8105 | 0 | to_move = 0; |
8106 | 0 | goto out_of; |
8107 | 0 | } |
8108 | 4.32k | sctp_snd_sb_alloc(stcb, SCTP_DATA_CHUNK_OVERHEAD(stcb)); |
8109 | 4.32k | chk->book_size = chk->send_size = (uint16_t)(to_move + SCTP_DATA_CHUNK_OVERHEAD(stcb)); |
8110 | 4.32k | chk->book_size_scale = 0; |
8111 | 4.32k | chk->sent = SCTP_DATAGRAM_UNSENT; |
8112 | | |
8113 | 4.32k | chk->flags = 0; |
8114 | 4.32k | chk->asoc = &stcb->asoc; |
8115 | 4.32k | chk->pad_inplace = 0; |
8116 | 4.32k | chk->no_fr_allowed = 0; |
8117 | 4.32k | if (stcb->asoc.idata_supported == 0) { |
8118 | 3.98k | if (rcv_flags & SCTP_DATA_UNORDERED) { |
8119 | | /* Just use 0. The receiver ignores the values. */ |
8120 | 0 | chk->rec.data.mid = 0; |
8121 | 3.98k | } else { |
8122 | 3.98k | chk->rec.data.mid = strq->next_mid_ordered; |
8123 | 3.98k | if (rcv_flags & SCTP_DATA_LAST_FRAG) { |
8124 | 0 | strq->next_mid_ordered++; |
8125 | 0 | } |
8126 | 3.98k | } |
8127 | 3.98k | } else { |
8128 | 339 | if (rcv_flags & SCTP_DATA_UNORDERED) { |
8129 | 0 | chk->rec.data.mid = strq->next_mid_unordered; |
8130 | 0 | if (rcv_flags & SCTP_DATA_LAST_FRAG) { |
8131 | 0 | strq->next_mid_unordered++; |
8132 | 0 | } |
8133 | 339 | } else { |
8134 | 339 | chk->rec.data.mid = strq->next_mid_ordered; |
8135 | 339 | if (rcv_flags & SCTP_DATA_LAST_FRAG) { |
8136 | 0 | strq->next_mid_ordered++; |
8137 | 0 | } |
8138 | 339 | } |
8139 | 339 | } |
8140 | 4.32k | chk->rec.data.sid = sp->sid; |
8141 | 4.32k | chk->rec.data.ppid = sp->ppid; |
8142 | 4.32k | chk->rec.data.context = sp->context; |
8143 | 4.32k | chk->rec.data.doing_fast_retransmit = 0; |
8144 | | |
8145 | 4.32k | chk->rec.data.timetodrop = sp->ts; |
8146 | 4.32k | chk->flags = sp->act_flags; |
8147 | | |
8148 | 4.32k | if (sp->net) { |
8149 | 0 | chk->whoTo = sp->net; |
8150 | 0 | atomic_add_int(&chk->whoTo->ref_count, 1); |
8151 | 0 | } else |
8152 | 4.32k | chk->whoTo = NULL; |
8153 | | |
8154 | 4.32k | if (sp->holds_key_ref) { |
8155 | 0 | chk->auth_keyid = sp->auth_keyid; |
8156 | 0 | sctp_auth_key_acquire(stcb, chk->auth_keyid); |
8157 | 0 | chk->holds_key_ref = 1; |
8158 | 0 | } |
8159 | 4.32k | stcb->asoc.ss_functions.sctp_ss_scheduled(stcb, net, asoc, strq, to_move); |
8160 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
8161 | | chk->rec.data.tsn = atomic_fetchadd_int(&asoc->sending_seq, 1); |
8162 | | #else |
8163 | 4.32k | chk->rec.data.tsn = asoc->sending_seq++; |
8164 | 4.32k | #endif |
8165 | 4.32k | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_AT_SEND_2_OUTQ) { |
8166 | 0 | sctp_misc_ints(SCTP_STRMOUT_LOG_SEND, |
8167 | 0 | (uint32_t)(uintptr_t)stcb, sp->length, |
8168 | 0 | (uint32_t)((chk->rec.data.sid << 16) | (0x0000ffff & chk->rec.data.mid)), |
8169 | 0 | chk->rec.data.tsn); |
8170 | 0 | } |
8171 | 4.32k | if (stcb->asoc.idata_supported == 0) { |
8172 | 3.98k | dchkh = mtod(chk->data, struct sctp_data_chunk *); |
8173 | 3.98k | } else { |
8174 | 339 | ndchkh = mtod(chk->data, struct sctp_idata_chunk *); |
8175 | 339 | } |
8176 | | /* |
8177 | | * Put the rest of the things in place now. Size was done |
8178 | | * earlier in previous loop prior to padding. |
8179 | | */ |
8180 | | |
8181 | 4.32k | SCTP_TCB_LOCK_ASSERT(stcb); |
8182 | | #ifdef SCTP_ASOCLOG_OF_TSNS |
8183 | | if (asoc->tsn_out_at >= SCTP_TSN_LOG_SIZE) { |
8184 | | asoc->tsn_out_at = 0; |
8185 | | asoc->tsn_out_wrapped = 1; |
8186 | | } |
8187 | | asoc->out_tsnlog[asoc->tsn_out_at].tsn = chk->rec.data.tsn; |
8188 | | asoc->out_tsnlog[asoc->tsn_out_at].strm = chk->rec.data.sid; |
8189 | | asoc->out_tsnlog[asoc->tsn_out_at].seq = chk->rec.data.mid; |
8190 | | asoc->out_tsnlog[asoc->tsn_out_at].sz = chk->send_size; |
8191 | | asoc->out_tsnlog[asoc->tsn_out_at].flgs = chk->rec.data.rcv_flags; |
8192 | | asoc->out_tsnlog[asoc->tsn_out_at].stcb = (void *)stcb; |
8193 | | asoc->out_tsnlog[asoc->tsn_out_at].in_pos = asoc->tsn_out_at; |
8194 | | asoc->out_tsnlog[asoc->tsn_out_at].in_out = 2; |
8195 | | asoc->tsn_out_at++; |
8196 | | #endif |
8197 | 4.32k | if (stcb->asoc.idata_supported == 0) { |
8198 | 3.98k | dchkh->ch.chunk_type = SCTP_DATA; |
8199 | 3.98k | dchkh->ch.chunk_flags = chk->rec.data.rcv_flags; |
8200 | 3.98k | dchkh->dp.tsn = htonl(chk->rec.data.tsn); |
8201 | 3.98k | dchkh->dp.sid = htons(strq->sid); |
8202 | 3.98k | dchkh->dp.ssn = htons((uint16_t)chk->rec.data.mid); |
8203 | 3.98k | dchkh->dp.ppid = chk->rec.data.ppid; |
8204 | 3.98k | dchkh->ch.chunk_length = htons(chk->send_size); |
8205 | 3.98k | } else { |
8206 | 339 | ndchkh->ch.chunk_type = SCTP_IDATA; |
8207 | 339 | ndchkh->ch.chunk_flags = chk->rec.data.rcv_flags; |
8208 | 339 | ndchkh->dp.tsn = htonl(chk->rec.data.tsn); |
8209 | 339 | ndchkh->dp.sid = htons(strq->sid); |
8210 | 339 | ndchkh->dp.reserved = htons(0); |
8211 | 339 | ndchkh->dp.mid = htonl(chk->rec.data.mid); |
8212 | 339 | if (sp->fsn == 0) |
8213 | 113 | ndchkh->dp.ppid_fsn.ppid = chk->rec.data.ppid; |
8214 | 226 | else |
8215 | 226 | ndchkh->dp.ppid_fsn.fsn = htonl(sp->fsn); |
8216 | 339 | sp->fsn++; |
8217 | 339 | ndchkh->ch.chunk_length = htons(chk->send_size); |
8218 | 339 | } |
8219 | | /* Now advance the chk->send_size by the actual pad needed. */ |
8220 | 4.32k | if (chk->send_size < SCTP_SIZE32(chk->book_size)) { |
8221 | | /* need a pad */ |
8222 | 0 | struct mbuf *lm; |
8223 | 0 | int pads; |
8224 | |
|
8225 | 0 | pads = SCTP_SIZE32(chk->book_size) - chk->send_size; |
8226 | 0 | lm = sctp_pad_lastmbuf(chk->data, pads, chk->last_mbuf); |
8227 | 0 | if (lm != NULL) { |
8228 | 0 | chk->last_mbuf = lm; |
8229 | 0 | chk->pad_inplace = 1; |
8230 | 0 | } |
8231 | 0 | chk->send_size += pads; |
8232 | 0 | } |
8233 | 4.32k | if (PR_SCTP_ENABLED(chk->flags)) { |
8234 | 0 | asoc->pr_sctp_cnt++; |
8235 | 0 | } |
8236 | 4.32k | if (sp->msg_is_complete && (sp->length == 0) && (sp->sender_all_done)) { |
8237 | | /* All done pull and kill the message */ |
8238 | 0 | if (sp->put_last_out == 0) { |
8239 | 0 | SCTP_PRINTF("Gak, put out entire msg with NO end!-2\n"); |
8240 | 0 | SCTP_PRINTF("sender_done:%d len:%d msg_comp:%d put_last_out:%d\n", |
8241 | 0 | sp->sender_all_done, |
8242 | 0 | sp->length, |
8243 | 0 | sp->msg_is_complete, |
8244 | 0 | sp->put_last_out); |
8245 | 0 | } |
8246 | 0 | atomic_subtract_int(&asoc->stream_queue_cnt, 1); |
8247 | 0 | TAILQ_REMOVE(&strq->outqueue, sp, next); |
8248 | 0 | stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, strq, sp); |
8249 | 0 | if ((strq->state == SCTP_STREAM_RESET_PENDING) && |
8250 | 0 | (strq->chunks_on_queues == 0) && |
8251 | 0 | TAILQ_EMPTY(&strq->outqueue)) { |
8252 | 0 | stcb->asoc.trigger_reset = 1; |
8253 | 0 | } |
8254 | 0 | if (sp->net) { |
8255 | 0 | sctp_free_remote_addr(sp->net); |
8256 | 0 | sp->net = NULL; |
8257 | 0 | } |
8258 | 0 | if (sp->data) { |
8259 | 0 | sctp_m_freem(sp->data); |
8260 | 0 | sp->data = NULL; |
8261 | 0 | } |
8262 | 0 | sctp_free_a_strmoq(stcb, sp, so_locked); |
8263 | 0 | } |
8264 | 4.32k | asoc->chunks_on_out_queue++; |
8265 | 4.32k | strq->chunks_on_queues++; |
8266 | 4.32k | TAILQ_INSERT_TAIL(&asoc->send_queue, chk, sctp_next); |
8267 | 4.32k | asoc->send_queue_cnt++; |
8268 | 4.32k | out_of: |
8269 | 4.32k | return (to_move); |
8270 | 4.32k | } |
8271 | | |
8272 | | static void |
8273 | | sctp_fill_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, |
8274 | | uint32_t frag_point, int eeor_mode, int *quit_now, |
8275 | | int so_locked) |
8276 | 4.32k | { |
8277 | 4.32k | struct sctp_association *asoc; |
8278 | 4.32k | struct sctp_stream_out *strq; |
8279 | 4.32k | uint32_t space_left, moved, total_moved; |
8280 | 4.32k | int bail, giveup; |
8281 | | |
8282 | 4.32k | SCTP_TCB_LOCK_ASSERT(stcb); |
8283 | 4.32k | asoc = &stcb->asoc; |
8284 | 4.32k | total_moved = 0; |
8285 | 4.32k | switch (net->ro._l_addr.sa.sa_family) { |
8286 | 0 | #ifdef INET |
8287 | 0 | case AF_INET: |
8288 | 0 | space_left = net->mtu - SCTP_MIN_V4_OVERHEAD; |
8289 | 0 | break; |
8290 | 0 | #endif |
8291 | 0 | #ifdef INET6 |
8292 | 0 | case AF_INET6: |
8293 | 0 | space_left = net->mtu - SCTP_MIN_OVERHEAD; |
8294 | 0 | break; |
8295 | 0 | #endif |
8296 | 0 | #if defined(__Userspace__) |
8297 | 4.32k | case AF_CONN: |
8298 | 4.32k | space_left = net->mtu - sizeof(struct sctphdr); |
8299 | 4.32k | break; |
8300 | 0 | #endif |
8301 | 0 | default: |
8302 | | /* TSNH */ |
8303 | 0 | space_left = net->mtu; |
8304 | 0 | break; |
8305 | 4.32k | } |
8306 | | /* Need an allowance for the data chunk header too */ |
8307 | 4.32k | space_left -= SCTP_DATA_CHUNK_OVERHEAD(stcb); |
8308 | | |
8309 | | /* must make even word boundary */ |
8310 | 4.32k | space_left &= 0xfffffffc; |
8311 | 4.32k | strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc); |
8312 | 4.32k | giveup = 0; |
8313 | 4.32k | bail = 0; |
8314 | 8.64k | while ((space_left > 0) && (strq != NULL)) { |
8315 | 4.32k | moved = sctp_move_to_outqueue(stcb, net, strq, space_left, |
8316 | 4.32k | frag_point, &giveup, eeor_mode, |
8317 | 4.32k | &bail, so_locked); |
8318 | 4.32k | if ((giveup != 0) || (bail != 0)) { |
8319 | 0 | break; |
8320 | 0 | } |
8321 | 4.32k | strq = stcb->asoc.ss_functions.sctp_ss_select_stream(stcb, net, asoc); |
8322 | 4.32k | total_moved += moved; |
8323 | 4.32k | if (space_left >= moved) { |
8324 | 4.32k | space_left -= moved; |
8325 | 4.32k | } else { |
8326 | 0 | space_left = 0; |
8327 | 0 | } |
8328 | 4.32k | if (space_left >= SCTP_DATA_CHUNK_OVERHEAD(stcb)) { |
8329 | 0 | space_left -= SCTP_DATA_CHUNK_OVERHEAD(stcb); |
8330 | 4.32k | } else { |
8331 | 4.32k | space_left = 0; |
8332 | 4.32k | } |
8333 | 4.32k | space_left &= 0xfffffffc; |
8334 | 4.32k | } |
8335 | 4.32k | if (bail != 0) |
8336 | 0 | *quit_now = 1; |
8337 | | |
8338 | 4.32k | stcb->asoc.ss_functions.sctp_ss_packet_done(stcb, net, asoc); |
8339 | | |
8340 | 4.32k | if (total_moved == 0) { |
8341 | 0 | if ((stcb->asoc.sctp_cmt_on_off == 0) && |
8342 | 0 | (net == stcb->asoc.primary_destination)) { |
8343 | | /* ran dry for primary network net */ |
8344 | 0 | SCTP_STAT_INCR(sctps_primary_randry); |
8345 | 0 | } else if (stcb->asoc.sctp_cmt_on_off > 0) { |
8346 | | /* ran dry with CMT on */ |
8347 | 0 | SCTP_STAT_INCR(sctps_cmt_randry); |
8348 | 0 | } |
8349 | 0 | } |
8350 | 4.32k | } |
8351 | | |
8352 | | void |
8353 | | sctp_fix_ecn_echo(struct sctp_association *asoc) |
8354 | 0 | { |
8355 | 0 | struct sctp_tmit_chunk *chk; |
8356 | |
|
8357 | 0 | TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { |
8358 | 0 | if (chk->rec.chunk_id.id == SCTP_ECN_ECHO) { |
8359 | 0 | chk->sent = SCTP_DATAGRAM_UNSENT; |
8360 | 0 | } |
8361 | 0 | } |
8362 | 0 | } |
8363 | | |
8364 | | void |
8365 | | sctp_move_chunks_from_net(struct sctp_tcb *stcb, struct sctp_nets *net) |
8366 | 0 | { |
8367 | 0 | struct sctp_association *asoc; |
8368 | 0 | struct sctp_tmit_chunk *chk; |
8369 | 0 | struct sctp_stream_queue_pending *sp; |
8370 | 0 | unsigned int i; |
8371 | |
|
8372 | 0 | if (net == NULL) { |
8373 | 0 | return; |
8374 | 0 | } |
8375 | 0 | asoc = &stcb->asoc; |
8376 | 0 | for (i = 0; i < stcb->asoc.streamoutcnt; i++) { |
8377 | 0 | TAILQ_FOREACH(sp, &stcb->asoc.strmout[i].outqueue, next) { |
8378 | 0 | if (sp->net == net) { |
8379 | 0 | sctp_free_remote_addr(sp->net); |
8380 | 0 | sp->net = NULL; |
8381 | 0 | } |
8382 | 0 | } |
8383 | 0 | } |
8384 | 0 | TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { |
8385 | 0 | if (chk->whoTo == net) { |
8386 | 0 | sctp_free_remote_addr(chk->whoTo); |
8387 | 0 | chk->whoTo = NULL; |
8388 | 0 | } |
8389 | 0 | } |
8390 | 0 | } |
8391 | | |
8392 | | int |
8393 | | sctp_med_chunk_output(struct sctp_inpcb *inp, |
8394 | | struct sctp_tcb *stcb, |
8395 | | struct sctp_association *asoc, |
8396 | | int *num_out, |
8397 | | int *reason_code, |
8398 | | int control_only, int from_where, |
8399 | | struct timeval *now, int *now_filled, |
8400 | | uint32_t frag_point, int so_locked) |
8401 | 25.7k | { |
8402 | | /** |
8403 | | * Ok this is the generic chunk service queue. we must do the |
8404 | | * following: |
8405 | | * - Service the stream queue that is next, moving any |
8406 | | * message (note I must get a complete message i.e. FIRST/MIDDLE and |
8407 | | * LAST to the out queue in one pass) and assigning TSN's. This |
8408 | | * only applies though if the peer does not support NDATA. For NDATA |
8409 | | * chunks its ok to not send the entire message ;-) |
8410 | | * - Check to see if the cwnd/rwnd allows any output, if so we go ahead and |
8411 | | * formulate and send the low level chunks. Making sure to combine |
8412 | | * any control in the control chunk queue also. |
8413 | | */ |
8414 | 25.7k | struct sctp_nets *net, *start_at, *sack_goes_to = NULL, *old_start_at = NULL; |
8415 | 25.7k | struct mbuf *outchain, *endoutchain; |
8416 | 25.7k | struct sctp_tmit_chunk *chk, *nchk; |
8417 | | |
8418 | | /* temp arrays for unlinking */ |
8419 | 25.7k | struct sctp_tmit_chunk *data_list[SCTP_MAX_DATA_BUNDLING]; |
8420 | 25.7k | int no_fragmentflg, error; |
8421 | 25.7k | unsigned int max_rwnd_per_dest, max_send_per_dest; |
8422 | 25.7k | int one_chunk, hbflag, skip_data_for_this_net; |
8423 | 25.7k | int asconf, cookie, no_out_cnt; |
8424 | 25.7k | int bundle_at, ctl_cnt, no_data_chunks, eeor_mode; |
8425 | 25.7k | unsigned int mtu, r_mtu, omtu, mx_mtu, to_out; |
8426 | 25.7k | int tsns_sent = 0; |
8427 | 25.7k | uint32_t auth_offset; |
8428 | 25.7k | struct sctp_auth_chunk *auth; |
8429 | 25.7k | uint16_t auth_keyid; |
8430 | 25.7k | int override_ok = 1; |
8431 | 25.7k | int skip_fill_up = 0; |
8432 | 25.7k | int data_auth_reqd = 0; |
8433 | | /* JRS 5/14/07 - Add flag for whether a heartbeat is sent to |
8434 | | the destination. */ |
8435 | 25.7k | int quit_now = 0; |
8436 | 25.7k | bool use_zero_crc; |
8437 | | |
8438 | | #if defined(__APPLE__) && !defined(__Userspace__) |
8439 | | if (so_locked) { |
8440 | | sctp_lock_assert(SCTP_INP_SO(inp)); |
8441 | | } else { |
8442 | | sctp_unlock_assert(SCTP_INP_SO(inp)); |
8443 | | } |
8444 | | #endif |
8445 | 25.7k | *num_out = 0; |
8446 | 25.7k | *reason_code = 0; |
8447 | 25.7k | auth_keyid = stcb->asoc.authinfo.active_keyid; |
8448 | 25.7k | if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) || |
8449 | 25.7k | (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED) || |
8450 | 25.7k | (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR))) { |
8451 | 0 | eeor_mode = 1; |
8452 | 25.7k | } else { |
8453 | 25.7k | eeor_mode = 0; |
8454 | 25.7k | } |
8455 | 25.7k | ctl_cnt = no_out_cnt = asconf = cookie = 0; |
8456 | | /* |
8457 | | * First lets prime the pump. For each destination, if there is room |
8458 | | * in the flight size, attempt to pull an MTU's worth out of the |
8459 | | * stream queues into the general send_queue |
8460 | | */ |
8461 | | #ifdef SCTP_AUDITING_ENABLED |
8462 | | sctp_audit_log(0xC2, 2); |
8463 | | #endif |
8464 | 25.7k | SCTP_TCB_LOCK_ASSERT(stcb); |
8465 | 25.7k | hbflag = 0; |
8466 | 25.7k | if (control_only) |
8467 | 0 | no_data_chunks = 1; |
8468 | 25.7k | else |
8469 | 25.7k | no_data_chunks = 0; |
8470 | | |
8471 | | /* Nothing to possible to send? */ |
8472 | 25.7k | if ((TAILQ_EMPTY(&asoc->control_send_queue) || |
8473 | 3.21k | (asoc->ctrl_queue_cnt == stcb->asoc.ecn_echo_cnt_onq)) && |
8474 | 25.7k | TAILQ_EMPTY(&asoc->asconf_send_queue) && |
8475 | 25.7k | TAILQ_EMPTY(&asoc->send_queue) && |
8476 | 22.5k | sctp_is_there_unsent_data(stcb, so_locked) == 0) { |
8477 | 0 | nothing_to_send: |
8478 | 0 | *reason_code = 9; |
8479 | 0 | return (0); |
8480 | 0 | } |
8481 | 25.7k | if (asoc->peers_rwnd == 0) { |
8482 | | /* No room in peers rwnd */ |
8483 | 0 | *reason_code = 1; |
8484 | 0 | if (asoc->total_flight > 0) { |
8485 | | /* we are allowed one chunk in flight */ |
8486 | 0 | no_data_chunks = 1; |
8487 | 0 | } |
8488 | 0 | } |
8489 | 25.7k | if (stcb->asoc.ecn_echo_cnt_onq) { |
8490 | | /* Record where a sack goes, if any */ |
8491 | 0 | if (no_data_chunks && |
8492 | 0 | (asoc->ctrl_queue_cnt == stcb->asoc.ecn_echo_cnt_onq)) { |
8493 | | /* Nothing but ECNe to send - we don't do that */ |
8494 | 0 | goto nothing_to_send; |
8495 | 0 | } |
8496 | 0 | TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { |
8497 | 0 | if ((chk->rec.chunk_id.id == SCTP_SELECTIVE_ACK) || |
8498 | 0 | (chk->rec.chunk_id.id == SCTP_NR_SELECTIVE_ACK)) { |
8499 | 0 | sack_goes_to = chk->whoTo; |
8500 | 0 | break; |
8501 | 0 | } |
8502 | 0 | } |
8503 | 0 | } |
8504 | 25.7k | max_rwnd_per_dest = ((asoc->peers_rwnd + asoc->total_flight) / asoc->numnets); |
8505 | 25.7k | if (stcb->sctp_socket) |
8506 | 25.7k | max_send_per_dest = SCTP_SB_LIMIT_SND(stcb->sctp_socket) / asoc->numnets; |
8507 | 0 | else |
8508 | 0 | max_send_per_dest = 0; |
8509 | 25.7k | if (no_data_chunks == 0) { |
8510 | | /* How many non-directed chunks are there? */ |
8511 | 25.7k | TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { |
8512 | 0 | if (chk->whoTo == NULL) { |
8513 | | /* We already have non-directed |
8514 | | * chunks on the queue, no need |
8515 | | * to do a fill-up. |
8516 | | */ |
8517 | 0 | skip_fill_up = 1; |
8518 | 0 | break; |
8519 | 0 | } |
8520 | 0 | } |
8521 | 25.7k | } |
8522 | 25.7k | if ((no_data_chunks == 0) && |
8523 | 25.7k | (skip_fill_up == 0) && |
8524 | 25.7k | (!stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc))) { |
8525 | 22.5k | TAILQ_FOREACH(net, &asoc->nets, sctp_next) { |
8526 | | /* |
8527 | | * This for loop we are in takes in |
8528 | | * each net, if its's got space in cwnd and |
8529 | | * has data sent to it (when CMT is off) then it |
8530 | | * calls sctp_fill_outqueue for the net. This gets |
8531 | | * data on the send queue for that network. |
8532 | | * |
8533 | | * In sctp_fill_outqueue TSN's are assigned and |
8534 | | * data is copied out of the stream buffers. Note |
8535 | | * mostly copy by reference (we hope). |
8536 | | */ |
8537 | 22.5k | net->window_probe = 0; |
8538 | 22.5k | if ((net != stcb->asoc.alternate) && |
8539 | 22.5k | ((net->dest_state & SCTP_ADDR_PF) || |
8540 | 22.5k | ((net->dest_state & SCTP_ADDR_REACHABLE) == 0) || |
8541 | 22.5k | (net->dest_state & SCTP_ADDR_UNCONFIRMED))) { |
8542 | 0 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { |
8543 | 0 | sctp_log_cwnd(stcb, net, 1, |
8544 | 0 | SCTP_CWND_LOG_FILL_OUTQ_CALLED); |
8545 | 0 | } |
8546 | 0 | continue; |
8547 | 0 | } |
8548 | 22.5k | if ((stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins) && |
8549 | 0 | (net->flight_size == 0)) { |
8550 | 0 | (*stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins)(stcb, net); |
8551 | 0 | } |
8552 | 22.5k | if (net->flight_size >= net->cwnd) { |
8553 | | /* skip this network, no room - can't fill */ |
8554 | 18.2k | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { |
8555 | 0 | sctp_log_cwnd(stcb, net, 3, |
8556 | 0 | SCTP_CWND_LOG_FILL_OUTQ_CALLED); |
8557 | 0 | } |
8558 | 18.2k | continue; |
8559 | 18.2k | } |
8560 | 4.32k | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { |
8561 | 0 | sctp_log_cwnd(stcb, net, 4, SCTP_CWND_LOG_FILL_OUTQ_CALLED); |
8562 | 0 | } |
8563 | 4.32k | sctp_fill_outqueue(stcb, net, frag_point, eeor_mode, &quit_now, so_locked); |
8564 | 4.32k | if (quit_now) { |
8565 | | /* memory alloc failure */ |
8566 | 0 | no_data_chunks = 1; |
8567 | 0 | break; |
8568 | 0 | } |
8569 | 4.32k | } |
8570 | 22.5k | } |
8571 | | /* now service each destination and send out what we can for it */ |
8572 | | /* Nothing to send? */ |
8573 | 25.7k | if (TAILQ_EMPTY(&asoc->control_send_queue) && |
8574 | 25.7k | TAILQ_EMPTY(&asoc->asconf_send_queue) && |
8575 | 25.7k | TAILQ_EMPTY(&asoc->send_queue)) { |
8576 | 18.2k | *reason_code = 8; |
8577 | 18.2k | return (0); |
8578 | 18.2k | } |
8579 | | |
8580 | 7.53k | if (asoc->sctp_cmt_on_off > 0) { |
8581 | | /* get the last start point */ |
8582 | 0 | start_at = asoc->last_net_cmt_send_started; |
8583 | 0 | if (start_at == NULL) { |
8584 | | /* null so to beginning */ |
8585 | 0 | start_at = TAILQ_FIRST(&asoc->nets); |
8586 | 0 | } else { |
8587 | 0 | start_at = TAILQ_NEXT(asoc->last_net_cmt_send_started, sctp_next); |
8588 | 0 | if (start_at == NULL) { |
8589 | 0 | start_at = TAILQ_FIRST(&asoc->nets); |
8590 | 0 | } |
8591 | 0 | } |
8592 | 0 | asoc->last_net_cmt_send_started = start_at; |
8593 | 7.53k | } else { |
8594 | 7.53k | start_at = TAILQ_FIRST(&asoc->nets); |
8595 | 7.53k | } |
8596 | 7.53k | TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { |
8597 | 3.21k | if (chk->whoTo == NULL) { |
8598 | 0 | if (asoc->alternate) { |
8599 | 0 | chk->whoTo = asoc->alternate; |
8600 | 0 | } else { |
8601 | 0 | chk->whoTo = asoc->primary_destination; |
8602 | 0 | } |
8603 | 0 | atomic_add_int(&chk->whoTo->ref_count, 1); |
8604 | 0 | } |
8605 | 3.21k | } |
8606 | 7.53k | old_start_at = NULL; |
8607 | 15.0k | again_one_more_time: |
8608 | 22.5k | for (net = start_at; net != NULL; net = TAILQ_NEXT(net, sctp_next)) { |
8609 | | /* how much can we send? */ |
8610 | | /* SCTPDBG("Examine for sending net:%x\n", (uint32_t)net); */ |
8611 | 15.0k | if (old_start_at && (old_start_at == net)) { |
8612 | | /* through list completely. */ |
8613 | 7.53k | break; |
8614 | 7.53k | } |
8615 | 7.53k | tsns_sent = 0xa; |
8616 | 7.53k | if (TAILQ_EMPTY(&asoc->control_send_queue) && |
8617 | 7.53k | TAILQ_EMPTY(&asoc->asconf_send_queue) && |
8618 | 4.32k | (net->flight_size >= net->cwnd)) { |
8619 | | /* Nothing on control or asconf and flight is full, we can skip |
8620 | | * even in the CMT case. |
8621 | | */ |
8622 | 0 | continue; |
8623 | 0 | } |
8624 | 7.53k | bundle_at = 0; |
8625 | 7.53k | endoutchain = outchain = NULL; |
8626 | 7.53k | auth = NULL; |
8627 | 7.53k | auth_offset = 0; |
8628 | 7.53k | no_fragmentflg = 1; |
8629 | 7.53k | one_chunk = 0; |
8630 | 7.53k | if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { |
8631 | 0 | skip_data_for_this_net = 1; |
8632 | 7.53k | } else { |
8633 | 7.53k | skip_data_for_this_net = 0; |
8634 | 7.53k | } |
8635 | 7.53k | switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) { |
8636 | 0 | #ifdef INET |
8637 | 0 | case AF_INET: |
8638 | 0 | mtu = net->mtu - SCTP_MIN_V4_OVERHEAD; |
8639 | 0 | break; |
8640 | 0 | #endif |
8641 | 0 | #ifdef INET6 |
8642 | 0 | case AF_INET6: |
8643 | 0 | mtu = net->mtu - SCTP_MIN_OVERHEAD; |
8644 | 0 | break; |
8645 | 0 | #endif |
8646 | 0 | #if defined(__Userspace__) |
8647 | 7.53k | case AF_CONN: |
8648 | 7.53k | mtu = net->mtu - sizeof(struct sctphdr); |
8649 | 7.53k | break; |
8650 | 0 | #endif |
8651 | 0 | default: |
8652 | | /* TSNH */ |
8653 | 0 | mtu = net->mtu; |
8654 | 0 | break; |
8655 | 7.53k | } |
8656 | 7.53k | mx_mtu = mtu; |
8657 | 7.53k | to_out = 0; |
8658 | 7.53k | if (mtu > asoc->peers_rwnd) { |
8659 | 0 | if (asoc->total_flight > 0) { |
8660 | | /* We have a packet in flight somewhere */ |
8661 | 0 | r_mtu = asoc->peers_rwnd; |
8662 | 0 | } else { |
8663 | | /* We are always allowed to send one MTU out */ |
8664 | 0 | one_chunk = 1; |
8665 | 0 | r_mtu = mtu; |
8666 | 0 | } |
8667 | 7.53k | } else { |
8668 | 7.53k | r_mtu = mtu; |
8669 | 7.53k | } |
8670 | 7.53k | error = 0; |
8671 | | /************************/ |
8672 | | /* ASCONF transmission */ |
8673 | | /************************/ |
8674 | | /* Now first lets go through the asconf queue */ |
8675 | 7.53k | TAILQ_FOREACH_SAFE(chk, &asoc->asconf_send_queue, sctp_next, nchk) { |
8676 | 0 | if (chk->rec.chunk_id.id != SCTP_ASCONF) { |
8677 | 0 | continue; |
8678 | 0 | } |
8679 | 0 | if (chk->whoTo == NULL) { |
8680 | 0 | if (asoc->alternate == NULL) { |
8681 | 0 | if (asoc->primary_destination != net) { |
8682 | 0 | break; |
8683 | 0 | } |
8684 | 0 | } else { |
8685 | 0 | if (asoc->alternate != net) { |
8686 | 0 | break; |
8687 | 0 | } |
8688 | 0 | } |
8689 | 0 | } else { |
8690 | 0 | if (chk->whoTo != net) { |
8691 | 0 | break; |
8692 | 0 | } |
8693 | 0 | } |
8694 | 0 | if (chk->data == NULL) { |
8695 | 0 | break; |
8696 | 0 | } |
8697 | 0 | if (chk->sent != SCTP_DATAGRAM_UNSENT && |
8698 | 0 | chk->sent != SCTP_DATAGRAM_RESEND) { |
8699 | 0 | break; |
8700 | 0 | } |
8701 | | /* |
8702 | | * if no AUTH is yet included and this chunk |
8703 | | * requires it, make sure to account for it. We |
8704 | | * don't apply the size until the AUTH chunk is |
8705 | | * actually added below in case there is no room for |
8706 | | * this chunk. NOTE: we overload the use of "omtu" |
8707 | | * here |
8708 | | */ |
8709 | 0 | if ((auth == NULL) && |
8710 | 0 | sctp_auth_is_required_chunk(chk->rec.chunk_id.id, |
8711 | 0 | stcb->asoc.peer_auth_chunks)) { |
8712 | 0 | omtu = sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); |
8713 | 0 | } else |
8714 | 0 | omtu = 0; |
8715 | | /* Here we do NOT factor the r_mtu */ |
8716 | 0 | if ((chk->send_size < (int)(mtu - omtu)) || |
8717 | 0 | (chk->flags & CHUNK_FLAGS_FRAGMENT_OK)) { |
8718 | | /* |
8719 | | * We probably should glom the mbuf chain |
8720 | | * from the chk->data for control but the |
8721 | | * problem is it becomes yet one more level |
8722 | | * of tracking to do if for some reason |
8723 | | * output fails. Then I have got to |
8724 | | * reconstruct the merged control chain.. el |
8725 | | * yucko.. for now we take the easy way and |
8726 | | * do the copy |
8727 | | */ |
8728 | | /* |
8729 | | * Add an AUTH chunk, if chunk requires it |
8730 | | * save the offset into the chain for AUTH |
8731 | | */ |
8732 | 0 | if ((auth == NULL) && |
8733 | 0 | (sctp_auth_is_required_chunk(chk->rec.chunk_id.id, |
8734 | 0 | stcb->asoc.peer_auth_chunks))) { |
8735 | 0 | outchain = sctp_add_auth_chunk(outchain, |
8736 | 0 | &endoutchain, |
8737 | 0 | &auth, |
8738 | 0 | &auth_offset, |
8739 | 0 | stcb, |
8740 | 0 | chk->rec.chunk_id.id); |
8741 | 0 | SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); |
8742 | 0 | } |
8743 | 0 | outchain = sctp_copy_mbufchain(chk->data, outchain, &endoutchain, |
8744 | 0 | (int)chk->rec.chunk_id.can_take_data, |
8745 | 0 | chk->send_size, chk->copy_by_ref); |
8746 | 0 | if (outchain == NULL) { |
8747 | 0 | *reason_code = 8; |
8748 | 0 | SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
8749 | 0 | return (ENOMEM); |
8750 | 0 | } |
8751 | 0 | SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); |
8752 | | /* update our MTU size */ |
8753 | 0 | if (mtu > (chk->send_size + omtu)) |
8754 | 0 | mtu -= (chk->send_size + omtu); |
8755 | 0 | else |
8756 | 0 | mtu = 0; |
8757 | 0 | to_out += (chk->send_size + omtu); |
8758 | | /* Do clear IP_DF ? */ |
8759 | 0 | if (chk->flags & CHUNK_FLAGS_FRAGMENT_OK) { |
8760 | 0 | no_fragmentflg = 0; |
8761 | 0 | } |
8762 | 0 | if (chk->rec.chunk_id.can_take_data) |
8763 | 0 | chk->data = NULL; |
8764 | | /* |
8765 | | * set hb flag since we can |
8766 | | * use these for RTO |
8767 | | */ |
8768 | 0 | hbflag = 1; |
8769 | 0 | asconf = 1; |
8770 | | /* |
8771 | | * should sysctl this: don't |
8772 | | * bundle data with ASCONF |
8773 | | * since it requires AUTH |
8774 | | */ |
8775 | 0 | no_data_chunks = 1; |
8776 | 0 | chk->sent = SCTP_DATAGRAM_SENT; |
8777 | 0 | if (chk->whoTo == NULL) { |
8778 | 0 | chk->whoTo = net; |
8779 | 0 | atomic_add_int(&net->ref_count, 1); |
8780 | 0 | } |
8781 | 0 | chk->snd_count++; |
8782 | 0 | if (mtu == 0) { |
8783 | | /* |
8784 | | * Ok we are out of room but we can |
8785 | | * output without effecting the |
8786 | | * flight size since this little guy |
8787 | | * is a control only packet. |
8788 | | */ |
8789 | 0 | sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, stcb, net); |
8790 | | /* |
8791 | | * do NOT clear the asconf |
8792 | | * flag as it is used to do |
8793 | | * appropriate source address |
8794 | | * selection. |
8795 | | */ |
8796 | 0 | if (*now_filled == 0) { |
8797 | 0 | (void)SCTP_GETTIME_TIMEVAL(now); |
8798 | 0 | *now_filled = 1; |
8799 | 0 | } |
8800 | 0 | net->last_sent_time = *now; |
8801 | 0 | hbflag = 0; |
8802 | 0 | if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, |
8803 | 0 | (struct sockaddr *)&net->ro._l_addr, |
8804 | 0 | outchain, auth_offset, auth, |
8805 | 0 | stcb->asoc.authinfo.active_keyid, |
8806 | 0 | no_fragmentflg, 0, asconf, |
8807 | 0 | inp->sctp_lport, stcb->rport, |
8808 | 0 | htonl(stcb->asoc.peer_vtag), |
8809 | 0 | net->port, NULL, |
8810 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
8811 | | 0, 0, |
8812 | | #endif |
8813 | 0 | false, so_locked))) { |
8814 | | /* error, we could not output */ |
8815 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); |
8816 | 0 | if (from_where == 0) { |
8817 | 0 | SCTP_STAT_INCR(sctps_lowlevelerrusr); |
8818 | 0 | } |
8819 | 0 | if (error == ENOBUFS) { |
8820 | 0 | asoc->ifp_had_enobuf = 1; |
8821 | 0 | SCTP_STAT_INCR(sctps_lowlevelerr); |
8822 | 0 | } |
8823 | | /* error, could not output */ |
8824 | 0 | if (error == EHOSTUNREACH) { |
8825 | | /* |
8826 | | * Destination went |
8827 | | * unreachable |
8828 | | * during this send |
8829 | | */ |
8830 | 0 | sctp_move_chunks_from_net(stcb, net); |
8831 | 0 | } |
8832 | 0 | asconf = 0; |
8833 | 0 | *reason_code = 7; |
8834 | 0 | break; |
8835 | 0 | } else { |
8836 | 0 | asoc->ifp_had_enobuf = 0; |
8837 | 0 | } |
8838 | | /* |
8839 | | * increase the number we sent, if a |
8840 | | * cookie is sent we don't tell them |
8841 | | * any was sent out. |
8842 | | */ |
8843 | 0 | outchain = endoutchain = NULL; |
8844 | 0 | auth = NULL; |
8845 | 0 | auth_offset = 0; |
8846 | 0 | asconf = 0; |
8847 | 0 | if (!no_out_cnt) |
8848 | 0 | *num_out += ctl_cnt; |
8849 | | /* recalc a clean slate and setup */ |
8850 | 0 | switch (net->ro._l_addr.sa.sa_family) { |
8851 | 0 | #ifdef INET |
8852 | 0 | case AF_INET: |
8853 | 0 | mtu = net->mtu - SCTP_MIN_V4_OVERHEAD; |
8854 | 0 | break; |
8855 | 0 | #endif |
8856 | 0 | #ifdef INET6 |
8857 | 0 | case AF_INET6: |
8858 | 0 | mtu = net->mtu - SCTP_MIN_OVERHEAD; |
8859 | 0 | break; |
8860 | 0 | #endif |
8861 | 0 | #if defined(__Userspace__) |
8862 | 0 | case AF_CONN: |
8863 | 0 | mtu = net->mtu - sizeof(struct sctphdr); |
8864 | 0 | break; |
8865 | 0 | #endif |
8866 | 0 | default: |
8867 | | /* TSNH */ |
8868 | 0 | mtu = net->mtu; |
8869 | 0 | break; |
8870 | 0 | } |
8871 | 0 | to_out = 0; |
8872 | 0 | no_fragmentflg = 1; |
8873 | 0 | } |
8874 | 0 | } |
8875 | 0 | } |
8876 | 7.53k | if (error != 0) { |
8877 | | /* try next net */ |
8878 | 0 | continue; |
8879 | 0 | } |
8880 | | /************************/ |
8881 | | /* Control transmission */ |
8882 | | /************************/ |
8883 | | /* Now first lets go through the control queue */ |
8884 | 7.53k | TAILQ_FOREACH_SAFE(chk, &asoc->control_send_queue, sctp_next, nchk) { |
8885 | 3.21k | if ((sack_goes_to) && |
8886 | 0 | (chk->rec.chunk_id.id == SCTP_ECN_ECHO) && |
8887 | 0 | (chk->whoTo != sack_goes_to)) { |
8888 | | /* |
8889 | | * if we have a sack in queue, and we are looking at an |
8890 | | * ecn echo that is NOT queued to where the sack is going.. |
8891 | | */ |
8892 | 0 | if (chk->whoTo == net) { |
8893 | | /* Don't transmit it to where its going (current net) */ |
8894 | 0 | continue; |
8895 | 0 | } else if (sack_goes_to == net) { |
8896 | | /* But do transmit it to this address */ |
8897 | 0 | goto skip_net_check; |
8898 | 0 | } |
8899 | 0 | } |
8900 | 3.21k | if (chk->whoTo == NULL) { |
8901 | 0 | if (asoc->alternate == NULL) { |
8902 | 0 | if (asoc->primary_destination != net) { |
8903 | 0 | continue; |
8904 | 0 | } |
8905 | 0 | } else { |
8906 | 0 | if (asoc->alternate != net) { |
8907 | 0 | continue; |
8908 | 0 | } |
8909 | 0 | } |
8910 | 3.21k | } else { |
8911 | 3.21k | if (chk->whoTo != net) { |
8912 | 0 | continue; |
8913 | 0 | } |
8914 | 3.21k | } |
8915 | 3.21k | skip_net_check: |
8916 | 3.21k | if (chk->data == NULL) { |
8917 | 0 | continue; |
8918 | 0 | } |
8919 | 3.21k | if (chk->sent != SCTP_DATAGRAM_UNSENT) { |
8920 | | /* |
8921 | | * It must be unsent. Cookies and ASCONF's |
8922 | | * hang around but there timers will force |
8923 | | * when marked for resend. |
8924 | | */ |
8925 | 1.60k | continue; |
8926 | 1.60k | } |
8927 | | /* |
8928 | | * if no AUTH is yet included and this chunk |
8929 | | * requires it, make sure to account for it. We |
8930 | | * don't apply the size until the AUTH chunk is |
8931 | | * actually added below in case there is no room for |
8932 | | * this chunk. NOTE: we overload the use of "omtu" |
8933 | | * here |
8934 | | */ |
8935 | 1.60k | if ((auth == NULL) && |
8936 | 1.60k | sctp_auth_is_required_chunk(chk->rec.chunk_id.id, |
8937 | 1.60k | stcb->asoc.peer_auth_chunks)) { |
8938 | 0 | omtu = sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); |
8939 | 0 | } else |
8940 | 1.60k | omtu = 0; |
8941 | | /* Here we do NOT factor the r_mtu */ |
8942 | 1.60k | if ((chk->send_size <= (int)(mtu - omtu)) || |
8943 | 1.60k | (chk->flags & CHUNK_FLAGS_FRAGMENT_OK)) { |
8944 | | /* |
8945 | | * We probably should glom the mbuf chain |
8946 | | * from the chk->data for control but the |
8947 | | * problem is it becomes yet one more level |
8948 | | * of tracking to do if for some reason |
8949 | | * output fails. Then I have got to |
8950 | | * reconstruct the merged control chain.. el |
8951 | | * yucko.. for now we take the easy way and |
8952 | | * do the copy |
8953 | | */ |
8954 | | /* |
8955 | | * Add an AUTH chunk, if chunk requires it |
8956 | | * save the offset into the chain for AUTH |
8957 | | */ |
8958 | 1.60k | if ((auth == NULL) && |
8959 | 1.60k | (sctp_auth_is_required_chunk(chk->rec.chunk_id.id, |
8960 | 1.60k | stcb->asoc.peer_auth_chunks))) { |
8961 | 0 | outchain = sctp_add_auth_chunk(outchain, |
8962 | 0 | &endoutchain, |
8963 | 0 | &auth, |
8964 | 0 | &auth_offset, |
8965 | 0 | stcb, |
8966 | 0 | chk->rec.chunk_id.id); |
8967 | 0 | SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); |
8968 | 0 | } |
8969 | 1.60k | outchain = sctp_copy_mbufchain(chk->data, outchain, &endoutchain, |
8970 | 1.60k | (int)chk->rec.chunk_id.can_take_data, |
8971 | 1.60k | chk->send_size, chk->copy_by_ref); |
8972 | 1.60k | if (outchain == NULL) { |
8973 | 0 | *reason_code = 8; |
8974 | 0 | SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
8975 | 0 | return (ENOMEM); |
8976 | 0 | } |
8977 | 1.60k | SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); |
8978 | | /* update our MTU size */ |
8979 | 1.60k | if (mtu > (chk->send_size + omtu)) |
8980 | 1.60k | mtu -= (chk->send_size + omtu); |
8981 | 0 | else |
8982 | 0 | mtu = 0; |
8983 | 1.60k | to_out += (chk->send_size + omtu); |
8984 | | /* Do clear IP_DF ? */ |
8985 | 1.60k | if (chk->flags & CHUNK_FLAGS_FRAGMENT_OK) { |
8986 | 1.60k | no_fragmentflg = 0; |
8987 | 1.60k | } |
8988 | 1.60k | if (chk->rec.chunk_id.can_take_data) |
8989 | 1 | chk->data = NULL; |
8990 | | /* Mark things to be removed, if needed */ |
8991 | 1.60k | if ((chk->rec.chunk_id.id == SCTP_SELECTIVE_ACK) || |
8992 | 1.60k | (chk->rec.chunk_id.id == SCTP_NR_SELECTIVE_ACK) || /* EY */ |
8993 | 1.60k | (chk->rec.chunk_id.id == SCTP_HEARTBEAT_REQUEST) || |
8994 | 1.60k | (chk->rec.chunk_id.id == SCTP_HEARTBEAT_ACK) || |
8995 | 1.60k | (chk->rec.chunk_id.id == SCTP_SHUTDOWN) || |
8996 | 1.60k | (chk->rec.chunk_id.id == SCTP_SHUTDOWN_ACK) || |
8997 | 1.60k | (chk->rec.chunk_id.id == SCTP_OPERATION_ERROR) || |
8998 | 1.60k | (chk->rec.chunk_id.id == SCTP_COOKIE_ACK) || |
8999 | 1.60k | (chk->rec.chunk_id.id == SCTP_ECN_CWR) || |
9000 | 1.60k | (chk->rec.chunk_id.id == SCTP_PACKET_DROPPED) || |
9001 | 1.60k | (chk->rec.chunk_id.id == SCTP_ASCONF_ACK)) { |
9002 | 1 | if (chk->rec.chunk_id.id == SCTP_HEARTBEAT_REQUEST) { |
9003 | 0 | hbflag = 1; |
9004 | 0 | } |
9005 | | /* remove these chunks at the end */ |
9006 | 1 | if ((chk->rec.chunk_id.id == SCTP_SELECTIVE_ACK) || |
9007 | 1 | (chk->rec.chunk_id.id == SCTP_NR_SELECTIVE_ACK)) { |
9008 | | /* turn off the timer */ |
9009 | 1 | if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) { |
9010 | 0 | sctp_timer_stop(SCTP_TIMER_TYPE_RECV, |
9011 | 0 | inp, stcb, NULL, |
9012 | 0 | SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_1); |
9013 | 0 | } |
9014 | 1 | } |
9015 | 1 | ctl_cnt++; |
9016 | 1.60k | } else { |
9017 | | /* |
9018 | | * Other chunks, since they have |
9019 | | * timers running (i.e. COOKIE) |
9020 | | * we just "trust" that it |
9021 | | * gets sent or retransmitted. |
9022 | | */ |
9023 | 1.60k | ctl_cnt++; |
9024 | 1.60k | if (chk->rec.chunk_id.id == SCTP_COOKIE_ECHO) { |
9025 | 1.60k | cookie = 1; |
9026 | 1.60k | no_out_cnt = 1; |
9027 | 1.60k | } else if (chk->rec.chunk_id.id == SCTP_ECN_ECHO) { |
9028 | | /* |
9029 | | * Increment ecne send count here |
9030 | | * this means we may be over-zealous in |
9031 | | * our counting if the send fails, but its |
9032 | | * the best place to do it (we used to do |
9033 | | * it in the queue of the chunk, but that did |
9034 | | * not tell how many times it was sent. |
9035 | | */ |
9036 | 0 | SCTP_STAT_INCR(sctps_sendecne); |
9037 | 0 | } |
9038 | 1.60k | chk->sent = SCTP_DATAGRAM_SENT; |
9039 | 1.60k | if (chk->whoTo == NULL) { |
9040 | 0 | chk->whoTo = net; |
9041 | 0 | atomic_add_int(&net->ref_count, 1); |
9042 | 0 | } |
9043 | 1.60k | chk->snd_count++; |
9044 | 1.60k | } |
9045 | 1.60k | if (mtu == 0) { |
9046 | | /* |
9047 | | * Ok we are out of room but we can |
9048 | | * output without effecting the |
9049 | | * flight size since this little guy |
9050 | | * is a control only packet. |
9051 | | */ |
9052 | 0 | switch (asoc->snd_edmid) { |
9053 | 0 | case SCTP_EDMID_LOWER_LAYER_DTLS: |
9054 | 0 | use_zero_crc = true; |
9055 | 0 | break; |
9056 | 0 | default: |
9057 | 0 | use_zero_crc = false; |
9058 | 0 | break; |
9059 | 0 | } |
9060 | 0 | if (asconf) { |
9061 | 0 | sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, stcb, net); |
9062 | 0 | use_zero_crc = false; |
9063 | | /* |
9064 | | * do NOT clear the asconf |
9065 | | * flag as it is used to do |
9066 | | * appropriate source address |
9067 | | * selection. |
9068 | | */ |
9069 | 0 | } |
9070 | 0 | if (cookie) { |
9071 | 0 | sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net); |
9072 | 0 | use_zero_crc = false; |
9073 | 0 | cookie = 0; |
9074 | 0 | } |
9075 | | /* Only HB or ASCONF advances time */ |
9076 | 0 | if (hbflag) { |
9077 | 0 | if (*now_filled == 0) { |
9078 | 0 | (void)SCTP_GETTIME_TIMEVAL(now); |
9079 | 0 | *now_filled = 1; |
9080 | 0 | } |
9081 | 0 | net->last_sent_time = *now; |
9082 | 0 | hbflag = 0; |
9083 | 0 | } |
9084 | 0 | if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, |
9085 | 0 | (struct sockaddr *)&net->ro._l_addr, |
9086 | 0 | outchain, |
9087 | 0 | auth_offset, auth, |
9088 | 0 | stcb->asoc.authinfo.active_keyid, |
9089 | 0 | no_fragmentflg, 0, asconf, |
9090 | 0 | inp->sctp_lport, stcb->rport, |
9091 | 0 | htonl(stcb->asoc.peer_vtag), |
9092 | 0 | net->port, NULL, |
9093 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
9094 | | 0, 0, |
9095 | | #endif |
9096 | 0 | use_zero_crc, so_locked))) { |
9097 | | /* error, we could not output */ |
9098 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); |
9099 | 0 | if (from_where == 0) { |
9100 | 0 | SCTP_STAT_INCR(sctps_lowlevelerrusr); |
9101 | 0 | } |
9102 | 0 | if (error == ENOBUFS) { |
9103 | 0 | asoc->ifp_had_enobuf = 1; |
9104 | 0 | SCTP_STAT_INCR(sctps_lowlevelerr); |
9105 | 0 | } |
9106 | 0 | if (error == EHOSTUNREACH) { |
9107 | | /* |
9108 | | * Destination went |
9109 | | * unreachable |
9110 | | * during this send |
9111 | | */ |
9112 | 0 | sctp_move_chunks_from_net(stcb, net); |
9113 | 0 | } |
9114 | 0 | asconf = 0; |
9115 | 0 | *reason_code = 7; |
9116 | 0 | break; |
9117 | 0 | } else { |
9118 | 0 | asoc->ifp_had_enobuf = 0; |
9119 | 0 | } |
9120 | | /* |
9121 | | * increase the number we sent, if a |
9122 | | * cookie is sent we don't tell them |
9123 | | * any was sent out. |
9124 | | */ |
9125 | 0 | outchain = endoutchain = NULL; |
9126 | 0 | auth = NULL; |
9127 | 0 | auth_offset = 0; |
9128 | 0 | asconf = 0; |
9129 | 0 | if (!no_out_cnt) |
9130 | 0 | *num_out += ctl_cnt; |
9131 | | /* recalc a clean slate and setup */ |
9132 | 0 | switch (net->ro._l_addr.sa.sa_family) { |
9133 | 0 | #ifdef INET |
9134 | 0 | case AF_INET: |
9135 | 0 | mtu = net->mtu - SCTP_MIN_V4_OVERHEAD; |
9136 | 0 | break; |
9137 | 0 | #endif |
9138 | 0 | #ifdef INET6 |
9139 | 0 | case AF_INET6: |
9140 | 0 | mtu = net->mtu - SCTP_MIN_OVERHEAD; |
9141 | 0 | break; |
9142 | 0 | #endif |
9143 | 0 | #if defined(__Userspace__) |
9144 | 0 | case AF_CONN: |
9145 | 0 | mtu = net->mtu - sizeof(struct sctphdr); |
9146 | 0 | break; |
9147 | 0 | #endif |
9148 | 0 | default: |
9149 | | /* TSNH */ |
9150 | 0 | mtu = net->mtu; |
9151 | 0 | break; |
9152 | 0 | } |
9153 | 0 | to_out = 0; |
9154 | 0 | no_fragmentflg = 1; |
9155 | 0 | } |
9156 | 1.60k | } |
9157 | 1.60k | } |
9158 | 7.53k | if (error != 0) { |
9159 | | /* try next net */ |
9160 | 0 | continue; |
9161 | 0 | } |
9162 | | /* JRI: if dest is in PF state, do not send data to it */ |
9163 | 7.53k | if ((asoc->sctp_cmt_on_off > 0) && |
9164 | 0 | (net != stcb->asoc.alternate) && |
9165 | 0 | (net->dest_state & SCTP_ADDR_PF)) { |
9166 | 0 | goto no_data_fill; |
9167 | 0 | } |
9168 | 7.53k | if (net->flight_size >= net->cwnd) { |
9169 | 0 | goto no_data_fill; |
9170 | 0 | } |
9171 | 7.53k | if ((asoc->sctp_cmt_on_off > 0) && |
9172 | 0 | (SCTP_BASE_SYSCTL(sctp_buffer_splitting) & SCTP_RECV_BUFFER_SPLITTING) && |
9173 | 0 | (net->flight_size > max_rwnd_per_dest)) { |
9174 | 0 | goto no_data_fill; |
9175 | 0 | } |
9176 | | /* |
9177 | | * We need a specific accounting for the usage of the |
9178 | | * send buffer. We also need to check the number of messages |
9179 | | * per net. For now, this is better than nothing and it |
9180 | | * disabled by default... |
9181 | | */ |
9182 | 7.53k | if ((asoc->sctp_cmt_on_off > 0) && |
9183 | 0 | (SCTP_BASE_SYSCTL(sctp_buffer_splitting) & SCTP_SEND_BUFFER_SPLITTING) && |
9184 | 0 | (max_send_per_dest > 0) && |
9185 | 0 | (net->flight_size > max_send_per_dest)) { |
9186 | 0 | goto no_data_fill; |
9187 | 0 | } |
9188 | | /*********************/ |
9189 | | /* Data transmission */ |
9190 | | /*********************/ |
9191 | | /* |
9192 | | * if AUTH for DATA is required and no AUTH has been added |
9193 | | * yet, account for this in the mtu now... if no data can be |
9194 | | * bundled, this adjustment won't matter anyways since the |
9195 | | * packet will be going out... |
9196 | | */ |
9197 | 7.53k | data_auth_reqd = sctp_auth_is_required_chunk(SCTP_DATA, |
9198 | 7.53k | stcb->asoc.peer_auth_chunks); |
9199 | 7.53k | if (data_auth_reqd && (auth == NULL)) { |
9200 | 0 | mtu -= sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); |
9201 | 0 | } |
9202 | | /* now lets add any data within the MTU constraints */ |
9203 | 7.53k | switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) { |
9204 | 0 | #ifdef INET |
9205 | 0 | case AF_INET: |
9206 | 0 | if (net->mtu > SCTP_MIN_V4_OVERHEAD) |
9207 | 0 | omtu = net->mtu - SCTP_MIN_V4_OVERHEAD; |
9208 | 0 | else |
9209 | 0 | omtu = 0; |
9210 | 0 | break; |
9211 | 0 | #endif |
9212 | 0 | #ifdef INET6 |
9213 | 0 | case AF_INET6: |
9214 | 0 | if (net->mtu > SCTP_MIN_OVERHEAD) |
9215 | 0 | omtu = net->mtu - SCTP_MIN_OVERHEAD; |
9216 | 0 | else |
9217 | 0 | omtu = 0; |
9218 | 0 | break; |
9219 | 0 | #endif |
9220 | 0 | #if defined(__Userspace__) |
9221 | 7.53k | case AF_CONN: |
9222 | 7.53k | if (net->mtu > sizeof(struct sctphdr)) { |
9223 | 7.53k | omtu = net->mtu - sizeof(struct sctphdr); |
9224 | 7.53k | } else { |
9225 | 0 | omtu = 0; |
9226 | 0 | } |
9227 | 7.53k | break; |
9228 | 0 | #endif |
9229 | 0 | default: |
9230 | | /* TSNH */ |
9231 | 0 | omtu = 0; |
9232 | 0 | break; |
9233 | 7.53k | } |
9234 | 7.53k | if ((((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || |
9235 | 3.21k | (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) && |
9236 | 4.32k | (skip_data_for_this_net == 0)) || |
9237 | 5.92k | (cookie)) { |
9238 | 5.92k | TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) { |
9239 | 4.32k | if (no_data_chunks) { |
9240 | | /* let only control go out */ |
9241 | 0 | *reason_code = 1; |
9242 | 0 | break; |
9243 | 0 | } |
9244 | 4.32k | if (net->flight_size >= net->cwnd) { |
9245 | | /* skip this net, no room for data */ |
9246 | 0 | *reason_code = 2; |
9247 | 0 | break; |
9248 | 0 | } |
9249 | 4.32k | if ((chk->whoTo != NULL) && |
9250 | 0 | (chk->whoTo != net)) { |
9251 | | /* Don't send the chunk on this net */ |
9252 | 0 | continue; |
9253 | 0 | } |
9254 | | |
9255 | 4.32k | if (asoc->sctp_cmt_on_off == 0) { |
9256 | 4.32k | if ((asoc->alternate) && |
9257 | 0 | (asoc->alternate != net) && |
9258 | 0 | (chk->whoTo == NULL)) { |
9259 | 0 | continue; |
9260 | 4.32k | } else if ((net != asoc->primary_destination) && |
9261 | 0 | (asoc->alternate == NULL) && |
9262 | 0 | (chk->whoTo == NULL)) { |
9263 | 0 | continue; |
9264 | 0 | } |
9265 | 4.32k | } |
9266 | 4.32k | if ((chk->send_size > omtu) && ((chk->flags & CHUNK_FLAGS_FRAGMENT_OK) == 0)) { |
9267 | | /*- |
9268 | | * strange, we have a chunk that is |
9269 | | * to big for its destination and |
9270 | | * yet no fragment ok flag. |
9271 | | * Something went wrong when the |
9272 | | * PMTU changed...we did not mark |
9273 | | * this chunk for some reason?? I |
9274 | | * will fix it here by letting IP |
9275 | | * fragment it for now and printing |
9276 | | * a warning. This really should not |
9277 | | * happen ... |
9278 | | */ |
9279 | 0 | SCTP_PRINTF("Warning chunk of %d bytes > mtu:%d and yet PMTU disc missed\n", |
9280 | 0 | chk->send_size, mtu); |
9281 | 0 | chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; |
9282 | 0 | } |
9283 | 4.32k | if (SCTP_BASE_SYSCTL(sctp_enable_sack_immediately) && |
9284 | 4.32k | (asoc->state & SCTP_STATE_SHUTDOWN_PENDING)) { |
9285 | 0 | struct sctp_data_chunk *dchkh; |
9286 | |
|
9287 | 0 | dchkh = mtod(chk->data, struct sctp_data_chunk *); |
9288 | 0 | dchkh->ch.chunk_flags |= SCTP_DATA_SACK_IMMEDIATELY; |
9289 | 0 | } |
9290 | 4.32k | if (((chk->send_size <= mtu) && (chk->send_size <= r_mtu)) || |
9291 | 4.32k | ((chk->flags & CHUNK_FLAGS_FRAGMENT_OK) && (chk->send_size <= asoc->peers_rwnd))) { |
9292 | | /* ok we will add this one */ |
9293 | | |
9294 | | /* |
9295 | | * Add an AUTH chunk, if chunk |
9296 | | * requires it, save the offset into |
9297 | | * the chain for AUTH |
9298 | | */ |
9299 | 4.32k | if (data_auth_reqd) { |
9300 | 0 | if (auth == NULL) { |
9301 | 0 | outchain = sctp_add_auth_chunk(outchain, |
9302 | 0 | &endoutchain, |
9303 | 0 | &auth, |
9304 | 0 | &auth_offset, |
9305 | 0 | stcb, |
9306 | 0 | SCTP_DATA); |
9307 | 0 | auth_keyid = chk->auth_keyid; |
9308 | 0 | override_ok = 0; |
9309 | 0 | SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); |
9310 | 0 | } else if (override_ok) { |
9311 | | /* use this data's keyid */ |
9312 | 0 | auth_keyid = chk->auth_keyid; |
9313 | 0 | override_ok = 0; |
9314 | 0 | } else if (auth_keyid != chk->auth_keyid) { |
9315 | | /* different keyid, so done bundling */ |
9316 | 0 | break; |
9317 | 0 | } |
9318 | 0 | } |
9319 | 4.32k | outchain = sctp_copy_mbufchain(chk->data, outchain, &endoutchain, 0, |
9320 | 4.32k | chk->send_size, chk->copy_by_ref); |
9321 | 4.32k | if (outchain == NULL) { |
9322 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "No memory?\n"); |
9323 | 0 | if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { |
9324 | 0 | sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); |
9325 | 0 | } |
9326 | 0 | *reason_code = 3; |
9327 | 0 | SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
9328 | 0 | return (ENOMEM); |
9329 | 0 | } |
9330 | | /* update our MTU size */ |
9331 | | /* Do clear IP_DF ? */ |
9332 | 4.32k | if (chk->flags & CHUNK_FLAGS_FRAGMENT_OK) { |
9333 | 0 | no_fragmentflg = 0; |
9334 | 0 | } |
9335 | | /* unsigned subtraction of mtu */ |
9336 | 4.32k | if (mtu > chk->send_size) |
9337 | 0 | mtu -= chk->send_size; |
9338 | 4.32k | else |
9339 | 4.32k | mtu = 0; |
9340 | | /* unsigned subtraction of r_mtu */ |
9341 | 4.32k | if (r_mtu > chk->send_size) |
9342 | 0 | r_mtu -= chk->send_size; |
9343 | 4.32k | else |
9344 | 4.32k | r_mtu = 0; |
9345 | | |
9346 | 4.32k | to_out += chk->send_size; |
9347 | 4.32k | if ((to_out > mx_mtu) && no_fragmentflg) { |
9348 | 0 | #ifdef INVARIANTS |
9349 | 0 | panic("Exceeding mtu of %d out size is %d", mx_mtu, to_out); |
9350 | | #else |
9351 | | SCTP_PRINTF("Exceeding mtu of %d out size is %d\n", |
9352 | | mx_mtu, to_out); |
9353 | | #endif |
9354 | 0 | } |
9355 | 4.32k | chk->window_probe = 0; |
9356 | 4.32k | data_list[bundle_at++] = chk; |
9357 | 4.32k | if (bundle_at >= SCTP_MAX_DATA_BUNDLING) { |
9358 | 0 | break; |
9359 | 0 | } |
9360 | 4.32k | if (chk->sent == SCTP_DATAGRAM_UNSENT) { |
9361 | 4.32k | if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0) { |
9362 | 4.32k | SCTP_STAT_INCR_COUNTER64(sctps_outorderchunks); |
9363 | 4.32k | } else { |
9364 | 0 | SCTP_STAT_INCR_COUNTER64(sctps_outunorderchunks); |
9365 | 0 | } |
9366 | 4.32k | if (((chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) == SCTP_DATA_LAST_FRAG) && |
9367 | 0 | ((chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == 0)) |
9368 | | /* Count number of user msg's that were fragmented |
9369 | | * we do this by counting when we see a LAST fragment |
9370 | | * only. |
9371 | | */ |
9372 | 4.32k | SCTP_STAT_INCR_COUNTER64(sctps_fragusrmsgs); |
9373 | 4.32k | } |
9374 | 4.32k | if ((mtu == 0) || (r_mtu == 0) || (one_chunk)) { |
9375 | 4.32k | if ((one_chunk) && (stcb->asoc.total_flight == 0)) { |
9376 | 0 | data_list[0]->window_probe = 1; |
9377 | 0 | net->window_probe = 1; |
9378 | 0 | } |
9379 | 4.32k | break; |
9380 | 4.32k | } |
9381 | 4.32k | } else { |
9382 | | /* |
9383 | | * Must be sent in order of the |
9384 | | * TSN's (on a network) |
9385 | | */ |
9386 | 0 | break; |
9387 | 0 | } |
9388 | 4.32k | } /* for (chunk gather loop for this net) */ |
9389 | 5.92k | } /* if asoc.state OPEN */ |
9390 | 7.53k | no_data_fill: |
9391 | | /* Is there something to send for this destination? */ |
9392 | 7.53k | if (outchain) { |
9393 | 5.92k | switch (asoc->snd_edmid) { |
9394 | 0 | case SCTP_EDMID_LOWER_LAYER_DTLS: |
9395 | 0 | use_zero_crc = true; |
9396 | 0 | break; |
9397 | 5.92k | default: |
9398 | 5.92k | use_zero_crc = false; |
9399 | 5.92k | break; |
9400 | 5.92k | } |
9401 | | /* We may need to start a control timer or two */ |
9402 | 5.92k | if (asconf) { |
9403 | 0 | sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, |
9404 | 0 | stcb, net); |
9405 | 0 | use_zero_crc = false; |
9406 | | /* |
9407 | | * do NOT clear the asconf flag as it is used |
9408 | | * to do appropriate source address selection. |
9409 | | */ |
9410 | 0 | } |
9411 | 5.92k | if (cookie) { |
9412 | 1.60k | sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net); |
9413 | 1.60k | use_zero_crc = false; |
9414 | 1.60k | cookie = 0; |
9415 | 1.60k | } |
9416 | | /* must start a send timer if data is being sent */ |
9417 | 5.92k | if (bundle_at && (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer))) { |
9418 | | /* |
9419 | | * no timer running on this destination |
9420 | | * restart it. |
9421 | | */ |
9422 | 1.44k | sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); |
9423 | 1.44k | } |
9424 | 5.92k | if (bundle_at || hbflag) { |
9425 | | /* For data/asconf and hb set time */ |
9426 | 4.32k | if (*now_filled == 0) { |
9427 | 1.44k | (void)SCTP_GETTIME_TIMEVAL(now); |
9428 | 1.44k | *now_filled = 1; |
9429 | 1.44k | } |
9430 | 4.32k | net->last_sent_time = *now; |
9431 | 4.32k | } |
9432 | | /* Now send it, if there is anything to send :> */ |
9433 | 5.92k | if ((error = sctp_lowlevel_chunk_output(inp, |
9434 | 5.92k | stcb, |
9435 | 5.92k | net, |
9436 | 5.92k | (struct sockaddr *)&net->ro._l_addr, |
9437 | 5.92k | outchain, |
9438 | 5.92k | auth_offset, |
9439 | 5.92k | auth, |
9440 | 5.92k | auth_keyid, |
9441 | 5.92k | no_fragmentflg, |
9442 | 5.92k | bundle_at, |
9443 | 5.92k | asconf, |
9444 | 5.92k | inp->sctp_lport, stcb->rport, |
9445 | 5.92k | htonl(stcb->asoc.peer_vtag), |
9446 | 5.92k | net->port, NULL, |
9447 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
9448 | | 0, 0, |
9449 | | #endif |
9450 | 5.92k | use_zero_crc, |
9451 | 5.92k | so_locked))) { |
9452 | | /* error, we could not output */ |
9453 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); |
9454 | 0 | if (from_where == 0) { |
9455 | 0 | SCTP_STAT_INCR(sctps_lowlevelerrusr); |
9456 | 0 | } |
9457 | 0 | if (error == ENOBUFS) { |
9458 | 0 | asoc->ifp_had_enobuf = 1; |
9459 | 0 | SCTP_STAT_INCR(sctps_lowlevelerr); |
9460 | 0 | } |
9461 | 0 | if (error == EHOSTUNREACH) { |
9462 | | /* |
9463 | | * Destination went unreachable |
9464 | | * during this send |
9465 | | */ |
9466 | 0 | sctp_move_chunks_from_net(stcb, net); |
9467 | 0 | } |
9468 | 0 | asconf = 0; |
9469 | 0 | *reason_code = 6; |
9470 | | /*- |
9471 | | * I add this line to be paranoid. As far as |
9472 | | * I can tell the continue, takes us back to |
9473 | | * the top of the for, but just to make sure |
9474 | | * I will reset these again here. |
9475 | | */ |
9476 | 0 | ctl_cnt = 0; |
9477 | 0 | continue; /* This takes us back to the for() for the nets. */ |
9478 | 5.92k | } else { |
9479 | 5.92k | asoc->ifp_had_enobuf = 0; |
9480 | 5.92k | } |
9481 | 5.92k | endoutchain = NULL; |
9482 | 5.92k | auth = NULL; |
9483 | 5.92k | auth_offset = 0; |
9484 | 5.92k | asconf = 0; |
9485 | 5.92k | if (!no_out_cnt) { |
9486 | 4.32k | *num_out += (ctl_cnt + bundle_at); |
9487 | 4.32k | } |
9488 | 5.92k | if (bundle_at) { |
9489 | | /* setup for a RTO measurement */ |
9490 | 4.32k | tsns_sent = data_list[0]->rec.data.tsn; |
9491 | | /* fill time if not already filled */ |
9492 | 4.32k | if (*now_filled == 0) { |
9493 | 0 | (void)SCTP_GETTIME_TIMEVAL(&asoc->time_last_sent); |
9494 | 0 | *now_filled = 1; |
9495 | 0 | *now = asoc->time_last_sent; |
9496 | 4.32k | } else { |
9497 | 4.32k | asoc->time_last_sent = *now; |
9498 | 4.32k | } |
9499 | 4.32k | if (net->rto_needed) { |
9500 | 1.44k | data_list[0]->do_rtt = 1; |
9501 | 1.44k | net->rto_needed = 0; |
9502 | 1.44k | } |
9503 | 4.32k | SCTP_STAT_INCR_BY(sctps_senddata, bundle_at); |
9504 | 4.32k | sctp_clean_up_datalist(stcb, asoc, data_list, bundle_at, net); |
9505 | 4.32k | } |
9506 | 5.92k | if (one_chunk) { |
9507 | 0 | break; |
9508 | 0 | } |
9509 | 5.92k | } |
9510 | 7.53k | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { |
9511 | 0 | sctp_log_cwnd(stcb, net, tsns_sent, SCTP_CWND_LOG_FROM_SEND); |
9512 | 0 | } |
9513 | 7.53k | } |
9514 | 15.0k | if (old_start_at == NULL) { |
9515 | 7.53k | old_start_at = start_at; |
9516 | 7.53k | start_at = TAILQ_FIRST(&asoc->nets); |
9517 | 7.53k | if (old_start_at) |
9518 | 7.53k | goto again_one_more_time; |
9519 | 7.53k | } |
9520 | | |
9521 | | /* |
9522 | | * At the end there should be no NON timed chunks hanging on this |
9523 | | * queue. |
9524 | | */ |
9525 | 7.53k | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { |
9526 | 0 | sctp_log_cwnd(stcb, net, *num_out, SCTP_CWND_LOG_FROM_SEND); |
9527 | 0 | } |
9528 | 7.53k | if ((*num_out == 0) && (*reason_code == 0)) { |
9529 | 3.21k | *reason_code = 4; |
9530 | 4.32k | } else { |
9531 | 4.32k | *reason_code = 5; |
9532 | 4.32k | } |
9533 | 7.53k | sctp_clean_up_ctl(stcb, asoc, so_locked); |
9534 | 7.53k | return (0); |
9535 | 15.0k | } |
9536 | | |
9537 | | void |
9538 | | sctp_queue_op_err(struct sctp_tcb *stcb, struct mbuf *op_err) |
9539 | 0 | { |
9540 | | /*- |
9541 | | * Prepend a OPERATIONAL_ERROR chunk header and put on the end of |
9542 | | * the control chunk queue. |
9543 | | */ |
9544 | 0 | struct sctp_chunkhdr *hdr; |
9545 | 0 | struct sctp_tmit_chunk *chk; |
9546 | 0 | struct mbuf *mat, *last_mbuf; |
9547 | 0 | uint32_t chunk_length; |
9548 | 0 | uint16_t padding_length; |
9549 | |
|
9550 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
9551 | 0 | SCTP_BUF_PREPEND(op_err, sizeof(struct sctp_chunkhdr), M_NOWAIT); |
9552 | 0 | if (op_err == NULL) { |
9553 | 0 | return; |
9554 | 0 | } |
9555 | 0 | last_mbuf = NULL; |
9556 | 0 | chunk_length = 0; |
9557 | 0 | for (mat = op_err; mat != NULL; mat = SCTP_BUF_NEXT(mat)) { |
9558 | 0 | chunk_length += SCTP_BUF_LEN(mat); |
9559 | 0 | if (SCTP_BUF_NEXT(mat) == NULL) { |
9560 | 0 | last_mbuf = mat; |
9561 | 0 | } |
9562 | 0 | } |
9563 | 0 | if (chunk_length > SCTP_MAX_CHUNK_LENGTH) { |
9564 | 0 | sctp_m_freem(op_err); |
9565 | 0 | return; |
9566 | 0 | } |
9567 | 0 | padding_length = chunk_length % 4; |
9568 | 0 | if (padding_length != 0) { |
9569 | 0 | padding_length = 4 - padding_length; |
9570 | 0 | } |
9571 | 0 | if (padding_length != 0) { |
9572 | 0 | if (sctp_add_pad_tombuf(last_mbuf, padding_length) == NULL) { |
9573 | 0 | sctp_m_freem(op_err); |
9574 | 0 | return; |
9575 | 0 | } |
9576 | 0 | } |
9577 | 0 | sctp_alloc_a_chunk(stcb, chk); |
9578 | 0 | if (chk == NULL) { |
9579 | | /* no memory */ |
9580 | 0 | sctp_m_freem(op_err); |
9581 | 0 | return; |
9582 | 0 | } |
9583 | 0 | chk->copy_by_ref = 0; |
9584 | 0 | chk->rec.chunk_id.id = SCTP_OPERATION_ERROR; |
9585 | 0 | chk->rec.chunk_id.can_take_data = 0; |
9586 | 0 | chk->flags = 0; |
9587 | 0 | chk->send_size = (uint16_t)chunk_length; |
9588 | 0 | chk->sent = SCTP_DATAGRAM_UNSENT; |
9589 | 0 | chk->snd_count = 0; |
9590 | 0 | chk->asoc = &stcb->asoc; |
9591 | 0 | chk->data = op_err; |
9592 | 0 | chk->whoTo = NULL; |
9593 | 0 | hdr = mtod(op_err, struct sctp_chunkhdr *); |
9594 | 0 | hdr->chunk_type = SCTP_OPERATION_ERROR; |
9595 | 0 | hdr->chunk_flags = 0; |
9596 | 0 | hdr->chunk_length = htons(chk->send_size); |
9597 | 0 | TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next); |
9598 | 0 | chk->asoc->ctrl_queue_cnt++; |
9599 | 0 | } |
9600 | | |
9601 | | int |
9602 | | sctp_send_cookie_echo(struct mbuf *m, |
9603 | | int offset, int limit, |
9604 | | struct sctp_tcb *stcb, |
9605 | | struct sctp_nets *net) |
9606 | 1.60k | { |
9607 | | /*- |
9608 | | * pull out the cookie and put it at the front of the control chunk |
9609 | | * queue. |
9610 | | */ |
9611 | 1.60k | int at; |
9612 | 1.60k | struct mbuf *cookie; |
9613 | 1.60k | struct sctp_paramhdr param, *phdr; |
9614 | 1.60k | struct sctp_chunkhdr *hdr; |
9615 | 1.60k | struct sctp_tmit_chunk *chk; |
9616 | 1.60k | uint16_t ptype, plen; |
9617 | | |
9618 | 1.60k | SCTP_TCB_LOCK_ASSERT(stcb); |
9619 | | /* First find the cookie in the param area */ |
9620 | 1.60k | cookie = NULL; |
9621 | 1.60k | at = offset + sizeof(struct sctp_init_chunk); |
9622 | 12.8k | for (;;) { |
9623 | 12.8k | phdr = sctp_get_next_param(m, at, ¶m, sizeof(param)); |
9624 | 12.8k | if (phdr == NULL) { |
9625 | 0 | return (-3); |
9626 | 0 | } |
9627 | 12.8k | ptype = ntohs(phdr->param_type); |
9628 | 12.8k | plen = ntohs(phdr->param_length); |
9629 | 12.8k | if (plen < sizeof(struct sctp_paramhdr)) { |
9630 | 0 | return (-6); |
9631 | 0 | } |
9632 | 12.8k | if (ptype == SCTP_STATE_COOKIE) { |
9633 | 1.60k | int pad; |
9634 | | |
9635 | | /* found the cookie */ |
9636 | 1.60k | if (at + plen > limit) { |
9637 | 0 | return (-7); |
9638 | 0 | } |
9639 | 1.60k | cookie = SCTP_M_COPYM(m, at, plen, M_NOWAIT); |
9640 | 1.60k | if (cookie == NULL) { |
9641 | | /* No memory */ |
9642 | 0 | return (-2); |
9643 | 0 | } |
9644 | 1.60k | if ((pad = (plen % 4)) > 0) { |
9645 | 0 | pad = 4 - pad; |
9646 | 0 | } |
9647 | 1.60k | if (pad > 0) { |
9648 | 0 | if (sctp_pad_lastmbuf(cookie, pad, NULL) == NULL) { |
9649 | 0 | return (-8); |
9650 | 0 | } |
9651 | 0 | } |
9652 | | #ifdef SCTP_MBUF_LOGGING |
9653 | | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { |
9654 | | sctp_log_mbc(cookie, SCTP_MBUF_ICOPY); |
9655 | | } |
9656 | | #endif |
9657 | 1.60k | break; |
9658 | 1.60k | } |
9659 | 11.2k | at += SCTP_SIZE32(plen); |
9660 | 11.2k | } |
9661 | | /* ok, we got the cookie lets change it into a cookie echo chunk */ |
9662 | | /* first the change from param to cookie */ |
9663 | 1.60k | hdr = mtod(cookie, struct sctp_chunkhdr *); |
9664 | 1.60k | hdr->chunk_type = SCTP_COOKIE_ECHO; |
9665 | 1.60k | hdr->chunk_flags = 0; |
9666 | | /* get the chunk stuff now and place it in the FRONT of the queue */ |
9667 | 1.60k | sctp_alloc_a_chunk(stcb, chk); |
9668 | 1.60k | if (chk == NULL) { |
9669 | | /* no memory */ |
9670 | 0 | sctp_m_freem(cookie); |
9671 | 0 | return (-5); |
9672 | 0 | } |
9673 | 1.60k | chk->copy_by_ref = 0; |
9674 | 1.60k | chk->rec.chunk_id.id = SCTP_COOKIE_ECHO; |
9675 | 1.60k | chk->rec.chunk_id.can_take_data = 0; |
9676 | 1.60k | chk->flags = CHUNK_FLAGS_FRAGMENT_OK; |
9677 | 1.60k | chk->send_size = SCTP_SIZE32(plen); |
9678 | 1.60k | chk->sent = SCTP_DATAGRAM_UNSENT; |
9679 | 1.60k | chk->snd_count = 0; |
9680 | 1.60k | chk->asoc = &stcb->asoc; |
9681 | 1.60k | chk->data = cookie; |
9682 | 1.60k | chk->whoTo = net; |
9683 | 1.60k | atomic_add_int(&chk->whoTo->ref_count, 1); |
9684 | 1.60k | TAILQ_INSERT_HEAD(&chk->asoc->control_send_queue, chk, sctp_next); |
9685 | 1.60k | chk->asoc->ctrl_queue_cnt++; |
9686 | 1.60k | return (0); |
9687 | 1.60k | } |
9688 | | |
9689 | | void |
9690 | | sctp_send_heartbeat_ack(struct sctp_tcb *stcb, |
9691 | | struct mbuf *m, |
9692 | | int offset, |
9693 | | int chk_length, |
9694 | | struct sctp_nets *net) |
9695 | 0 | { |
9696 | | /* |
9697 | | * take a HB request and make it into a HB ack and send it. |
9698 | | */ |
9699 | 0 | struct mbuf *outchain; |
9700 | 0 | struct sctp_chunkhdr *chdr; |
9701 | 0 | struct sctp_tmit_chunk *chk; |
9702 | |
|
9703 | 0 | if (net == NULL) |
9704 | | /* must have a net pointer */ |
9705 | 0 | return; |
9706 | | |
9707 | 0 | outchain = SCTP_M_COPYM(m, offset, chk_length, M_NOWAIT); |
9708 | 0 | if (outchain == NULL) { |
9709 | | /* gak out of memory */ |
9710 | 0 | return; |
9711 | 0 | } |
9712 | | #ifdef SCTP_MBUF_LOGGING |
9713 | | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { |
9714 | | sctp_log_mbc(outchain, SCTP_MBUF_ICOPY); |
9715 | | } |
9716 | | #endif |
9717 | 0 | chdr = mtod(outchain, struct sctp_chunkhdr *); |
9718 | 0 | chdr->chunk_type = SCTP_HEARTBEAT_ACK; |
9719 | 0 | chdr->chunk_flags = 0; |
9720 | 0 | if (chk_length % 4 != 0) { |
9721 | 0 | sctp_pad_lastmbuf(outchain, 4 - (chk_length % 4), NULL); |
9722 | 0 | } |
9723 | 0 | sctp_alloc_a_chunk(stcb, chk); |
9724 | 0 | if (chk == NULL) { |
9725 | | /* no memory */ |
9726 | 0 | sctp_m_freem(outchain); |
9727 | 0 | return; |
9728 | 0 | } |
9729 | 0 | chk->copy_by_ref = 0; |
9730 | 0 | chk->rec.chunk_id.id = SCTP_HEARTBEAT_ACK; |
9731 | 0 | chk->rec.chunk_id.can_take_data = 1; |
9732 | 0 | chk->flags = 0; |
9733 | 0 | chk->send_size = chk_length; |
9734 | 0 | chk->sent = SCTP_DATAGRAM_UNSENT; |
9735 | 0 | chk->snd_count = 0; |
9736 | 0 | chk->asoc = &stcb->asoc; |
9737 | 0 | chk->data = outchain; |
9738 | 0 | chk->whoTo = net; |
9739 | 0 | atomic_add_int(&chk->whoTo->ref_count, 1); |
9740 | 0 | TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next); |
9741 | 0 | chk->asoc->ctrl_queue_cnt++; |
9742 | 0 | } |
9743 | | |
9744 | | void |
9745 | | sctp_send_cookie_ack(struct sctp_tcb *stcb) |
9746 | 0 | { |
9747 | | /* formulate and queue a cookie-ack back to sender */ |
9748 | 0 | struct mbuf *cookie_ack; |
9749 | 0 | struct sctp_chunkhdr *hdr; |
9750 | 0 | struct sctp_tmit_chunk *chk; |
9751 | |
|
9752 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
9753 | | |
9754 | 0 | cookie_ack = sctp_get_mbuf_for_msg(sizeof(struct sctp_chunkhdr), 0, M_NOWAIT, 1, MT_HEADER); |
9755 | 0 | if (cookie_ack == NULL) { |
9756 | | /* no mbuf's */ |
9757 | 0 | return; |
9758 | 0 | } |
9759 | 0 | SCTP_BUF_RESV_UF(cookie_ack, SCTP_MIN_OVERHEAD); |
9760 | 0 | sctp_alloc_a_chunk(stcb, chk); |
9761 | 0 | if (chk == NULL) { |
9762 | | /* no memory */ |
9763 | 0 | sctp_m_freem(cookie_ack); |
9764 | 0 | return; |
9765 | 0 | } |
9766 | 0 | chk->copy_by_ref = 0; |
9767 | 0 | chk->rec.chunk_id.id = SCTP_COOKIE_ACK; |
9768 | 0 | chk->rec.chunk_id.can_take_data = 1; |
9769 | 0 | chk->flags = 0; |
9770 | 0 | chk->send_size = sizeof(struct sctp_chunkhdr); |
9771 | 0 | chk->sent = SCTP_DATAGRAM_UNSENT; |
9772 | 0 | chk->snd_count = 0; |
9773 | 0 | chk->asoc = &stcb->asoc; |
9774 | 0 | chk->data = cookie_ack; |
9775 | 0 | if (chk->asoc->last_control_chunk_from != NULL) { |
9776 | 0 | chk->whoTo = chk->asoc->last_control_chunk_from; |
9777 | 0 | atomic_add_int(&chk->whoTo->ref_count, 1); |
9778 | 0 | } else { |
9779 | 0 | chk->whoTo = NULL; |
9780 | 0 | } |
9781 | 0 | hdr = mtod(cookie_ack, struct sctp_chunkhdr *); |
9782 | 0 | hdr->chunk_type = SCTP_COOKIE_ACK; |
9783 | 0 | hdr->chunk_flags = 0; |
9784 | 0 | hdr->chunk_length = htons(chk->send_size); |
9785 | 0 | SCTP_BUF_LEN(cookie_ack) = chk->send_size; |
9786 | 0 | TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next); |
9787 | 0 | chk->asoc->ctrl_queue_cnt++; |
9788 | 0 | return; |
9789 | 0 | } |
9790 | | |
9791 | | void |
9792 | | sctp_send_shutdown_ack(struct sctp_tcb *stcb, struct sctp_nets *net) |
9793 | 0 | { |
9794 | | /* formulate and queue a SHUTDOWN-ACK back to the sender */ |
9795 | 0 | struct mbuf *m_shutdown_ack; |
9796 | 0 | struct sctp_shutdown_ack_chunk *ack_cp; |
9797 | 0 | struct sctp_tmit_chunk *chk; |
9798 | |
|
9799 | 0 | m_shutdown_ack = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_ack_chunk), 0, M_NOWAIT, 1, MT_HEADER); |
9800 | 0 | if (m_shutdown_ack == NULL) { |
9801 | | /* no mbuf's */ |
9802 | 0 | return; |
9803 | 0 | } |
9804 | 0 | SCTP_BUF_RESV_UF(m_shutdown_ack, SCTP_MIN_OVERHEAD); |
9805 | 0 | sctp_alloc_a_chunk(stcb, chk); |
9806 | 0 | if (chk == NULL) { |
9807 | | /* no memory */ |
9808 | 0 | sctp_m_freem(m_shutdown_ack); |
9809 | 0 | return; |
9810 | 0 | } |
9811 | 0 | chk->copy_by_ref = 0; |
9812 | 0 | chk->rec.chunk_id.id = SCTP_SHUTDOWN_ACK; |
9813 | 0 | chk->rec.chunk_id.can_take_data = 1; |
9814 | 0 | chk->flags = 0; |
9815 | 0 | chk->send_size = sizeof(struct sctp_chunkhdr); |
9816 | 0 | chk->sent = SCTP_DATAGRAM_UNSENT; |
9817 | 0 | chk->snd_count = 0; |
9818 | 0 | chk->asoc = &stcb->asoc; |
9819 | 0 | chk->data = m_shutdown_ack; |
9820 | 0 | chk->whoTo = net; |
9821 | 0 | if (chk->whoTo) { |
9822 | 0 | atomic_add_int(&chk->whoTo->ref_count, 1); |
9823 | 0 | } |
9824 | 0 | ack_cp = mtod(m_shutdown_ack, struct sctp_shutdown_ack_chunk *); |
9825 | 0 | ack_cp->ch.chunk_type = SCTP_SHUTDOWN_ACK; |
9826 | 0 | ack_cp->ch.chunk_flags = 0; |
9827 | 0 | ack_cp->ch.chunk_length = htons(chk->send_size); |
9828 | 0 | SCTP_BUF_LEN(m_shutdown_ack) = chk->send_size; |
9829 | 0 | TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next); |
9830 | 0 | chk->asoc->ctrl_queue_cnt++; |
9831 | 0 | return; |
9832 | 0 | } |
9833 | | |
9834 | | void |
9835 | | sctp_send_shutdown(struct sctp_tcb *stcb, struct sctp_nets *net) |
9836 | 0 | { |
9837 | | /* formulate and queue a SHUTDOWN to the sender */ |
9838 | 0 | struct mbuf *m_shutdown; |
9839 | 0 | struct sctp_shutdown_chunk *shutdown_cp; |
9840 | 0 | struct sctp_tmit_chunk *chk; |
9841 | |
|
9842 | 0 | TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { |
9843 | 0 | if (chk->rec.chunk_id.id == SCTP_SHUTDOWN) { |
9844 | | /* We already have a SHUTDOWN queued. Reuse it. */ |
9845 | 0 | if (chk->whoTo) { |
9846 | 0 | sctp_free_remote_addr(chk->whoTo); |
9847 | 0 | chk->whoTo = NULL; |
9848 | 0 | } |
9849 | 0 | break; |
9850 | 0 | } |
9851 | 0 | } |
9852 | 0 | if (chk == NULL) { |
9853 | 0 | m_shutdown = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_chunk), 0, M_NOWAIT, 1, MT_HEADER); |
9854 | 0 | if (m_shutdown == NULL) { |
9855 | | /* no mbuf's */ |
9856 | 0 | return; |
9857 | 0 | } |
9858 | 0 | SCTP_BUF_RESV_UF(m_shutdown, SCTP_MIN_OVERHEAD); |
9859 | 0 | sctp_alloc_a_chunk(stcb, chk); |
9860 | 0 | if (chk == NULL) { |
9861 | | /* no memory */ |
9862 | 0 | sctp_m_freem(m_shutdown); |
9863 | 0 | return; |
9864 | 0 | } |
9865 | 0 | chk->copy_by_ref = 0; |
9866 | 0 | chk->rec.chunk_id.id = SCTP_SHUTDOWN; |
9867 | 0 | chk->rec.chunk_id.can_take_data = 1; |
9868 | 0 | chk->flags = 0; |
9869 | 0 | chk->send_size = sizeof(struct sctp_shutdown_chunk); |
9870 | 0 | chk->sent = SCTP_DATAGRAM_UNSENT; |
9871 | 0 | chk->snd_count = 0; |
9872 | 0 | chk->asoc = &stcb->asoc; |
9873 | 0 | chk->data = m_shutdown; |
9874 | 0 | chk->whoTo = net; |
9875 | 0 | if (chk->whoTo) { |
9876 | 0 | atomic_add_int(&chk->whoTo->ref_count, 1); |
9877 | 0 | } |
9878 | 0 | shutdown_cp = mtod(m_shutdown, struct sctp_shutdown_chunk *); |
9879 | 0 | shutdown_cp->ch.chunk_type = SCTP_SHUTDOWN; |
9880 | 0 | shutdown_cp->ch.chunk_flags = 0; |
9881 | 0 | shutdown_cp->ch.chunk_length = htons(chk->send_size); |
9882 | 0 | shutdown_cp->cumulative_tsn_ack = htonl(stcb->asoc.cumulative_tsn); |
9883 | 0 | SCTP_BUF_LEN(m_shutdown) = chk->send_size; |
9884 | 0 | TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next); |
9885 | 0 | chk->asoc->ctrl_queue_cnt++; |
9886 | 0 | } else { |
9887 | 0 | TAILQ_REMOVE(&stcb->asoc.control_send_queue, chk, sctp_next); |
9888 | 0 | chk->whoTo = net; |
9889 | 0 | if (chk->whoTo) { |
9890 | 0 | atomic_add_int(&chk->whoTo->ref_count, 1); |
9891 | 0 | } |
9892 | 0 | shutdown_cp = mtod(chk->data, struct sctp_shutdown_chunk *); |
9893 | 0 | shutdown_cp->cumulative_tsn_ack = htonl(stcb->asoc.cumulative_tsn); |
9894 | 0 | TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, chk, sctp_next); |
9895 | 0 | } |
9896 | 0 | return; |
9897 | 0 | } |
9898 | | |
9899 | | void |
9900 | | sctp_send_asconf(struct sctp_tcb *stcb, struct sctp_nets *net, int addr_locked) |
9901 | 0 | { |
9902 | | /* |
9903 | | * formulate and queue an ASCONF to the peer. |
9904 | | * ASCONF parameters should be queued on the assoc queue. |
9905 | | */ |
9906 | 0 | struct sctp_tmit_chunk *chk; |
9907 | 0 | struct mbuf *m_asconf; |
9908 | 0 | int len; |
9909 | |
|
9910 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
9911 | | |
9912 | 0 | if ((!TAILQ_EMPTY(&stcb->asoc.asconf_send_queue)) && |
9913 | 0 | (!sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_MULTIPLE_ASCONFS))) { |
9914 | | /* can't send a new one if there is one in flight already */ |
9915 | 0 | return; |
9916 | 0 | } |
9917 | | |
9918 | | /* compose an ASCONF chunk, maximum length is PMTU */ |
9919 | 0 | m_asconf = sctp_compose_asconf(stcb, &len, addr_locked); |
9920 | 0 | if (m_asconf == NULL) { |
9921 | 0 | return; |
9922 | 0 | } |
9923 | | |
9924 | 0 | sctp_alloc_a_chunk(stcb, chk); |
9925 | 0 | if (chk == NULL) { |
9926 | | /* no memory */ |
9927 | 0 | sctp_m_freem(m_asconf); |
9928 | 0 | return; |
9929 | 0 | } |
9930 | | |
9931 | 0 | chk->copy_by_ref = 0; |
9932 | 0 | chk->rec.chunk_id.id = SCTP_ASCONF; |
9933 | 0 | chk->rec.chunk_id.can_take_data = 0; |
9934 | 0 | chk->flags = CHUNK_FLAGS_FRAGMENT_OK; |
9935 | 0 | chk->data = m_asconf; |
9936 | 0 | chk->send_size = len; |
9937 | 0 | chk->sent = SCTP_DATAGRAM_UNSENT; |
9938 | 0 | chk->snd_count = 0; |
9939 | 0 | chk->asoc = &stcb->asoc; |
9940 | 0 | chk->whoTo = net; |
9941 | 0 | if (chk->whoTo) { |
9942 | 0 | atomic_add_int(&chk->whoTo->ref_count, 1); |
9943 | 0 | } |
9944 | 0 | TAILQ_INSERT_TAIL(&chk->asoc->asconf_send_queue, chk, sctp_next); |
9945 | 0 | chk->asoc->ctrl_queue_cnt++; |
9946 | 0 | return; |
9947 | 0 | } |
9948 | | |
9949 | | void |
9950 | | sctp_send_asconf_ack(struct sctp_tcb *stcb) |
9951 | 0 | { |
9952 | | /* |
9953 | | * formulate and queue a asconf-ack back to sender. |
9954 | | * the asconf-ack must be stored in the tcb. |
9955 | | */ |
9956 | 0 | struct sctp_tmit_chunk *chk; |
9957 | 0 | struct sctp_asconf_ack *ack, *latest_ack; |
9958 | 0 | struct mbuf *m_ack; |
9959 | 0 | struct sctp_nets *net = NULL; |
9960 | |
|
9961 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
9962 | | /* Get the latest ASCONF-ACK */ |
9963 | 0 | latest_ack = TAILQ_LAST(&stcb->asoc.asconf_ack_sent, sctp_asconf_ackhead); |
9964 | 0 | if (latest_ack == NULL) { |
9965 | 0 | return; |
9966 | 0 | } |
9967 | 0 | if (latest_ack->last_sent_to != NULL && |
9968 | 0 | latest_ack->last_sent_to == stcb->asoc.last_control_chunk_from) { |
9969 | | /* we're doing a retransmission */ |
9970 | 0 | net = sctp_find_alternate_net(stcb, stcb->asoc.last_control_chunk_from, 0); |
9971 | 0 | if (net == NULL) { |
9972 | | /* no alternate */ |
9973 | 0 | if (stcb->asoc.last_control_chunk_from == NULL) { |
9974 | 0 | if (stcb->asoc.alternate) { |
9975 | 0 | net = stcb->asoc.alternate; |
9976 | 0 | } else { |
9977 | 0 | net = stcb->asoc.primary_destination; |
9978 | 0 | } |
9979 | 0 | } else { |
9980 | 0 | net = stcb->asoc.last_control_chunk_from; |
9981 | 0 | } |
9982 | 0 | } |
9983 | 0 | } else { |
9984 | | /* normal case */ |
9985 | 0 | if (stcb->asoc.last_control_chunk_from == NULL) { |
9986 | 0 | if (stcb->asoc.alternate) { |
9987 | 0 | net = stcb->asoc.alternate; |
9988 | 0 | } else { |
9989 | 0 | net = stcb->asoc.primary_destination; |
9990 | 0 | } |
9991 | 0 | } else { |
9992 | 0 | net = stcb->asoc.last_control_chunk_from; |
9993 | 0 | } |
9994 | 0 | } |
9995 | 0 | latest_ack->last_sent_to = net; |
9996 | |
|
9997 | 0 | TAILQ_FOREACH(ack, &stcb->asoc.asconf_ack_sent, next) { |
9998 | 0 | if (ack->data == NULL) { |
9999 | 0 | continue; |
10000 | 0 | } |
10001 | | |
10002 | | /* copy the asconf_ack */ |
10003 | 0 | m_ack = SCTP_M_COPYM(ack->data, 0, M_COPYALL, M_NOWAIT); |
10004 | 0 | if (m_ack == NULL) { |
10005 | | /* couldn't copy it */ |
10006 | 0 | return; |
10007 | 0 | } |
10008 | | #ifdef SCTP_MBUF_LOGGING |
10009 | | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { |
10010 | | sctp_log_mbc(m_ack, SCTP_MBUF_ICOPY); |
10011 | | } |
10012 | | #endif |
10013 | | |
10014 | 0 | sctp_alloc_a_chunk(stcb, chk); |
10015 | 0 | if (chk == NULL) { |
10016 | | /* no memory */ |
10017 | 0 | if (m_ack) |
10018 | 0 | sctp_m_freem(m_ack); |
10019 | 0 | return; |
10020 | 0 | } |
10021 | 0 | chk->copy_by_ref = 0; |
10022 | 0 | chk->rec.chunk_id.id = SCTP_ASCONF_ACK; |
10023 | 0 | chk->rec.chunk_id.can_take_data = 1; |
10024 | 0 | chk->flags = CHUNK_FLAGS_FRAGMENT_OK; |
10025 | 0 | chk->whoTo = net; |
10026 | 0 | if (chk->whoTo) { |
10027 | 0 | atomic_add_int(&chk->whoTo->ref_count, 1); |
10028 | 0 | } |
10029 | 0 | chk->data = m_ack; |
10030 | 0 | chk->send_size = ack->len; |
10031 | 0 | chk->sent = SCTP_DATAGRAM_UNSENT; |
10032 | 0 | chk->snd_count = 0; |
10033 | 0 | chk->asoc = &stcb->asoc; |
10034 | |
|
10035 | 0 | TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next); |
10036 | 0 | chk->asoc->ctrl_queue_cnt++; |
10037 | 0 | } |
10038 | 0 | return; |
10039 | 0 | } |
10040 | | |
10041 | | static int |
10042 | | sctp_chunk_retransmission(struct sctp_inpcb *inp, |
10043 | | struct sctp_tcb *stcb, |
10044 | | struct sctp_association *asoc, |
10045 | | int *cnt_out, struct timeval *now, int *now_filled, int *fr_done, int so_locked) |
10046 | 0 | { |
10047 | | /*- |
10048 | | * send out one MTU of retransmission. If fast_retransmit is |
10049 | | * happening we ignore the cwnd. Otherwise we obey the cwnd and |
10050 | | * rwnd. For a Cookie or Asconf in the control chunk queue we |
10051 | | * retransmit them by themselves. |
10052 | | * |
10053 | | * For data chunks we will pick out the lowest TSN's in the sent_queue |
10054 | | * marked for resend and bundle them all together (up to a MTU of |
10055 | | * destination). The address to send to should have been |
10056 | | * selected/changed where the retransmission was marked (i.e. in FR |
10057 | | * or t3-timeout routines). |
10058 | | */ |
10059 | 0 | struct sctp_tmit_chunk *data_list[SCTP_MAX_DATA_BUNDLING]; |
10060 | 0 | struct sctp_tmit_chunk *chk, *fwd; |
10061 | 0 | struct mbuf *m, *endofchain; |
10062 | 0 | struct sctp_nets *net = NULL; |
10063 | 0 | uint32_t tsns_sent = 0; |
10064 | 0 | int no_fragmentflg, bundle_at; |
10065 | 0 | unsigned int mtu; |
10066 | 0 | int error, i, one_chunk, fwd_tsn, ctl_cnt, tmr_started; |
10067 | 0 | struct sctp_auth_chunk *auth = NULL; |
10068 | 0 | uint32_t auth_offset = 0; |
10069 | 0 | uint16_t auth_keyid; |
10070 | 0 | int override_ok = 1; |
10071 | 0 | int data_auth_reqd = 0; |
10072 | 0 | uint32_t dmtu = 0; |
10073 | 0 | bool use_zero_crc; |
10074 | |
|
10075 | | #if defined(__APPLE__) && !defined(__Userspace__) |
10076 | | if (so_locked) { |
10077 | | sctp_lock_assert(SCTP_INP_SO(inp)); |
10078 | | } else { |
10079 | | sctp_unlock_assert(SCTP_INP_SO(inp)); |
10080 | | } |
10081 | | #endif |
10082 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
10083 | 0 | tmr_started = ctl_cnt = 0; |
10084 | 0 | no_fragmentflg = 1; |
10085 | 0 | fwd_tsn = 0; |
10086 | 0 | *cnt_out = 0; |
10087 | 0 | fwd = NULL; |
10088 | 0 | endofchain = m = NULL; |
10089 | 0 | auth_keyid = stcb->asoc.authinfo.active_keyid; |
10090 | | #ifdef SCTP_AUDITING_ENABLED |
10091 | | sctp_audit_log(0xC3, 1); |
10092 | | #endif |
10093 | 0 | if ((TAILQ_EMPTY(&asoc->sent_queue)) && |
10094 | 0 | (TAILQ_EMPTY(&asoc->control_send_queue))) { |
10095 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1,"SCTP hits empty queue with cnt set to %d?\n", |
10096 | 0 | asoc->sent_queue_retran_cnt); |
10097 | 0 | asoc->sent_queue_cnt = 0; |
10098 | 0 | asoc->sent_queue_cnt_removeable = 0; |
10099 | | /* send back 0/0 so we enter normal transmission */ |
10100 | 0 | *cnt_out = 0; |
10101 | 0 | return (0); |
10102 | 0 | } |
10103 | 0 | TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { |
10104 | 0 | if ((chk->rec.chunk_id.id == SCTP_COOKIE_ECHO) || |
10105 | 0 | (chk->rec.chunk_id.id == SCTP_STREAM_RESET) || |
10106 | 0 | (chk->rec.chunk_id.id == SCTP_FORWARD_CUM_TSN)) { |
10107 | 0 | if (chk->sent != SCTP_DATAGRAM_RESEND) { |
10108 | 0 | continue; |
10109 | 0 | } |
10110 | 0 | if (chk->rec.chunk_id.id == SCTP_STREAM_RESET) { |
10111 | 0 | if (chk != asoc->str_reset) { |
10112 | | /* |
10113 | | * not eligible for retran if its |
10114 | | * not ours |
10115 | | */ |
10116 | 0 | continue; |
10117 | 0 | } |
10118 | 0 | } |
10119 | 0 | ctl_cnt++; |
10120 | 0 | if (chk->rec.chunk_id.id == SCTP_FORWARD_CUM_TSN) { |
10121 | 0 | fwd_tsn = 1; |
10122 | 0 | } |
10123 | | /* |
10124 | | * Add an AUTH chunk, if chunk requires it save the |
10125 | | * offset into the chain for AUTH |
10126 | | */ |
10127 | 0 | if ((auth == NULL) && |
10128 | 0 | (sctp_auth_is_required_chunk(chk->rec.chunk_id.id, |
10129 | 0 | stcb->asoc.peer_auth_chunks))) { |
10130 | 0 | m = sctp_add_auth_chunk(m, &endofchain, |
10131 | 0 | &auth, &auth_offset, |
10132 | 0 | stcb, |
10133 | 0 | chk->rec.chunk_id.id); |
10134 | 0 | SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); |
10135 | 0 | } |
10136 | 0 | m = sctp_copy_mbufchain(chk->data, m, &endofchain, 0, chk->send_size, chk->copy_by_ref); |
10137 | 0 | break; |
10138 | 0 | } |
10139 | 0 | } |
10140 | 0 | one_chunk = 0; |
10141 | | /* do we have control chunks to retransmit? */ |
10142 | 0 | if (m != NULL) { |
10143 | | /* Start a timer no matter if we succeed or fail */ |
10144 | 0 | switch (asoc->snd_edmid) { |
10145 | 0 | case SCTP_EDMID_LOWER_LAYER_DTLS: |
10146 | 0 | use_zero_crc = true; |
10147 | 0 | break; |
10148 | 0 | default: |
10149 | 0 | use_zero_crc = false; |
10150 | 0 | break; |
10151 | 0 | } |
10152 | 0 | if (chk->rec.chunk_id.id == SCTP_COOKIE_ECHO) { |
10153 | 0 | sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, chk->whoTo); |
10154 | 0 | use_zero_crc = false; |
10155 | 0 | } else if (chk->rec.chunk_id.id == SCTP_ASCONF) { |
10156 | | /* XXXMT: Can this happen? */ |
10157 | 0 | sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, stcb, chk->whoTo); |
10158 | 0 | use_zero_crc = false; |
10159 | 0 | } |
10160 | 0 | chk->snd_count++; /* update our count */ |
10161 | 0 | if ((error = sctp_lowlevel_chunk_output(inp, stcb, chk->whoTo, |
10162 | 0 | (struct sockaddr *)&chk->whoTo->ro._l_addr, m, |
10163 | 0 | auth_offset, auth, stcb->asoc.authinfo.active_keyid, |
10164 | 0 | no_fragmentflg, 0, 0, |
10165 | 0 | inp->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag), |
10166 | 0 | chk->whoTo->port, NULL, |
10167 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
10168 | | 0, 0, |
10169 | | #endif |
10170 | 0 | use_zero_crc, |
10171 | 0 | so_locked))) { |
10172 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); |
10173 | 0 | if (error == ENOBUFS) { |
10174 | 0 | asoc->ifp_had_enobuf = 1; |
10175 | 0 | SCTP_STAT_INCR(sctps_lowlevelerr); |
10176 | 0 | } |
10177 | 0 | return (error); |
10178 | 0 | } else { |
10179 | 0 | asoc->ifp_had_enobuf = 0; |
10180 | 0 | } |
10181 | 0 | endofchain = NULL; |
10182 | 0 | auth = NULL; |
10183 | 0 | auth_offset = 0; |
10184 | | /* |
10185 | | * We don't want to mark the net->sent time here since this |
10186 | | * we use this for HB and retrans cannot measure RTT |
10187 | | */ |
10188 | | /* (void)SCTP_GETTIME_TIMEVAL(&chk->whoTo->last_sent_time); */ |
10189 | 0 | *cnt_out += 1; |
10190 | 0 | chk->sent = SCTP_DATAGRAM_SENT; |
10191 | 0 | sctp_ucount_decr(stcb->asoc.sent_queue_retran_cnt); |
10192 | 0 | if (fwd_tsn == 0) { |
10193 | 0 | return (0); |
10194 | 0 | } else { |
10195 | | /* Clean up the fwd-tsn list */ |
10196 | 0 | sctp_clean_up_ctl(stcb, asoc, so_locked); |
10197 | 0 | return (0); |
10198 | 0 | } |
10199 | 0 | } |
10200 | | /* |
10201 | | * Ok, it is just data retransmission we need to do or that and a |
10202 | | * fwd-tsn with it all. |
10203 | | */ |
10204 | 0 | if (TAILQ_EMPTY(&asoc->sent_queue)) { |
10205 | 0 | return (SCTP_RETRAN_DONE); |
10206 | 0 | } |
10207 | 0 | if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED) || |
10208 | 0 | (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT)) { |
10209 | | /* not yet open, resend the cookie and that is it */ |
10210 | 0 | return (1); |
10211 | 0 | } |
10212 | | #ifdef SCTP_AUDITING_ENABLED |
10213 | | sctp_auditing(20, inp, stcb, NULL); |
10214 | | #endif |
10215 | 0 | data_auth_reqd = sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks); |
10216 | 0 | TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { |
10217 | 0 | if (chk->sent != SCTP_DATAGRAM_RESEND) { |
10218 | | /* No, not sent to this net or not ready for rtx */ |
10219 | 0 | continue; |
10220 | 0 | } |
10221 | 0 | if (chk->data == NULL) { |
10222 | 0 | SCTP_PRINTF("TSN:%x chk->snd_count:%d chk->sent:%d can't retran - no data\n", |
10223 | 0 | chk->rec.data.tsn, chk->snd_count, chk->sent); |
10224 | 0 | continue; |
10225 | 0 | } |
10226 | 0 | if ((SCTP_BASE_SYSCTL(sctp_max_retran_chunk)) && |
10227 | 0 | (chk->snd_count >= SCTP_BASE_SYSCTL(sctp_max_retran_chunk))) { |
10228 | 0 | struct mbuf *op_err; |
10229 | 0 | char msg[SCTP_DIAG_INFO_LEN]; |
10230 | |
|
10231 | 0 | SCTP_SNPRINTF(msg, sizeof(msg), "TSN %8.8x retransmitted %d times, giving up", |
10232 | 0 | chk->rec.data.tsn, chk->snd_count); |
10233 | 0 | op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), |
10234 | 0 | msg); |
10235 | 0 | atomic_add_int(&stcb->asoc.refcnt, 1); |
10236 | 0 | sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, |
10237 | 0 | false, so_locked); |
10238 | 0 | SCTP_TCB_LOCK(stcb); |
10239 | 0 | atomic_subtract_int(&stcb->asoc.refcnt, 1); |
10240 | 0 | return (SCTP_RETRAN_EXIT); |
10241 | 0 | } |
10242 | | /* pick up the net */ |
10243 | 0 | net = chk->whoTo; |
10244 | 0 | switch (net->ro._l_addr.sa.sa_family) { |
10245 | 0 | #ifdef INET |
10246 | 0 | case AF_INET: |
10247 | 0 | mtu = net->mtu - SCTP_MIN_V4_OVERHEAD; |
10248 | 0 | break; |
10249 | 0 | #endif |
10250 | 0 | #ifdef INET6 |
10251 | 0 | case AF_INET6: |
10252 | 0 | mtu = net->mtu - SCTP_MIN_OVERHEAD; |
10253 | 0 | break; |
10254 | 0 | #endif |
10255 | 0 | #if defined(__Userspace__) |
10256 | 0 | case AF_CONN: |
10257 | 0 | mtu = net->mtu - sizeof(struct sctphdr); |
10258 | 0 | break; |
10259 | 0 | #endif |
10260 | 0 | default: |
10261 | | /* TSNH */ |
10262 | 0 | mtu = net->mtu; |
10263 | 0 | break; |
10264 | 0 | } |
10265 | | |
10266 | 0 | if ((asoc->peers_rwnd < mtu) && (asoc->total_flight > 0)) { |
10267 | | /* No room in peers rwnd */ |
10268 | 0 | uint32_t tsn; |
10269 | |
|
10270 | 0 | tsn = asoc->last_acked_seq + 1; |
10271 | 0 | if (tsn == chk->rec.data.tsn) { |
10272 | | /* |
10273 | | * we make a special exception for this |
10274 | | * case. The peer has no rwnd but is missing |
10275 | | * the lowest chunk.. which is probably what |
10276 | | * is holding up the rwnd. |
10277 | | */ |
10278 | 0 | goto one_chunk_around; |
10279 | 0 | } |
10280 | 0 | return (1); |
10281 | 0 | } |
10282 | 0 | one_chunk_around: |
10283 | 0 | if (asoc->peers_rwnd < mtu) { |
10284 | 0 | one_chunk = 1; |
10285 | 0 | if ((asoc->peers_rwnd == 0) && |
10286 | 0 | (asoc->total_flight == 0)) { |
10287 | 0 | chk->window_probe = 1; |
10288 | 0 | chk->whoTo->window_probe = 1; |
10289 | 0 | } |
10290 | 0 | } |
10291 | | #ifdef SCTP_AUDITING_ENABLED |
10292 | | sctp_audit_log(0xC3, 2); |
10293 | | #endif |
10294 | 0 | bundle_at = 0; |
10295 | 0 | m = NULL; |
10296 | 0 | net->fast_retran_ip = 0; |
10297 | 0 | if (chk->rec.data.doing_fast_retransmit == 0) { |
10298 | | /* |
10299 | | * if no FR in progress skip destination that have |
10300 | | * flight_size > cwnd. |
10301 | | */ |
10302 | 0 | if (net->flight_size >= net->cwnd) { |
10303 | 0 | continue; |
10304 | 0 | } |
10305 | 0 | } else { |
10306 | | /* |
10307 | | * Mark the destination net to have FR recovery |
10308 | | * limits put on it. |
10309 | | */ |
10310 | 0 | *fr_done = 1; |
10311 | 0 | net->fast_retran_ip = 1; |
10312 | 0 | } |
10313 | | |
10314 | | /* |
10315 | | * if no AUTH is yet included and this chunk requires it, |
10316 | | * make sure to account for it. We don't apply the size |
10317 | | * until the AUTH chunk is actually added below in case |
10318 | | * there is no room for this chunk. |
10319 | | */ |
10320 | 0 | if (data_auth_reqd && (auth == NULL)) { |
10321 | 0 | dmtu = sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); |
10322 | 0 | } else |
10323 | 0 | dmtu = 0; |
10324 | |
|
10325 | 0 | if ((chk->send_size <= (mtu - dmtu)) || |
10326 | 0 | (chk->flags & CHUNK_FLAGS_FRAGMENT_OK)) { |
10327 | | /* ok we will add this one */ |
10328 | 0 | if (data_auth_reqd) { |
10329 | 0 | if (auth == NULL) { |
10330 | 0 | m = sctp_add_auth_chunk(m, |
10331 | 0 | &endofchain, |
10332 | 0 | &auth, |
10333 | 0 | &auth_offset, |
10334 | 0 | stcb, |
10335 | 0 | SCTP_DATA); |
10336 | 0 | auth_keyid = chk->auth_keyid; |
10337 | 0 | override_ok = 0; |
10338 | 0 | SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); |
10339 | 0 | } else if (override_ok) { |
10340 | 0 | auth_keyid = chk->auth_keyid; |
10341 | 0 | override_ok = 0; |
10342 | 0 | } else if (chk->auth_keyid != auth_keyid) { |
10343 | | /* different keyid, so done bundling */ |
10344 | 0 | break; |
10345 | 0 | } |
10346 | 0 | } |
10347 | 0 | m = sctp_copy_mbufchain(chk->data, m, &endofchain, 0, chk->send_size, chk->copy_by_ref); |
10348 | 0 | if (m == NULL) { |
10349 | 0 | SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
10350 | 0 | return (ENOMEM); |
10351 | 0 | } |
10352 | | /* Do clear IP_DF ? */ |
10353 | 0 | if (chk->flags & CHUNK_FLAGS_FRAGMENT_OK) { |
10354 | 0 | no_fragmentflg = 0; |
10355 | 0 | } |
10356 | | /* update our MTU size */ |
10357 | 0 | if (mtu > (chk->send_size + dmtu)) |
10358 | 0 | mtu -= (chk->send_size + dmtu); |
10359 | 0 | else |
10360 | 0 | mtu = 0; |
10361 | 0 | data_list[bundle_at++] = chk; |
10362 | 0 | if (one_chunk && (asoc->total_flight <= 0)) { |
10363 | 0 | SCTP_STAT_INCR(sctps_windowprobed); |
10364 | 0 | } |
10365 | 0 | } |
10366 | 0 | if (one_chunk == 0) { |
10367 | | /* |
10368 | | * now are there anymore forward from chk to pick |
10369 | | * up? |
10370 | | */ |
10371 | 0 | for (fwd = TAILQ_NEXT(chk, sctp_next); fwd != NULL; fwd = TAILQ_NEXT(fwd, sctp_next)) { |
10372 | 0 | if (fwd->sent != SCTP_DATAGRAM_RESEND) { |
10373 | | /* Nope, not for retran */ |
10374 | 0 | continue; |
10375 | 0 | } |
10376 | 0 | if (fwd->whoTo != net) { |
10377 | | /* Nope, not the net in question */ |
10378 | 0 | continue; |
10379 | 0 | } |
10380 | 0 | if (data_auth_reqd && (auth == NULL)) { |
10381 | 0 | dmtu = sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); |
10382 | 0 | } else |
10383 | 0 | dmtu = 0; |
10384 | 0 | if (fwd->send_size <= (mtu - dmtu)) { |
10385 | 0 | if (data_auth_reqd) { |
10386 | 0 | if (auth == NULL) { |
10387 | 0 | m = sctp_add_auth_chunk(m, |
10388 | 0 | &endofchain, |
10389 | 0 | &auth, |
10390 | 0 | &auth_offset, |
10391 | 0 | stcb, |
10392 | 0 | SCTP_DATA); |
10393 | 0 | auth_keyid = fwd->auth_keyid; |
10394 | 0 | override_ok = 0; |
10395 | 0 | SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); |
10396 | 0 | } else if (override_ok) { |
10397 | 0 | auth_keyid = fwd->auth_keyid; |
10398 | 0 | override_ok = 0; |
10399 | 0 | } else if (fwd->auth_keyid != auth_keyid) { |
10400 | | /* different keyid, so done bundling */ |
10401 | 0 | break; |
10402 | 0 | } |
10403 | 0 | } |
10404 | 0 | m = sctp_copy_mbufchain(fwd->data, m, &endofchain, 0, fwd->send_size, fwd->copy_by_ref); |
10405 | 0 | if (m == NULL) { |
10406 | 0 | SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
10407 | 0 | return (ENOMEM); |
10408 | 0 | } |
10409 | | /* Do clear IP_DF ? */ |
10410 | 0 | if (fwd->flags & CHUNK_FLAGS_FRAGMENT_OK) { |
10411 | 0 | no_fragmentflg = 0; |
10412 | 0 | } |
10413 | | /* update our MTU size */ |
10414 | 0 | if (mtu > (fwd->send_size + dmtu)) |
10415 | 0 | mtu -= (fwd->send_size + dmtu); |
10416 | 0 | else |
10417 | 0 | mtu = 0; |
10418 | 0 | data_list[bundle_at++] = fwd; |
10419 | 0 | if (bundle_at >= SCTP_MAX_DATA_BUNDLING) { |
10420 | 0 | break; |
10421 | 0 | } |
10422 | 0 | } else { |
10423 | | /* can't fit so we are done */ |
10424 | 0 | break; |
10425 | 0 | } |
10426 | 0 | } |
10427 | 0 | } |
10428 | | /* Is there something to send for this destination? */ |
10429 | 0 | if (m) { |
10430 | | /* |
10431 | | * No matter if we fail/or succeed we should start a |
10432 | | * timer. A failure is like a lost IP packet :-) |
10433 | | */ |
10434 | 0 | if (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { |
10435 | | /* |
10436 | | * no timer running on this destination |
10437 | | * restart it. |
10438 | | */ |
10439 | 0 | sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); |
10440 | 0 | tmr_started = 1; |
10441 | 0 | } |
10442 | 0 | switch (asoc->snd_edmid) { |
10443 | 0 | case SCTP_EDMID_LOWER_LAYER_DTLS: |
10444 | 0 | use_zero_crc = true; |
10445 | 0 | break; |
10446 | 0 | default: |
10447 | 0 | use_zero_crc = false; |
10448 | 0 | break; |
10449 | 0 | } |
10450 | | /* Now lets send it, if there is anything to send :> */ |
10451 | 0 | if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, |
10452 | 0 | (struct sockaddr *)&net->ro._l_addr, m, |
10453 | 0 | auth_offset, auth, auth_keyid, |
10454 | 0 | no_fragmentflg, 0, 0, |
10455 | 0 | inp->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag), |
10456 | 0 | net->port, NULL, |
10457 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
10458 | | 0, 0, |
10459 | | #endif |
10460 | 0 | use_zero_crc, |
10461 | 0 | so_locked))) { |
10462 | | /* error, we could not output */ |
10463 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); |
10464 | 0 | if (error == ENOBUFS) { |
10465 | 0 | asoc->ifp_had_enobuf = 1; |
10466 | 0 | SCTP_STAT_INCR(sctps_lowlevelerr); |
10467 | 0 | } |
10468 | 0 | return (error); |
10469 | 0 | } else { |
10470 | 0 | asoc->ifp_had_enobuf = 0; |
10471 | 0 | } |
10472 | 0 | endofchain = NULL; |
10473 | 0 | auth = NULL; |
10474 | 0 | auth_offset = 0; |
10475 | | /* For HB's */ |
10476 | | /* |
10477 | | * We don't want to mark the net->sent time here |
10478 | | * since this we use this for HB and retrans cannot |
10479 | | * measure RTT |
10480 | | */ |
10481 | | /* (void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time); */ |
10482 | | |
10483 | | /* For auto-close */ |
10484 | 0 | if (*now_filled == 0) { |
10485 | 0 | (void)SCTP_GETTIME_TIMEVAL(&asoc->time_last_sent); |
10486 | 0 | *now = asoc->time_last_sent; |
10487 | 0 | *now_filled = 1; |
10488 | 0 | } else { |
10489 | 0 | asoc->time_last_sent = *now; |
10490 | 0 | } |
10491 | 0 | *cnt_out += bundle_at; |
10492 | | #ifdef SCTP_AUDITING_ENABLED |
10493 | | sctp_audit_log(0xC4, bundle_at); |
10494 | | #endif |
10495 | 0 | if (bundle_at) { |
10496 | 0 | tsns_sent = data_list[0]->rec.data.tsn; |
10497 | 0 | } |
10498 | 0 | for (i = 0; i < bundle_at; i++) { |
10499 | 0 | SCTP_STAT_INCR(sctps_sendretransdata); |
10500 | 0 | data_list[i]->sent = SCTP_DATAGRAM_SENT; |
10501 | | /* |
10502 | | * When we have a revoked data, and we |
10503 | | * retransmit it, then we clear the revoked |
10504 | | * flag since this flag dictates if we |
10505 | | * subtracted from the fs |
10506 | | */ |
10507 | 0 | if (data_list[i]->rec.data.chunk_was_revoked) { |
10508 | | /* Deflate the cwnd */ |
10509 | 0 | data_list[i]->whoTo->cwnd -= data_list[i]->book_size; |
10510 | 0 | data_list[i]->rec.data.chunk_was_revoked = 0; |
10511 | 0 | } |
10512 | 0 | data_list[i]->snd_count++; |
10513 | 0 | sctp_ucount_decr(asoc->sent_queue_retran_cnt); |
10514 | | /* record the time */ |
10515 | 0 | data_list[i]->sent_rcv_time = asoc->time_last_sent; |
10516 | 0 | if (data_list[i]->book_size_scale) { |
10517 | | /* |
10518 | | * need to double the book size on |
10519 | | * this one |
10520 | | */ |
10521 | 0 | data_list[i]->book_size_scale = 0; |
10522 | | /* Since we double the booksize, we must |
10523 | | * also double the output queue size, since this |
10524 | | * get shrunk when we free by this amount. |
10525 | | */ |
10526 | 0 | atomic_add_int(&((asoc)->total_output_queue_size), data_list[i]->book_size); |
10527 | 0 | data_list[i]->book_size *= 2; |
10528 | 0 | } else { |
10529 | 0 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_RWND_ENABLE) { |
10530 | 0 | sctp_log_rwnd(SCTP_DECREASE_PEER_RWND, |
10531 | 0 | asoc->peers_rwnd, data_list[i]->send_size, SCTP_BASE_SYSCTL(sctp_peer_chunk_oh)); |
10532 | 0 | } |
10533 | 0 | asoc->peers_rwnd = sctp_sbspace_sub(asoc->peers_rwnd, |
10534 | 0 | (uint32_t) (data_list[i]->send_size + |
10535 | 0 | SCTP_BASE_SYSCTL(sctp_peer_chunk_oh))); |
10536 | 0 | } |
10537 | 0 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { |
10538 | 0 | sctp_misc_ints(SCTP_FLIGHT_LOG_UP_RSND, |
10539 | 0 | data_list[i]->whoTo->flight_size, |
10540 | 0 | data_list[i]->book_size, |
10541 | 0 | (uint32_t)(uintptr_t)data_list[i]->whoTo, |
10542 | 0 | data_list[i]->rec.data.tsn); |
10543 | 0 | } |
10544 | 0 | sctp_flight_size_increase(data_list[i]); |
10545 | 0 | sctp_total_flight_increase(stcb, data_list[i]); |
10546 | 0 | if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { |
10547 | | /* SWS sender side engages */ |
10548 | 0 | asoc->peers_rwnd = 0; |
10549 | 0 | } |
10550 | 0 | if ((i == 0) && |
10551 | 0 | (data_list[i]->rec.data.doing_fast_retransmit)) { |
10552 | 0 | SCTP_STAT_INCR(sctps_sendfastretrans); |
10553 | 0 | if ((data_list[i] == TAILQ_FIRST(&asoc->sent_queue)) && |
10554 | 0 | (tmr_started == 0)) { |
10555 | | /*- |
10556 | | * ok we just fast-retrans'd |
10557 | | * the lowest TSN, i.e the |
10558 | | * first on the list. In |
10559 | | * this case we want to give |
10560 | | * some more time to get a |
10561 | | * SACK back without a |
10562 | | * t3-expiring. |
10563 | | */ |
10564 | 0 | sctp_timer_stop(SCTP_TIMER_TYPE_SEND, inp, stcb, net, |
10565 | 0 | SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_2); |
10566 | 0 | sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); |
10567 | 0 | } |
10568 | 0 | } |
10569 | 0 | } |
10570 | 0 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { |
10571 | 0 | sctp_log_cwnd(stcb, net, tsns_sent, SCTP_CWND_LOG_FROM_RESEND); |
10572 | 0 | } |
10573 | | #ifdef SCTP_AUDITING_ENABLED |
10574 | | sctp_auditing(21, inp, stcb, NULL); |
10575 | | #endif |
10576 | 0 | } else { |
10577 | | /* None will fit */ |
10578 | 0 | return (1); |
10579 | 0 | } |
10580 | 0 | if (asoc->sent_queue_retran_cnt <= 0) { |
10581 | | /* all done we have no more to retran */ |
10582 | 0 | asoc->sent_queue_retran_cnt = 0; |
10583 | 0 | break; |
10584 | 0 | } |
10585 | 0 | if (one_chunk) { |
10586 | | /* No more room in rwnd */ |
10587 | 0 | return (1); |
10588 | 0 | } |
10589 | | /* stop the for loop here. we sent out a packet */ |
10590 | 0 | break; |
10591 | 0 | } |
10592 | 0 | return (0); |
10593 | 0 | } |
10594 | | |
10595 | | static void |
10596 | | sctp_timer_validation(struct sctp_inpcb *inp, |
10597 | | struct sctp_tcb *stcb, |
10598 | | struct sctp_association *asoc) |
10599 | 0 | { |
10600 | 0 | struct sctp_nets *net; |
10601 | | |
10602 | | /* Validate that a timer is running somewhere */ |
10603 | 0 | TAILQ_FOREACH(net, &asoc->nets, sctp_next) { |
10604 | 0 | if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { |
10605 | | /* Here is a timer */ |
10606 | 0 | return; |
10607 | 0 | } |
10608 | 0 | } |
10609 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
10610 | | /* Gak, we did not have a timer somewhere */ |
10611 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "Deadlock avoided starting timer on a dest at retran\n"); |
10612 | 0 | if (asoc->alternate) { |
10613 | 0 | sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, asoc->alternate); |
10614 | 0 | } else { |
10615 | 0 | sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, asoc->primary_destination); |
10616 | 0 | } |
10617 | 0 | return; |
10618 | 0 | } |
10619 | | |
10620 | | void |
10621 | | sctp_chunk_output(struct sctp_inpcb *inp, |
10622 | | struct sctp_tcb *stcb, |
10623 | | int from_where, |
10624 | | int so_locked) |
10625 | 21.4k | { |
10626 | | /*- |
10627 | | * Ok this is the generic chunk service queue. we must do the |
10628 | | * following: |
10629 | | * - See if there are retransmits pending, if so we must |
10630 | | * do these first. |
10631 | | * - Service the stream queue that is next, moving any |
10632 | | * message (note I must get a complete message i.e. |
10633 | | * FIRST/MIDDLE and LAST to the out queue in one pass) and assigning |
10634 | | * TSN's |
10635 | | * - Check to see if the cwnd/rwnd allows any output, if so we |
10636 | | * go ahead and formulate and send the low level chunks. Making sure |
10637 | | * to combine any control in the control chunk queue also. |
10638 | | */ |
10639 | 21.4k | struct sctp_association *asoc; |
10640 | 21.4k | struct sctp_nets *net; |
10641 | 21.4k | int error = 0, num_out, tot_out = 0, ret = 0, reason_code; |
10642 | 21.4k | unsigned int burst_cnt = 0; |
10643 | 21.4k | struct timeval now; |
10644 | 21.4k | int now_filled = 0; |
10645 | 21.4k | int nagle_on; |
10646 | 21.4k | uint32_t frag_point = sctp_get_frag_point(stcb); |
10647 | 21.4k | int un_sent = 0; |
10648 | 21.4k | int fr_done; |
10649 | 21.4k | unsigned int tot_frs = 0; |
10650 | | |
10651 | | #if defined(__APPLE__) && !defined(__Userspace__) |
10652 | | if (so_locked) { |
10653 | | sctp_lock_assert(SCTP_INP_SO(inp)); |
10654 | | } else { |
10655 | | sctp_unlock_assert(SCTP_INP_SO(inp)); |
10656 | | } |
10657 | | #endif |
10658 | 21.4k | asoc = &stcb->asoc; |
10659 | 21.4k | do_it_again: |
10660 | | /* The Nagle algorithm is only applied when handling a send call. */ |
10661 | 21.4k | if (from_where == SCTP_OUTPUT_FROM_USR_SEND) { |
10662 | 18.0k | if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY)) { |
10663 | 18.0k | nagle_on = 0; |
10664 | 18.0k | } else { |
10665 | 0 | nagle_on = 1; |
10666 | 0 | } |
10667 | 18.0k | } else { |
10668 | 3.40k | nagle_on = 0; |
10669 | 3.40k | } |
10670 | 21.4k | SCTP_TCB_LOCK_ASSERT(stcb); |
10671 | | |
10672 | 21.4k | un_sent = (stcb->asoc.total_output_queue_size - stcb->asoc.total_flight); |
10673 | | |
10674 | 21.4k | if ((un_sent <= 0) && |
10675 | 3.21k | (TAILQ_EMPTY(&asoc->control_send_queue)) && |
10676 | 0 | (TAILQ_EMPTY(&asoc->asconf_send_queue)) && |
10677 | 0 | (asoc->sent_queue_retran_cnt == 0) && |
10678 | 0 | (asoc->trigger_reset == 0)) { |
10679 | | /* Nothing to do unless there is something to be sent left */ |
10680 | 0 | return; |
10681 | 0 | } |
10682 | | /* Do we have something to send, data or control AND |
10683 | | * a sack timer running, if so piggy-back the sack. |
10684 | | */ |
10685 | 21.4k | if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) { |
10686 | 0 | sctp_send_sack(stcb, so_locked); |
10687 | 0 | sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, |
10688 | 0 | SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_3); |
10689 | 0 | } |
10690 | 21.4k | while (asoc->sent_queue_retran_cnt) { |
10691 | | /*- |
10692 | | * Ok, it is retransmission time only, we send out only ONE |
10693 | | * packet with a single call off to the retran code. |
10694 | | */ |
10695 | 0 | if (from_where == SCTP_OUTPUT_FROM_COOKIE_ACK) { |
10696 | | /*- |
10697 | | * Special hook for handling cookies discarded |
10698 | | * by peer that carried data. Send cookie-ack only |
10699 | | * and then the next call with get the retran's. |
10700 | | */ |
10701 | 0 | (void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1, |
10702 | 0 | from_where, |
10703 | 0 | &now, &now_filled, frag_point, so_locked); |
10704 | 0 | return; |
10705 | 0 | } else if (from_where != SCTP_OUTPUT_FROM_HB_TMR) { |
10706 | | /* if its not from a HB then do it */ |
10707 | 0 | fr_done = 0; |
10708 | 0 | ret = sctp_chunk_retransmission(inp, stcb, asoc, &num_out, &now, &now_filled, &fr_done, so_locked); |
10709 | 0 | if (fr_done) { |
10710 | 0 | tot_frs++; |
10711 | 0 | } |
10712 | 0 | } else { |
10713 | | /* |
10714 | | * its from any other place, we don't allow retran |
10715 | | * output (only control) |
10716 | | */ |
10717 | 0 | ret = 1; |
10718 | 0 | } |
10719 | 0 | if (ret > 0) { |
10720 | | /* Can't send anymore */ |
10721 | | /*- |
10722 | | * now lets push out control by calling med-level |
10723 | | * output once. this assures that we WILL send HB's |
10724 | | * if queued too. |
10725 | | */ |
10726 | 0 | (void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1, |
10727 | 0 | from_where, |
10728 | 0 | &now, &now_filled, frag_point, so_locked); |
10729 | | #ifdef SCTP_AUDITING_ENABLED |
10730 | | sctp_auditing(8, inp, stcb, NULL); |
10731 | | #endif |
10732 | 0 | sctp_timer_validation(inp, stcb, asoc); |
10733 | 0 | return; |
10734 | 0 | } |
10735 | 0 | if (ret < 0) { |
10736 | | /*- |
10737 | | * The count was off.. retran is not happening so do |
10738 | | * the normal retransmission. |
10739 | | */ |
10740 | | #ifdef SCTP_AUDITING_ENABLED |
10741 | | sctp_auditing(9, inp, stcb, NULL); |
10742 | | #endif |
10743 | 0 | if (ret == SCTP_RETRAN_EXIT) { |
10744 | 0 | return; |
10745 | 0 | } |
10746 | 0 | break; |
10747 | 0 | } |
10748 | 0 | if (from_where == SCTP_OUTPUT_FROM_T3) { |
10749 | | /* Only one transmission allowed out of a timeout */ |
10750 | | #ifdef SCTP_AUDITING_ENABLED |
10751 | | sctp_auditing(10, inp, stcb, NULL); |
10752 | | #endif |
10753 | | /* Push out any control */ |
10754 | 0 | (void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1, from_where, |
10755 | 0 | &now, &now_filled, frag_point, so_locked); |
10756 | 0 | return; |
10757 | 0 | } |
10758 | 0 | if ((asoc->fr_max_burst > 0) && (tot_frs >= asoc->fr_max_burst)) { |
10759 | | /* Hit FR burst limit */ |
10760 | 0 | return; |
10761 | 0 | } |
10762 | 0 | if ((num_out == 0) && (ret == 0)) { |
10763 | | /* No more retrans to send */ |
10764 | 0 | break; |
10765 | 0 | } |
10766 | 0 | } |
10767 | | #ifdef SCTP_AUDITING_ENABLED |
10768 | | sctp_auditing(12, inp, stcb, NULL); |
10769 | | #endif |
10770 | | /* Check for bad destinations, if they exist move chunks around. */ |
10771 | 21.4k | TAILQ_FOREACH(net, &asoc->nets, sctp_next) { |
10772 | 21.4k | if ((net->dest_state & SCTP_ADDR_REACHABLE) == 0) { |
10773 | | /*- |
10774 | | * if possible move things off of this address we |
10775 | | * still may send below due to the dormant state but |
10776 | | * we try to find an alternate address to send to |
10777 | | * and if we have one we move all queued data on the |
10778 | | * out wheel to this alternate address. |
10779 | | */ |
10780 | 0 | if (net->ref_count > 1) |
10781 | 0 | sctp_move_chunks_from_net(stcb, net); |
10782 | 21.4k | } else { |
10783 | | /*- |
10784 | | * if ((asoc->sat_network) || (net->addr_is_local)) |
10785 | | * { burst_limit = asoc->max_burst * |
10786 | | * SCTP_SAT_NETWORK_BURST_INCR; } |
10787 | | */ |
10788 | 21.4k | if (asoc->max_burst > 0) { |
10789 | 21.4k | if (SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst)) { |
10790 | 21.4k | if ((net->flight_size + (asoc->max_burst * net->mtu)) < net->cwnd) { |
10791 | | /* JRS - Use the congestion control given in the congestion control module */ |
10792 | 0 | asoc->cc_functions.sctp_cwnd_update_after_output(stcb, net, asoc->max_burst); |
10793 | 0 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_MAXBURST_ENABLE) { |
10794 | 0 | sctp_log_maxburst(stcb, net, 0, asoc->max_burst, SCTP_MAX_BURST_APPLIED); |
10795 | 0 | } |
10796 | 0 | SCTP_STAT_INCR(sctps_maxburstqueued); |
10797 | 0 | } |
10798 | 21.4k | net->fast_retran_ip = 0; |
10799 | 21.4k | } else { |
10800 | 0 | if (net->flight_size == 0) { |
10801 | | /* Should be decaying the cwnd here */ |
10802 | 0 | ; |
10803 | 0 | } |
10804 | 0 | } |
10805 | 21.4k | } |
10806 | 21.4k | } |
10807 | 21.4k | } |
10808 | 21.4k | burst_cnt = 0; |
10809 | 25.7k | do { |
10810 | 25.7k | error = sctp_med_chunk_output(inp, stcb, asoc, &num_out, |
10811 | 25.7k | &reason_code, 0, from_where, |
10812 | 25.7k | &now, &now_filled, frag_point, so_locked); |
10813 | 25.7k | if (error) { |
10814 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Error %d was returned from med-c-op\n", error); |
10815 | 0 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_MAXBURST_ENABLE) { |
10816 | 0 | sctp_log_maxburst(stcb, asoc->primary_destination, error, burst_cnt, SCTP_MAX_BURST_ERROR_STOP); |
10817 | 0 | } |
10818 | 0 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { |
10819 | 0 | sctp_log_cwnd(stcb, NULL, error, SCTP_SEND_NOW_COMPLETES); |
10820 | 0 | sctp_log_cwnd(stcb, NULL, 0xdeadbeef, SCTP_SEND_NOW_COMPLETES); |
10821 | 0 | } |
10822 | 0 | break; |
10823 | 0 | } |
10824 | 25.7k | SCTPDBG(SCTP_DEBUG_OUTPUT3, "m-c-o put out %d\n", num_out); |
10825 | | |
10826 | 25.7k | tot_out += num_out; |
10827 | 25.7k | burst_cnt++; |
10828 | 25.7k | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { |
10829 | 0 | sctp_log_cwnd(stcb, NULL, num_out, SCTP_SEND_NOW_COMPLETES); |
10830 | 0 | if (num_out == 0) { |
10831 | 0 | sctp_log_cwnd(stcb, NULL, reason_code, SCTP_SEND_NOW_COMPLETES); |
10832 | 0 | } |
10833 | 0 | } |
10834 | 25.7k | if (nagle_on) { |
10835 | | /* |
10836 | | * When the Nagle algorithm is used, look at how much |
10837 | | * is unsent, then if its smaller than an MTU and we |
10838 | | * have data in flight we stop, except if we are |
10839 | | * handling a fragmented user message. |
10840 | | */ |
10841 | 0 | un_sent = stcb->asoc.total_output_queue_size - stcb->asoc.total_flight; |
10842 | 0 | if ((un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD)) && |
10843 | 0 | (stcb->asoc.total_flight > 0)) { |
10844 | | /* && sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR))) {*/ |
10845 | 0 | break; |
10846 | 0 | } |
10847 | 0 | } |
10848 | 25.7k | if (TAILQ_EMPTY(&asoc->control_send_queue) && |
10849 | 25.7k | TAILQ_EMPTY(&asoc->send_queue) && |
10850 | 22.5k | sctp_is_there_unsent_data(stcb, so_locked) == 0) { |
10851 | | /* Nothing left to send */ |
10852 | 1 | break; |
10853 | 1 | } |
10854 | 25.7k | if ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) <= 0) { |
10855 | | /* Nothing left to send */ |
10856 | 3.21k | break; |
10857 | 3.21k | } |
10858 | 25.7k | } while (num_out && |
10859 | 4.32k | ((asoc->max_burst == 0) || |
10860 | 4.32k | SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst) || |
10861 | 0 | (burst_cnt < asoc->max_burst))); |
10862 | | |
10863 | 21.4k | if (SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst) == 0) { |
10864 | 0 | if ((asoc->max_burst > 0) && (burst_cnt >= asoc->max_burst)) { |
10865 | 0 | SCTP_STAT_INCR(sctps_maxburstqueued); |
10866 | 0 | asoc->burst_limit_applied = 1; |
10867 | 0 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_MAXBURST_ENABLE) { |
10868 | 0 | sctp_log_maxburst(stcb, asoc->primary_destination, 0, burst_cnt, SCTP_MAX_BURST_APPLIED); |
10869 | 0 | } |
10870 | 0 | } else { |
10871 | 0 | asoc->burst_limit_applied = 0; |
10872 | 0 | } |
10873 | 0 | } |
10874 | 21.4k | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { |
10875 | 0 | sctp_log_cwnd(stcb, NULL, tot_out, SCTP_SEND_NOW_COMPLETES); |
10876 | 0 | } |
10877 | 21.4k | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Ok, we have put out %d chunks\n", |
10878 | 21.4k | tot_out); |
10879 | | |
10880 | | /*- |
10881 | | * Now we need to clean up the control chunk chain if a ECNE is on |
10882 | | * it. It must be marked as UNSENT again so next call will continue |
10883 | | * to send it until such time that we get a CWR, to remove it. |
10884 | | */ |
10885 | 21.4k | if (stcb->asoc.ecn_echo_cnt_onq) |
10886 | 0 | sctp_fix_ecn_echo(asoc); |
10887 | | |
10888 | 21.4k | if (stcb->asoc.trigger_reset) { |
10889 | 0 | if (sctp_send_stream_reset_out_if_possible(stcb, so_locked) == 0) { |
10890 | 0 | goto do_it_again; |
10891 | 0 | } |
10892 | 0 | } |
10893 | 21.4k | return; |
10894 | 21.4k | } |
10895 | | |
10896 | | int |
10897 | | sctp_output( |
10898 | | struct sctp_inpcb *inp, |
10899 | | struct mbuf *m, |
10900 | | struct sockaddr *addr, |
10901 | | struct mbuf *control, |
10902 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
10903 | | struct thread *p, |
10904 | | #elif defined(_WIN32) && !defined(__Userspace__) |
10905 | | PKTHREAD p, |
10906 | | #else |
10907 | | #if defined(__APPLE__) && !defined(__Userspace__) |
10908 | | struct proc *p SCTP_UNUSED, |
10909 | | #else |
10910 | | struct proc *p, |
10911 | | #endif |
10912 | | #endif |
10913 | | int flags) |
10914 | 0 | { |
10915 | 0 | if (inp == NULL) { |
10916 | 0 | SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL); |
10917 | 0 | return (EINVAL); |
10918 | 0 | } |
10919 | | |
10920 | 0 | if (inp->sctp_socket == NULL) { |
10921 | 0 | SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL); |
10922 | 0 | return (EINVAL); |
10923 | 0 | } |
10924 | 0 | return (sctp_sosend(inp->sctp_socket, |
10925 | 0 | addr, |
10926 | 0 | (struct uio *)NULL, |
10927 | 0 | m, |
10928 | 0 | control, |
10929 | | #if defined(__APPLE__) && !defined(__Userspace__) |
10930 | | flags |
10931 | | #else |
10932 | 0 | flags, p |
10933 | 0 | #endif |
10934 | 0 | )); |
10935 | 0 | } |
10936 | | |
10937 | | void |
10938 | | send_forward_tsn(struct sctp_tcb *stcb, |
10939 | | struct sctp_association *asoc) |
10940 | 0 | { |
10941 | 0 | struct sctp_tmit_chunk *chk, *at, *tp1, *last; |
10942 | 0 | struct sctp_forward_tsn_chunk *fwdtsn; |
10943 | 0 | struct sctp_strseq *strseq; |
10944 | 0 | struct sctp_strseq_mid *strseq_m; |
10945 | 0 | uint32_t advance_peer_ack_point; |
10946 | 0 | unsigned int cnt_of_space, i, ovh; |
10947 | 0 | unsigned int space_needed; |
10948 | 0 | unsigned int cnt_of_skipped = 0; |
10949 | |
|
10950 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
10951 | 0 | TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { |
10952 | 0 | if (chk->rec.chunk_id.id == SCTP_FORWARD_CUM_TSN) { |
10953 | | /* mark it to unsent */ |
10954 | 0 | chk->sent = SCTP_DATAGRAM_UNSENT; |
10955 | 0 | chk->snd_count = 0; |
10956 | | /* Do we correct its output location? */ |
10957 | 0 | if (chk->whoTo) { |
10958 | 0 | sctp_free_remote_addr(chk->whoTo); |
10959 | 0 | chk->whoTo = NULL; |
10960 | 0 | } |
10961 | 0 | goto sctp_fill_in_rest; |
10962 | 0 | } |
10963 | 0 | } |
10964 | | /* Ok if we reach here we must build one */ |
10965 | 0 | sctp_alloc_a_chunk(stcb, chk); |
10966 | 0 | if (chk == NULL) { |
10967 | 0 | return; |
10968 | 0 | } |
10969 | 0 | asoc->fwd_tsn_cnt++; |
10970 | 0 | chk->copy_by_ref = 0; |
10971 | | /* |
10972 | | * We don't do the old thing here since |
10973 | | * this is used not for on-wire but to |
10974 | | * tell if we are sending a fwd-tsn by |
10975 | | * the stack during output. And if its |
10976 | | * a IFORWARD or a FORWARD it is a fwd-tsn. |
10977 | | */ |
10978 | 0 | chk->rec.chunk_id.id = SCTP_FORWARD_CUM_TSN; |
10979 | 0 | chk->rec.chunk_id.can_take_data = 0; |
10980 | 0 | chk->flags = 0; |
10981 | 0 | chk->asoc = asoc; |
10982 | 0 | chk->whoTo = NULL; |
10983 | 0 | chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); |
10984 | 0 | if (chk->data == NULL) { |
10985 | 0 | sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); |
10986 | 0 | return; |
10987 | 0 | } |
10988 | 0 | SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); |
10989 | 0 | chk->sent = SCTP_DATAGRAM_UNSENT; |
10990 | 0 | chk->snd_count = 0; |
10991 | 0 | TAILQ_INSERT_TAIL(&asoc->control_send_queue, chk, sctp_next); |
10992 | 0 | asoc->ctrl_queue_cnt++; |
10993 | 0 | sctp_fill_in_rest: |
10994 | | /*- |
10995 | | * Here we go through and fill out the part that deals with |
10996 | | * stream/seq of the ones we skip. |
10997 | | */ |
10998 | 0 | SCTP_BUF_LEN(chk->data) = 0; |
10999 | 0 | TAILQ_FOREACH(at, &asoc->sent_queue, sctp_next) { |
11000 | 0 | if ((at->sent != SCTP_FORWARD_TSN_SKIP) && |
11001 | 0 | (at->sent != SCTP_DATAGRAM_NR_ACKED)) { |
11002 | | /* no more to look at */ |
11003 | 0 | break; |
11004 | 0 | } |
11005 | 0 | if (!asoc->idata_supported && (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED)) { |
11006 | | /* We don't report these */ |
11007 | 0 | continue; |
11008 | 0 | } |
11009 | 0 | cnt_of_skipped++; |
11010 | 0 | } |
11011 | 0 | if (asoc->idata_supported) { |
11012 | 0 | space_needed = (sizeof(struct sctp_forward_tsn_chunk) + |
11013 | 0 | (cnt_of_skipped * sizeof(struct sctp_strseq_mid))); |
11014 | 0 | } else { |
11015 | 0 | space_needed = (sizeof(struct sctp_forward_tsn_chunk) + |
11016 | 0 | (cnt_of_skipped * sizeof(struct sctp_strseq))); |
11017 | 0 | } |
11018 | 0 | cnt_of_space = (unsigned int)M_TRAILINGSPACE(chk->data); |
11019 | |
|
11020 | 0 | if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { |
11021 | 0 | ovh = SCTP_MIN_OVERHEAD; |
11022 | 0 | } else { |
11023 | 0 | ovh = SCTP_MIN_V4_OVERHEAD; |
11024 | 0 | } |
11025 | 0 | if (cnt_of_space > (asoc->smallest_mtu - ovh)) { |
11026 | | /* trim to a mtu size */ |
11027 | 0 | cnt_of_space = asoc->smallest_mtu - ovh; |
11028 | 0 | } |
11029 | 0 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) { |
11030 | 0 | sctp_misc_ints(SCTP_FWD_TSN_CHECK, |
11031 | 0 | 0xff, 0, cnt_of_skipped, |
11032 | 0 | asoc->advanced_peer_ack_point); |
11033 | 0 | } |
11034 | 0 | advance_peer_ack_point = asoc->advanced_peer_ack_point; |
11035 | 0 | if (cnt_of_space < space_needed) { |
11036 | | /*- |
11037 | | * ok we must trim down the chunk by lowering the |
11038 | | * advance peer ack point. |
11039 | | */ |
11040 | 0 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) { |
11041 | 0 | sctp_misc_ints(SCTP_FWD_TSN_CHECK, |
11042 | 0 | 0xff, 0xff, cnt_of_space, |
11043 | 0 | space_needed); |
11044 | 0 | } |
11045 | 0 | cnt_of_skipped = cnt_of_space - sizeof(struct sctp_forward_tsn_chunk); |
11046 | 0 | if (asoc->idata_supported) { |
11047 | 0 | cnt_of_skipped /= sizeof(struct sctp_strseq_mid); |
11048 | 0 | } else { |
11049 | 0 | cnt_of_skipped /= sizeof(struct sctp_strseq); |
11050 | 0 | } |
11051 | | /*- |
11052 | | * Go through and find the TSN that will be the one |
11053 | | * we report. |
11054 | | */ |
11055 | 0 | at = TAILQ_FIRST(&asoc->sent_queue); |
11056 | 0 | if (at != NULL) { |
11057 | 0 | for (i = 0; i < cnt_of_skipped; i++) { |
11058 | 0 | tp1 = TAILQ_NEXT(at, sctp_next); |
11059 | 0 | if (tp1 == NULL) { |
11060 | 0 | break; |
11061 | 0 | } |
11062 | 0 | at = tp1; |
11063 | 0 | } |
11064 | 0 | } |
11065 | 0 | if (at && SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) { |
11066 | 0 | sctp_misc_ints(SCTP_FWD_TSN_CHECK, |
11067 | 0 | 0xff, cnt_of_skipped, at->rec.data.tsn, |
11068 | 0 | asoc->advanced_peer_ack_point); |
11069 | 0 | } |
11070 | 0 | last = at; |
11071 | | /*- |
11072 | | * last now points to last one I can report, update |
11073 | | * peer ack point |
11074 | | */ |
11075 | 0 | if (last) { |
11076 | 0 | advance_peer_ack_point = last->rec.data.tsn; |
11077 | 0 | } |
11078 | 0 | if (asoc->idata_supported) { |
11079 | 0 | space_needed = sizeof(struct sctp_forward_tsn_chunk) + |
11080 | 0 | cnt_of_skipped * sizeof(struct sctp_strseq_mid); |
11081 | 0 | } else { |
11082 | 0 | space_needed = sizeof(struct sctp_forward_tsn_chunk) + |
11083 | 0 | cnt_of_skipped * sizeof(struct sctp_strseq); |
11084 | 0 | } |
11085 | 0 | } |
11086 | 0 | chk->send_size = space_needed; |
11087 | | /* Setup the chunk */ |
11088 | 0 | fwdtsn = mtod(chk->data, struct sctp_forward_tsn_chunk *); |
11089 | 0 | fwdtsn->ch.chunk_length = htons(chk->send_size); |
11090 | 0 | fwdtsn->ch.chunk_flags = 0; |
11091 | 0 | if (asoc->idata_supported) { |
11092 | 0 | fwdtsn->ch.chunk_type = SCTP_IFORWARD_CUM_TSN; |
11093 | 0 | } else { |
11094 | 0 | fwdtsn->ch.chunk_type = SCTP_FORWARD_CUM_TSN; |
11095 | 0 | } |
11096 | 0 | fwdtsn->new_cumulative_tsn = htonl(advance_peer_ack_point); |
11097 | 0 | SCTP_BUF_LEN(chk->data) = chk->send_size; |
11098 | 0 | fwdtsn++; |
11099 | | /*- |
11100 | | * Move pointer to after the fwdtsn and transfer to the |
11101 | | * strseq pointer. |
11102 | | */ |
11103 | 0 | if (asoc->idata_supported) { |
11104 | 0 | strseq_m = (struct sctp_strseq_mid *)fwdtsn; |
11105 | 0 | strseq = NULL; |
11106 | 0 | } else { |
11107 | 0 | strseq = (struct sctp_strseq *)fwdtsn; |
11108 | 0 | strseq_m = NULL; |
11109 | 0 | } |
11110 | | /*- |
11111 | | * Now populate the strseq list. This is done blindly |
11112 | | * without pulling out duplicate stream info. This is |
11113 | | * inefficient but won't harm the process since the peer will |
11114 | | * look at these in sequence and will thus release anything. |
11115 | | * It could mean we exceed the PMTU and chop off some that |
11116 | | * we could have included.. but this is unlikely (aka 1432/4 |
11117 | | * would mean 300+ stream seq's would have to be reported in |
11118 | | * one FWD-TSN. With a bit of work we can later FIX this to |
11119 | | * optimize and pull out duplicates.. but it does add more |
11120 | | * overhead. So for now... not! |
11121 | | */ |
11122 | 0 | i = 0; |
11123 | 0 | TAILQ_FOREACH(at, &asoc->sent_queue, sctp_next) { |
11124 | 0 | if (i >= cnt_of_skipped) { |
11125 | 0 | break; |
11126 | 0 | } |
11127 | 0 | if (!asoc->idata_supported && (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED)) { |
11128 | | /* We don't report these */ |
11129 | 0 | continue; |
11130 | 0 | } |
11131 | 0 | if (at->rec.data.tsn == advance_peer_ack_point) { |
11132 | 0 | at->rec.data.fwd_tsn_cnt = 0; |
11133 | 0 | } |
11134 | 0 | if (asoc->idata_supported) { |
11135 | 0 | strseq_m->sid = htons(at->rec.data.sid); |
11136 | 0 | if (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED) { |
11137 | 0 | strseq_m->flags = htons(PR_SCTP_UNORDERED_FLAG); |
11138 | 0 | } else { |
11139 | 0 | strseq_m->flags = 0; |
11140 | 0 | } |
11141 | 0 | strseq_m->mid = htonl(at->rec.data.mid); |
11142 | 0 | strseq_m++; |
11143 | 0 | } else { |
11144 | 0 | strseq->sid = htons(at->rec.data.sid); |
11145 | 0 | strseq->ssn = htons((uint16_t)at->rec.data.mid); |
11146 | 0 | strseq++; |
11147 | 0 | } |
11148 | 0 | i++; |
11149 | 0 | } |
11150 | 0 | return; |
11151 | 0 | } |
11152 | | |
11153 | | void |
11154 | | sctp_send_sack(struct sctp_tcb *stcb, int so_locked) |
11155 | 1 | { |
11156 | | /*- |
11157 | | * Queue up a SACK or NR-SACK in the control queue. |
11158 | | * We must first check to see if a SACK or NR-SACK is |
11159 | | * somehow on the control queue. |
11160 | | * If so, we will take and and remove the old one. |
11161 | | */ |
11162 | 1 | struct sctp_association *asoc; |
11163 | 1 | struct sctp_tmit_chunk *chk, *a_chk; |
11164 | 1 | struct sctp_sack_chunk *sack; |
11165 | 1 | struct sctp_nr_sack_chunk *nr_sack; |
11166 | 1 | struct sctp_gap_ack_block *gap_descriptor; |
11167 | 1 | const struct sack_track *selector; |
11168 | 1 | int mergeable = 0; |
11169 | 1 | int offset; |
11170 | 1 | caddr_t limit; |
11171 | 1 | uint32_t *dup; |
11172 | 1 | int limit_reached = 0; |
11173 | 1 | unsigned int i, siz, j; |
11174 | 1 | unsigned int num_gap_blocks = 0, num_nr_gap_blocks = 0, space; |
11175 | 1 | int num_dups = 0; |
11176 | 1 | int space_req; |
11177 | 1 | uint32_t highest_tsn; |
11178 | 1 | uint8_t flags; |
11179 | 1 | uint8_t type; |
11180 | 1 | uint8_t tsn_map; |
11181 | | |
11182 | 1 | if (stcb->asoc.nrsack_supported == 1) { |
11183 | 0 | type = SCTP_NR_SELECTIVE_ACK; |
11184 | 1 | } else { |
11185 | 1 | type = SCTP_SELECTIVE_ACK; |
11186 | 1 | } |
11187 | 1 | a_chk = NULL; |
11188 | 1 | asoc = &stcb->asoc; |
11189 | 1 | SCTP_TCB_LOCK_ASSERT(stcb); |
11190 | 1 | if (asoc->last_data_chunk_from == NULL) { |
11191 | | /* Hmm we never received anything */ |
11192 | 0 | return; |
11193 | 0 | } |
11194 | 1 | sctp_slide_mapping_arrays(stcb); |
11195 | 1 | sctp_set_rwnd(stcb, asoc); |
11196 | 1 | TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { |
11197 | 0 | if (chk->rec.chunk_id.id == type) { |
11198 | | /* Hmm, found a sack already on queue, remove it */ |
11199 | 0 | TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next); |
11200 | 0 | asoc->ctrl_queue_cnt--; |
11201 | 0 | a_chk = chk; |
11202 | 0 | if (a_chk->data) { |
11203 | 0 | sctp_m_freem(a_chk->data); |
11204 | 0 | a_chk->data = NULL; |
11205 | 0 | } |
11206 | 0 | if (a_chk->whoTo) { |
11207 | 0 | sctp_free_remote_addr(a_chk->whoTo); |
11208 | 0 | a_chk->whoTo = NULL; |
11209 | 0 | } |
11210 | 0 | break; |
11211 | 0 | } |
11212 | 0 | } |
11213 | 1 | if (a_chk == NULL) { |
11214 | 1 | sctp_alloc_a_chunk(stcb, a_chk); |
11215 | 1 | if (a_chk == NULL) { |
11216 | | /* No memory so we drop the idea, and set a timer */ |
11217 | 0 | if (stcb->asoc.delayed_ack) { |
11218 | 0 | sctp_timer_stop(SCTP_TIMER_TYPE_RECV, |
11219 | 0 | stcb->sctp_ep, stcb, NULL, |
11220 | 0 | SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_4); |
11221 | 0 | sctp_timer_start(SCTP_TIMER_TYPE_RECV, |
11222 | 0 | stcb->sctp_ep, stcb, NULL); |
11223 | 0 | } else { |
11224 | 0 | stcb->asoc.send_sack = 1; |
11225 | 0 | } |
11226 | 0 | return; |
11227 | 0 | } |
11228 | 1 | a_chk->copy_by_ref = 0; |
11229 | 1 | a_chk->rec.chunk_id.id = type; |
11230 | 1 | a_chk->rec.chunk_id.can_take_data = 1; |
11231 | 1 | } |
11232 | | /* Clear our pkt counts */ |
11233 | 1 | asoc->data_pkts_seen = 0; |
11234 | | |
11235 | 1 | a_chk->flags = 0; |
11236 | 1 | a_chk->asoc = asoc; |
11237 | 1 | a_chk->snd_count = 0; |
11238 | 1 | a_chk->send_size = 0; /* fill in later */ |
11239 | 1 | a_chk->sent = SCTP_DATAGRAM_UNSENT; |
11240 | 1 | a_chk->whoTo = NULL; |
11241 | | |
11242 | 1 | if ((asoc->last_data_chunk_from->dest_state & SCTP_ADDR_REACHABLE) == 0) { |
11243 | | /*- |
11244 | | * Ok, the destination for the SACK is unreachable, lets see if |
11245 | | * we can select an alternate to asoc->last_data_chunk_from |
11246 | | */ |
11247 | 0 | a_chk->whoTo = sctp_find_alternate_net(stcb, asoc->last_data_chunk_from, 0); |
11248 | 0 | if (a_chk->whoTo == NULL) { |
11249 | | /* Nope, no alternate */ |
11250 | 0 | a_chk->whoTo = asoc->last_data_chunk_from; |
11251 | 0 | } |
11252 | 1 | } else { |
11253 | 1 | a_chk->whoTo = asoc->last_data_chunk_from; |
11254 | 1 | } |
11255 | 1 | if (a_chk->whoTo) { |
11256 | 1 | atomic_add_int(&a_chk->whoTo->ref_count, 1); |
11257 | 1 | } |
11258 | 1 | if (SCTP_TSN_GT(asoc->highest_tsn_inside_map, asoc->highest_tsn_inside_nr_map)) { |
11259 | 0 | highest_tsn = asoc->highest_tsn_inside_map; |
11260 | 1 | } else { |
11261 | 1 | highest_tsn = asoc->highest_tsn_inside_nr_map; |
11262 | 1 | } |
11263 | 1 | if (highest_tsn == asoc->cumulative_tsn) { |
11264 | | /* no gaps */ |
11265 | 1 | if (type == SCTP_SELECTIVE_ACK) { |
11266 | 1 | space_req = sizeof(struct sctp_sack_chunk); |
11267 | 1 | } else { |
11268 | 0 | space_req = sizeof(struct sctp_nr_sack_chunk); |
11269 | 0 | } |
11270 | 1 | } else { |
11271 | | /* gaps get a cluster */ |
11272 | 0 | space_req = MCLBYTES; |
11273 | 0 | } |
11274 | | /* Ok now lets formulate a MBUF with our sack */ |
11275 | 1 | a_chk->data = sctp_get_mbuf_for_msg(space_req, 0, M_NOWAIT, 1, MT_DATA); |
11276 | 1 | if ((a_chk->data == NULL) || |
11277 | 1 | (a_chk->whoTo == NULL)) { |
11278 | | /* rats, no mbuf memory */ |
11279 | 0 | if (a_chk->data) { |
11280 | | /* was a problem with the destination */ |
11281 | 0 | sctp_m_freem(a_chk->data); |
11282 | 0 | a_chk->data = NULL; |
11283 | 0 | } |
11284 | 0 | sctp_free_a_chunk(stcb, a_chk, so_locked); |
11285 | | /* sa_ignore NO_NULL_CHK */ |
11286 | 0 | if (stcb->asoc.delayed_ack) { |
11287 | 0 | sctp_timer_stop(SCTP_TIMER_TYPE_RECV, |
11288 | 0 | stcb->sctp_ep, stcb, NULL, |
11289 | 0 | SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_5); |
11290 | 0 | sctp_timer_start(SCTP_TIMER_TYPE_RECV, |
11291 | 0 | stcb->sctp_ep, stcb, NULL); |
11292 | 0 | } else { |
11293 | 0 | stcb->asoc.send_sack = 1; |
11294 | 0 | } |
11295 | 0 | return; |
11296 | 0 | } |
11297 | | /* ok, lets go through and fill it in */ |
11298 | 1 | SCTP_BUF_RESV_UF(a_chk->data, SCTP_MIN_OVERHEAD); |
11299 | 1 | space = (unsigned int)M_TRAILINGSPACE(a_chk->data); |
11300 | 1 | if (space > (a_chk->whoTo->mtu - SCTP_MIN_OVERHEAD)) { |
11301 | 0 | space = (a_chk->whoTo->mtu - SCTP_MIN_OVERHEAD); |
11302 | 0 | } |
11303 | 1 | limit = mtod(a_chk->data, caddr_t); |
11304 | 1 | limit += space; |
11305 | | |
11306 | 1 | flags = 0; |
11307 | | |
11308 | 1 | if ((asoc->sctp_cmt_on_off > 0) && |
11309 | 0 | SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { |
11310 | | /*- |
11311 | | * CMT DAC algorithm: If 2 (i.e., 0x10) packets have been |
11312 | | * received, then set high bit to 1, else 0. Reset |
11313 | | * pkts_rcvd. |
11314 | | */ |
11315 | 0 | flags |= (asoc->cmt_dac_pkts_rcvd << 6); |
11316 | 0 | asoc->cmt_dac_pkts_rcvd = 0; |
11317 | 0 | } |
11318 | | #ifdef SCTP_ASOCLOG_OF_TSNS |
11319 | | stcb->asoc.cumack_logsnt[stcb->asoc.cumack_log_atsnt] = asoc->cumulative_tsn; |
11320 | | stcb->asoc.cumack_log_atsnt++; |
11321 | | if (stcb->asoc.cumack_log_atsnt >= SCTP_TSN_LOG_SIZE) { |
11322 | | stcb->asoc.cumack_log_atsnt = 0; |
11323 | | } |
11324 | | #endif |
11325 | | /* reset the readers interpretation */ |
11326 | 1 | stcb->freed_by_sorcv_sincelast = 0; |
11327 | | |
11328 | 1 | if (type == SCTP_SELECTIVE_ACK) { |
11329 | 1 | sack = mtod(a_chk->data, struct sctp_sack_chunk *); |
11330 | 1 | nr_sack = NULL; |
11331 | 1 | gap_descriptor = (struct sctp_gap_ack_block *)((caddr_t)sack + sizeof(struct sctp_sack_chunk)); |
11332 | 1 | if (highest_tsn > asoc->mapping_array_base_tsn) { |
11333 | 0 | siz = (((highest_tsn - asoc->mapping_array_base_tsn) + 1) + 7) / 8; |
11334 | 1 | } else { |
11335 | 1 | siz = (((MAX_TSN - asoc->mapping_array_base_tsn) + 1) + highest_tsn + 7) / 8; |
11336 | 1 | } |
11337 | 1 | } else { |
11338 | 0 | sack = NULL; |
11339 | 0 | nr_sack = mtod(a_chk->data, struct sctp_nr_sack_chunk *); |
11340 | 0 | gap_descriptor = (struct sctp_gap_ack_block *)((caddr_t)nr_sack + sizeof(struct sctp_nr_sack_chunk)); |
11341 | 0 | if (asoc->highest_tsn_inside_map > asoc->mapping_array_base_tsn) { |
11342 | 0 | siz = (((asoc->highest_tsn_inside_map - asoc->mapping_array_base_tsn) + 1) + 7) / 8; |
11343 | 0 | } else { |
11344 | 0 | siz = (((MAX_TSN - asoc->mapping_array_base_tsn) + 1) + asoc->highest_tsn_inside_map + 7) / 8; |
11345 | 0 | } |
11346 | 0 | } |
11347 | | |
11348 | 1 | if (SCTP_TSN_GT(asoc->mapping_array_base_tsn, asoc->cumulative_tsn)) { |
11349 | 1 | offset = 1; |
11350 | 1 | } else { |
11351 | 0 | offset = asoc->mapping_array_base_tsn - asoc->cumulative_tsn; |
11352 | 0 | } |
11353 | 1 | if (((type == SCTP_SELECTIVE_ACK) && |
11354 | 1 | SCTP_TSN_GT(highest_tsn, asoc->cumulative_tsn)) || |
11355 | 1 | ((type == SCTP_NR_SELECTIVE_ACK) && |
11356 | 1 | SCTP_TSN_GT(asoc->highest_tsn_inside_map, asoc->cumulative_tsn))) { |
11357 | | /* we have a gap .. maybe */ |
11358 | 0 | for (i = 0; i < siz; i++) { |
11359 | 0 | tsn_map = asoc->mapping_array[i]; |
11360 | 0 | if (type == SCTP_SELECTIVE_ACK) { |
11361 | 0 | tsn_map |= asoc->nr_mapping_array[i]; |
11362 | 0 | } |
11363 | 0 | if (i == 0) { |
11364 | | /* |
11365 | | * Clear all bits corresponding to TSNs |
11366 | | * smaller or equal to the cumulative TSN. |
11367 | | */ |
11368 | 0 | tsn_map &= (~0U << (1 - offset)); |
11369 | 0 | } |
11370 | 0 | selector = &sack_array[tsn_map]; |
11371 | 0 | if (mergeable && selector->right_edge) { |
11372 | | /* |
11373 | | * Backup, left and right edges were ok to |
11374 | | * merge. |
11375 | | */ |
11376 | 0 | num_gap_blocks--; |
11377 | 0 | gap_descriptor--; |
11378 | 0 | } |
11379 | 0 | if (selector->num_entries == 0) |
11380 | 0 | mergeable = 0; |
11381 | 0 | else { |
11382 | 0 | for (j = 0; j < selector->num_entries; j++) { |
11383 | 0 | if (mergeable && selector->right_edge) { |
11384 | | /* |
11385 | | * do a merge by NOT setting |
11386 | | * the left side |
11387 | | */ |
11388 | 0 | mergeable = 0; |
11389 | 0 | } else { |
11390 | | /* |
11391 | | * no merge, set the left |
11392 | | * side |
11393 | | */ |
11394 | 0 | mergeable = 0; |
11395 | 0 | gap_descriptor->start = htons((selector->gaps[j].start + offset)); |
11396 | 0 | } |
11397 | 0 | gap_descriptor->end = htons((selector->gaps[j].end + offset)); |
11398 | 0 | num_gap_blocks++; |
11399 | 0 | gap_descriptor++; |
11400 | 0 | if (((caddr_t)gap_descriptor + sizeof(struct sctp_gap_ack_block)) > limit) { |
11401 | | /* no more room */ |
11402 | 0 | limit_reached = 1; |
11403 | 0 | break; |
11404 | 0 | } |
11405 | 0 | } |
11406 | 0 | if (selector->left_edge) { |
11407 | 0 | mergeable = 1; |
11408 | 0 | } |
11409 | 0 | } |
11410 | 0 | if (limit_reached) { |
11411 | | /* Reached the limit stop */ |
11412 | 0 | break; |
11413 | 0 | } |
11414 | 0 | offset += 8; |
11415 | 0 | } |
11416 | 0 | } |
11417 | 1 | if ((type == SCTP_NR_SELECTIVE_ACK) && |
11418 | 0 | (limit_reached == 0)) { |
11419 | 0 | mergeable = 0; |
11420 | |
|
11421 | 0 | if (asoc->highest_tsn_inside_nr_map > asoc->mapping_array_base_tsn) { |
11422 | 0 | siz = (((asoc->highest_tsn_inside_nr_map - asoc->mapping_array_base_tsn) + 1) + 7) / 8; |
11423 | 0 | } else { |
11424 | 0 | siz = (((MAX_TSN - asoc->mapping_array_base_tsn) + 1) + asoc->highest_tsn_inside_nr_map + 7) / 8; |
11425 | 0 | } |
11426 | |
|
11427 | 0 | if (SCTP_TSN_GT(asoc->mapping_array_base_tsn, asoc->cumulative_tsn)) { |
11428 | 0 | offset = 1; |
11429 | 0 | } else { |
11430 | 0 | offset = asoc->mapping_array_base_tsn - asoc->cumulative_tsn; |
11431 | 0 | } |
11432 | 0 | if (SCTP_TSN_GT(asoc->highest_tsn_inside_nr_map, asoc->cumulative_tsn)) { |
11433 | | /* we have a gap .. maybe */ |
11434 | 0 | for (i = 0; i < siz; i++) { |
11435 | 0 | tsn_map = asoc->nr_mapping_array[i]; |
11436 | 0 | if (i == 0) { |
11437 | | /* |
11438 | | * Clear all bits corresponding to TSNs |
11439 | | * smaller or equal to the cumulative TSN. |
11440 | | */ |
11441 | 0 | tsn_map &= (~0U << (1 - offset)); |
11442 | 0 | } |
11443 | 0 | selector = &sack_array[tsn_map]; |
11444 | 0 | if (mergeable && selector->right_edge) { |
11445 | | /* |
11446 | | * Backup, left and right edges were ok to |
11447 | | * merge. |
11448 | | */ |
11449 | 0 | num_nr_gap_blocks--; |
11450 | 0 | gap_descriptor--; |
11451 | 0 | } |
11452 | 0 | if (selector->num_entries == 0) |
11453 | 0 | mergeable = 0; |
11454 | 0 | else { |
11455 | 0 | for (j = 0; j < selector->num_entries; j++) { |
11456 | 0 | if (mergeable && selector->right_edge) { |
11457 | | /* |
11458 | | * do a merge by NOT setting |
11459 | | * the left side |
11460 | | */ |
11461 | 0 | mergeable = 0; |
11462 | 0 | } else { |
11463 | | /* |
11464 | | * no merge, set the left |
11465 | | * side |
11466 | | */ |
11467 | 0 | mergeable = 0; |
11468 | 0 | gap_descriptor->start = htons((selector->gaps[j].start + offset)); |
11469 | 0 | } |
11470 | 0 | gap_descriptor->end = htons((selector->gaps[j].end + offset)); |
11471 | 0 | num_nr_gap_blocks++; |
11472 | 0 | gap_descriptor++; |
11473 | 0 | if (((caddr_t)gap_descriptor + sizeof(struct sctp_gap_ack_block)) > limit) { |
11474 | | /* no more room */ |
11475 | 0 | limit_reached = 1; |
11476 | 0 | break; |
11477 | 0 | } |
11478 | 0 | } |
11479 | 0 | if (selector->left_edge) { |
11480 | 0 | mergeable = 1; |
11481 | 0 | } |
11482 | 0 | } |
11483 | 0 | if (limit_reached) { |
11484 | | /* Reached the limit stop */ |
11485 | 0 | break; |
11486 | 0 | } |
11487 | 0 | offset += 8; |
11488 | 0 | } |
11489 | 0 | } |
11490 | 0 | } |
11491 | | /* now we must add any dups we are going to report. */ |
11492 | 1 | if ((limit_reached == 0) && (asoc->numduptsns)) { |
11493 | 0 | dup = (uint32_t *) gap_descriptor; |
11494 | 0 | for (i = 0; i < asoc->numduptsns; i++) { |
11495 | 0 | *dup = htonl(asoc->dup_tsns[i]); |
11496 | 0 | dup++; |
11497 | 0 | num_dups++; |
11498 | 0 | if (((caddr_t)dup + sizeof(uint32_t)) > limit) { |
11499 | | /* no more room */ |
11500 | 0 | break; |
11501 | 0 | } |
11502 | 0 | } |
11503 | 0 | asoc->numduptsns = 0; |
11504 | 0 | } |
11505 | | /* |
11506 | | * now that the chunk is prepared queue it to the control chunk |
11507 | | * queue. |
11508 | | */ |
11509 | 1 | if (type == SCTP_SELECTIVE_ACK) { |
11510 | 1 | a_chk->send_size = (uint16_t)(sizeof(struct sctp_sack_chunk) + |
11511 | 1 | (num_gap_blocks + num_nr_gap_blocks) * sizeof(struct sctp_gap_ack_block) + |
11512 | 1 | num_dups * sizeof(int32_t)); |
11513 | 1 | SCTP_BUF_LEN(a_chk->data) = a_chk->send_size; |
11514 | 1 | sack->sack.cum_tsn_ack = htonl(asoc->cumulative_tsn); |
11515 | 1 | sack->sack.a_rwnd = htonl(asoc->my_rwnd); |
11516 | 1 | sack->sack.num_gap_ack_blks = htons(num_gap_blocks); |
11517 | 1 | sack->sack.num_dup_tsns = htons(num_dups); |
11518 | 1 | sack->ch.chunk_type = type; |
11519 | 1 | sack->ch.chunk_flags = flags; |
11520 | 1 | sack->ch.chunk_length = htons(a_chk->send_size); |
11521 | 1 | } else { |
11522 | 0 | a_chk->send_size = (uint16_t)(sizeof(struct sctp_nr_sack_chunk) + |
11523 | 0 | (num_gap_blocks + num_nr_gap_blocks) * sizeof(struct sctp_gap_ack_block) + |
11524 | 0 | num_dups * sizeof(int32_t)); |
11525 | 0 | SCTP_BUF_LEN(a_chk->data) = a_chk->send_size; |
11526 | 0 | nr_sack->nr_sack.cum_tsn_ack = htonl(asoc->cumulative_tsn); |
11527 | 0 | nr_sack->nr_sack.a_rwnd = htonl(asoc->my_rwnd); |
11528 | 0 | nr_sack->nr_sack.num_gap_ack_blks = htons(num_gap_blocks); |
11529 | 0 | nr_sack->nr_sack.num_nr_gap_ack_blks = htons(num_nr_gap_blocks); |
11530 | 0 | nr_sack->nr_sack.num_dup_tsns = htons(num_dups); |
11531 | 0 | nr_sack->nr_sack.reserved = 0; |
11532 | 0 | nr_sack->ch.chunk_type = type; |
11533 | 0 | nr_sack->ch.chunk_flags = flags; |
11534 | 0 | nr_sack->ch.chunk_length = htons(a_chk->send_size); |
11535 | 0 | } |
11536 | 1 | TAILQ_INSERT_TAIL(&asoc->control_send_queue, a_chk, sctp_next); |
11537 | 1 | asoc->my_last_reported_rwnd = asoc->my_rwnd; |
11538 | 1 | asoc->ctrl_queue_cnt++; |
11539 | 1 | asoc->send_sack = 0; |
11540 | 1 | SCTP_STAT_INCR(sctps_sendsacks); |
11541 | 1 | return; |
11542 | 1 | } |
11543 | | |
11544 | | void |
11545 | | sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked) |
11546 | 1.60k | { |
11547 | 1.60k | struct mbuf *m_abort, *m, *m_last; |
11548 | 1.60k | struct mbuf *m_out, *m_end = NULL; |
11549 | 1.60k | struct sctp_abort_chunk *abort; |
11550 | 1.60k | struct sctp_auth_chunk *auth = NULL; |
11551 | 1.60k | struct sctp_nets *net; |
11552 | 1.60k | uint32_t vtag; |
11553 | 1.60k | uint32_t auth_offset = 0; |
11554 | 1.60k | int error; |
11555 | 1.60k | uint16_t cause_len, chunk_len, padding_len; |
11556 | 1.60k | bool use_zero_crc; |
11557 | | |
11558 | | #if defined(__APPLE__) && !defined(__Userspace__) |
11559 | | if (so_locked) { |
11560 | | sctp_lock_assert(SCTP_INP_SO(stcb->sctp_ep)); |
11561 | | } else { |
11562 | | sctp_unlock_assert(SCTP_INP_SO(stcb->sctp_ep)); |
11563 | | } |
11564 | | #endif |
11565 | 1.60k | SCTP_TCB_LOCK_ASSERT(stcb); |
11566 | | /*- |
11567 | | * Add an AUTH chunk, if chunk requires it and save the offset into |
11568 | | * the chain for AUTH |
11569 | | */ |
11570 | 1.60k | if (sctp_auth_is_required_chunk(SCTP_ABORT_ASSOCIATION, |
11571 | 1.60k | stcb->asoc.peer_auth_chunks)) { |
11572 | 0 | m_out = sctp_add_auth_chunk(NULL, &m_end, &auth, &auth_offset, |
11573 | 0 | stcb, SCTP_ABORT_ASSOCIATION); |
11574 | 0 | SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); |
11575 | 1.60k | } else { |
11576 | 1.60k | m_out = NULL; |
11577 | 1.60k | } |
11578 | 1.60k | switch (stcb->asoc.snd_edmid) { |
11579 | 0 | case SCTP_EDMID_LOWER_LAYER_DTLS: |
11580 | 0 | use_zero_crc = true; |
11581 | 0 | break; |
11582 | 1.60k | default: |
11583 | 1.60k | use_zero_crc = false; |
11584 | 1.60k | break; |
11585 | 1.60k | } |
11586 | 1.60k | m_abort = sctp_get_mbuf_for_msg(sizeof(struct sctp_abort_chunk), 0, M_NOWAIT, 1, MT_HEADER); |
11587 | 1.60k | if (m_abort == NULL) { |
11588 | 0 | if (m_out) { |
11589 | 0 | sctp_m_freem(m_out); |
11590 | 0 | } |
11591 | 0 | if (operr) { |
11592 | 0 | sctp_m_freem(operr); |
11593 | 0 | } |
11594 | 0 | return; |
11595 | 0 | } |
11596 | | /* link in any error */ |
11597 | 1.60k | SCTP_BUF_NEXT(m_abort) = operr; |
11598 | 1.60k | cause_len = 0; |
11599 | 1.60k | m_last = NULL; |
11600 | 3.21k | for (m = operr; m; m = SCTP_BUF_NEXT(m)) { |
11601 | 1.60k | cause_len += (uint16_t)SCTP_BUF_LEN(m); |
11602 | 1.60k | if (SCTP_BUF_NEXT(m) == NULL) { |
11603 | 1.60k | m_last = m; |
11604 | 1.60k | } |
11605 | 1.60k | } |
11606 | 1.60k | SCTP_BUF_LEN(m_abort) = sizeof(struct sctp_abort_chunk); |
11607 | 1.60k | chunk_len = (uint16_t)sizeof(struct sctp_abort_chunk) + cause_len; |
11608 | 1.60k | padding_len = SCTP_SIZE32(chunk_len) - chunk_len; |
11609 | 1.60k | if (m_out == NULL) { |
11610 | | /* NO Auth chunk prepended, so reserve space in front */ |
11611 | 1.60k | SCTP_BUF_RESV_UF(m_abort, SCTP_MIN_OVERHEAD); |
11612 | 1.60k | m_out = m_abort; |
11613 | 1.60k | } else { |
11614 | | /* Put AUTH chunk at the front of the chain */ |
11615 | 0 | SCTP_BUF_NEXT(m_end) = m_abort; |
11616 | 0 | } |
11617 | 1.60k | if (stcb->asoc.alternate) { |
11618 | 0 | net = stcb->asoc.alternate; |
11619 | 1.60k | } else { |
11620 | 1.60k | net = stcb->asoc.primary_destination; |
11621 | 1.60k | } |
11622 | | /* Fill in the ABORT chunk header. */ |
11623 | 1.60k | abort = mtod(m_abort, struct sctp_abort_chunk *); |
11624 | 1.60k | abort->ch.chunk_type = SCTP_ABORT_ASSOCIATION; |
11625 | 1.60k | if (stcb->asoc.peer_vtag == 0) { |
11626 | | /* This happens iff the assoc is in COOKIE-WAIT state. */ |
11627 | 0 | vtag = stcb->asoc.my_vtag; |
11628 | 0 | abort->ch.chunk_flags = SCTP_HAD_NO_TCB; |
11629 | 1.60k | } else { |
11630 | 1.60k | vtag = stcb->asoc.peer_vtag; |
11631 | 1.60k | abort->ch.chunk_flags = 0; |
11632 | 1.60k | } |
11633 | 1.60k | abort->ch.chunk_length = htons(chunk_len); |
11634 | | /* Add padding, if necessary. */ |
11635 | 1.60k | if (padding_len > 0) { |
11636 | 0 | if ((m_last == NULL) || |
11637 | 0 | (sctp_add_pad_tombuf(m_last, padding_len) == NULL)) { |
11638 | 0 | sctp_m_freem(m_out); |
11639 | 0 | return; |
11640 | 0 | } |
11641 | 0 | } |
11642 | 1.60k | if ((error = sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net, |
11643 | 1.60k | (struct sockaddr *)&net->ro._l_addr, |
11644 | 1.60k | m_out, auth_offset, auth, stcb->asoc.authinfo.active_keyid, 1, 0, 0, |
11645 | 1.60k | stcb->sctp_ep->sctp_lport, stcb->rport, htonl(vtag), |
11646 | 1.60k | stcb->asoc.primary_destination->port, NULL, |
11647 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
11648 | | 0, 0, |
11649 | | #endif |
11650 | 1.60k | use_zero_crc, |
11651 | 1.60k | so_locked))) { |
11652 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); |
11653 | 0 | if (error == ENOBUFS) { |
11654 | 0 | stcb->asoc.ifp_had_enobuf = 1; |
11655 | 0 | SCTP_STAT_INCR(sctps_lowlevelerr); |
11656 | 0 | } |
11657 | 1.60k | } else { |
11658 | 1.60k | stcb->asoc.ifp_had_enobuf = 0; |
11659 | 1.60k | } |
11660 | 1.60k | SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); |
11661 | 1.60k | } |
11662 | | |
11663 | | void |
11664 | | sctp_send_shutdown_complete(struct sctp_tcb *stcb, |
11665 | | struct sctp_nets *net, |
11666 | | int reflect_vtag) |
11667 | 0 | { |
11668 | | /* formulate and SEND a SHUTDOWN-COMPLETE */ |
11669 | 0 | struct mbuf *m_shutdown_comp; |
11670 | 0 | struct sctp_shutdown_complete_chunk *shutdown_complete; |
11671 | 0 | uint32_t vtag; |
11672 | 0 | int error; |
11673 | 0 | uint8_t flags; |
11674 | 0 | bool use_zero_crc; |
11675 | |
|
11676 | 0 | m_shutdown_comp = sctp_get_mbuf_for_msg(sizeof(struct sctp_chunkhdr), 0, M_NOWAIT, 1, MT_HEADER); |
11677 | 0 | if (m_shutdown_comp == NULL) { |
11678 | | /* no mbuf's */ |
11679 | 0 | return; |
11680 | 0 | } |
11681 | 0 | if (reflect_vtag) { |
11682 | 0 | flags = SCTP_HAD_NO_TCB; |
11683 | 0 | vtag = stcb->asoc.my_vtag; |
11684 | 0 | } else { |
11685 | 0 | flags = 0; |
11686 | 0 | vtag = stcb->asoc.peer_vtag; |
11687 | 0 | } |
11688 | 0 | switch (stcb->asoc.snd_edmid) { |
11689 | 0 | case SCTP_EDMID_LOWER_LAYER_DTLS: |
11690 | 0 | use_zero_crc = true; |
11691 | 0 | break; |
11692 | 0 | default: |
11693 | 0 | use_zero_crc = false; |
11694 | 0 | break; |
11695 | 0 | } |
11696 | 0 | shutdown_complete = mtod(m_shutdown_comp, struct sctp_shutdown_complete_chunk *); |
11697 | 0 | shutdown_complete->ch.chunk_type = SCTP_SHUTDOWN_COMPLETE; |
11698 | 0 | shutdown_complete->ch.chunk_flags = flags; |
11699 | 0 | shutdown_complete->ch.chunk_length = htons(sizeof(struct sctp_shutdown_complete_chunk)); |
11700 | 0 | SCTP_BUF_LEN(m_shutdown_comp) = sizeof(struct sctp_shutdown_complete_chunk); |
11701 | 0 | if ((error = sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net, |
11702 | 0 | (struct sockaddr *)&net->ro._l_addr, |
11703 | 0 | m_shutdown_comp, 0, NULL, 0, 1, 0, 0, |
11704 | 0 | stcb->sctp_ep->sctp_lport, stcb->rport, |
11705 | 0 | htonl(vtag), |
11706 | 0 | net->port, NULL, |
11707 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
11708 | | 0, 0, |
11709 | | #endif |
11710 | 0 | use_zero_crc, |
11711 | 0 | SCTP_SO_NOT_LOCKED))) { |
11712 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT3, "Gak send error %d\n", error); |
11713 | 0 | if (error == ENOBUFS) { |
11714 | 0 | stcb->asoc.ifp_had_enobuf = 1; |
11715 | 0 | SCTP_STAT_INCR(sctps_lowlevelerr); |
11716 | 0 | } |
11717 | 0 | } else { |
11718 | 0 | stcb->asoc.ifp_had_enobuf = 0; |
11719 | 0 | } |
11720 | 0 | SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); |
11721 | 0 | return; |
11722 | 0 | } |
11723 | | |
11724 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
11725 | | static void |
11726 | | sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, |
11727 | | struct sctphdr *sh, uint32_t vtag, |
11728 | | uint8_t type, struct mbuf *cause, |
11729 | | uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum, |
11730 | | uint32_t vrf_id, uint16_t port) |
11731 | | #else |
11732 | | static void |
11733 | | sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, |
11734 | | struct sctphdr *sh, uint32_t vtag, |
11735 | | uint8_t type, struct mbuf *cause, |
11736 | | uint32_t vrf_id SCTP_UNUSED, uint16_t port) |
11737 | | #endif |
11738 | 7.16k | { |
11739 | 7.16k | struct mbuf *o_pak; |
11740 | 7.16k | struct mbuf *mout; |
11741 | 7.16k | struct sctphdr *shout; |
11742 | 7.16k | struct sctp_chunkhdr *ch; |
11743 | 7.16k | #if defined(INET) || defined(INET6) |
11744 | 7.16k | struct udphdr *udp; |
11745 | 7.16k | #endif |
11746 | 7.16k | int ret, len, cause_len, padding_len; |
11747 | 7.16k | #ifdef INET |
11748 | | #if defined(__APPLE__) && !defined(__Userspace__) |
11749 | | sctp_route_t ro; |
11750 | | #endif |
11751 | 7.16k | struct sockaddr_in *src_sin, *dst_sin; |
11752 | 7.16k | struct ip *ip; |
11753 | 7.16k | #endif |
11754 | 7.16k | #ifdef INET6 |
11755 | 7.16k | struct sockaddr_in6 *src_sin6, *dst_sin6; |
11756 | 7.16k | struct ip6_hdr *ip6; |
11757 | 7.16k | #endif |
11758 | | |
11759 | | /* Compute the length of the cause and add final padding. */ |
11760 | 7.16k | cause_len = 0; |
11761 | 7.16k | if (cause != NULL) { |
11762 | 7.16k | struct mbuf *m_at, *m_last = NULL; |
11763 | | |
11764 | 14.3k | for (m_at = cause; m_at; m_at = SCTP_BUF_NEXT(m_at)) { |
11765 | 7.16k | if (SCTP_BUF_NEXT(m_at) == NULL) |
11766 | 7.16k | m_last = m_at; |
11767 | 7.16k | cause_len += SCTP_BUF_LEN(m_at); |
11768 | 7.16k | } |
11769 | 7.16k | padding_len = cause_len % 4; |
11770 | 7.16k | if (padding_len != 0) { |
11771 | 0 | padding_len = 4 - padding_len; |
11772 | 0 | } |
11773 | 7.16k | if (padding_len != 0) { |
11774 | 0 | if (sctp_add_pad_tombuf(m_last, padding_len) == NULL) { |
11775 | 0 | sctp_m_freem(cause); |
11776 | 0 | return; |
11777 | 0 | } |
11778 | 0 | } |
11779 | 7.16k | } else { |
11780 | 0 | padding_len = 0; |
11781 | 0 | } |
11782 | | /* Get an mbuf for the header. */ |
11783 | 7.16k | len = sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); |
11784 | 7.16k | switch (dst->sa_family) { |
11785 | 0 | #ifdef INET |
11786 | 0 | case AF_INET: |
11787 | 0 | len += sizeof(struct ip); |
11788 | 0 | break; |
11789 | 0 | #endif |
11790 | 0 | #ifdef INET6 |
11791 | 0 | case AF_INET6: |
11792 | 0 | len += sizeof(struct ip6_hdr); |
11793 | 0 | break; |
11794 | 0 | #endif |
11795 | 7.16k | default: |
11796 | 7.16k | break; |
11797 | 7.16k | } |
11798 | 7.16k | #if defined(INET) || defined(INET6) |
11799 | 7.16k | if (port) { |
11800 | 0 | len += sizeof(struct udphdr); |
11801 | 0 | } |
11802 | 7.16k | #endif |
11803 | | #if defined(__APPLE__) && !defined(__Userspace__) |
11804 | | #if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) |
11805 | | mout = sctp_get_mbuf_for_msg(len + max_linkhdr, 1, M_NOWAIT, 1, MT_DATA); |
11806 | | #else |
11807 | | mout = sctp_get_mbuf_for_msg(len + SCTP_MAX_LINKHDR, 1, M_NOWAIT, 1, MT_DATA); |
11808 | | #endif |
11809 | | #else |
11810 | 7.16k | mout = sctp_get_mbuf_for_msg(len + max_linkhdr, 1, M_NOWAIT, 1, MT_DATA); |
11811 | 7.16k | #endif |
11812 | 7.16k | if (mout == NULL) { |
11813 | 0 | if (cause) { |
11814 | 0 | sctp_m_freem(cause); |
11815 | 0 | } |
11816 | 0 | return; |
11817 | 0 | } |
11818 | | #if defined(__APPLE__) && !defined(__Userspace__) |
11819 | | #if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) |
11820 | | SCTP_BUF_RESV_UF(mout, max_linkhdr); |
11821 | | #else |
11822 | | SCTP_BUF_RESV_UF(mout, SCTP_MAX_LINKHDR); |
11823 | | #endif |
11824 | | #else |
11825 | 7.16k | SCTP_BUF_RESV_UF(mout, max_linkhdr); |
11826 | 7.16k | #endif |
11827 | 7.16k | SCTP_BUF_LEN(mout) = len; |
11828 | 7.16k | SCTP_BUF_NEXT(mout) = cause; |
11829 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
11830 | | M_SETFIB(mout, fibnum); |
11831 | | mout->m_pkthdr.flowid = mflowid; |
11832 | | M_HASHTYPE_SET(mout, mflowtype); |
11833 | | #endif |
11834 | 7.16k | #ifdef INET |
11835 | 7.16k | ip = NULL; |
11836 | 7.16k | #endif |
11837 | 7.16k | #ifdef INET6 |
11838 | 7.16k | ip6 = NULL; |
11839 | 7.16k | #endif |
11840 | 7.16k | switch (dst->sa_family) { |
11841 | 0 | #ifdef INET |
11842 | 0 | case AF_INET: |
11843 | 0 | src_sin = (struct sockaddr_in *)src; |
11844 | 0 | dst_sin = (struct sockaddr_in *)dst; |
11845 | 0 | ip = mtod(mout, struct ip *); |
11846 | 0 | ip->ip_v = IPVERSION; |
11847 | 0 | ip->ip_hl = (sizeof(struct ip) >> 2); |
11848 | 0 | ip->ip_tos = 0; |
11849 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
11850 | | ip->ip_off = htons(IP_DF); |
11851 | | #elif defined(WITH_CONVERT_IP_OFF) || defined(__APPLE__) |
11852 | | ip->ip_off = IP_DF; |
11853 | | #else |
11854 | 0 | ip->ip_off = htons(IP_DF); |
11855 | 0 | #endif |
11856 | 0 | #if defined(__Userspace__) |
11857 | 0 | ip->ip_id = htons(ip_id++); |
11858 | | #elif defined(__FreeBSD__) |
11859 | | ip_fillid(ip, V_ip_random_id); |
11860 | | #elif defined(__APPLE__) |
11861 | | #if RANDOM_IP_ID |
11862 | | ip->ip_id = ip_randomid(); |
11863 | | #else |
11864 | | ip->ip_id = htons(ip_id++); |
11865 | | #endif |
11866 | | #else |
11867 | | ip->ip_id = ip_id++; |
11868 | | #endif |
11869 | 0 | ip->ip_ttl = MODULE_GLOBAL(ip_defttl); |
11870 | 0 | if (port) { |
11871 | 0 | ip->ip_p = IPPROTO_UDP; |
11872 | 0 | } else { |
11873 | 0 | ip->ip_p = IPPROTO_SCTP; |
11874 | 0 | } |
11875 | 0 | ip->ip_src.s_addr = dst_sin->sin_addr.s_addr; |
11876 | 0 | ip->ip_dst.s_addr = src_sin->sin_addr.s_addr; |
11877 | 0 | ip->ip_sum = 0; |
11878 | 0 | len = sizeof(struct ip); |
11879 | 0 | shout = (struct sctphdr *)((caddr_t)ip + len); |
11880 | 0 | break; |
11881 | 0 | #endif |
11882 | 0 | #ifdef INET6 |
11883 | 0 | case AF_INET6: |
11884 | 0 | src_sin6 = (struct sockaddr_in6 *)src; |
11885 | 0 | dst_sin6 = (struct sockaddr_in6 *)dst; |
11886 | 0 | ip6 = mtod(mout, struct ip6_hdr *); |
11887 | 0 | ip6->ip6_flow = htonl(0x60000000); |
11888 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
11889 | | if (V_ip6_auto_flowlabel) { |
11890 | | ip6->ip6_flow |= (htonl(ip6_randomflowlabel()) & IPV6_FLOWLABEL_MASK); |
11891 | | } |
11892 | | #endif |
11893 | 0 | #if defined(__Userspace__) |
11894 | 0 | ip6->ip6_hlim = IPv6_HOP_LIMIT; |
11895 | | #else |
11896 | | ip6->ip6_hlim = MODULE_GLOBAL(ip6_defhlim); |
11897 | | #endif |
11898 | 0 | if (port) { |
11899 | 0 | ip6->ip6_nxt = IPPROTO_UDP; |
11900 | 0 | } else { |
11901 | 0 | ip6->ip6_nxt = IPPROTO_SCTP; |
11902 | 0 | } |
11903 | 0 | ip6->ip6_src = dst_sin6->sin6_addr; |
11904 | 0 | ip6->ip6_dst = src_sin6->sin6_addr; |
11905 | 0 | len = sizeof(struct ip6_hdr); |
11906 | 0 | shout = (struct sctphdr *)((caddr_t)ip6 + len); |
11907 | 0 | break; |
11908 | 0 | #endif |
11909 | 7.16k | default: |
11910 | 7.16k | len = 0; |
11911 | 7.16k | shout = mtod(mout, struct sctphdr *); |
11912 | 7.16k | break; |
11913 | 7.16k | } |
11914 | 7.16k | #if defined(INET) || defined(INET6) |
11915 | 7.16k | if (port) { |
11916 | 0 | if (htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)) == 0) { |
11917 | 0 | sctp_m_freem(mout); |
11918 | 0 | return; |
11919 | 0 | } |
11920 | 0 | udp = (struct udphdr *)shout; |
11921 | 0 | udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); |
11922 | 0 | udp->uh_dport = port; |
11923 | 0 | udp->uh_sum = 0; |
11924 | 0 | udp->uh_ulen = htons((uint16_t)(sizeof(struct udphdr) + |
11925 | 0 | sizeof(struct sctphdr) + |
11926 | 0 | sizeof(struct sctp_chunkhdr) + |
11927 | 0 | cause_len + padding_len)); |
11928 | 0 | len += sizeof(struct udphdr); |
11929 | 0 | shout = (struct sctphdr *)((caddr_t)shout + sizeof(struct udphdr)); |
11930 | 7.16k | } else { |
11931 | 7.16k | udp = NULL; |
11932 | 7.16k | } |
11933 | 7.16k | #endif |
11934 | 7.16k | shout->src_port = sh->dest_port; |
11935 | 7.16k | shout->dest_port = sh->src_port; |
11936 | 7.16k | shout->checksum = 0; |
11937 | 7.16k | if (vtag) { |
11938 | 2.32k | shout->v_tag = htonl(vtag); |
11939 | 4.84k | } else { |
11940 | 4.84k | shout->v_tag = sh->v_tag; |
11941 | 4.84k | } |
11942 | 7.16k | len += sizeof(struct sctphdr); |
11943 | 7.16k | ch = (struct sctp_chunkhdr *)((caddr_t)shout + sizeof(struct sctphdr)); |
11944 | 7.16k | ch->chunk_type = type; |
11945 | 7.16k | if (vtag) { |
11946 | 2.32k | ch->chunk_flags = 0; |
11947 | 4.84k | } else { |
11948 | 4.84k | ch->chunk_flags = SCTP_HAD_NO_TCB; |
11949 | 4.84k | } |
11950 | 7.16k | ch->chunk_length = htons((uint16_t)(sizeof(struct sctp_chunkhdr) + cause_len)); |
11951 | 7.16k | len += sizeof(struct sctp_chunkhdr); |
11952 | 7.16k | len += cause_len + padding_len; |
11953 | | |
11954 | 7.16k | if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) { |
11955 | 0 | sctp_m_freem(mout); |
11956 | 0 | return; |
11957 | 0 | } |
11958 | 7.16k | SCTP_ATTACH_CHAIN(o_pak, mout, len); |
11959 | 7.16k | switch (dst->sa_family) { |
11960 | 0 | #ifdef INET |
11961 | 0 | case AF_INET: |
11962 | | #if defined(__APPLE__) && !defined(__Userspace__) |
11963 | | /* zap the stack pointer to the route */ |
11964 | | memset(&ro, 0, sizeof(sctp_route_t)); |
11965 | | #endif |
11966 | 0 | if (port) { |
11967 | | #if !defined(_WIN32) && !defined(__Userspace__) |
11968 | | #if defined(__FreeBSD__) |
11969 | | if (V_udp_cksum) { |
11970 | | udp->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); |
11971 | | } else { |
11972 | | udp->uh_sum = 0; |
11973 | | } |
11974 | | #else |
11975 | | udp->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); |
11976 | | #endif |
11977 | | #else |
11978 | 0 | udp->uh_sum = 0; |
11979 | 0 | #endif |
11980 | 0 | } |
11981 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
11982 | | ip->ip_len = htons(len); |
11983 | | #elif defined(__APPLE__) || defined(__Userspace__) |
11984 | | ip->ip_len = len; |
11985 | | #else |
11986 | | ip->ip_len = htons(len); |
11987 | | #endif |
11988 | 0 | if (port) { |
11989 | 0 | shout->checksum = sctp_calculate_cksum(mout, sizeof(struct ip) + sizeof(struct udphdr)); |
11990 | 0 | SCTP_STAT_INCR(sctps_sendswcrc); |
11991 | | #if !defined(_WIN32) && !defined(__Userspace__) |
11992 | | #if defined(__FreeBSD__) |
11993 | | if (V_udp_cksum) { |
11994 | | SCTP_ENABLE_UDP_CSUM(o_pak); |
11995 | | } |
11996 | | #else |
11997 | | SCTP_ENABLE_UDP_CSUM(o_pak); |
11998 | | #endif |
11999 | | #endif |
12000 | 0 | } else { |
12001 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
12002 | | mout->m_pkthdr.csum_flags = CSUM_SCTP; |
12003 | | mout->m_pkthdr.csum_data = offsetof(struct sctphdr, checksum); |
12004 | | SCTP_STAT_INCR(sctps_sendhwcrc); |
12005 | | #else |
12006 | 0 | shout->checksum = sctp_calculate_cksum(mout, sizeof(struct ip)); |
12007 | 0 | SCTP_STAT_INCR(sctps_sendswcrc); |
12008 | 0 | #endif |
12009 | 0 | } |
12010 | | #ifdef SCTP_PACKET_LOGGING |
12011 | | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) { |
12012 | | sctp_packet_log(o_pak); |
12013 | | } |
12014 | | #endif |
12015 | | #if defined(__APPLE__) && !defined(__Userspace__) |
12016 | | SCTP_IP_OUTPUT(ret, o_pak, &ro, NULL, vrf_id); |
12017 | | /* Free the route if we got one back */ |
12018 | | if (ro.ro_rt) { |
12019 | | RTFREE(ro.ro_rt); |
12020 | | ro.ro_rt = NULL; |
12021 | | } |
12022 | | #else |
12023 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
12024 | | SCTP_PROBE5(send, NULL, NULL, ip, NULL, shout); |
12025 | | #endif |
12026 | 0 | SCTP_IP_OUTPUT(ret, o_pak, NULL, NULL, vrf_id); |
12027 | 0 | #endif |
12028 | 0 | break; |
12029 | 0 | #endif |
12030 | 0 | #ifdef INET6 |
12031 | 0 | case AF_INET6: |
12032 | 0 | ip6->ip6_plen = htons((uint16_t)(len - sizeof(struct ip6_hdr))); |
12033 | 0 | if (port) { |
12034 | 0 | shout->checksum = sctp_calculate_cksum(mout, sizeof(struct ip6_hdr) + sizeof(struct udphdr)); |
12035 | 0 | SCTP_STAT_INCR(sctps_sendswcrc); |
12036 | | #if !defined(__Userspace__) |
12037 | | #if defined(_WIN32) |
12038 | | udp->uh_sum = 0; |
12039 | | #else |
12040 | | if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr))) == 0) { |
12041 | | udp->uh_sum = 0xffff; |
12042 | | } |
12043 | | #endif |
12044 | | #endif |
12045 | 0 | } else { |
12046 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
12047 | | mout->m_pkthdr.csum_flags = CSUM_SCTP_IPV6; |
12048 | | mout->m_pkthdr.csum_data = offsetof(struct sctphdr, checksum); |
12049 | | SCTP_STAT_INCR(sctps_sendhwcrc); |
12050 | | #else |
12051 | 0 | shout->checksum = sctp_calculate_cksum(mout, sizeof(struct ip6_hdr)); |
12052 | 0 | SCTP_STAT_INCR(sctps_sendswcrc); |
12053 | 0 | #endif |
12054 | 0 | } |
12055 | | #ifdef SCTP_PACKET_LOGGING |
12056 | | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) { |
12057 | | sctp_packet_log(o_pak); |
12058 | | } |
12059 | | #endif |
12060 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
12061 | | SCTP_PROBE5(send, NULL, NULL, ip6, NULL, shout); |
12062 | | #endif |
12063 | 0 | SCTP_IP6_OUTPUT(ret, o_pak, NULL, NULL, NULL, vrf_id); |
12064 | 0 | break; |
12065 | 0 | #endif |
12066 | 0 | #if defined(__Userspace__) |
12067 | 7.16k | case AF_CONN: |
12068 | 7.16k | { |
12069 | 7.16k | char *buffer; |
12070 | 7.16k | struct sockaddr_conn *sconn; |
12071 | | |
12072 | 7.16k | sconn = (struct sockaddr_conn *)src; |
12073 | 7.16k | if (SCTP_BASE_VAR(crc32c_offloaded) == 0) { |
12074 | 0 | shout->checksum = sctp_calculate_cksum(o_pak, 0); |
12075 | 0 | SCTP_STAT_INCR(sctps_sendswcrc); |
12076 | 7.16k | } else { |
12077 | 7.16k | SCTP_STAT_INCR(sctps_sendhwcrc); |
12078 | 7.16k | } |
12079 | | #ifdef SCTP_PACKET_LOGGING |
12080 | | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) { |
12081 | | sctp_packet_log(mout); |
12082 | | } |
12083 | | #endif |
12084 | | /* Don't alloc/free for each packet */ |
12085 | 7.16k | if ((buffer = malloc(len)) != NULL) { |
12086 | 7.16k | m_copydata(o_pak, 0, len, buffer); |
12087 | 7.16k | ret = SCTP_BASE_VAR(conn_output)(sconn->sconn_addr, buffer, len, 0, 0); |
12088 | 7.16k | free(buffer); |
12089 | 7.16k | } else { |
12090 | 0 | ret = ENOMEM; |
12091 | 0 | } |
12092 | 7.16k | sctp_m_freem(o_pak); |
12093 | 7.16k | break; |
12094 | 0 | } |
12095 | 0 | #endif |
12096 | 0 | default: |
12097 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Unknown protocol (TSNH) type %d\n", |
12098 | 0 | dst->sa_family); |
12099 | 0 | sctp_m_freem(mout); |
12100 | 0 | SCTP_LTRACE_ERR_RET_PKT(mout, NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT); |
12101 | 0 | return; |
12102 | 7.16k | } |
12103 | 7.16k | SCTPDBG(SCTP_DEBUG_OUTPUT3, "return from send is %d\n", ret); |
12104 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
12105 | | if (port) { |
12106 | | UDPSTAT_INC(udps_opackets); |
12107 | | } |
12108 | | #endif |
12109 | 7.16k | SCTP_STAT_INCR(sctps_sendpackets); |
12110 | 7.16k | SCTP_STAT_INCR_COUNTER64(sctps_outpackets); |
12111 | 7.16k | SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); |
12112 | 7.16k | if (ret) { |
12113 | 0 | SCTP_STAT_INCR(sctps_senderrors); |
12114 | 0 | } |
12115 | 7.16k | return; |
12116 | 7.16k | } |
12117 | | |
12118 | | void |
12119 | | sctp_send_shutdown_complete2(struct sockaddr *src, struct sockaddr *dst, |
12120 | | struct sctphdr *sh, |
12121 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
12122 | | uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum, |
12123 | | #endif |
12124 | | uint32_t vrf_id, uint16_t port) |
12125 | 0 | { |
12126 | 0 | sctp_send_resp_msg(src, dst, sh, 0, SCTP_SHUTDOWN_COMPLETE, NULL, |
12127 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
12128 | | mflowtype, mflowid, fibnum, |
12129 | | #endif |
12130 | 0 | vrf_id, port); |
12131 | 0 | } |
12132 | | |
12133 | | void |
12134 | | sctp_send_hb(struct sctp_tcb *stcb, struct sctp_nets *net,int so_locked) |
12135 | 0 | { |
12136 | 0 | struct sctp_tmit_chunk *chk; |
12137 | 0 | struct sctp_heartbeat_chunk *hb; |
12138 | 0 | struct timeval now; |
12139 | |
|
12140 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
12141 | 0 | if (net == NULL) { |
12142 | 0 | return; |
12143 | 0 | } |
12144 | 0 | (void)SCTP_GETTIME_TIMEVAL(&now); |
12145 | 0 | switch (net->ro._l_addr.sa.sa_family) { |
12146 | 0 | #ifdef INET |
12147 | 0 | case AF_INET: |
12148 | 0 | break; |
12149 | 0 | #endif |
12150 | 0 | #ifdef INET6 |
12151 | 0 | case AF_INET6: |
12152 | 0 | break; |
12153 | 0 | #endif |
12154 | 0 | #if defined(__Userspace__) |
12155 | 0 | case AF_CONN: |
12156 | 0 | break; |
12157 | 0 | #endif |
12158 | 0 | default: |
12159 | 0 | return; |
12160 | 0 | } |
12161 | 0 | sctp_alloc_a_chunk(stcb, chk); |
12162 | 0 | if (chk == NULL) { |
12163 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak, can't get a chunk for hb\n"); |
12164 | 0 | return; |
12165 | 0 | } |
12166 | | |
12167 | 0 | chk->copy_by_ref = 0; |
12168 | 0 | chk->rec.chunk_id.id = SCTP_HEARTBEAT_REQUEST; |
12169 | 0 | chk->rec.chunk_id.can_take_data = 1; |
12170 | 0 | chk->flags = 0; |
12171 | 0 | chk->asoc = &stcb->asoc; |
12172 | 0 | chk->send_size = sizeof(struct sctp_heartbeat_chunk); |
12173 | |
|
12174 | 0 | chk->data = sctp_get_mbuf_for_msg(chk->send_size, 0, M_NOWAIT, 1, MT_HEADER); |
12175 | 0 | if (chk->data == NULL) { |
12176 | 0 | sctp_free_a_chunk(stcb, chk, so_locked); |
12177 | 0 | return; |
12178 | 0 | } |
12179 | 0 | SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); |
12180 | 0 | SCTP_BUF_LEN(chk->data) = chk->send_size; |
12181 | 0 | chk->sent = SCTP_DATAGRAM_UNSENT; |
12182 | 0 | chk->snd_count = 0; |
12183 | 0 | chk->whoTo = net; |
12184 | 0 | atomic_add_int(&chk->whoTo->ref_count, 1); |
12185 | | /* Now we have a mbuf that we can fill in with the details */ |
12186 | 0 | hb = mtod(chk->data, struct sctp_heartbeat_chunk *); |
12187 | 0 | memset(hb, 0, sizeof(struct sctp_heartbeat_chunk)); |
12188 | | /* fill out chunk header */ |
12189 | 0 | hb->ch.chunk_type = SCTP_HEARTBEAT_REQUEST; |
12190 | 0 | hb->ch.chunk_flags = 0; |
12191 | 0 | hb->ch.chunk_length = htons(chk->send_size); |
12192 | | /* Fill out hb parameter */ |
12193 | 0 | hb->heartbeat.hb_info.ph.param_type = htons(SCTP_HEARTBEAT_INFO); |
12194 | 0 | hb->heartbeat.hb_info.ph.param_length = htons(sizeof(struct sctp_heartbeat_info_param)); |
12195 | 0 | hb->heartbeat.hb_info.time_value_1 = now.tv_sec; |
12196 | 0 | hb->heartbeat.hb_info.time_value_2 = now.tv_usec; |
12197 | | /* Did our user request this one, put it in */ |
12198 | 0 | hb->heartbeat.hb_info.addr_family = (uint8_t)net->ro._l_addr.sa.sa_family; |
12199 | | #ifdef HAVE_SA_LEN |
12200 | | hb->heartbeat.hb_info.addr_len = net->ro._l_addr.sa.sa_len; |
12201 | | #else |
12202 | 0 | switch (net->ro._l_addr.sa.sa_family) { |
12203 | 0 | #ifdef INET |
12204 | 0 | case AF_INET: |
12205 | 0 | hb->heartbeat.hb_info.addr_len = sizeof(struct sockaddr_in); |
12206 | 0 | break; |
12207 | 0 | #endif |
12208 | 0 | #ifdef INET6 |
12209 | 0 | case AF_INET6: |
12210 | 0 | hb->heartbeat.hb_info.addr_len = sizeof(struct sockaddr_in6); |
12211 | 0 | break; |
12212 | 0 | #endif |
12213 | 0 | #if defined(__Userspace__) |
12214 | 0 | case AF_CONN: |
12215 | 0 | hb->heartbeat.hb_info.addr_len = sizeof(struct sockaddr_conn); |
12216 | 0 | break; |
12217 | 0 | #endif |
12218 | 0 | default: |
12219 | 0 | hb->heartbeat.hb_info.addr_len = 0; |
12220 | 0 | break; |
12221 | 0 | } |
12222 | 0 | #endif |
12223 | 0 | if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { |
12224 | | /* |
12225 | | * we only take from the entropy pool if the address is not |
12226 | | * confirmed. |
12227 | | */ |
12228 | 0 | net->heartbeat_random1 = hb->heartbeat.hb_info.random_value1 = sctp_select_initial_TSN(&stcb->sctp_ep->sctp_ep); |
12229 | 0 | net->heartbeat_random2 = hb->heartbeat.hb_info.random_value2 = sctp_select_initial_TSN(&stcb->sctp_ep->sctp_ep); |
12230 | 0 | } else { |
12231 | 0 | net->heartbeat_random1 = hb->heartbeat.hb_info.random_value1 = 0; |
12232 | 0 | net->heartbeat_random2 = hb->heartbeat.hb_info.random_value2 = 0; |
12233 | 0 | } |
12234 | 0 | switch (net->ro._l_addr.sa.sa_family) { |
12235 | 0 | #ifdef INET |
12236 | 0 | case AF_INET: |
12237 | 0 | memcpy(hb->heartbeat.hb_info.address, |
12238 | 0 | &net->ro._l_addr.sin.sin_addr, |
12239 | 0 | sizeof(net->ro._l_addr.sin.sin_addr)); |
12240 | 0 | break; |
12241 | 0 | #endif |
12242 | 0 | #ifdef INET6 |
12243 | 0 | case AF_INET6: |
12244 | 0 | memcpy(hb->heartbeat.hb_info.address, |
12245 | 0 | &net->ro._l_addr.sin6.sin6_addr, |
12246 | 0 | sizeof(net->ro._l_addr.sin6.sin6_addr)); |
12247 | 0 | break; |
12248 | 0 | #endif |
12249 | 0 | #if defined(__Userspace__) |
12250 | 0 | case AF_CONN: |
12251 | 0 | memcpy(hb->heartbeat.hb_info.address, |
12252 | 0 | &net->ro._l_addr.sconn.sconn_addr, |
12253 | 0 | sizeof(net->ro._l_addr.sconn.sconn_addr)); |
12254 | 0 | break; |
12255 | 0 | #endif |
12256 | 0 | default: |
12257 | 0 | if (chk->data) { |
12258 | 0 | sctp_m_freem(chk->data); |
12259 | 0 | chk->data = NULL; |
12260 | 0 | } |
12261 | 0 | sctp_free_a_chunk(stcb, chk, so_locked); |
12262 | 0 | return; |
12263 | 0 | break; |
12264 | 0 | } |
12265 | 0 | net->hb_responded = 0; |
12266 | 0 | TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, chk, sctp_next); |
12267 | 0 | stcb->asoc.ctrl_queue_cnt++; |
12268 | 0 | SCTP_STAT_INCR(sctps_sendheartbeat); |
12269 | 0 | return; |
12270 | 0 | } |
12271 | | |
12272 | | void |
12273 | | sctp_send_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net, |
12274 | | uint32_t high_tsn) |
12275 | 0 | { |
12276 | 0 | struct sctp_association *asoc; |
12277 | 0 | struct sctp_ecne_chunk *ecne; |
12278 | 0 | struct sctp_tmit_chunk *chk; |
12279 | |
|
12280 | 0 | if (net == NULL) { |
12281 | 0 | return; |
12282 | 0 | } |
12283 | 0 | asoc = &stcb->asoc; |
12284 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
12285 | 0 | TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { |
12286 | 0 | if ((chk->rec.chunk_id.id == SCTP_ECN_ECHO) && (net == chk->whoTo)) { |
12287 | | /* found a previous ECN_ECHO update it if needed */ |
12288 | 0 | uint32_t cnt, ctsn; |
12289 | 0 | ecne = mtod(chk->data, struct sctp_ecne_chunk *); |
12290 | 0 | ctsn = ntohl(ecne->tsn); |
12291 | 0 | if (SCTP_TSN_GT(high_tsn, ctsn)) { |
12292 | 0 | ecne->tsn = htonl(high_tsn); |
12293 | 0 | SCTP_STAT_INCR(sctps_queue_upd_ecne); |
12294 | 0 | } |
12295 | 0 | cnt = ntohl(ecne->num_pkts_since_cwr); |
12296 | 0 | cnt++; |
12297 | 0 | ecne->num_pkts_since_cwr = htonl(cnt); |
12298 | 0 | return; |
12299 | 0 | } |
12300 | 0 | } |
12301 | | /* nope could not find one to update so we must build one */ |
12302 | 0 | sctp_alloc_a_chunk(stcb, chk); |
12303 | 0 | if (chk == NULL) { |
12304 | 0 | return; |
12305 | 0 | } |
12306 | 0 | SCTP_STAT_INCR(sctps_queue_upd_ecne); |
12307 | 0 | chk->copy_by_ref = 0; |
12308 | 0 | chk->rec.chunk_id.id = SCTP_ECN_ECHO; |
12309 | 0 | chk->rec.chunk_id.can_take_data = 0; |
12310 | 0 | chk->flags = 0; |
12311 | 0 | chk->asoc = &stcb->asoc; |
12312 | 0 | chk->send_size = sizeof(struct sctp_ecne_chunk); |
12313 | 0 | chk->data = sctp_get_mbuf_for_msg(chk->send_size, 0, M_NOWAIT, 1, MT_HEADER); |
12314 | 0 | if (chk->data == NULL) { |
12315 | 0 | sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); |
12316 | 0 | return; |
12317 | 0 | } |
12318 | 0 | SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); |
12319 | 0 | SCTP_BUF_LEN(chk->data) = chk->send_size; |
12320 | 0 | chk->sent = SCTP_DATAGRAM_UNSENT; |
12321 | 0 | chk->snd_count = 0; |
12322 | 0 | chk->whoTo = net; |
12323 | 0 | atomic_add_int(&chk->whoTo->ref_count, 1); |
12324 | |
|
12325 | 0 | stcb->asoc.ecn_echo_cnt_onq++; |
12326 | 0 | ecne = mtod(chk->data, struct sctp_ecne_chunk *); |
12327 | 0 | ecne->ch.chunk_type = SCTP_ECN_ECHO; |
12328 | 0 | ecne->ch.chunk_flags = 0; |
12329 | 0 | ecne->ch.chunk_length = htons(sizeof(struct sctp_ecne_chunk)); |
12330 | 0 | ecne->tsn = htonl(high_tsn); |
12331 | 0 | ecne->num_pkts_since_cwr = htonl(1); |
12332 | 0 | TAILQ_INSERT_HEAD(&stcb->asoc.control_send_queue, chk, sctp_next); |
12333 | 0 | asoc->ctrl_queue_cnt++; |
12334 | 0 | } |
12335 | | |
12336 | | void |
12337 | | sctp_send_packet_dropped(struct sctp_tcb *stcb, struct sctp_nets *net, |
12338 | | struct mbuf *m, int len, int iphlen, int bad_crc) |
12339 | 0 | { |
12340 | 0 | struct sctp_association *asoc; |
12341 | 0 | struct sctp_pktdrop_chunk *drp; |
12342 | 0 | struct sctp_tmit_chunk *chk; |
12343 | 0 | uint8_t *datap; |
12344 | 0 | int was_trunc = 0; |
12345 | 0 | int fullsz = 0; |
12346 | 0 | long spc; |
12347 | 0 | int offset; |
12348 | 0 | struct sctp_chunkhdr *ch, chunk_buf; |
12349 | 0 | unsigned int chk_length; |
12350 | |
|
12351 | 0 | if (!stcb) { |
12352 | 0 | return; |
12353 | 0 | } |
12354 | 0 | asoc = &stcb->asoc; |
12355 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
12356 | 0 | if (asoc->pktdrop_supported == 0) { |
12357 | | /*- |
12358 | | * peer must declare support before I send one. |
12359 | | */ |
12360 | 0 | return; |
12361 | 0 | } |
12362 | 0 | if (stcb->sctp_socket == NULL) { |
12363 | 0 | return; |
12364 | 0 | } |
12365 | 0 | sctp_alloc_a_chunk(stcb, chk); |
12366 | 0 | if (chk == NULL) { |
12367 | 0 | return; |
12368 | 0 | } |
12369 | 0 | chk->copy_by_ref = 0; |
12370 | 0 | chk->rec.chunk_id.id = SCTP_PACKET_DROPPED; |
12371 | 0 | chk->rec.chunk_id.can_take_data = 1; |
12372 | 0 | chk->flags = 0; |
12373 | 0 | len -= iphlen; |
12374 | 0 | chk->send_size = len; |
12375 | | /* Validate that we do not have an ABORT in here. */ |
12376 | 0 | offset = iphlen + sizeof(struct sctphdr); |
12377 | 0 | ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, |
12378 | 0 | sizeof(*ch), (uint8_t *) & chunk_buf); |
12379 | 0 | while (ch != NULL) { |
12380 | 0 | chk_length = ntohs(ch->chunk_length); |
12381 | 0 | if (chk_length < sizeof(*ch)) { |
12382 | | /* break to abort land */ |
12383 | 0 | break; |
12384 | 0 | } |
12385 | 0 | switch (ch->chunk_type) { |
12386 | 0 | case SCTP_PACKET_DROPPED: |
12387 | 0 | case SCTP_ABORT_ASSOCIATION: |
12388 | 0 | case SCTP_INITIATION_ACK: |
12389 | | /** |
12390 | | * We don't respond with an PKT-DROP to an ABORT |
12391 | | * or PKT-DROP. We also do not respond to an |
12392 | | * INIT-ACK, because we can't know if the initiation |
12393 | | * tag is correct or not. |
12394 | | */ |
12395 | 0 | sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); |
12396 | 0 | return; |
12397 | 0 | default: |
12398 | 0 | break; |
12399 | 0 | } |
12400 | 0 | offset += SCTP_SIZE32(chk_length); |
12401 | 0 | ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, |
12402 | 0 | sizeof(*ch), (uint8_t *) & chunk_buf); |
12403 | 0 | } |
12404 | | |
12405 | 0 | if ((len + SCTP_MAX_OVERHEAD + sizeof(struct sctp_pktdrop_chunk)) > |
12406 | 0 | min(stcb->asoc.smallest_mtu, MCLBYTES)) { |
12407 | | /* only send 1 mtu worth, trim off the |
12408 | | * excess on the end. |
12409 | | */ |
12410 | 0 | fullsz = len; |
12411 | 0 | len = min(stcb->asoc.smallest_mtu, MCLBYTES) - SCTP_MAX_OVERHEAD; |
12412 | 0 | was_trunc = 1; |
12413 | 0 | } |
12414 | 0 | chk->asoc = &stcb->asoc; |
12415 | 0 | chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); |
12416 | 0 | if (chk->data == NULL) { |
12417 | 0 | jump_out: |
12418 | 0 | sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); |
12419 | 0 | return; |
12420 | 0 | } |
12421 | 0 | SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); |
12422 | 0 | drp = mtod(chk->data, struct sctp_pktdrop_chunk *); |
12423 | 0 | if (drp == NULL) { |
12424 | 0 | sctp_m_freem(chk->data); |
12425 | 0 | chk->data = NULL; |
12426 | 0 | goto jump_out; |
12427 | 0 | } |
12428 | 0 | chk->book_size = SCTP_SIZE32((chk->send_size + sizeof(struct sctp_pktdrop_chunk) + |
12429 | 0 | sizeof(struct sctphdr) + SCTP_MED_OVERHEAD)); |
12430 | 0 | chk->book_size_scale = 0; |
12431 | 0 | if (was_trunc) { |
12432 | 0 | drp->ch.chunk_flags = SCTP_PACKET_TRUNCATED; |
12433 | 0 | drp->trunc_len = htons(fullsz); |
12434 | | /* Len is already adjusted to size minus overhead above |
12435 | | * take out the pkt_drop chunk itself from it. |
12436 | | */ |
12437 | 0 | chk->send_size = (uint16_t)(len - sizeof(struct sctp_pktdrop_chunk)); |
12438 | 0 | len = chk->send_size; |
12439 | 0 | } else { |
12440 | | /* no truncation needed */ |
12441 | 0 | drp->ch.chunk_flags = 0; |
12442 | 0 | drp->trunc_len = htons(0); |
12443 | 0 | } |
12444 | 0 | if (bad_crc) { |
12445 | 0 | drp->ch.chunk_flags |= SCTP_BADCRC; |
12446 | 0 | } |
12447 | 0 | chk->send_size += sizeof(struct sctp_pktdrop_chunk); |
12448 | 0 | SCTP_BUF_LEN(chk->data) = chk->send_size; |
12449 | 0 | chk->sent = SCTP_DATAGRAM_UNSENT; |
12450 | 0 | chk->snd_count = 0; |
12451 | 0 | if (net) { |
12452 | | /* we should hit here */ |
12453 | 0 | chk->whoTo = net; |
12454 | 0 | atomic_add_int(&chk->whoTo->ref_count, 1); |
12455 | 0 | } else { |
12456 | 0 | chk->whoTo = NULL; |
12457 | 0 | } |
12458 | 0 | drp->ch.chunk_type = SCTP_PACKET_DROPPED; |
12459 | 0 | drp->ch.chunk_length = htons(chk->send_size); |
12460 | 0 | spc = SCTP_SB_LIMIT_RCV(stcb->sctp_socket); |
12461 | 0 | if (spc < 0) { |
12462 | 0 | spc = 0; |
12463 | 0 | } |
12464 | 0 | drp->bottle_bw = htonl(spc); |
12465 | 0 | if (asoc->my_rwnd) { |
12466 | 0 | drp->current_onq = htonl(asoc->size_on_reasm_queue + |
12467 | 0 | asoc->size_on_all_streams + |
12468 | 0 | asoc->my_rwnd_control_len + |
12469 | 0 | SCTP_SBAVAIL(&stcb->sctp_socket->so_rcv)); |
12470 | 0 | } else { |
12471 | | /*- |
12472 | | * If my rwnd is 0, possibly from mbuf depletion as well as |
12473 | | * space used, tell the peer there is NO space aka onq == bw |
12474 | | */ |
12475 | 0 | drp->current_onq = htonl(spc); |
12476 | 0 | } |
12477 | 0 | drp->reserved = 0; |
12478 | 0 | datap = drp->data; |
12479 | 0 | m_copydata(m, iphlen, len, (caddr_t)datap); |
12480 | 0 | TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, chk, sctp_next); |
12481 | 0 | asoc->ctrl_queue_cnt++; |
12482 | 0 | } |
12483 | | |
12484 | | void |
12485 | | sctp_send_cwr(struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t high_tsn, uint8_t override) |
12486 | 0 | { |
12487 | 0 | struct sctp_association *asoc; |
12488 | 0 | struct sctp_cwr_chunk *cwr; |
12489 | 0 | struct sctp_tmit_chunk *chk; |
12490 | |
|
12491 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
12492 | 0 | if (net == NULL) { |
12493 | 0 | return; |
12494 | 0 | } |
12495 | 0 | asoc = &stcb->asoc; |
12496 | 0 | TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { |
12497 | 0 | if ((chk->rec.chunk_id.id == SCTP_ECN_CWR) && (net == chk->whoTo)) { |
12498 | | /* found a previous CWR queued to same destination update it if needed */ |
12499 | 0 | uint32_t ctsn; |
12500 | 0 | cwr = mtod(chk->data, struct sctp_cwr_chunk *); |
12501 | 0 | ctsn = ntohl(cwr->tsn); |
12502 | 0 | if (SCTP_TSN_GT(high_tsn, ctsn)) { |
12503 | 0 | cwr->tsn = htonl(high_tsn); |
12504 | 0 | } |
12505 | 0 | if (override & SCTP_CWR_REDUCE_OVERRIDE) { |
12506 | | /* Make sure override is carried */ |
12507 | 0 | cwr->ch.chunk_flags |= SCTP_CWR_REDUCE_OVERRIDE; |
12508 | 0 | } |
12509 | 0 | return; |
12510 | 0 | } |
12511 | 0 | } |
12512 | 0 | sctp_alloc_a_chunk(stcb, chk); |
12513 | 0 | if (chk == NULL) { |
12514 | 0 | return; |
12515 | 0 | } |
12516 | 0 | chk->copy_by_ref = 0; |
12517 | 0 | chk->rec.chunk_id.id = SCTP_ECN_CWR; |
12518 | 0 | chk->rec.chunk_id.can_take_data = 1; |
12519 | 0 | chk->flags = 0; |
12520 | 0 | chk->asoc = asoc; |
12521 | 0 | chk->send_size = sizeof(struct sctp_cwr_chunk); |
12522 | 0 | chk->data = sctp_get_mbuf_for_msg(chk->send_size, 0, M_NOWAIT, 1, MT_HEADER); |
12523 | 0 | if (chk->data == NULL) { |
12524 | 0 | sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); |
12525 | 0 | return; |
12526 | 0 | } |
12527 | 0 | SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); |
12528 | 0 | SCTP_BUF_LEN(chk->data) = chk->send_size; |
12529 | 0 | chk->sent = SCTP_DATAGRAM_UNSENT; |
12530 | 0 | chk->snd_count = 0; |
12531 | 0 | chk->whoTo = net; |
12532 | 0 | atomic_add_int(&chk->whoTo->ref_count, 1); |
12533 | 0 | cwr = mtod(chk->data, struct sctp_cwr_chunk *); |
12534 | 0 | cwr->ch.chunk_type = SCTP_ECN_CWR; |
12535 | 0 | cwr->ch.chunk_flags = override; |
12536 | 0 | cwr->ch.chunk_length = htons(sizeof(struct sctp_cwr_chunk)); |
12537 | 0 | cwr->tsn = htonl(high_tsn); |
12538 | 0 | TAILQ_INSERT_TAIL(&asoc->control_send_queue, chk, sctp_next); |
12539 | 0 | asoc->ctrl_queue_cnt++; |
12540 | 0 | } |
12541 | | |
12542 | | static int |
12543 | | sctp_add_stream_reset_out(struct sctp_tcb *stcb, struct sctp_tmit_chunk *chk, |
12544 | | uint32_t seq, uint32_t resp_seq, uint32_t last_sent) |
12545 | 0 | { |
12546 | 0 | uint16_t len, old_len, i; |
12547 | 0 | struct sctp_stream_reset_out_request *req_out; |
12548 | 0 | struct sctp_chunkhdr *ch; |
12549 | 0 | int at; |
12550 | 0 | int number_entries=0; |
12551 | |
|
12552 | 0 | ch = mtod(chk->data, struct sctp_chunkhdr *); |
12553 | 0 | old_len = len = SCTP_SIZE32(ntohs(ch->chunk_length)); |
12554 | | /* get to new offset for the param. */ |
12555 | 0 | req_out = (struct sctp_stream_reset_out_request *)((caddr_t)ch + len); |
12556 | | /* now how long will this param be? */ |
12557 | 0 | for (i = 0; i < stcb->asoc.streamoutcnt; i++) { |
12558 | 0 | if ((stcb->asoc.strmout[i].state == SCTP_STREAM_RESET_PENDING) && |
12559 | 0 | (stcb->asoc.strmout[i].chunks_on_queues == 0) && |
12560 | 0 | TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { |
12561 | 0 | number_entries++; |
12562 | 0 | } |
12563 | 0 | } |
12564 | 0 | if (number_entries == 0) { |
12565 | 0 | return (0); |
12566 | 0 | } |
12567 | 0 | if (number_entries == stcb->asoc.streamoutcnt) { |
12568 | 0 | number_entries = 0; |
12569 | 0 | } |
12570 | 0 | if (number_entries > SCTP_MAX_STREAMS_AT_ONCE_RESET) { |
12571 | 0 | number_entries = SCTP_MAX_STREAMS_AT_ONCE_RESET; |
12572 | 0 | } |
12573 | 0 | len = (uint16_t)(sizeof(struct sctp_stream_reset_out_request) + (sizeof(uint16_t) * number_entries)); |
12574 | 0 | req_out->ph.param_type = htons(SCTP_STR_RESET_OUT_REQUEST); |
12575 | 0 | req_out->ph.param_length = htons(len); |
12576 | 0 | req_out->request_seq = htonl(seq); |
12577 | 0 | req_out->response_seq = htonl(resp_seq); |
12578 | 0 | req_out->send_reset_at_tsn = htonl(last_sent); |
12579 | 0 | at = 0; |
12580 | 0 | if (number_entries) { |
12581 | 0 | for (i = 0; i < stcb->asoc.streamoutcnt; i++) { |
12582 | 0 | if ((stcb->asoc.strmout[i].state == SCTP_STREAM_RESET_PENDING) && |
12583 | 0 | (stcb->asoc.strmout[i].chunks_on_queues == 0) && |
12584 | 0 | TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { |
12585 | 0 | req_out->list_of_streams[at] = htons(i); |
12586 | 0 | at++; |
12587 | 0 | stcb->asoc.strmout[i].state = SCTP_STREAM_RESET_IN_FLIGHT; |
12588 | 0 | if (at >= number_entries) { |
12589 | 0 | break; |
12590 | 0 | } |
12591 | 0 | } |
12592 | 0 | } |
12593 | 0 | } else { |
12594 | 0 | for (i = 0; i < stcb->asoc.streamoutcnt; i++) { |
12595 | 0 | stcb->asoc.strmout[i].state = SCTP_STREAM_RESET_IN_FLIGHT; |
12596 | 0 | } |
12597 | 0 | } |
12598 | 0 | if (SCTP_SIZE32(len) > len) { |
12599 | | /*- |
12600 | | * Need to worry about the pad we may end up adding to the |
12601 | | * end. This is easy since the struct is either aligned to 4 |
12602 | | * bytes or 2 bytes off. |
12603 | | */ |
12604 | 0 | req_out->list_of_streams[number_entries] = 0; |
12605 | 0 | } |
12606 | | /* now fix the chunk length */ |
12607 | 0 | ch->chunk_length = htons(len + old_len); |
12608 | 0 | chk->book_size = len + old_len; |
12609 | 0 | chk->book_size_scale = 0; |
12610 | 0 | chk->send_size = SCTP_SIZE32(chk->book_size); |
12611 | 0 | SCTP_BUF_LEN(chk->data) = chk->send_size; |
12612 | 0 | return (1); |
12613 | 0 | } |
12614 | | |
12615 | | static void |
12616 | | sctp_add_stream_reset_in(struct sctp_tmit_chunk *chk, |
12617 | | int number_entries, uint16_t *list, |
12618 | | uint32_t seq) |
12619 | 0 | { |
12620 | 0 | uint16_t len, old_len, i; |
12621 | 0 | struct sctp_stream_reset_in_request *req_in; |
12622 | 0 | struct sctp_chunkhdr *ch; |
12623 | |
|
12624 | 0 | ch = mtod(chk->data, struct sctp_chunkhdr *); |
12625 | 0 | old_len = len = SCTP_SIZE32(ntohs(ch->chunk_length)); |
12626 | | |
12627 | | /* get to new offset for the param. */ |
12628 | 0 | req_in = (struct sctp_stream_reset_in_request *)((caddr_t)ch + len); |
12629 | | /* now how long will this param be? */ |
12630 | 0 | len = (uint16_t)(sizeof(struct sctp_stream_reset_in_request) + (sizeof(uint16_t) * number_entries)); |
12631 | 0 | req_in->ph.param_type = htons(SCTP_STR_RESET_IN_REQUEST); |
12632 | 0 | req_in->ph.param_length = htons(len); |
12633 | 0 | req_in->request_seq = htonl(seq); |
12634 | 0 | if (number_entries) { |
12635 | 0 | for (i = 0; i < number_entries; i++) { |
12636 | 0 | req_in->list_of_streams[i] = htons(list[i]); |
12637 | 0 | } |
12638 | 0 | } |
12639 | 0 | if (SCTP_SIZE32(len) > len) { |
12640 | | /*- |
12641 | | * Need to worry about the pad we may end up adding to the |
12642 | | * end. This is easy since the struct is either aligned to 4 |
12643 | | * bytes or 2 bytes off. |
12644 | | */ |
12645 | 0 | req_in->list_of_streams[number_entries] = 0; |
12646 | 0 | } |
12647 | | /* now fix the chunk length */ |
12648 | 0 | ch->chunk_length = htons(len + old_len); |
12649 | 0 | chk->book_size = len + old_len; |
12650 | 0 | chk->book_size_scale = 0; |
12651 | 0 | chk->send_size = SCTP_SIZE32(chk->book_size); |
12652 | 0 | SCTP_BUF_LEN(chk->data) = chk->send_size; |
12653 | 0 | return; |
12654 | 0 | } |
12655 | | |
12656 | | static void |
12657 | | sctp_add_stream_reset_tsn(struct sctp_tmit_chunk *chk, |
12658 | | uint32_t seq) |
12659 | 0 | { |
12660 | 0 | uint16_t len, old_len; |
12661 | 0 | struct sctp_stream_reset_tsn_request *req_tsn; |
12662 | 0 | struct sctp_chunkhdr *ch; |
12663 | |
|
12664 | 0 | ch = mtod(chk->data, struct sctp_chunkhdr *); |
12665 | 0 | old_len = len = SCTP_SIZE32(ntohs(ch->chunk_length)); |
12666 | | |
12667 | | /* get to new offset for the param. */ |
12668 | 0 | req_tsn = (struct sctp_stream_reset_tsn_request *)((caddr_t)ch + len); |
12669 | | /* now how long will this param be? */ |
12670 | 0 | len = sizeof(struct sctp_stream_reset_tsn_request); |
12671 | 0 | req_tsn->ph.param_type = htons(SCTP_STR_RESET_TSN_REQUEST); |
12672 | 0 | req_tsn->ph.param_length = htons(len); |
12673 | 0 | req_tsn->request_seq = htonl(seq); |
12674 | | |
12675 | | /* now fix the chunk length */ |
12676 | 0 | ch->chunk_length = htons(len + old_len); |
12677 | 0 | chk->send_size = len + old_len; |
12678 | 0 | chk->book_size = SCTP_SIZE32(chk->send_size); |
12679 | 0 | chk->book_size_scale = 0; |
12680 | 0 | SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size); |
12681 | 0 | return; |
12682 | 0 | } |
12683 | | |
12684 | | void |
12685 | | sctp_add_stream_reset_result(struct sctp_tmit_chunk *chk, |
12686 | | uint32_t resp_seq, uint32_t result) |
12687 | 0 | { |
12688 | 0 | uint16_t len, old_len; |
12689 | 0 | struct sctp_stream_reset_response *resp; |
12690 | 0 | struct sctp_chunkhdr *ch; |
12691 | |
|
12692 | 0 | ch = mtod(chk->data, struct sctp_chunkhdr *); |
12693 | 0 | old_len = len = SCTP_SIZE32(ntohs(ch->chunk_length)); |
12694 | | |
12695 | | /* get to new offset for the param. */ |
12696 | 0 | resp = (struct sctp_stream_reset_response *)((caddr_t)ch + len); |
12697 | | /* now how long will this param be? */ |
12698 | 0 | len = sizeof(struct sctp_stream_reset_response); |
12699 | 0 | resp->ph.param_type = htons(SCTP_STR_RESET_RESPONSE); |
12700 | 0 | resp->ph.param_length = htons(len); |
12701 | 0 | resp->response_seq = htonl(resp_seq); |
12702 | 0 | resp->result = ntohl(result); |
12703 | | |
12704 | | /* now fix the chunk length */ |
12705 | 0 | ch->chunk_length = htons(len + old_len); |
12706 | 0 | chk->book_size = len + old_len; |
12707 | 0 | chk->book_size_scale = 0; |
12708 | 0 | chk->send_size = SCTP_SIZE32(chk->book_size); |
12709 | 0 | SCTP_BUF_LEN(chk->data) = chk->send_size; |
12710 | 0 | return; |
12711 | 0 | } |
12712 | | |
12713 | | void |
12714 | | sctp_send_deferred_reset_response(struct sctp_tcb *stcb, |
12715 | | struct sctp_stream_reset_list *ent, |
12716 | | int response) |
12717 | 0 | { |
12718 | 0 | struct sctp_association *asoc; |
12719 | 0 | struct sctp_tmit_chunk *chk; |
12720 | 0 | struct sctp_chunkhdr *ch; |
12721 | |
|
12722 | 0 | asoc = &stcb->asoc; |
12723 | | |
12724 | | /* |
12725 | | * Reset our last reset action to the new one IP -> response |
12726 | | * (PERFORMED probably). This assures that if we fail to send, a |
12727 | | * retran from the peer will get the new response. |
12728 | | */ |
12729 | 0 | asoc->last_reset_action[0] = response; |
12730 | 0 | if (asoc->stream_reset_outstanding) { |
12731 | 0 | return; |
12732 | 0 | } |
12733 | 0 | sctp_alloc_a_chunk(stcb, chk); |
12734 | 0 | if (chk == NULL) { |
12735 | 0 | SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
12736 | 0 | return; |
12737 | 0 | } |
12738 | 0 | chk->copy_by_ref = 0; |
12739 | 0 | chk->rec.chunk_id.id = SCTP_STREAM_RESET; |
12740 | 0 | chk->rec.chunk_id.can_take_data = 0; |
12741 | 0 | chk->flags = 0; |
12742 | 0 | chk->asoc = &stcb->asoc; |
12743 | 0 | chk->book_size = sizeof(struct sctp_chunkhdr); |
12744 | 0 | chk->send_size = SCTP_SIZE32(chk->book_size); |
12745 | 0 | chk->book_size_scale = 0; |
12746 | 0 | chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); |
12747 | 0 | if (chk->data == NULL) { |
12748 | 0 | sctp_free_a_chunk(stcb, chk, SCTP_SO_LOCKED); |
12749 | 0 | SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
12750 | 0 | return; |
12751 | 0 | } |
12752 | 0 | SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); |
12753 | | /* setup chunk parameters */ |
12754 | 0 | chk->sent = SCTP_DATAGRAM_UNSENT; |
12755 | 0 | chk->snd_count = 0; |
12756 | 0 | if (stcb->asoc.alternate) { |
12757 | 0 | chk->whoTo = stcb->asoc.alternate; |
12758 | 0 | } else { |
12759 | 0 | chk->whoTo = stcb->asoc.primary_destination; |
12760 | 0 | } |
12761 | 0 | ch = mtod(chk->data, struct sctp_chunkhdr *); |
12762 | 0 | ch->chunk_type = SCTP_STREAM_RESET; |
12763 | 0 | ch->chunk_flags = 0; |
12764 | 0 | ch->chunk_length = htons(chk->book_size); |
12765 | 0 | atomic_add_int(&chk->whoTo->ref_count, 1); |
12766 | 0 | SCTP_BUF_LEN(chk->data) = chk->send_size; |
12767 | 0 | sctp_add_stream_reset_result(chk, ent->seq, response); |
12768 | | /* insert the chunk for sending */ |
12769 | 0 | TAILQ_INSERT_TAIL(&asoc->control_send_queue, |
12770 | 0 | chk, |
12771 | 0 | sctp_next); |
12772 | 0 | asoc->ctrl_queue_cnt++; |
12773 | 0 | } |
12774 | | |
12775 | | void |
12776 | | sctp_add_stream_reset_result_tsn(struct sctp_tmit_chunk *chk, |
12777 | | uint32_t resp_seq, uint32_t result, |
12778 | | uint32_t send_una, uint32_t recv_next) |
12779 | 0 | { |
12780 | 0 | uint16_t len, old_len; |
12781 | 0 | struct sctp_stream_reset_response_tsn *resp; |
12782 | 0 | struct sctp_chunkhdr *ch; |
12783 | |
|
12784 | 0 | ch = mtod(chk->data, struct sctp_chunkhdr *); |
12785 | 0 | old_len = len = SCTP_SIZE32(ntohs(ch->chunk_length)); |
12786 | | |
12787 | | /* get to new offset for the param. */ |
12788 | 0 | resp = (struct sctp_stream_reset_response_tsn *)((caddr_t)ch + len); |
12789 | | /* now how long will this param be? */ |
12790 | 0 | len = sizeof(struct sctp_stream_reset_response_tsn); |
12791 | 0 | resp->ph.param_type = htons(SCTP_STR_RESET_RESPONSE); |
12792 | 0 | resp->ph.param_length = htons(len); |
12793 | 0 | resp->response_seq = htonl(resp_seq); |
12794 | 0 | resp->result = htonl(result); |
12795 | 0 | resp->senders_next_tsn = htonl(send_una); |
12796 | 0 | resp->receivers_next_tsn = htonl(recv_next); |
12797 | | |
12798 | | /* now fix the chunk length */ |
12799 | 0 | ch->chunk_length = htons(len + old_len); |
12800 | 0 | chk->book_size = len + old_len; |
12801 | 0 | chk->send_size = SCTP_SIZE32(chk->book_size); |
12802 | 0 | chk->book_size_scale = 0; |
12803 | 0 | SCTP_BUF_LEN(chk->data) = chk->send_size; |
12804 | 0 | return; |
12805 | 0 | } |
12806 | | |
12807 | | static void |
12808 | | sctp_add_an_out_stream(struct sctp_tmit_chunk *chk, |
12809 | | uint32_t seq, |
12810 | | uint16_t adding) |
12811 | 0 | { |
12812 | 0 | uint16_t len, old_len; |
12813 | 0 | struct sctp_chunkhdr *ch; |
12814 | 0 | struct sctp_stream_reset_add_strm *addstr; |
12815 | |
|
12816 | 0 | ch = mtod(chk->data, struct sctp_chunkhdr *); |
12817 | 0 | old_len = len = SCTP_SIZE32(ntohs(ch->chunk_length)); |
12818 | | |
12819 | | /* get to new offset for the param. */ |
12820 | 0 | addstr = (struct sctp_stream_reset_add_strm *)((caddr_t)ch + len); |
12821 | | /* now how long will this param be? */ |
12822 | 0 | len = sizeof(struct sctp_stream_reset_add_strm); |
12823 | | |
12824 | | /* Fill it out. */ |
12825 | 0 | addstr->ph.param_type = htons(SCTP_STR_RESET_ADD_OUT_STREAMS); |
12826 | 0 | addstr->ph.param_length = htons(len); |
12827 | 0 | addstr->request_seq = htonl(seq); |
12828 | 0 | addstr->number_of_streams = htons(adding); |
12829 | 0 | addstr->reserved = 0; |
12830 | | |
12831 | | /* now fix the chunk length */ |
12832 | 0 | ch->chunk_length = htons(len + old_len); |
12833 | 0 | chk->send_size = len + old_len; |
12834 | 0 | chk->book_size = SCTP_SIZE32(chk->send_size); |
12835 | 0 | chk->book_size_scale = 0; |
12836 | 0 | SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size); |
12837 | 0 | return; |
12838 | 0 | } |
12839 | | |
12840 | | static void |
12841 | | sctp_add_an_in_stream(struct sctp_tmit_chunk *chk, |
12842 | | uint32_t seq, |
12843 | | uint16_t adding) |
12844 | 0 | { |
12845 | 0 | uint16_t len, old_len; |
12846 | 0 | struct sctp_chunkhdr *ch; |
12847 | 0 | struct sctp_stream_reset_add_strm *addstr; |
12848 | |
|
12849 | 0 | ch = mtod(chk->data, struct sctp_chunkhdr *); |
12850 | 0 | old_len = len = SCTP_SIZE32(ntohs(ch->chunk_length)); |
12851 | | |
12852 | | /* get to new offset for the param. */ |
12853 | 0 | addstr = (struct sctp_stream_reset_add_strm *)((caddr_t)ch + len); |
12854 | | /* now how long will this param be? */ |
12855 | 0 | len = sizeof(struct sctp_stream_reset_add_strm); |
12856 | | /* Fill it out. */ |
12857 | 0 | addstr->ph.param_type = htons(SCTP_STR_RESET_ADD_IN_STREAMS); |
12858 | 0 | addstr->ph.param_length = htons(len); |
12859 | 0 | addstr->request_seq = htonl(seq); |
12860 | 0 | addstr->number_of_streams = htons(adding); |
12861 | 0 | addstr->reserved = 0; |
12862 | | |
12863 | | /* now fix the chunk length */ |
12864 | 0 | ch->chunk_length = htons(len + old_len); |
12865 | 0 | chk->send_size = len + old_len; |
12866 | 0 | chk->book_size = SCTP_SIZE32(chk->send_size); |
12867 | 0 | chk->book_size_scale = 0; |
12868 | 0 | SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size); |
12869 | 0 | return; |
12870 | 0 | } |
12871 | | |
12872 | | int |
12873 | | sctp_send_stream_reset_out_if_possible(struct sctp_tcb *stcb, int so_locked) |
12874 | 0 | { |
12875 | 0 | struct sctp_association *asoc; |
12876 | 0 | struct sctp_tmit_chunk *chk; |
12877 | 0 | struct sctp_chunkhdr *ch; |
12878 | 0 | uint32_t seq; |
12879 | |
|
12880 | 0 | asoc = &stcb->asoc; |
12881 | 0 | asoc->trigger_reset = 0; |
12882 | 0 | if (asoc->stream_reset_outstanding) { |
12883 | 0 | return (EALREADY); |
12884 | 0 | } |
12885 | 0 | sctp_alloc_a_chunk(stcb, chk); |
12886 | 0 | if (chk == NULL) { |
12887 | 0 | SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
12888 | 0 | return (ENOMEM); |
12889 | 0 | } |
12890 | 0 | chk->copy_by_ref = 0; |
12891 | 0 | chk->rec.chunk_id.id = SCTP_STREAM_RESET; |
12892 | 0 | chk->rec.chunk_id.can_take_data = 0; |
12893 | 0 | chk->flags = 0; |
12894 | 0 | chk->asoc = &stcb->asoc; |
12895 | 0 | chk->book_size = sizeof(struct sctp_chunkhdr); |
12896 | 0 | chk->send_size = SCTP_SIZE32(chk->book_size); |
12897 | 0 | chk->book_size_scale = 0; |
12898 | 0 | chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); |
12899 | 0 | if (chk->data == NULL) { |
12900 | 0 | sctp_free_a_chunk(stcb, chk, so_locked); |
12901 | 0 | SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
12902 | 0 | return (ENOMEM); |
12903 | 0 | } |
12904 | 0 | SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); |
12905 | | |
12906 | | /* setup chunk parameters */ |
12907 | 0 | chk->sent = SCTP_DATAGRAM_UNSENT; |
12908 | 0 | chk->snd_count = 0; |
12909 | 0 | if (stcb->asoc.alternate) { |
12910 | 0 | chk->whoTo = stcb->asoc.alternate; |
12911 | 0 | } else { |
12912 | 0 | chk->whoTo = stcb->asoc.primary_destination; |
12913 | 0 | } |
12914 | 0 | ch = mtod(chk->data, struct sctp_chunkhdr *); |
12915 | 0 | ch->chunk_type = SCTP_STREAM_RESET; |
12916 | 0 | ch->chunk_flags = 0; |
12917 | 0 | ch->chunk_length = htons(chk->book_size); |
12918 | 0 | atomic_add_int(&chk->whoTo->ref_count, 1); |
12919 | 0 | SCTP_BUF_LEN(chk->data) = chk->send_size; |
12920 | 0 | seq = stcb->asoc.str_reset_seq_out; |
12921 | 0 | if (sctp_add_stream_reset_out(stcb, chk, seq, (stcb->asoc.str_reset_seq_in - 1), (stcb->asoc.sending_seq - 1))) { |
12922 | 0 | seq++; |
12923 | 0 | asoc->stream_reset_outstanding++; |
12924 | 0 | } else { |
12925 | 0 | m_freem(chk->data); |
12926 | 0 | chk->data = NULL; |
12927 | 0 | sctp_free_a_chunk(stcb, chk, so_locked); |
12928 | 0 | return (ENOENT); |
12929 | 0 | } |
12930 | 0 | asoc->str_reset = chk; |
12931 | | /* insert the chunk for sending */ |
12932 | 0 | TAILQ_INSERT_TAIL(&asoc->control_send_queue, |
12933 | 0 | chk, |
12934 | 0 | sctp_next); |
12935 | 0 | asoc->ctrl_queue_cnt++; |
12936 | |
|
12937 | 0 | if (stcb->asoc.send_sack) { |
12938 | 0 | sctp_send_sack(stcb, so_locked); |
12939 | 0 | } |
12940 | 0 | sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, stcb->sctp_ep, stcb, chk->whoTo); |
12941 | 0 | return (0); |
12942 | 0 | } |
12943 | | |
12944 | | int |
12945 | | sctp_send_str_reset_req(struct sctp_tcb *stcb, |
12946 | | uint16_t number_entries, uint16_t *list, |
12947 | | uint8_t send_in_req, |
12948 | | uint8_t send_tsn_req, |
12949 | | uint8_t add_stream, |
12950 | | uint16_t adding_o, |
12951 | | uint16_t adding_i, uint8_t peer_asked) |
12952 | 0 | { |
12953 | 0 | struct sctp_association *asoc; |
12954 | 0 | struct sctp_tmit_chunk *chk; |
12955 | 0 | struct sctp_chunkhdr *ch; |
12956 | 0 | int can_send_out_req=0; |
12957 | 0 | uint32_t seq; |
12958 | |
|
12959 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
12960 | | |
12961 | 0 | asoc = &stcb->asoc; |
12962 | 0 | if (asoc->stream_reset_outstanding) { |
12963 | | /*- |
12964 | | * Already one pending, must get ACK back to clear the flag. |
12965 | | */ |
12966 | 0 | SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EBUSY); |
12967 | 0 | return (EBUSY); |
12968 | 0 | } |
12969 | 0 | if ((send_in_req == 0) && (send_tsn_req == 0) && |
12970 | 0 | (add_stream == 0)) { |
12971 | | /* nothing to do */ |
12972 | 0 | SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL); |
12973 | 0 | return (EINVAL); |
12974 | 0 | } |
12975 | 0 | if (send_tsn_req && send_in_req) { |
12976 | | /* error, can't do that */ |
12977 | 0 | SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL); |
12978 | 0 | return (EINVAL); |
12979 | 0 | } else if (send_in_req) { |
12980 | 0 | can_send_out_req = 1; |
12981 | 0 | } |
12982 | 0 | if (number_entries > (MCLBYTES - |
12983 | 0 | SCTP_MIN_OVERHEAD - |
12984 | 0 | sizeof(struct sctp_chunkhdr) - |
12985 | 0 | sizeof(struct sctp_stream_reset_out_request)) / |
12986 | 0 | sizeof(uint16_t)) { |
12987 | 0 | SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
12988 | 0 | return (ENOMEM); |
12989 | 0 | } |
12990 | 0 | sctp_alloc_a_chunk(stcb, chk); |
12991 | 0 | if (chk == NULL) { |
12992 | 0 | SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
12993 | 0 | return (ENOMEM); |
12994 | 0 | } |
12995 | 0 | chk->copy_by_ref = 0; |
12996 | 0 | chk->rec.chunk_id.id = SCTP_STREAM_RESET; |
12997 | 0 | chk->rec.chunk_id.can_take_data = 0; |
12998 | 0 | chk->flags = 0; |
12999 | 0 | chk->asoc = &stcb->asoc; |
13000 | 0 | chk->book_size = sizeof(struct sctp_chunkhdr); |
13001 | 0 | chk->send_size = SCTP_SIZE32(chk->book_size); |
13002 | 0 | chk->book_size_scale = 0; |
13003 | 0 | chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); |
13004 | 0 | if (chk->data == NULL) { |
13005 | 0 | sctp_free_a_chunk(stcb, chk, SCTP_SO_LOCKED); |
13006 | 0 | SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
13007 | 0 | return (ENOMEM); |
13008 | 0 | } |
13009 | 0 | SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); |
13010 | | |
13011 | | /* setup chunk parameters */ |
13012 | 0 | chk->sent = SCTP_DATAGRAM_UNSENT; |
13013 | 0 | chk->snd_count = 0; |
13014 | 0 | if (stcb->asoc.alternate) { |
13015 | 0 | chk->whoTo = stcb->asoc.alternate; |
13016 | 0 | } else { |
13017 | 0 | chk->whoTo = stcb->asoc.primary_destination; |
13018 | 0 | } |
13019 | 0 | atomic_add_int(&chk->whoTo->ref_count, 1); |
13020 | 0 | ch = mtod(chk->data, struct sctp_chunkhdr *); |
13021 | 0 | ch->chunk_type = SCTP_STREAM_RESET; |
13022 | 0 | ch->chunk_flags = 0; |
13023 | 0 | ch->chunk_length = htons(chk->book_size); |
13024 | 0 | SCTP_BUF_LEN(chk->data) = chk->send_size; |
13025 | |
|
13026 | 0 | seq = stcb->asoc.str_reset_seq_out; |
13027 | 0 | if (can_send_out_req) { |
13028 | 0 | int ret; |
13029 | |
|
13030 | 0 | ret = sctp_add_stream_reset_out(stcb, chk, seq, (stcb->asoc.str_reset_seq_in - 1), (stcb->asoc.sending_seq - 1)); |
13031 | 0 | if (ret) { |
13032 | 0 | seq++; |
13033 | 0 | asoc->stream_reset_outstanding++; |
13034 | 0 | } |
13035 | 0 | } |
13036 | 0 | if ((add_stream & 1) && |
13037 | 0 | ((stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt) < adding_o)) { |
13038 | | /* Need to allocate more */ |
13039 | 0 | struct sctp_stream_out *oldstream; |
13040 | 0 | struct sctp_stream_queue_pending *sp, *nsp; |
13041 | 0 | int i; |
13042 | | #if defined(SCTP_DETAILED_STR_STATS) |
13043 | | int j; |
13044 | | #endif |
13045 | |
|
13046 | 0 | oldstream = stcb->asoc.strmout; |
13047 | | /* get some more */ |
13048 | 0 | SCTP_MALLOC(stcb->asoc.strmout, struct sctp_stream_out *, |
13049 | 0 | (stcb->asoc.streamoutcnt + adding_o) * sizeof(struct sctp_stream_out), |
13050 | 0 | SCTP_M_STRMO); |
13051 | 0 | if (stcb->asoc.strmout == NULL) { |
13052 | 0 | uint8_t x; |
13053 | 0 | stcb->asoc.strmout = oldstream; |
13054 | | /* Turn off the bit */ |
13055 | 0 | x = add_stream & 0xfe; |
13056 | 0 | add_stream = x; |
13057 | 0 | goto skip_stuff; |
13058 | 0 | } |
13059 | | /* Ok now we proceed with copying the old out stuff and |
13060 | | * initializing the new stuff. |
13061 | | */ |
13062 | 0 | stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, false); |
13063 | 0 | for (i = 0; i < stcb->asoc.streamoutcnt; i++) { |
13064 | 0 | TAILQ_INIT(&stcb->asoc.strmout[i].outqueue); |
13065 | | /* FIX ME FIX ME */ |
13066 | | /* This should be a SS_COPY operation FIX ME STREAM SCHEDULER EXPERT */ |
13067 | 0 | stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], &oldstream[i]); |
13068 | 0 | stcb->asoc.strmout[i].chunks_on_queues = oldstream[i].chunks_on_queues; |
13069 | | #if defined(SCTP_DETAILED_STR_STATS) |
13070 | | for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) { |
13071 | | stcb->asoc.strmout[i].abandoned_sent[j] = oldstream[i].abandoned_sent[j]; |
13072 | | stcb->asoc.strmout[i].abandoned_unsent[j] = oldstream[i].abandoned_unsent[j]; |
13073 | | } |
13074 | | #else |
13075 | 0 | stcb->asoc.strmout[i].abandoned_sent[0] = oldstream[i].abandoned_sent[0]; |
13076 | 0 | stcb->asoc.strmout[i].abandoned_unsent[0] = oldstream[i].abandoned_unsent[0]; |
13077 | 0 | #endif |
13078 | 0 | stcb->asoc.strmout[i].next_mid_ordered = oldstream[i].next_mid_ordered; |
13079 | 0 | stcb->asoc.strmout[i].next_mid_unordered = oldstream[i].next_mid_unordered; |
13080 | 0 | stcb->asoc.strmout[i].last_msg_incomplete = oldstream[i].last_msg_incomplete; |
13081 | 0 | stcb->asoc.strmout[i].sid = i; |
13082 | 0 | stcb->asoc.strmout[i].state = oldstream[i].state; |
13083 | | /* now anything on those queues? */ |
13084 | 0 | TAILQ_FOREACH_SAFE(sp, &oldstream[i].outqueue, next, nsp) { |
13085 | 0 | TAILQ_REMOVE(&oldstream[i].outqueue, sp, next); |
13086 | 0 | TAILQ_INSERT_TAIL(&stcb->asoc.strmout[i].outqueue, sp, next); |
13087 | 0 | } |
13088 | 0 | } |
13089 | | /* now the new streams */ |
13090 | 0 | stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc); |
13091 | 0 | for (i = stcb->asoc.streamoutcnt; i < (stcb->asoc.streamoutcnt + adding_o); i++) { |
13092 | 0 | TAILQ_INIT(&stcb->asoc.strmout[i].outqueue); |
13093 | 0 | stcb->asoc.strmout[i].chunks_on_queues = 0; |
13094 | | #if defined(SCTP_DETAILED_STR_STATS) |
13095 | | for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) { |
13096 | | stcb->asoc.strmout[i].abandoned_sent[j] = 0; |
13097 | | stcb->asoc.strmout[i].abandoned_unsent[j] = 0; |
13098 | | } |
13099 | | #else |
13100 | 0 | stcb->asoc.strmout[i].abandoned_sent[0] = 0; |
13101 | 0 | stcb->asoc.strmout[i].abandoned_unsent[0] = 0; |
13102 | 0 | #endif |
13103 | 0 | stcb->asoc.strmout[i].next_mid_ordered = 0; |
13104 | 0 | stcb->asoc.strmout[i].next_mid_unordered = 0; |
13105 | 0 | stcb->asoc.strmout[i].sid = i; |
13106 | 0 | stcb->asoc.strmout[i].last_msg_incomplete = 0; |
13107 | 0 | stcb->asoc.ss_functions.sctp_ss_init_stream(stcb, &stcb->asoc.strmout[i], NULL); |
13108 | 0 | stcb->asoc.strmout[i].state = SCTP_STREAM_CLOSED; |
13109 | 0 | } |
13110 | 0 | stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + adding_o; |
13111 | 0 | SCTP_FREE(oldstream, SCTP_M_STRMO); |
13112 | 0 | } |
13113 | 0 | skip_stuff: |
13114 | 0 | if ((add_stream & 1) && (adding_o > 0)) { |
13115 | 0 | asoc->strm_pending_add_size = adding_o; |
13116 | 0 | asoc->peer_req_out = peer_asked; |
13117 | 0 | sctp_add_an_out_stream(chk, seq, adding_o); |
13118 | 0 | seq++; |
13119 | 0 | asoc->stream_reset_outstanding++; |
13120 | 0 | } |
13121 | 0 | if ((add_stream & 2) && (adding_i > 0)) { |
13122 | 0 | sctp_add_an_in_stream(chk, seq, adding_i); |
13123 | 0 | seq++; |
13124 | 0 | asoc->stream_reset_outstanding++; |
13125 | 0 | } |
13126 | 0 | if (send_in_req) { |
13127 | 0 | sctp_add_stream_reset_in(chk, number_entries, list, seq); |
13128 | 0 | seq++; |
13129 | 0 | asoc->stream_reset_outstanding++; |
13130 | 0 | } |
13131 | 0 | if (send_tsn_req) { |
13132 | 0 | sctp_add_stream_reset_tsn(chk, seq); |
13133 | 0 | asoc->stream_reset_outstanding++; |
13134 | 0 | } |
13135 | 0 | asoc->str_reset = chk; |
13136 | | /* insert the chunk for sending */ |
13137 | 0 | TAILQ_INSERT_TAIL(&asoc->control_send_queue, |
13138 | 0 | chk, |
13139 | 0 | sctp_next); |
13140 | 0 | asoc->ctrl_queue_cnt++; |
13141 | 0 | if (stcb->asoc.send_sack) { |
13142 | 0 | sctp_send_sack(stcb, SCTP_SO_LOCKED); |
13143 | 0 | } |
13144 | 0 | sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, stcb->sctp_ep, stcb, chk->whoTo); |
13145 | 0 | return (0); |
13146 | 0 | } |
13147 | | |
13148 | | void |
13149 | | sctp_send_abort(struct mbuf *m, int iphlen, struct sockaddr *src, struct sockaddr *dst, |
13150 | | struct sctphdr *sh, uint32_t vtag, struct mbuf *cause, |
13151 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
13152 | | uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum, |
13153 | | #endif |
13154 | | uint32_t vrf_id, uint16_t port) |
13155 | 0 | { |
13156 | | /* Don't respond to an ABORT with an ABORT. */ |
13157 | 0 | if (sctp_is_there_an_abort_here(m, iphlen, &vtag)) { |
13158 | 0 | if (cause) |
13159 | 0 | sctp_m_freem(cause); |
13160 | 0 | return; |
13161 | 0 | } |
13162 | 0 | sctp_send_resp_msg(src, dst, sh, vtag, SCTP_ABORT_ASSOCIATION, cause, |
13163 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
13164 | | mflowtype, mflowid, fibnum, |
13165 | | #endif |
13166 | 0 | vrf_id, port); |
13167 | 0 | return; |
13168 | 0 | } |
13169 | | |
13170 | | void |
13171 | | sctp_send_operr_to(struct sockaddr *src, struct sockaddr *dst, |
13172 | | struct sctphdr *sh, uint32_t vtag, struct mbuf *cause, |
13173 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
13174 | | uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum, |
13175 | | #endif |
13176 | | uint32_t vrf_id, uint16_t port) |
13177 | 7.16k | { |
13178 | 7.16k | sctp_send_resp_msg(src, dst, sh, vtag, SCTP_OPERATION_ERROR, cause, |
13179 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
13180 | | mflowtype, mflowid, fibnum, |
13181 | | #endif |
13182 | 7.16k | vrf_id, port); |
13183 | 7.16k | return; |
13184 | 7.16k | } |
13185 | | |
13186 | | static struct mbuf * |
13187 | | sctp_copy_resume(struct uio *uio, |
13188 | | int max_send_len, |
13189 | | #if defined(__FreeBSD__) || defined(__Userspace__) |
13190 | | int user_marks_eor, |
13191 | | #endif |
13192 | | int *error, |
13193 | | uint32_t *sndout, |
13194 | | struct mbuf **new_tail) |
13195 | 0 | { |
13196 | 0 | #if defined(__FreeBSD__) || defined(__Userspace__) |
13197 | 0 | struct mbuf *m; |
13198 | |
|
13199 | 0 | m = m_uiotombuf(uio, M_WAITOK, max_send_len, 0, |
13200 | 0 | (M_PKTHDR | (user_marks_eor ? M_EOR : 0))); |
13201 | 0 | if (m == NULL) { |
13202 | | /* The only possible error is EFAULT. */ |
13203 | 0 | SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT); |
13204 | 0 | *error = EFAULT; |
13205 | 0 | } else { |
13206 | 0 | *sndout = m_length(m, NULL); |
13207 | 0 | *new_tail = m_last(m); |
13208 | 0 | } |
13209 | 0 | return (m); |
13210 | | #else |
13211 | | int left, cancpy, willcpy; |
13212 | | struct mbuf *m, *head; |
13213 | | |
13214 | | #if defined(__APPLE__) && !defined(__Userspace__) |
13215 | | #if defined(APPLE_LEOPARD) |
13216 | | left = (int)min(uio->uio_resid, max_send_len); |
13217 | | #else |
13218 | | left = (int)min(uio_resid(uio), max_send_len); |
13219 | | #endif |
13220 | | #else |
13221 | | left = (int)min(uio->uio_resid, max_send_len); |
13222 | | #endif |
13223 | | /* Always get a header just in case */ |
13224 | | head = sctp_get_mbuf_for_msg(left, 0, M_WAITOK, 0, MT_DATA); |
13225 | | if (head == NULL) { |
13226 | | SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); |
13227 | | *error = ENOBUFS; |
13228 | | return (NULL); |
13229 | | } |
13230 | | cancpy = (int)M_TRAILINGSPACE(head); |
13231 | | willcpy = min(cancpy, left); |
13232 | | *error = uiomove(mtod(head, caddr_t), willcpy, uio); |
13233 | | if (*error != 0) { |
13234 | | sctp_m_freem(head); |
13235 | | return (NULL); |
13236 | | } |
13237 | | *sndout += willcpy; |
13238 | | left -= willcpy; |
13239 | | SCTP_BUF_LEN(head) = willcpy; |
13240 | | m = head; |
13241 | | *new_tail = head; |
13242 | | while (left > 0) { |
13243 | | /* move in user data */ |
13244 | | SCTP_BUF_NEXT(m) = sctp_get_mbuf_for_msg(left, 0, M_WAITOK, 0, MT_DATA); |
13245 | | if (SCTP_BUF_NEXT(m) == NULL) { |
13246 | | sctp_m_freem(head); |
13247 | | *new_tail = NULL; |
13248 | | SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); |
13249 | | *error = ENOBUFS; |
13250 | | return (NULL); |
13251 | | } |
13252 | | m = SCTP_BUF_NEXT(m); |
13253 | | cancpy = (int)M_TRAILINGSPACE(m); |
13254 | | willcpy = min(cancpy, left); |
13255 | | *error = uiomove(mtod(m, caddr_t), willcpy, uio); |
13256 | | if (*error != 0) { |
13257 | | sctp_m_freem(head); |
13258 | | *new_tail = NULL; |
13259 | | SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, *error); |
13260 | | return (NULL); |
13261 | | } |
13262 | | SCTP_BUF_LEN(m) = willcpy; |
13263 | | left -= willcpy; |
13264 | | *sndout += willcpy; |
13265 | | *new_tail = m; |
13266 | | if (left == 0) { |
13267 | | SCTP_BUF_NEXT(m) = NULL; |
13268 | | } |
13269 | | } |
13270 | | return (head); |
13271 | | #endif |
13272 | 0 | } |
13273 | | |
13274 | | static int |
13275 | | sctp_copy_one(struct sctp_stream_queue_pending *sp, |
13276 | | struct uio *uio, |
13277 | | int resv_upfront) |
13278 | 18.0k | { |
13279 | 18.0k | #if defined(__FreeBSD__) || defined(__Userspace__) |
13280 | 18.0k | sp->data = m_uiotombuf(uio, M_WAITOK, sp->length, resv_upfront, 0); |
13281 | 18.0k | if (sp->data == NULL) { |
13282 | | /* The only possible error is EFAULT. */ |
13283 | 0 | SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT); |
13284 | 0 | return (EFAULT); |
13285 | 0 | } |
13286 | 18.0k | sp->tail_mbuf = m_last(sp->data); |
13287 | 18.0k | return (0); |
13288 | | #else |
13289 | | int left; |
13290 | | int cancpy, willcpy, error; |
13291 | | struct mbuf *m, *head; |
13292 | | int cpsz = 0; |
13293 | | |
13294 | | /* First one gets a header */ |
13295 | | left = sp->length; |
13296 | | head = m = sctp_get_mbuf_for_msg((left + resv_upfront), 0, M_WAITOK, 0, MT_DATA); |
13297 | | if (m == NULL) { |
13298 | | SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); |
13299 | | return (ENOBUFS); |
13300 | | } |
13301 | | /*- |
13302 | | * Add this one for m in now, that way if the alloc fails we won't |
13303 | | * have a bad cnt. |
13304 | | */ |
13305 | | SCTP_BUF_RESV_UF(m, resv_upfront); |
13306 | | cancpy = (int)M_TRAILINGSPACE(m); |
13307 | | willcpy = min(cancpy, left); |
13308 | | while (left > 0) { |
13309 | | /* move in user data */ |
13310 | | error = uiomove(mtod(m, caddr_t), willcpy, uio); |
13311 | | if (error) { |
13312 | | sctp_m_freem(head); |
13313 | | return (error); |
13314 | | } |
13315 | | SCTP_BUF_LEN(m) = willcpy; |
13316 | | left -= willcpy; |
13317 | | cpsz += willcpy; |
13318 | | if (left > 0) { |
13319 | | SCTP_BUF_NEXT(m) = sctp_get_mbuf_for_msg(left, 0, M_WAITOK, 0, MT_DATA); |
13320 | | if (SCTP_BUF_NEXT(m) == NULL) { |
13321 | | /* |
13322 | | * the head goes back to caller, he can free |
13323 | | * the rest |
13324 | | */ |
13325 | | sctp_m_freem(head); |
13326 | | SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); |
13327 | | return (ENOBUFS); |
13328 | | } |
13329 | | m = SCTP_BUF_NEXT(m); |
13330 | | cancpy = (int)M_TRAILINGSPACE(m); |
13331 | | willcpy = min(cancpy, left); |
13332 | | } else { |
13333 | | sp->tail_mbuf = m; |
13334 | | SCTP_BUF_NEXT(m) = NULL; |
13335 | | } |
13336 | | } |
13337 | | sp->data = head; |
13338 | | sp->length = cpsz; |
13339 | | return (0); |
13340 | | #endif |
13341 | 18.0k | } |
13342 | | |
13343 | | static struct sctp_stream_queue_pending * |
13344 | | sctp_copy_it_in(struct sctp_tcb *stcb, |
13345 | | struct sctp_association *asoc, |
13346 | | struct sctp_nonpad_sndrcvinfo *srcv, |
13347 | | struct uio *uio, |
13348 | | struct sctp_nets *net, |
13349 | | ssize_t max_send_len, |
13350 | | int user_marks_eor, |
13351 | | int *error) |
13352 | | |
13353 | 18.0k | { |
13354 | | /*- |
13355 | | * This routine must be very careful in its work. Protocol |
13356 | | * processing is up and running so care must be taken to spl...() |
13357 | | * when you need to do something that may effect the stcb/asoc. The |
13358 | | * sb is locked however. When data is copied the protocol processing |
13359 | | * should be enabled since this is a slower operation... |
13360 | | */ |
13361 | 18.0k | struct sctp_stream_queue_pending *sp; |
13362 | 18.0k | int resv_in_first; |
13363 | | |
13364 | 18.0k | *error = 0; |
13365 | 18.0k | sctp_alloc_a_strmoq(stcb, sp); |
13366 | 18.0k | if (sp == NULL) { |
13367 | 0 | SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOMEM); |
13368 | 0 | *error = ENOMEM; |
13369 | 0 | goto out_now; |
13370 | 0 | } |
13371 | 18.0k | sp->act_flags = 0; |
13372 | 18.0k | sp->sender_all_done = 0; |
13373 | 18.0k | sp->sinfo_flags = srcv->sinfo_flags; |
13374 | 18.0k | sp->timetolive = srcv->sinfo_timetolive; |
13375 | 18.0k | sp->ppid = srcv->sinfo_ppid; |
13376 | 18.0k | sp->context = srcv->sinfo_context; |
13377 | 18.0k | sp->fsn = 0; |
13378 | 18.0k | (void)SCTP_GETTIME_TIMEVAL(&sp->ts); |
13379 | 18.0k | sp->sid = srcv->sinfo_stream; |
13380 | | #if defined(__APPLE__) && !defined(__Userspace__) |
13381 | | #if defined(APPLE_LEOPARD) |
13382 | | sp->length = (uint32_t)min(uio->uio_resid, max_send_len); |
13383 | | #else |
13384 | | sp->length = (uint32_t)min(uio_resid(uio), max_send_len); |
13385 | | #endif |
13386 | | #else |
13387 | 18.0k | sp->length = (uint32_t)min(uio->uio_resid, max_send_len); |
13388 | 18.0k | #endif |
13389 | | #if defined(__APPLE__) && !defined(__Userspace__) |
13390 | | #if defined(APPLE_LEOPARD) |
13391 | | if ((sp->length == (uint32_t)uio->uio_resid) && |
13392 | | #else |
13393 | | if ((sp->length == (uint32_t)uio_resid(uio)) && |
13394 | | #endif |
13395 | | #else |
13396 | 18.0k | if ((sp->length == (uint32_t)uio->uio_resid) && |
13397 | 18.0k | #endif |
13398 | 18.0k | ((user_marks_eor == 0) || |
13399 | 0 | (srcv->sinfo_flags & SCTP_EOF) || |
13400 | 18.0k | (user_marks_eor && (srcv->sinfo_flags & SCTP_EOR)))) { |
13401 | 18.0k | sp->msg_is_complete = 1; |
13402 | 18.0k | } else { |
13403 | 0 | sp->msg_is_complete = 0; |
13404 | 0 | } |
13405 | 18.0k | sp->sender_all_done = 0; |
13406 | 18.0k | sp->some_taken = 0; |
13407 | 18.0k | sp->put_last_out = 0; |
13408 | 18.0k | resv_in_first = SCTP_DATA_CHUNK_OVERHEAD(stcb); |
13409 | 18.0k | sp->data = sp->tail_mbuf = NULL; |
13410 | 18.0k | if (sp->length == 0) { |
13411 | 0 | goto skip_copy; |
13412 | 0 | } |
13413 | 18.0k | if (srcv->sinfo_keynumber_valid) { |
13414 | 0 | sp->auth_keyid = srcv->sinfo_keynumber; |
13415 | 18.0k | } else { |
13416 | 18.0k | sp->auth_keyid = stcb->asoc.authinfo.active_keyid; |
13417 | 18.0k | } |
13418 | 18.0k | if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) { |
13419 | 0 | sctp_auth_key_acquire(stcb, sp->auth_keyid); |
13420 | 0 | sp->holds_key_ref = 1; |
13421 | 0 | } |
13422 | | #if defined(__APPLE__) && !defined(__Userspace__) |
13423 | | SCTP_SOCKET_UNLOCK(SCTP_INP_SO(stcb->sctp_ep), 0); |
13424 | | #endif |
13425 | 18.0k | *error = sctp_copy_one(sp, uio, resv_in_first); |
13426 | | #if defined(__APPLE__) && !defined(__Userspace__) |
13427 | | SCTP_SOCKET_LOCK(SCTP_INP_SO(stcb->sctp_ep), 0); |
13428 | | #endif |
13429 | 18.0k | skip_copy: |
13430 | 18.0k | if (*error) { |
13431 | 0 | #if defined(__Userspace__) |
13432 | 0 | SCTP_TCB_LOCK(stcb); |
13433 | 0 | #endif |
13434 | 0 | sctp_free_a_strmoq(stcb, sp, SCTP_SO_LOCKED); |
13435 | 0 | #if defined(__Userspace__) |
13436 | 0 | SCTP_TCB_UNLOCK(stcb); |
13437 | 0 | #endif |
13438 | 0 | sp = NULL; |
13439 | 18.0k | } else { |
13440 | 18.0k | if (sp->sinfo_flags & SCTP_ADDR_OVER) { |
13441 | 0 | sp->net = net; |
13442 | 0 | atomic_add_int(&sp->net->ref_count, 1); |
13443 | 18.0k | } else { |
13444 | 18.0k | sp->net = NULL; |
13445 | 18.0k | } |
13446 | 18.0k | sctp_set_prsctp_policy(sp); |
13447 | 18.0k | } |
13448 | 18.0k | out_now: |
13449 | 18.0k | return (sp); |
13450 | 18.0k | } |
13451 | | |
13452 | | int |
13453 | | sctp_sosend(struct socket *so, |
13454 | | struct sockaddr *addr, |
13455 | | struct uio *uio, |
13456 | | struct mbuf *top, |
13457 | | struct mbuf *control, |
13458 | | #if defined(__APPLE__) && !defined(__Userspace__) |
13459 | | int flags) |
13460 | | #else |
13461 | | int flags, |
13462 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
13463 | | struct thread *p) |
13464 | | #elif defined(_WIN32) && !defined(__Userspace__) |
13465 | | PKTHREAD p) |
13466 | | #else |
13467 | | #if defined(__Userspace__) |
13468 | | /* |
13469 | | * proc is a dummy in __Userspace__ and will not be passed |
13470 | | * to sctp_lower_sosend |
13471 | | */ |
13472 | | #endif |
13473 | | struct proc *p) |
13474 | | #endif |
13475 | | #endif |
13476 | 0 | { |
13477 | 0 | struct sctp_sndrcvinfo sndrcvninfo; |
13478 | 0 | #if defined(INET) && defined(INET6) |
13479 | 0 | struct sockaddr_in sin; |
13480 | 0 | #endif |
13481 | 0 | struct sockaddr *addr_to_use; |
13482 | | #if defined(__APPLE__) && !defined(__Userspace__) |
13483 | | struct proc *p = current_proc(); |
13484 | | #endif |
13485 | 0 | int error; |
13486 | 0 | bool use_sndinfo; |
13487 | |
|
13488 | 0 | if (control != NULL) { |
13489 | | /* process cmsg snd/rcv info (maybe a assoc-id) */ |
13490 | 0 | use_sndinfo = sctp_find_cmsg(SCTP_SNDRCV, (void *)&sndrcvninfo, control, sizeof(sndrcvninfo)); |
13491 | 0 | } else { |
13492 | 0 | use_sndinfo = false; |
13493 | 0 | } |
13494 | 0 | #if defined(INET) && defined(INET6) |
13495 | 0 | if ((addr != NULL) && (addr->sa_family == AF_INET6)) { |
13496 | 0 | struct sockaddr_in6 *sin6; |
13497 | |
|
13498 | | #ifdef HAVE_SA_LEN |
13499 | | if (addr->sa_len != sizeof(struct sockaddr_in6)) { |
13500 | | SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL); |
13501 | | return (EINVAL); |
13502 | | } |
13503 | | #endif |
13504 | 0 | sin6 = (struct sockaddr_in6 *)addr; |
13505 | 0 | if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { |
13506 | 0 | in6_sin6_2_sin(&sin, sin6); |
13507 | 0 | addr_to_use = (struct sockaddr *)&sin; |
13508 | 0 | } else { |
13509 | 0 | addr_to_use = addr; |
13510 | 0 | } |
13511 | 0 | } else { |
13512 | 0 | addr_to_use = addr; |
13513 | 0 | } |
13514 | | #else |
13515 | | addr_to_use = addr; |
13516 | | #endif |
13517 | | #if defined(__APPLE__) && !defined(__Userspace__) |
13518 | | SCTP_SOCKET_LOCK(so, 1); |
13519 | | #endif |
13520 | 0 | error = sctp_lower_sosend(so, addr_to_use, uio, top, control, flags, |
13521 | 0 | #if defined(__Userspace__) |
13522 | 0 | use_sndinfo ? &sndrcvninfo : NULL); |
13523 | | #else |
13524 | | use_sndinfo ? &sndrcvninfo : NULL, p); |
13525 | | #endif |
13526 | | #if defined(__APPLE__) && !defined(__Userspace__) |
13527 | | SCTP_SOCKET_UNLOCK(so, 1); |
13528 | | #endif |
13529 | 0 | return (error); |
13530 | 0 | } |
13531 | | |
13532 | | int |
13533 | | sctp_lower_sosend(struct socket *so, |
13534 | | struct sockaddr *addr, |
13535 | | struct uio *uio, |
13536 | | struct mbuf *top, |
13537 | | struct mbuf *control, |
13538 | | int flags, |
13539 | | #if defined(__Userspace__) |
13540 | | struct sctp_sndrcvinfo *srcv) |
13541 | | #else |
13542 | | struct sctp_sndrcvinfo *srcv, |
13543 | | #if defined(__FreeBSD__) |
13544 | | struct thread *p) |
13545 | | #elif defined(_WIN32) |
13546 | | PKTHREAD p) |
13547 | | #else |
13548 | | struct proc *p) |
13549 | | #endif |
13550 | | #endif |
13551 | 7.95M | { |
13552 | 7.95M | struct sctp_nonpad_sndrcvinfo sndrcvninfo_buf; |
13553 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
13554 | | struct epoch_tracker et; |
13555 | | #endif |
13556 | 7.95M | struct timeval now; |
13557 | 7.95M | struct sctp_block_entry be; |
13558 | 7.95M | struct sctp_inpcb *inp; |
13559 | 7.95M | struct sctp_tcb *stcb = NULL; |
13560 | 7.95M | struct sctp_nets *net; |
13561 | 7.95M | struct sctp_association *asoc; |
13562 | 7.95M | struct sctp_inpcb *t_inp; |
13563 | 7.95M | struct sctp_nonpad_sndrcvinfo *sndrcvninfo; |
13564 | 7.95M | ssize_t sndlen = 0, max_len, local_add_more; |
13565 | 7.95M | ssize_t local_soresv = 0; |
13566 | 7.95M | sctp_assoc_t sinfo_assoc_id; |
13567 | 7.95M | int user_marks_eor; |
13568 | 7.95M | int nagle_applies = 0; |
13569 | 7.95M | int error; |
13570 | 7.95M | int queue_only = 0, queue_only_for_init = 0; |
13571 | 7.95M | int un_sent; |
13572 | 7.95M | int now_filled = 0; |
13573 | 7.95M | unsigned int inqueue_bytes = 0; |
13574 | 7.95M | uint16_t port; |
13575 | 7.95M | uint16_t sinfo_flags; |
13576 | 7.95M | uint16_t sinfo_stream; |
13577 | 7.95M | bool create_lock_applied = false; |
13578 | 7.95M | bool free_cnt_applied = false; |
13579 | 7.95M | bool some_on_control; |
13580 | 7.95M | bool got_all_of_the_send = false; |
13581 | 7.95M | bool non_blocking = false; |
13582 | | |
13583 | 7.95M | error = 0; |
13584 | 7.95M | net = NULL; |
13585 | 7.95M | stcb = NULL; |
13586 | | |
13587 | | #if defined(__APPLE__) && !defined(__Userspace__) |
13588 | | sctp_lock_assert(so); |
13589 | | #endif |
13590 | 7.95M | if ((uio == NULL) && (top == NULL)) { |
13591 | 0 | error = EINVAL; |
13592 | 0 | goto out_unlocked; |
13593 | 0 | } |
13594 | 7.95M | if (addr != NULL) { |
13595 | 0 | union sctp_sockstore *raddr = (union sctp_sockstore *)addr; |
13596 | |
|
13597 | 0 | switch (raddr->sa.sa_family) { |
13598 | 0 | #ifdef INET |
13599 | 0 | case AF_INET: |
13600 | | #ifdef HAVE_SIN_LEN |
13601 | | if (raddr->sin.sin_len != sizeof(struct sockaddr_in)) { |
13602 | | error = EINVAL; |
13603 | | goto out_unlocked; |
13604 | | } |
13605 | | #endif |
13606 | 0 | port = raddr->sin.sin_port; |
13607 | 0 | break; |
13608 | 0 | #endif |
13609 | 0 | #ifdef INET6 |
13610 | 0 | case AF_INET6: |
13611 | | #ifdef HAVE_SIN6_LEN |
13612 | | if (raddr->sin6.sin6_len != sizeof(struct sockaddr_in6)) { |
13613 | | error = EINVAL; |
13614 | | goto out_unlocked; |
13615 | | } |
13616 | | #endif |
13617 | 0 | port = raddr->sin6.sin6_port; |
13618 | 0 | break; |
13619 | 0 | #endif |
13620 | 0 | #if defined(__Userspace__) |
13621 | 0 | case AF_CONN: |
13622 | | #ifdef HAVE_SCONN_LEN |
13623 | | if (raddr->sconn.sconn_len != sizeof(struct sockaddr_conn)) { |
13624 | | error = EINVAL; |
13625 | | goto out_unlocked; |
13626 | | } |
13627 | | #endif |
13628 | 0 | port = raddr->sconn.sconn_port; |
13629 | 0 | break; |
13630 | 0 | #endif |
13631 | 0 | default: |
13632 | 0 | error = EAFNOSUPPORT; |
13633 | 0 | goto out_unlocked; |
13634 | 0 | } |
13635 | 7.95M | } else { |
13636 | 7.95M | port = 0; |
13637 | 7.95M | } |
13638 | 7.95M | if (uio != NULL) { |
13639 | | #if defined(__APPLE__) && !defined(__Userspace__) |
13640 | | #if defined(APPLE_LEOPARD) |
13641 | | if (uio->uio_resid < 0) { |
13642 | | #else |
13643 | | if (uio_resid(uio) < 0) { |
13644 | | #endif |
13645 | | #else |
13646 | 7.95M | if (uio->uio_resid < 0) { |
13647 | 0 | #endif |
13648 | 0 | error = EINVAL; |
13649 | 0 | goto out_unlocked; |
13650 | 0 | } |
13651 | | #if defined(__APPLE__) && !defined(__Userspace__) |
13652 | | #if defined(APPLE_LEOPARD) |
13653 | | sndlen = uio->uio_resid; |
13654 | | #else |
13655 | | sndlen = uio_resid(uio); |
13656 | | #endif |
13657 | | #else |
13658 | 7.95M | sndlen = uio->uio_resid; |
13659 | 7.95M | #endif |
13660 | 7.95M | } else { |
13661 | 0 | sndlen = SCTP_HEADER_LEN(top); |
13662 | 0 | } |
13663 | 7.95M | SCTPDBG(SCTP_DEBUG_OUTPUT1, "Send called addr:%p send length %zd\n", |
13664 | 7.95M | (void *)addr, sndlen); |
13665 | | |
13666 | 7.95M | t_inp = inp = (struct sctp_inpcb *)so->so_pcb; |
13667 | 7.95M | if (inp == NULL) { |
13668 | 0 | error = EINVAL; |
13669 | 0 | goto out_unlocked; |
13670 | 0 | } |
13671 | 7.95M | user_marks_eor = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); |
13672 | 7.95M | if ((uio == NULL) && (user_marks_eor != 0)) { |
13673 | | /*- |
13674 | | * We do not support eeor mode for |
13675 | | * sending with mbuf chains (like sendfile). |
13676 | | */ |
13677 | 0 | error = EINVAL; |
13678 | 0 | goto out_unlocked; |
13679 | 0 | } |
13680 | 7.95M | if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && |
13681 | 7.95M | SCTP_IS_LISTENING(inp)) { |
13682 | | /* The listener can NOT send. */ |
13683 | 0 | error = EINVAL; |
13684 | 0 | goto out_unlocked; |
13685 | 0 | } |
13686 | 7.95M | atomic_add_int(&inp->total_sends, 1); |
13687 | | |
13688 | 7.95M | if (srcv != NULL) { |
13689 | 0 | sndrcvninfo = (struct sctp_nonpad_sndrcvinfo *)srcv; |
13690 | 0 | sinfo_assoc_id = sndrcvninfo->sinfo_assoc_id; |
13691 | 0 | sinfo_flags = sndrcvninfo->sinfo_flags; |
13692 | 0 | if (INVALID_SINFO_FLAG(sinfo_flags) || |
13693 | 0 | PR_SCTP_INVALID_POLICY(sinfo_flags)) { |
13694 | 0 | error = EINVAL; |
13695 | 0 | goto out_unlocked; |
13696 | 0 | } |
13697 | 0 | if (sinfo_flags != 0) { |
13698 | 0 | SCTP_STAT_INCR(sctps_sends_with_flags); |
13699 | 0 | } |
13700 | 7.95M | } else { |
13701 | 7.95M | sndrcvninfo = NULL; |
13702 | 7.95M | sinfo_flags = inp->def_send.sinfo_flags; |
13703 | 7.95M | sinfo_assoc_id = inp->def_send.sinfo_assoc_id; |
13704 | 7.95M | } |
13705 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
13706 | | if (flags & MSG_EOR) { |
13707 | | sinfo_flags |= SCTP_EOR; |
13708 | | } |
13709 | | if (flags & MSG_EOF) { |
13710 | | sinfo_flags |= SCTP_EOF; |
13711 | | } |
13712 | | #endif |
13713 | 7.95M | if ((sinfo_flags & SCTP_ADDR_OVER) && (addr == NULL)) { |
13714 | 0 | error = EINVAL; |
13715 | 0 | goto out_unlocked; |
13716 | 0 | } |
13717 | 7.95M | SCTP_INP_RLOCK(inp); |
13718 | 7.95M | if ((sinfo_flags & SCTP_SENDALL) && |
13719 | 0 | (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) { |
13720 | 0 | SCTP_INP_RUNLOCK(inp); |
13721 | 0 | error = sctp_sendall(inp, uio, top, sndrcvninfo); |
13722 | 0 | top = NULL; |
13723 | 0 | goto out_unlocked; |
13724 | 0 | } |
13725 | | /* Now we must find the association. */ |
13726 | 7.95M | if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) || |
13727 | 7.95M | (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { |
13728 | 7.95M | stcb = LIST_FIRST(&inp->sctp_asoc_list); |
13729 | 7.95M | if (stcb != NULL) { |
13730 | 7.95M | SCTP_TCB_LOCK(stcb); |
13731 | 7.95M | } |
13732 | 7.95M | SCTP_INP_RUNLOCK(inp); |
13733 | 7.95M | } else if (sinfo_assoc_id > SCTP_ALL_ASSOC) { |
13734 | 0 | stcb = sctp_findasoc_ep_asocid_locked(inp, sinfo_assoc_id, 1); |
13735 | 0 | SCTP_INP_RUNLOCK(inp); |
13736 | 0 | if (stcb != NULL) { |
13737 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
13738 | 0 | } |
13739 | 0 | } else if (addr != NULL) { |
13740 | | /*- |
13741 | | * Since we did not use findep we must |
13742 | | * increment it, and if we don't find a tcb |
13743 | | * decrement it. |
13744 | | */ |
13745 | 0 | SCTP_INP_INCR_REF(inp); |
13746 | 0 | SCTP_INP_RUNLOCK(inp); |
13747 | 0 | stcb = sctp_findassociation_ep_addr(&t_inp, addr, &net, NULL, NULL); |
13748 | 0 | if (stcb == NULL) { |
13749 | 0 | SCTP_INP_WLOCK(inp); |
13750 | 0 | SCTP_INP_DECR_REF(inp); |
13751 | 0 | SCTP_INP_WUNLOCK(inp); |
13752 | 0 | } else { |
13753 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
13754 | 0 | } |
13755 | 0 | } else { |
13756 | 0 | SCTP_INP_RUNLOCK(inp); |
13757 | 0 | } |
13758 | | |
13759 | 7.95M | #ifdef INVARIANTS |
13760 | 7.95M | if (stcb != NULL) { |
13761 | 7.95M | SCTP_TCB_LOCK_ASSERT(stcb); |
13762 | 7.95M | } |
13763 | 7.95M | #endif |
13764 | | |
13765 | 7.95M | if ((stcb == NULL) && (addr != NULL)) { |
13766 | | /* Possible implicit send? */ |
13767 | 0 | SCTP_ASOC_CREATE_LOCK(inp); |
13768 | 0 | create_lock_applied = true; |
13769 | 0 | if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || |
13770 | 0 | (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { |
13771 | 0 | error = EINVAL; |
13772 | 0 | goto out_unlocked; |
13773 | 0 | } |
13774 | 0 | if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && |
13775 | 0 | (addr->sa_family == AF_INET6)) { |
13776 | 0 | error = EINVAL; |
13777 | 0 | goto out_unlocked; |
13778 | 0 | } |
13779 | 0 | SCTP_INP_WLOCK(inp); |
13780 | 0 | SCTP_INP_INCR_REF(inp); |
13781 | 0 | SCTP_INP_WUNLOCK(inp); |
13782 | | /* With the lock applied look again */ |
13783 | 0 | stcb = sctp_findassociation_ep_addr(&t_inp, addr, &net, NULL, NULL); |
13784 | 0 | #if defined(INET) || defined(INET6) |
13785 | 0 | if ((stcb == NULL) && (control != NULL) && (port > 0)) { |
13786 | 0 | stcb = sctp_findassociation_cmsgs(&t_inp, port, control, &net, &error); |
13787 | 0 | } |
13788 | 0 | #endif |
13789 | 0 | if (stcb == NULL) { |
13790 | 0 | SCTP_INP_WLOCK(inp); |
13791 | 0 | SCTP_INP_DECR_REF(inp); |
13792 | 0 | SCTP_INP_WUNLOCK(inp); |
13793 | 0 | } else { |
13794 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
13795 | 0 | SCTP_ASOC_CREATE_UNLOCK(inp); |
13796 | 0 | create_lock_applied = false; |
13797 | 0 | } |
13798 | 0 | if (error != 0) { |
13799 | 0 | goto out_unlocked; |
13800 | 0 | } |
13801 | 0 | if (t_inp != inp) { |
13802 | 0 | error = ENOTCONN; |
13803 | 0 | goto out_unlocked; |
13804 | 0 | } |
13805 | 0 | } |
13806 | 7.95M | if (stcb == NULL) { |
13807 | 0 | if (addr == NULL) { |
13808 | 0 | error = ENOENT; |
13809 | 0 | goto out_unlocked; |
13810 | 0 | } else { |
13811 | | /* We must go ahead and start the INIT process */ |
13812 | 0 | uint32_t vrf_id; |
13813 | |
|
13814 | 0 | if ((sinfo_flags & SCTP_ABORT) || |
13815 | 0 | ((sinfo_flags & SCTP_EOF) && (sndlen == 0))) { |
13816 | | /*- |
13817 | | * User asks to abort a non-existent assoc, |
13818 | | * or EOF a non-existent assoc with no data |
13819 | | */ |
13820 | 0 | error = ENOENT; |
13821 | 0 | goto out_unlocked; |
13822 | 0 | } |
13823 | | /* get an asoc/stcb struct */ |
13824 | 0 | vrf_id = inp->def_vrf_id; |
13825 | 0 | KASSERT(create_lock_applied, ("create_lock_applied is false")); |
13826 | 0 | stcb = sctp_aloc_assoc_connected(inp, addr, &error, 0, 0, vrf_id, |
13827 | 0 | inp->sctp_ep.pre_open_stream_count, |
13828 | 0 | inp->sctp_ep.port, |
13829 | | #if !defined(__Userspace__) |
13830 | | p, |
13831 | | #else |
13832 | 0 | (struct proc *)NULL, |
13833 | 0 | #endif |
13834 | 0 | SCTP_INITIALIZE_AUTH_PARAMS); |
13835 | 0 | if (stcb == NULL) { |
13836 | | /* error is setup for us in the call. */ |
13837 | 0 | KASSERT(error != 0, ("error is 0 although stcb is NULL")); |
13838 | 0 | goto out_unlocked; |
13839 | 0 | } |
13840 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
13841 | 0 | SCTP_ASOC_CREATE_UNLOCK(inp); |
13842 | 0 | create_lock_applied = false; |
13843 | | /* Turn on queue only flag to prevent data from being sent */ |
13844 | 0 | queue_only = 1; |
13845 | 0 | SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); |
13846 | 0 | (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); |
13847 | 0 | if (control != NULL) { |
13848 | 0 | if (sctp_process_cmsgs_for_init(stcb, control, &error)) { |
13849 | 0 | sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, |
13850 | 0 | SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_6); |
13851 | 0 | stcb = NULL; |
13852 | 0 | KASSERT(error != 0, |
13853 | 0 | ("error is 0 although sctp_process_cmsgs_for_init() indicated an error")); |
13854 | 0 | goto out_unlocked; |
13855 | 0 | } |
13856 | 0 | } |
13857 | | /* out with the INIT */ |
13858 | 0 | queue_only_for_init = 1; |
13859 | | /*- |
13860 | | * we may want to dig in after this call and adjust the MTU |
13861 | | * value. It defaulted to 1500 (constant) but the ro |
13862 | | * structure may now have an update and thus we may need to |
13863 | | * change it BEFORE we append the message. |
13864 | | */ |
13865 | 0 | } |
13866 | 0 | } |
13867 | | |
13868 | 7.95M | KASSERT(!create_lock_applied, ("create_lock_applied is true")); |
13869 | 7.95M | KASSERT(stcb != NULL, ("stcb is NULL")); |
13870 | 7.95M | SCTP_TCB_LOCK_ASSERT(stcb); |
13871 | | |
13872 | 7.95M | asoc = &stcb->asoc; |
13873 | 7.95M | if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || |
13874 | 7.95M | (asoc->state & SCTP_STATE_WAS_ABORTED)) { |
13875 | 0 | if (asoc->state & SCTP_STATE_WAS_ABORTED) { |
13876 | | /* XXX: Could also be ECONNABORTED, not enough info. */ |
13877 | 0 | error = ECONNRESET; |
13878 | 0 | } else { |
13879 | 0 | error = ENOTCONN; |
13880 | 0 | } |
13881 | 0 | goto out_unlocked; |
13882 | 0 | } |
13883 | 7.95M | if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || |
13884 | 7.95M | (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { |
13885 | 0 | queue_only = 1; |
13886 | 0 | } |
13887 | | /* Keep the stcb from being freed under our feet. */ |
13888 | 7.95M | atomic_add_int(&asoc->refcnt, 1); |
13889 | 7.95M | free_cnt_applied = true; |
13890 | 7.95M | if (sndrcvninfo == NULL) { |
13891 | | /* Use a local copy to have a consistent view. */ |
13892 | 7.95M | sndrcvninfo_buf = asoc->def_send; |
13893 | 7.95M | sndrcvninfo = &sndrcvninfo_buf; |
13894 | 7.95M | sinfo_flags = sndrcvninfo->sinfo_flags; |
13895 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
13896 | | if (flags & MSG_EOR) { |
13897 | | sinfo_flags |= SCTP_EOR; |
13898 | | } |
13899 | | if (flags & MSG_EOF) { |
13900 | | sinfo_flags |= SCTP_EOF; |
13901 | | } |
13902 | | #endif |
13903 | 7.95M | } |
13904 | | /* Are we aborting? */ |
13905 | 7.95M | if (sinfo_flags & SCTP_ABORT) { |
13906 | 0 | struct mbuf *mm; |
13907 | 0 | struct sctp_paramhdr *ph; |
13908 | 0 | ssize_t tot_demand, tot_out = 0, max_out; |
13909 | |
|
13910 | 0 | SCTP_STAT_INCR(sctps_sends_with_abort); |
13911 | 0 | if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || |
13912 | 0 | (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { |
13913 | | /* It has to be up before we abort. */ |
13914 | 0 | error = EINVAL; |
13915 | 0 | goto out_unlocked; |
13916 | 0 | } |
13917 | | /* How big is the user initiated abort? */ |
13918 | 0 | if (top != NULL) { |
13919 | 0 | struct mbuf *cntm; |
13920 | |
|
13921 | 0 | if (sndlen != 0) { |
13922 | 0 | for (cntm = top; cntm; cntm = SCTP_BUF_NEXT(cntm)) { |
13923 | 0 | tot_out += SCTP_BUF_LEN(cntm); |
13924 | 0 | } |
13925 | 0 | } |
13926 | 0 | mm = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA); |
13927 | 0 | } else { |
13928 | | /* Must fit in a MTU */ |
13929 | 0 | tot_out = sndlen; |
13930 | 0 | tot_demand = (tot_out + sizeof(struct sctp_paramhdr)); |
13931 | 0 | if (tot_demand > SCTP_DEFAULT_ADD_MORE) { |
13932 | 0 | error = EMSGSIZE; |
13933 | 0 | goto out_unlocked; |
13934 | 0 | } |
13935 | 0 | mm = sctp_get_mbuf_for_msg((unsigned int)tot_demand, 0, M_NOWAIT, 1, MT_DATA); |
13936 | 0 | } |
13937 | 0 | if (mm == NULL) { |
13938 | 0 | error = ENOMEM; |
13939 | 0 | goto out_unlocked; |
13940 | 0 | } |
13941 | 0 | max_out = asoc->smallest_mtu - sizeof(struct sctp_paramhdr); |
13942 | 0 | max_out -= sizeof(struct sctp_abort_msg); |
13943 | 0 | if (tot_out > max_out) { |
13944 | 0 | tot_out = max_out; |
13945 | 0 | } |
13946 | 0 | ph = mtod(mm, struct sctp_paramhdr *); |
13947 | 0 | ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); |
13948 | 0 | ph->param_length = htons((uint16_t)(sizeof(struct sctp_paramhdr) + tot_out)); |
13949 | 0 | ph++; |
13950 | 0 | SCTP_BUF_LEN(mm) = (int)(tot_out + sizeof(struct sctp_paramhdr)); |
13951 | 0 | if (top == NULL) { |
13952 | 0 | SCTP_TCB_UNLOCK(stcb); |
13953 | | #if defined(__APPLE__) && !defined(__Userspace__) |
13954 | | SCTP_SOCKET_UNLOCK(so, 0); |
13955 | | #endif |
13956 | 0 | error = uiomove((caddr_t)ph, (int)tot_out, uio); |
13957 | | #if defined(__APPLE__) && !defined(__Userspace__) |
13958 | | SCTP_SOCKET_LOCK(so, 0); |
13959 | | #endif |
13960 | 0 | SCTP_TCB_LOCK(stcb); |
13961 | 0 | if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || |
13962 | 0 | (asoc->state & SCTP_STATE_WAS_ABORTED)) { |
13963 | 0 | sctp_m_freem(mm); |
13964 | 0 | if (asoc->state & SCTP_STATE_WAS_ABORTED) { |
13965 | | /* XXX: Could also be ECONNABORTED, not enough info. */ |
13966 | 0 | error = ECONNRESET; |
13967 | 0 | } else { |
13968 | 0 | error = ENOTCONN; |
13969 | 0 | } |
13970 | 0 | goto out_unlocked; |
13971 | 0 | } |
13972 | 0 | if (error != 0) { |
13973 | | /*- |
13974 | | * Here if we can't get his data we |
13975 | | * still abort we just don't get to |
13976 | | * send the users note :-0 |
13977 | | */ |
13978 | 0 | sctp_m_freem(mm); |
13979 | 0 | mm = NULL; |
13980 | 0 | error = 0; |
13981 | 0 | } |
13982 | 0 | } else { |
13983 | 0 | if (sndlen != 0) { |
13984 | 0 | SCTP_BUF_NEXT(mm) = top; |
13985 | 0 | } |
13986 | 0 | } |
13987 | 0 | atomic_subtract_int(&asoc->refcnt, 1); |
13988 | 0 | free_cnt_applied = false; |
13989 | | /* release this lock, otherwise we hang on ourselves */ |
13990 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
13991 | | NET_EPOCH_ENTER(et); |
13992 | | #endif |
13993 | 0 | sctp_abort_an_association(stcb->sctp_ep, stcb, mm, false, SCTP_SO_LOCKED); |
13994 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
13995 | | NET_EPOCH_EXIT(et); |
13996 | | #endif |
13997 | 0 | stcb = NULL; |
13998 | | /* In this case top is already chained to mm |
13999 | | * avoid double free, since we free it below if |
14000 | | * top != NULL and driver would free it after sending |
14001 | | * the packet out |
14002 | | */ |
14003 | 0 | if (sndlen != 0) { |
14004 | 0 | top = NULL; |
14005 | 0 | } |
14006 | 0 | goto out_unlocked; |
14007 | 0 | } |
14008 | | |
14009 | 7.95M | KASSERT(stcb != NULL, ("stcb is NULL")); |
14010 | 7.95M | SCTP_TCB_LOCK_ASSERT(stcb); |
14011 | 7.95M | KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, |
14012 | 7.95M | ("Association about to be freed")); |
14013 | 7.95M | KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, |
14014 | 7.95M | ("Association was aborted")); |
14015 | | |
14016 | 7.95M | if (sinfo_flags & SCTP_ADDR_OVER) { |
14017 | 0 | if (addr != NULL) { |
14018 | 0 | net = sctp_findnet(stcb, addr); |
14019 | 0 | } else { |
14020 | 0 | net = NULL; |
14021 | 0 | } |
14022 | 0 | if ((net == NULL) || |
14023 | 0 | ((port != 0) && (port != stcb->rport))) { |
14024 | 0 | error = EINVAL; |
14025 | 0 | goto out_unlocked; |
14026 | 0 | } |
14027 | 7.95M | } else { |
14028 | 7.95M | if (asoc->alternate != NULL) { |
14029 | 0 | net = asoc->alternate; |
14030 | 7.95M | } else { |
14031 | 7.95M | net = asoc->primary_destination; |
14032 | 7.95M | } |
14033 | 7.95M | } |
14034 | 7.95M | if (sndlen == 0) { |
14035 | 0 | if (sinfo_flags & SCTP_EOF) { |
14036 | 0 | got_all_of_the_send = true; |
14037 | 0 | goto dataless_eof; |
14038 | 0 | } else { |
14039 | 0 | error = EINVAL; |
14040 | 0 | goto out_unlocked; |
14041 | 0 | } |
14042 | 0 | } |
14043 | 7.95M | if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT)) { |
14044 | 0 | if (sndlen > (ssize_t)asoc->smallest_mtu) { |
14045 | 0 | error = EMSGSIZE; |
14046 | 0 | goto out_unlocked; |
14047 | 0 | } |
14048 | 0 | } |
14049 | 7.95M | sinfo_stream = sndrcvninfo->sinfo_stream; |
14050 | | /* Is the stream no. valid? */ |
14051 | 7.95M | if (sinfo_stream >= asoc->streamoutcnt) { |
14052 | | /* Invalid stream number */ |
14053 | 0 | error = EINVAL; |
14054 | 0 | goto out_unlocked; |
14055 | 0 | } |
14056 | 7.95M | if ((asoc->strmout[sinfo_stream].state != SCTP_STREAM_OPEN) && |
14057 | 0 | (asoc->strmout[sinfo_stream].state != SCTP_STREAM_OPENING)) { |
14058 | | /* |
14059 | | * Can't queue any data while stream reset is underway. |
14060 | | */ |
14061 | 0 | if (asoc->strmout[sinfo_stream].state > SCTP_STREAM_OPEN) { |
14062 | 0 | error = EAGAIN; |
14063 | 0 | } else { |
14064 | 0 | error = EINVAL; |
14065 | 0 | } |
14066 | 0 | goto out_unlocked; |
14067 | 0 | } |
14068 | 7.95M | atomic_add_int(&stcb->total_sends, 1); |
14069 | 7.95M | #if defined(__Userspace__) |
14070 | 7.95M | if (inp->recv_callback != NULL) { |
14071 | 0 | non_blocking = true; |
14072 | 0 | } |
14073 | 7.95M | #endif |
14074 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
14075 | | if (SCTP_SO_IS_NBIO(so) || (flags & (MSG_NBIO | MSG_DONTWAIT)) != 0) { |
14076 | | #else |
14077 | 7.95M | if (SCTP_SO_IS_NBIO(so)) { |
14078 | 7.95M | #endif |
14079 | 7.95M | non_blocking = true; |
14080 | 7.95M | } |
14081 | 7.95M | if (non_blocking) { |
14082 | 7.95M | ssize_t amount; |
14083 | | |
14084 | 7.95M | inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); |
14085 | 7.95M | if (user_marks_eor == 0) { |
14086 | 7.95M | amount = sndlen; |
14087 | 7.95M | } else { |
14088 | 0 | amount = 1; |
14089 | 0 | } |
14090 | 7.95M | if ((SCTP_SB_LIMIT_SND(so) < (amount + inqueue_bytes + asoc->sb_send_resv)) || |
14091 | 7.93M | (asoc->chunks_on_out_queue >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) { |
14092 | 7.93M | if ((sndlen > (ssize_t)SCTP_SB_LIMIT_SND(so)) && |
14093 | 0 | (user_marks_eor == 0)) { |
14094 | 0 | error = EMSGSIZE; |
14095 | 7.93M | } else { |
14096 | 7.93M | error = EWOULDBLOCK; |
14097 | 7.93M | } |
14098 | 7.93M | goto out_unlocked; |
14099 | 7.93M | } |
14100 | 7.95M | } |
14101 | 18.0k | atomic_add_int(&asoc->sb_send_resv, (int)sndlen); |
14102 | 18.0k | local_soresv = sndlen; |
14103 | | |
14104 | 18.0k | KASSERT(stcb != NULL, ("stcb is NULL")); |
14105 | 18.0k | SCTP_TCB_LOCK_ASSERT(stcb); |
14106 | 18.0k | KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, |
14107 | 18.0k | ("Association about to be freed")); |
14108 | 18.0k | KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, |
14109 | 18.0k | ("Association was aborted")); |
14110 | | |
14111 | | /* Ok, we will attempt a msgsnd :> */ |
14112 | | #if !(defined(_WIN32) || defined(__Userspace__)) |
14113 | | if (p != NULL) { |
14114 | | #if defined(__FreeBSD__) |
14115 | | p->td_ru.ru_msgsnd++; |
14116 | | #else |
14117 | | p->p_stats->p_ru.ru_msgsnd++; |
14118 | | #endif |
14119 | | } |
14120 | | #endif |
14121 | | /* Calculate the maximum we can send */ |
14122 | 18.0k | inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); |
14123 | 18.0k | if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) { |
14124 | 18.0k | max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes; |
14125 | 18.0k | } else { |
14126 | 0 | max_len = 0; |
14127 | 0 | } |
14128 | | /* Unless E_EOR mode is on, we must make a send FIT in one call. */ |
14129 | 18.0k | if ((user_marks_eor == 0) && |
14130 | 18.0k | (sndlen > (ssize_t)SCTP_SB_LIMIT_SND(stcb->sctp_socket))) { |
14131 | | /* It will NEVER fit. */ |
14132 | 0 | error = EMSGSIZE; |
14133 | 0 | goto out_unlocked; |
14134 | 0 | } |
14135 | 18.0k | if (user_marks_eor != 0) { |
14136 | 0 | local_add_more = (ssize_t)min(SCTP_SB_LIMIT_SND(so), SCTP_BASE_SYSCTL(sctp_add_more_threshold)); |
14137 | 18.0k | } else { |
14138 | | /*- |
14139 | | * For non-eeor the whole message must fit in |
14140 | | * the socket send buffer. |
14141 | | */ |
14142 | 18.0k | local_add_more = sndlen; |
14143 | 18.0k | } |
14144 | 18.0k | if (non_blocking) { |
14145 | 18.0k | goto skip_preblock; |
14146 | 18.0k | } |
14147 | 0 | if (((max_len <= local_add_more) && ((ssize_t)SCTP_SB_LIMIT_SND(so) >= local_add_more)) || |
14148 | 0 | (max_len == 0) || |
14149 | 0 | ((asoc->chunks_on_out_queue + asoc->stream_queue_cnt) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) { |
14150 | | /* No room right now! */ |
14151 | 0 | inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); |
14152 | 0 | SOCKBUF_LOCK(&so->so_snd); |
14153 | 0 | while ((SCTP_SB_LIMIT_SND(so) < (inqueue_bytes + local_add_more)) || |
14154 | 0 | ((asoc->stream_queue_cnt + asoc->chunks_on_out_queue) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) { |
14155 | 0 | SCTPDBG(SCTP_DEBUG_OUTPUT1,"pre_block limit:%u <(inq:%d + %zd) || (%d+%d > %d)\n", |
14156 | 0 | (unsigned int)SCTP_SB_LIMIT_SND(so), |
14157 | 0 | inqueue_bytes, |
14158 | 0 | local_add_more, |
14159 | 0 | asoc->stream_queue_cnt, |
14160 | 0 | asoc->chunks_on_out_queue, |
14161 | 0 | SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue)); |
14162 | 0 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { |
14163 | 0 | sctp_log_block(SCTP_BLOCK_LOG_INTO_BLKA, asoc, sndlen); |
14164 | 0 | } |
14165 | 0 | be.error = 0; |
14166 | 0 | #if !(defined(_WIN32) && !defined(__Userspace__)) |
14167 | 0 | stcb->block_entry = &be; |
14168 | 0 | #endif |
14169 | 0 | SCTP_TCB_UNLOCK(stcb); |
14170 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
14171 | | error = sbwait(so, SO_SND); |
14172 | | #else |
14173 | 0 | error = sbwait(&so->so_snd); |
14174 | 0 | #endif |
14175 | 0 | if (error == 0) { |
14176 | 0 | if (so->so_error != 0) { |
14177 | 0 | error = so->so_error; |
14178 | 0 | } |
14179 | 0 | if (be.error != 0) { |
14180 | 0 | error = be.error; |
14181 | 0 | } |
14182 | 0 | } |
14183 | 0 | SOCKBUF_UNLOCK(&so->so_snd); |
14184 | 0 | SCTP_TCB_LOCK(stcb); |
14185 | 0 | stcb->block_entry = NULL; |
14186 | 0 | if (error != 0) { |
14187 | 0 | goto out_unlocked; |
14188 | 0 | } |
14189 | 0 | if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || |
14190 | 0 | (asoc->state & SCTP_STATE_WAS_ABORTED)) { |
14191 | 0 | if (asoc->state & SCTP_STATE_WAS_ABORTED) { |
14192 | | /* XXX: Could also be ECONNABORTED, not enough info. */ |
14193 | 0 | error = ECONNRESET; |
14194 | 0 | } else { |
14195 | 0 | error = ENOTCONN; |
14196 | 0 | } |
14197 | 0 | goto out_unlocked; |
14198 | 0 | } |
14199 | 0 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { |
14200 | 0 | sctp_log_block(SCTP_BLOCK_LOG_OUTOF_BLK, |
14201 | 0 | asoc, asoc->total_output_queue_size); |
14202 | 0 | } |
14203 | 0 | inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); |
14204 | 0 | SOCKBUF_LOCK(&so->so_snd); |
14205 | 0 | } |
14206 | 0 | if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) { |
14207 | 0 | max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes; |
14208 | 0 | } else { |
14209 | 0 | max_len = 0; |
14210 | 0 | } |
14211 | 0 | SOCKBUF_UNLOCK(&so->so_snd); |
14212 | 0 | } |
14213 | | |
14214 | 18.0k | skip_preblock: |
14215 | 18.0k | KASSERT(stcb != NULL, ("stcb is NULL")); |
14216 | 18.0k | SCTP_TCB_LOCK_ASSERT(stcb); |
14217 | 18.0k | KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, |
14218 | 18.0k | ("Association about to be freed")); |
14219 | 18.0k | KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, |
14220 | 18.0k | ("Association was aborted")); |
14221 | | |
14222 | | #if defined(__APPLE__) && !defined(__Userspace__) |
14223 | | error = sblock(&so->so_snd, SBLOCKWAIT(flags)); |
14224 | | if (error != 0) { |
14225 | | goto out_unlocked; |
14226 | | } |
14227 | | #endif |
14228 | | /* sndlen covers for mbuf case |
14229 | | * uio_resid covers for the non-mbuf case |
14230 | | * NOTE: uio will be null when top/mbuf is passed |
14231 | | */ |
14232 | 18.0k | if (top == NULL) { |
14233 | 18.0k | struct sctp_stream_queue_pending *sp; |
14234 | 18.0k | struct sctp_stream_out *strm; |
14235 | 18.0k | uint32_t sndout; |
14236 | | |
14237 | 18.0k | if ((asoc->stream_locked) && |
14238 | 0 | (asoc->stream_locked_on != sinfo_stream)) { |
14239 | 0 | error = EINVAL; |
14240 | 0 | goto out; |
14241 | 0 | } |
14242 | 18.0k | strm = &asoc->strmout[sinfo_stream]; |
14243 | 18.0k | if (strm->last_msg_incomplete == 0) { |
14244 | 18.0k | do_a_copy_in: |
14245 | 18.0k | SCTP_TCB_UNLOCK(stcb); |
14246 | 18.0k | sp = sctp_copy_it_in(stcb, asoc, sndrcvninfo, uio, net, max_len, user_marks_eor, &error); |
14247 | 18.0k | SCTP_TCB_LOCK(stcb); |
14248 | 18.0k | if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || |
14249 | 18.0k | (asoc->state & SCTP_STATE_WAS_ABORTED)) { |
14250 | 0 | if (asoc->state & SCTP_STATE_WAS_ABORTED) { |
14251 | | /* XXX: Could also be ECONNABORTED, not enough info. */ |
14252 | 0 | error = ECONNRESET; |
14253 | 0 | } else { |
14254 | 0 | error = ENOTCONN; |
14255 | 0 | } |
14256 | 0 | goto out; |
14257 | 0 | } |
14258 | 18.0k | if (error != 0) { |
14259 | 0 | goto out; |
14260 | 0 | } |
14261 | | /* |
14262 | | * Reject the sending of a new user message, if the |
14263 | | * association is about to be shut down. |
14264 | | */ |
14265 | 18.0k | if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_SENT) || |
14266 | 18.0k | (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED) || |
14267 | 18.0k | (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_ACK_SENT) || |
14268 | 18.0k | (asoc->state & SCTP_STATE_SHUTDOWN_PENDING)) { |
14269 | 0 | if (sp->data != 0) { |
14270 | 0 | sctp_m_freem(sp->data); |
14271 | 0 | sp->data = NULL; |
14272 | 0 | sp->tail_mbuf = NULL; |
14273 | 0 | sp->length = 0; |
14274 | 0 | } |
14275 | 0 | if (sp->net != NULL) { |
14276 | 0 | sctp_free_remote_addr(sp->net); |
14277 | 0 | sp->net = NULL; |
14278 | 0 | } |
14279 | 0 | sctp_free_a_strmoq(stcb, sp, SCTP_SO_LOCKED); |
14280 | 0 | error = EPIPE; |
14281 | 0 | goto out_unlocked; |
14282 | 0 | } |
14283 | | /* The out streams might be reallocated. */ |
14284 | 18.0k | strm = &asoc->strmout[sinfo_stream]; |
14285 | 18.0k | if (sp->msg_is_complete) { |
14286 | 18.0k | strm->last_msg_incomplete = 0; |
14287 | 18.0k | asoc->stream_locked = 0; |
14288 | 18.0k | } else { |
14289 | | /* Just got locked to this guy in |
14290 | | * case of an interrupt. |
14291 | | */ |
14292 | 0 | strm->last_msg_incomplete = 1; |
14293 | 0 | if (asoc->idata_supported == 0) { |
14294 | 0 | asoc->stream_locked = 1; |
14295 | 0 | asoc->stream_locked_on = sinfo_stream; |
14296 | 0 | } |
14297 | 0 | sp->sender_all_done = 0; |
14298 | 0 | } |
14299 | 18.0k | sctp_snd_sb_alloc(stcb, sp->length); |
14300 | 18.0k | atomic_add_int(&asoc->stream_queue_cnt, 1); |
14301 | 18.0k | if (sinfo_flags & SCTP_UNORDERED) { |
14302 | 0 | SCTP_STAT_INCR(sctps_sends_with_unord); |
14303 | 0 | } |
14304 | 18.0k | sp->processing = 1; |
14305 | 18.0k | TAILQ_INSERT_TAIL(&strm->outqueue, sp, next); |
14306 | 18.0k | asoc->ss_functions.sctp_ss_add_to_stream(stcb, asoc, strm, sp); |
14307 | 18.0k | } else { |
14308 | 0 | sp = TAILQ_LAST(&strm->outqueue, sctp_streamhead); |
14309 | 0 | if (sp == NULL) { |
14310 | | /* ???? Huh ??? last msg is gone */ |
14311 | 0 | #ifdef INVARIANTS |
14312 | 0 | panic("Warning: Last msg marked incomplete, yet nothing left?"); |
14313 | | #else |
14314 | | SCTP_PRINTF("Warning: Last msg marked incomplete, yet nothing left?\n"); |
14315 | | strm->last_msg_incomplete = 0; |
14316 | | #endif |
14317 | 0 | goto do_a_copy_in; |
14318 | 0 | } |
14319 | 0 | if (sp->processing != 0) { |
14320 | 0 | error = EINVAL; |
14321 | 0 | goto out; |
14322 | 0 | } else { |
14323 | 0 | sp->processing = 1; |
14324 | 0 | } |
14325 | 0 | } |
14326 | | |
14327 | 18.0k | KASSERT(stcb != NULL, ("stcb is NULL")); |
14328 | 18.0k | SCTP_TCB_LOCK_ASSERT(stcb); |
14329 | 18.0k | KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, |
14330 | 18.0k | ("Association about to be freed")); |
14331 | 18.0k | KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, |
14332 | 18.0k | ("Association was aborted")); |
14333 | | |
14334 | | #if defined(__APPLE__) && !defined(__Userspace__) |
14335 | | #if defined(APPLE_LEOPARD) |
14336 | | while (uio->uio_resid > 0) { |
14337 | | #else |
14338 | | while (uio_resid(uio) > 0) { |
14339 | | #endif |
14340 | | #else |
14341 | 18.0k | while (uio->uio_resid > 0) { |
14342 | 0 | #endif |
14343 | | /* How much room do we have? */ |
14344 | 0 | struct mbuf *new_tail, *mm; |
14345 | |
|
14346 | 0 | inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); |
14347 | 0 | if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) { |
14348 | 0 | max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes; |
14349 | 0 | } else { |
14350 | 0 | max_len = 0; |
14351 | 0 | } |
14352 | 0 | if ((max_len > (ssize_t)SCTP_BASE_SYSCTL(sctp_add_more_threshold)) || |
14353 | 0 | ((max_len > 0 ) && (SCTP_SB_LIMIT_SND(so) < SCTP_BASE_SYSCTL(sctp_add_more_threshold))) || |
14354 | | #if defined(__APPLE__) && !defined(__Userspace__) |
14355 | | #if defined(APPLE_LEOPARD) |
14356 | | (uio->uio_resid <= max_len)) { |
14357 | | #else |
14358 | | (uio_resid(uio) <= max_len)) { |
14359 | | #endif |
14360 | | #else |
14361 | 0 | (uio->uio_resid <= max_len)) { |
14362 | 0 | #endif |
14363 | 0 | SCTP_TCB_UNLOCK(stcb); |
14364 | | #if defined(__APPLE__) && !defined(__Userspace__) |
14365 | | SCTP_SOCKET_UNLOCK(so, 0); |
14366 | | #endif |
14367 | 0 | sndout = 0; |
14368 | 0 | new_tail = NULL; |
14369 | 0 | #if defined(__FreeBSD__) || defined(__Userspace__) |
14370 | 0 | mm = sctp_copy_resume(uio, (int)max_len, user_marks_eor, &error, &sndout, &new_tail); |
14371 | | #else |
14372 | | mm = sctp_copy_resume(uio, (int)max_len, &error, &sndout, &new_tail); |
14373 | | #endif |
14374 | | #if defined(__APPLE__) && !defined(__Userspace__) |
14375 | | SCTP_SOCKET_LOCK(so, 0); |
14376 | | #endif |
14377 | 0 | SCTP_TCB_LOCK(stcb); |
14378 | 0 | if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || |
14379 | 0 | (asoc->state & SCTP_STATE_WAS_ABORTED)) { |
14380 | | /* We need to get out. |
14381 | | * Peer probably aborted. |
14382 | | */ |
14383 | 0 | sctp_m_freem(mm); |
14384 | 0 | if (asoc->state & SCTP_STATE_WAS_ABORTED) { |
14385 | | /* XXX: Could also be ECONNABORTED, not enough info. */ |
14386 | 0 | error = ECONNRESET; |
14387 | 0 | } else { |
14388 | 0 | error = ENOTCONN; |
14389 | 0 | } |
14390 | 0 | goto out; |
14391 | 0 | } |
14392 | 0 | if ((mm == NULL) || (error != 0)) { |
14393 | 0 | if (mm != NULL) { |
14394 | 0 | sctp_m_freem(mm); |
14395 | 0 | } |
14396 | 0 | if (sp != NULL) { |
14397 | 0 | sp->processing = 0; |
14398 | 0 | } |
14399 | 0 | goto out; |
14400 | 0 | } |
14401 | | /* Update the mbuf and count */ |
14402 | 0 | if (sp->tail_mbuf != NULL) { |
14403 | | /* Tack it to the end. */ |
14404 | 0 | SCTP_BUF_NEXT(sp->tail_mbuf) = mm; |
14405 | 0 | } else { |
14406 | | /* A stolen mbuf. */ |
14407 | 0 | sp->data = mm; |
14408 | 0 | } |
14409 | 0 | sp->tail_mbuf = new_tail; |
14410 | 0 | sctp_snd_sb_alloc(stcb, sndout); |
14411 | 0 | atomic_add_int(&sp->length, sndout); |
14412 | 0 | if (sinfo_flags & SCTP_SACK_IMMEDIATELY) { |
14413 | 0 | sp->sinfo_flags |= SCTP_SACK_IMMEDIATELY; |
14414 | 0 | } |
14415 | | |
14416 | | /* Did we reach EOR? */ |
14417 | | #if defined(__APPLE__) && !defined(__Userspace__) |
14418 | | #if defined(APPLE_LEOPARD) |
14419 | | if ((uio->uio_resid == 0) && |
14420 | | #else |
14421 | | if ((uio_resid(uio) == 0) && |
14422 | | #endif |
14423 | | #else |
14424 | 0 | if ((uio->uio_resid == 0) && |
14425 | 0 | #endif |
14426 | 0 | ((user_marks_eor == 0) || |
14427 | 0 | (sinfo_flags & SCTP_EOF) || |
14428 | 0 | (user_marks_eor && (sinfo_flags & SCTP_EOR)))) { |
14429 | 0 | sp->msg_is_complete = 1; |
14430 | 0 | } else { |
14431 | 0 | sp->msg_is_complete = 0; |
14432 | 0 | } |
14433 | 0 | } |
14434 | | |
14435 | 0 | KASSERT(stcb != NULL, ("stcb is NULL")); |
14436 | 0 | SCTP_TCB_LOCK_ASSERT(stcb); |
14437 | 0 | KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, |
14438 | 0 | ("Association about to be freed")); |
14439 | 0 | KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, |
14440 | 0 | ("Association was aborted")); |
14441 | | |
14442 | | #if defined(__APPLE__) && !defined(__Userspace__) |
14443 | | #if defined(APPLE_LEOPARD) |
14444 | | if (uio->uio_resid == 0) { |
14445 | | #else |
14446 | | if (uio_resid(uio) == 0) { |
14447 | | #endif |
14448 | | #else |
14449 | 0 | if (uio->uio_resid == 0) { |
14450 | 0 | #endif |
14451 | | /* got it all? */ |
14452 | 0 | continue; |
14453 | 0 | } |
14454 | | /* PR-SCTP? */ |
14455 | 0 | if ((asoc->prsctp_supported) && (asoc->sent_queue_cnt_removeable > 0)) { |
14456 | | /* This is ugly but we must assure locking order */ |
14457 | 0 | sctp_prune_prsctp(stcb, asoc, sndrcvninfo, (int)sndlen); |
14458 | 0 | inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); |
14459 | 0 | if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) |
14460 | 0 | max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes; |
14461 | 0 | else |
14462 | 0 | max_len = 0; |
14463 | 0 | if (max_len > 0) { |
14464 | 0 | continue; |
14465 | 0 | } |
14466 | 0 | } |
14467 | | /* wait for space now */ |
14468 | 0 | if (non_blocking) { |
14469 | | /* Non-blocking io in place out */ |
14470 | 0 | if (sp != NULL) { |
14471 | 0 | sp->processing = 0; |
14472 | 0 | } |
14473 | 0 | goto skip_out_eof; |
14474 | 0 | } |
14475 | | /* What about the INIT, send it maybe */ |
14476 | 0 | if (queue_only_for_init) { |
14477 | 0 | if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) { |
14478 | | /* a collision took us forward? */ |
14479 | 0 | queue_only = 0; |
14480 | 0 | } else { |
14481 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
14482 | | NET_EPOCH_ENTER(et); |
14483 | | #endif |
14484 | 0 | sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); |
14485 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
14486 | | NET_EPOCH_EXIT(et); |
14487 | | #endif |
14488 | 0 | SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); |
14489 | 0 | queue_only = 1; |
14490 | 0 | } |
14491 | 0 | } |
14492 | 0 | if ((net->flight_size > net->cwnd) && |
14493 | 0 | (asoc->sctp_cmt_on_off == 0)) { |
14494 | 0 | SCTP_STAT_INCR(sctps_send_cwnd_avoid); |
14495 | 0 | queue_only = 1; |
14496 | 0 | } else if (asoc->ifp_had_enobuf) { |
14497 | 0 | SCTP_STAT_INCR(sctps_ifnomemqueued); |
14498 | 0 | if (net->flight_size > (2 * net->mtu)) { |
14499 | 0 | queue_only = 1; |
14500 | 0 | } |
14501 | 0 | asoc->ifp_had_enobuf = 0; |
14502 | 0 | } |
14503 | 0 | un_sent = asoc->total_output_queue_size - asoc->total_flight; |
14504 | 0 | if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) && |
14505 | 0 | (asoc->total_flight > 0) && |
14506 | 0 | (asoc->stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) && |
14507 | 0 | (un_sent < (int)(asoc->smallest_mtu - SCTP_MIN_OVERHEAD))) { |
14508 | | /*- |
14509 | | * Ok, Nagle is set on and we have data outstanding. |
14510 | | * Don't send anything and let SACKs drive out the |
14511 | | * data unless we have a "full" segment to send. |
14512 | | */ |
14513 | 0 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_NAGLE_LOGGING_ENABLE) { |
14514 | 0 | sctp_log_nagle_event(stcb, SCTP_NAGLE_APPLIED); |
14515 | 0 | } |
14516 | 0 | SCTP_STAT_INCR(sctps_naglequeued); |
14517 | 0 | nagle_applies = 1; |
14518 | 0 | } else { |
14519 | 0 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_NAGLE_LOGGING_ENABLE) { |
14520 | 0 | if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) |
14521 | 0 | sctp_log_nagle_event(stcb, SCTP_NAGLE_SKIPPED); |
14522 | 0 | } |
14523 | 0 | SCTP_STAT_INCR(sctps_naglesent); |
14524 | 0 | nagle_applies = 0; |
14525 | 0 | } |
14526 | 0 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { |
14527 | 0 | sctp_misc_ints(SCTP_CWNDLOG_PRESEND, queue_only_for_init, queue_only, |
14528 | 0 | nagle_applies, un_sent); |
14529 | 0 | sctp_misc_ints(SCTP_CWNDLOG_PRESEND, asoc->total_output_queue_size, |
14530 | 0 | asoc->total_flight, |
14531 | 0 | asoc->chunks_on_out_queue, asoc->total_flight_count); |
14532 | 0 | } |
14533 | 0 | if (queue_only_for_init) { |
14534 | 0 | queue_only_for_init = 0; |
14535 | 0 | } |
14536 | 0 | if ((queue_only == 0) && (nagle_applies == 0)) { |
14537 | | /*- |
14538 | | * need to start chunk output |
14539 | | * before blocking.. note that if |
14540 | | * a lock is already applied, then |
14541 | | * the input via the net is happening |
14542 | | * and I don't need to start output :-D |
14543 | | */ |
14544 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
14545 | | NET_EPOCH_ENTER(et); |
14546 | | #endif |
14547 | 0 | sctp_chunk_output(inp, stcb, |
14548 | 0 | SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED); |
14549 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
14550 | | NET_EPOCH_EXIT(et); |
14551 | | #endif |
14552 | 0 | } |
14553 | | /*- |
14554 | | * This is a bit strange, but I think it will |
14555 | | * work. The total_output_queue_size is locked and |
14556 | | * protected by the TCB_LOCK, which we just released. |
14557 | | * There is a race that can occur between releasing it |
14558 | | * above, and me getting the socket lock, where sacks |
14559 | | * come in but we have not put the SB_WAIT on the |
14560 | | * so_snd buffer to get the wakeup. After the LOCK |
14561 | | * is applied the sack_processing will also need to |
14562 | | * LOCK the so->so_snd to do the actual sowwakeup(). So |
14563 | | * once we have the socket buffer lock if we recheck the |
14564 | | * size we KNOW we will get to sleep safely with the |
14565 | | * wakeup flag in place. |
14566 | | */ |
14567 | 0 | inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb)); |
14568 | 0 | SOCKBUF_LOCK(&so->so_snd); |
14569 | 0 | if (SCTP_SB_LIMIT_SND(so) <= (inqueue_bytes + |
14570 | 0 | min(SCTP_BASE_SYSCTL(sctp_add_more_threshold), SCTP_SB_LIMIT_SND(so)))) { |
14571 | 0 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { |
14572 | | #if defined(__APPLE__) && !defined(__Userspace__) |
14573 | | #if defined(APPLE_LEOPARD) |
14574 | | sctp_log_block(SCTP_BLOCK_LOG_INTO_BLK, |
14575 | | asoc, uio->uio_resid); |
14576 | | #else |
14577 | | sctp_log_block(SCTP_BLOCK_LOG_INTO_BLK, |
14578 | | asoc, uio_resid(uio)); |
14579 | | #endif |
14580 | | #else |
14581 | 0 | sctp_log_block(SCTP_BLOCK_LOG_INTO_BLK, |
14582 | 0 | asoc, uio->uio_resid); |
14583 | 0 | #endif |
14584 | 0 | } |
14585 | 0 | be.error = 0; |
14586 | 0 | #if !(defined(_WIN32) && !defined(__Userspace__)) |
14587 | 0 | stcb->block_entry = &be; |
14588 | 0 | #endif |
14589 | 0 | SCTP_TCB_UNLOCK(stcb); |
14590 | | #if defined(__APPLE__) && !defined(__Userspace__) |
14591 | | sbunlock(&so->so_snd, 1); |
14592 | | #endif |
14593 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
14594 | | error = sbwait(so, SO_SND); |
14595 | | #else |
14596 | 0 | error = sbwait(&so->so_snd); |
14597 | 0 | #endif |
14598 | 0 | if (error == 0) { |
14599 | 0 | if (so->so_error != 0) |
14600 | 0 | error = so->so_error; |
14601 | 0 | if (be.error != 0) { |
14602 | 0 | error = be.error; |
14603 | 0 | } |
14604 | 0 | } |
14605 | 0 | SOCKBUF_UNLOCK(&so->so_snd); |
14606 | 0 | SCTP_TCB_LOCK(stcb); |
14607 | 0 | stcb->block_entry = NULL; |
14608 | 0 | if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) || |
14609 | 0 | (asoc->state & SCTP_STATE_WAS_ABORTED)) { |
14610 | 0 | if (asoc->state & SCTP_STATE_WAS_ABORTED) { |
14611 | | /* XXX: Could also be ECONNABORTED, not enough info. */ |
14612 | 0 | error = ECONNRESET; |
14613 | 0 | } else { |
14614 | 0 | error = ENOTCONN; |
14615 | 0 | } |
14616 | 0 | goto out_unlocked; |
14617 | 0 | } |
14618 | 0 | if (error != 0) { |
14619 | 0 | if (sp != NULL) { |
14620 | 0 | sp->processing = 0; |
14621 | 0 | } |
14622 | 0 | goto out_unlocked; |
14623 | 0 | } |
14624 | | #if defined(__APPLE__) && !defined(__Userspace__) |
14625 | | error = sblock(&so->so_snd, SBLOCKWAIT(flags)); |
14626 | | if (error != 0) { |
14627 | | goto out_unlocked; |
14628 | | } |
14629 | | #endif |
14630 | 0 | } else { |
14631 | 0 | SOCKBUF_UNLOCK(&so->so_snd); |
14632 | 0 | } |
14633 | 0 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { |
14634 | 0 | sctp_log_block(SCTP_BLOCK_LOG_OUTOF_BLK, |
14635 | 0 | asoc, asoc->total_output_queue_size); |
14636 | 0 | } |
14637 | 0 | } |
14638 | | |
14639 | 18.0k | KASSERT(stcb != NULL, ("stcb is NULL")); |
14640 | 18.0k | SCTP_TCB_LOCK_ASSERT(stcb); |
14641 | 18.0k | KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, |
14642 | 18.0k | ("Association about to be freed")); |
14643 | 18.0k | KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, |
14644 | 18.0k | ("Association was aborted")); |
14645 | | |
14646 | | /* The out streams might be reallocated. */ |
14647 | 18.0k | strm = &asoc->strmout[sinfo_stream]; |
14648 | 18.0k | if (sp != NULL) { |
14649 | 18.0k | if (sp->msg_is_complete == 0) { |
14650 | 0 | strm->last_msg_incomplete = 1; |
14651 | 0 | if (asoc->idata_supported == 0) { |
14652 | 0 | asoc->stream_locked = 1; |
14653 | 0 | asoc->stream_locked_on = sinfo_stream; |
14654 | 0 | } |
14655 | 18.0k | } else { |
14656 | 18.0k | sp->sender_all_done = 1; |
14657 | 18.0k | strm->last_msg_incomplete = 0; |
14658 | 18.0k | asoc->stream_locked = 0; |
14659 | 18.0k | } |
14660 | 18.0k | sp->processing = 0; |
14661 | 18.0k | } else { |
14662 | 0 | SCTP_PRINTF("Huh no sp TSNH?\n"); |
14663 | 0 | strm->last_msg_incomplete = 0; |
14664 | 0 | asoc->stream_locked = 0; |
14665 | 0 | } |
14666 | | #if defined(__APPLE__) && !defined(__Userspace__) |
14667 | | #if defined(APPLE_LEOPARD) |
14668 | | if (uio->uio_resid == 0) { |
14669 | | #else |
14670 | | if (uio_resid(uio) == 0) { |
14671 | | #endif |
14672 | | #else |
14673 | 18.0k | if (uio->uio_resid == 0) { |
14674 | 18.0k | #endif |
14675 | 18.0k | got_all_of_the_send = true; |
14676 | 18.0k | } |
14677 | 18.0k | } else { |
14678 | 0 | error = sctp_msg_append(stcb, net, top, sndrcvninfo); |
14679 | 0 | top = NULL; |
14680 | 0 | if ((sinfo_flags & SCTP_EOF) != 0) { |
14681 | 0 | got_all_of_the_send = true; |
14682 | 0 | } |
14683 | 0 | } |
14684 | 18.0k | if (error != 0) { |
14685 | 0 | goto out; |
14686 | 0 | } |
14687 | | |
14688 | 18.0k | dataless_eof: |
14689 | 18.0k | KASSERT(stcb != NULL, ("stcb is NULL")); |
14690 | 18.0k | SCTP_TCB_LOCK_ASSERT(stcb); |
14691 | 18.0k | KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, |
14692 | 18.0k | ("Association about to be freed")); |
14693 | 18.0k | KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, |
14694 | 18.0k | ("Association was aborted")); |
14695 | | |
14696 | | /* EOF thing ? */ |
14697 | 18.0k | if ((sinfo_flags & SCTP_EOF) && got_all_of_the_send) { |
14698 | 0 | SCTP_STAT_INCR(sctps_sends_with_eof); |
14699 | 0 | error = 0; |
14700 | 0 | if (TAILQ_EMPTY(&asoc->send_queue) && |
14701 | 0 | TAILQ_EMPTY(&asoc->sent_queue) && |
14702 | 0 | sctp_is_there_unsent_data(stcb, SCTP_SO_LOCKED) == 0) { |
14703 | 0 | if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { |
14704 | 0 | goto abort_anyway; |
14705 | 0 | } |
14706 | | /* there is nothing queued to send, so I'm done... */ |
14707 | 0 | if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) && |
14708 | 0 | (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_RECEIVED) && |
14709 | 0 | (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { |
14710 | 0 | struct sctp_nets *netp; |
14711 | | |
14712 | | /* only send SHUTDOWN the first time through */ |
14713 | 0 | if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) { |
14714 | 0 | SCTP_STAT_DECR_GAUGE32(sctps_currestab); |
14715 | 0 | } |
14716 | 0 | SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT); |
14717 | 0 | sctp_stop_timers_for_shutdown(stcb); |
14718 | 0 | if (asoc->alternate != NULL) { |
14719 | 0 | netp = asoc->alternate; |
14720 | 0 | } else { |
14721 | 0 | netp = asoc->primary_destination; |
14722 | 0 | } |
14723 | 0 | sctp_send_shutdown(stcb, netp); |
14724 | 0 | sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, |
14725 | 0 | netp); |
14726 | 0 | sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, |
14727 | 0 | NULL); |
14728 | 0 | } |
14729 | 0 | } else { |
14730 | | /*- |
14731 | | * we still got (or just got) data to send, so set |
14732 | | * SHUTDOWN_PENDING |
14733 | | */ |
14734 | | /*- |
14735 | | * XXX sockets draft says that SCTP_EOF should be |
14736 | | * sent with no data. currently, we will allow user |
14737 | | * data to be sent first and move to |
14738 | | * SHUTDOWN-PENDING |
14739 | | */ |
14740 | 0 | if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) && |
14741 | 0 | (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_RECEIVED) && |
14742 | 0 | (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { |
14743 | 0 | if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) { |
14744 | 0 | SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT); |
14745 | 0 | } |
14746 | 0 | SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING); |
14747 | 0 | if (TAILQ_EMPTY(&asoc->send_queue) && |
14748 | 0 | TAILQ_EMPTY(&asoc->sent_queue) && |
14749 | 0 | (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { |
14750 | 0 | struct mbuf *op_err; |
14751 | 0 | char msg[SCTP_DIAG_INFO_LEN]; |
14752 | |
|
14753 | 0 | abort_anyway: |
14754 | 0 | if (free_cnt_applied) { |
14755 | 0 | atomic_subtract_int(&asoc->refcnt, 1); |
14756 | 0 | free_cnt_applied = false; |
14757 | 0 | } |
14758 | 0 | SCTP_SNPRINTF(msg, sizeof(msg), |
14759 | 0 | "%s:%d at %s", __FILE__, __LINE__, __func__); |
14760 | 0 | op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), |
14761 | 0 | msg); |
14762 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
14763 | | NET_EPOCH_ENTER(et); |
14764 | | #endif |
14765 | 0 | sctp_abort_an_association(stcb->sctp_ep, stcb, |
14766 | 0 | op_err, false, SCTP_SO_LOCKED); |
14767 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
14768 | | NET_EPOCH_EXIT(et); |
14769 | | #endif |
14770 | 0 | stcb = NULL; |
14771 | 0 | error = ECONNABORTED; |
14772 | 0 | goto out; |
14773 | 0 | } |
14774 | 0 | sctp_feature_off(inp, SCTP_PCB_FLAGS_NODELAY); |
14775 | 0 | } |
14776 | 0 | } |
14777 | 0 | } |
14778 | | |
14779 | 18.0k | skip_out_eof: |
14780 | 18.0k | KASSERT(stcb != NULL, ("stcb is NULL")); |
14781 | 18.0k | SCTP_TCB_LOCK_ASSERT(stcb); |
14782 | 18.0k | KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, |
14783 | 18.0k | ("Association about to be freed")); |
14784 | 18.0k | KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, |
14785 | 18.0k | ("Association was aborted")); |
14786 | | |
14787 | 18.0k | some_on_control = !TAILQ_EMPTY(&asoc->control_send_queue); |
14788 | 18.0k | if (queue_only_for_init) { |
14789 | 0 | if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) { |
14790 | | /* a collision took us forward? */ |
14791 | 0 | queue_only = 0; |
14792 | 0 | } else { |
14793 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
14794 | | NET_EPOCH_ENTER(et); |
14795 | | #endif |
14796 | 0 | sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); |
14797 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
14798 | | NET_EPOCH_EXIT(et); |
14799 | | #endif |
14800 | 0 | SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); |
14801 | 0 | queue_only = 1; |
14802 | 0 | } |
14803 | 0 | } |
14804 | | |
14805 | 18.0k | KASSERT(stcb != NULL, ("stcb is NULL")); |
14806 | 18.0k | SCTP_TCB_LOCK_ASSERT(stcb); |
14807 | 18.0k | KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, |
14808 | 18.0k | ("Association about to be freed")); |
14809 | 18.0k | KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, |
14810 | 18.0k | ("Association was aborted")); |
14811 | | |
14812 | 18.0k | if ((net->flight_size > net->cwnd) && |
14813 | 0 | (asoc->sctp_cmt_on_off == 0)) { |
14814 | 0 | SCTP_STAT_INCR(sctps_send_cwnd_avoid); |
14815 | 0 | queue_only = 1; |
14816 | 18.0k | } else if (asoc->ifp_had_enobuf) { |
14817 | 0 | SCTP_STAT_INCR(sctps_ifnomemqueued); |
14818 | 0 | if (net->flight_size > (2 * net->mtu)) { |
14819 | 0 | queue_only = 1; |
14820 | 0 | } |
14821 | 0 | asoc->ifp_had_enobuf = 0; |
14822 | 0 | } |
14823 | 18.0k | un_sent = asoc->total_output_queue_size - asoc->total_flight; |
14824 | 18.0k | if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) && |
14825 | 0 | (asoc->total_flight > 0) && |
14826 | 0 | (asoc->stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) && |
14827 | 0 | (un_sent < (int)(asoc->smallest_mtu - SCTP_MIN_OVERHEAD))) { |
14828 | | /*- |
14829 | | * Ok, Nagle is set on and we have data outstanding. |
14830 | | * Don't send anything and let SACKs drive out the |
14831 | | * data unless wen have a "full" segment to send. |
14832 | | */ |
14833 | 0 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_NAGLE_LOGGING_ENABLE) { |
14834 | 0 | sctp_log_nagle_event(stcb, SCTP_NAGLE_APPLIED); |
14835 | 0 | } |
14836 | 0 | SCTP_STAT_INCR(sctps_naglequeued); |
14837 | 0 | nagle_applies = 1; |
14838 | 18.0k | } else { |
14839 | 18.0k | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_NAGLE_LOGGING_ENABLE) { |
14840 | 0 | if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) |
14841 | 0 | sctp_log_nagle_event(stcb, SCTP_NAGLE_SKIPPED); |
14842 | 0 | } |
14843 | 18.0k | SCTP_STAT_INCR(sctps_naglesent); |
14844 | 18.0k | nagle_applies = 0; |
14845 | 18.0k | } |
14846 | 18.0k | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { |
14847 | 0 | sctp_misc_ints(SCTP_CWNDLOG_PRESEND, queue_only_for_init, queue_only, |
14848 | 0 | nagle_applies, un_sent); |
14849 | 0 | sctp_misc_ints(SCTP_CWNDLOG_PRESEND, asoc->total_output_queue_size, |
14850 | 0 | asoc->total_flight, |
14851 | 0 | asoc->chunks_on_out_queue, asoc->total_flight_count); |
14852 | 0 | } |
14853 | | |
14854 | 18.0k | KASSERT(stcb != NULL, ("stcb is NULL")); |
14855 | 18.0k | SCTP_TCB_LOCK_ASSERT(stcb); |
14856 | 18.0k | KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, |
14857 | 18.0k | ("Association about to be freed")); |
14858 | 18.0k | KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, |
14859 | 18.0k | ("Association was aborted")); |
14860 | | |
14861 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
14862 | | NET_EPOCH_ENTER(et); |
14863 | | #endif |
14864 | 18.0k | if ((queue_only == 0) && (nagle_applies == 0) && (asoc->peers_rwnd && un_sent)) { |
14865 | 18.0k | sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED); |
14866 | 18.0k | } else if ((queue_only == 0) && |
14867 | 0 | (asoc->peers_rwnd == 0) && |
14868 | 0 | (asoc->total_flight == 0)) { |
14869 | | /* We get to have a probe outstanding */ |
14870 | 0 | sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED); |
14871 | 0 | } else if (some_on_control) { |
14872 | 0 | int num_out, reason; |
14873 | | |
14874 | | /* Here we do control only */ |
14875 | 0 | (void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, |
14876 | 0 | &reason, 1, 1, &now, &now_filled, |
14877 | 0 | sctp_get_frag_point(stcb), |
14878 | 0 | SCTP_SO_LOCKED); |
14879 | 0 | } |
14880 | | #if defined(__FreeBSD__) && !defined(__Userspace__) |
14881 | | NET_EPOCH_EXIT(et); |
14882 | | #endif |
14883 | 18.0k | SCTPDBG(SCTP_DEBUG_OUTPUT1, "USR Send complete qo:%d prw:%d unsent:%d tf:%d cooq:%d toqs:%d err:%d\n", |
14884 | 18.0k | queue_only, asoc->peers_rwnd, un_sent, |
14885 | 18.0k | asoc->total_flight, asoc->chunks_on_out_queue, |
14886 | 18.0k | asoc->total_output_queue_size, error); |
14887 | | |
14888 | 18.0k | KASSERT(stcb != NULL, ("stcb is NULL")); |
14889 | 18.0k | SCTP_TCB_LOCK_ASSERT(stcb); |
14890 | 18.0k | KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0, |
14891 | 18.0k | ("Association about to be freed")); |
14892 | 18.0k | KASSERT((asoc->state & SCTP_STATE_WAS_ABORTED) == 0, |
14893 | 18.0k | ("Association was aborted")); |
14894 | | |
14895 | 18.0k | out: |
14896 | | #if defined(__APPLE__) && !defined(__Userspace__) |
14897 | | sbunlock(&so->so_snd, 1); |
14898 | | #endif |
14899 | 7.95M | out_unlocked: |
14900 | 7.95M | if (create_lock_applied) { |
14901 | 0 | SCTP_ASOC_CREATE_UNLOCK(inp); |
14902 | 0 | } |
14903 | 7.95M | if (stcb != NULL) { |
14904 | 7.95M | if (local_soresv) { |
14905 | 18.0k | atomic_subtract_int(&asoc->sb_send_resv, (int)sndlen); |
14906 | 18.0k | } |
14907 | 7.95M | if (free_cnt_applied) { |
14908 | 7.95M | atomic_subtract_int(&asoc->refcnt, 1); |
14909 | 7.95M | } |
14910 | 7.95M | SCTP_TCB_UNLOCK(stcb); |
14911 | 7.95M | } |
14912 | 7.95M | if (top != NULL) { |
14913 | 0 | sctp_m_freem(top); |
14914 | 0 | } |
14915 | 7.95M | if (control != NULL) { |
14916 | 0 | sctp_m_freem(control); |
14917 | 0 | } |
14918 | 7.95M | SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, error); |
14919 | 7.95M | return (error); |
14920 | 7.95M | } |
14921 | | |
14922 | | /* |
14923 | | * generate an AUTHentication chunk, if required |
14924 | | */ |
14925 | | struct mbuf * |
14926 | | sctp_add_auth_chunk(struct mbuf *m, struct mbuf **m_end, |
14927 | | struct sctp_auth_chunk **auth_ret, uint32_t * offset, |
14928 | | struct sctp_tcb *stcb, uint8_t chunk) |
14929 | 0 | { |
14930 | 0 | struct mbuf *m_auth; |
14931 | 0 | struct sctp_auth_chunk *auth; |
14932 | 0 | int chunk_len; |
14933 | 0 | struct mbuf *cn; |
14934 | |
|
14935 | 0 | if ((m_end == NULL) || (auth_ret == NULL) || (offset == NULL) || |
14936 | 0 | (stcb == NULL)) |
14937 | 0 | return (m); |
14938 | | |
14939 | 0 | if (stcb->asoc.auth_supported == 0) { |
14940 | 0 | return (m); |
14941 | 0 | } |
14942 | | /* does the requested chunk require auth? */ |
14943 | 0 | if (!sctp_auth_is_required_chunk(chunk, stcb->asoc.peer_auth_chunks)) { |
14944 | 0 | return (m); |
14945 | 0 | } |
14946 | 0 | m_auth = sctp_get_mbuf_for_msg(sizeof(*auth), 0, M_NOWAIT, 1, MT_HEADER); |
14947 | 0 | if (m_auth == NULL) { |
14948 | | /* no mbuf's */ |
14949 | 0 | return (m); |
14950 | 0 | } |
14951 | | /* reserve some space if this will be the first mbuf */ |
14952 | 0 | if (m == NULL) |
14953 | 0 | SCTP_BUF_RESV_UF(m_auth, SCTP_MIN_OVERHEAD); |
14954 | | /* fill in the AUTH chunk details */ |
14955 | 0 | auth = mtod(m_auth, struct sctp_auth_chunk *); |
14956 | 0 | memset(auth, 0, sizeof(*auth)); |
14957 | 0 | auth->ch.chunk_type = SCTP_AUTHENTICATION; |
14958 | 0 | auth->ch.chunk_flags = 0; |
14959 | 0 | chunk_len = sizeof(*auth) + |
14960 | 0 | sctp_get_hmac_digest_len(stcb->asoc.peer_hmac_id); |
14961 | 0 | auth->ch.chunk_length = htons(chunk_len); |
14962 | 0 | auth->hmac_id = htons(stcb->asoc.peer_hmac_id); |
14963 | | /* key id and hmac digest will be computed and filled in upon send */ |
14964 | | |
14965 | | /* save the offset where the auth was inserted into the chain */ |
14966 | 0 | *offset = 0; |
14967 | 0 | for (cn = m; cn; cn = SCTP_BUF_NEXT(cn)) { |
14968 | 0 | *offset += SCTP_BUF_LEN(cn); |
14969 | 0 | } |
14970 | | |
14971 | | /* update length and return pointer to the auth chunk */ |
14972 | 0 | SCTP_BUF_LEN(m_auth) = chunk_len; |
14973 | 0 | m = sctp_copy_mbufchain(m_auth, m, m_end, 1, chunk_len, 0); |
14974 | 0 | if (auth_ret != NULL) |
14975 | 0 | *auth_ret = auth; |
14976 | |
|
14977 | 0 | return (m); |
14978 | 0 | } |
14979 | | |
14980 | | #if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__) |
14981 | | #ifdef INET6 |
14982 | | int |
14983 | | sctp_v6src_match_nexthop(struct sockaddr_in6 *src6, sctp_route_t *ro) |
14984 | | { |
14985 | | struct nd_prefix *pfx = NULL; |
14986 | | struct nd_pfxrouter *pfxrtr = NULL; |
14987 | | struct sockaddr_in6 gw6; |
14988 | | |
14989 | | #if defined(__FreeBSD__) |
14990 | | if (ro == NULL || ro->ro_nh == NULL || src6->sin6_family != AF_INET6) |
14991 | | #else |
14992 | | if (ro == NULL || ro->ro_rt == NULL || src6->sin6_family != AF_INET6) |
14993 | | #endif |
14994 | | return (0); |
14995 | | |
14996 | | /* get prefix entry of address */ |
14997 | | #if defined(__FreeBSD__) |
14998 | | ND6_RLOCK(); |
14999 | | #endif |
15000 | | LIST_FOREACH(pfx, &MODULE_GLOBAL(nd_prefix), ndpr_entry) { |
15001 | | if (pfx->ndpr_stateflags & NDPRF_DETACHED) |
15002 | | continue; |
15003 | | if (IN6_ARE_MASKED_ADDR_EQUAL(&pfx->ndpr_prefix.sin6_addr, |
15004 | | &src6->sin6_addr, &pfx->ndpr_mask)) |
15005 | | break; |
15006 | | } |
15007 | | /* no prefix entry in the prefix list */ |
15008 | | if (pfx == NULL) { |
15009 | | #if defined(__FreeBSD__) |
15010 | | ND6_RUNLOCK(); |
15011 | | #endif |
15012 | | SCTPDBG(SCTP_DEBUG_OUTPUT2, "No prefix entry for "); |
15013 | | SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)src6); |
15014 | | return (0); |
15015 | | } |
15016 | | |
15017 | | SCTPDBG(SCTP_DEBUG_OUTPUT2, "v6src_match_nexthop(), Prefix entry is "); |
15018 | | SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)src6); |
15019 | | |
15020 | | /* search installed gateway from prefix entry */ |
15021 | | LIST_FOREACH(pfxrtr, &pfx->ndpr_advrtrs, pfr_entry) { |
15022 | | memset(&gw6, 0, sizeof(struct sockaddr_in6)); |
15023 | | gw6.sin6_family = AF_INET6; |
15024 | | #ifdef HAVE_SIN6_LEN |
15025 | | gw6.sin6_len = sizeof(struct sockaddr_in6); |
15026 | | #endif |
15027 | | memcpy(&gw6.sin6_addr, &pfxrtr->router->rtaddr, |
15028 | | sizeof(struct in6_addr)); |
15029 | | SCTPDBG(SCTP_DEBUG_OUTPUT2, "prefix router is "); |
15030 | | SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)&gw6); |
15031 | | SCTPDBG(SCTP_DEBUG_OUTPUT2, "installed router is "); |
15032 | | #if defined(__FreeBSD__) |
15033 | | SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &ro->ro_nh->gw_sa); |
15034 | | #else |
15035 | | SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, ro->ro_rt->rt_gateway); |
15036 | | #endif |
15037 | | #if defined(__FreeBSD__) |
15038 | | if (sctp_cmpaddr((struct sockaddr *)&gw6, &ro->ro_nh->gw_sa)) { |
15039 | | ND6_RUNLOCK(); |
15040 | | #else |
15041 | | if (sctp_cmpaddr((struct sockaddr *)&gw6, ro->ro_rt->rt_gateway)) { |
15042 | | #endif |
15043 | | SCTPDBG(SCTP_DEBUG_OUTPUT2, "pfxrouter is installed\n"); |
15044 | | return (1); |
15045 | | } |
15046 | | } |
15047 | | #if defined(__FreeBSD__) |
15048 | | ND6_RUNLOCK(); |
15049 | | #endif |
15050 | | SCTPDBG(SCTP_DEBUG_OUTPUT2, "pfxrouter is not installed\n"); |
15051 | | return (0); |
15052 | | } |
15053 | | #endif |
15054 | | |
15055 | | int |
15056 | | sctp_v4src_match_nexthop(struct sctp_ifa *sifa, sctp_route_t *ro) |
15057 | | { |
15058 | | #ifdef INET |
15059 | | struct sockaddr_in *sin, *mask; |
15060 | | struct ifaddr *ifa; |
15061 | | struct in_addr srcnetaddr, gwnetaddr; |
15062 | | |
15063 | | #if defined(__FreeBSD__) |
15064 | | if (ro == NULL || ro->ro_nh == NULL || |
15065 | | #else |
15066 | | if (ro == NULL || ro->ro_rt == NULL || |
15067 | | #endif |
15068 | | sifa->address.sa.sa_family != AF_INET) { |
15069 | | return (0); |
15070 | | } |
15071 | | ifa = (struct ifaddr *)sifa->ifa; |
15072 | | mask = (struct sockaddr_in *)(ifa->ifa_netmask); |
15073 | | sin = &sifa->address.sin; |
15074 | | srcnetaddr.s_addr = (sin->sin_addr.s_addr & mask->sin_addr.s_addr); |
15075 | | SCTPDBG(SCTP_DEBUG_OUTPUT2, "match_nexthop4: src address is "); |
15076 | | SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &sifa->address.sa); |
15077 | | SCTPDBG(SCTP_DEBUG_OUTPUT2, "network address is %x\n", srcnetaddr.s_addr); |
15078 | | |
15079 | | #if defined(__FreeBSD__) |
15080 | | sin = &ro->ro_nh->gw4_sa; |
15081 | | #else |
15082 | | sin = (struct sockaddr_in *)ro->ro_rt->rt_gateway; |
15083 | | #endif |
15084 | | gwnetaddr.s_addr = (sin->sin_addr.s_addr & mask->sin_addr.s_addr); |
15085 | | SCTPDBG(SCTP_DEBUG_OUTPUT2, "match_nexthop4: nexthop is "); |
15086 | | #if defined(__FreeBSD__) |
15087 | | SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &ro->ro_nh->gw_sa); |
15088 | | #else |
15089 | | SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, ro->ro_rt->rt_gateway); |
15090 | | #endif |
15091 | | SCTPDBG(SCTP_DEBUG_OUTPUT2, "network address is %x\n", gwnetaddr.s_addr); |
15092 | | if (srcnetaddr.s_addr == gwnetaddr.s_addr) { |
15093 | | return (1); |
15094 | | } |
15095 | | #endif |
15096 | | return (0); |
15097 | | } |
15098 | | #elif defined(__Userspace__) |
15099 | | /* TODO __Userspace__ versions of sctp_vXsrc_match_nexthop(). */ |
15100 | | int |
15101 | | sctp_v6src_match_nexthop(struct sockaddr_in6 *src6, sctp_route_t *ro) |
15102 | 0 | { |
15103 | 0 | return (0); |
15104 | 0 | } |
15105 | | int |
15106 | | sctp_v4src_match_nexthop(struct sctp_ifa *sifa, sctp_route_t *ro) |
15107 | 0 | { |
15108 | 0 | return (0); |
15109 | 0 | } |
15110 | | |
15111 | | #endif |