dma: bump man page date
[dragonfly.git] / sys / netinet / sctputil.c
blob493a7a23179928f62305d4de29adf92c11bb346a
1 /* $KAME: sctputil.c,v 1.36 2005/03/06 16:04:19 itojun Exp $ */
2 /* $DragonFly: src/sys/netinet/sctputil.c,v 1.9 2008/03/07 11:34:20 sephe Exp $ */
4 /*
5 * Copyright (c) 2001, 2002, 2003, 2004 Cisco Systems, Inc.
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Cisco Systems, Inc.
19 * 4. Neither the name of the project nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY CISCO SYSTEMS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL CISCO SYSTEMS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
36 #if !(defined(__OpenBSD__) || defined(__APPLE__))
37 #include "opt_ipsec.h"
38 #endif
39 #if defined(__FreeBSD__) || defined(__DragonFly__)
40 #include "opt_compat.h"
41 #include "opt_inet6.h"
42 #include "opt_inet.h"
43 #if !(defined(SCTP_BASE_FREEBSD) || defined(__DragonFly__))
44 #include "opt_mpath.h"
45 #endif /* SCTP_BASE_FREEBSD || __DragonFly__ */
46 #endif /* FreeBSD */
47 #if defined(__NetBSD__)
48 #include "opt_inet.h"
49 #endif
50 #ifdef __APPLE__
51 #include <sctp.h>
52 #elif !defined(__OpenBSD__)
53 #include "opt_sctp.h"
54 #endif
56 #include <sys/param.h>
57 #include <sys/systm.h>
58 #include <sys/malloc.h>
59 #include <sys/mbuf.h>
60 #include <sys/domain.h>
61 #include <sys/protosw.h>
62 #include <sys/socket.h>
63 #include <sys/socketvar.h>
64 #include <sys/proc.h>
65 #include <sys/kernel.h>
66 #include <sys/sysctl.h>
67 #include <sys/thread2.h>
69 #if defined(__FreeBSD__) || defined(__DragonFly__)
70 #include <sys/callout.h>
71 #else
72 #include <netinet/sctp_callout.h> /* for callout_active() */
73 #endif
75 #include <net/radix.h>
76 #include <net/route.h>
78 #ifdef INET6
79 #ifndef __OpenBSD__
80 #include <sys/domain.h>
81 #endif
82 #endif
84 #if (defined(__FreeBSD__) && __FreeBSD_version >= 500000)
85 #include <sys/limits.h>
86 #else
87 #include <machine/limits.h>
88 #endif
90 #include <net/if.h>
91 #include <net/if_types.h>
92 #include <net/route.h>
94 #include <netinet/in.h>
95 #include <netinet/in_systm.h>
96 #include <netinet/ip.h>
97 #include <netinet/in_pcb.h>
98 #include <netinet/in_var.h>
99 #include <netinet/ip_var.h>
101 #ifdef INET6
102 #include <netinet/ip6.h>
103 #include <netinet6/ip6_var.h>
105 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || defined(__DragonFly_)
106 #include <netinet6/in6_pcb.h>
107 #elif defined(__OpenBSD__)
108 #include <netinet/in_pcb.h>
109 #endif
111 #endif /* INET6 */
113 #include <netinet/sctp_pcb.h>
115 #ifdef IPSEC
116 #ifndef __OpenBSD__
117 #include <netinet6/ipsec.h>
118 #include <netproto/key/key.h>
119 #else
120 #undef IPSEC
121 #endif
122 #endif /* IPSEC */
124 #include <netinet/sctputil.h>
125 #include <netinet/sctp_var.h>
126 #ifdef INET6
127 #include <netinet6/sctp6_var.h>
128 #endif
129 #include <netinet/sctp_header.h>
130 #include <netinet/sctp_output.h>
131 #include <netinet/sctp_hashdriver.h>
132 #include <netinet/sctp_uio.h>
133 #include <netinet/sctp_timer.h>
134 #include <netinet/sctp_crc32.h>
135 #include <netinet/sctp_indata.h> /* for sctp_deliver_data() */
136 #define NUMBER_OF_MTU_SIZES 18
138 #ifdef SCTP_DEBUG
139 extern u_int32_t sctp_debug_on;
140 #endif
142 #ifdef SCTP_STAT_LOGGING
143 int sctp_cwnd_log_at=0;
144 int sctp_cwnd_log_rolled=0;
145 struct sctp_cwnd_log sctp_clog[SCTP_STAT_LOG_SIZE];
147 void
148 sctp_clr_stat_log(void)
150 sctp_cwnd_log_at=0;
151 sctp_cwnd_log_rolled=0;
154 void
155 sctp_log_strm_del_alt(u_int32_t tsn, u_int16_t sseq, int from)
158 sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
159 sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_STRM;
160 sctp_clog[sctp_cwnd_log_at].x.strlog.n_tsn = tsn;
161 sctp_clog[sctp_cwnd_log_at].x.strlog.n_sseq = sseq;
162 sctp_clog[sctp_cwnd_log_at].x.strlog.e_tsn = 0;
163 sctp_clog[sctp_cwnd_log_at].x.strlog.e_sseq = 0;
164 sctp_cwnd_log_at++;
165 if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
166 sctp_cwnd_log_at = 0;
167 sctp_cwnd_log_rolled = 1;
173 void
174 sctp_log_map(uint32_t map, uint32_t cum, uint32_t high, int from)
177 sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
178 sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_MAP;
179 sctp_clog[sctp_cwnd_log_at].x.map.base = map;
180 sctp_clog[sctp_cwnd_log_at].x.map.cum = cum;
181 sctp_clog[sctp_cwnd_log_at].x.map.high = high;
182 sctp_cwnd_log_at++;
183 if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
184 sctp_cwnd_log_at = 0;
185 sctp_cwnd_log_rolled = 1;
189 void
190 sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn,
191 int from)
194 sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
195 sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_FR;
196 sctp_clog[sctp_cwnd_log_at].x.fr.largest_tsn = biggest_tsn;
197 sctp_clog[sctp_cwnd_log_at].x.fr.largest_new_tsn = biggest_new_tsn;
198 sctp_clog[sctp_cwnd_log_at].x.fr.tsn = tsn;
199 sctp_cwnd_log_at++;
200 if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
201 sctp_cwnd_log_at = 0;
202 sctp_cwnd_log_rolled = 1;
206 void
207 sctp_log_strm_del(struct sctp_tmit_chunk *chk, struct sctp_tmit_chunk *poschk,
208 int from)
211 if (chk == NULL) {
212 kprintf("Gak log of NULL?\n");
213 return;
215 sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
216 sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_STRM;
217 sctp_clog[sctp_cwnd_log_at].x.strlog.n_tsn = chk->rec.data.TSN_seq;
218 sctp_clog[sctp_cwnd_log_at].x.strlog.n_sseq = chk->rec.data.stream_seq;
219 if (poschk != NULL) {
220 sctp_clog[sctp_cwnd_log_at].x.strlog.e_tsn =
221 poschk->rec.data.TSN_seq;
222 sctp_clog[sctp_cwnd_log_at].x.strlog.e_sseq =
223 poschk->rec.data.stream_seq;
224 } else {
225 sctp_clog[sctp_cwnd_log_at].x.strlog.e_tsn = 0;
226 sctp_clog[sctp_cwnd_log_at].x.strlog.e_sseq = 0;
228 sctp_cwnd_log_at++;
229 if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
230 sctp_cwnd_log_at = 0;
231 sctp_cwnd_log_rolled = 1;
235 void
236 sctp_log_cwnd(struct sctp_nets *net, int augment, uint8_t from)
239 sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
240 sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_CWND;
241 sctp_clog[sctp_cwnd_log_at].x.cwnd.net = net;
242 sctp_clog[sctp_cwnd_log_at].x.cwnd.cwnd_new_value = net->cwnd;
243 sctp_clog[sctp_cwnd_log_at].x.cwnd.inflight = net->flight_size;
244 sctp_clog[sctp_cwnd_log_at].x.cwnd.cwnd_augment = augment;
245 sctp_cwnd_log_at++;
246 if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
247 sctp_cwnd_log_at = 0;
248 sctp_cwnd_log_rolled = 1;
252 void
253 sctp_log_maxburst(struct sctp_nets *net, int error, int burst, uint8_t from)
255 sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
256 sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_MAXBURST;
257 sctp_clog[sctp_cwnd_log_at].x.cwnd.net = net;
258 sctp_clog[sctp_cwnd_log_at].x.cwnd.cwnd_new_value = error;
259 sctp_clog[sctp_cwnd_log_at].x.cwnd.inflight = net->flight_size;
260 sctp_clog[sctp_cwnd_log_at].x.cwnd.cwnd_augment = burst;
261 sctp_cwnd_log_at++;
262 if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
263 sctp_cwnd_log_at = 0;
264 sctp_cwnd_log_rolled = 1;
268 void
269 sctp_log_rwnd(uint8_t from, u_int32_t peers_rwnd , u_int32_t snd_size, u_int32_t overhead)
271 sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
272 sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_RWND;
273 sctp_clog[sctp_cwnd_log_at].x.rwnd.rwnd = peers_rwnd;
274 sctp_clog[sctp_cwnd_log_at].x.rwnd.send_size = snd_size;
275 sctp_clog[sctp_cwnd_log_at].x.rwnd.overhead = overhead;
276 sctp_clog[sctp_cwnd_log_at].x.rwnd.new_rwnd = 0;
277 sctp_cwnd_log_at++;
278 if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
279 sctp_cwnd_log_at = 0;
280 sctp_cwnd_log_rolled = 1;
284 void
285 sctp_log_rwnd_set(uint8_t from, u_int32_t peers_rwnd , u_int32_t flight_size, u_int32_t overhead, u_int32_t a_rwndval)
287 sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
288 sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_RWND;
289 sctp_clog[sctp_cwnd_log_at].x.rwnd.rwnd = peers_rwnd;
290 sctp_clog[sctp_cwnd_log_at].x.rwnd.send_size = flight_size;
291 sctp_clog[sctp_cwnd_log_at].x.rwnd.overhead = overhead;
292 sctp_clog[sctp_cwnd_log_at].x.rwnd.new_rwnd = a_rwndval;
293 sctp_cwnd_log_at++;
294 if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
295 sctp_cwnd_log_at = 0;
296 sctp_cwnd_log_rolled = 1;
300 void
301 sctp_log_mbcnt(uint8_t from, u_int32_t total_oq , u_int32_t book, u_int32_t total_mbcnt_q, u_int32_t mbcnt)
303 sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
304 sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_MBCNT;
305 sctp_clog[sctp_cwnd_log_at].x.mbcnt.total_queue_size = total_oq;
306 sctp_clog[sctp_cwnd_log_at].x.mbcnt.size_change = book;
307 sctp_clog[sctp_cwnd_log_at].x.mbcnt.total_queue_mb_size = total_mbcnt_q;
308 sctp_clog[sctp_cwnd_log_at].x.mbcnt.mbcnt_change = mbcnt;
309 sctp_cwnd_log_at++;
310 if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
311 sctp_cwnd_log_at = 0;
312 sctp_cwnd_log_rolled = 1;
316 void
317 sctp_log_block(uint8_t from, struct socket *so, struct sctp_association *asoc)
320 sctp_clog[sctp_cwnd_log_at].from = (u_int8_t)from;
321 sctp_clog[sctp_cwnd_log_at].event_type = (u_int8_t)SCTP_LOG_EVENT_BLOCK;
322 sctp_clog[sctp_cwnd_log_at].x.blk.maxmb = (u_int16_t)(so->so_snd.ssb_mbmax/1024);
323 sctp_clog[sctp_cwnd_log_at].x.blk.onmb = asoc->total_output_mbuf_queue_size;
324 sctp_clog[sctp_cwnd_log_at].x.blk.maxsb = (u_int16_t)(so->so_snd.ssb_hiwat/1024);
325 sctp_clog[sctp_cwnd_log_at].x.blk.onsb = asoc->total_output_queue_size;
326 sctp_clog[sctp_cwnd_log_at].x.blk.send_sent_qcnt = (u_int16_t)(asoc->send_queue_cnt + asoc->sent_queue_cnt);
327 sctp_clog[sctp_cwnd_log_at].x.blk.stream_qcnt = (u_int16_t)asoc->stream_queue_cnt;
328 sctp_cwnd_log_at++;
329 if (sctp_cwnd_log_at >= SCTP_STAT_LOG_SIZE) {
330 sctp_cwnd_log_at = 0;
331 sctp_cwnd_log_rolled = 1;
336 sctp_fill_stat_log(struct mbuf *m)
338 struct sctp_cwnd_log_req *req;
339 int size_limit, num, i, at, cnt_out=0;
341 if (m == NULL)
342 return (EINVAL);
344 size_limit = (m->m_len - sizeof(struct sctp_cwnd_log_req));
345 if (size_limit < sizeof(struct sctp_cwnd_log)) {
346 return (EINVAL);
348 req = mtod(m, struct sctp_cwnd_log_req *);
349 num = size_limit/sizeof(struct sctp_cwnd_log);
350 if (sctp_cwnd_log_rolled) {
351 req->num_in_log = SCTP_STAT_LOG_SIZE;
352 } else {
353 req->num_in_log = sctp_cwnd_log_at;
354 /* if the log has not rolled, we don't
355 * let you have old data.
357 if (req->end_at > sctp_cwnd_log_at) {
358 req->end_at = sctp_cwnd_log_at;
361 if ((num < SCTP_STAT_LOG_SIZE) &&
362 ((sctp_cwnd_log_rolled) || (sctp_cwnd_log_at > num))) {
363 /* we can't return all of it */
364 if (((req->start_at == 0) && (req->end_at == 0)) ||
365 (req->start_at >= SCTP_STAT_LOG_SIZE) ||
366 (req->end_at >= SCTP_STAT_LOG_SIZE)) {
367 /* No user request or user is wacked. */
368 req->num_ret = num;
369 req->end_at = sctp_cwnd_log_at - 1;
370 if ((sctp_cwnd_log_at - num) < 0) {
371 int cc;
372 cc = num - sctp_cwnd_log_at;
373 req->start_at = SCTP_STAT_LOG_SIZE - cc;
374 } else {
375 req->start_at = sctp_cwnd_log_at - num;
377 } else {
378 /* a user request */
379 int cc;
380 if (req->start_at > req->end_at) {
381 cc = (SCTP_STAT_LOG_SIZE - req->start_at) +
382 (req->end_at + 1);
383 } else {
385 cc = req->end_at - req->start_at;
387 if (cc < num) {
388 num = cc;
390 req->num_ret = num;
392 } else {
393 /* We can return all of it */
394 req->start_at = 0;
395 req->end_at = sctp_cwnd_log_at - 1;
396 req->num_ret = sctp_cwnd_log_at;
398 for (i = 0, at = req->start_at; i < req->num_ret; i++) {
399 req->log[i] = sctp_clog[at];
400 cnt_out++;
401 at++;
402 if (at >= SCTP_STAT_LOG_SIZE)
403 at = 0;
405 m->m_len = (cnt_out * sizeof(struct sctp_cwnd_log_req)) + sizeof(struct sctp_cwnd_log_req);
406 return (0);
409 #endif
411 #ifdef SCTP_AUDITING_ENABLED
412 u_int8_t sctp_audit_data[SCTP_AUDIT_SIZE][2];
413 static int sctp_audit_indx = 0;
415 static void
416 sctp_print_audit_report(void)
418 int i;
419 int cnt;
420 cnt = 0;
421 for (i=sctp_audit_indx;i<SCTP_AUDIT_SIZE;i++) {
422 if ((sctp_audit_data[i][0] == 0xe0) &&
423 (sctp_audit_data[i][1] == 0x01)) {
424 cnt = 0;
425 kprintf("\n");
426 } else if (sctp_audit_data[i][0] == 0xf0) {
427 cnt = 0;
428 kprintf("\n");
429 } else if ((sctp_audit_data[i][0] == 0xc0) &&
430 (sctp_audit_data[i][1] == 0x01)) {
431 kprintf("\n");
432 cnt = 0;
434 kprintf("%2.2x%2.2x ", (uint32_t)sctp_audit_data[i][0],
435 (uint32_t)sctp_audit_data[i][1]);
436 cnt++;
437 if ((cnt % 14) == 0)
438 kprintf("\n");
440 for (i=0;i<sctp_audit_indx;i++) {
441 if ((sctp_audit_data[i][0] == 0xe0) &&
442 (sctp_audit_data[i][1] == 0x01)) {
443 cnt = 0;
444 kprintf("\n");
445 } else if (sctp_audit_data[i][0] == 0xf0) {
446 cnt = 0;
447 kprintf("\n");
448 } else if ((sctp_audit_data[i][0] == 0xc0) &&
449 (sctp_audit_data[i][1] == 0x01)) {
450 kprintf("\n");
451 cnt = 0;
453 kprintf("%2.2x%2.2x ", (uint32_t)sctp_audit_data[i][0],
454 (uint32_t)sctp_audit_data[i][1]);
455 cnt++;
456 if ((cnt % 14) == 0)
457 kprintf("\n");
459 kprintf("\n");
462 void
463 sctp_auditing(int from, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
464 struct sctp_nets *net)
466 int resend_cnt, tot_out, rep, tot_book_cnt;
467 struct sctp_nets *lnet;
468 struct sctp_tmit_chunk *chk;
470 sctp_audit_data[sctp_audit_indx][0] = 0xAA;
471 sctp_audit_data[sctp_audit_indx][1] = 0x000000ff & from;
472 sctp_audit_indx++;
473 if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
474 sctp_audit_indx = 0;
476 if (inp == NULL) {
477 sctp_audit_data[sctp_audit_indx][0] = 0xAF;
478 sctp_audit_data[sctp_audit_indx][1] = 0x01;
479 sctp_audit_indx++;
480 if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
481 sctp_audit_indx = 0;
483 return;
485 if (stcb == NULL) {
486 sctp_audit_data[sctp_audit_indx][0] = 0xAF;
487 sctp_audit_data[sctp_audit_indx][1] = 0x02;
488 sctp_audit_indx++;
489 if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
490 sctp_audit_indx = 0;
492 return;
494 sctp_audit_data[sctp_audit_indx][0] = 0xA1;
495 sctp_audit_data[sctp_audit_indx][1] =
496 (0x000000ff & stcb->asoc.sent_queue_retran_cnt);
497 sctp_audit_indx++;
498 if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
499 sctp_audit_indx = 0;
501 rep = 0;
502 tot_book_cnt = 0;
503 resend_cnt = tot_out = 0;
504 TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
505 if (chk->sent == SCTP_DATAGRAM_RESEND) {
506 resend_cnt++;
507 } else if (chk->sent < SCTP_DATAGRAM_RESEND) {
508 tot_out += chk->book_size;
509 tot_book_cnt++;
512 if (resend_cnt != stcb->asoc.sent_queue_retran_cnt) {
513 sctp_audit_data[sctp_audit_indx][0] = 0xAF;
514 sctp_audit_data[sctp_audit_indx][1] = 0xA1;
515 sctp_audit_indx++;
516 if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
517 sctp_audit_indx = 0;
519 kprintf("resend_cnt:%d asoc-tot:%d\n",
520 resend_cnt, stcb->asoc.sent_queue_retran_cnt);
521 rep = 1;
522 stcb->asoc.sent_queue_retran_cnt = resend_cnt;
523 sctp_audit_data[sctp_audit_indx][0] = 0xA2;
524 sctp_audit_data[sctp_audit_indx][1] =
525 (0x000000ff & stcb->asoc.sent_queue_retran_cnt);
526 sctp_audit_indx++;
527 if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
528 sctp_audit_indx = 0;
531 if (tot_out != stcb->asoc.total_flight) {
532 sctp_audit_data[sctp_audit_indx][0] = 0xAF;
533 sctp_audit_data[sctp_audit_indx][1] = 0xA2;
534 sctp_audit_indx++;
535 if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
536 sctp_audit_indx = 0;
538 rep = 1;
539 kprintf("tot_flt:%d asoc_tot:%d\n", tot_out,
540 (int)stcb->asoc.total_flight);
541 stcb->asoc.total_flight = tot_out;
543 if (tot_book_cnt != stcb->asoc.total_flight_count) {
544 sctp_audit_data[sctp_audit_indx][0] = 0xAF;
545 sctp_audit_data[sctp_audit_indx][1] = 0xA5;
546 sctp_audit_indx++;
547 if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
548 sctp_audit_indx = 0;
550 rep = 1;
551 kprintf("tot_flt_book:%d\n", tot_book);
553 stcb->asoc.total_flight_count = tot_book_cnt;
555 tot_out = 0;
556 TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
557 tot_out += lnet->flight_size;
559 if (tot_out != stcb->asoc.total_flight) {
560 sctp_audit_data[sctp_audit_indx][0] = 0xAF;
561 sctp_audit_data[sctp_audit_indx][1] = 0xA3;
562 sctp_audit_indx++;
563 if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
564 sctp_audit_indx = 0;
566 rep = 1;
567 kprintf("real flight:%d net total was %d\n",
568 stcb->asoc.total_flight, tot_out);
569 /* now corrective action */
570 TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
571 tot_out = 0;
572 TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
573 if ((chk->whoTo == lnet) &&
574 (chk->sent < SCTP_DATAGRAM_RESEND)) {
575 tot_out += chk->book_size;
578 if (lnet->flight_size != tot_out) {
579 kprintf("net:%x flight was %d corrected to %d\n",
580 (uint32_t)lnet, lnet->flight_size, tot_out);
581 lnet->flight_size = tot_out;
587 if (rep) {
588 sctp_print_audit_report();
592 void
593 sctp_audit_log(u_int8_t ev, u_int8_t fd)
595 crit_enter();
596 sctp_audit_data[sctp_audit_indx][0] = ev;
597 sctp_audit_data[sctp_audit_indx][1] = fd;
598 sctp_audit_indx++;
599 if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
600 sctp_audit_indx = 0;
602 crit_exit();
605 #endif
608 * a list of sizes based on typical mtu's, used only if next hop
609 * size not returned.
611 static int sctp_mtu_sizes[] = {
613 296,
614 508,
615 512,
616 544,
617 576,
618 1006,
619 1492,
620 1500,
621 1536,
622 2002,
623 2048,
624 4352,
625 4464,
626 8166,
627 17914,
628 32000,
629 65535
633 find_next_best_mtu(int totsz)
635 int i, perfer;
637 * if we are in here we must find the next best fit based on the
638 * size of the dg that failed to be sent.
640 perfer = 0;
641 for (i = 0; i < NUMBER_OF_MTU_SIZES; i++) {
642 if (totsz < sctp_mtu_sizes[i]) {
643 perfer = i - 1;
644 if (perfer < 0)
645 perfer = 0;
646 break;
649 return (sctp_mtu_sizes[perfer]);
652 void
653 sctp_fill_random_store(struct sctp_pcb *m)
656 * Here we use the MD5/SHA-1 to hash with our good randomNumbers
657 * and our counter. The result becomes our good random numbers and
658 * we then setup to give these out. Note that we do no lockig
659 * to protect this. This is ok, since if competing folks call
660 * this we will get more gobbled gook in the random store whic
661 * is what we want. There is a danger that two guys will use
662 * the same random numbers, but thats ok too since that
663 * is random as well :->
665 m->store_at = 0;
666 sctp_hash_digest((char *)m->random_numbers, sizeof(m->random_numbers),
667 (char *)&m->random_counter, sizeof(m->random_counter),
668 (char *)m->random_store);
669 m->random_counter++;
672 uint32_t
673 sctp_select_initial_TSN(struct sctp_pcb *m)
676 * A true implementation should use random selection process to
677 * get the initial stream sequence number, using RFC1750 as a
678 * good guideline
680 u_long x, *xp;
681 uint8_t *p;
683 if (m->initial_sequence_debug != 0) {
684 u_int32_t ret;
685 ret = m->initial_sequence_debug;
686 m->initial_sequence_debug++;
687 return (ret);
689 if ((m->store_at+sizeof(u_long)) > SCTP_SIGNATURE_SIZE) {
690 /* Refill the random store */
691 sctp_fill_random_store(m);
693 p = &m->random_store[(int)m->store_at];
694 xp = (u_long *)p;
695 x = *xp;
696 m->store_at += sizeof(u_long);
697 return (x);
700 u_int32_t
701 sctp_select_a_tag(struct sctp_inpcb *m)
703 u_long x, not_done;
704 struct timeval now;
706 SCTP_GETTIME_TIMEVAL(&now);
707 not_done = 1;
708 while (not_done) {
709 x = sctp_select_initial_TSN(&m->sctp_ep);
710 if (x == 0) {
711 /* we never use 0 */
712 continue;
714 if (sctp_is_vtag_good(m, x, &now)) {
715 not_done = 0;
718 return (x);
723 sctp_init_asoc(struct sctp_inpcb *m, struct sctp_association *asoc,
724 int for_a_init, uint32_t override_tag )
727 * Anything set to zero is taken care of by the allocation
728 * routine's bzero
732 * Up front select what scoping to apply on addresses I tell my peer
733 * Not sure what to do with these right now, we will need to come up
734 * with a way to set them. We may need to pass them through from the
735 * caller in the sctp_aloc_assoc() function.
737 int i;
738 /* init all variables to a known value.*/
739 asoc->state = SCTP_STATE_INUSE;
740 asoc->max_burst = m->sctp_ep.max_burst;
741 asoc->heart_beat_delay = m->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT];
742 asoc->cookie_life = m->sctp_ep.def_cookie_life;
744 if (override_tag) {
745 asoc->my_vtag = override_tag;
746 } else {
747 asoc->my_vtag = sctp_select_a_tag(m);
749 asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number = asoc->sending_seq =
750 sctp_select_initial_TSN(&m->sctp_ep);
751 asoc->t3timeout_highest_marked = asoc->asconf_seq_out;
752 /* we are opptimisitic here */
753 asoc->peer_supports_asconf = 1;
754 asoc->peer_supports_asconf_setprim = 1;
755 asoc->peer_supports_pktdrop = 1;
757 asoc->sent_queue_retran_cnt = 0;
758 /* This will need to be adjusted */
759 asoc->last_cwr_tsn = asoc->init_seq_number - 1;
760 asoc->last_acked_seq = asoc->init_seq_number - 1;
761 asoc->advanced_peer_ack_point = asoc->last_acked_seq;
762 asoc->asconf_seq_in = asoc->last_acked_seq;
764 /* here we are different, we hold the next one we expect */
765 asoc->str_reset_seq_in = asoc->last_acked_seq + 1;
767 asoc->initial_init_rto_max = m->sctp_ep.initial_init_rto_max;
768 asoc->initial_rto = m->sctp_ep.initial_rto;
770 asoc->max_init_times = m->sctp_ep.max_init_times;
771 asoc->max_send_times = m->sctp_ep.max_send_times;
772 asoc->def_net_failure = m->sctp_ep.def_net_failure;
774 /* ECN Nonce initialization */
775 asoc->ecn_nonce_allowed = 0;
776 asoc->receiver_nonce_sum = 1;
777 asoc->nonce_sum_expect_base = 1;
778 asoc->nonce_sum_check = 1;
779 asoc->nonce_resync_tsn = 0;
780 asoc->nonce_wait_for_ecne = 0;
781 asoc->nonce_wait_tsn = 0;
783 if (m->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
784 struct in6pcb *inp6;
787 /* Its a V6 socket */
788 inp6 = (struct in6pcb *)m;
789 asoc->ipv6_addr_legal = 1;
790 /* Now look at the binding flag to see if V4 will be legal */
791 if (
792 #if defined(__OpenBSD__)
793 (0) /* we always do dual bind */
794 #elif defined (__NetBSD__)
795 (inp6->in6p_flags & IN6P_IPV6_V6ONLY)
796 #else
797 (inp6->inp_flags & IN6P_IPV6_V6ONLY)
798 #endif
799 == 0) {
800 asoc->ipv4_addr_legal = 1;
801 } else {
802 /* V4 addresses are NOT legal on the association */
803 asoc->ipv4_addr_legal = 0;
805 } else {
806 /* Its a V4 socket, no - V6 */
807 asoc->ipv4_addr_legal = 1;
808 asoc->ipv6_addr_legal = 0;
812 asoc->my_rwnd = max(m->sctp_socket->so_rcv.ssb_hiwat, SCTP_MINIMAL_RWND);
813 asoc->peers_rwnd = m->sctp_socket->so_rcv.ssb_hiwat;
815 asoc->smallest_mtu = m->sctp_frag_point;
816 asoc->minrto = m->sctp_ep.sctp_minrto;
817 asoc->maxrto = m->sctp_ep.sctp_maxrto;
819 LIST_INIT(&asoc->sctp_local_addr_list);
820 TAILQ_INIT(&asoc->nets);
821 TAILQ_INIT(&asoc->pending_reply_queue);
822 asoc->last_asconf_ack_sent = NULL;
823 /* Setup to fill the hb random cache at first HB */
824 asoc->hb_random_idx = 4;
826 asoc->sctp_autoclose_ticks = m->sctp_ep.auto_close_time;
829 * Now the stream parameters, here we allocate space for all
830 * streams that we request by default.
832 asoc->streamoutcnt = asoc->pre_open_streams =
833 m->sctp_ep.pre_open_stream_count;
834 MALLOC(asoc->strmout, struct sctp_stream_out *, asoc->streamoutcnt *
835 sizeof(struct sctp_stream_out), M_PCB, M_NOWAIT);
836 if (asoc->strmout == NULL) {
837 /* big trouble no memory */
838 return (ENOMEM);
840 for (i = 0; i < asoc->streamoutcnt; i++) {
842 * inbound side must be set to 0xffff,
843 * also NOTE when we get the INIT-ACK back (for INIT sender)
844 * we MUST reduce the count (streamoutcnt) but first check
845 * if we sent to any of the upper streams that were dropped
846 * (if some were). Those that were dropped must be notified
847 * to the upper layer as failed to send.
849 asoc->strmout[i].next_sequence_sent = 0x0;
850 TAILQ_INIT(&asoc->strmout[i].outqueue);
851 asoc->strmout[i].stream_no = i;
852 asoc->strmout[i].next_spoke.tqe_next = 0;
853 asoc->strmout[i].next_spoke.tqe_prev = 0;
855 /* Now the mapping array */
856 asoc->mapping_array_size = SCTP_INITIAL_MAPPING_ARRAY;
857 #ifdef __NetBSD__
858 MALLOC(asoc->mapping_array, u_int8_t *, SCTP_INITIAL_MAPPING_ARRAY,
859 M_PCB, M_NOWAIT);
860 #else
861 MALLOC(asoc->mapping_array, u_int8_t *, asoc->mapping_array_size,
862 M_PCB, M_NOWAIT);
863 #endif
864 if (asoc->mapping_array == NULL) {
865 FREE(asoc->strmout, M_PCB);
866 return (ENOMEM);
868 memset(asoc->mapping_array, 0, asoc->mapping_array_size);
869 /* Now the init of the other outqueues */
870 TAILQ_INIT(&asoc->out_wheel);
871 TAILQ_INIT(&asoc->control_send_queue);
872 TAILQ_INIT(&asoc->send_queue);
873 TAILQ_INIT(&asoc->sent_queue);
874 TAILQ_INIT(&asoc->reasmqueue);
875 TAILQ_INIT(&asoc->delivery_queue);
876 asoc->max_inbound_streams = m->sctp_ep.max_open_streams_intome;
878 TAILQ_INIT(&asoc->asconf_queue);
879 return (0);
883 sctp_expand_mapping_array(struct sctp_association *asoc)
885 /* mapping array needs to grow */
886 u_int8_t *new_array;
887 uint16_t new_size;
889 new_size = asoc->mapping_array_size + SCTP_MAPPING_ARRAY_INCR;
890 #ifdef __NetBSD__
891 MALLOC(new_array, u_int8_t *, asoc->mapping_array_size
892 + SCTP_MAPPING_ARRAY_INCR, M_PCB, M_NOWAIT);
893 #else
894 MALLOC(new_array, u_int8_t *, new_size, M_PCB, M_NOWAIT);
895 #endif
896 if (new_array == NULL) {
897 /* can't get more, forget it */
898 kprintf("No memory for expansion of SCTP mapping array %d\n",
899 new_size);
900 return (-1);
902 memset(new_array, 0, new_size);
903 memcpy(new_array, asoc->mapping_array, asoc->mapping_array_size);
904 FREE(asoc->mapping_array, M_PCB);
905 asoc->mapping_array = new_array;
906 asoc->mapping_array_size = new_size;
907 return (0);
910 static void
911 sctp_timeout_handler(void *t)
913 struct sctp_inpcb *inp;
914 struct sctp_tcb *stcb;
915 struct sctp_nets *net;
916 struct sctp_timer *tmr;
917 int did_output, typ;
918 #if defined(__APPLE__)
919 boolean_t funnel_state;
921 /* get BSD kernel funnel/mutex */
922 funnel_state = thread_funnel_set(network_flock, TRUE);
923 #endif
925 crit_enter();
926 tmr = (struct sctp_timer *)t;
927 inp = (struct sctp_inpcb *)tmr->ep;
928 stcb = (struct sctp_tcb *)tmr->tcb;
929 net = (struct sctp_nets *)tmr->net;
930 did_output = 1;
933 #ifdef SCTP_AUDITING_ENABLED
934 sctp_audit_log(0xF0, (u_int8_t)tmr->type);
935 sctp_auditing(3, inp, stcb, net);
936 #endif
937 sctp_pegs[SCTP_TIMERS_EXP]++;
939 if (inp == NULL) {
940 return;
943 SCTP_INP_WLOCK(inp);
944 if (inp->sctp_socket == 0) {
945 crit_exit();
946 #if defined(__APPLE__)
947 /* release BSD kernel funnel/mutex */
948 thread_funnel_set(network_flock, FALSE);
949 #endif
950 SCTP_INP_WUNLOCK(inp);
951 return;
953 if (stcb) {
954 if (stcb->asoc.state == 0) {
955 crit_exit();
956 #if defined(__APPLE__)
957 /* release BSD kernel funnel/mutex */
958 thread_funnel_set(network_flock, FALSE);
959 #endif
960 SCTP_INP_WUNLOCK(inp);
961 return;
964 #ifdef SCTP_DEBUG
965 if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
966 kprintf("Timer type %d goes off\n", tmr->type);
968 #endif /* SCTP_DEBUG */
969 #ifndef __NetBSD__
970 if (!callout_active(&tmr->timer)) {
971 crit_exit();
972 #if defined(__APPLE__)
973 /* release BSD kernel funnel/mutex */
974 thread_funnel_set(network_flock, FALSE);
975 #endif
976 SCTP_INP_WUNLOCK(inp);
977 return;
979 #endif
980 #if defined(__APPLE__)
981 /* clear the callout pending status here */
982 callout_stop(&tmr->timer);
983 #endif
984 if (stcb) {
985 SCTP_TCB_LOCK(stcb);
987 SCTP_INP_INCR_REF(inp);
988 SCTP_INP_WUNLOCK(inp);
990 typ = tmr->type;
991 switch (tmr->type) {
992 case SCTP_TIMER_TYPE_ITERATOR:
994 struct sctp_iterator *it;
995 it = (struct sctp_iterator *)inp;
996 sctp_iterator_timer(it);
998 break;
999 /* call the handler for the appropriate timer type */
1000 case SCTP_TIMER_TYPE_SEND:
1001 sctp_pegs[SCTP_TMIT_TIMER]++;
1002 stcb->asoc.num_send_timers_up--;
1003 if (stcb->asoc.num_send_timers_up < 0) {
1004 stcb->asoc.num_send_timers_up = 0;
1006 if (sctp_t3rxt_timer(inp, stcb, net)) {
1007 /* no need to unlock on tcb its gone */
1009 goto out_decr;
1011 #ifdef SCTP_AUDITING_ENABLED
1012 sctp_auditing(4, inp, stcb, net);
1013 #endif
1014 sctp_chunk_output(inp, stcb, 1);
1015 if ((stcb->asoc.num_send_timers_up == 0) &&
1016 (stcb->asoc.sent_queue_cnt > 0)
1018 struct sctp_tmit_chunk *chk;
1020 * safeguard. If there on some on the sent queue
1021 * somewhere but no timers running something is
1022 * wrong... so we start a timer on the first chunk
1023 * on the send queue on whatever net it is sent to.
1025 sctp_pegs[SCTP_T3_SAFEGRD]++;
1026 chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
1027 sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb,
1028 chk->whoTo);
1030 break;
1031 case SCTP_TIMER_TYPE_INIT:
1032 if (sctp_t1init_timer(inp, stcb, net)) {
1033 /* no need to unlock on tcb its gone */
1034 goto out_decr;
1036 /* We do output but not here */
1037 did_output = 0;
1038 break;
1039 case SCTP_TIMER_TYPE_RECV:
1040 sctp_pegs[SCTP_RECV_TIMER]++;
1041 sctp_send_sack(stcb);
1042 #ifdef SCTP_AUDITING_ENABLED
1043 sctp_auditing(4, inp, stcb, net);
1044 #endif
1045 sctp_chunk_output(inp, stcb, 4);
1046 break;
1047 case SCTP_TIMER_TYPE_SHUTDOWN:
1048 if (sctp_shutdown_timer(inp, stcb, net) ) {
1049 /* no need to unlock on tcb its gone */
1050 goto out_decr;
1052 #ifdef SCTP_AUDITING_ENABLED
1053 sctp_auditing(4, inp, stcb, net);
1054 #endif
1055 sctp_chunk_output(inp, stcb, 5);
1056 break;
1057 case SCTP_TIMER_TYPE_HEARTBEAT:
1058 if (sctp_heartbeat_timer(inp, stcb, net)) {
1059 /* no need to unlock on tcb its gone */
1060 goto out_decr;
1062 #ifdef SCTP_AUDITING_ENABLED
1063 sctp_auditing(4, inp, stcb, net);
1064 #endif
1065 sctp_chunk_output(inp, stcb, 6);
1066 break;
1067 case SCTP_TIMER_TYPE_COOKIE:
1068 if (sctp_cookie_timer(inp, stcb, net)) {
1069 /* no need to unlock on tcb its gone */
1070 goto out_decr;
1072 #ifdef SCTP_AUDITING_ENABLED
1073 sctp_auditing(4, inp, stcb, net);
1074 #endif
1075 sctp_chunk_output(inp, stcb, 1);
1076 break;
1077 case SCTP_TIMER_TYPE_NEWCOOKIE:
1079 struct timeval tv;
1080 int i, secret;
1081 SCTP_GETTIME_TIMEVAL(&tv);
1082 SCTP_INP_WLOCK(inp);
1083 inp->sctp_ep.time_of_secret_change = tv.tv_sec;
1084 inp->sctp_ep.last_secret_number =
1085 inp->sctp_ep.current_secret_number;
1086 inp->sctp_ep.current_secret_number++;
1087 if (inp->sctp_ep.current_secret_number >=
1088 SCTP_HOW_MANY_SECRETS) {
1089 inp->sctp_ep.current_secret_number = 0;
1091 secret = (int)inp->sctp_ep.current_secret_number;
1092 for (i = 0; i < SCTP_NUMBER_OF_SECRETS; i++) {
1093 inp->sctp_ep.secret_key[secret][i] =
1094 sctp_select_initial_TSN(&inp->sctp_ep);
1096 SCTP_INP_WUNLOCK(inp);
1097 sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, stcb, net);
1099 did_output = 0;
1100 break;
1101 case SCTP_TIMER_TYPE_PATHMTURAISE:
1102 sctp_pathmtu_timer(inp, stcb, net);
1103 did_output = 0;
1104 break;
1105 case SCTP_TIMER_TYPE_SHUTDOWNACK:
1106 if (sctp_shutdownack_timer(inp, stcb, net)) {
1107 /* no need to unlock on tcb its gone */
1108 goto out_decr;
1110 #ifdef SCTP_AUDITING_ENABLED
1111 sctp_auditing(4, inp, stcb, net);
1112 #endif
1113 sctp_chunk_output(inp, stcb, 7);
1114 break;
1115 case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
1116 sctp_abort_an_association(inp, stcb,
1117 SCTP_SHUTDOWN_GUARD_EXPIRES, NULL);
1118 /* no need to unlock on tcb its gone */
1119 goto out_decr;
1120 break;
1122 case SCTP_TIMER_TYPE_STRRESET:
1123 if (sctp_strreset_timer(inp, stcb, net)) {
1124 /* no need to unlock on tcb its gone */
1125 goto out_decr;
1127 sctp_chunk_output(inp, stcb, 9);
1128 break;
1130 case SCTP_TIMER_TYPE_ASCONF:
1131 if (sctp_asconf_timer(inp, stcb, net)) {
1132 /* no need to unlock on tcb its gone */
1133 goto out_decr;
1135 #ifdef SCTP_AUDITING_ENABLED
1136 sctp_auditing(4, inp, stcb, net);
1137 #endif
1138 sctp_chunk_output(inp, stcb, 8);
1139 break;
1141 case SCTP_TIMER_TYPE_AUTOCLOSE:
1142 sctp_autoclose_timer(inp, stcb, net);
1143 sctp_chunk_output(inp, stcb, 10);
1144 did_output = 0;
1145 break;
1146 case SCTP_TIMER_TYPE_INPKILL:
1147 /* special case, take away our
1148 * increment since WE are the killer
1150 SCTP_INP_WLOCK(inp);
1151 SCTP_INP_DECR_REF(inp);
1152 SCTP_INP_WUNLOCK(inp);
1153 sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL);
1154 sctp_inpcb_free(inp, 1);
1155 goto out_no_decr;
1156 break;
1157 default:
1158 #ifdef SCTP_DEBUG
1159 if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
1160 kprintf("sctp_timeout_handler:unknown timer %d\n",
1161 tmr->type);
1163 #endif /* SCTP_DEBUG */
1164 break;
1166 #ifdef SCTP_AUDITING_ENABLED
1167 sctp_audit_log(0xF1, (u_int8_t)tmr->type);
1168 sctp_auditing(5, inp, stcb, net);
1169 #endif
1170 if (did_output) {
1172 * Now we need to clean up the control chunk chain if an
1173 * ECNE is on it. It must be marked as UNSENT again so next
1174 * call will continue to send it until such time that we get
1175 * a CWR, to remove it. It is, however, less likely that we
1176 * will find a ecn echo on the chain though.
1178 sctp_fix_ecn_echo(&stcb->asoc);
1180 if (stcb) {
1181 SCTP_TCB_UNLOCK(stcb);
1183 out_decr:
1184 SCTP_INP_WLOCK(inp);
1185 SCTP_INP_DECR_REF(inp);
1186 SCTP_INP_WUNLOCK(inp);
1188 out_no_decr:
1190 #ifdef SCTP_DEBUG
1191 if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
1192 kprintf("Timer now complete (type %d)\n", typ);
1194 #endif /* SCTP_DEBUG */
1196 crit_exit();
1197 #if defined(__APPLE__)
1198 /* release BSD kernel funnel/mutex */
1199 thread_funnel_set(network_flock, FALSE);
1200 #endif
1204 sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1205 struct sctp_nets *net)
1207 int to_ticks;
1208 struct sctp_timer *tmr;
1210 if (inp == NULL)
1211 return (EFAULT);
1213 to_ticks = 0;
1215 tmr = NULL;
1216 switch (t_type) {
1217 case SCTP_TIMER_TYPE_ITERATOR:
1219 struct sctp_iterator *it;
1220 it = (struct sctp_iterator *)inp;
1221 tmr = &it->tmr;
1222 to_ticks = SCTP_ITERATOR_TICKS;
1224 break;
1225 case SCTP_TIMER_TYPE_SEND:
1226 /* Here we use the RTO timer */
1228 int rto_val;
1229 if ((stcb == NULL) || (net == NULL)) {
1230 return (EFAULT);
1232 tmr = &net->rxt_timer;
1233 if (net->RTO == 0) {
1234 rto_val = stcb->asoc.initial_rto;
1235 } else {
1236 rto_val = net->RTO;
1238 to_ticks = MSEC_TO_TICKS(rto_val);
1240 break;
1241 case SCTP_TIMER_TYPE_INIT:
1243 * Here we use the INIT timer default
1244 * usually about 1 minute.
1246 if ((stcb == NULL) || (net == NULL)) {
1247 return (EFAULT);
1249 tmr = &net->rxt_timer;
1250 if (net->RTO == 0) {
1251 to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
1252 } else {
1253 to_ticks = MSEC_TO_TICKS(net->RTO);
1255 break;
1256 case SCTP_TIMER_TYPE_RECV:
1258 * Here we use the Delayed-Ack timer value from the inp
1259 * ususually about 200ms.
1261 if (stcb == NULL) {
1262 return (EFAULT);
1264 tmr = &stcb->asoc.dack_timer;
1265 to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV];
1266 break;
1267 case SCTP_TIMER_TYPE_SHUTDOWN:
1268 /* Here we use the RTO of the destination. */
1269 if ((stcb == NULL) || (net == NULL)) {
1270 return (EFAULT);
1273 if (net->RTO == 0) {
1274 to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
1275 } else {
1276 to_ticks = MSEC_TO_TICKS(net->RTO);
1278 tmr = &net->rxt_timer;
1279 break;
1280 case SCTP_TIMER_TYPE_HEARTBEAT:
1282 * the net is used here so that we can add in the RTO.
1283 * Even though we use a different timer. We also add the
1284 * HB timer PLUS a random jitter.
1286 if (stcb == NULL) {
1287 return (EFAULT);
1290 uint32_t rndval;
1291 uint8_t this_random;
1292 int cnt_of_unconf=0;
1293 struct sctp_nets *lnet;
1295 TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
1296 if (lnet->dest_state & SCTP_ADDR_UNCONFIRMED) {
1297 cnt_of_unconf++;
1300 #ifdef SCTP_DEBUG
1301 if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
1302 kprintf("HB timer to start unconfirmed:%d hb_delay:%d\n",
1303 cnt_of_unconf, stcb->asoc.heart_beat_delay);
1305 #endif
1306 if (stcb->asoc.hb_random_idx > 3) {
1307 rndval = sctp_select_initial_TSN(&inp->sctp_ep);
1308 memcpy(stcb->asoc.hb_random_values, &rndval,
1309 sizeof(stcb->asoc.hb_random_values));
1310 this_random = stcb->asoc.hb_random_values[0];
1311 stcb->asoc.hb_random_idx = 0;
1312 stcb->asoc.hb_ect_randombit = 0;
1313 } else {
1314 this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx];
1315 stcb->asoc.hb_random_idx++;
1316 stcb->asoc.hb_ect_randombit = 0;
1319 * this_random will be 0 - 256 ms
1320 * RTO is in ms.
1322 if ((stcb->asoc.heart_beat_delay == 0) &&
1323 (cnt_of_unconf == 0)) {
1324 /* no HB on this inp after confirmations */
1325 return (0);
1327 if (net) {
1328 struct sctp_nets *lnet;
1329 int delay;
1330 delay = stcb->asoc.heart_beat_delay;
1331 TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
1332 if ((lnet->dest_state & SCTP_ADDR_UNCONFIRMED) &&
1333 ((lnet->dest_state & SCTP_ADDR_OUT_OF_SCOPE) == 0) &&
1334 (lnet->dest_state & SCTP_ADDR_REACHABLE)) {
1335 delay = 0;
1338 if (net->RTO == 0) {
1339 /* Never been checked */
1340 to_ticks = this_random + stcb->asoc.initial_rto + delay;
1341 } else {
1342 /* set rto_val to the ms */
1343 to_ticks = delay + net->RTO + this_random;
1345 } else {
1346 if (cnt_of_unconf) {
1347 to_ticks = this_random + stcb->asoc.initial_rto;
1348 } else {
1349 to_ticks = stcb->asoc.heart_beat_delay + this_random + stcb->asoc.initial_rto;
1353 * Now we must convert the to_ticks that are now in
1354 * ms to ticks.
1356 to_ticks *= hz;
1357 to_ticks /= 1000;
1358 #ifdef SCTP_DEBUG
1359 if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
1360 kprintf("Timer to expire in %d ticks\n", to_ticks);
1362 #endif
1363 tmr = &stcb->asoc.hb_timer;
1365 break;
1366 case SCTP_TIMER_TYPE_COOKIE:
1368 * Here we can use the RTO timer from the network since
1369 * one RTT was compelete. If a retran happened then we will
1370 * be using the RTO initial value.
1372 if ((stcb == NULL) || (net == NULL)) {
1373 return (EFAULT);
1375 if (net->RTO == 0) {
1376 to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
1377 } else {
1378 to_ticks = MSEC_TO_TICKS(net->RTO);
1380 tmr = &net->rxt_timer;
1381 break;
1382 case SCTP_TIMER_TYPE_NEWCOOKIE:
1384 * nothing needed but the endpoint here
1385 * ususually about 60 minutes.
1387 tmr = &inp->sctp_ep.signature_change;
1388 to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_SIGNATURE];
1389 break;
1390 case SCTP_TIMER_TYPE_INPKILL:
1392 * The inp is setup to die. We re-use the
1393 * signature_chage timer since that has
1394 * stopped and we are in the GONE state.
1396 tmr = &inp->sctp_ep.signature_change;
1397 to_ticks = (SCTP_INP_KILL_TIMEOUT * hz) / 1000;
1398 break;
1399 case SCTP_TIMER_TYPE_PATHMTURAISE:
1401 * Here we use the value found in the EP for PMTU
1402 * ususually about 10 minutes.
1404 if (stcb == NULL) {
1405 return (EFAULT);
1407 if (net == NULL) {
1408 return (EFAULT);
1410 to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_PMTU];
1411 tmr = &net->pmtu_timer;
1412 break;
1413 case SCTP_TIMER_TYPE_SHUTDOWNACK:
1414 /* Here we use the RTO of the destination */
1415 if ((stcb == NULL) || (net == NULL)) {
1416 return (EFAULT);
1418 if (net->RTO == 0) {
1419 to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
1420 } else {
1421 to_ticks = MSEC_TO_TICKS(net->RTO);
1423 tmr = &net->rxt_timer;
1424 break;
1425 case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
1427 * Here we use the endpoints shutdown guard timer
1428 * usually about 3 minutes.
1430 if (stcb == NULL) {
1431 return (EFAULT);
1433 to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN];
1434 tmr = &stcb->asoc.shut_guard_timer;
1435 break;
1436 case SCTP_TIMER_TYPE_STRRESET:
1438 * Here the timer comes from the inp
1439 * but its value is from the RTO.
1441 if ((stcb == NULL) || (net == NULL)) {
1442 return (EFAULT);
1444 if (net->RTO == 0) {
1445 to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
1446 } else {
1447 to_ticks = MSEC_TO_TICKS(net->RTO);
1449 tmr = &stcb->asoc.strreset_timer;
1450 break;
1452 case SCTP_TIMER_TYPE_ASCONF:
1454 * Here the timer comes from the inp
1455 * but its value is from the RTO.
1457 if ((stcb == NULL) || (net == NULL)) {
1458 return (EFAULT);
1460 if (net->RTO == 0) {
1461 to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
1462 } else {
1463 to_ticks = MSEC_TO_TICKS(net->RTO);
1465 tmr = &stcb->asoc.asconf_timer;
1466 break;
1467 case SCTP_TIMER_TYPE_AUTOCLOSE:
1468 if (stcb == NULL) {
1469 return (EFAULT);
1471 if (stcb->asoc.sctp_autoclose_ticks == 0) {
1472 /* Really an error since stcb is NOT set to autoclose */
1473 return (0);
1475 to_ticks = stcb->asoc.sctp_autoclose_ticks;
1476 tmr = &stcb->asoc.autoclose_timer;
1477 break;
1478 default:
1479 #ifdef SCTP_DEBUG
1480 if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
1481 kprintf("sctp_timer_start:Unknown timer type %d\n",
1482 t_type);
1484 #endif /* SCTP_DEBUG */
1485 return (EFAULT);
1486 break;
1488 if ((to_ticks <= 0) || (tmr == NULL)) {
1489 #ifdef SCTP_DEBUG
1490 if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
1491 kprintf("sctp_timer_start:%d:software error to_ticks:%d tmr:%p not set ??\n",
1492 t_type, to_ticks, tmr);
1494 #endif /* SCTP_DEBUG */
1495 return (EFAULT);
1497 if (callout_pending(&tmr->timer)) {
1499 * we do NOT allow you to have it already running.
1500 * if it is we leave the current one up unchanged
1502 return (EALREADY);
1504 /* At this point we can proceed */
1505 if (t_type == SCTP_TIMER_TYPE_SEND) {
1506 stcb->asoc.num_send_timers_up++;
1508 tmr->type = t_type;
1509 tmr->ep = (void *)inp;
1510 tmr->tcb = (void *)stcb;
1511 tmr->net = (void *)net;
1512 callout_reset(&tmr->timer, to_ticks, sctp_timeout_handler, tmr);
1513 return (0);
1517 sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1518 struct sctp_nets *net)
1520 struct sctp_timer *tmr;
1522 if (inp == NULL)
1523 return (EFAULT);
1525 tmr = NULL;
1526 switch (t_type) {
1527 case SCTP_TIMER_TYPE_ITERATOR:
1529 struct sctp_iterator *it;
1530 it = (struct sctp_iterator *)inp;
1531 tmr = &it->tmr;
1533 break;
1534 case SCTP_TIMER_TYPE_SEND:
1535 if ((stcb == NULL) || (net == NULL)) {
1536 return (EFAULT);
1538 tmr = &net->rxt_timer;
1539 break;
1540 case SCTP_TIMER_TYPE_INIT:
1541 if ((stcb == NULL) || (net == NULL)) {
1542 return (EFAULT);
1544 tmr = &net->rxt_timer;
1545 break;
1546 case SCTP_TIMER_TYPE_RECV:
1547 if (stcb == NULL) {
1548 return (EFAULT);
1550 tmr = &stcb->asoc.dack_timer;
1551 break;
1552 case SCTP_TIMER_TYPE_SHUTDOWN:
1553 if ((stcb == NULL) || (net == NULL)) {
1554 return (EFAULT);
1556 tmr = &net->rxt_timer;
1557 break;
1558 case SCTP_TIMER_TYPE_HEARTBEAT:
1559 if (stcb == NULL) {
1560 return (EFAULT);
1562 tmr = &stcb->asoc.hb_timer;
1563 break;
1564 case SCTP_TIMER_TYPE_COOKIE:
1565 if ((stcb == NULL) || (net == NULL)) {
1566 return (EFAULT);
1568 tmr = &net->rxt_timer;
1569 break;
1570 case SCTP_TIMER_TYPE_NEWCOOKIE:
1571 /* nothing needed but the endpoint here */
1572 tmr = &inp->sctp_ep.signature_change;
1573 /* We re-use the newcookie timer for
1574 * the INP kill timer. We must assure
1575 * that we do not kill it by accident.
1577 break;
1578 case SCTP_TIMER_TYPE_INPKILL:
1580 * The inp is setup to die. We re-use the
1581 * signature_chage timer since that has
1582 * stopped and we are in the GONE state.
1584 tmr = &inp->sctp_ep.signature_change;
1585 break;
1586 case SCTP_TIMER_TYPE_PATHMTURAISE:
1587 if (stcb == NULL) {
1588 return (EFAULT);
1590 if (net == NULL) {
1591 return (EFAULT);
1593 tmr = &net->pmtu_timer;
1594 break;
1595 case SCTP_TIMER_TYPE_SHUTDOWNACK:
1596 if ((stcb == NULL) || (net == NULL)) {
1597 return (EFAULT);
1599 tmr = &net->rxt_timer;
1600 break;
1601 case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
1602 if (stcb == NULL) {
1603 return (EFAULT);
1605 tmr = &stcb->asoc.shut_guard_timer;
1606 break;
1607 case SCTP_TIMER_TYPE_STRRESET:
1608 if (stcb == NULL) {
1609 return (EFAULT);
1611 tmr = &stcb->asoc.strreset_timer;
1612 break;
1613 case SCTP_TIMER_TYPE_ASCONF:
1614 if (stcb == NULL) {
1615 return (EFAULT);
1617 tmr = &stcb->asoc.asconf_timer;
1618 break;
1619 case SCTP_TIMER_TYPE_AUTOCLOSE:
1620 if (stcb == NULL) {
1621 return (EFAULT);
1623 tmr = &stcb->asoc.autoclose_timer;
1624 break;
1625 default:
1626 #ifdef SCTP_DEBUG
1627 if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
1628 kprintf("sctp_timer_stop:Unknown timer type %d\n",
1629 t_type);
1631 #endif /* SCTP_DEBUG */
1632 break;
1634 if (tmr == NULL)
1635 return (EFAULT);
1637 if ((tmr->type != t_type) && tmr->type) {
1639 * Ok we have a timer that is under joint use. Cookie timer
1640 * per chance with the SEND timer. We therefore are NOT
1641 * running the timer that the caller wants stopped. So just
1642 * return.
1644 return (0);
1646 if (t_type == SCTP_TIMER_TYPE_SEND) {
1647 stcb->asoc.num_send_timers_up--;
1648 if (stcb->asoc.num_send_timers_up < 0) {
1649 stcb->asoc.num_send_timers_up = 0;
1652 callout_stop(&tmr->timer);
1653 return (0);
1656 #ifdef SCTP_USE_ADLER32
1657 static uint32_t
1658 update_adler32(uint32_t adler, uint8_t *buf, int32_t len)
1660 u_int32_t s1 = adler & 0xffff;
1661 u_int32_t s2 = (adler >> 16) & 0xffff;
1662 int n;
1664 for (n = 0; n < len; n++, buf++) {
1665 /* s1 = (s1 + buf[n]) % BASE */
1666 /* first we add */
1667 s1 = (s1 + *buf);
1669 * now if we need to, we do a mod by subtracting. It seems
1670 * a bit faster since I really will only ever do one subtract
1671 * at the MOST, since buf[n] is a max of 255.
1673 if (s1 >= SCTP_ADLER32_BASE) {
1674 s1 -= SCTP_ADLER32_BASE;
1676 /* s2 = (s2 + s1) % BASE */
1677 /* first we add */
1678 s2 = (s2 + s1);
1680 * again, it is more efficent (it seems) to subtract since
1681 * the most s2 will ever be is (BASE-1 + BASE-1) in the worse
1682 * case. This would then be (2 * BASE) - 2, which will still
1683 * only do one subtract. On Intel this is much better to do
1684 * this way and avoid the divide. Have not -pg'd on sparc.
1686 if (s2 >= SCTP_ADLER32_BASE) {
1687 s2 -= SCTP_ADLER32_BASE;
1690 /* Return the adler32 of the bytes buf[0..len-1] */
1691 return ((s2 << 16) + s1);
1694 #endif
1697 u_int32_t
1698 sctp_calculate_len(struct mbuf *m)
1700 u_int32_t tlen=0;
1701 struct mbuf *at;
1702 at = m;
1703 while (at) {
1704 tlen += at->m_len;
1705 at = at->m_next;
1707 return (tlen);
1710 #if defined(SCTP_WITH_NO_CSUM)
1712 uint32_t
1713 sctp_calculate_sum(struct mbuf *m, int32_t *pktlen, uint32_t offset)
1716 * given a mbuf chain with a packetheader offset by 'offset'
1717 * pointing at a sctphdr (with csum set to 0) go through
1718 * the chain of m_next's and calculate the SCTP checksum.
1719 * This is currently Adler32 but will change to CRC32x
1720 * soon. Also has a side bonus calculate the total length
1721 * of the mbuf chain.
1722 * Note: if offset is greater than the total mbuf length,
1723 * checksum=1, pktlen=0 is returned (ie. no real error code)
1725 if (pktlen == NULL)
1726 return (0);
1727 *pktlen = sctp_calculate_len(m);
1728 return (0);
1731 #elif defined(SCTP_USE_INCHKSUM)
1733 #include <machine/in_cksum.h>
1735 uint32_t
1736 sctp_calculate_sum(struct mbuf *m, int32_t *pktlen, uint32_t offset)
1739 * given a mbuf chain with a packetheader offset by 'offset'
1740 * pointing at a sctphdr (with csum set to 0) go through
1741 * the chain of m_next's and calculate the SCTP checksum.
1742 * This is currently Adler32 but will change to CRC32x
1743 * soon. Also has a side bonus calculate the total length
1744 * of the mbuf chain.
1745 * Note: if offset is greater than the total mbuf length,
1746 * checksum=1, pktlen=0 is returned (ie. no real error code)
1748 int32_t tlen=0;
1749 struct mbuf *at;
1750 uint32_t the_sum, retsum;
1752 at = m;
1753 while (at) {
1754 tlen += at->m_len;
1755 at = at->m_next;
1757 the_sum = (uint32_t)(in_cksum_skip(m, tlen, offset));
1758 if (pktlen != NULL)
1759 *pktlen = (tlen-offset);
1760 retsum = htons(the_sum);
1761 return (the_sum);
1764 #else
1766 uint32_t
1767 sctp_calculate_sum(struct mbuf *m, int32_t *pktlen, uint32_t offset)
1770 * given a mbuf chain with a packetheader offset by 'offset'
1771 * pointing at a sctphdr (with csum set to 0) go through
1772 * the chain of m_next's and calculate the SCTP checksum.
1773 * This is currently Adler32 but will change to CRC32x
1774 * soon. Also has a side bonus calculate the total length
1775 * of the mbuf chain.
1776 * Note: if offset is greater than the total mbuf length,
1777 * checksum=1, pktlen=0 is returned (ie. no real error code)
1779 int32_t tlen=0;
1780 #ifdef SCTP_USE_ADLER32
1781 uint32_t base = 1L;
1782 #else
1783 uint32_t base = 0xffffffff;
1784 #endif /* SCTP_USE_ADLER32 */
1785 struct mbuf *at;
1786 at = m;
1787 /* find the correct mbuf and offset into mbuf */
1788 while ((at != NULL) && (offset > (uint32_t)at->m_len)) {
1789 offset -= at->m_len; /* update remaining offset left */
1790 at = at->m_next;
1793 while (at != NULL) {
1794 #ifdef SCTP_USE_ADLER32
1795 base = update_adler32(base, at->m_data + offset,
1796 at->m_len - offset);
1797 #else
1798 base = update_crc32(base, at->m_data + offset,
1799 at->m_len - offset);
1800 #endif /* SCTP_USE_ADLER32 */
1801 tlen += at->m_len - offset;
1802 /* we only offset once into the first mbuf */
1803 if (offset) {
1804 offset = 0;
1806 at = at->m_next;
1808 if (pktlen != NULL) {
1809 *pktlen = tlen;
1811 #ifdef SCTP_USE_ADLER32
1812 /* Adler32 */
1813 base = htonl(base);
1814 #else
1815 /* CRC-32c */
1816 base = sctp_csum_finalize(base);
1817 #endif
1818 return (base);
1822 #endif
1824 void
1825 sctp_mtu_size_reset(struct sctp_inpcb *inp,
1826 struct sctp_association *asoc, u_long mtu)
1829 * Reset the P-MTU size on this association, this involves changing
1830 * the asoc MTU, going through ANY chunk+overhead larger than mtu
1831 * to allow the DF flag to be cleared.
1833 struct sctp_tmit_chunk *chk;
1834 struct sctp_stream_out *strm;
1835 unsigned int eff_mtu, ovh;
1836 asoc->smallest_mtu = mtu;
1837 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
1838 ovh = SCTP_MIN_OVERHEAD;
1839 } else {
1840 ovh = SCTP_MIN_V4_OVERHEAD;
1842 eff_mtu = mtu - ovh;
1843 /* Now mark any chunks that need to let IP fragment */
1844 TAILQ_FOREACH(strm, &asoc->out_wheel, next_spoke) {
1845 TAILQ_FOREACH(chk, &strm->outqueue, sctp_next) {
1846 if (chk->send_size > eff_mtu) {
1847 chk->flags &= SCTP_DONT_FRAGMENT;
1848 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
1852 TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) {
1853 if (chk->send_size > eff_mtu) {
1854 chk->flags &= SCTP_DONT_FRAGMENT;
1855 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
1858 TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
1859 if (chk->send_size > eff_mtu) {
1860 chk->flags &= SCTP_DONT_FRAGMENT;
1861 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
1868 * given an association and starting time of the current RTT period
1869 * return RTO in number of usecs
1870 * net should point to the current network
1872 u_int32_t
1873 sctp_calculate_rto(struct sctp_tcb *stcb,
1874 struct sctp_association *asoc,
1875 struct sctp_nets *net,
1876 struct timeval *old)
1879 * given an association and the starting time of the current RTT
1880 * period (in value1/value2) return RTO in number of usecs.
1882 int calc_time = 0;
1883 int o_calctime;
1884 unsigned int new_rto = 0;
1885 int first_measure = 0;
1886 struct timeval now;
1888 /************************/
1889 /* 1. calculate new RTT */
1890 /************************/
1891 /* get the current time */
1892 SCTP_GETTIME_TIMEVAL(&now);
1893 /* compute the RTT value */
1894 if ((u_long)now.tv_sec > (u_long)old->tv_sec) {
1895 calc_time = ((u_long)now.tv_sec - (u_long)old->tv_sec) * 1000;
1896 if ((u_long)now.tv_usec > (u_long)old->tv_usec) {
1897 calc_time += (((u_long)now.tv_usec -
1898 (u_long)old->tv_usec)/1000);
1899 } else if ((u_long)now.tv_usec < (u_long)old->tv_usec) {
1900 /* Borrow 1,000ms from current calculation */
1901 calc_time -= 1000;
1902 /* Add in the slop over */
1903 calc_time += ((int)now.tv_usec/1000);
1904 /* Add in the pre-second ms's */
1905 calc_time += (((int)1000000 - (int)old->tv_usec)/1000);
1907 } else if ((u_long)now.tv_sec == (u_long)old->tv_sec) {
1908 if ((u_long)now.tv_usec > (u_long)old->tv_usec) {
1909 calc_time = ((u_long)now.tv_usec -
1910 (u_long)old->tv_usec)/1000;
1911 } else if ((u_long)now.tv_usec < (u_long)old->tv_usec) {
1912 /* impossible .. garbage in nothing out */
1913 return (((net->lastsa >> 2) + net->lastsv) >> 1);
1914 } else {
1915 /* impossible .. garbage in nothing out */
1916 return (((net->lastsa >> 2) + net->lastsv) >> 1);
1918 } else {
1919 /* Clock wrapped? */
1920 return (((net->lastsa >> 2) + net->lastsv) >> 1);
1922 /***************************/
1923 /* 2. update RTTVAR & SRTT */
1924 /***************************/
1925 #if 0
1926 /* if (net->lastsv || net->lastsa) {*/
1927 /* per Section 5.3.1 C3 in SCTP */
1928 /* net->lastsv = (int) *//* RTTVAR */
1929 /* (((double)(1.0 - 0.25) * (double)net->lastsv) +
1930 (double)(0.25 * (double)abs(net->lastsa - calc_time)));
1931 net->lastsa = (int) */ /* SRTT */
1932 /*(((double)(1.0 - 0.125) * (double)net->lastsa) +
1933 (double)(0.125 * (double)calc_time));
1934 } else {
1935 *//* the first RTT calculation, per C2 Section 5.3.1 */
1936 /* net->lastsa = calc_time; *//* SRTT */
1937 /* net->lastsv = calc_time / 2; *//* RTTVAR */
1938 /* }*/
1939 /* if RTTVAR goes to 0 you set to clock grainularity */
1940 /* if (net->lastsv == 0) {
1941 net->lastsv = SCTP_CLOCK_GRANULARITY;
1943 new_rto = net->lastsa + 4 * net->lastsv;
1945 #endif
1946 o_calctime = calc_time;
1947 /* this is Van Jacobson's integer version */
1948 if (net->RTO) {
1949 calc_time -= (net->lastsa >> 3);
1950 net->lastsa += calc_time;
1951 if (calc_time < 0) {
1952 calc_time = -calc_time;
1954 calc_time -= (net->lastsv >> 2);
1955 net->lastsv += calc_time;
1956 if (net->lastsv == 0) {
1957 net->lastsv = SCTP_CLOCK_GRANULARITY;
1959 } else {
1960 /* First RTO measurment */
1961 net->lastsa = calc_time;
1962 net->lastsv = calc_time >> 1;
1963 first_measure = 1;
1965 new_rto = ((net->lastsa >> 2) + net->lastsv) >> 1;
1966 if ((new_rto > SCTP_SAT_NETWORK_MIN) &&
1967 (stcb->asoc.sat_network_lockout == 0)) {
1968 stcb->asoc.sat_network = 1;
1969 } else if ((!first_measure) && stcb->asoc.sat_network) {
1970 stcb->asoc.sat_network = 0;
1971 stcb->asoc.sat_network_lockout = 1;
1973 /* bound it, per C6/C7 in Section 5.3.1 */
1974 if (new_rto < stcb->asoc.minrto) {
1975 new_rto = stcb->asoc.minrto;
1977 if (new_rto > stcb->asoc.maxrto) {
1978 new_rto = stcb->asoc.maxrto;
1980 /* we are now returning the RTT Smoothed */
1981 return ((u_int32_t)new_rto);
1986 * return a pointer to a contiguous piece of data from the given
1987 * mbuf chain starting at 'off' for 'len' bytes. If the desired
1988 * piece spans more than one mbuf, a copy is made at 'ptr'.
1989 * caller must ensure that the buffer size is >= 'len'
1990 * returns NULL if there there isn't 'len' bytes in the chain.
1992 caddr_t
1993 sctp_m_getptr(struct mbuf *m, int off, int len, u_int8_t *in_ptr)
1995 uint32_t count;
1996 uint8_t *ptr;
1997 ptr = in_ptr;
1998 if ((off < 0) || (len <= 0))
1999 return (NULL);
2001 /* find the desired start location */
2002 while ((m != NULL) && (off > 0)) {
2003 if (off < m->m_len)
2004 break;
2005 off -= m->m_len;
2006 m = m->m_next;
2008 if (m == NULL)
2009 return (NULL);
2011 /* is the current mbuf large enough (eg. contiguous)? */
2012 if ((m->m_len - off) >= len) {
2013 return (mtod(m, caddr_t) + off);
2014 } else {
2015 /* else, it spans more than one mbuf, so save a temp copy... */
2016 while ((m != NULL) && (len > 0)) {
2017 count = min(m->m_len - off, len);
2018 bcopy(mtod(m, caddr_t) + off, ptr, count);
2019 len -= count;
2020 ptr += count;
2021 off = 0;
2022 m = m->m_next;
2024 if ((m == NULL) && (len > 0))
2025 return (NULL);
2026 else
2027 return ((caddr_t)in_ptr);
2032 struct sctp_paramhdr *
2033 sctp_get_next_param(struct mbuf *m,
2034 int offset,
2035 struct sctp_paramhdr *pull,
2036 int pull_limit)
2038 /* This just provides a typed signature to Peter's Pull routine */
2039 return ((struct sctp_paramhdr *)sctp_m_getptr(m, offset, pull_limit,
2040 (u_int8_t *)pull));
2045 sctp_add_pad_tombuf(struct mbuf *m, int padlen)
2048 * add padlen bytes of 0 filled padding to the end of the mbuf.
2049 * If padlen is > 3 this routine will fail.
2051 u_int8_t *dp;
2052 int i;
2053 if (padlen > 3) {
2054 return (ENOBUFS);
2056 if (M_TRAILINGSPACE(m)) {
2058 * The easy way.
2059 * We hope the majority of the time we hit here :)
2061 dp = (u_int8_t *)(mtod(m, caddr_t) + m->m_len);
2062 m->m_len += padlen;
2063 } else {
2064 /* Hard way we must grow the mbuf */
2065 struct mbuf *tmp;
2066 MGET(tmp, MB_DONTWAIT, MT_DATA);
2067 if (tmp == NULL) {
2068 /* Out of space GAK! we are in big trouble. */
2069 return (ENOSPC);
2071 /* setup and insert in middle */
2072 tmp->m_next = m->m_next;
2073 tmp->m_len = padlen;
2074 m->m_next = tmp;
2075 dp = mtod(tmp, u_int8_t *);
2077 /* zero out the pad */
2078 for (i= 0; i < padlen; i++) {
2079 *dp = 0;
2080 dp++;
2082 return (0);
2086 sctp_pad_lastmbuf(struct mbuf *m, int padval)
2088 /* find the last mbuf in chain and pad it */
2089 struct mbuf *m_at;
2090 m_at = m;
2091 while (m_at) {
2092 if (m_at->m_next == NULL) {
2093 return (sctp_add_pad_tombuf(m_at, padval));
2095 m_at = m_at->m_next;
2097 return (EFAULT);
2100 static void
2101 sctp_notify_assoc_change(u_int32_t event, struct sctp_tcb *stcb,
2102 u_int32_t error)
2104 struct mbuf *m_notify;
2105 struct sctp_assoc_change *sac;
2106 struct sockaddr *to;
2107 struct sockaddr_in6 sin6, lsa6;
2110 * First if we are are going down dump everything we
2111 * can to the socket rcv queue.
2113 if ((event == SCTP_SHUTDOWN_COMP) || (event == SCTP_COMM_LOST)) {
2114 sctp_deliver_data(stcb, &stcb->asoc, NULL, 0);
2118 * For TCP model AND UDP connected sockets we will send
2119 * an error up when an ABORT comes in.
2121 if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2122 (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
2123 (event == SCTP_COMM_LOST)) {
2124 stcb->sctp_socket->so_error = ECONNRESET;
2125 /* Wake ANY sleepers */
2126 sowwakeup(stcb->sctp_socket);
2127 sorwakeup(stcb->sctp_socket);
2129 #if 0
2130 if ((event == SCTP_COMM_UP) &&
2131 (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
2132 (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
2133 soisconnected(stcb->sctp_socket);
2135 #endif
2136 if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_RECVASSOCEVNT)) {
2137 /* event not enabled */
2138 return;
2140 MGETHDR(m_notify, MB_DONTWAIT, MT_DATA);
2141 if (m_notify == NULL)
2142 /* no space left */
2143 return;
2144 m_notify->m_len = 0;
2146 sac = mtod(m_notify, struct sctp_assoc_change *);
2147 sac->sac_type = SCTP_ASSOC_CHANGE;
2148 sac->sac_flags = 0;
2149 sac->sac_length = sizeof(struct sctp_assoc_change);
2150 sac->sac_state = event;
2151 sac->sac_error = error;
2152 /* XXX verify these stream counts */
2153 sac->sac_outbound_streams = stcb->asoc.streamoutcnt;
2154 sac->sac_inbound_streams = stcb->asoc.streamincnt;
2155 sac->sac_assoc_id = sctp_get_associd(stcb);
2157 m_notify->m_flags |= M_EOR | M_NOTIFICATION;
2158 m_notify->m_pkthdr.len = sizeof(struct sctp_assoc_change);
2159 m_notify->m_pkthdr.rcvif = 0;
2160 m_notify->m_len = sizeof(struct sctp_assoc_change);
2161 m_notify->m_next = NULL;
2163 /* append to socket */
2164 to = (struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr;
2165 if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
2166 to->sa_family == AF_INET) {
2167 struct sockaddr_in *sin;
2169 sin = (struct sockaddr_in *)to;
2170 bzero(&sin6, sizeof(sin6));
2171 sin6.sin6_family = AF_INET6;
2172 sin6.sin6_len = sizeof(struct sockaddr_in6);
2173 sin6.sin6_addr.s6_addr16[2] = 0xffff;
2174 bcopy(&sin->sin_addr, &sin6.sin6_addr.s6_addr16[3],
2175 sizeof(sin6.sin6_addr.s6_addr16[3]));
2176 sin6.sin6_port = sin->sin_port;
2177 to = (struct sockaddr *)&sin6;
2179 /* check and strip embedded scope junk */
2180 to = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)to,
2181 &lsa6);
2183 * We need to always notify comm changes.
2184 * if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
2185 * sctp_m_freem(m_notify);
2186 * return;
2189 SCTP_TCB_UNLOCK(stcb);
2190 SCTP_INP_WLOCK(stcb->sctp_ep);
2191 SCTP_TCB_LOCK(stcb);
2192 if (!sctp_sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv,
2193 to, m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
2194 /* not enough room */
2195 sctp_m_freem(m_notify);
2196 SCTP_INP_WUNLOCK(stcb->sctp_ep);
2197 return;
2199 if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
2200 ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
2201 if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
2202 stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
2204 } else {
2205 stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
2207 SCTP_INP_WUNLOCK(stcb->sctp_ep);
2208 /* Wake up any sleeper */
2209 sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
2210 sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
2213 static void
2214 sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
2215 struct sockaddr *sa, uint32_t error)
2217 struct mbuf *m_notify;
2218 struct sctp_paddr_change *spc;
2219 struct sockaddr *to;
2220 struct sockaddr_in6 sin6, lsa6;
2222 if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_RECVPADDREVNT))
2223 /* event not enabled */
2224 return;
2226 MGETHDR(m_notify, MB_DONTWAIT, MT_DATA);
2227 if (m_notify == NULL)
2228 return;
2229 m_notify->m_len = 0;
2231 MCLGET(m_notify, MB_DONTWAIT);
2232 if ((m_notify->m_flags & M_EXT) != M_EXT) {
2233 sctp_m_freem(m_notify);
2234 return;
2237 spc = mtod(m_notify, struct sctp_paddr_change *);
2238 spc->spc_type = SCTP_PEER_ADDR_CHANGE;
2239 spc->spc_flags = 0;
2240 spc->spc_length = sizeof(struct sctp_paddr_change);
2241 if (sa->sa_family == AF_INET) {
2242 memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in));
2243 } else {
2244 memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in6));
2246 spc->spc_state = state;
2247 spc->spc_error = error;
2248 spc->spc_assoc_id = sctp_get_associd(stcb);
2250 m_notify->m_flags |= M_EOR | M_NOTIFICATION;
2251 m_notify->m_pkthdr.len = sizeof(struct sctp_paddr_change);
2252 m_notify->m_pkthdr.rcvif = 0;
2253 m_notify->m_len = sizeof(struct sctp_paddr_change);
2254 m_notify->m_next = NULL;
2256 to = (struct sockaddr *)(struct sockaddr *)
2257 &stcb->asoc.primary_destination->ro._l_addr;
2258 if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
2259 to->sa_family == AF_INET) {
2260 struct sockaddr_in *sin;
2262 sin = (struct sockaddr_in *)to;
2263 bzero(&sin6, sizeof(sin6));
2264 sin6.sin6_family = AF_INET6;
2265 sin6.sin6_len = sizeof(struct sockaddr_in6);
2266 sin6.sin6_addr.s6_addr16[2] = 0xffff;
2267 bcopy(&sin->sin_addr, &sin6.sin6_addr.s6_addr16[3],
2268 sizeof(sin6.sin6_addr.s6_addr16[3]));
2269 sin6.sin6_port = sin->sin_port;
2270 to = (struct sockaddr *)&sin6;
2272 /* check and strip embedded scope junk */
2273 to = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)to,
2274 &lsa6);
2276 if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
2277 sctp_m_freem(m_notify);
2278 return;
2280 /* append to socket */
2281 SCTP_TCB_UNLOCK(stcb);
2282 SCTP_INP_WLOCK(stcb->sctp_ep);
2283 SCTP_TCB_LOCK(stcb);
2284 if (!sctp_sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to,
2285 m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
2286 /* not enough room */
2287 sctp_m_freem(m_notify);
2288 SCTP_INP_WUNLOCK(stcb->sctp_ep);
2289 return;
2291 if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
2292 ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
2293 if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
2294 stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
2296 } else {
2297 stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
2299 SCTP_INP_WUNLOCK(stcb->sctp_ep);
2300 sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
2304 static void
2305 sctp_notify_send_failed(struct sctp_tcb *stcb, u_int32_t error,
2306 struct sctp_tmit_chunk *chk)
2308 struct mbuf *m_notify;
2309 struct sctp_send_failed *ssf;
2310 struct sockaddr_in6 sin6, lsa6;
2311 struct sockaddr *to;
2312 int length;
2314 if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_RECVSENDFAILEVNT))
2315 /* event not enabled */
2316 return;
2318 length = sizeof(struct sctp_send_failed) + chk->send_size;
2319 MGETHDR(m_notify, MB_DONTWAIT, MT_DATA);
2320 if (m_notify == NULL)
2321 /* no space left */
2322 return;
2323 m_notify->m_len = 0;
2324 ssf = mtod(m_notify, struct sctp_send_failed *);
2325 ssf->ssf_type = SCTP_SEND_FAILED;
2326 if (error == SCTP_NOTIFY_DATAGRAM_UNSENT)
2327 ssf->ssf_flags = SCTP_DATA_UNSENT;
2328 else
2329 ssf->ssf_flags = SCTP_DATA_SENT;
2330 ssf->ssf_length = length;
2331 ssf->ssf_error = error;
2332 /* not exactly what the user sent in, but should be close :) */
2333 ssf->ssf_info.sinfo_stream = chk->rec.data.stream_number;
2334 ssf->ssf_info.sinfo_ssn = chk->rec.data.stream_seq;
2335 ssf->ssf_info.sinfo_flags = chk->rec.data.rcv_flags;
2336 ssf->ssf_info.sinfo_ppid = chk->rec.data.payloadtype;
2337 ssf->ssf_info.sinfo_context = chk->rec.data.context;
2338 ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb);
2339 ssf->ssf_assoc_id = sctp_get_associd(stcb);
2340 m_notify->m_next = chk->data;
2341 if (m_notify->m_next == NULL)
2342 m_notify->m_flags |= M_EOR | M_NOTIFICATION;
2343 else {
2344 struct mbuf *m;
2345 m_notify->m_flags |= M_NOTIFICATION;
2346 m = m_notify;
2347 while (m->m_next != NULL)
2348 m = m->m_next;
2349 m->m_flags |= M_EOR;
2351 m_notify->m_pkthdr.len = length;
2352 m_notify->m_pkthdr.rcvif = 0;
2353 m_notify->m_len = sizeof(struct sctp_send_failed);
2355 /* Steal off the mbuf */
2356 chk->data = NULL;
2357 to = (struct sockaddr *)(struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr;
2358 if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
2359 to->sa_family == AF_INET) {
2360 struct sockaddr_in *sin;
2362 sin = (struct sockaddr_in *)to;
2363 bzero(&sin6, sizeof(sin6));
2364 sin6.sin6_family = AF_INET6;
2365 sin6.sin6_len = sizeof(struct sockaddr_in6);
2366 sin6.sin6_addr.s6_addr16[2] = 0xffff;
2367 bcopy(&sin->sin_addr, &sin6.sin6_addr.s6_addr16[3],
2368 sizeof(sin6.sin6_addr.s6_addr16[3]));
2369 sin6.sin6_port = sin->sin_port;
2370 to = (struct sockaddr *)&sin6;
2372 /* check and strip embedded scope junk */
2373 to = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)to,
2374 &lsa6);
2376 if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
2377 sctp_m_freem(m_notify);
2378 return;
2381 /* append to socket */
2382 SCTP_TCB_UNLOCK(stcb);
2383 SCTP_INP_WLOCK(stcb->sctp_ep);
2384 SCTP_TCB_LOCK(stcb);
2385 if (!sctp_sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to,
2386 m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
2387 /* not enough room */
2388 sctp_m_freem(m_notify);
2389 SCTP_INP_WUNLOCK(stcb->sctp_ep);
2390 return;
2392 if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
2393 ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
2394 if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
2395 stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
2397 } else {
2398 stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
2400 SCTP_INP_WUNLOCK(stcb->sctp_ep);
2401 sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
2404 static void
2405 sctp_notify_adaption_layer(struct sctp_tcb *stcb,
2406 u_int32_t error)
2408 struct mbuf *m_notify;
2409 struct sctp_adaption_event *sai;
2410 struct sockaddr_in6 sin6, lsa6;
2411 struct sockaddr *to;
2413 if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_ADAPTIONEVNT))
2414 /* event not enabled */
2415 return;
2417 MGETHDR(m_notify, MB_DONTWAIT, MT_DATA);
2418 if (m_notify == NULL)
2419 /* no space left */
2420 return;
2421 m_notify->m_len = 0;
2422 sai = mtod(m_notify, struct sctp_adaption_event *);
2423 sai->sai_type = SCTP_ADAPTION_INDICATION;
2424 sai->sai_flags = 0;
2425 sai->sai_length = sizeof(struct sctp_adaption_event);
2426 sai->sai_adaption_ind = error;
2427 sai->sai_assoc_id = sctp_get_associd(stcb);
2429 m_notify->m_flags |= M_EOR | M_NOTIFICATION;
2430 m_notify->m_pkthdr.len = sizeof(struct sctp_adaption_event);
2431 m_notify->m_pkthdr.rcvif = 0;
2432 m_notify->m_len = sizeof(struct sctp_adaption_event);
2433 m_notify->m_next = NULL;
2435 to = (struct sockaddr *)(struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr;
2436 if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
2437 (to->sa_family == AF_INET)) {
2438 struct sockaddr_in *sin;
2440 sin = (struct sockaddr_in *)to;
2441 bzero(&sin6, sizeof(sin6));
2442 sin6.sin6_family = AF_INET6;
2443 sin6.sin6_len = sizeof(struct sockaddr_in6);
2444 sin6.sin6_addr.s6_addr16[2] = 0xffff;
2445 bcopy(&sin->sin_addr, &sin6.sin6_addr.s6_addr16[3],
2446 sizeof(sin6.sin6_addr.s6_addr16[3]));
2447 sin6.sin6_port = sin->sin_port;
2448 to = (struct sockaddr *)&sin6;
2450 /* check and strip embedded scope junk */
2451 to = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)to,
2452 &lsa6);
2453 if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
2454 sctp_m_freem(m_notify);
2455 return;
2457 /* append to socket */
2458 SCTP_TCB_UNLOCK(stcb);
2459 SCTP_INP_WLOCK(stcb->sctp_ep);
2460 SCTP_TCB_LOCK(stcb);
2461 if (!sctp_sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to,
2462 m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
2463 /* not enough room */
2464 sctp_m_freem(m_notify);
2465 SCTP_INP_WUNLOCK(stcb->sctp_ep);
2466 return;
2468 if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
2469 ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
2470 if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
2471 stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
2473 } else {
2474 stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
2476 SCTP_INP_WUNLOCK(stcb->sctp_ep);
2477 sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
2480 static void
2481 sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb,
2482 u_int32_t error)
2484 struct mbuf *m_notify;
2485 struct sctp_pdapi_event *pdapi;
2486 struct sockaddr_in6 sin6, lsa6;
2487 struct sockaddr *to;
2489 if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_PDAPIEVNT))
2490 /* event not enabled */
2491 return;
2493 MGETHDR(m_notify, MB_DONTWAIT, MT_DATA);
2494 if (m_notify == NULL)
2495 /* no space left */
2496 return;
2497 m_notify->m_len = 0;
2498 pdapi = mtod(m_notify, struct sctp_pdapi_event *);
2499 pdapi->pdapi_type = SCTP_PARTIAL_DELIVERY_EVENT;
2500 pdapi->pdapi_flags = 0;
2501 pdapi->pdapi_length = sizeof(struct sctp_pdapi_event);
2502 pdapi->pdapi_indication = error;
2503 pdapi->pdapi_assoc_id = sctp_get_associd(stcb);
2505 m_notify->m_flags |= M_EOR | M_NOTIFICATION;
2506 m_notify->m_pkthdr.len = sizeof(struct sctp_pdapi_event);
2507 m_notify->m_pkthdr.rcvif = 0;
2508 m_notify->m_len = sizeof(struct sctp_pdapi_event);
2509 m_notify->m_next = NULL;
2511 to = (struct sockaddr *)(struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr;
2512 if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
2513 (to->sa_family == AF_INET)) {
2514 struct sockaddr_in *sin;
2516 sin = (struct sockaddr_in *)to;
2517 bzero(&sin6, sizeof(sin6));
2518 sin6.sin6_family = AF_INET6;
2519 sin6.sin6_len = sizeof(struct sockaddr_in6);
2520 sin6.sin6_addr.s6_addr16[2] = 0xffff;
2521 bcopy(&sin->sin_addr, &sin6.sin6_addr.s6_addr16[3],
2522 sizeof(sin6.sin6_addr.s6_addr16[3]));
2523 sin6.sin6_port = sin->sin_port;
2524 to = (struct sockaddr *)&sin6;
2526 /* check and strip embedded scope junk */
2527 to = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)to,
2528 &lsa6);
2529 if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
2530 sctp_m_freem(m_notify);
2531 return;
2533 /* append to socket */
2534 SCTP_TCB_UNLOCK(stcb);
2535 SCTP_INP_WLOCK(stcb->sctp_ep);
2536 SCTP_TCB_LOCK(stcb);
2537 if (!sctp_sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to,
2538 m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
2539 /* not enough room */
2540 sctp_m_freem(m_notify);
2541 SCTP_INP_WUNLOCK(stcb->sctp_ep);
2542 return;
2544 if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
2545 ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
2546 if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
2547 stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
2549 } else {
2550 stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
2552 SCTP_INP_WUNLOCK(stcb->sctp_ep);
2553 sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
2556 static void
2557 sctp_notify_shutdown_event(struct sctp_tcb *stcb)
2559 struct mbuf *m_notify;
2560 struct sctp_shutdown_event *sse;
2561 struct sockaddr_in6 sin6, lsa6;
2562 struct sockaddr *to;
2565 * For TCP model AND UDP connected sockets we will send
2566 * an error up when an SHUTDOWN completes
2568 if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2569 (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
2570 /* mark socket closed for read/write and wakeup! */
2571 socantrcvmore(stcb->sctp_socket);
2572 socantsendmore(stcb->sctp_socket);
2575 if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT))
2576 /* event not enabled */
2577 return;
2579 MGETHDR(m_notify, MB_DONTWAIT, MT_DATA);
2580 if (m_notify == NULL)
2581 /* no space left */
2582 return;
2583 m_notify->m_len = 0;
2584 sse = mtod(m_notify, struct sctp_shutdown_event *);
2585 sse->sse_type = SCTP_SHUTDOWN_EVENT;
2586 sse->sse_flags = 0;
2587 sse->sse_length = sizeof(struct sctp_shutdown_event);
2588 sse->sse_assoc_id = sctp_get_associd(stcb);
2590 m_notify->m_flags |= M_EOR | M_NOTIFICATION;
2591 m_notify->m_pkthdr.len = sizeof(struct sctp_shutdown_event);
2592 m_notify->m_pkthdr.rcvif = 0;
2593 m_notify->m_len = sizeof(struct sctp_shutdown_event);
2594 m_notify->m_next = NULL;
2596 to = (struct sockaddr *)(struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr;
2597 if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
2598 to->sa_family == AF_INET) {
2599 struct sockaddr_in *sin;
2601 sin = (struct sockaddr_in *)to;
2602 bzero(&sin6, sizeof(sin6));
2603 sin6.sin6_family = AF_INET6;
2604 sin6.sin6_len = sizeof(struct sockaddr_in6);
2605 sin6.sin6_addr.s6_addr16[2] = 0xffff;
2606 bcopy(&sin->sin_addr, &sin6.sin6_addr.s6_addr16[3],
2607 sizeof(sin6.sin6_addr.s6_addr16[3]));
2608 sin6.sin6_port = sin->sin_port;
2609 to = (struct sockaddr *)&sin6;
2611 /* check and strip embedded scope junk */
2612 to = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)to,
2613 &lsa6);
2614 if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
2615 sctp_m_freem(m_notify);
2616 return;
2618 /* append to socket */
2619 SCTP_TCB_UNLOCK(stcb);
2620 SCTP_INP_WLOCK(stcb->sctp_ep);
2621 SCTP_TCB_LOCK(stcb);
2622 if (!sctp_sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to,
2623 m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
2624 /* not enough room */
2625 sctp_m_freem(m_notify);
2626 SCTP_INP_WUNLOCK(stcb->sctp_ep);
2627 return;
2629 if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
2630 ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
2631 if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
2632 stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
2634 } else {
2635 stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
2637 SCTP_INP_WUNLOCK(stcb->sctp_ep);
2638 sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
2641 static void
2642 sctp_notify_stream_reset(struct sctp_tcb *stcb,
2643 int number_entries, uint16_t *list, int flag)
2645 struct mbuf *m_notify;
2646 struct sctp_stream_reset_event *strreset;
2647 struct sockaddr_in6 sin6, lsa6;
2648 struct sockaddr *to;
2649 int len;
2651 if (!(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_STREAM_RESETEVNT))
2652 /* event not enabled */
2653 return;
2655 MGETHDR(m_notify, MB_DONTWAIT, MT_DATA);
2656 if (m_notify == NULL)
2657 /* no space left */
2658 return;
2659 m_notify->m_len = 0;
2660 len = sizeof(struct sctp_stream_reset_event) + (number_entries * sizeof(uint16_t));
2661 if (len > M_TRAILINGSPACE(m_notify)) {
2662 MCLGET(m_notify, MB_WAIT);
2664 if (m_notify == NULL)
2665 /* no clusters */
2666 return;
2668 if (len > M_TRAILINGSPACE(m_notify)) {
2669 /* never enough room */
2670 m_freem(m_notify);
2671 return;
2673 strreset = mtod(m_notify, struct sctp_stream_reset_event *);
2674 strreset->strreset_type = SCTP_STREAM_RESET_EVENT;
2675 if (number_entries == 0) {
2676 strreset->strreset_flags = flag | SCTP_STRRESET_ALL_STREAMS;
2677 } else {
2678 strreset->strreset_flags = flag | SCTP_STRRESET_STREAM_LIST;
2680 strreset->strreset_length = len;
2681 strreset->strreset_assoc_id = sctp_get_associd(stcb);
2682 if (number_entries) {
2683 int i;
2684 for (i=0; i<number_entries; i++) {
2685 strreset->strreset_list[i] = list[i];
2688 m_notify->m_flags |= M_EOR | M_NOTIFICATION;
2689 m_notify->m_pkthdr.len = len;
2690 m_notify->m_pkthdr.rcvif = 0;
2691 m_notify->m_len = len;
2692 m_notify->m_next = NULL;
2693 if (sctp_sbspace(&stcb->sctp_socket->so_rcv) < m_notify->m_len) {
2694 /* no space */
2695 sctp_m_freem(m_notify);
2696 return;
2698 to = (struct sockaddr *)(struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr;
2699 if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
2700 to->sa_family == AF_INET) {
2701 struct sockaddr_in *sin;
2703 sin = (struct sockaddr_in *)to;
2704 bzero(&sin6, sizeof(sin6));
2705 sin6.sin6_family = AF_INET6;
2706 sin6.sin6_len = sizeof(struct sockaddr_in6);
2707 sin6.sin6_addr.s6_addr16[2] = 0xffff;
2708 bcopy(&sin->sin_addr, &sin6.sin6_addr.s6_addr16[3],
2709 sizeof(sin6.sin6_addr.s6_addr16[3]));
2710 sin6.sin6_port = sin->sin_port;
2711 to = (struct sockaddr *)&sin6;
2713 /* check and strip embedded scope junk */
2714 to = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)to,
2715 &lsa6);
2716 /* append to socket */
2717 SCTP_TCB_UNLOCK(stcb);
2718 SCTP_INP_WLOCK(stcb->sctp_ep);
2719 SCTP_TCB_LOCK(stcb);
2720 if (!sctp_sbappendaddr_nocheck(&stcb->sctp_socket->so_rcv, to,
2721 m_notify, NULL, stcb->asoc.my_vtag, stcb->sctp_ep)) {
2722 /* not enough room */
2723 sctp_m_freem(m_notify);
2724 SCTP_INP_WUNLOCK(stcb->sctp_ep);
2725 return;
2727 if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
2728 ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)){
2729 if (sctp_add_to_socket_q(stcb->sctp_ep, stcb)) {
2730 stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
2732 } else {
2733 stcb->asoc.my_rwnd_control_len += sizeof(struct mbuf);
2735 SCTP_INP_WUNLOCK(stcb->sctp_ep);
2736 sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
2740 void
2741 sctp_ulp_notify(u_int32_t notification, struct sctp_tcb *stcb,
2742 u_int32_t error, void *data)
2744 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
2745 /* No notifications up when we are in a no socket state */
2746 return;
2748 if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
2749 /* Can't send up to a closed socket any notifications */
2750 return;
2752 switch (notification) {
2753 case SCTP_NOTIFY_ASSOC_UP:
2754 sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error);
2755 break;
2756 case SCTP_NOTIFY_ASSOC_DOWN:
2757 sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error);
2758 break;
2759 case SCTP_NOTIFY_INTERFACE_DOWN:
2761 struct sctp_nets *net;
2762 net = (struct sctp_nets *)data;
2763 sctp_notify_peer_addr_change(stcb, SCTP_ADDR_UNREACHABLE,
2764 (struct sockaddr *)&net->ro._l_addr, error);
2765 break;
2767 case SCTP_NOTIFY_INTERFACE_UP:
2769 struct sctp_nets *net;
2770 net = (struct sctp_nets *)data;
2771 sctp_notify_peer_addr_change(stcb, SCTP_ADDR_AVAILABLE,
2772 (struct sockaddr *)&net->ro._l_addr, error);
2773 break;
2775 case SCTP_NOTIFY_INTERFACE_CONFIRMED:
2777 struct sctp_nets *net;
2778 net = (struct sctp_nets *)data;
2779 sctp_notify_peer_addr_change(stcb, SCTP_ADDR_CONFIRMED,
2780 (struct sockaddr *)&net->ro._l_addr, error);
2781 break;
2783 case SCTP_NOTIFY_DG_FAIL:
2784 sctp_notify_send_failed(stcb, error,
2785 (struct sctp_tmit_chunk *)data);
2786 break;
2787 case SCTP_NOTIFY_ADAPTION_INDICATION:
2788 /* Here the error is the adaption indication */
2789 sctp_notify_adaption_layer(stcb, error);
2790 break;
2791 case SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION:
2792 sctp_notify_partial_delivery_indication(stcb, error);
2793 break;
2794 case SCTP_NOTIFY_STRDATA_ERR:
2795 break;
2796 case SCTP_NOTIFY_ASSOC_ABORTED:
2797 sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error);
2798 break;
2799 case SCTP_NOTIFY_PEER_OPENED_STREAM:
2800 break;
2801 case SCTP_NOTIFY_STREAM_OPENED_OK:
2802 break;
2803 case SCTP_NOTIFY_ASSOC_RESTART:
2804 sctp_notify_assoc_change(SCTP_RESTART, stcb, error);
2805 break;
2806 case SCTP_NOTIFY_HB_RESP:
2807 break;
2808 case SCTP_NOTIFY_STR_RESET_SEND:
2809 sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), SCTP_STRRESET_OUTBOUND_STR);
2810 break;
2811 case SCTP_NOTIFY_STR_RESET_RECV:
2812 sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), SCTP_STRRESET_INBOUND_STR);
2813 break;
2814 case SCTP_NOTIFY_ASCONF_ADD_IP:
2815 sctp_notify_peer_addr_change(stcb, SCTP_ADDR_ADDED, data,
2816 error);
2817 break;
2818 case SCTP_NOTIFY_ASCONF_DELETE_IP:
2819 sctp_notify_peer_addr_change(stcb, SCTP_ADDR_REMOVED, data,
2820 error);
2821 break;
2822 case SCTP_NOTIFY_ASCONF_SET_PRIMARY:
2823 sctp_notify_peer_addr_change(stcb, SCTP_ADDR_MADE_PRIM, data,
2824 error);
2825 break;
2826 case SCTP_NOTIFY_ASCONF_SUCCESS:
2827 break;
2828 case SCTP_NOTIFY_ASCONF_FAILED:
2829 break;
2830 case SCTP_NOTIFY_PEER_SHUTDOWN:
2831 sctp_notify_shutdown_event(stcb);
2832 break;
2833 default:
2834 #ifdef SCTP_DEBUG
2835 if (sctp_debug_on & SCTP_DEBUG_UTIL1) {
2836 kprintf("NOTIFY: unknown notification %xh (%u)\n",
2837 notification, notification);
2839 #endif /* SCTP_DEBUG */
2840 break;
2841 } /* end switch */
2844 void
2845 sctp_report_all_outbound(struct sctp_tcb *stcb)
2847 struct sctp_association *asoc;
2848 struct sctp_stream_out *outs;
2849 struct sctp_tmit_chunk *chk;
2851 asoc = &stcb->asoc;
2853 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
2854 return;
2856 /* now through all the gunk freeing chunks */
2857 TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) {
2858 /* now clean up any chunks here */
2859 chk = TAILQ_FIRST(&outs->outqueue);
2860 while (chk) {
2861 stcb->asoc.stream_queue_cnt--;
2862 TAILQ_REMOVE(&outs->outqueue, chk, sctp_next);
2863 sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
2864 SCTP_NOTIFY_DATAGRAM_UNSENT, chk);
2865 if (chk->data) {
2866 sctp_m_freem(chk->data);
2867 chk->data = NULL;
2869 if (chk->whoTo)
2870 sctp_free_remote_addr(chk->whoTo);
2871 chk->whoTo = NULL;
2872 chk->asoc = NULL;
2873 /* Free the chunk */
2874 SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
2875 sctppcbinfo.ipi_count_chunk--;
2876 if ((int)sctppcbinfo.ipi_count_chunk < 0) {
2877 panic("Chunk count is negative");
2879 sctppcbinfo.ipi_gencnt_chunk++;
2880 chk = TAILQ_FIRST(&outs->outqueue);
2883 /* pending send queue SHOULD be empty */
2884 if (!TAILQ_EMPTY(&asoc->send_queue)) {
2885 chk = TAILQ_FIRST(&asoc->send_queue);
2886 while (chk) {
2887 TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next);
2888 sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, SCTP_NOTIFY_DATAGRAM_UNSENT, chk);
2889 if (chk->data) {
2890 sctp_m_freem(chk->data);
2891 chk->data = NULL;
2893 if (chk->whoTo)
2894 sctp_free_remote_addr(chk->whoTo);
2895 chk->whoTo = NULL;
2896 SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
2897 sctppcbinfo.ipi_count_chunk--;
2898 if ((int)sctppcbinfo.ipi_count_chunk < 0) {
2899 panic("Chunk count is negative");
2901 sctppcbinfo.ipi_gencnt_chunk++;
2902 chk = TAILQ_FIRST(&asoc->send_queue);
2905 /* sent queue SHOULD be empty */
2906 if (!TAILQ_EMPTY(&asoc->sent_queue)) {
2907 chk = TAILQ_FIRST(&asoc->sent_queue);
2908 while (chk) {
2909 TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next);
2910 sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
2911 SCTP_NOTIFY_DATAGRAM_SENT, chk);
2912 if (chk->data) {
2913 sctp_m_freem(chk->data);
2914 chk->data = NULL;
2916 if (chk->whoTo)
2917 sctp_free_remote_addr(chk->whoTo);
2918 chk->whoTo = NULL;
2919 SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
2920 sctppcbinfo.ipi_count_chunk--;
2921 if ((int)sctppcbinfo.ipi_count_chunk < 0) {
2922 panic("Chunk count is negative");
2924 sctppcbinfo.ipi_gencnt_chunk++;
2925 chk = TAILQ_FIRST(&asoc->sent_queue);
2930 void
2931 sctp_abort_notification(struct sctp_tcb *stcb, int error)
2934 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
2935 return;
2937 /* Tell them we lost the asoc */
2938 sctp_report_all_outbound(stcb);
2939 sctp_ulp_notify(SCTP_NOTIFY_ASSOC_ABORTED, stcb, error, NULL);
2942 void
2943 sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
2944 struct mbuf *m, int iphlen, struct sctphdr *sh, struct mbuf *op_err)
2946 u_int32_t vtag;
2948 vtag = 0;
2949 if (stcb != NULL) {
2950 /* We have a TCB to abort, send notification too */
2951 vtag = stcb->asoc.peer_vtag;
2952 sctp_abort_notification(stcb, 0);
2954 sctp_send_abort(m, iphlen, sh, vtag, op_err);
2955 if (stcb != NULL) {
2956 /* Ok, now lets free it */
2957 sctp_free_assoc(inp, stcb);
2958 } else {
2959 if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
2960 if (LIST_FIRST(&inp->sctp_asoc_list) == NULL) {
2961 sctp_inpcb_free(inp, 1);
2967 void
2968 sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
2969 int error, struct mbuf *op_err)
2971 u_int32_t vtag;
2973 if (stcb == NULL) {
2974 /* Got to have a TCB */
2975 if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
2976 if (LIST_FIRST(&inp->sctp_asoc_list) == NULL) {
2977 sctp_inpcb_free(inp, 1);
2980 return;
2982 vtag = stcb->asoc.peer_vtag;
2983 /* notify the ulp */
2984 if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0)
2985 sctp_abort_notification(stcb, error);
2986 /* notify the peer */
2987 sctp_send_abort_tcb(stcb, op_err);
2988 /* now free the asoc */
2989 sctp_free_assoc(inp, stcb);
2992 void
2993 sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
2994 struct sctp_inpcb *inp, struct mbuf *op_err)
2996 struct sctp_chunkhdr *ch, chunk_buf;
2997 unsigned int chk_length;
2999 /* Generate a TO address for future reference */
3000 if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
3001 if (LIST_FIRST(&inp->sctp_asoc_list) == NULL) {
3002 sctp_inpcb_free(inp, 1);
3005 ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
3006 sizeof(*ch), (u_int8_t *)&chunk_buf);
3007 while (ch != NULL) {
3008 chk_length = ntohs(ch->chunk_length);
3009 if (chk_length < sizeof(*ch)) {
3010 /* break to abort land */
3011 break;
3013 switch (ch->chunk_type) {
3014 case SCTP_PACKET_DROPPED:
3015 /* we don't respond to pkt-dropped */
3016 return;
3017 case SCTP_ABORT_ASSOCIATION:
3018 /* we don't respond with an ABORT to an ABORT */
3019 return;
3020 case SCTP_SHUTDOWN_COMPLETE:
3022 * we ignore it since we are not waiting for it
3023 * and peer is gone
3025 return;
3026 case SCTP_SHUTDOWN_ACK:
3027 sctp_send_shutdown_complete2(m, iphlen, sh);
3028 return;
3029 default:
3030 break;
3032 offset += SCTP_SIZE32(chk_length);
3033 ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
3034 sizeof(*ch), (u_int8_t *)&chunk_buf);
3036 sctp_send_abort(m, iphlen, sh, 0, op_err);
3040 * check the inbound datagram to make sure there is not an abort
3041 * inside it, if there is return 1, else return 0.
3044 sctp_is_there_an_abort_here(struct mbuf *m, int iphlen, int *vtagfill)
3046 struct sctp_chunkhdr *ch;
3047 struct sctp_init_chunk *init_chk, chunk_buf;
3048 int offset;
3049 unsigned int chk_length;
3051 offset = iphlen + sizeof(struct sctphdr);
3052 ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, sizeof(*ch),
3053 (u_int8_t *)&chunk_buf);
3054 while (ch != NULL) {
3055 chk_length = ntohs(ch->chunk_length);
3056 if (chk_length < sizeof(*ch)) {
3057 /* packet is probably corrupt */
3058 break;
3060 /* we seem to be ok, is it an abort? */
3061 if (ch->chunk_type == SCTP_ABORT_ASSOCIATION) {
3062 /* yep, tell them */
3063 return (1);
3065 if (ch->chunk_type == SCTP_INITIATION) {
3066 /* need to update the Vtag */
3067 init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m,
3068 offset, sizeof(*init_chk), (u_int8_t *)&chunk_buf);
3069 if (init_chk != NULL) {
3070 *vtagfill = ntohl(init_chk->init.initiate_tag);
3073 /* Nope, move to the next chunk */
3074 offset += SCTP_SIZE32(chk_length);
3075 ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
3076 sizeof(*ch), (u_int8_t *)&chunk_buf);
3078 return (0);
3082 * currently (2/02), ifa_addr embeds scope_id's and don't
3083 * have sin6_scope_id set (i.e. it's 0)
3084 * so, create this function to compare link local scopes
3086 uint32_t
3087 sctp_is_same_scope(struct sockaddr_in6 *addr1, struct sockaddr_in6 *addr2)
3089 struct sockaddr_in6 a, b;
3091 /* save copies */
3092 a = *addr1;
3093 b = *addr2;
3095 if (a.sin6_scope_id == 0)
3096 if (in6_recoverscope(&a, &a.sin6_addr, NULL)) {
3097 /* can't get scope, so can't match */
3098 return (0);
3100 if (b.sin6_scope_id == 0)
3101 if (in6_recoverscope(&b, &b.sin6_addr, NULL)) {
3102 /* can't get scope, so can't match */
3103 return (0);
3105 if (a.sin6_scope_id != b.sin6_scope_id)
3106 return (0);
3108 return (1);
3112 * returns a sockaddr_in6 with embedded scope recovered and removed
3114 struct sockaddr_in6 *
3115 sctp_recover_scope(struct sockaddr_in6 *addr, struct sockaddr_in6 *store)
3118 /* check and strip embedded scope junk */
3119 if (addr->sin6_family == AF_INET6) {
3120 if (IN6_IS_SCOPE_LINKLOCAL(&addr->sin6_addr)) {
3121 if (addr->sin6_scope_id == 0) {
3122 *store = *addr;
3123 if (!in6_recoverscope(store, &store->sin6_addr,
3124 NULL)) {
3125 /* use the recovered scope */
3126 addr = store;
3128 /* else, return the original "to" addr */
3132 return (addr);
3136 * are the two addresses the same? currently a "scopeless" check
3137 * returns: 1 if same, 0 if not
3140 sctp_cmpaddr(struct sockaddr *sa1, struct sockaddr *sa2)
3143 /* must be valid */
3144 if (sa1 == NULL || sa2 == NULL)
3145 return (0);
3147 /* must be the same family */
3148 if (sa1->sa_family != sa2->sa_family)
3149 return (0);
3151 if (sa1->sa_family == AF_INET6) {
3152 /* IPv6 addresses */
3153 struct sockaddr_in6 *sin6_1, *sin6_2;
3155 sin6_1 = (struct sockaddr_in6 *)sa1;
3156 sin6_2 = (struct sockaddr_in6 *)sa2;
3157 return (SCTP6_ARE_ADDR_EQUAL(&sin6_1->sin6_addr,
3158 &sin6_2->sin6_addr));
3159 } else if (sa1->sa_family == AF_INET) {
3160 /* IPv4 addresses */
3161 struct sockaddr_in *sin_1, *sin_2;
3163 sin_1 = (struct sockaddr_in *)sa1;
3164 sin_2 = (struct sockaddr_in *)sa2;
3165 return (sin_1->sin_addr.s_addr == sin_2->sin_addr.s_addr);
3166 } else {
3167 /* we don't do these... */
3168 return (0);
3172 void
3173 sctp_print_address(struct sockaddr *sa)
3176 if (sa->sa_family == AF_INET6) {
3177 struct sockaddr_in6 *sin6;
3178 sin6 = (struct sockaddr_in6 *)sa;
3179 kprintf("IPv6 address: %s:%d scope:%u\n",
3180 ip6_sprintf(&sin6->sin6_addr), ntohs(sin6->sin6_port),
3181 sin6->sin6_scope_id);
3182 } else if (sa->sa_family == AF_INET) {
3183 struct sockaddr_in *sin;
3184 sin = (struct sockaddr_in *)sa;
3185 kprintf("IPv4 address: %s:%d\n", inet_ntoa(sin->sin_addr),
3186 ntohs(sin->sin_port));
3187 } else {
3188 kprintf("?\n");
3192 void
3193 sctp_print_address_pkt(struct ip *iph, struct sctphdr *sh)
3195 if (iph->ip_v == IPVERSION) {
3196 struct sockaddr_in lsa, fsa;
3198 bzero(&lsa, sizeof(lsa));
3199 lsa.sin_len = sizeof(lsa);
3200 lsa.sin_family = AF_INET;
3201 lsa.sin_addr = iph->ip_src;
3202 lsa.sin_port = sh->src_port;
3203 bzero(&fsa, sizeof(fsa));
3204 fsa.sin_len = sizeof(fsa);
3205 fsa.sin_family = AF_INET;
3206 fsa.sin_addr = iph->ip_dst;
3207 fsa.sin_port = sh->dest_port;
3208 kprintf("src: ");
3209 sctp_print_address((struct sockaddr *)&lsa);
3210 kprintf("dest: ");
3211 sctp_print_address((struct sockaddr *)&fsa);
3212 } else if (iph->ip_v == (IPV6_VERSION >> 4)) {
3213 struct ip6_hdr *ip6;
3214 struct sockaddr_in6 lsa6, fsa6;
3216 ip6 = (struct ip6_hdr *)iph;
3217 bzero(&lsa6, sizeof(lsa6));
3218 lsa6.sin6_len = sizeof(lsa6);
3219 lsa6.sin6_family = AF_INET6;
3220 lsa6.sin6_addr = ip6->ip6_src;
3221 lsa6.sin6_port = sh->src_port;
3222 bzero(&fsa6, sizeof(fsa6));
3223 fsa6.sin6_len = sizeof(fsa6);
3224 fsa6.sin6_family = AF_INET6;
3225 fsa6.sin6_addr = ip6->ip6_dst;
3226 fsa6.sin6_port = sh->dest_port;
3227 kprintf("src: ");
3228 sctp_print_address((struct sockaddr *)&lsa6);
3229 kprintf("dest: ");
3230 sctp_print_address((struct sockaddr *)&fsa6);
3234 #if defined(__FreeBSD__) || defined(__APPLE__)
3236 /* cloned from uipc_socket.c */
3238 #define SCTP_SBLINKRECORD(sb, m0) do { \
3239 if ((sb)->sb_lastrecord != NULL) \
3240 (sb)->sb_lastrecord->m_nextpkt = (m0); \
3241 else \
3242 (sb)->sb_mb = (m0); \
3243 (sb)->sb_lastrecord = (m0); \
3244 } while (/*CONSTCOND*/0)
3245 #endif
3249 sctp_sbappendaddr_nocheck(struct signalsockbuf *ssb, struct sockaddr *asa, struct mbuf *m0,
3250 struct mbuf *control, u_int32_t tag,
3251 struct sctp_inpcb *inp)
3253 struct mbuf *m, *n, *nlast;
3254 int cnt=0;
3256 if (m0 && (m0->m_flags & M_PKTHDR) == 0)
3257 panic("sctp_sbappendaddr_nocheck");
3259 for (n = control; n; n = n->m_next) {
3260 if (n->m_next == 0) /* get pointer to last control buf */
3261 break;
3263 if (((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) ||
3264 ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)== 0)) {
3265 if (asa->sa_len > MHLEN)
3266 return (0);
3267 try_again:
3268 MGETHDR(m, MB_DONTWAIT, MT_SONAME);
3269 if (m == 0)
3270 return (0);
3271 m->m_len = 0;
3272 /* safety */
3273 if (m == m0) {
3274 kprintf("Duplicate mbuf allocated %p in and mget returned %p?\n",
3275 m0, m);
3276 if (cnt) {
3277 panic("more than once");
3279 cnt++;
3280 goto try_again;
3282 m->m_len = asa->sa_len;
3283 bcopy((caddr_t)asa, mtod(m, caddr_t), asa->sa_len);
3285 else {
3286 m = NULL;
3288 if (n)
3289 n->m_next = m0; /* concatenate data to control */
3290 else
3291 control = m0;
3292 if (m)
3293 m->m_next = control;
3294 else
3295 m = control;
3296 m->m_pkthdr.csum_data = (int)tag;
3298 SOCKBUF_LOCK(ssb);
3299 for (n = m; n; n = n->m_next)
3300 sballoc(&ssb->sb, n);
3301 nlast = n;
3302 if (ssb->ssb_mb == NULL) {
3303 inp->sctp_vtag_first = tag;
3305 if ((n = ssb->ssb_mb) != NULL) {
3306 if ((n->m_nextpkt != inp->sb_last_mpkt) && (n->m_nextpkt == NULL)) {
3307 inp->sb_last_mpkt = NULL;
3309 if (inp->sb_last_mpkt)
3310 inp->sb_last_mpkt->m_nextpkt = m;
3311 else {
3312 while (n->m_nextpkt) {
3313 n = n->m_nextpkt;
3315 n->m_nextpkt = m;
3317 inp->sb_last_mpkt = m;
3318 } else {
3319 inp->sb_last_mpkt = ssb->ssb_mb = m;
3320 inp->sctp_vtag_first = tag;
3322 SOCKBUF_UNLOCK(ssb);
3323 return (1);
3326 /*************HOLD THIS COMMENT FOR PATCH FILE OF
3327 *************ALTERNATE ROUTING CODE
3330 /*************HOLD THIS COMMENT FOR END OF PATCH FILE OF
3331 *************ALTERNATE ROUTING CODE
3334 struct mbuf *
3335 sctp_generate_invmanparam(int err)
3337 /* Return a MBUF with a invalid mandatory parameter */
3338 struct mbuf *m;
3340 MGET(m, MB_DONTWAIT, MT_DATA);
3341 if (m) {
3342 struct sctp_paramhdr *ph;
3343 m->m_len = sizeof(struct sctp_paramhdr);
3344 ph = mtod(m, struct sctp_paramhdr *);
3345 ph->param_length = htons(sizeof(struct sctp_paramhdr));
3346 ph->param_type = htons(err);
3348 return (m);
3351 static int
3352 sctp_should_be_moved(struct mbuf *this, struct sctp_association *asoc)
3354 struct mbuf *m;
3356 * given a mbuf chain, look through it finding
3357 * the M_PKTHDR and return 1 if it belongs to
3358 * the association given. We tell this by
3359 * a kludge where we stuff the my_vtag of the asoc
3360 * into the m->m_pkthdr.csum_data/csum field.
3362 m = this;
3363 while (m) {
3364 if (m->m_flags & M_PKTHDR) {
3365 /* check it */
3366 #if defined(__OpenBSD__)
3367 if ((u_int32_t)m->m_pkthdr.csum == asoc->my_vtag)
3368 #else
3369 if ((u_int32_t)m->m_pkthdr.csum_data == asoc->my_vtag)
3370 #endif
3372 /* Yep */
3373 return (1);
3376 m = m->m_next;
3378 return (0);
3381 u_int32_t
3382 sctp_get_first_vtag_from_sb(struct socket *so)
3384 struct mbuf *this, *at;
3385 u_int32_t retval;
3387 retval = 0;
3388 if (so->so_rcv.ssb_mb) {
3389 /* grubbing time */
3390 this = so->so_rcv.ssb_mb;
3391 while (this) {
3392 at = this;
3393 /* get to the m_pkthdr */
3394 while (at) {
3395 if (at->m_flags & M_PKTHDR)
3396 break;
3397 else {
3398 at = at->m_next;
3401 /* now do we have a m_pkthdr */
3402 if (at && (at->m_flags & M_PKTHDR)) {
3403 /* check it */
3404 #if defined(__OpenBSD__)
3405 if ((u_int32_t)at->m_pkthdr.csum != 0)
3406 #else
3407 if ((u_int32_t)at->m_pkthdr.csum_data != 0)
3408 #endif
3410 /* its the one */
3411 #if defined(__OpenBSD__)
3412 retval = (u_int32_t)at->m_pkthdr.csum;
3413 #else
3414 retval =
3415 (u_int32_t)at->m_pkthdr.csum_data;
3416 #endif
3417 break;
3420 this = this->m_nextpkt;
3424 return (retval);
3427 void
3428 sctp_grub_through_socket_buffer(struct sctp_inpcb *inp, struct socket *old,
3429 struct socket *new, struct sctp_tcb *stcb)
3431 struct mbuf **put, **take, *next, *this;
3432 struct signalsockbuf *old_sb, *new_sb;
3433 struct sctp_association *asoc;
3434 int moved_top = 0;
3436 asoc = &stcb->asoc;
3437 old_sb = &old->so_rcv;
3438 new_sb = &new->so_rcv;
3439 if (old_sb->ssb_mb == NULL) {
3440 /* Nothing to move */
3441 return;
3443 SOCKBUF_LOCK(old_sb);
3444 SOCKBUF_LOCK(new_sb);
3446 if (inp->sctp_vtag_first == asoc->my_vtag) {
3447 /* First one must be moved */
3448 struct mbuf *mm;
3449 for (mm = old_sb->ssb_mb; mm; mm = mm->m_next) {
3451 * Go down the chain and fix
3452 * the space allocation of the
3453 * two sockets.
3455 sbfree(&old_sb->sb, mm);
3456 sballoc(&new_sb->sb, mm);
3458 new_sb->ssb_mb = old_sb->ssb_mb;
3459 old_sb->ssb_mb = new_sb->ssb_mb->m_nextpkt;
3460 new_sb->ssb_mb->m_nextpkt = NULL;
3461 put = &new_sb->ssb_mb->m_nextpkt;
3462 moved_top = 1;
3463 } else {
3464 put = &new_sb->ssb_mb;
3467 take = &old_sb->ssb_mb;
3468 next = old_sb->ssb_mb;
3469 while (next) {
3470 this = next;
3471 /* postion for next one */
3472 next = this->m_nextpkt;
3473 /* check the tag of this packet */
3474 if (sctp_should_be_moved(this, asoc)) {
3475 /* yes this needs to be moved */
3476 struct mbuf *mm;
3477 *take = this->m_nextpkt;
3478 this->m_nextpkt = NULL;
3479 *put = this;
3480 for (mm = this; mm; mm = mm->m_next) {
3482 * Go down the chain and fix
3483 * the space allocation of the
3484 * two sockets.
3486 sbfree(&old_sb->sb, mm);
3487 sballoc(&new_sb->sb, mm);
3489 put = &this->m_nextpkt;
3491 } else {
3492 /* no advance our take point. */
3493 take = &this->m_nextpkt;
3496 if (moved_top) {
3498 * Ok so now we must re-postion vtag_first to
3499 * match the new first one since we moved the
3500 * mbuf at the top.
3502 inp->sctp_vtag_first = sctp_get_first_vtag_from_sb(old);
3504 SOCKBUF_UNLOCK(old_sb);
3505 SOCKBUF_UNLOCK(new_sb);
3508 void
3509 sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc,
3510 struct sctp_tmit_chunk *tp1)
3512 if (tp1->data == NULL) {
3513 return;
3515 #ifdef SCTP_MBCNT_LOGGING
3516 sctp_log_mbcnt(SCTP_LOG_MBCNT_DECREASE,
3517 asoc->total_output_queue_size,
3518 tp1->book_size,
3519 asoc->total_output_mbuf_queue_size,
3520 tp1->mbcnt);
3521 #endif
3522 if (asoc->total_output_queue_size >= tp1->book_size) {
3523 asoc->total_output_queue_size -= tp1->book_size;
3524 } else {
3525 asoc->total_output_queue_size = 0;
3528 /* Now free the mbuf */
3529 if (asoc->total_output_mbuf_queue_size >= tp1->mbcnt) {
3530 asoc->total_output_mbuf_queue_size -= tp1->mbcnt;
3531 } else {
3532 asoc->total_output_mbuf_queue_size = 0;
3534 if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3535 (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
3536 if (stcb->sctp_socket->so_snd.ssb_cc >= tp1->book_size) {
3537 stcb->sctp_socket->so_snd.ssb_cc -= tp1->book_size;
3538 } else {
3539 stcb->sctp_socket->so_snd.ssb_cc = 0;
3542 if (stcb->sctp_socket->so_snd.ssb_mbcnt >= tp1->mbcnt) {
3543 stcb->sctp_socket->so_snd.ssb_mbcnt -= tp1->mbcnt;
3544 } else {
3545 stcb->sctp_socket->so_snd.ssb_mbcnt = 0;
3551 sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
3552 int reason, struct sctpchunk_listhead *queue)
3554 int ret_sz = 0;
3555 int notdone;
3556 uint8_t foundeom = 0;
3558 do {
3559 ret_sz += tp1->book_size;
3560 tp1->sent = SCTP_FORWARD_TSN_SKIP;
3561 if (tp1->data) {
3562 sctp_free_bufspace(stcb, &stcb->asoc, tp1);
3563 sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, reason, tp1);
3564 sctp_m_freem(tp1->data);
3565 tp1->data = NULL;
3566 sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
3568 if (tp1->flags & SCTP_PR_SCTP_BUFFER) {
3569 stcb->asoc.sent_queue_cnt_removeable--;
3571 if (queue == &stcb->asoc.send_queue) {
3572 TAILQ_REMOVE(&stcb->asoc.send_queue, tp1, sctp_next);
3573 /* on to the sent queue */
3574 TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, tp1,
3575 sctp_next);
3576 stcb->asoc.sent_queue_cnt++;
3578 if ((tp1->rec.data.rcv_flags & SCTP_DATA_NOT_FRAG) ==
3579 SCTP_DATA_NOT_FRAG) {
3580 /* not frag'ed we ae done */
3581 notdone = 0;
3582 foundeom = 1;
3583 } else if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
3584 /* end of frag, we are done */
3585 notdone = 0;
3586 foundeom = 1;
3587 } else {
3588 /* Its a begin or middle piece, we must mark all of it */
3589 notdone = 1;
3590 tp1 = TAILQ_NEXT(tp1, sctp_next);
3592 } while (tp1 && notdone);
3593 if ((foundeom == 0) && (queue == &stcb->asoc.sent_queue)) {
3595 * The multi-part message was scattered
3596 * across the send and sent queue.
3598 tp1 = TAILQ_FIRST(&stcb->asoc.send_queue);
3600 * recurse throught the send_queue too, starting at the
3601 * beginning.
3603 if (tp1) {
3604 ret_sz += sctp_release_pr_sctp_chunk(stcb, tp1, reason,
3605 &stcb->asoc.send_queue);
3606 } else {
3607 kprintf("hmm, nothing on the send queue and no EOM?\n");
3610 return (ret_sz);
3614 * checks to see if the given address, sa, is one that is currently
3615 * known by the kernel
3616 * note: can't distinguish the same address on multiple interfaces and
3617 * doesn't handle multiple addresses with different zone/scope id's
3618 * note: ifa_ifwithaddr() compares the entire sockaddr struct
3620 struct ifaddr *
3621 sctp_find_ifa_by_addr(struct sockaddr *sa)
3623 struct ifnet *ifn;
3625 /* go through all our known interfaces */
3626 TAILQ_FOREACH(ifn, &ifnet, if_list) {
3627 struct ifaddr_container *ifac;
3629 /* go through each interface addresses */
3630 TAILQ_FOREACH(ifac, &ifn->if_addrheads[mycpuid], ifa_link) {
3631 struct ifaddr *ifa = ifac->ifa;
3633 /* correct family? */
3634 if (ifa->ifa_addr->sa_family != sa->sa_family)
3635 continue;
3637 #ifdef INET6
3638 if (ifa->ifa_addr->sa_family == AF_INET6) {
3639 /* IPv6 address */
3640 struct sockaddr_in6 *sin1, *sin2, sin6_tmp;
3641 sin1 = (struct sockaddr_in6 *)ifa->ifa_addr;
3642 if (IN6_IS_SCOPE_LINKLOCAL(&sin1->sin6_addr)) {
3643 /* create a copy and clear scope */
3644 memcpy(&sin6_tmp, sin1,
3645 sizeof(struct sockaddr_in6));
3646 sin1 = &sin6_tmp;
3647 in6_clearscope(&sin1->sin6_addr);
3649 sin2 = (struct sockaddr_in6 *)sa;
3650 if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
3651 sizeof(struct in6_addr)) == 0) {
3652 /* found it */
3653 return (ifa);
3655 } else
3656 #endif
3657 if (ifa->ifa_addr->sa_family == AF_INET) {
3658 /* IPv4 address */
3659 struct sockaddr_in *sin1, *sin2;
3660 sin1 = (struct sockaddr_in *)ifa->ifa_addr;
3661 sin2 = (struct sockaddr_in *)sa;
3662 if (sin1->sin_addr.s_addr ==
3663 sin2->sin_addr.s_addr) {
3664 /* found it */
3665 return (ifa);
3668 /* else, not AF_INET or AF_INET6, so skip */
3669 } /* end foreach ifa */
3670 } /* end foreach ifn */
3671 /* not found! */
3672 return (NULL);
3676 #ifdef __APPLE__
3678 * here we hack in a fix for Apple's m_copym for the case where the first mbuf
3679 * in the chain is a M_PKTHDR and the length is zero
3681 static void
3682 sctp_pkthdr_fix(struct mbuf *m)
3684 struct mbuf *m_nxt;
3686 if ((m->m_flags & M_PKTHDR) == 0) {
3687 /* not a PKTHDR */
3688 return;
3691 if (m->m_len != 0) {
3692 /* not a zero length PKTHDR mbuf */
3693 return;
3696 /* let's move in a word into the first mbuf... yes, ugly! */
3697 m_nxt = m->m_next;
3698 if (m_nxt == NULL) {
3699 /* umm... not a very useful mbuf chain... */
3700 return;
3702 if ((size_t)m_nxt->m_len > sizeof(long)) {
3703 /* move over a long */
3704 bcopy(mtod(m_nxt, caddr_t), mtod(m, caddr_t), sizeof(long));
3705 /* update mbuf data pointers and lengths */
3706 m->m_len += sizeof(long);
3707 m_nxt->m_data += sizeof(long);
3708 m_nxt->m_len -= sizeof(long);
3712 inline struct mbuf *
3713 sctp_m_copym(struct mbuf *m, int off, int len, int wait)
3715 sctp_pkthdr_fix(m);
3716 return (m_copym(m, off, len, wait));
3718 #endif /* __APPLE__ */