1 /* $KAME: sctp_asconf.c,v 1.23 2004/08/17 06:28:01 t-momose Exp $ */
2 /* $DragonFly: src/sys/netinet/sctp_asconf.c,v 1.6 2007/08/27 16:15:42 hasso Exp $ */
5 * Copyright (c) 2001, 2002, 2003, 2004 Cisco Systems, Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY CISCO SYSTEMS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL CISCO SYSTEMS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #if !(defined(__OpenBSD__) || defined(__APPLE__))
33 #include "opt_ipsec.h"
35 #if defined(__FreeBSD__)
36 #include "opt_compat.h"
37 #include "opt_inet6.h"
40 #if defined(__NetBSD__)
46 #elif !defined(__OpenBSD__)
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/malloc.h>
54 #include <sys/socket.h>
55 #include <sys/socketvar.h>
56 #include <sys/kernel.h>
57 #include <sys/sysctl.h>
58 #include <sys/thread2.h>
61 #include <net/if_types.h>
62 #include <net/route.h>
64 #include <netinet/in.h>
65 #include <netinet/in_systm.h>
66 #include <netinet/ip.h>
67 #include <netinet/in_pcb.h>
68 #include <netinet/in_var.h>
69 #include <netinet/ip_var.h>
72 #include <netinet/ip6.h>
73 #include <netinet6/ip6_var.h>
74 #if defined(__FreeBSD__) || (__NetBSD__)
75 #include <netinet6/in6_pcb.h>
76 #elif defined(__OpenBSD__)
77 #include <netinet/in_pcb.h>
79 #include <netinet/icmp6.h>
80 #include <netinet6/nd6.h>
83 #include <netinet/in_pcb.h>
85 #include <netinet/sctp_var.h>
86 #include <netinet/sctp_pcb.h>
87 #include <netinet/sctp_header.h>
88 #include <netinet/sctputil.h>
89 #include <netinet/sctp_output.h>
90 #include <netinet/sctp_asconf.h>
94 * SCTP_DEBUG_ASCONF1: protocol info, general info and errors
95 * SCTP_DEBUG_ASCONF2: detailed info
98 extern u_int32_t sctp_debug_on
;
100 #if defined(SCTP_BASE_FREEBSD) || defined(__APPLE__)
101 #define strlcpy strncpy
103 #endif /* SCTP_DEBUG */
106 * draft-ietf-tsvwg-addip-sctp
108 * Address management only currently supported
109 * For the bound all case:
110 * the asoc local addr list is always a "DO NOT USE" list
111 * For the subset bound case:
112 * If ASCONFs are allowed:
113 * the endpoint local addr list is the usable address list
114 * the asoc local addr list is the "DO NOT USE" list
115 * If ASCONFs are not allowed:
116 * the endpoint local addr list is the default usable list
117 * the asoc local addr list is the usable address list
119 * An ASCONF parameter queue exists per asoc which holds the pending
120 * address operations. Lists are updated upon receipt of ASCONF-ACK.
122 * Deleted addresses are always immediately removed from the lists as
123 * they will (shortly) no longer exist in the kernel. We send ASCONFs
124 * as a courtesy, only if allowed.
128 * ASCONF parameter processing
129 * response_required: set if a reply is required (eg. SUCCESS_REPORT)
130 * returns a mbuf to an "error" response parameter or NULL/"success" if ok
131 * FIX: allocating this many mbufs on the fly is pretty inefficient...
135 sctp_asconf_success_response(uint32_t id
)
137 struct mbuf
*m_reply
= NULL
;
138 struct sctp_asconf_paramhdr
*aph
;
140 MGET(m_reply
, MB_DONTWAIT
, MT_DATA
);
141 if (m_reply
== NULL
) {
143 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
144 kprintf("asconf_success_response: couldn't get mbuf!\n");
146 #endif /* SCTP_DEBUG */
149 aph
= mtod(m_reply
, struct sctp_asconf_paramhdr
*);
150 aph
->correlation_id
= id
;
151 aph
->ph
.param_type
= htons(SCTP_SUCCESS_REPORT
);
152 aph
->ph
.param_length
= sizeof(struct sctp_asconf_paramhdr
);
153 m_reply
->m_len
= aph
->ph
.param_length
;
154 aph
->ph
.param_length
= htons(aph
->ph
.param_length
);
160 sctp_asconf_error_response(uint32_t id
, uint16_t cause
, uint8_t *error_tlv
,
163 struct mbuf
*m_reply
= NULL
;
164 struct sctp_asconf_paramhdr
*aph
;
165 struct sctp_error_cause
*error
;
168 MGET(m_reply
, MB_DONTWAIT
, MT_DATA
);
169 if (m_reply
== NULL
) {
171 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
172 kprintf("asconf_error_response: couldn't get mbuf!\n");
174 #endif /* SCTP_DEBUG */
177 aph
= mtod(m_reply
, struct sctp_asconf_paramhdr
*);
178 error
= (struct sctp_error_cause
*)(aph
+ 1);
180 aph
->correlation_id
= id
;
181 aph
->ph
.param_type
= htons(SCTP_ERROR_CAUSE_IND
);
182 error
->code
= htons(cause
);
183 error
->length
= tlv_length
+ sizeof(struct sctp_error_cause
);
184 aph
->ph
.param_length
= error
->length
+
185 sizeof(struct sctp_asconf_paramhdr
);
187 if (aph
->ph
.param_length
> MLEN
) {
189 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
190 kprintf("asconf_error_response: tlv_length (%xh) too big\n",
193 #endif /* SCTP_DEBUG */
194 sctp_m_freem(m_reply
); /* discard */
198 if (error_tlv
!= NULL
) {
199 tlv
= (uint8_t *)(error
+ 1);
200 memcpy(tlv
, error_tlv
, tlv_length
);
203 m_reply
->m_len
= aph
->ph
.param_length
;
204 error
->length
= htons(error
->length
);
205 aph
->ph
.param_length
= htons(aph
->ph
.param_length
);
211 sctp_process_asconf_add_ip(struct sctp_asconf_paramhdr
*aph
,
212 struct sctp_tcb
*stcb
, int response_required
)
214 struct mbuf
*m_reply
= NULL
;
215 struct sockaddr_storage sa_store
;
216 struct sctp_ipv4addr_param
*v4addr
;
217 uint16_t param_type
, param_length
, aparam_length
;
219 struct sockaddr_in
*sin
;
221 struct sockaddr_in6
*sin6
;
222 struct sctp_ipv6addr_param
*v6addr
;
225 aparam_length
= ntohs(aph
->ph
.param_length
);
226 v4addr
= (struct sctp_ipv4addr_param
*)(aph
+ 1);
228 v6addr
= (struct sctp_ipv6addr_param
*)(aph
+ 1);
230 param_type
= ntohs(v4addr
->ph
.param_type
);
231 param_length
= ntohs(v4addr
->ph
.param_length
);
233 sa
= (struct sockaddr
*)&sa_store
;
234 switch (param_type
) {
235 case SCTP_IPV4_ADDRESS
:
236 if (param_length
!= sizeof(struct sctp_ipv4addr_param
)) {
237 /* invalid param size */
240 sin
= (struct sockaddr_in
*)&sa_store
;
241 bzero(sin
, sizeof(*sin
));
242 sin
->sin_family
= AF_INET
;
243 sin
->sin_len
= sizeof(struct sockaddr_in
);
244 sin
->sin_port
= stcb
->rport
;
245 sin
->sin_addr
.s_addr
= v4addr
->addr
;
247 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
248 kprintf("process_asconf_add_ip: adding ");
249 sctp_print_address(sa
);
251 #endif /* SCTP_DEBUG */
253 case SCTP_IPV6_ADDRESS
:
255 if (param_length
!= sizeof(struct sctp_ipv6addr_param
)) {
256 /* invalid param size */
259 sin6
= (struct sockaddr_in6
*)&sa_store
;
260 bzero(sin6
, sizeof(*sin6
));
261 sin6
->sin6_family
= AF_INET6
;
262 sin6
->sin6_len
= sizeof(struct sockaddr_in6
);
263 sin6
->sin6_port
= stcb
->rport
;
264 memcpy((caddr_t
)&sin6
->sin6_addr
, v6addr
->addr
,
265 sizeof(struct in6_addr
));
267 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
268 kprintf("process_asconf_add_ip: adding ");
269 sctp_print_address(sa
);
271 #endif /* SCTP_DEBUG */
273 /* IPv6 not enabled! */
274 /* FIX ME: currently sends back an invalid param error */
275 m_reply
= sctp_asconf_error_response(aph
->correlation_id
,
276 SCTP_ERROR_INVALID_PARAM
, (uint8_t *)aph
, aparam_length
);
278 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
279 kprintf("process_asconf_add_ip: v6 disabled- skipping ");
280 sctp_print_address(sa
);
282 #endif /* SCTP_DEBUG */
287 m_reply
= sctp_asconf_error_response(aph
->correlation_id
,
288 SCTP_ERROR_UNRESOLVABLE_ADDR
, (uint8_t *)aph
,
293 /* add the address */
294 if (sctp_add_remote_addr(stcb
, sa
, 0, 6) != 0) {
296 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
297 kprintf("process_asconf_add_ip: error adding address\n");
299 #endif /* SCTP_DEBUG */
300 m_reply
= sctp_asconf_error_response(aph
->correlation_id
,
301 SCTP_ERROR_RESOURCE_SHORTAGE
, (uint8_t *)aph
,
304 /* notify upper layer */
305 sctp_ulp_notify(SCTP_NOTIFY_ASCONF_ADD_IP
, stcb
, 0, sa
);
306 if (response_required
) {
308 sctp_asconf_success_response(aph
->correlation_id
);
316 sctp_process_asconf_delete_ip(struct mbuf
*m
, struct sctp_asconf_paramhdr
*aph
,
317 struct sctp_tcb
*stcb
, int response_required
)
319 struct mbuf
*m_reply
= NULL
;
320 struct sockaddr_storage sa_store
, sa_source
;
321 struct sctp_ipv4addr_param
*v4addr
;
322 uint16_t param_type
, param_length
, aparam_length
;
324 struct sockaddr_in
*sin
;
328 struct sockaddr_in6
*sin6
;
329 struct sctp_ipv6addr_param
*v6addr
;
332 aparam_length
= ntohs(aph
->ph
.param_length
);
333 v4addr
= (struct sctp_ipv4addr_param
*)(aph
+ 1);
335 v6addr
= (struct sctp_ipv6addr_param
*)(aph
+ 1);
337 param_type
= ntohs(v4addr
->ph
.param_type
);
338 param_length
= ntohs(v4addr
->ph
.param_length
);
340 /* get the source IP address for deletion check */
341 iph
= mtod(m
, struct ip
*);
342 if (iph
->ip_v
== IPVERSION
) {
344 sin
= (struct sockaddr_in
*)&sa_source
;
345 bzero(sin
, sizeof(*sin
));
346 sin
->sin_family
= AF_INET
;
347 sin
->sin_len
= sizeof(struct sockaddr_in
);
348 sin
->sin_port
= stcb
->rport
;
349 sin
->sin_addr
.s_addr
= iph
->ip_src
.s_addr
;
352 else if (iph
->ip_v
== (IPV6_VERSION
>> 4)) {
356 sin6
= (struct sockaddr_in6
*)&sa_source
;
357 bzero(sin6
, sizeof(*sin6
));
358 sin6
->sin6_family
= AF_INET6
;
359 sin6
->sin6_len
= sizeof(struct sockaddr_in6
);
360 sin6
->sin6_port
= stcb
->rport
;
361 ip6
= mtod(m
, struct ip6_hdr
*);
362 sin6
->sin6_addr
= ip6
->ip6_src
;
368 sa
= (struct sockaddr
*)&sa_store
;
369 switch (param_type
) {
370 case SCTP_IPV4_ADDRESS
:
371 if (param_length
!= sizeof(struct sctp_ipv4addr_param
)) {
372 /* invalid param size */
375 sin
= (struct sockaddr_in
*)&sa_store
;
376 bzero(sin
, sizeof(*sin
));
377 sin
->sin_family
= AF_INET
;
378 sin
->sin_len
= sizeof(struct sockaddr_in
);
379 sin
->sin_port
= stcb
->rport
;
380 sin
->sin_addr
.s_addr
= v4addr
->addr
;
382 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
383 kprintf("process_asconf_delete_ip: deleting ");
384 sctp_print_address(sa
);
386 #endif /* SCTP_DEBUG */
388 case SCTP_IPV6_ADDRESS
:
389 if (param_length
!= sizeof(struct sctp_ipv6addr_param
)) {
390 /* invalid param size */
394 sin6
= (struct sockaddr_in6
*)&sa_store
;
395 bzero(sin6
, sizeof(*sin6
));
396 sin6
->sin6_family
= AF_INET6
;
397 sin6
->sin6_len
= sizeof(struct sockaddr_in6
);
398 sin6
->sin6_port
= stcb
->rport
;
399 memcpy(&sin6
->sin6_addr
, v6addr
->addr
,
400 sizeof(struct in6_addr
));
402 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
403 kprintf("process_asconf_delete_ip: deleting ");
404 sctp_print_address(sa
);
406 #endif /* SCTP_DEBUG */
408 /* IPv6 not enabled! No "action" needed; just ack it */
410 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
411 kprintf("process_asconf_delete_ip: v6 disabled- ignoring: ");
412 sctp_print_address(sa
);
414 #endif /* SCTP_DEBUG */
415 /* just respond with a "success" ASCONF-ACK */
420 m_reply
= sctp_asconf_error_response(aph
->correlation_id
,
421 SCTP_ERROR_UNRESOLVABLE_ADDR
, (uint8_t *)aph
,
426 /* make sure the source address is not being deleted */
427 if ((memcmp(sa
, &sa_source
, sizeof(struct sockaddr_in
)) == 0)
429 || (memcmp(sa
, &sa_source
, sizeof(struct sockaddr_in6
)) == 0)
432 /* trying to delete the source address! */
434 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
435 kprintf("process_asconf_delete_ip: tried to delete source addr\n");
437 #endif /* SCTP_DEBUG */
438 m_reply
= sctp_asconf_error_response(aph
->correlation_id
,
439 SCTP_ERROR_DELETE_SOURCE_ADDR
, (uint8_t *)aph
,
444 /* delete the address */
445 result
= sctp_del_remote_addr(stcb
, sa
);
447 * note if result == -2, the address doesn't exist in the asoc
448 * but since it's being deleted anyways, we just ack the delete
449 * -- but this probably means something has already gone awry
452 /* only one address in the asoc */
454 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
455 kprintf("process_asconf_delete_ip: tried to delete last IP addr!\n");
457 #endif /* SCTP_DEBUG */
458 m_reply
= sctp_asconf_error_response(aph
->correlation_id
,
459 SCTP_ERROR_DELETE_LAST_ADDR
, (uint8_t *)aph
,
462 /* notify upper layer */
463 sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP
, stcb
, 0, sa
);
466 if (response_required
) {
467 m_reply
= sctp_asconf_success_response(aph
->correlation_id
);
473 sctp_process_asconf_set_primary(struct sctp_asconf_paramhdr
*aph
,
474 struct sctp_tcb
*stcb
, int response_required
)
476 struct mbuf
*m_reply
= NULL
;
477 struct sockaddr_storage sa_store
;
478 struct sctp_ipv4addr_param
*v4addr
;
479 uint16_t param_type
, param_length
, aparam_length
;
481 struct sockaddr_in
*sin
;
483 struct sockaddr_in6
*sin6
;
484 struct sctp_ipv6addr_param
*v6addr
;
487 aparam_length
= ntohs(aph
->ph
.param_length
);
488 v4addr
= (struct sctp_ipv4addr_param
*)(aph
+ 1);
490 v6addr
= (struct sctp_ipv6addr_param
*)(aph
+ 1);
492 param_type
= ntohs(v4addr
->ph
.param_type
);
493 param_length
= ntohs(v4addr
->ph
.param_length
);
495 sa
= (struct sockaddr
*)&sa_store
;
496 switch (param_type
) {
497 case SCTP_IPV4_ADDRESS
:
498 if (param_length
!= sizeof(struct sctp_ipv4addr_param
)) {
499 /* invalid param size */
502 sin
= (struct sockaddr_in
*)&sa_store
;
503 bzero(sin
, sizeof(*sin
));
504 sin
->sin_family
= AF_INET
;
505 sin
->sin_len
= sizeof(struct sockaddr_in
);
506 sin
->sin_addr
.s_addr
= v4addr
->addr
;
508 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
509 kprintf("process_asconf_set_primary: ");
510 sctp_print_address(sa
);
512 #endif /* SCTP_DEBUG */
514 case SCTP_IPV6_ADDRESS
:
515 if (param_length
!= sizeof(struct sctp_ipv6addr_param
)) {
516 /* invalid param size */
520 sin6
= (struct sockaddr_in6
*)&sa_store
;
521 bzero(sin6
, sizeof(*sin6
));
522 sin6
->sin6_family
= AF_INET6
;
523 sin6
->sin6_len
= sizeof(struct sockaddr_in6
);
524 memcpy((caddr_t
)&sin6
->sin6_addr
, v6addr
->addr
,
525 sizeof(struct in6_addr
));
527 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
528 kprintf("process_asconf_set_primary: ");
529 sctp_print_address(sa
);
531 #endif /* SCTP_DEBUG */
533 /* IPv6 not enabled! No "action" needed; just ack it */
535 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
536 kprintf("process_asconf_set_primary: v6 disabled- ignoring: ");
537 sctp_print_address(sa
);
539 #endif /* SCTP_DEBUG */
540 /* just respond with a "success" ASCONF-ACK */
545 m_reply
= sctp_asconf_error_response(aph
->correlation_id
,
546 SCTP_ERROR_UNRESOLVABLE_ADDR
, (uint8_t *)aph
,
551 /* set the primary address */
552 if (sctp_set_primary_addr(stcb
, sa
, NULL
) == 0) {
554 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
555 kprintf("process_asconf_set_primary: primary address set\n");
557 #endif /* SCTP_DEBUG */
558 /* notify upper layer */
559 sctp_ulp_notify(SCTP_NOTIFY_ASCONF_SET_PRIMARY
, stcb
, 0, sa
);
561 if (response_required
) {
562 m_reply
= sctp_asconf_success_response(aph
->correlation_id
);
565 /* couldn't set the requested primary address! */
567 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
568 kprintf("process_asconf_set_primary: set primary failed!\n");
570 #endif /* SCTP_DEBUG */
571 /* must have been an invalid address, so report */
572 m_reply
= sctp_asconf_error_response(aph
->correlation_id
,
573 SCTP_ERROR_UNRESOLVABLE_ADDR
, (uint8_t *)aph
,
581 * handles an ASCONF chunk
582 * if all parameters are processed ok, send a plain (empty) ASCONF-ACK
585 sctp_handle_asconf(struct mbuf
*m
, unsigned int offset
, struct sctp_asconf_chunk
*cp
,
586 struct sctp_tcb
*stcb
, struct sctp_nets
*net
)
588 struct sctp_association
*asoc
;
590 struct mbuf
*m_ack
, *m_result
, *m_tail
;
591 struct sctp_asconf_ack_chunk
*ack_cp
;
592 struct sctp_asconf_paramhdr
*aph
, *ack_aph
;
593 struct sctp_ipv6addr_param
*p_addr
;
594 unsigned int asconf_limit
;
595 int error
= 0; /* did an error occur? */
596 /* asconf param buffer */
597 static u_int8_t aparam_buf
[DEFAULT_PARAM_BUFFER
];
599 /* verify minimum length */
600 if (ntohs(cp
->ch
.chunk_length
) < sizeof(struct sctp_asconf_chunk
)) {
602 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
603 kprintf("handle_asconf: chunk too small = %xh\n",
604 ntohs(cp
->ch
.chunk_length
));
606 #endif /* SCTP_DEBUG */
611 serial_num
= ntohl(cp
->serial_number
);
613 if (serial_num
== asoc
->asconf_seq_in
) {
614 /* got a duplicate ASCONF */
616 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
617 kprintf("handle_asconf: got duplicate serial number = %xh\n",
620 #endif /* SCTP_DEBUG */
621 /* resend last ASCONF-ACK... */
622 sctp_send_asconf_ack(stcb
, 1);
624 } else if (serial_num
!= (asoc
->asconf_seq_in
+ 1)) {
626 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
627 kprintf("handle_asconf: incorrect serial number = %xh (expected next = %xh)\n",
628 serial_num
, asoc
->asconf_seq_in
+1);
630 #endif /* SCTP_DEBUG */
634 /* it's the expected "next" sequence number, so process it */
635 asoc
->asconf_seq_in
= serial_num
; /* update sequence */
636 /* get length of all the param's in the ASCONF */
637 asconf_limit
= offset
+ ntohs(cp
->ch
.chunk_length
);
639 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
640 kprintf("handle_asconf: asconf_limit=%u, sequence=%xh\n",
641 asconf_limit
, serial_num
);
643 #endif /* SCTP_DEBUG */
644 if (asoc
->last_asconf_ack_sent
!= NULL
) {
645 /* free last ASCONF-ACK message sent */
646 sctp_m_freem(asoc
->last_asconf_ack_sent
);
647 asoc
->last_asconf_ack_sent
= NULL
;
649 MGETHDR(m_ack
, MB_DONTWAIT
, MT_DATA
);
652 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
653 kprintf("handle_asconf: couldn't get mbuf!\n");
655 #endif /* SCTP_DEBUG */
658 m_tail
= m_ack
; /* current reply chain's tail */
660 /* fill in ASCONF-ACK header */
661 ack_cp
= mtod(m_ack
, struct sctp_asconf_ack_chunk
*);
662 ack_cp
->ch
.chunk_type
= SCTP_ASCONF_ACK
;
663 ack_cp
->ch
.chunk_flags
= 0;
664 ack_cp
->serial_number
= htonl(serial_num
);
665 /* set initial lengths (eg. just an ASCONF-ACK), ntohx at the end! */
666 m_ack
->m_len
= sizeof(struct sctp_asconf_ack_chunk
);
667 ack_cp
->ch
.chunk_length
= sizeof(struct sctp_asconf_ack_chunk
);
668 m_ack
->m_pkthdr
.len
= sizeof(struct sctp_asconf_ack_chunk
);
670 /* skip the lookup address parameter */
671 offset
+= sizeof(struct sctp_asconf_chunk
);
672 p_addr
= (struct sctp_ipv6addr_param
*)sctp_m_getptr(m
, offset
, sizeof(struct sctp_paramhdr
), (uint8_t *)&aparam_buf
);
673 if (p_addr
== NULL
) {
675 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
676 kprintf("handle_asconf: couldn't get lookup addr!\n");
678 #endif /* SCTP_DEBUG */
680 /* respond with a missing/invalid mandatory parameter error */
683 /* param_length is already validated in process_control... */
684 offset
+= ntohs(p_addr
->ph
.param_length
); /* skip lookup addr */
686 /* get pointer to first asconf param in ASCONF */
687 aph
= (struct sctp_asconf_paramhdr
*)sctp_m_getptr(m
, offset
, sizeof(struct sctp_asconf_paramhdr
), (uint8_t *)&aparam_buf
);
688 /* get pointer to first asconf param in ASCONF-ACK */
690 kprintf("Gak in asconf\n");
693 ack_aph
= (struct sctp_asconf_paramhdr
*)(mtod(m_ack
, caddr_t
) + sizeof(struct sctp_asconf_ack_chunk
));
694 if (ack_aph
== NULL
) {
695 kprintf("Gak in asconf2\n");
699 /* process through all parameters */
700 while (aph
!= NULL
) {
701 unsigned int param_length
, param_type
;
703 param_type
= ntohs(aph
->ph
.param_type
);
704 param_length
= ntohs(aph
->ph
.param_length
);
705 if (offset
+ param_length
> asconf_limit
) {
706 /* parameter goes beyond end of chunk! */
712 if (param_length
> sizeof(aparam_buf
)) {
714 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
715 kprintf("handle_asconf: param length (%u) larger than buffer size!\n", param_length
);
717 #endif /* SCTP_DEBUG */
721 if (param_length
<= sizeof(struct sctp_paramhdr
)) {
723 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
724 kprintf("handle_asconf: param length (%u) too short\n", param_length
);
726 #endif /* SCTP_DEBUG */
730 /* get the entire parameter */
731 aph
= (struct sctp_asconf_paramhdr
*)sctp_m_getptr(m
, offset
, param_length
, aparam_buf
);
737 switch (param_type
) {
738 case SCTP_ADD_IP_ADDRESS
:
739 asoc
->peer_supports_asconf
= 1;
740 m_result
= sctp_process_asconf_add_ip(aph
, stcb
, error
);
742 case SCTP_DEL_IP_ADDRESS
:
743 asoc
->peer_supports_asconf
= 1;
744 m_result
= sctp_process_asconf_delete_ip(m
, aph
, stcb
,
747 case SCTP_ERROR_CAUSE_IND
:
748 /* not valid in an ASCONF chunk */
750 case SCTP_SET_PRIM_ADDR
:
751 asoc
->peer_supports_asconf_setprim
= 1;
752 m_result
= sctp_process_asconf_set_primary(aph
, stcb
,
755 case SCTP_SUCCESS_REPORT
:
756 /* not valid in an ASCONF chunk */
758 case SCTP_ULP_ADAPTION
:
762 if ((param_type
& 0x8000) == 0) {
763 /* Been told to STOP at this param */
764 asconf_limit
= offset
;
765 /* FIX FIX - We need to call sctp_arethere_unrecognized_parameters()
766 * to get a operr and send it for any param's with the
767 * 0x4000 bit set OR do it here ourselves... note we still
768 * must STOP if the 0x8000 bit is clear.
771 /* unknown/invalid param type */
775 /* add any (error) result to the reply mbuf chain */
776 if (m_result
!= NULL
) {
778 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
779 kprintf("handle_asconf: adding reply...\n");
781 #endif /* SCTP_DEBUG */
782 m_tail
->m_next
= m_result
;
784 /* update lengths, make sure it's aligned too */
785 m_result
->m_len
= SCTP_SIZE32(m_result
->m_len
);
786 m_ack
->m_pkthdr
.len
+= m_result
->m_len
;
787 ack_cp
->ch
.chunk_length
+= m_result
->m_len
;
788 /* set flag to force success reports */
792 offset
+= SCTP_SIZE32(param_length
);
793 /* update remaining ASCONF message length to process */
794 if (offset
>= asconf_limit
) {
795 /* no more data in the mbuf chain */
798 /* get pointer to next asconf param */
799 aph
= (struct sctp_asconf_paramhdr
*)sctp_m_getptr(m
, offset
,
800 sizeof(struct sctp_asconf_paramhdr
),
801 (uint8_t *)&aparam_buf
);
803 /* can't get an asconf paramhdr */
805 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
806 kprintf("handle_asconf: can't get asconf param hdr!\n");
808 #endif /* SCTP_DEBUG */
809 /* FIX ME - add error here... */
813 ack_cp
->ch
.chunk_length
= htons(ack_cp
->ch
.chunk_length
);
814 /* save the ASCONF-ACK reply */
815 asoc
->last_asconf_ack_sent
= m_ack
;
816 /* and send (a new one) it out... */
817 sctp_send_asconf_ack(stcb
, 0);
821 * does the address match?
822 * returns 0 if not, 1 if so
825 sctp_asconf_addr_match(struct sctp_asconf_addr
*aa
, struct sockaddr
*sa
)
828 if (sa
->sa_family
== AF_INET6
) {
829 /* IPv6 sa address */
831 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)sa
;
832 if ((aa
->ap
.addrp
.ph
.param_type
== SCTP_IPV6_ADDRESS
) &&
833 (memcmp(&aa
->ap
.addrp
.addr
, &sin6
->sin6_addr
,
834 sizeof(struct in6_addr
)) == 0)) {
839 if (sa
->sa_family
== AF_INET
) {
840 /* IPv4 sa address */
841 struct sockaddr_in
*sin
= (struct sockaddr_in
*)sa
;
842 if ((aa
->ap
.addrp
.ph
.param_type
== SCTP_IPV4_ADDRESS
) &&
843 (memcmp(&aa
->ap
.addrp
.addr
, &sin
->sin_addr
,
844 sizeof(struct in_addr
)) == 0)) {
852 * Cleanup for non-responded/OP ERR'd ASCONF
855 sctp_asconf_cleanup(struct sctp_tcb
*stcb
, struct sctp_nets
*net
)
858 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
859 kprintf("asconf_cleanup: marking peer ASCONF incapable and cleaning up\n");
861 #endif /* SCTP_DEBUG */
862 /* mark peer as ASCONF incapable */
863 stcb
->asoc
.peer_supports_asconf
= 0;
864 stcb
->asoc
.peer_supports_asconf_setprim
= 0;
866 * clear out any existing asconfs going out
868 sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF
, stcb
->sctp_ep
, stcb
, net
);
869 stcb
->asoc
.asconf_seq_out
++;
870 /* remove the old ASCONF on our outbound queue */
871 sctp_toss_old_asconf(stcb
);
875 * process an ADD/DELETE IP ack from peer
876 * ifa: corresponding ifaddr to the address being added/deleted
877 * type: SCTP_ADD_IP_ADDRESS or SCTP_DEL_IP_ADDRESS
878 * flag: 1=success, 0=failure
881 sctp_asconf_addr_mgmt_ack(struct sctp_tcb
*stcb
, struct ifaddr
*addr
,
882 uint16_t type
, uint32_t flag
)
886 * do the necessary asoc list work-
887 * if we get a failure indication, leave the address on the
888 * "do not use" asoc list
889 * if we get a success indication, remove the address from
893 * Note: this will only occur for ADD_IP_ADDRESS, since
894 * DEL_IP_ADDRESS is never actually added to the list...
897 /* success case, so remove from the list */
898 sctp_del_local_addr_assoc(stcb
, addr
);
900 /* else, leave it on the list */
904 * add an asconf add/delete IP address parameter to the queue
905 * type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR
906 * returns 0 if completed, non-zero if not completed
907 * NOTE: if adding, but delete already scheduled (and not yet
908 * sent out), simply remove from queue. Same for deleting
909 * an address already scheduled for add. If a duplicate
910 * operation is found, ignore the new one.
913 sctp_asconf_queue_add(struct sctp_tcb
*stcb
, struct ifaddr
*ifa
, uint16_t type
)
915 struct sctp_asconf_addr
*aa
, *aa_next
;
917 char buf
[128]; /* for address in string format */
918 #endif /* SCTP_DEBUG */
920 /* see if peer supports ASCONF */
921 if (stcb
->asoc
.peer_supports_asconf
== 0) {
923 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
924 kprintf("asconf_queue_add: peer doesn't support ASCONF\n");
926 #endif /* SCTP_DEBUG */
930 /* make sure the request isn't already in the queue */
931 for (aa
=TAILQ_FIRST(&stcb
->asoc
.asconf_queue
); aa
!=NULL
; aa
=aa_next
) {
932 aa_next
= TAILQ_NEXT(aa
, next
);
934 if (sctp_asconf_addr_match(aa
, ifa
->ifa_addr
) == 0)
936 /* is the request already in queue (sent or not) */
937 if (aa
->ap
.aph
.ph
.param_type
== type
) {
939 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
940 kprintf("asconf_queue_add: request already exists\n");
942 #endif /* SCTP_DEBUG */
945 /* is the negative request already in queue, and not sent */
947 /* add requested, delete already queued */
948 ((type
== SCTP_ADD_IP_ADDRESS
&&
949 aa
->ap
.aph
.ph
.param_type
== SCTP_DEL_IP_ADDRESS
) ||
950 /* delete requested, add already queued */
951 (type
== SCTP_DEL_IP_ADDRESS
&&
952 aa
->ap
.aph
.ph
.param_type
== SCTP_ADD_IP_ADDRESS
))) {
953 /* delete the existing entry in the queue */
954 TAILQ_REMOVE(&stcb
->asoc
.asconf_queue
, aa
, next
);
955 /* take the entry off the appropriate list */
956 sctp_asconf_addr_mgmt_ack(stcb
, aa
->ifa
, type
, 1);
961 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
962 kprintf("asconf_queue_add: removing 'opposite' queued request\n");
964 #endif /* SCTP_DEBUG */
969 /* adding new request to the queue */
970 MALLOC(aa
, struct sctp_asconf_addr
*, sizeof(*aa
), M_PCB
, M_NOWAIT
);
972 /* didn't get memory */
974 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
975 kprintf("asconf_queue_add: failed to get memory!\n");
977 #endif /* SCTP_DEBUG */
980 /* fill in asconf address parameter fields */
981 /* top level elements are "networked" during send */
982 aa
->ap
.aph
.ph
.param_type
= type
;
984 /* correlation_id filled in during send routine later... */
985 if (ifa
->ifa_addr
->sa_family
== AF_INET6
) {
987 struct sockaddr_in6
*sin6
;
989 sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
990 aa
->ap
.addrp
.ph
.param_type
= SCTP_IPV6_ADDRESS
;
991 aa
->ap
.addrp
.ph
.param_length
= (sizeof(struct sctp_ipv6addr_param
));
992 aa
->ap
.aph
.ph
.param_length
=
993 sizeof(struct sctp_asconf_paramhdr
) +
994 sizeof(struct sctp_ipv6addr_param
);
995 memcpy(&aa
->ap
.addrp
.addr
, &sin6
->sin6_addr
,
996 sizeof(struct in6_addr
));
998 strlcpy(buf
, ip6_sprintf(&sin6
->sin6_addr
), sizeof(buf
));
999 #endif /* SCTP_DEBUG */
1001 } else if (ifa
->ifa_addr
->sa_family
== AF_INET
) {
1003 struct sockaddr_in
*sin
= (struct sockaddr_in
*)ifa
->ifa_addr
;
1004 aa
->ap
.addrp
.ph
.param_type
= SCTP_IPV4_ADDRESS
;
1005 aa
->ap
.addrp
.ph
.param_length
= (sizeof(struct sctp_ipv4addr_param
));
1006 aa
->ap
.aph
.ph
.param_length
=
1007 sizeof(struct sctp_asconf_paramhdr
) +
1008 sizeof(struct sctp_ipv4addr_param
);
1009 memcpy(&aa
->ap
.addrp
.addr
, &sin
->sin_addr
,
1010 sizeof(struct in_addr
));
1012 strlcpy(buf
, inet_ntoa(sin
->sin_addr
), sizeof(buf
));
1013 #endif /* SCTP_DEBUG */
1015 /* invalid family! */
1018 aa
->sent
= 0; /* clear sent flag */
1021 * if we are deleting an address it should go out last
1022 * otherwise, add it to front of the pending queue
1024 if (type
== SCTP_ADD_IP_ADDRESS
) {
1025 /* add goes to the front of the queue */
1026 TAILQ_INSERT_HEAD(&stcb
->asoc
.asconf_queue
, aa
, next
);
1028 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1029 kprintf("asconf_queue_add: appended asconf ADD_IP_ADDRESS: %s\n", buf
);
1031 #endif /* SCTP_DEBUG */
1033 /* delete and set primary goes to the back of the queue */
1034 TAILQ_INSERT_TAIL(&stcb
->asoc
.asconf_queue
, aa
, next
);
1036 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1037 if (type
== SCTP_DEL_IP_ADDRESS
) {
1038 kprintf("asconf_queue_add: inserted asconf DEL_IP_ADDRESS: %s\n", buf
);
1040 kprintf("asconf_queue_add: inserted asconf SET_PRIM_ADDR: %s\n", buf
);
1043 #endif /* SCTP_DEBUG */
1050 * add an asconf add/delete IP address parameter to the queue by addr
1051 * type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR
1052 * returns 0 if completed, non-zero if not completed
1053 * NOTE: if adding, but delete already scheduled (and not yet
1054 * sent out), simply remove from queue. Same for deleting
1055 * an address already scheduled for add. If a duplicate
1056 * operation is found, ignore the new one.
1059 sctp_asconf_queue_add_sa(struct sctp_tcb
*stcb
, struct sockaddr
*sa
,
1062 struct sctp_asconf_addr
*aa
, *aa_next
;
1064 /* see if peer supports ASCONF */
1065 if (stcb
->asoc
.peer_supports_asconf
== 0) {
1067 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1068 kprintf("asconf_queue_add_sa: peer doesn't support ASCONF\n");
1070 #endif /* SCTP_DEBUG */
1074 /* make sure the request isn't already in the queue */
1075 for (aa
= TAILQ_FIRST(&stcb
->asoc
.asconf_queue
); aa
!= NULL
;
1077 aa_next
= TAILQ_NEXT(aa
, next
);
1078 /* address match? */
1079 if (sctp_asconf_addr_match(aa
, sa
) == 0)
1081 /* is the request already in queue (sent or not) */
1082 if (aa
->ap
.aph
.ph
.param_type
== type
) {
1084 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1085 kprintf("asconf_queue_add_sa: request already exists\n");
1087 #endif /* SCTP_DEBUG */
1091 /* is the negative request already in queue, and not sent */
1094 if (type
== SCTP_ADD_IP_ADDRESS
&&
1095 aa
->ap
.aph
.ph
.param_type
== SCTP_DEL_IP_ADDRESS
) {
1096 /* add requested, delete already queued */
1098 /* delete the existing entry in the queue */
1099 TAILQ_REMOVE(&stcb
->asoc
.asconf_queue
, aa
, next
);
1100 /* free the entry */
1103 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1104 kprintf("asconf_queue_add_sa: removing queued delete request\n");
1106 #endif /* SCTP_DEBUG */
1108 } else if (type
== SCTP_DEL_IP_ADDRESS
&&
1109 aa
->ap
.aph
.ph
.param_type
== SCTP_ADD_IP_ADDRESS
) {
1110 /* delete requested, add already queued */
1112 /* delete the existing entry in the queue */
1113 TAILQ_REMOVE(&stcb
->asoc
.asconf_queue
, aa
, next
);
1114 /* take the entry off the appropriate list */
1115 sctp_asconf_addr_mgmt_ack(stcb
, aa
->ifa
, type
, 1);
1116 /* free the entry */
1119 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1120 kprintf("asconf_queue_add_sa: removing queued add request\n");
1122 #endif /* SCTP_DEBUG */
1127 /* adding new request to the queue */
1128 MALLOC(aa
, struct sctp_asconf_addr
*, sizeof(*aa
), M_PCB
, M_NOWAIT
);
1130 /* didn't get memory */
1132 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1133 kprintf("asconf_queue_add_sa: failed to get memory!\n");
1135 #endif /* SCTP_DEBUG */
1138 /* fill in asconf address parameter fields */
1139 /* top level elements are "networked" during send */
1140 aa
->ap
.aph
.ph
.param_type
= type
;
1141 aa
->ifa
= sctp_find_ifa_by_addr(sa
);
1142 /* correlation_id filled in during send routine later... */
1143 if (sa
->sa_family
== AF_INET6
) {
1145 struct sockaddr_in6
*sin6
;
1147 sin6
= (struct sockaddr_in6
*)sa
;
1148 aa
->ap
.addrp
.ph
.param_type
= SCTP_IPV6_ADDRESS
;
1149 aa
->ap
.addrp
.ph
.param_length
= (sizeof(struct sctp_ipv6addr_param
));
1150 aa
->ap
.aph
.ph
.param_length
= sizeof(struct sctp_asconf_paramhdr
) + sizeof(struct sctp_ipv6addr_param
);
1151 memcpy(&aa
->ap
.addrp
.addr
, &sin6
->sin6_addr
,
1152 sizeof(struct in6_addr
));
1153 } else if (sa
->sa_family
== AF_INET
) {
1155 struct sockaddr_in
*sin
= (struct sockaddr_in
*)sa
;
1156 aa
->ap
.addrp
.ph
.param_type
= SCTP_IPV4_ADDRESS
;
1157 aa
->ap
.addrp
.ph
.param_length
= (sizeof(struct sctp_ipv4addr_param
));
1158 aa
->ap
.aph
.ph
.param_length
= sizeof(struct sctp_asconf_paramhdr
) + sizeof(struct sctp_ipv4addr_param
);
1159 memcpy(&aa
->ap
.addrp
.addr
, &sin
->sin_addr
,
1160 sizeof(struct in_addr
));
1162 /* invalid family! */
1165 aa
->sent
= 0; /* clear sent flag */
1168 * if we are deleting an address it should go out last
1169 * otherwise, add it to front of the pending queue
1171 if (type
== SCTP_ADD_IP_ADDRESS
) {
1172 /* add goes to the front of the queue */
1173 TAILQ_INSERT_HEAD(&stcb
->asoc
.asconf_queue
, aa
, next
);
1175 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1176 kprintf("asconf_queue_add_sa: appended asconf ADD_IP_ADDRESS\n");
1178 #endif /* SCTP_DEBUG */
1180 /* delete and set primary goes to the back of the queue */
1181 TAILQ_INSERT_TAIL(&stcb
->asoc
.asconf_queue
, aa
, next
);
1183 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1184 if (type
== SCTP_DEL_IP_ADDRESS
) {
1185 kprintf("asconf_queue_add_sa: inserted asconf DEL_IP_ADDRESS\n");
1187 kprintf("asconf_queue_add_sa: inserted asconf SET_PRIM_ADDR\n");
1190 #endif /* SCTP_DEBUG */
1197 * find a specific asconf param on our "sent" queue
1199 static struct sctp_asconf_addr
*
1200 sctp_asconf_find_param(struct sctp_tcb
*stcb
, uint32_t correlation_id
)
1202 struct sctp_asconf_addr
*aa
;
1204 TAILQ_FOREACH(aa
, &stcb
->asoc
.asconf_queue
, next
) {
1205 if (aa
->ap
.aph
.correlation_id
== correlation_id
&&
1211 /* didn't find it */
1216 * process an SCTP_ERROR_CAUSE_IND for a ASCONF-ACK parameter
1217 * and do notifications based on the error response
1220 sctp_asconf_process_error(struct sctp_tcb
*stcb
,
1221 struct sctp_asconf_paramhdr
*aph
)
1223 struct sctp_error_cause
*eh
;
1224 struct sctp_paramhdr
*ph
;
1225 uint16_t param_type
;
1226 uint16_t error_code
;
1228 eh
= (struct sctp_error_cause
*)(aph
+ 1);
1229 ph
= (struct sctp_paramhdr
*)(eh
+ 1);
1230 /* validate lengths */
1231 if (htons(eh
->length
) + sizeof(struct sctp_error_cause
) >
1232 htons(aph
->ph
.param_length
)) {
1233 /* invalid error cause length */
1235 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1236 kprintf("asconf_process_error: cause element too long\n");
1238 #endif /* SCTP_DEBUG */
1241 if (htons(ph
->param_length
) + sizeof(struct sctp_paramhdr
) >
1242 htons(eh
->length
)) {
1243 /* invalid included TLV length */
1245 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1246 kprintf("asconf_process_error: included TLV too long\n");
1248 #endif /* SCTP_DEBUG */
1252 /* which error code ? */
1253 error_code
= ntohs(eh
->code
);
1254 param_type
= ntohs(aph
->ph
.param_type
);
1255 /* FIX: this should go back up the REMOTE_ERROR ULP notify */
1256 switch (error_code
) {
1257 case SCTP_ERROR_RESOURCE_SHORTAGE
:
1258 /* we allow ourselves to "try again" for this error */
1261 /* peer can't handle it... */
1262 switch (param_type
) {
1263 case SCTP_ADD_IP_ADDRESS
:
1264 case SCTP_DEL_IP_ADDRESS
:
1265 stcb
->asoc
.peer_supports_asconf
= 0;
1267 case SCTP_SET_PRIM_ADDR
:
1268 stcb
->asoc
.peer_supports_asconf_setprim
= 0;
1277 * process an asconf queue param
1278 * aparam: parameter to process, will be removed from the queue
1279 * flag: 1=success, 0=failure
1282 sctp_asconf_process_param_ack(struct sctp_tcb
*stcb
,
1283 struct sctp_asconf_addr
*aparam
, uint32_t flag
)
1285 uint16_t param_type
;
1287 /* process this param */
1288 param_type
= aparam
->ap
.aph
.ph
.param_type
;
1290 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1291 kprintf("process_param_ack: handling asconf parameter type=%xh\n", param_type
);
1293 #endif /* SCTP_DEBUG */
1294 switch (param_type
) {
1295 case SCTP_ADD_IP_ADDRESS
:
1297 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1298 kprintf("process_param_ack: added IP address\n");
1300 #endif /* SCTP_DEBUG */
1301 sctp_asconf_addr_mgmt_ack(stcb
, aparam
->ifa
, param_type
, flag
);
1303 case SCTP_DEL_IP_ADDRESS
:
1305 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1306 kprintf("process_param_ack: deleted IP address\n");
1308 #endif /* SCTP_DEBUG */
1309 /* nothing really to do... lists already updated */
1311 case SCTP_SET_PRIM_ADDR
:
1312 /* nothing to do... peer may start using this addr */
1314 stcb
->asoc
.peer_supports_asconf_setprim
= 0;
1317 /* should NEVER happen */
1321 /* remove the param and free it */
1322 TAILQ_REMOVE(&stcb
->asoc
.asconf_queue
, aparam
, next
);
1323 FREE(aparam
, M_PCB
);
1327 * cleanup from a bad asconf ack parameter
1330 sctp_asconf_ack_clear(struct sctp_tcb
*stcb
)
1332 /* assume peer doesn't really know how to do asconfs */
1333 stcb
->asoc
.peer_supports_asconf
= 0;
1334 stcb
->asoc
.peer_supports_asconf_setprim
= 0;
1335 /* XXX we could free the pending queue here */
1339 sctp_handle_asconf_ack(struct mbuf
*m
, int offset
,
1340 struct sctp_asconf_ack_chunk
*cp
, struct sctp_tcb
*stcb
,
1341 struct sctp_nets
*net
)
1343 struct sctp_association
*asoc
;
1344 uint32_t serial_num
;
1345 uint16_t ack_length
;
1346 struct sctp_asconf_paramhdr
*aph
;
1347 struct sctp_asconf_addr
*aa
, *aa_next
;
1348 uint32_t last_error_id
= 0; /* last error correlation id */
1350 struct sctp_asconf_addr
*ap
;
1351 /* asconf param buffer */
1352 static u_int8_t aparam_buf
[DEFAULT_PARAM_BUFFER
];
1354 /* verify minimum length */
1355 if (ntohs(cp
->ch
.chunk_length
) < sizeof(struct sctp_asconf_ack_chunk
)) {
1357 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1358 kprintf("handle_asconf_ack: chunk too small = %xh\n",
1359 ntohs(cp
->ch
.chunk_length
));
1361 #endif /* SCTP_DEBUG */
1366 serial_num
= ntohl(cp
->serial_number
);
1369 * NOTE: we may want to handle this differently- currently, we
1370 * will abort when we get an ack for the expected serial number + 1
1371 * (eg. we didn't send it), process an ack normally if it is the
1372 * expected serial number, and re-send the previous ack for *ALL*
1373 * other serial numbers
1377 * if the serial number is the next expected, but I didn't send it,
1378 * abort the asoc, since someone probably just hijacked us...
1380 if (serial_num
== (asoc
->asconf_seq_out
+ 1)) {
1381 sctp_abort_an_association(stcb
->sctp_ep
, stcb
,
1382 SCTP_ERROR_ILLEGAL_ASCONF_ACK
, NULL
);
1384 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1385 kprintf("handle_asconf_ack: got unexpected next serial number! Aborting asoc!\n");
1387 #endif /* SCTP_DEBUG */
1391 if (serial_num
!= asoc
->asconf_seq_out
) {
1392 /* got a duplicate/unexpected ASCONF-ACK */
1394 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1395 kprintf("handle_asconf_ack: got duplicate/unexpected serial number = %xh (expected = %xh)\n", serial_num
, asoc
->asconf_seq_out
);
1397 #endif /* SCTP_DEBUG */
1400 /* stop our timer */
1401 sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF
, stcb
->sctp_ep
, stcb
, net
);
1403 /* process the ASCONF-ACK contents */
1404 ack_length
= ntohs(cp
->ch
.chunk_length
) -
1405 sizeof(struct sctp_asconf_ack_chunk
);
1406 offset
+= sizeof(struct sctp_asconf_ack_chunk
);
1407 /* process through all parameters */
1408 while (ack_length
>= sizeof(struct sctp_asconf_paramhdr
)) {
1409 unsigned int param_length
, param_type
;
1411 /* get pointer to next asconf parameter */
1412 aph
= (struct sctp_asconf_paramhdr
*)sctp_m_getptr(m
, offset
,
1413 sizeof(struct sctp_asconf_paramhdr
), aparam_buf
);
1415 /* can't get an asconf paramhdr */
1416 sctp_asconf_ack_clear(stcb
);
1419 param_type
= ntohs(aph
->ph
.param_type
);
1420 param_length
= ntohs(aph
->ph
.param_length
);
1421 if (param_length
> ack_length
) {
1422 sctp_asconf_ack_clear(stcb
);
1425 if (param_length
< sizeof(struct sctp_paramhdr
)) {
1426 sctp_asconf_ack_clear(stcb
);
1430 /* get the complete parameter... */
1431 if (param_length
> sizeof(aparam_buf
)) {
1433 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1434 kprintf("param length (%u) larger than buffer size!\n", param_length
);
1436 #endif /* SCTP_DEBUG */
1437 sctp_asconf_ack_clear(stcb
);
1440 aph
= (struct sctp_asconf_paramhdr
*)sctp_m_getptr(m
, offset
, param_length
, aparam_buf
);
1442 sctp_asconf_ack_clear(stcb
);
1445 /* correlation_id is transparent to peer, no ntohl needed */
1446 id
= aph
->correlation_id
;
1448 switch (param_type
) {
1449 case SCTP_ERROR_CAUSE_IND
:
1451 /* find the corresponding asconf param in our queue */
1452 ap
= sctp_asconf_find_param(stcb
, id
);
1454 /* hmm... can't find this in our queue! */
1457 /* process the parameter, failed flag */
1458 sctp_asconf_process_param_ack(stcb
, ap
, 0);
1459 /* process the error response */
1460 sctp_asconf_process_error(stcb
, aph
);
1462 case SCTP_SUCCESS_REPORT
:
1463 /* find the corresponding asconf param in our queue */
1464 ap
= sctp_asconf_find_param(stcb
, id
);
1466 /* hmm... can't find this in our queue! */
1469 /* process the parameter, success flag */
1470 sctp_asconf_process_param_ack(stcb
, ap
, 1);
1476 /* update remaining ASCONF-ACK message length to process */
1477 ack_length
-= SCTP_SIZE32(param_length
);
1478 if (ack_length
<= 0) {
1479 /* no more data in the mbuf chain */
1482 offset
+= SCTP_SIZE32(param_length
);
1486 * if there are any "sent" params still on the queue, these are
1487 * implicitly "success", or "failed" (if we got an error back)
1488 * ... so process these appropriately
1490 * we assume that the correlation_id's are monotonically increasing
1491 * beginning from 1 and that we don't have *that* many outstanding
1494 if (last_error_id
== 0)
1495 last_error_id
--; /* set to "max" value */
1496 for (aa
= TAILQ_FIRST(&stcb
->asoc
.asconf_queue
); aa
!= NULL
;
1498 aa_next
= TAILQ_NEXT(aa
, next
);
1499 if (aa
->sent
== 1) {
1501 * implicitly successful or failed
1502 * if correlation_id < last_error_id, then success
1505 if (aa
->ap
.aph
.correlation_id
< last_error_id
)
1506 sctp_asconf_process_param_ack(stcb
, aa
,
1507 SCTP_SUCCESS_REPORT
);
1509 sctp_asconf_process_param_ack(stcb
, aa
,
1510 SCTP_ERROR_CAUSE_IND
);
1513 * since we always process in order (FIFO queue)
1514 * if we reach one that hasn't been sent, the
1515 * rest should not have been sent either.
1522 /* update the next sequence number to use */
1523 asoc
->asconf_seq_out
++;
1524 /* remove the old ASCONF on our outbound queue */
1525 sctp_toss_old_asconf(stcb
);
1526 /* clear the sent flag to allow new ASCONFs */
1527 asoc
->asconf_sent
= 0;
1528 if (!TAILQ_EMPTY(&stcb
->asoc
.asconf_queue
)) {
1529 /* we have more params, so restart our timer */
1530 sctp_timer_start(SCTP_TIMER_TYPE_ASCONF
, stcb
->sctp_ep
,
1535 /* is this an interface that we care about at all? */
1537 sctp_is_desired_interface_type(struct ifaddr
*ifa
)
1541 /* check the interface type to see if it's one we care about */
1542 switch (ifa
->ifa_ifp
->if_type
) {
1557 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1558 kprintf("ignoring interface type = %u\n",
1559 ifa
->ifa_ifp
->if_type
);
1561 #endif /* SCTP_DEBUG */
1569 sctp_is_scopeid_in_nets(struct sctp_tcb
*stcb
, struct sockaddr
*sa
)
1571 struct sockaddr_in6
*sin6
, *net6
;
1572 struct sctp_nets
*net
;
1574 if (sa
->sa_family
!= AF_INET6
) {
1579 sin6
= (struct sockaddr_in6
*)sa
;
1580 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
) == 0) {
1581 /* not link local address */
1585 /* hunt through our destination nets list for this scope_id */
1586 TAILQ_FOREACH(net
, &stcb
->asoc
.nets
, sctp_next
) {
1587 if (((struct sockaddr
*)(&net
->ro
._l_addr
))->sa_family
!=
1590 net6
= (struct sockaddr_in6
*)&net
->ro
._l_addr
;
1591 if (IN6_IS_ADDR_LINKLOCAL(&net6
->sin6_addr
) == 0)
1593 if (sctp_is_same_scope(sin6
, net6
)) {
1598 /* didn't find one */
1603 * address management functions
1606 sctp_addr_mgmt_assoc(struct sctp_inpcb
*inp
, struct sctp_tcb
*stcb
,
1607 struct ifaddr
*ifa
, uint16_t type
)
1611 char buf
[128]; /* for address in string format */
1612 #endif /* SCTP_DEBUG */
1614 if ((inp
->sctp_flags
& SCTP_PCB_FLAGS_BOUNDALL
) == 0 &&
1615 (inp
->sctp_flags
& SCTP_PCB_FLAGS_DO_ASCONF
) == 0) {
1616 /* subset bound, no ASCONF allowed case, so ignore */
1621 * note: we know this is not the subset bound, no ASCONF case
1622 * eg. this is boundall or subset bound w/ASCONF allowed
1625 /* first, make sure it's a good address family */
1626 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
&&
1627 ifa
->ifa_addr
->sa_family
!= AF_INET
) {
1631 /* make sure we're "allowed" to add this type of addr */
1632 if (ifa
->ifa_addr
->sa_family
== AF_INET6
) {
1633 struct in6_ifaddr
*ifa6
;
1635 /* invalid if we're not a v6 endpoint */
1636 if ((inp
->sctp_flags
& SCTP_PCB_FLAGS_BOUND_V6
) == 0)
1638 /* is the v6 addr really valid ? */
1639 ifa6
= (struct in6_ifaddr
*)ifa
;
1640 if (IFA6_IS_DEPRECATED(ifa6
) ||
1642 (IN6_IFF_DETACHED
| IN6_IFF_ANYCAST
| IN6_IFF_NOTREADY
))) {
1643 /* can't use an invalid address */
1648 /* put this address on the "pending/do not use yet" list */
1650 * Note: we do this primarily for the subset bind case
1651 * We don't have scoping flags at the EP level, so we must
1652 * add link local/site local addresses to the EP, then need
1653 * to "negate" them here. Recall that this routine is only
1654 * called for the subset bound w/ASCONF allowed case.
1658 * do a scope_id check against any link local addresses
1659 * in the destination nets list to see if we should put
1660 * this local address on the pending list or not
1661 * eg. don't put on the list if we have a link local
1662 * destination with the same scope_id
1664 if (type
== SCTP_ADD_IP_ADDRESS
) {
1665 if (sctp_is_scopeid_in_nets(stcb
, ifa
->ifa_addr
) == 0) {
1666 sctp_add_local_addr_assoc(stcb
, ifa
);
1668 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1669 kprintf("addr_mgmt_assoc: added to pending list ");
1670 sctp_print_address(ifa
->ifa_addr
);
1672 #endif /* SCTP_DEBUG */
1676 * check address scope
1677 * if address is out of scope, don't queue anything...
1678 * note: this would leave the address on both inp and asoc lists
1680 if (ifa
->ifa_addr
->sa_family
== AF_INET6
) {
1681 struct sockaddr_in6
*sin6
;
1683 sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
1685 strlcpy(buf
, ip6_sprintf(&sin6
->sin6_addr
), sizeof(buf
));
1686 #endif /* SCTP_DEBUG */
1687 if (IN6_IS_ADDR_UNSPECIFIED(&sin6
->sin6_addr
)) {
1688 /* we skip unspecifed addresses */
1690 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1691 kprintf("addr_mgmt_assoc: unspecified IPv6 addr\n");
1693 #endif /* SCTP_DEBUG */
1696 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
)) {
1697 if (stcb
->asoc
.local_scope
== 0) {
1699 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1700 kprintf("addr_mgmt_assoc: skipping link local IPv6 addr: %s\n", buf
);
1702 #endif /* SCTP_DEBUG */
1705 /* is it the right link local scope? */
1706 if (sctp_is_scopeid_in_nets(stcb
, ifa
->ifa_addr
) == 0) {
1708 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1709 kprintf("addr_mgmt_assoc: skipping link local IPv6 addr: %s, wrong scope_id\n", buf
);
1711 #endif /* SCTP_DEBUG */
1715 if (stcb
->asoc
.site_scope
== 0 &&
1716 IN6_IS_ADDR_SITELOCAL(&sin6
->sin6_addr
)) {
1718 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1719 kprintf("addr_mgmt_assoc: skipping site local IPv6 addr: %s\n", buf
);
1721 #endif /* SCTP_DEBUG */
1724 } else if (ifa
->ifa_addr
->sa_family
== AF_INET
) {
1725 struct sockaddr_in
*sin
;
1726 struct in6pcb
*inp6
;
1728 inp6
= (struct in6pcb
*)&inp
->ip_inp
.inp
;
1729 /* invalid if we are a v6 only endpoint */
1730 if ((inp
->sctp_flags
& SCTP_PCB_FLAGS_BOUND_V6
) &&
1731 #if defined(__OpenBSD__)
1732 (0) /* we always do dual bind */
1733 #elif defined (__NetBSD__)
1734 (inp6
->in6p_flags
& IN6P_IPV6_V6ONLY
)
1736 (inp6
->inp_flags
& IN6P_IPV6_V6ONLY
)
1741 sin
= (struct sockaddr_in
*)ifa
->ifa_addr
;
1743 strlcpy(buf
, inet_ntoa(sin
->sin_addr
), sizeof(buf
));
1744 #endif /* SCTP_DEBUG */
1745 if (sin
->sin_addr
.s_addr
== 0) {
1746 /* we skip unspecifed addresses */
1748 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1749 kprintf("addr_mgmt_assoc: unspecified IPv4 addr\n");
1751 #endif /* SCTP_DEBUG */
1754 if (stcb
->asoc
.ipv4_local_scope
== 0 &&
1755 IN4_ISPRIVATE_ADDRESS(&sin
->sin_addr
)) {
1757 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1758 kprintf("addr_mgmt_assoc: skipping private IPv4 addr: %s\n", buf
);
1760 #endif /* SCTP_DEBUG */
1764 /* else, not AF_INET or AF_INET6, so skip */
1766 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1767 kprintf("addr_mgmt_assoc: not AF_INET or AF_INET6\n");
1769 #endif /* SCTP_DEBUG */
1773 /* queue an asconf for this address add/delete */
1774 if (inp
->sctp_flags
& SCTP_PCB_FLAGS_DO_ASCONF
) {
1775 /* does the peer do asconf? */
1776 if (stcb
->asoc
.peer_supports_asconf
) {
1777 /* queue an asconf for this addr */
1778 status
= sctp_asconf_queue_add(stcb
, ifa
, type
);
1780 * if queued ok, and in correct state, set the
1782 * if in non-open state, we will set this timer
1783 * when the state does go open and do all the
1787 SCTP_GET_STATE(&stcb
->asoc
) == SCTP_STATE_OPEN
) {
1788 sctp_timer_start(SCTP_TIMER_TYPE_ASCONF
, inp
,
1789 stcb
, stcb
->asoc
.primary_destination
);
1793 /* this is the boundall, no ASCONF case */
1794 #if 0 /* assume kernel will delete this very shortly; add done above */
1795 if (type
== SCTP_DEL_IP_ADDRESS
) {
1796 /* if deleting, add this addr to the do not use list */
1797 sctp_add_local_addr_assoc(stcb
, ifa
);
1804 sctp_addr_mgmt_ep(struct sctp_inpcb
*inp
, struct ifaddr
*ifa
, uint16_t type
)
1806 struct sctp_tcb
*stcb
;
1808 SCTP_INP_WLOCK(inp
);
1809 /* make sure we're "allowed" to add this type of addr */
1810 if (ifa
->ifa_addr
->sa_family
== AF_INET6
) {
1811 struct in6_ifaddr
*ifa6
;
1813 /* invalid if we're not a v6 endpoint */
1814 if ((inp
->sctp_flags
& SCTP_PCB_FLAGS_BOUND_V6
) == 0) {
1815 SCTP_INP_WUNLOCK(inp
);
1818 /* is the v6 addr really valid ? */
1819 ifa6
= (struct in6_ifaddr
*)ifa
;
1820 if (IFA6_IS_DEPRECATED(ifa6
) ||
1822 (IN6_IFF_DETACHED
| IN6_IFF_ANYCAST
| IN6_IFF_NOTREADY
))) {
1823 /* can't use an invalid address */
1824 SCTP_INP_WUNLOCK(inp
);
1827 } else if (ifa
->ifa_addr
->sa_family
== AF_INET
) {
1828 /* invalid if we are a v6 only endpoint */
1829 struct in6pcb
*inp6
;
1830 inp6
= (struct in6pcb
*)&inp
->ip_inp
.inp
;
1832 if ((inp
->sctp_flags
& SCTP_PCB_FLAGS_BOUND_V6
) &&
1833 #if defined(__OpenBSD__)
1834 (0) /* we always do dual bind */
1835 #elif defined (__NetBSD__)
1836 (inp6
->in6p_flags
& IN6P_IPV6_V6ONLY
)
1838 (inp6
->inp_flags
& IN6P_IPV6_V6ONLY
)
1841 SCTP_INP_WUNLOCK(inp
);
1845 /* invalid address family */
1846 SCTP_INP_WUNLOCK(inp
);
1849 /* is this endpoint subset bound ? */
1850 if ((inp
->sctp_flags
& SCTP_PCB_FLAGS_BOUNDALL
) == 0) {
1851 /* subset bound endpoint */
1852 if ((inp
->sctp_flags
& SCTP_PCB_FLAGS_DO_ASCONF
) == 0) {
1854 * subset bound, but ASCONFs not allowed...
1855 * if adding, nothing to do, since not allowed
1856 * if deleting, remove address from endpoint
1857 * peer will have to "timeout" this addr
1859 if (type
== SCTP_DEL_IP_ADDRESS
) {
1860 sctp_del_local_addr_ep(inp
, ifa
);
1862 /* no asconfs to queue for this inp... */
1863 SCTP_INP_WUNLOCK(inp
);
1867 * subset bound, ASCONFs allowed...
1868 * if adding, add address to endpoint list
1869 * if deleting, remove address from endpoint
1871 if (type
== SCTP_ADD_IP_ADDRESS
) {
1872 sctp_add_local_addr_ep(inp
, ifa
);
1874 sctp_del_local_addr_ep(inp
, ifa
);
1876 /* drop through and notify all asocs */
1881 /* process for all associations for this endpoint */
1882 LIST_FOREACH(stcb
, &inp
->sctp_asoc_list
, sctp_tcblist
) {
1883 SCTP_TCB_LOCK(stcb
);
1884 sctp_addr_mgmt_assoc(inp
, stcb
, ifa
, type
);
1885 SCTP_TCB_UNLOCK(stcb
);
1886 } /* for each stcb */
1888 SCTP_INP_WUNLOCK(inp
);
1892 * restrict the use of this address
1895 sctp_addr_mgmt_restrict_ep(struct sctp_inpcb
*inp
, struct ifaddr
*ifa
)
1897 struct sctp_tcb
*stcb
;
1899 /* is this endpoint bound to all? */
1900 if ((inp
->sctp_flags
& SCTP_PCB_FLAGS_BOUNDALL
) == 0) {
1902 * Nothing to do for subset bound case.
1903 * Allow sctp_bindx() to manage the address lists
1909 SCTP_INP_RLOCK(inp
);
1910 /* process for all associations for this endpoint */
1911 LIST_FOREACH(stcb
, &inp
->sctp_asoc_list
, sctp_tcblist
) {
1912 /* put this address on the "pending/do not use yet" list */
1913 SCTP_TCB_LOCK(stcb
);
1914 sctp_add_local_addr_assoc(stcb
, ifa
);
1915 SCTP_TCB_UNLOCK(stcb
);
1917 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1918 kprintf("restrict_ep: added addr to unusable list\n");
1920 #endif /* SCTP_DEBUG */
1921 } /* for each stcb */
1923 SCTP_INP_RUNLOCK(inp
);
1927 * this is only called for kernel initiated address changes
1928 * eg. it will check the PCB_FLAGS_AUTO_ASCONF flag
1931 sctp_addr_mgmt(struct ifaddr
*ifa
, uint16_t type
) {
1932 struct sockaddr
*sa
;
1933 struct sctp_inpcb
*inp
;
1935 /* make sure we care about this interface... */
1936 if (!sctp_is_desired_interface_type(ifa
)) {
1938 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1939 kprintf("sctp_addr_mgmt: ignoring this interface\n");
1941 #endif /* SCTP_DEBUG */
1946 if (sa
->sa_family
!= AF_INET
&& sa
->sa_family
!= AF_INET6
)
1950 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
1951 if (type
== SCTP_ADD_IP_ADDRESS
)
1952 kprintf("sctp_addr_mgmt: kernel adds ");
1954 kprintf("sctp_addr_mgmt: kernel deletes ");
1955 sctp_print_address(sa
);
1957 #endif /* SCTP_DEBUG */
1959 /* go through all our PCB's */
1960 LIST_FOREACH(inp
, &sctppcbinfo
.listhead
, sctp_list
) {
1961 if (inp
->sctp_flags
& SCTP_PCB_FLAGS_AUTO_ASCONF
) {
1962 sctp_addr_mgmt_ep(inp
, ifa
, type
);
1964 /* this address is going away anyways... */
1965 if (type
== SCTP_DEL_IP_ADDRESS
)
1967 /* (temporarily) restrict this address */
1968 sctp_addr_mgmt_restrict_ep(inp
, ifa
);
1970 /* else, not allowing automatic asconf's, so ignore */
1971 } /* for each inp */
1975 * add/delete IP address requests from kernel (via routing change)
1976 * assumed that the address is non-broadcast, non-multicast
1977 * all addresses are passed from any type of interface-- need to filter
1978 * duplicate addresses may get requested
1982 sctp_add_ip_address(struct ifaddr
*ifa
)
1984 sctp_addr_mgmt(ifa
, SCTP_ADD_IP_ADDRESS
);
1988 sctp_delete_ip_address(struct ifaddr
*ifa
)
1990 struct sctp_inpcb
*inp
;
1992 /* process the delete */
1993 sctp_addr_mgmt(ifa
, SCTP_DEL_IP_ADDRESS
);
1996 * need to remove this ifaddr from any cached routes
1997 * and also any from any assoc "restricted/pending" lists
1999 /* make sure we care about this interface... */
2000 if (!sctp_is_desired_interface_type(ifa
)) {
2002 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
2003 kprintf("sctp_delete_ip_address: ignoring this interface\n");
2005 #endif /* SCTP_DEBUG */
2009 /* go through all our PCB's */
2010 SCTP_INP_INFO_RLOCK();
2011 LIST_FOREACH(inp
, &sctppcbinfo
.listhead
, sctp_list
) {
2012 struct sctp_tcb
*stcb
;
2013 struct sctp_laddr
*laddr
, *laddr_next
;
2015 /* process for all associations for this endpoint */
2016 SCTP_INP_RLOCK(inp
);
2017 LIST_FOREACH(stcb
, &inp
->sctp_asoc_list
, sctp_tcblist
) {
2018 struct sctp_nets
*net
;
2020 /* process through the nets list */
2021 TAILQ_FOREACH(net
, &stcb
->asoc
.nets
, sctp_next
) {
2023 /* delete this address if cached */
2025 if (rt
!= NULL
&& rt
->rt_ifa
== ifa
) {
2027 net
->ro
.ro_rt
= NULL
;
2029 } /* for each net */
2030 /* process through the asoc "pending" list */
2031 laddr
= LIST_FIRST(&stcb
->asoc
.sctp_local_addr_list
);
2032 while (laddr
!= NULL
) {
2033 laddr_next
= LIST_NEXT(laddr
, sctp_nxt_addr
);
2034 /* remove if in use */
2035 if (laddr
->ifa
== ifa
) {
2036 sctp_remove_laddr(laddr
);
2040 } /* for each stcb */
2041 /* process through the inp bound addr list */
2042 laddr
= LIST_FIRST(&inp
->sctp_addr_list
);
2043 while (laddr
!= NULL
) {
2044 laddr_next
= LIST_NEXT(laddr
, sctp_nxt_addr
);
2045 /* remove if in use */
2046 if (laddr
->ifa
== ifa
) {
2047 sctp_remove_laddr(laddr
);
2051 SCTP_INP_RUNLOCK(inp
);
2052 } /* for each inp */
2053 SCTP_INP_INFO_RUNLOCK();
2057 * sa is the sockaddr to ask the peer to set primary to
2058 * returns: 0 = completed, -1 = error
2061 sctp_set_primary_ip_address_sa(struct sctp_tcb
*stcb
, struct sockaddr
*sa
)
2063 /* NOTE: we currently don't check the validity of the address! */
2065 /* queue an ASCONF:SET_PRIM_ADDR to be sent */
2066 if (!sctp_asconf_queue_add_sa(stcb
, sa
, SCTP_SET_PRIM_ADDR
)) {
2067 /* set primary queuing succeeded */
2068 if (SCTP_GET_STATE(&stcb
->asoc
) == SCTP_STATE_OPEN
) {
2069 sctp_timer_start(SCTP_TIMER_TYPE_ASCONF
,
2070 stcb
->sctp_ep
, stcb
,
2071 stcb
->asoc
.primary_destination
);
2074 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
2075 kprintf("set_primary_ip_address_sa: queued on tcb=%p, ",
2077 sctp_print_address(sa
);
2079 #endif /* SCTP_DEBUG */
2082 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
2083 kprintf("set_primary_ip_address_sa: failed to add to queue on tcb=%p, ",
2085 sctp_print_address(sa
);
2087 #endif /* SCTP_DEBUG */
2094 sctp_set_primary_ip_address(struct ifaddr
*ifa
)
2096 struct sctp_inpcb
*inp
;
2098 /* make sure we care about this interface... */
2099 if (!sctp_is_desired_interface_type(ifa
)) {
2101 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
2102 kprintf("set_primary_ip_address: ignoring this interface\n");
2104 #endif /* SCTP_DEBUG */
2108 /* go through all our PCB's */
2109 LIST_FOREACH(inp
, &sctppcbinfo
.listhead
, sctp_list
) {
2110 struct sctp_tcb
*stcb
;
2112 /* process for all associations for this endpoint */
2113 LIST_FOREACH(stcb
, &inp
->sctp_asoc_list
, sctp_tcblist
) {
2114 /* queue an ASCONF:SET_PRIM_ADDR to be sent */
2115 if (!sctp_asconf_queue_add(stcb
, ifa
,
2116 SCTP_SET_PRIM_ADDR
)) {
2117 /* set primary queuing succeeded */
2118 if (SCTP_GET_STATE(&stcb
->asoc
) ==
2120 sctp_timer_start(SCTP_TIMER_TYPE_ASCONF
,
2121 stcb
->sctp_ep
, stcb
,
2122 stcb
->asoc
.primary_destination
);
2125 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
2126 kprintf("set_primary_ip_address: queued on stcb=%p, ",
2128 sctp_print_address(ifa
->ifa_addr
);
2130 #endif /* SCTP_DEBUG */
2133 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
2134 kprintf("set_primary_ip_address: failed to add to queue, ");
2135 sctp_print_address(ifa
->ifa_addr
);
2137 #endif /* SCTP_DEBUG */
2139 } /* for each stcb */
2140 } /* for each inp */
2143 static struct sockaddr
*
2144 sctp_find_valid_localaddr(struct sctp_tcb
*stcb
)
2149 TAILQ_FOREACH(ifn
, &ifnet
, if_list
) {
2150 if (stcb
->asoc
.loopback_scope
== 0 && ifn
->if_type
== IFT_LOOP
) {
2151 /* Skip if loopback_scope not set */
2154 TAILQ_FOREACH(ifa
, &ifn
->if_addrlist
, ifa_list
) {
2155 if (ifa
->ifa_addr
->sa_family
== AF_INET
&&
2156 stcb
->asoc
.ipv4_addr_legal
) {
2157 struct sockaddr_in
*sin
;
2159 sin
= (struct sockaddr_in
*)ifa
->ifa_addr
;
2160 if (sin
->sin_addr
.s_addr
== 0) {
2161 /* skip unspecifed addresses */
2164 if (stcb
->asoc
.ipv4_local_scope
== 0 &&
2165 IN4_ISPRIVATE_ADDRESS(&sin
->sin_addr
))
2168 if (sctp_is_addr_restricted(stcb
,
2171 /* found a valid local v4 address to use */
2172 return (ifa
->ifa_addr
);
2173 } else if (ifa
->ifa_addr
->sa_family
== AF_INET6
&&
2174 stcb
->asoc
.ipv6_addr_legal
) {
2175 struct sockaddr_in6
*sin6
;
2176 struct in6_ifaddr
*ifa6
;
2178 ifa6
= (struct in6_ifaddr
*)ifa
;
2179 if (IFA6_IS_DEPRECATED(ifa6
) ||
2180 (ifa6
->ia6_flags
& (IN6_IFF_DETACHED
|
2181 IN6_IFF_ANYCAST
| IN6_IFF_NOTREADY
)))
2184 sin6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
2185 if (IN6_IS_ADDR_UNSPECIFIED(&sin6
->sin6_addr
)) {
2186 /* we skip unspecifed addresses */
2189 if (stcb
->asoc
.local_scope
== 0 &&
2190 IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
))
2192 if (stcb
->asoc
.site_scope
== 0 &&
2193 IN6_IS_ADDR_SITELOCAL(&sin6
->sin6_addr
))
2196 /* found a valid local v6 address to use */
2197 return (ifa
->ifa_addr
);
2201 /* no valid addresses found */
2205 static struct sockaddr
*
2206 sctp_find_valid_localaddr_ep(struct sctp_tcb
*stcb
)
2208 struct sctp_laddr
*laddr
;
2210 LIST_FOREACH(laddr
, &stcb
->sctp_ep
->sctp_addr_list
, sctp_nxt_addr
) {
2211 if (laddr
->ifa
== NULL
) {
2213 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
2214 kprintf("find_valid_localaddr_ep: laddr error\n");
2216 #endif /* SCTP_DEBUG */
2219 if (laddr
->ifa
->ifa_addr
== NULL
) {
2221 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
2222 kprintf("find_valid_localaddr_ep: laddr->ifa error\n");
2224 #endif /* SCTP_DEBUG */
2227 /* is the address restricted ? */
2228 if (sctp_is_addr_restricted(stcb
, laddr
->ifa
->ifa_addr
))
2231 /* found a valid local address to use */
2232 return (laddr
->ifa
->ifa_addr
);
2234 /* no valid addresses found */
2239 * builds an ASCONF chunk from queued ASCONF params
2240 * returns NULL on error (no mbuf, no ASCONF params queued, etc)
2243 sctp_compose_asconf(struct sctp_tcb
*stcb
)
2245 struct mbuf
*m_asconf
, *m_asconf_chk
;
2246 struct sctp_asconf_addr
*aa
;
2247 struct sctp_asconf_chunk
*acp
;
2248 struct sctp_asconf_paramhdr
*aph
;
2249 struct sctp_asconf_addr_param
*aap
;
2251 uint32_t correlation_id
= 1; /* 0 is reserved... */
2252 caddr_t ptr
, lookup_ptr
;
2253 uint8_t lookup_used
= 0;
2255 /* are there any asconf params to send? */
2256 if (TAILQ_EMPTY(&stcb
->asoc
.asconf_queue
)) {
2261 * get a chunk header mbuf and a cluster for the asconf params
2262 * since it's simpler to fill in the asconf chunk header lookup
2263 * address on the fly
2265 m_asconf_chk
= NULL
;
2266 MGETHDR(m_asconf_chk
, MB_DONTWAIT
, MT_DATA
);
2267 if (m_asconf_chk
== NULL
) {
2270 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
)
2271 kprintf("compose_asconf: couldn't get chunk mbuf!\n");
2272 #endif /* SCTP_DEBUG */
2276 MGETHDR(m_asconf
, MB_DONTWAIT
, MT_HEADER
);
2277 if (m_asconf
== NULL
) {
2280 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
)
2281 kprintf("compose_asconf: couldn't get mbuf!\n");
2282 #endif /* SCTP_DEBUG */
2283 sctp_m_freem(m_asconf_chk
);
2286 MCLGET(m_asconf
, MB_DONTWAIT
);
2287 if ((m_asconf
->m_flags
& M_EXT
) != M_EXT
) {
2288 /* failed to get cluster buffer */
2290 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
)
2291 kprintf("compose_asconf: couldn't get cluster!\n");
2292 #endif /* SCTP_DEBUG */
2293 sctp_m_freem(m_asconf_chk
);
2294 sctp_m_freem(m_asconf
);
2298 m_asconf_chk
->m_len
= sizeof(struct sctp_asconf_chunk
);
2299 m_asconf
->m_len
= 0;
2300 acp
= mtod(m_asconf_chk
, struct sctp_asconf_chunk
*);
2301 bzero(acp
, sizeof(struct sctp_asconf_chunk
));
2302 /* save pointers to lookup address and asconf params */
2303 lookup_ptr
= (caddr_t
)(acp
+ 1); /* after the header */
2304 ptr
= mtod(m_asconf
, caddr_t
); /* beginning of cluster */
2306 /* fill in chunk header info */
2307 acp
->ch
.chunk_type
= SCTP_ASCONF
;
2308 acp
->ch
.chunk_flags
= 0;
2309 acp
->serial_number
= htonl(stcb
->asoc
.asconf_seq_out
);
2311 /* add parameters... up to smallest MTU allowed */
2312 TAILQ_FOREACH(aa
, &stcb
->asoc
.asconf_queue
, next
) {
2313 /* get the parameter length */
2314 p_length
= SCTP_SIZE32(aa
->ap
.aph
.ph
.param_length
);
2315 /* will it fit in current chunk? */
2316 if (m_asconf
->m_len
+ p_length
> stcb
->asoc
.smallest_mtu
) {
2317 /* won't fit, so we're done with this chunk */
2320 /* assign (and store) a correlation id */
2321 aa
->ap
.aph
.correlation_id
= correlation_id
++;
2324 * fill in address if we're doing a delete
2325 * this is a simple way for us to fill in the correlation
2326 * address, which should only be used by the peer if we're
2327 * deleting our source address and adding a new address
2328 * (e.g. renumbering case)
2330 if (lookup_used
== 0 &&
2331 aa
->ap
.aph
.ph
.param_type
== SCTP_DEL_IP_ADDRESS
) {
2332 struct sctp_ipv6addr_param
*lookup
;
2333 uint16_t p_size
, addr_size
;
2335 lookup
= (struct sctp_ipv6addr_param
*)lookup_ptr
;
2336 lookup
->ph
.param_type
=
2337 htons(aa
->ap
.addrp
.ph
.param_type
);
2338 if (aa
->ap
.addrp
.ph
.param_type
== SCTP_IPV6_ADDRESS
) {
2339 /* copy IPv6 address */
2340 p_size
= sizeof(struct sctp_ipv6addr_param
);
2341 addr_size
= sizeof(struct in6_addr
);
2343 /* copy IPv4 address */
2344 p_size
= sizeof(struct sctp_ipv4addr_param
);
2345 addr_size
= sizeof(struct in_addr
);
2347 lookup
->ph
.param_length
= htons(SCTP_SIZE32(p_size
));
2348 memcpy(lookup
->addr
, &aa
->ap
.addrp
.addr
, addr_size
);
2349 m_asconf_chk
->m_len
+= SCTP_SIZE32(p_size
);
2353 /* copy into current space */
2354 memcpy(ptr
, &aa
->ap
, p_length
);
2356 /* network elements and update lengths */
2357 aph
= (struct sctp_asconf_paramhdr
*) ptr
;
2358 aap
= (struct sctp_asconf_addr_param
*) ptr
;
2359 /* correlation_id is transparent to peer, no htonl needed */
2360 aph
->ph
.param_type
= htons(aph
->ph
.param_type
);
2361 aph
->ph
.param_length
= htons(aph
->ph
.param_length
);
2362 aap
->addrp
.ph
.param_type
= htons(aap
->addrp
.ph
.param_type
);
2363 aap
->addrp
.ph
.param_length
= htons(aap
->addrp
.ph
.param_length
);
2365 m_asconf
->m_len
+= SCTP_SIZE32(p_length
);
2366 ptr
+= SCTP_SIZE32(p_length
);
2369 * these params are removed off the pending list upon
2370 * getting an ASCONF-ACK back from the peer, just set flag
2374 /* check to see if the lookup addr has been populated yet */
2375 if (lookup_used
== 0) {
2376 /* NOTE: if the address param is optional, can skip this... */
2377 /* add any valid (existing) address... */
2378 struct sctp_ipv6addr_param
*lookup
;
2379 uint16_t p_size
, addr_size
;
2380 struct sockaddr
*found_addr
;
2383 if (stcb
->sctp_ep
->sctp_flags
& SCTP_PCB_FLAGS_BOUNDALL
)
2384 found_addr
= sctp_find_valid_localaddr(stcb
);
2386 found_addr
= sctp_find_valid_localaddr_ep(stcb
);
2388 lookup
= (struct sctp_ipv6addr_param
*)lookup_ptr
;
2389 if (found_addr
!= NULL
) {
2390 if (found_addr
->sa_family
== AF_INET6
) {
2391 /* copy IPv6 address */
2392 lookup
->ph
.param_type
=
2393 htons(SCTP_IPV6_ADDRESS
);
2394 p_size
= sizeof(struct sctp_ipv6addr_param
);
2395 addr_size
= sizeof(struct in6_addr
);
2396 addr_ptr
= (caddr_t
)&((struct sockaddr_in6
*)
2397 found_addr
)->sin6_addr
;
2399 /* copy IPv4 address */
2400 lookup
->ph
.param_type
=
2401 htons(SCTP_IPV4_ADDRESS
);
2402 p_size
= sizeof(struct sctp_ipv4addr_param
);
2403 addr_size
= sizeof(struct in_addr
);
2404 addr_ptr
= (caddr_t
)&((struct sockaddr_in
*)
2405 found_addr
)->sin_addr
;
2407 lookup
->ph
.param_length
= htons(SCTP_SIZE32(p_size
));
2408 memcpy(lookup
->addr
, addr_ptr
, addr_size
);
2409 m_asconf_chk
->m_len
+= SCTP_SIZE32(p_size
);
2412 /* uh oh... don't have any address?? */
2414 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
)
2415 kprintf("compose_asconf: no lookup addr!\n");
2416 #endif /* SCTP_DEBUG */
2417 /* for now, we send a IPv4 address of 0.0.0.0 */
2418 lookup
->ph
.param_type
= htons(SCTP_IPV4_ADDRESS
);
2419 lookup
->ph
.param_length
= htons(SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param
)));
2420 bzero(lookup
->addr
, sizeof(struct in_addr
));
2421 m_asconf_chk
->m_len
+= SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param
));
2426 /* chain it all together */
2427 m_asconf_chk
->m_next
= m_asconf
;
2428 m_asconf_chk
->m_pkthdr
.len
= m_asconf_chk
->m_len
+ m_asconf
->m_len
;
2429 acp
->ch
.chunk_length
= ntohs(m_asconf_chk
->m_pkthdr
.len
);
2431 /* update "sent" flag */
2432 stcb
->asoc
.asconf_sent
++;
2434 return (m_asconf_chk
);
2438 * section to handle address changes before an association is up
2439 * eg. changes during INIT/INIT-ACK/COOKIE-ECHO handshake
2443 * processes the (local) addresses in the INIT-ACK chunk
2446 sctp_process_initack_addresses(struct sctp_tcb
*stcb
, struct mbuf
*m
,
2447 unsigned int offset
, unsigned int length
)
2449 struct sctp_paramhdr tmp_param
, *ph
;
2450 uint16_t plen
, ptype
;
2451 struct sctp_ipv6addr_param addr_store
;
2452 struct sockaddr_in6 sin6
;
2453 struct sockaddr_in sin
;
2454 struct sockaddr
*sa
;
2458 if (sctp_debug_on
& SCTP_DEBUG_ASCONF2
) {
2459 kprintf("processing init-ack addresses\n");
2461 #endif /* SCTP_DEBUG */
2463 /* convert to upper bound */
2466 if ((offset
+ sizeof(struct sctp_paramhdr
)) > length
) {
2468 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
2469 kprintf("process_initack_addrs: invalid offset?\n");
2471 #endif /* SCTP_DEBUG */
2475 /* init the addresses */
2476 bzero(&sin6
, sizeof(sin6
));
2477 sin6
.sin6_family
= AF_INET6
;
2478 sin6
.sin6_len
= sizeof(sin6
);
2479 sin6
.sin6_port
= stcb
->rport
;
2481 bzero(&sin
, sizeof(sin
));
2482 sin
.sin_len
= sizeof(sin
);
2483 sin
.sin_family
= AF_INET
;
2484 sin
.sin_port
= stcb
->rport
;
2486 /* go through the addresses in the init-ack */
2487 ph
= (struct sctp_paramhdr
*)sctp_m_getptr(m
, offset
,
2488 sizeof(struct sctp_paramhdr
), (uint8_t *)&tmp_param
);
2489 while (ph
!= NULL
) {
2490 ptype
= ntohs(ph
->param_type
);
2491 plen
= ntohs(ph
->param_length
);
2492 if (ptype
== SCTP_IPV6_ADDRESS
) {
2493 struct sctp_ipv6addr_param
*a6p
;
2494 /* get the entire IPv6 address param */
2496 if (sctp_debug_on
& SCTP_DEBUG_ASCONF2
) {
2497 kprintf("process_initack_addrs: checking IPv6 param\n");
2499 #endif /* SCTP_DEBUG */
2500 a6p
= (struct sctp_ipv6addr_param
*)
2501 sctp_m_getptr(m
, offset
,
2502 sizeof(struct sctp_ipv6addr_param
),
2503 (uint8_t *)&addr_store
);
2504 if (plen
!= sizeof(struct sctp_ipv6addr_param
) ||
2507 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
2508 kprintf("process_initack_addrs: invalid IPv6 param length\n");
2510 #endif /* SCTP_DEBUG */
2513 memcpy(&sin6
.sin6_addr
, a6p
->addr
,
2514 sizeof(struct in6_addr
));
2515 sa
= (struct sockaddr
*)&sin6
;
2516 } else if (ptype
== SCTP_IPV4_ADDRESS
) {
2517 struct sctp_ipv4addr_param
*a4p
;
2518 /* get the entire IPv4 address param */
2520 if (sctp_debug_on
& SCTP_DEBUG_ASCONF2
) {
2521 kprintf("process_initack_addrs: checking IPv4 param\n");
2523 #endif /* SCTP_DEBUG */
2524 a4p
= (struct sctp_ipv4addr_param
*)sctp_m_getptr(m
, offset
, sizeof(struct sctp_ipv4addr_param
), (uint8_t *)&addr_store
);
2525 if (plen
!= sizeof(struct sctp_ipv4addr_param
) ||
2528 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
2529 kprintf("process_initack_addrs: invalid IPv4 param length\n");
2531 #endif /* SCTP_DEBUG */
2534 sin
.sin_addr
.s_addr
= a4p
->addr
;
2535 sa
= (struct sockaddr
*)&sin
;
2538 if (sctp_debug_on
& SCTP_DEBUG_ASCONF2
) {
2539 kprintf("process_initack_addrs: skipping param type=%xh\n", ptype
);
2541 #endif /* SCTP_DEBUG */
2545 /* see if this address really (still) exists */
2546 ifa
= sctp_find_ifa_by_addr(sa
);
2548 /* address doesn't exist anymore */
2550 /* are ASCONFs allowed ? */
2551 if ((stcb
->sctp_ep
->sctp_flags
& SCTP_PCB_FLAGS_DO_ASCONF
) &&
2552 stcb
->asoc
.peer_supports_asconf
) {
2553 /* queue an ASCONF DEL_IP_ADDRESS */
2554 status
= sctp_asconf_queue_add_sa(stcb
, sa
,
2555 SCTP_DEL_IP_ADDRESS
);
2557 * if queued ok, and in correct state,
2558 * set the ASCONF timer
2561 SCTP_GET_STATE(&stcb
->asoc
) ==
2563 sctp_timer_start(SCTP_TIMER_TYPE_ASCONF
,
2564 stcb
->sctp_ep
, stcb
,
2565 stcb
->asoc
.primary_destination
);
2569 /* address still exists */
2571 * if subset bound, ep addr's managed by default
2572 * if not doing ASCONF, add the address to the assoc
2574 if ((stcb
->sctp_ep
->sctp_flags
&
2575 SCTP_PCB_FLAGS_BOUNDALL
) == 0 &&
2576 (stcb
->sctp_ep
->sctp_flags
&
2577 SCTP_PCB_FLAGS_DO_ASCONF
) == 0) {
2579 if (sctp_debug_on
& SCTP_DEBUG_ASCONF2
) {
2580 kprintf("process_initack_addrs: adding local addr to asoc\n");
2582 #endif /* SCTP_DEBUG */
2583 sctp_add_local_addr_assoc(stcb
, ifa
);
2588 /* get next parameter */
2589 offset
+= SCTP_SIZE32(plen
);
2590 if ((offset
+ sizeof(struct sctp_paramhdr
)) > length
)
2592 ph
= (struct sctp_paramhdr
*)sctp_m_getptr(m
, offset
,
2593 sizeof(struct sctp_paramhdr
), (uint8_t *)&tmp_param
);
2597 /* FIX ME: need to verify return result for v6 address type if v6 disabled */
2599 * checks to see if a specific address is in the initack address list
2600 * returns 1 if found, 0 if not
2603 sctp_addr_in_initack(struct sctp_tcb
*stcb
, struct mbuf
*m
, unsigned int offset
,
2604 unsigned int length
, struct sockaddr
*sa
)
2606 struct sctp_paramhdr tmp_param
, *ph
;
2607 uint16_t plen
, ptype
;
2608 struct sctp_ipv6addr_param addr_store
;
2609 struct sockaddr_in
*sin
;
2610 struct sctp_ipv4addr_param
*a4p
;
2612 struct sockaddr_in6
*sin6
, sin6_tmp
;
2613 struct sctp_ipv6addr_param
*a6p
;
2618 (sa
->sa_family
!= AF_INET6
) &&
2620 (sa
->sa_family
!= AF_INET
))
2624 if (sctp_debug_on
& SCTP_DEBUG_ASCONF2
) {
2625 kprintf("find_initack_addr: starting search for ");
2626 sctp_print_address(sa
);
2628 #endif /* SCTP_DEBUG */
2629 /* convert to upper bound */
2632 if ((offset
+ sizeof(struct sctp_paramhdr
)) > length
) {
2634 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
2635 kprintf("find_initack_addr: invalid offset?\n");
2637 #endif /* SCTP_DEBUG */
2641 /* go through the addresses in the init-ack */
2642 ph
= (struct sctp_paramhdr
*)sctp_m_getptr(m
, offset
,
2643 sizeof(struct sctp_paramhdr
), (uint8_t *)&tmp_param
);
2644 while (ph
!= NULL
) {
2645 ptype
= ntohs(ph
->param_type
);
2646 plen
= ntohs(ph
->param_length
);
2648 if (ptype
== SCTP_IPV6_ADDRESS
&& sa
->sa_family
== AF_INET6
) {
2649 /* get the entire IPv6 address param */
2651 if (sctp_debug_on
& SCTP_DEBUG_ASCONF2
) {
2652 kprintf("addr_in_initack: checking IPv6 param\n");
2654 #endif /* SCTP_DEBUG */
2655 a6p
= (struct sctp_ipv6addr_param
*)
2656 sctp_m_getptr(m
, offset
,
2657 sizeof(struct sctp_ipv6addr_param
),
2658 (uint8_t *)&addr_store
);
2659 if (plen
!= sizeof(struct sctp_ipv6addr_param
) ||
2662 if (sctp_debug_on
& SCTP_DEBUG_ASCONF2
) {
2663 kprintf("addr_in_initack: invalid IPv6 param length\n");
2665 #endif /* SCTP_DEBUG */
2668 sin6
= (struct sockaddr_in6
*)sa
;
2669 if (IN6_IS_SCOPE_LINKLOCAL(&sin6
->sin6_addr
)) {
2670 /* create a copy and clear scope */
2671 memcpy(&sin6_tmp
, sin6
,
2672 sizeof(struct sockaddr_in6
));
2674 in6_clearscope(&sin6
->sin6_addr
);
2676 if (memcmp(&sin6
->sin6_addr
, a6p
->addr
,
2677 sizeof(struct in6_addr
)) == 0) {
2680 if (sctp_debug_on
& SCTP_DEBUG_ASCONF2
) {
2681 kprintf("addr_in_initack: found IPv6 addr\n");
2683 #endif /* SCTP_DEBUG */
2689 if (ptype
== SCTP_IPV4_ADDRESS
&&
2690 sa
->sa_family
== AF_INET
) {
2691 /* get the entire IPv4 address param */
2693 if (sctp_debug_on
& SCTP_DEBUG_ASCONF2
) {
2694 kprintf("addr_in_initack: checking IPv4 param\n");
2696 #endif /* SCTP_DEBUG */
2697 a4p
= (struct sctp_ipv4addr_param
*)sctp_m_getptr(m
,
2698 offset
, sizeof(struct sctp_ipv4addr_param
),
2699 (uint8_t *)&addr_store
);
2700 if (plen
!= sizeof(struct sctp_ipv4addr_param
) ||
2703 if (sctp_debug_on
& SCTP_DEBUG_ASCONF2
) {
2704 kprintf("addr_in_initack: invalid IPv4 param length\n");
2706 #endif /* SCTP_DEBUG */
2709 sin
= (struct sockaddr_in
*)sa
;
2710 if (sin
->sin_addr
.s_addr
== a4p
->addr
) {
2713 if (sctp_debug_on
& SCTP_DEBUG_ASCONF2
) {
2714 kprintf("addr_in_initack: found IPv4 addr\n");
2716 #endif /* SCTP_DEBUG */
2721 if (sctp_debug_on
& SCTP_DEBUG_ASCONF2
) {
2722 kprintf("addr_in_initack: skipping param type=%xh\n", ptype
);
2724 #endif /* SCTP_DEBUG */
2726 /* get next parameter */
2727 offset
+= SCTP_SIZE32(plen
);
2728 if (offset
+ sizeof(struct sctp_paramhdr
) > length
)
2730 ph
= (struct sctp_paramhdr
*)
2731 sctp_m_getptr(m
, offset
, sizeof(struct sctp_paramhdr
),
2732 (uint8_t *)&tmp_param
);
2736 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
2737 kprintf("addr_in_initack: not found!\n");
2739 #endif /* SCTP_DEBUG */
2744 * makes sure that the current endpoint local addr list is consistent
2745 * with the new association (eg. subset bound, asconf allowed)
2746 * adds addresses as necessary
2749 sctp_check_address_list_ep(struct sctp_tcb
*stcb
, struct mbuf
*m
, int offset
,
2750 int length
, struct sockaddr
*init_addr
)
2752 struct sctp_laddr
*laddr
;
2754 /* go through the endpoint list */
2755 LIST_FOREACH(laddr
, &stcb
->sctp_ep
->sctp_addr_list
, sctp_nxt_addr
) {
2756 /* be paranoid and validate the laddr */
2757 if (laddr
->ifa
== NULL
) {
2759 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
2760 kprintf("check_addr_list_ep: laddr->ifa is NULL");
2765 if (laddr
->ifa
->ifa_addr
== NULL
) {
2767 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
2768 kprintf("check_addr_list_ep: laddr->ifa->ifa_addr is NULL");
2773 /* do i have it implicitly? */
2774 if (sctp_cmpaddr(laddr
->ifa
->ifa_addr
, init_addr
)) {
2776 if (sctp_debug_on
& SCTP_DEBUG_ASCONF2
) {
2777 kprintf("check_address_list_all: skipping ");
2778 sctp_print_address(laddr
->ifa
->ifa_addr
);
2780 #endif /* SCTP_DEBUG */
2783 /* check to see if in the init-ack */
2784 if (!sctp_addr_in_initack(stcb
, m
, offset
, length
,
2785 laddr
->ifa
->ifa_addr
)) {
2787 sctp_addr_mgmt_assoc(stcb
->sctp_ep
, stcb
, laddr
->ifa
,
2788 SCTP_ADD_IP_ADDRESS
);
2794 * makes sure that the current kernel address list is consistent
2795 * with the new association (with all addrs bound)
2796 * adds addresses as necessary
2799 sctp_check_address_list_all(struct sctp_tcb
*stcb
, struct mbuf
*m
, int offset
,
2800 int length
, struct sockaddr
*init_addr
, uint16_t local_scope
,
2801 uint16_t site_scope
, uint16_t ipv4_scope
, uint16_t loopback_scope
)
2806 /* go through all our known interfaces */
2807 TAILQ_FOREACH(ifn
, &ifnet
, if_list
) {
2808 if (loopback_scope
== 0 && ifn
->if_type
== IFT_LOOP
) {
2809 /* skip loopback interface */
2813 /* go through each interface address */
2814 TAILQ_FOREACH(ifa
, &ifn
->if_addrlist
, ifa_list
) {
2815 /* do i have it implicitly? */
2816 if (sctp_cmpaddr(ifa
->ifa_addr
, init_addr
)) {
2818 if (sctp_debug_on
& SCTP_DEBUG_ASCONF2
) {
2819 kprintf("check_address_list_all: skipping ");
2820 sctp_print_address(ifa
->ifa_addr
);
2822 #endif /* SCTP_DEBUG */
2825 /* check to see if in the init-ack */
2826 if (!sctp_addr_in_initack(stcb
, m
, offset
, length
,
2829 sctp_addr_mgmt_assoc(stcb
->sctp_ep
, stcb
,
2830 ifa
, SCTP_ADD_IP_ADDRESS
);
2832 } /* end foreach ifa */
2833 } /* end foreach ifn */
2837 * validates an init-ack chunk (from a cookie-echo) with current addresses
2838 * adds addresses from the init-ack into our local address list, if needed
2839 * queues asconf adds/deletes addresses as needed and makes appropriate
2840 * list changes for source address selection
2841 * m, offset: points to the start of the address list in an init-ack chunk
2842 * length: total length of the address params only
2843 * init_addr: address where my INIT-ACK was sent from
2846 sctp_check_address_list(struct sctp_tcb
*stcb
, struct mbuf
*m
, int offset
,
2847 int length
, struct sockaddr
*init_addr
, uint16_t local_scope
,
2848 uint16_t site_scope
, uint16_t ipv4_scope
, uint16_t loopback_scope
)
2851 /* process the local addresses in the initack */
2852 sctp_process_initack_addresses(stcb
, m
, offset
, length
);
2854 if (stcb
->sctp_ep
->sctp_flags
& SCTP_PCB_FLAGS_BOUNDALL
) {
2855 /* bound all case */
2856 sctp_check_address_list_all(stcb
, m
, offset
, length
, init_addr
,
2857 local_scope
, site_scope
, ipv4_scope
, loopback_scope
);
2859 /* subset bound case */
2860 if (stcb
->sctp_ep
->sctp_flags
& SCTP_PCB_FLAGS_DO_ASCONF
) {
2861 /* asconf's allowed */
2862 sctp_check_address_list_ep(stcb
, m
, offset
, length
,
2865 /* else, no asconfs allowed, so what we sent is what we get */
2870 * sctp_bindx() support
2873 sctp_addr_mgmt_ep_sa(struct sctp_inpcb
*inp
, struct sockaddr
*sa
, uint16_t type
)
2877 if (sa
->sa_len
== 0)
2880 ifa
= sctp_find_ifa_by_addr(sa
);
2883 if (ifa
->ifa_addr
->sa_family
== AF_INET6
) {
2884 struct in6_ifaddr
*ifa6
;
2885 ifa6
= (struct in6_ifaddr
*)ifa
;
2886 if (IFA6_IS_DEPRECATED(ifa6
) ||
2887 (ifa6
->ia6_flags
& (IN6_IFF_DETACHED
|
2888 IN6_IFF_ANYCAST
| IN6_IFF_NOTREADY
))) {
2889 /* Can't bind a non-existent addr. */
2894 /* add this address */
2895 sctp_addr_mgmt_ep(inp
, ifa
, type
);
2897 /* invalid address! */
2899 if (sctp_debug_on
& SCTP_DEBUG_ASCONF1
) {
2900 kprintf("addr_mgmt_ep_sa: got invalid address!\n");
2902 #endif /* SCTP_DEBUG */
2903 return (EADDRNOTAVAIL
);