sctp_asconf.c revision 164085
1191783Srmacklem/*-
2191783Srmacklem * Copyright (c) 2001-2006, Cisco Systems, Inc. All rights reserved.
3191783Srmacklem *
4191783Srmacklem * Redistribution and use in source and binary forms, with or without
5191783Srmacklem * modification, are permitted provided that the following conditions are met:
6191783Srmacklem *
7191783Srmacklem * a) Redistributions of source code must retain the above copyright notice,
8191783Srmacklem *   this list of conditions and the following disclaimer.
9191783Srmacklem *
10191783Srmacklem * b) Redistributions in binary form must reproduce the above copyright
11191783Srmacklem *    notice, this list of conditions and the following disclaimer in
12191783Srmacklem *   the documentation and/or other materials provided with the distribution.
13191783Srmacklem *
14191783Srmacklem * c) Neither the name of Cisco Systems, Inc. nor the names of its
15191783Srmacklem *    contributors may be used to endorse or promote products derived
16191783Srmacklem *    from this software without specific prior written permission.
17191783Srmacklem *
18191783Srmacklem * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19191783Srmacklem * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20191783Srmacklem * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21191783Srmacklem * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22191783Srmacklem * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23191783Srmacklem * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24191783Srmacklem * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25191783Srmacklem * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26191783Srmacklem * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27191783Srmacklem * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28191783Srmacklem * THE POSSIBILITY OF SUCH DAMAGE.
29191783Srmacklem */
30191783Srmacklem
31191783Srmacklem/* $KAME: sctp_asconf.c,v 1.24 2005/03/06 16:04:16 itojun Exp $	 */
32191783Srmacklem
33191783Srmacklem#include <sys/cdefs.h>
34191783Srmacklem__FBSDID("$FreeBSD: head/sys/netinet/sctp_asconf.c 164085 2006-11-08 00:21:13Z rrs $");
35191783Srmacklem
36191783Srmacklem
37228217Srmacklem
38191783Srmacklem#include "opt_ipsec.h"
39191783Srmacklem#include "opt_compat.h"
40191783Srmacklem#include "opt_inet6.h"
41191783Srmacklem#include "opt_inet.h"
42191783Srmacklem
43244042Srmacklem#include "opt_sctp.h"
44244042Srmacklem
45244042Srmacklem#include <sys/param.h>
46244042Srmacklem#include <sys/systm.h>
47244042Srmacklem#include <sys/malloc.h>
48191783Srmacklem#include <sys/mbuf.h>
49244042Srmacklem#include <sys/socket.h>
50191783Srmacklem#include <sys/socketvar.h>
51244042Srmacklem#include <sys/kernel.h>
52244042Srmacklem#include <sys/sysctl.h>
53244042Srmacklem
54191783Srmacklem#include <net/if.h>
55244042Srmacklem#include <net/if_types.h>
56244042Srmacklem#include <net/route.h>
57244042Srmacklem
58244042Srmacklem#include <netinet/in.h>
59244042Srmacklem#include <netinet/in_systm.h>
60269398Srmacklem#include <netinet/ip.h>
61244042Srmacklem#include <netinet/in_pcb.h>
62244042Srmacklem#include <netinet/in_var.h>
63244042Srmacklem#include <netinet/ip_var.h>
64244042Srmacklem
65244042Srmacklem#ifdef INET6
66244042Srmacklem#include <netinet/ip6.h>
67244042Srmacklem#include <netinet6/ip6_var.h>
68244042Srmacklem#include <netinet6/in6_pcb.h>
69244042Srmacklem#include <netinet/icmp6.h>
70244042Srmacklem#include <netinet6/nd6.h>
71244042Srmacklem#include <netinet6/scope6_var.h>
72244042Srmacklem#endif				/* INET6 */
73244042Srmacklem
74244042Srmacklem#include <netinet/in_pcb.h>
75244042Srmacklem
76244042Srmacklem#include <netinet/sctp_os.h>
77244042Srmacklem#include <netinet/sctp_var.h>
78244042Srmacklem#include <netinet/sctp_pcb.h>
79244042Srmacklem#include <netinet/sctp_header.h>
80244042Srmacklem#include <netinet/sctputil.h>
81244042Srmacklem#include <netinet/sctp_output.h>
82244042Srmacklem#include <netinet/sctp_bsd_addr.h>
83244042Srmacklem#include <netinet/sctp_asconf.h>
84244042Srmacklem
85244042Srmacklem/*
86244042Srmacklem * debug flags:
87244042Srmacklem * SCTP_DEBUG_ASCONF1: protocol info, general info and errors
88244042Srmacklem * SCTP_DEBUG_ASCONF2: detailed info
89244042Srmacklem */
90244042Srmacklem#ifdef SCTP_DEBUG
91244042Srmacklemextern uint32_t sctp_debug_on;
92244042Srmacklem
93244042Srmacklem#endif				/* SCTP_DEBUG */
94191783Srmacklem
95191783Srmacklem
96191783Srmacklemstatic int
97191783Srmacklemsctp_asconf_get_source_ip(struct mbuf *m, struct sockaddr *sa)
98191783Srmacklem{
99244042Srmacklem	struct ip *iph;
100244042Srmacklem	struct sockaddr_in *sin;
101244042Srmacklem
102244042Srmacklem#ifdef INET6
103244042Srmacklem	struct sockaddr_in6 *sin6;
104244042Srmacklem
105244042Srmacklem#endif
106244042Srmacklem
107244042Srmacklem	iph = mtod(m, struct ip *);
108244042Srmacklem	if (iph->ip_v == IPVERSION) {
109244042Srmacklem		/* IPv4 source */
110244042Srmacklem		sin = (struct sockaddr_in *)sa;
111244042Srmacklem		bzero(sin, sizeof(*sin));
112244042Srmacklem		sin->sin_family = AF_INET;
113191783Srmacklem		sin->sin_len = sizeof(struct sockaddr_in);
114191783Srmacklem		sin->sin_port = 0;
115191783Srmacklem		sin->sin_addr.s_addr = iph->ip_src.s_addr;
116191783Srmacklem		return 0;
117191783Srmacklem	}
118191783Srmacklem#ifdef INET6
119191783Srmacklem	else if (iph->ip_v == (IPV6_VERSION >> 4)) {
120191783Srmacklem		/* IPv6 source */
121191783Srmacklem		struct ip6_hdr *ip6;
122191783Srmacklem
123191783Srmacklem		sin6 = (struct sockaddr_in6 *)sa;
124191783Srmacklem		bzero(sin6, sizeof(*sin6));
125191783Srmacklem		sin6->sin6_family = AF_INET6;
126191783Srmacklem		sin6->sin6_len = sizeof(struct sockaddr_in6);
127206818Srmacklem		sin6->sin6_port = 0;
128191783Srmacklem		ip6 = mtod(m, struct ip6_hdr *);
129191783Srmacklem		sin6->sin6_addr = ip6->ip6_src;
130191783Srmacklem		return 0;
131191783Srmacklem	}
132191783Srmacklem#endif				/* INET6 */
133191783Srmacklem	else
134191783Srmacklem		return -1;
135191783Srmacklem}
136191783Srmacklem
137191783Srmacklem/*
138191783Srmacklem * draft-ietf-tsvwg-addip-sctp
139191783Srmacklem *
140191783Srmacklem * Address management only currently supported For the bound all case: the asoc
141191783Srmacklem * local addr list is always a "DO NOT USE" list For the subset bound case:
142191783Srmacklem * If ASCONFs are allowed: the endpoint local addr list is the usable address
143191783Srmacklem * list the asoc local addr list is the "DO NOT USE" list If ASCONFs are not
144191783Srmacklem * allowed: the endpoint local addr list is the default usable list the asoc
145191783Srmacklem * local addr list is the usable address list
146191783Srmacklem *
147191783Srmacklem * An ASCONF parameter queue exists per asoc which holds the pending address
148191783Srmacklem * operations.  Lists are updated upon receipt of ASCONF-ACK.
149191783Srmacklem *
150191783Srmacklem * Deleted addresses are always immediately removed from the lists as they will
151191783Srmacklem * (shortly) no longer exist in the kernel.  We send ASCONFs as a courtesy,
152191783Srmacklem * only if allowed.
153191783Srmacklem */
154191783Srmacklem
155191783Srmacklem/*
156191783Srmacklem * ASCONF parameter processing response_required: set if a reply is required
157191783Srmacklem * (eg. SUCCESS_REPORT) returns a mbuf to an "error" response parameter or
158191783Srmacklem * NULL/"success" if ok FIX: allocating this many mbufs on the fly is pretty
159191783Srmacklem * inefficient...
160191783Srmacklem */
161191783Srmacklemstatic struct mbuf *
162191783Srmacklemsctp_asconf_success_response(uint32_t id)
163191783Srmacklem{
164191783Srmacklem	struct mbuf *m_reply = NULL;
165191783Srmacklem	struct sctp_asconf_paramhdr *aph;
166191783Srmacklem
167191783Srmacklem	m_reply = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_paramhdr),
168191783Srmacklem	    0, M_DONTWAIT, 1, MT_DATA);
169191783Srmacklem	if (m_reply == NULL) {
170191783Srmacklem#ifdef SCTP_DEBUG
171214406Srmacklem		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
172191783Srmacklem			printf("asconf_success_response: couldn't get mbuf!\n");
173191783Srmacklem		}
174191783Srmacklem#endif				/* SCTP_DEBUG */
175191783Srmacklem		return NULL;
176191783Srmacklem	}
177191783Srmacklem	aph = mtod(m_reply, struct sctp_asconf_paramhdr *);
178191783Srmacklem	aph->correlation_id = id;
179191783Srmacklem	aph->ph.param_type = htons(SCTP_SUCCESS_REPORT);
180191783Srmacklem	aph->ph.param_length = sizeof(struct sctp_asconf_paramhdr);
181191783Srmacklem	m_reply->m_len = aph->ph.param_length;
182191783Srmacklem	aph->ph.param_length = htons(aph->ph.param_length);
183191783Srmacklem
184191783Srmacklem	return m_reply;
185191783Srmacklem}
186191783Srmacklem
187191783Srmacklemstatic struct mbuf *
188191783Srmacklemsctp_asconf_error_response(uint32_t id, uint16_t cause, uint8_t * error_tlv,
189191783Srmacklem    uint16_t tlv_length)
190191783Srmacklem{
191191783Srmacklem	struct mbuf *m_reply = NULL;
192191783Srmacklem	struct sctp_asconf_paramhdr *aph;
193191783Srmacklem	struct sctp_error_cause *error;
194191783Srmacklem	uint8_t *tlv;
195206688Srmacklem
196191783Srmacklem	m_reply = sctp_get_mbuf_for_msg((sizeof(struct sctp_asconf_paramhdr) +
197191783Srmacklem	    tlv_length +
198191783Srmacklem	    sizeof(struct sctp_error_cause)),
199191783Srmacklem	    0, M_DONTWAIT, 1, MT_DATA);
200191783Srmacklem	if (m_reply == NULL) {
201191783Srmacklem#ifdef SCTP_DEBUG
202191783Srmacklem		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
203228217Srmacklem			printf("asconf_error_response: couldn't get mbuf!\n");
204191783Srmacklem		}
205191783Srmacklem#endif				/* SCTP_DEBUG */
206191783Srmacklem		return NULL;
207191783Srmacklem	}
208191783Srmacklem	aph = mtod(m_reply, struct sctp_asconf_paramhdr *);
209191783Srmacklem	error = (struct sctp_error_cause *)(aph + 1);
210191783Srmacklem
211191783Srmacklem	aph->correlation_id = id;
212191783Srmacklem	aph->ph.param_type = htons(SCTP_ERROR_CAUSE_IND);
213191783Srmacklem	error->code = htons(cause);
214191783Srmacklem	error->length = tlv_length + sizeof(struct sctp_error_cause);
215191783Srmacklem	aph->ph.param_length = error->length +
216191783Srmacklem	    sizeof(struct sctp_asconf_paramhdr);
217191783Srmacklem
218191783Srmacklem	if (aph->ph.param_length > MLEN) {
219191783Srmacklem#ifdef SCTP_DEBUG
220228217Srmacklem		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
221228217Srmacklem			printf("asconf_error_response: tlv_length (%xh) too big\n",
222228217Srmacklem			    tlv_length);
223228217Srmacklem		}
224228217Srmacklem#endif				/* SCTP_DEBUG */
225228217Srmacklem		sctp_m_freem(m_reply);	/* discard */
226228217Srmacklem		return NULL;
227228217Srmacklem	}
228191783Srmacklem	if (error_tlv != NULL) {
229244042Srmacklem		tlv = (uint8_t *) (error + 1);
230244042Srmacklem		memcpy(tlv, error_tlv, tlv_length);
231244042Srmacklem	}
232244042Srmacklem	m_reply->m_len = aph->ph.param_length;
233244042Srmacklem	error->length = htons(error->length);
234244042Srmacklem	aph->ph.param_length = htons(aph->ph.param_length);
235244042Srmacklem
236244042Srmacklem	return m_reply;
237244042Srmacklem}
238244042Srmacklem
239244042Srmacklemstatic struct mbuf *
240244042Srmacklemsctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph,
241244042Srmacklem    struct sctp_tcb *stcb, int response_required)
242244042Srmacklem{
243244042Srmacklem	struct mbuf *m_reply = NULL;
244244042Srmacklem	struct sockaddr_storage sa_source, sa_store;
245244042Srmacklem	struct sctp_ipv4addr_param *v4addr;
246244042Srmacklem	uint16_t param_type, param_length, aparam_length;
247244042Srmacklem	struct sockaddr *sa;
248244042Srmacklem	struct sockaddr_in *sin;
249244042Srmacklem	int zero_address = 0;
250244042Srmacklem
251244042Srmacklem#ifdef INET6
252244042Srmacklem	struct sockaddr_in6 *sin6;
253244042Srmacklem	struct sctp_ipv6addr_param *v6addr;
254244042Srmacklem
255244042Srmacklem#endif				/* INET6 */
256244042Srmacklem
257244042Srmacklem	aparam_length = ntohs(aph->ph.param_length);
258244042Srmacklem	v4addr = (struct sctp_ipv4addr_param *)(aph + 1);
259244042Srmacklem#ifdef INET6
260244042Srmacklem	v6addr = (struct sctp_ipv6addr_param *)(aph + 1);
261244042Srmacklem#endif				/* INET6 */
262244042Srmacklem	param_type = ntohs(v4addr->ph.param_type);
263244042Srmacklem	param_length = ntohs(v4addr->ph.param_length);
264244042Srmacklem
265244042Srmacklem	sa = (struct sockaddr *)&sa_store;
266244042Srmacklem	switch (param_type) {
267244042Srmacklem	case SCTP_IPV4_ADDRESS:
268244042Srmacklem		if (param_length != sizeof(struct sctp_ipv4addr_param)) {
269244042Srmacklem			/* invalid param size */
270244042Srmacklem			return NULL;
271244042Srmacklem		}
272244042Srmacklem		sin = (struct sockaddr_in *)&sa_store;
273244042Srmacklem		bzero(sin, sizeof(*sin));
274244042Srmacklem		sin->sin_family = AF_INET;
275244042Srmacklem		sin->sin_len = sizeof(struct sockaddr_in);
276244042Srmacklem		sin->sin_port = stcb->rport;
277244042Srmacklem		sin->sin_addr.s_addr = v4addr->addr;
278244042Srmacklem		if (sin->sin_addr.s_addr == INADDR_ANY)
279244042Srmacklem			zero_address = 1;
280244042Srmacklem#ifdef SCTP_DEBUG
281244042Srmacklem		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
282244042Srmacklem			printf("process_asconf_add_ip: adding ");
283244042Srmacklem			sctp_print_address(sa);
284244042Srmacklem		}
285244042Srmacklem#endif				/* SCTP_DEBUG */
286244042Srmacklem		break;
287244042Srmacklem	case SCTP_IPV6_ADDRESS:
288244042Srmacklem#ifdef INET6
289244042Srmacklem		if (param_length != sizeof(struct sctp_ipv6addr_param)) {
290244042Srmacklem			/* invalid param size */
291244042Srmacklem			return NULL;
292244042Srmacklem		}
293244042Srmacklem		sin6 = (struct sockaddr_in6 *)&sa_store;
294244042Srmacklem		bzero(sin6, sizeof(*sin6));
295244042Srmacklem		sin6->sin6_family = AF_INET6;
296244042Srmacklem		sin6->sin6_len = sizeof(struct sockaddr_in6);
297244042Srmacklem		sin6->sin6_port = stcb->rport;
298244042Srmacklem		memcpy((caddr_t)&sin6->sin6_addr, v6addr->addr,
299244042Srmacklem		    sizeof(struct in6_addr));
300244042Srmacklem		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
301244042Srmacklem			zero_address = 1;
302244042Srmacklem#ifdef SCTP_DEBUG
303244042Srmacklem		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
304244042Srmacklem			printf("process_asconf_add_ip: adding ");
305244042Srmacklem			sctp_print_address(sa);
306244042Srmacklem		}
307244042Srmacklem#endif				/* SCTP_DEBUG */
308244042Srmacklem#else
309244042Srmacklem		/* IPv6 not enabled! */
310244042Srmacklem		/* FIX ME: currently sends back an invalid param error */
311244042Srmacklem		m_reply = sctp_asconf_error_response(aph->correlation_id,
312244042Srmacklem		    SCTP_CAUSE_INVALID_PARAM, (uint8_t *) aph, aparam_length);
313244042Srmacklem#ifdef SCTP_DEBUG
314244042Srmacklem		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
315244042Srmacklem			printf("process_asconf_add_ip: v6 disabled- skipping ");
316244042Srmacklem			sctp_print_address(sa);
317244042Srmacklem		}
318244042Srmacklem#endif				/* SCTP_DEBUG */
319244042Srmacklem		return m_reply;
320244042Srmacklem#endif				/* INET6 */
321244042Srmacklem		break;
322244042Srmacklem	default:
323244042Srmacklem		m_reply = sctp_asconf_error_response(aph->correlation_id,
324244042Srmacklem		    SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph,
325244042Srmacklem		    aparam_length);
326244042Srmacklem		return m_reply;
327244042Srmacklem	}			/* end switch */
328244042Srmacklem
329244042Srmacklem	/* if 0.0.0.0/::0, add the source address instead */
330244042Srmacklem	if (zero_address) {
331244042Srmacklem		sa = (struct sockaddr *)&sa_source;
332244042Srmacklem		sctp_asconf_get_source_ip(m, sa);
333244042Srmacklem#ifdef SCTP_DEBUG
334244042Srmacklem		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
335244042Srmacklem			printf("process_asconf_add_ip: using source addr ");
336244042Srmacklem			sctp_print_address(sa);
337244042Srmacklem		}
338244042Srmacklem#endif				/* SCTP_DEBUG */
339244042Srmacklem	}
340244042Srmacklem	/* add the address */
341244042Srmacklem	if (sctp_add_remote_addr(stcb, sa, 0, 6) != 0) {
342244042Srmacklem#ifdef SCTP_DEBUG
343244042Srmacklem		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
344244042Srmacklem			printf("process_asconf_add_ip: error adding address\n");
345244042Srmacklem		}
346244042Srmacklem#endif				/* SCTP_DEBUG */
347244042Srmacklem		m_reply = sctp_asconf_error_response(aph->correlation_id,
348244042Srmacklem		    SCTP_CAUSE_RESOURCE_SHORTAGE, (uint8_t *) aph,
349244042Srmacklem		    aparam_length);
350244042Srmacklem	} else {
351244042Srmacklem		/* notify upper layer */
352244042Srmacklem		sctp_ulp_notify(SCTP_NOTIFY_ASCONF_ADD_IP, stcb, 0, sa);
353244042Srmacklem		if (response_required) {
354244042Srmacklem			m_reply =
355244042Srmacklem			    sctp_asconf_success_response(aph->correlation_id);
356244042Srmacklem		}
357244042Srmacklem		sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, NULL);
358244042Srmacklem		sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, NULL);
359244042Srmacklem
360244042Srmacklem	}
361244042Srmacklem
362244042Srmacklem	return m_reply;
363244042Srmacklem}
364191783Srmacklem
365191783Srmacklemstatic int
366191783Srmacklemsctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb,
367191783Srmacklem    struct sockaddr *src)
368191783Srmacklem{
369191783Srmacklem	struct sctp_nets *src_net, *net;
370191783Srmacklem
371191783Srmacklem	/* make sure the source address exists as a destination net */
372	src_net = sctp_findnet(stcb, src);
373	if (src_net == NULL) {
374		/* not found */
375		return -1;
376	}
377	/* delete all destination addresses except the source */
378	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
379		if (net != src_net) {
380			/* delete this address */
381			sctp_remove_net(stcb, net);
382#ifdef SCTP_DEBUG
383			if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
384				printf("asconf_del_remote_addrs_except: deleting ");
385				sctp_print_address((struct sockaddr *)&net->ro._l_addr);
386			}
387#endif
388			/* notify upper layer */
389			sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0,
390			    (struct sockaddr *)&net->ro._l_addr);
391		}
392	}
393	return 0;
394}
395
396static struct mbuf *
397sctp_process_asconf_delete_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph,
398    struct sctp_tcb *stcb, int response_required)
399{
400	struct mbuf *m_reply = NULL;
401	struct sockaddr_storage sa_source, sa_store;
402	struct sctp_ipv4addr_param *v4addr;
403	uint16_t param_type, param_length, aparam_length;
404	struct sockaddr *sa;
405	struct sockaddr_in *sin;
406	int zero_address = 0;
407	int result;
408
409#ifdef INET6
410	struct sockaddr_in6 *sin6;
411	struct sctp_ipv6addr_param *v6addr;
412
413#endif				/* INET6 */
414
415	/* get the source IP address for src and 0.0.0.0/::0 delete checks */
416	sctp_asconf_get_source_ip(m, (struct sockaddr *)&sa_source);
417
418	aparam_length = ntohs(aph->ph.param_length);
419	v4addr = (struct sctp_ipv4addr_param *)(aph + 1);
420#ifdef INET6
421	v6addr = (struct sctp_ipv6addr_param *)(aph + 1);
422#endif				/* INET6 */
423	param_type = ntohs(v4addr->ph.param_type);
424	param_length = ntohs(v4addr->ph.param_length);
425
426	sa = (struct sockaddr *)&sa_store;
427	switch (param_type) {
428	case SCTP_IPV4_ADDRESS:
429		if (param_length != sizeof(struct sctp_ipv4addr_param)) {
430			/* invalid param size */
431			return NULL;
432		}
433		sin = (struct sockaddr_in *)&sa_store;
434		bzero(sin, sizeof(*sin));
435		sin->sin_family = AF_INET;
436		sin->sin_len = sizeof(struct sockaddr_in);
437		sin->sin_port = stcb->rport;
438		sin->sin_addr.s_addr = v4addr->addr;
439		if (sin->sin_addr.s_addr == INADDR_ANY)
440			zero_address = 1;
441#ifdef SCTP_DEBUG
442		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
443			printf("process_asconf_delete_ip: deleting ");
444			sctp_print_address(sa);
445		}
446#endif				/* SCTP_DEBUG */
447		break;
448	case SCTP_IPV6_ADDRESS:
449		if (param_length != sizeof(struct sctp_ipv6addr_param)) {
450			/* invalid param size */
451			return NULL;
452		}
453#ifdef INET6
454		sin6 = (struct sockaddr_in6 *)&sa_store;
455		bzero(sin6, sizeof(*sin6));
456		sin6->sin6_family = AF_INET6;
457		sin6->sin6_len = sizeof(struct sockaddr_in6);
458		sin6->sin6_port = stcb->rport;
459		memcpy(&sin6->sin6_addr, v6addr->addr,
460		    sizeof(struct in6_addr));
461		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
462			zero_address = 1;
463#ifdef SCTP_DEBUG
464		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
465			printf("process_asconf_delete_ip: deleting ");
466			sctp_print_address(sa);
467		}
468#endif				/* SCTP_DEBUG */
469#else
470		/* IPv6 not enabled!  No "action" needed; just ack it */
471#ifdef SCTP_DEBUG
472		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
473			printf("process_asconf_delete_ip: v6 disabled- ignoring: ");
474			sctp_print_address(sa);
475		}
476#endif				/* SCTP_DEBUG */
477		/* just respond with a "success" ASCONF-ACK */
478		return NULL;
479#endif				/* INET6 */
480		break;
481	default:
482		m_reply = sctp_asconf_error_response(aph->correlation_id,
483		    SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph,
484		    aparam_length);
485		return m_reply;
486	}
487
488	/* make sure the source address is not being deleted */
489	if (sctp_cmpaddr(sa, (struct sockaddr *)&sa_source)) {
490		/* trying to delete the source address! */
491#ifdef SCTP_DEBUG
492		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
493			printf("process_asconf_delete_ip: tried to delete source addr\n");
494		}
495#endif				/* SCTP_DEBUG */
496		m_reply = sctp_asconf_error_response(aph->correlation_id,
497		    SCTP_CAUSE_DELETING_SRC_ADDR, (uint8_t *) aph,
498		    aparam_length);
499		return m_reply;
500	}
501	/* if deleting 0.0.0.0/::0, delete all addresses except src addr */
502	if (zero_address) {
503		result = sctp_asconf_del_remote_addrs_except(stcb,
504		    (struct sockaddr *)&sa_source);
505
506		if (result) {
507			/* src address did not exist? */
508#ifdef SCTP_DEBUG
509			if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
510				printf("process_asconf_delete_ip: src addr does not exist?\n");
511			}
512#endif				/* SCTP_DEBUG */
513			/* what error to reply with?? */
514			m_reply =
515			    sctp_asconf_error_response(aph->correlation_id,
516			    SCTP_CAUSE_REQUEST_REFUSED, (uint8_t *) aph,
517			    aparam_length);
518		} else if (response_required) {
519			m_reply =
520			    sctp_asconf_success_response(aph->correlation_id);
521		}
522		return m_reply;
523	}
524	/* delete the address */
525	result = sctp_del_remote_addr(stcb, sa);
526	/*
527	 * note if result == -2, the address doesn't exist in the asoc but
528	 * since it's being deleted anyways, we just ack the delete -- but
529	 * this probably means something has already gone awry
530	 */
531	if (result == -1) {
532		/* only one address in the asoc */
533#ifdef SCTP_DEBUG
534		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
535			printf("process_asconf_delete_ip: tried to delete last IP addr!\n");
536		}
537#endif				/* SCTP_DEBUG */
538		m_reply = sctp_asconf_error_response(aph->correlation_id,
539		    SCTP_CAUSE_DELETING_LAST_ADDR, (uint8_t *) aph,
540		    aparam_length);
541	} else {
542		if (response_required) {
543			m_reply = sctp_asconf_success_response(aph->correlation_id);
544		}
545		/* notify upper layer */
546		sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0, sa);
547	}
548	return m_reply;
549}
550
551static struct mbuf *
552sctp_process_asconf_set_primary(struct mbuf *m,
553    struct sctp_asconf_paramhdr *aph, struct sctp_tcb *stcb,
554    int response_required)
555{
556	struct mbuf *m_reply = NULL;
557	struct sockaddr_storage sa_source, sa_store;
558	struct sctp_ipv4addr_param *v4addr;
559	uint16_t param_type, param_length, aparam_length;
560	struct sockaddr *sa;
561	struct sockaddr_in *sin;
562	int zero_address = 0;
563
564#ifdef INET6
565	struct sockaddr_in6 *sin6;
566	struct sctp_ipv6addr_param *v6addr;
567
568#endif				/* INET6 */
569
570	aparam_length = ntohs(aph->ph.param_length);
571	v4addr = (struct sctp_ipv4addr_param *)(aph + 1);
572#ifdef INET6
573	v6addr = (struct sctp_ipv6addr_param *)(aph + 1);
574#endif				/* INET6 */
575	param_type = ntohs(v4addr->ph.param_type);
576	param_length = ntohs(v4addr->ph.param_length);
577
578	sa = (struct sockaddr *)&sa_store;
579	switch (param_type) {
580	case SCTP_IPV4_ADDRESS:
581		if (param_length != sizeof(struct sctp_ipv4addr_param)) {
582			/* invalid param size */
583			return NULL;
584		}
585		sin = (struct sockaddr_in *)&sa_store;
586		bzero(sin, sizeof(*sin));
587		sin->sin_family = AF_INET;
588		sin->sin_len = sizeof(struct sockaddr_in);
589		sin->sin_addr.s_addr = v4addr->addr;
590		if (sin->sin_addr.s_addr == INADDR_ANY)
591			zero_address = 1;
592#ifdef SCTP_DEBUG
593		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
594			printf("process_asconf_set_primary: ");
595			sctp_print_address(sa);
596		}
597#endif				/* SCTP_DEBUG */
598		break;
599	case SCTP_IPV6_ADDRESS:
600		if (param_length != sizeof(struct sctp_ipv6addr_param)) {
601			/* invalid param size */
602			return NULL;
603		}
604#ifdef INET6
605		sin6 = (struct sockaddr_in6 *)&sa_store;
606		bzero(sin6, sizeof(*sin6));
607		sin6->sin6_family = AF_INET6;
608		sin6->sin6_len = sizeof(struct sockaddr_in6);
609		memcpy((caddr_t)&sin6->sin6_addr, v6addr->addr,
610		    sizeof(struct in6_addr));
611		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
612			zero_address = 1;
613#ifdef SCTP_DEBUG
614		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
615			printf("process_asconf_set_primary: ");
616			sctp_print_address(sa);
617		}
618#endif				/* SCTP_DEBUG */
619#else
620		/* IPv6 not enabled!  No "action" needed; just ack it */
621#ifdef SCTP_DEBUG
622		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
623			printf("process_asconf_set_primary: v6 disabled- ignoring: ");
624			sctp_print_address(sa);
625		}
626#endif				/* SCTP_DEBUG */
627		/* just respond with a "success" ASCONF-ACK */
628		return NULL;
629#endif				/* INET6 */
630		break;
631	default:
632		m_reply = sctp_asconf_error_response(aph->correlation_id,
633		    SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph,
634		    aparam_length);
635		return m_reply;
636	}
637
638	/* if 0.0.0.0/::0, use the source address instead */
639	if (zero_address) {
640		sa = (struct sockaddr *)&sa_source;
641		sctp_asconf_get_source_ip(m, sa);
642#ifdef SCTP_DEBUG
643		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
644			printf("process_asconf_set_primary: using source addr ");
645			sctp_print_address(sa);
646		}
647#endif				/* SCTP_DEBUG */
648	}
649	/* set the primary address */
650	if (sctp_set_primary_addr(stcb, sa, NULL) == 0) {
651#ifdef SCTP_DEBUG
652		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
653			printf("process_asconf_set_primary: primary address set\n");
654		}
655#endif				/* SCTP_DEBUG */
656		/* notify upper layer */
657		sctp_ulp_notify(SCTP_NOTIFY_ASCONF_SET_PRIMARY, stcb, 0, sa);
658
659		if (response_required) {
660			m_reply = sctp_asconf_success_response(aph->correlation_id);
661		}
662	} else {
663		/* couldn't set the requested primary address! */
664#ifdef SCTP_DEBUG
665		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
666			printf("process_asconf_set_primary: set primary failed!\n");
667		}
668#endif				/* SCTP_DEBUG */
669		/* must have been an invalid address, so report */
670		m_reply = sctp_asconf_error_response(aph->correlation_id,
671		    SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph,
672		    aparam_length);
673	}
674
675	return m_reply;
676}
677
678/*
679 * handles an ASCONF chunk.
680 * if all parameters are processed ok, send a plain (empty) ASCONF-ACK
681 */
682void
683sctp_handle_asconf(struct mbuf *m, unsigned int offset,
684    struct sctp_asconf_chunk *cp, struct sctp_tcb *stcb)
685{
686	struct sctp_association *asoc;
687	uint32_t serial_num;
688	struct mbuf *m_ack, *m_result, *m_tail;
689	struct sctp_asconf_ack_chunk *ack_cp;
690	struct sctp_asconf_paramhdr *aph, *ack_aph;
691	struct sctp_ipv6addr_param *p_addr;
692	unsigned int asconf_limit;
693	int error = 0;		/* did an error occur? */
694
695	/* asconf param buffer */
696	static uint8_t aparam_buf[DEFAULT_PARAM_BUFFER];
697
698	/* verify minimum length */
699	if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_asconf_chunk)) {
700#ifdef SCTP_DEBUG
701		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
702			printf("handle_asconf: chunk too small = %xh\n",
703			    ntohs(cp->ch.chunk_length));
704		}
705#endif				/* SCTP_DEBUG */
706		return;
707	}
708	asoc = &stcb->asoc;
709	serial_num = ntohl(cp->serial_number);
710
711	if (serial_num == asoc->asconf_seq_in) {
712		/* got a duplicate ASCONF */
713#ifdef SCTP_DEBUG
714		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
715			printf("handle_asconf: got duplicate serial number = %xh\n",
716			    serial_num);
717		}
718#endif				/* SCTP_DEBUG */
719		/* resend last ASCONF-ACK... */
720		sctp_send_asconf_ack(stcb, 1);
721		return;
722	} else if (serial_num != (asoc->asconf_seq_in + 1)) {
723#ifdef SCTP_DEBUG
724		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
725			printf("handle_asconf: incorrect serial number = %xh (expected next = %xh)\n",
726			    serial_num, asoc->asconf_seq_in + 1);
727		}
728#endif				/* SCTP_DEBUG */
729		return;
730	}
731	/* it's the expected "next" sequence number, so process it */
732	asoc->asconf_seq_in = serial_num;	/* update sequence */
733	/* get length of all the param's in the ASCONF */
734	asconf_limit = offset + ntohs(cp->ch.chunk_length);
735#ifdef SCTP_DEBUG
736	if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
737		printf("handle_asconf: asconf_limit=%u, sequence=%xh\n",
738		    asconf_limit, serial_num);
739	}
740#endif				/* SCTP_DEBUG */
741	if (asoc->last_asconf_ack_sent != NULL) {
742		/* free last ASCONF-ACK message sent */
743		sctp_m_freem(asoc->last_asconf_ack_sent);
744		asoc->last_asconf_ack_sent = NULL;
745	}
746	m_ack = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_ack_chunk), 1,
747	    M_DONTWAIT, 1, MT_DATA);
748	if (m_ack == NULL) {
749#ifdef SCTP_DEBUG
750		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
751			printf("handle_asconf: couldn't get mbuf!\n");
752		}
753#endif				/* SCTP_DEBUG */
754		return;
755	}
756	m_tail = m_ack;		/* current reply chain's tail */
757
758	/* fill in ASCONF-ACK header */
759	ack_cp = mtod(m_ack, struct sctp_asconf_ack_chunk *);
760	ack_cp->ch.chunk_type = SCTP_ASCONF_ACK;
761	ack_cp->ch.chunk_flags = 0;
762	ack_cp->serial_number = htonl(serial_num);
763	/* set initial lengths (eg. just an ASCONF-ACK), ntohx at the end! */
764	m_ack->m_len = sizeof(struct sctp_asconf_ack_chunk);
765	ack_cp->ch.chunk_length = sizeof(struct sctp_asconf_ack_chunk);
766	m_ack->m_pkthdr.len = sizeof(struct sctp_asconf_ack_chunk);
767
768	/* skip the lookup address parameter */
769	offset += sizeof(struct sctp_asconf_chunk);
770	p_addr = (struct sctp_ipv6addr_param *)sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr), (uint8_t *) & aparam_buf);
771	if (p_addr == NULL) {
772#ifdef SCTP_DEBUG
773		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
774			printf("handle_asconf: couldn't get lookup addr!\n");
775		}
776#endif				/* SCTP_DEBUG */
777
778		/* respond with a missing/invalid mandatory parameter error */
779		return;
780	}
781	/* param_length is already validated in process_control... */
782	offset += ntohs(p_addr->ph.param_length);	/* skip lookup addr */
783
784	/* get pointer to first asconf param in ASCONF-ACK */
785	ack_aph = (struct sctp_asconf_paramhdr *)(mtod(m_ack, caddr_t)+sizeof(struct sctp_asconf_ack_chunk));
786	if (ack_aph == NULL) {
787#ifdef SCTP_DEBUG
788		printf("Gak in asconf2\n");
789#endif
790		return;
791	}
792	/* get pointer to first asconf param in ASCONF */
793	aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, sizeof(struct sctp_asconf_paramhdr), (uint8_t *) & aparam_buf);
794	if (aph == NULL) {
795#ifdef SCTP_DEBUG
796		printf("Empty ASCONF received?\n");
797#endif
798		goto send_reply;
799	}
800	/* process through all parameters */
801	while (aph != NULL) {
802		unsigned int param_length, param_type;
803
804		param_type = ntohs(aph->ph.param_type);
805		param_length = ntohs(aph->ph.param_length);
806		if (offset + param_length > asconf_limit) {
807			/* parameter goes beyond end of chunk! */
808			sctp_m_freem(m_ack);
809			return;
810		}
811		m_result = NULL;
812
813		if (param_length > sizeof(aparam_buf)) {
814#ifdef SCTP_DEBUG
815			if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
816				printf("handle_asconf: param length (%u) larger than buffer size!\n", param_length);
817			}
818#endif				/* SCTP_DEBUG */
819			sctp_m_freem(m_ack);
820			return;
821		}
822		if (param_length <= sizeof(struct sctp_paramhdr)) {
823#ifdef SCTP_DEBUG
824			if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
825				printf("handle_asconf: param length (%u) too short\n", param_length);
826			}
827#endif				/* SCTP_DEBUG */
828			sctp_m_freem(m_ack);
829		}
830		/* get the entire parameter */
831		aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, param_length, aparam_buf);
832		if (aph == NULL) {
833#ifdef SCTP_DEBUG
834			printf("Gag\n");
835#endif
836			sctp_m_freem(m_ack);
837			return;
838		}
839		switch (param_type) {
840		case SCTP_ADD_IP_ADDRESS:
841			asoc->peer_supports_asconf = 1;
842			m_result = sctp_process_asconf_add_ip(m, aph, stcb,
843			    error);
844			break;
845		case SCTP_DEL_IP_ADDRESS:
846			asoc->peer_supports_asconf = 1;
847			m_result = sctp_process_asconf_delete_ip(m, aph, stcb,
848			    error);
849			break;
850		case SCTP_ERROR_CAUSE_IND:
851			/* not valid in an ASCONF chunk */
852			break;
853		case SCTP_SET_PRIM_ADDR:
854			asoc->peer_supports_asconf = 1;
855			m_result = sctp_process_asconf_set_primary(m, aph,
856			    stcb, error);
857			break;
858		case SCTP_SUCCESS_REPORT:
859			/* not valid in an ASCONF chunk */
860			break;
861		case SCTP_ULP_ADAPTATION:
862			/* FIX */
863			break;
864		default:
865			if ((param_type & 0x8000) == 0) {
866				/* Been told to STOP at this param */
867				asconf_limit = offset;
868				/*
869				 * FIX FIX - We need to call
870				 * sctp_arethere_unrecognized_parameters()
871				 * to get a operr and send it for any
872				 * param's with the 0x4000 bit set OR do it
873				 * here ourselves... note we still must STOP
874				 * if the 0x8000 bit is clear.
875				 */
876			}
877			/* unknown/invalid param type */
878			break;
879		}		/* switch */
880
881		/* add any (error) result to the reply mbuf chain */
882		if (m_result != NULL) {
883			m_tail->m_next = m_result;
884			m_tail = m_result;
885			/* update lengths, make sure it's aligned too */
886			m_result->m_len = SCTP_SIZE32(m_result->m_len);
887			m_ack->m_pkthdr.len += m_result->m_len;
888			ack_cp->ch.chunk_length += m_result->m_len;
889			/* set flag to force success reports */
890			error = 1;
891		}
892		offset += SCTP_SIZE32(param_length);
893		/* update remaining ASCONF message length to process */
894		if (offset >= asconf_limit) {
895			/* no more data in the mbuf chain */
896			break;
897		}
898		/* get pointer to next asconf param */
899		aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset,
900		    sizeof(struct sctp_asconf_paramhdr),
901		    (uint8_t *) & aparam_buf);
902		if (aph == NULL) {
903			/* can't get an asconf paramhdr */
904#ifdef SCTP_DEBUG
905			if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
906				printf("handle_asconf: can't get asconf param hdr!\n");
907			}
908#endif				/* SCTP_DEBUG */
909			/* FIX ME - add error here... */
910		}
911	}			/* while */
912
913send_reply:
914	ack_cp->ch.chunk_length = htons(ack_cp->ch.chunk_length);
915	/* save the ASCONF-ACK reply */
916	asoc->last_asconf_ack_sent = m_ack;
917
918	/* see if last_control_chunk_from is set properly (use IP src addr) */
919	if (stcb->asoc.last_control_chunk_from == NULL) {
920		/*
921		 * this could happen if the source address was just newly
922		 * added
923		 */
924		struct ip *iph;
925		struct sctphdr *sh;
926		struct sockaddr_storage from_store;
927		struct sockaddr *from = (struct sockaddr *)&from_store;
928
929#ifdef SCTP_DEBUG
930		if (sctp_debug_on & SCTP_DEBUG_ASCONF1)
931			printf("handle_asconf: looking up net for IP source address\n");
932#endif				/* SCTP_DEBUG */
933		/* pullup already done, IP options already stripped */
934		iph = mtod(m, struct ip *);
935		sh = (struct sctphdr *)((caddr_t)iph + sizeof(*iph));
936		if (iph->ip_v == IPVERSION) {
937			struct sockaddr_in *from4;
938
939			from4 = (struct sockaddr_in *)&from_store;
940			bzero(from4, sizeof(*from4));
941			from4->sin_family = AF_INET;
942			from4->sin_len = sizeof(struct sockaddr_in);
943			from4->sin_addr.s_addr = iph->ip_src.s_addr;
944			from4->sin_port = sh->src_port;
945		} else if (iph->ip_v == (IPV6_VERSION >> 4)) {
946			struct ip6_hdr *ip6;
947			struct sockaddr_in6 *from6;
948
949			ip6 = mtod(m, struct ip6_hdr *);
950			from6 = (struct sockaddr_in6 *)&from_store;
951			bzero(from6, sizeof(*from6));
952			from6->sin6_family = AF_INET6;
953			from6->sin6_len = sizeof(struct sockaddr_in6);
954			from6->sin6_addr = ip6->ip6_src;
955			from6->sin6_port = sh->src_port;
956			/* Get the scopes in properly to the sin6 addr's */
957			/* we probably don't need these operations */
958			(void)sa6_recoverscope(from6);
959			sa6_embedscope(from6, ip6_use_defzone);
960		} else {
961			/* unknown address type */
962			from = NULL;
963		}
964		if (from != NULL) {
965#ifdef SCTP_DEBUG
966			if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
967				printf("Looking for IP source: ");
968				sctp_print_address(from);
969			}
970#endif				/* SCTP_DEBUG */
971			/* look up the from address */
972			stcb->asoc.last_control_chunk_from = sctp_findnet(stcb, from);
973#ifdef SCTP_DEBUG
974			if ((stcb->asoc.last_control_chunk_from == NULL) &&
975			    (sctp_debug_on & SCTP_DEBUG_ASCONF1))
976				printf("handle_asconf: IP source address not found?!\n");
977#endif				/* SCTP_DEBUG */
978		}
979	}
980	/* and send it (a new one) out... */
981	sctp_send_asconf_ack(stcb, 0);
982}
983
984/*
985 * does the address match? returns 0 if not, 1 if so
986 */
987static uint32_t
988sctp_asconf_addr_match(struct sctp_asconf_addr *aa, struct sockaddr *sa)
989{
990#ifdef INET6
991	if (sa->sa_family == AF_INET6) {
992		/* IPv6 sa address */
993		/* XXX scopeid */
994		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
995
996		if ((aa->ap.addrp.ph.param_type == SCTP_IPV6_ADDRESS) &&
997		    (memcmp(&aa->ap.addrp.addr, &sin6->sin6_addr,
998		    sizeof(struct in6_addr)) == 0)) {
999			return (1);
1000		}
1001	} else
1002#endif				/* INET6 */
1003	if (sa->sa_family == AF_INET) {
1004		/* IPv4 sa address */
1005		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1006
1007		if ((aa->ap.addrp.ph.param_type == SCTP_IPV4_ADDRESS) &&
1008		    (memcmp(&aa->ap.addrp.addr, &sin->sin_addr,
1009		    sizeof(struct in_addr)) == 0)) {
1010			return (1);
1011		}
1012	}
1013	return (0);
1014}
1015
1016/*
1017 * Cleanup for non-responded/OP ERR'd ASCONF
1018 */
1019void
1020sctp_asconf_cleanup(struct sctp_tcb *stcb, struct sctp_nets *net)
1021{
1022	/* mark peer as ASCONF incapable */
1023	stcb->asoc.peer_supports_asconf = 0;
1024	/*
1025	 * clear out any existing asconfs going out
1026	 */
1027	sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net);
1028	stcb->asoc.asconf_seq_out++;
1029	/* remove the old ASCONF on our outbound queue */
1030	sctp_toss_old_asconf(stcb);
1031}
1032
1033/*
1034 * process an ADD/DELETE IP ack from peer.
1035 * addr  corresponding ifaddr to the address being added/deleted.
1036 * type: SCTP_ADD_IP_ADDRESS or SCTP_DEL_IP_ADDRESS.
1037 * flag: 1=success, 0=failure.
1038 */
1039static void
1040sctp_asconf_addr_mgmt_ack(struct sctp_tcb *stcb, struct ifaddr *addr,
1041    uint16_t type, uint32_t flag)
1042{
1043	/*
1044	 * do the necessary asoc list work- if we get a failure indication,
1045	 * leave the address on the "do not use" asoc list if we get a
1046	 * success indication, remove the address from the list
1047	 */
1048	/*
1049	 * Note: this will only occur for ADD_IP_ADDRESS, since
1050	 * DEL_IP_ADDRESS is never actually added to the list...
1051	 */
1052	if (flag) {
1053		/* success case, so remove from the list */
1054		sctp_del_local_addr_assoc(stcb, addr);
1055	}
1056	/* else, leave it on the list */
1057}
1058
1059/*
1060 * add an asconf add/delete IP address parameter to the queue.
1061 * type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR.
1062 * returns 0 if completed, non-zero if not completed.
1063 * NOTE: if adding, but delete already scheduled (and not yet sent out),
1064 * simply remove from queue.  Same for deleting an address already scheduled
1065 * for add.  If a duplicate operation is found, ignore the new one.
1066 */
1067static uint32_t
1068sctp_asconf_queue_add(struct sctp_tcb *stcb, struct ifaddr *ifa, uint16_t type)
1069{
1070	struct sctp_asconf_addr *aa, *aa_next;
1071	struct sockaddr *sa;
1072
1073	/* see if peer supports ASCONF */
1074	if (stcb->asoc.peer_supports_asconf == 0) {
1075		return (-1);
1076	}
1077	/* make sure the request isn't already in the queue */
1078	for (aa = TAILQ_FIRST(&stcb->asoc.asconf_queue); aa != NULL;
1079	    aa = aa_next) {
1080		aa_next = TAILQ_NEXT(aa, next);
1081		/* address match? */
1082		if (sctp_asconf_addr_match(aa, ifa->ifa_addr) == 0)
1083			continue;
1084		/* is the request already in queue (sent or not) */
1085		if (aa->ap.aph.ph.param_type == type) {
1086			return (-1);
1087		}
1088		/* is the negative request already in queue, and not sent */
1089		if (aa->sent == 0 &&
1090		/* add requested, delete already queued */
1091		    ((type == SCTP_ADD_IP_ADDRESS &&
1092		    aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS) ||
1093		/* delete requested, add already queued */
1094		    (type == SCTP_DEL_IP_ADDRESS &&
1095		    aa->ap.aph.ph.param_type == SCTP_ADD_IP_ADDRESS))) {
1096			/* delete the existing entry in the queue */
1097			TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
1098			/* take the entry off the appropriate list */
1099			sctp_asconf_addr_mgmt_ack(stcb, aa->ifa, type, 1);
1100			/* free the entry */
1101			SCTP_FREE(aa);
1102			return (-1);
1103		}
1104	}			/* for each aa */
1105
1106	/* adding new request to the queue */
1107	SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa), "AsconfAddr");
1108	if (aa == NULL) {
1109		/* didn't get memory */
1110#ifdef SCTP_DEBUG
1111		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
1112			printf("asconf_queue_add: failed to get memory!\n");
1113		}
1114#endif				/* SCTP_DEBUG */
1115		return (-1);
1116	}
1117	/* fill in asconf address parameter fields */
1118	/* top level elements are "networked" during send */
1119	aa->ap.aph.ph.param_type = type;
1120	aa->ifa = ifa;
1121	/* correlation_id filled in during send routine later... */
1122	if (ifa->ifa_addr->sa_family == AF_INET6) {
1123		/* IPv6 address */
1124		struct sockaddr_in6 *sin6;
1125
1126		sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
1127		sa = (struct sockaddr *)sin6;
1128		aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
1129		aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param));
1130		aa->ap.aph.ph.param_length =
1131		    sizeof(struct sctp_asconf_paramhdr) +
1132		    sizeof(struct sctp_ipv6addr_param);
1133		memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr,
1134		    sizeof(struct in6_addr));
1135	} else if (ifa->ifa_addr->sa_family == AF_INET) {
1136		/* IPv4 address */
1137		struct sockaddr_in *sin = (struct sockaddr_in *)ifa->ifa_addr;
1138
1139		sa = (struct sockaddr *)sin;
1140		aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
1141		aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv4addr_param));
1142		aa->ap.aph.ph.param_length =
1143		    sizeof(struct sctp_asconf_paramhdr) +
1144		    sizeof(struct sctp_ipv4addr_param);
1145		memcpy(&aa->ap.addrp.addr, &sin->sin_addr,
1146		    sizeof(struct in_addr));
1147	} else {
1148		/* invalid family! */
1149		return (-1);
1150	}
1151	aa->sent = 0;		/* clear sent flag */
1152
1153	/*
1154	 * if we are deleting an address it should go out last otherwise,
1155	 * add it to front of the pending queue
1156	 */
1157	if (type == SCTP_ADD_IP_ADDRESS) {
1158		/* add goes to the front of the queue */
1159		TAILQ_INSERT_HEAD(&stcb->asoc.asconf_queue, aa, next);
1160#ifdef SCTP_DEBUG
1161		if (sctp_debug_on & SCTP_DEBUG_ASCONF2) {
1162			printf("asconf_queue_add: appended asconf ADD_IP_ADDRESS: ");
1163			sctp_print_address(sa);
1164		}
1165#endif				/* SCTP_DEBUG */
1166	} else {
1167		/* delete and set primary goes to the back of the queue */
1168		TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
1169#ifdef SCTP_DEBUG
1170		if (sctp_debug_on & SCTP_DEBUG_ASCONF2) {
1171			if (type == SCTP_DEL_IP_ADDRESS) {
1172				printf("asconf_queue_add: inserted asconf DEL_IP_ADDRESS: ");
1173				sctp_print_address(sa);
1174			} else {
1175				printf("asconf_queue_add: inserted asconf SET_PRIM_ADDR: ");
1176				sctp_print_address(sa);
1177			}
1178		}
1179#endif				/* SCTP_DEBUG */
1180	}
1181
1182	return (0);
1183}
1184
1185/*
1186 * add an asconf add/delete IP address parameter to the queue by addr.
1187 * type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR.
1188 * returns 0 if completed, non-zero if not completed.
1189 * NOTE: if adding, but delete already scheduled (and not yet sent out),
1190 * simply remove from queue.  Same for deleting an address already scheduled
1191 * for add.  If a duplicate operation is found, ignore the new one.
1192 */
1193static uint32_t
1194sctp_asconf_queue_add_sa(struct sctp_tcb *stcb, struct sockaddr *sa,
1195    uint16_t type)
1196{
1197	struct sctp_asconf_addr *aa, *aa_next;
1198
1199	/* see if peer supports ASCONF */
1200	if (stcb->asoc.peer_supports_asconf == 0) {
1201		return (-1);
1202	}
1203	/* make sure the request isn't already in the queue */
1204	for (aa = TAILQ_FIRST(&stcb->asoc.asconf_queue); aa != NULL;
1205	    aa = aa_next) {
1206		aa_next = TAILQ_NEXT(aa, next);
1207		/* address match? */
1208		if (sctp_asconf_addr_match(aa, sa) == 0)
1209			continue;
1210		/* is the request already in queue (sent or not) */
1211		if (aa->ap.aph.ph.param_type == type) {
1212			return (-1);
1213		}
1214		/* is the negative request already in queue, and not sent */
1215		if (aa->sent == 1)
1216			continue;
1217		if (type == SCTP_ADD_IP_ADDRESS &&
1218		    aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS) {
1219			/* add requested, delete already queued */
1220
1221			/* delete the existing entry in the queue */
1222			TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
1223			/* free the entry */
1224			SCTP_FREE(aa);
1225			return (-1);
1226		} else if (type == SCTP_DEL_IP_ADDRESS &&
1227		    aa->ap.aph.ph.param_type == SCTP_ADD_IP_ADDRESS) {
1228			/* delete requested, add already queued */
1229
1230			/* delete the existing entry in the queue */
1231			TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
1232			/* take the entry off the appropriate list */
1233			sctp_asconf_addr_mgmt_ack(stcb, aa->ifa, type, 1);
1234			/* free the entry */
1235			SCTP_FREE(aa);
1236			return (-1);
1237		}
1238	}			/* for each aa */
1239
1240	/* adding new request to the queue */
1241	SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa), "AsconfAddr");
1242	if (aa == NULL) {
1243		/* didn't get memory */
1244#ifdef SCTP_DEBUG
1245		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
1246			printf("asconf_queue_add_sa: failed to get memory!\n");
1247		}
1248#endif				/* SCTP_DEBUG */
1249		return (-1);
1250	}
1251	/* fill in asconf address parameter fields */
1252	/* top level elements are "networked" during send */
1253	aa->ap.aph.ph.param_type = type;
1254	aa->ifa = sctp_find_ifa_by_addr(sa);
1255	/* correlation_id filled in during send routine later... */
1256	if (sa->sa_family == AF_INET6) {
1257		/* IPv6 address */
1258		struct sockaddr_in6 *sin6;
1259
1260		sin6 = (struct sockaddr_in6 *)sa;
1261		aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
1262		aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param));
1263		aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_ipv6addr_param);
1264		memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr,
1265		    sizeof(struct in6_addr));
1266	} else if (sa->sa_family == AF_INET) {
1267		/* IPv4 address */
1268		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1269
1270		aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
1271		aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv4addr_param));
1272		aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_ipv4addr_param);
1273		memcpy(&aa->ap.addrp.addr, &sin->sin_addr,
1274		    sizeof(struct in_addr));
1275	} else {
1276		/* invalid family! */
1277		SCTP_FREE(aa);
1278		return (-1);
1279	}
1280	aa->sent = 0;		/* clear sent flag */
1281
1282	/*
1283	 * if we are deleting an address it should go out last otherwise,
1284	 * add it to front of the pending queue
1285	 */
1286	if (type == SCTP_ADD_IP_ADDRESS) {
1287		/* add goes to the front of the queue */
1288		TAILQ_INSERT_HEAD(&stcb->asoc.asconf_queue, aa, next);
1289	} else {
1290		/* delete and set primary goes to the back of the queue */
1291		TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
1292	}
1293
1294	return (0);
1295}
1296
1297/*
1298 * find a specific asconf param on our "sent" queue
1299 */
1300static struct sctp_asconf_addr *
1301sctp_asconf_find_param(struct sctp_tcb *stcb, uint32_t correlation_id)
1302{
1303	struct sctp_asconf_addr *aa;
1304
1305	TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) {
1306		if (aa->ap.aph.correlation_id == correlation_id &&
1307		    aa->sent == 1) {
1308			/* found it */
1309			return (aa);
1310		}
1311	}
1312	/* didn't find it */
1313	return (NULL);
1314}
1315
1316/*
1317 * process an SCTP_ERROR_CAUSE_IND for a ASCONF-ACK parameter and do
1318 * notifications based on the error response
1319 */
1320static void
1321sctp_asconf_process_error(struct sctp_tcb *stcb,
1322    struct sctp_asconf_paramhdr *aph)
1323{
1324	struct sctp_error_cause *eh;
1325	struct sctp_paramhdr *ph;
1326	uint16_t param_type;
1327	uint16_t error_code;
1328
1329	eh = (struct sctp_error_cause *)(aph + 1);
1330	ph = (struct sctp_paramhdr *)(eh + 1);
1331	/* validate lengths */
1332	if (htons(eh->length) + sizeof(struct sctp_error_cause) >
1333	    htons(aph->ph.param_length)) {
1334		/* invalid error cause length */
1335#ifdef SCTP_DEBUG
1336		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
1337			printf("asconf_process_error: cause element too long\n");
1338		}
1339#endif				/* SCTP_DEBUG */
1340		return;
1341	}
1342	if (htons(ph->param_length) + sizeof(struct sctp_paramhdr) >
1343	    htons(eh->length)) {
1344		/* invalid included TLV length */
1345#ifdef SCTP_DEBUG
1346		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
1347			printf("asconf_process_error: included TLV too long\n");
1348		}
1349#endif				/* SCTP_DEBUG */
1350		return;
1351	}
1352	/* which error code ? */
1353	error_code = ntohs(eh->code);
1354	param_type = ntohs(aph->ph.param_type);
1355	/* FIX: this should go back up the REMOTE_ERROR ULP notify */
1356	switch (error_code) {
1357	case SCTP_CAUSE_RESOURCE_SHORTAGE:
1358		/* we allow ourselves to "try again" for this error */
1359		break;
1360	default:
1361		/* peer can't handle it... */
1362		switch (param_type) {
1363		case SCTP_ADD_IP_ADDRESS:
1364		case SCTP_DEL_IP_ADDRESS:
1365			stcb->asoc.peer_supports_asconf = 0;
1366			break;
1367		case SCTP_SET_PRIM_ADDR:
1368			stcb->asoc.peer_supports_asconf = 0;
1369			break;
1370		default:
1371			break;
1372		}
1373	}
1374}
1375
1376/*
1377 * process an asconf queue param aparam: parameter to process, will be
1378 * removed from the queue flag: 1=success, 0=failure
1379 */
1380static void
1381sctp_asconf_process_param_ack(struct sctp_tcb *stcb,
1382    struct sctp_asconf_addr *aparam, uint32_t flag)
1383{
1384	uint16_t param_type;
1385
1386	/* process this param */
1387	param_type = aparam->ap.aph.ph.param_type;
1388	switch (param_type) {
1389	case SCTP_ADD_IP_ADDRESS:
1390#ifdef SCTP_DEBUG
1391		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
1392			printf("process_param_ack: added IP address\n");
1393		}
1394#endif				/* SCTP_DEBUG */
1395		sctp_asconf_addr_mgmt_ack(stcb, aparam->ifa, param_type, flag);
1396		break;
1397	case SCTP_DEL_IP_ADDRESS:
1398#ifdef SCTP_DEBUG
1399		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
1400			printf("process_param_ack: deleted IP address\n");
1401		}
1402#endif				/* SCTP_DEBUG */
1403		/* nothing really to do... lists already updated */
1404		break;
1405	case SCTP_SET_PRIM_ADDR:
1406		/* nothing to do... peer may start using this addr */
1407		if (flag == 0)
1408			stcb->asoc.peer_supports_asconf = 0;
1409		break;
1410	default:
1411		/* should NEVER happen */
1412		break;
1413	}
1414
1415	/* remove the param and free it */
1416	TAILQ_REMOVE(&stcb->asoc.asconf_queue, aparam, next);
1417	SCTP_FREE(aparam);
1418}
1419
1420/*
1421 * cleanup from a bad asconf ack parameter
1422 */
1423static void
1424sctp_asconf_ack_clear(struct sctp_tcb *stcb)
1425{
1426	/* assume peer doesn't really know how to do asconfs */
1427	stcb->asoc.peer_supports_asconf = 0;
1428	/* XXX we could free the pending queue here */
1429}
1430
1431void
1432sctp_handle_asconf_ack(struct mbuf *m, int offset,
1433    struct sctp_asconf_ack_chunk *cp, struct sctp_tcb *stcb,
1434    struct sctp_nets *net)
1435{
1436	struct sctp_association *asoc;
1437	uint32_t serial_num;
1438	uint16_t ack_length;
1439	struct sctp_asconf_paramhdr *aph;
1440	struct sctp_asconf_addr *aa, *aa_next;
1441	uint32_t last_error_id = 0;	/* last error correlation id */
1442	uint32_t id;
1443	struct sctp_asconf_addr *ap;
1444
1445	/* asconf param buffer */
1446	static uint8_t aparam_buf[DEFAULT_PARAM_BUFFER];
1447
1448	/* verify minimum length */
1449	if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_asconf_ack_chunk)) {
1450#ifdef SCTP_DEBUG
1451		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
1452			printf("handle_asconf_ack: chunk too small = %xh\n",
1453			    ntohs(cp->ch.chunk_length));
1454		}
1455#endif				/* SCTP_DEBUG */
1456		return;
1457	}
1458	asoc = &stcb->asoc;
1459	serial_num = ntohl(cp->serial_number);
1460
1461	/*
1462	 * NOTE: we may want to handle this differently- currently, we will
1463	 * abort when we get an ack for the expected serial number + 1 (eg.
1464	 * we didn't send it), process an ack normally if it is the expected
1465	 * serial number, and re-send the previous ack for *ALL* other
1466	 * serial numbers
1467	 */
1468
1469	/*
1470	 * if the serial number is the next expected, but I didn't send it,
1471	 * abort the asoc, since someone probably just hijacked us...
1472	 */
1473	if (serial_num == (asoc->asconf_seq_out + 1)) {
1474#ifdef SCTP_DEBUG
1475		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
1476			printf("handle_asconf_ack: got unexpected next serial number! Aborting asoc!\n");
1477		}
1478#endif				/* SCTP_DEBUG */
1479		sctp_abort_an_association(stcb->sctp_ep, stcb,
1480		    SCTP_CAUSE_ILLEGAL_ASCONF_ACK, NULL);
1481		return;
1482	}
1483	if (serial_num != asoc->asconf_seq_out) {
1484		/* got a duplicate/unexpected ASCONF-ACK */
1485#ifdef SCTP_DEBUG
1486		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
1487			printf("handle_asconf_ack: got duplicate/unexpected serial number = %xh (expected = %xh)\n", serial_num, asoc->asconf_seq_out);
1488		}
1489#endif				/* SCTP_DEBUG */
1490		return;
1491	}
1492	if (stcb->asoc.asconf_sent == 0) {
1493		/* got a unexpected ASCONF-ACK for serial not in flight */
1494#ifdef SCTP_DEBUG
1495		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
1496			printf("handle_asconf_ack: got serial number = %xh but not in flight\n", serial_num);
1497		}
1498#endif				/* SCTP_DEBUG */
1499		/* nothing to do... duplicate ACK received */
1500		return;
1501	}
1502	/* stop our timer */
1503	sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net);
1504
1505	/* process the ASCONF-ACK contents */
1506	ack_length = ntohs(cp->ch.chunk_length) -
1507	    sizeof(struct sctp_asconf_ack_chunk);
1508	offset += sizeof(struct sctp_asconf_ack_chunk);
1509	/* process through all parameters */
1510	while (ack_length >= sizeof(struct sctp_asconf_paramhdr)) {
1511		unsigned int param_length, param_type;
1512
1513		/* get pointer to next asconf parameter */
1514		aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset,
1515		    sizeof(struct sctp_asconf_paramhdr), aparam_buf);
1516		if (aph == NULL) {
1517			/* can't get an asconf paramhdr */
1518			sctp_asconf_ack_clear(stcb);
1519			return;
1520		}
1521		param_type = ntohs(aph->ph.param_type);
1522		param_length = ntohs(aph->ph.param_length);
1523		if (param_length > ack_length) {
1524			sctp_asconf_ack_clear(stcb);
1525			return;
1526		}
1527		if (param_length < sizeof(struct sctp_paramhdr)) {
1528			sctp_asconf_ack_clear(stcb);
1529			return;
1530		}
1531		/* get the complete parameter... */
1532		if (param_length > sizeof(aparam_buf)) {
1533#ifdef SCTP_DEBUG
1534			if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
1535				printf("param length (%u) larger than buffer size!\n", param_length);
1536			}
1537#endif				/* SCTP_DEBUG */
1538			sctp_asconf_ack_clear(stcb);
1539			return;
1540		}
1541		aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, param_length, aparam_buf);
1542		if (aph == NULL) {
1543			sctp_asconf_ack_clear(stcb);
1544			return;
1545		}
1546		/* correlation_id is transparent to peer, no ntohl needed */
1547		id = aph->correlation_id;
1548
1549		switch (param_type) {
1550		case SCTP_ERROR_CAUSE_IND:
1551			last_error_id = id;
1552			/* find the corresponding asconf param in our queue */
1553			ap = sctp_asconf_find_param(stcb, id);
1554			if (ap == NULL) {
1555				/* hmm... can't find this in our queue! */
1556				break;
1557			}
1558			/* process the parameter, failed flag */
1559			sctp_asconf_process_param_ack(stcb, ap, 0);
1560			/* process the error response */
1561			sctp_asconf_process_error(stcb, aph);
1562			break;
1563		case SCTP_SUCCESS_REPORT:
1564			/* find the corresponding asconf param in our queue */
1565			ap = sctp_asconf_find_param(stcb, id);
1566			if (ap == NULL) {
1567				/* hmm... can't find this in our queue! */
1568				break;
1569			}
1570			/* process the parameter, success flag */
1571			sctp_asconf_process_param_ack(stcb, ap, 1);
1572			break;
1573		default:
1574			break;
1575		}		/* switch */
1576
1577		/* update remaining ASCONF-ACK message length to process */
1578		ack_length -= SCTP_SIZE32(param_length);
1579		if (ack_length <= 0) {
1580			/* no more data in the mbuf chain */
1581			break;
1582		}
1583		offset += SCTP_SIZE32(param_length);
1584	}			/* while */
1585
1586	/*
1587	 * if there are any "sent" params still on the queue, these are
1588	 * implicitly "success", or "failed" (if we got an error back) ...
1589	 * so process these appropriately
1590	 *
1591	 * we assume that the correlation_id's are monotonically increasing
1592	 * beginning from 1 and that we don't have *that* many outstanding
1593	 * at any given time
1594	 */
1595	if (last_error_id == 0)
1596		last_error_id--;/* set to "max" value */
1597	for (aa = TAILQ_FIRST(&stcb->asoc.asconf_queue); aa != NULL;
1598	    aa = aa_next) {
1599		aa_next = TAILQ_NEXT(aa, next);
1600		if (aa->sent == 1) {
1601			/*
1602			 * implicitly successful or failed if correlation_id
1603			 * < last_error_id, then success else, failure
1604			 */
1605			if (aa->ap.aph.correlation_id < last_error_id)
1606				sctp_asconf_process_param_ack(stcb, aa,
1607				    SCTP_SUCCESS_REPORT);
1608			else
1609				sctp_asconf_process_param_ack(stcb, aa,
1610				    SCTP_ERROR_CAUSE_IND);
1611		} else {
1612			/*
1613			 * since we always process in order (FIFO queue) if
1614			 * we reach one that hasn't been sent, the rest
1615			 * should not have been sent either. so, we're
1616			 * done...
1617			 */
1618			break;
1619		}
1620	}
1621
1622	/* update the next sequence number to use */
1623	asoc->asconf_seq_out++;
1624	/* remove the old ASCONF on our outbound queue */
1625	sctp_toss_old_asconf(stcb);
1626	/* clear the sent flag to allow new ASCONFs */
1627	asoc->asconf_sent = 0;
1628	if (!TAILQ_EMPTY(&stcb->asoc.asconf_queue)) {
1629		/* we have more params, so restart our timer */
1630		sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep,
1631		    stcb, net);
1632	}
1633}
1634
1635/* is this an interface that we care about at all? */
1636static uint32_t
1637sctp_is_desired_interface_type(struct ifaddr *ifa)
1638{
1639	int result;
1640
1641	/* check the interface type to see if it's one we care about */
1642	switch (ifa->ifa_ifp->if_type) {
1643	case IFT_ETHER:
1644	case IFT_ISO88023:
1645	case IFT_ISO88025:
1646	case IFT_STARLAN:
1647	case IFT_P10:
1648	case IFT_P80:
1649	case IFT_HY:
1650	case IFT_FDDI:
1651	case IFT_PPP:
1652	case IFT_XETHER:
1653	case IFT_SLIP:
1654	case IFT_GIF:
1655		result = 1;
1656		break;
1657	default:
1658		result = 0;
1659	}
1660
1661	return (result);
1662}
1663
1664static uint32_t
1665sctp_is_scopeid_in_nets(struct sctp_tcb *stcb, struct sockaddr *sa)
1666{
1667	struct sockaddr_in6 *sin6, *net6;
1668	struct sctp_nets *net;
1669
1670	if (sa->sa_family != AF_INET6) {
1671		/* wrong family */
1672		return (0);
1673	}
1674	sin6 = (struct sockaddr_in6 *)sa;
1675	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) == 0) {
1676		/* not link local address */
1677		return (0);
1678	}
1679	/* hunt through our destination nets list for this scope_id */
1680	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1681		if (((struct sockaddr *)(&net->ro._l_addr))->sa_family !=
1682		    AF_INET6)
1683			continue;
1684		net6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1685		if (IN6_IS_ADDR_LINKLOCAL(&net6->sin6_addr) == 0)
1686			continue;
1687		if (sctp_is_same_scope(sin6, net6)) {
1688			/* found one */
1689			return (1);
1690		}
1691	}
1692	/* didn't find one */
1693	return (0);
1694}
1695
1696/*
1697 * address management functions
1698 */
1699static void
1700sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1701    struct ifaddr *ifa, uint16_t type)
1702{
1703	int status;
1704
1705
1706	if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0 &&
1707	    sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
1708		/* subset bound, no ASCONF allowed case, so ignore */
1709		return;
1710	}
1711	/*
1712	 * note: we know this is not the subset bound, no ASCONF case eg.
1713	 * this is boundall or subset bound w/ASCONF allowed
1714	 */
1715
1716	/* first, make sure it's a good address family */
1717	if (ifa->ifa_addr->sa_family != AF_INET6 &&
1718	    ifa->ifa_addr->sa_family != AF_INET) {
1719		return;
1720	}
1721	/* make sure we're "allowed" to add this type of addr */
1722	if (ifa->ifa_addr->sa_family == AF_INET6) {
1723		struct in6_ifaddr *ifa6;
1724
1725		/* invalid if we're not a v6 endpoint */
1726		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0)
1727			return;
1728		/* is the v6 addr really valid ? */
1729		ifa6 = (struct in6_ifaddr *)ifa;
1730		if (IFA6_IS_DEPRECATED(ifa6) ||
1731		    (ifa6->ia6_flags &
1732		    (IN6_IFF_DETACHED | IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
1733			/* can't use an invalid address */
1734			return;
1735		}
1736	}
1737	/* put this address on the "pending/do not use yet" list */
1738	/*
1739	 * Note: we do this primarily for the subset bind case We don't have
1740	 * scoping flags at the EP level, so we must add link local/site
1741	 * local addresses to the EP, then need to "negate" them here.
1742	 * Recall that this routine is only called for the subset bound
1743	 * w/ASCONF allowed case.
1744	 */
1745
1746	/*
1747	 * do a scope_id check against any link local addresses in the
1748	 * destination nets list to see if we should put this local address
1749	 * on the pending list or not eg. don't put on the list if we have a
1750	 * link local destination with the same scope_id
1751	 */
1752	if (type == SCTP_ADD_IP_ADDRESS) {
1753		if (sctp_is_scopeid_in_nets(stcb, ifa->ifa_addr) == 0) {
1754			sctp_add_local_addr_assoc(stcb, ifa);
1755		}
1756	}
1757	/*
1758	 * check address scope if address is out of scope, don't queue
1759	 * anything... note: this would leave the address on both inp and
1760	 * asoc lists
1761	 */
1762	if (ifa->ifa_addr->sa_family == AF_INET6) {
1763		struct sockaddr_in6 *sin6;
1764
1765		sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
1766		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
1767			/* we skip unspecifed addresses */
1768			return;
1769		}
1770		if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1771			if (stcb->asoc.local_scope == 0) {
1772				return;
1773			}
1774			/* is it the right link local scope? */
1775			if (sctp_is_scopeid_in_nets(stcb, ifa->ifa_addr) == 0) {
1776				return;
1777			}
1778		}
1779		if (stcb->asoc.site_scope == 0 &&
1780		    IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
1781			return;
1782		}
1783	} else if (ifa->ifa_addr->sa_family == AF_INET) {
1784		struct sockaddr_in *sin;
1785		struct in6pcb *inp6;
1786
1787		inp6 = (struct in6pcb *)&inp->ip_inp.inp;
1788		/* invalid if we are a v6 only endpoint */
1789		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
1790		    (inp6->inp_flags & IN6P_IPV6_V6ONLY)
1791		    )
1792			return;
1793
1794		sin = (struct sockaddr_in *)ifa->ifa_addr;
1795		if (sin->sin_addr.s_addr == 0) {
1796			/* we skip unspecifed addresses */
1797			return;
1798		}
1799		if (stcb->asoc.ipv4_local_scope == 0 &&
1800		    IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) {
1801			return;
1802		}
1803	} else {
1804		/* else, not AF_INET or AF_INET6, so skip */
1805#ifdef SCTP_DEBUG
1806		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
1807			printf("addr_mgmt_assoc: not AF_INET or AF_INET6\n");
1808		}
1809#endif				/* SCTP_DEBUG */
1810		return;
1811	}
1812
1813	/* queue an asconf for this address add/delete */
1814
1815	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
1816		/* does the peer do asconf? */
1817		if (stcb->asoc.peer_supports_asconf) {
1818			/* queue an asconf for this addr */
1819			status = sctp_asconf_queue_add(stcb, ifa, type);
1820			/*
1821			 * if queued ok, and in correct state, set the
1822			 * ASCONF timer if in non-open state, we will set
1823			 * this timer when the state does go open and do all
1824			 * the asconf's
1825			 */
1826			if (status == 0 &&
1827			    SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
1828				sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp,
1829				    stcb, stcb->asoc.primary_destination);
1830			}
1831		}
1832	} else {
1833		/* this is the boundall, no ASCONF case */
1834#if 0
1835		/* Peter: Fixe me? why the if 0? */
1836		/*
1837		 * assume kernel will delete this very shortly; add done
1838		 * above
1839		 */
1840		if (type == SCTP_DEL_IP_ADDRESS) {
1841			/* if deleting, add this addr to the do not use list */
1842			sctp_add_local_addr_assoc(stcb, ifa);
1843		}
1844#endif
1845	}
1846}
1847
1848static void
1849sctp_addr_mgmt_ep(struct sctp_inpcb *inp, struct ifaddr *ifa, uint16_t type)
1850{
1851	struct sctp_tcb *stcb;
1852	int s;
1853
1854
1855	SCTP_INP_WLOCK(inp);
1856	/* make sure we're "allowed" to add this type of addr */
1857	if (ifa->ifa_addr->sa_family == AF_INET6) {
1858		struct in6_ifaddr *ifa6;
1859
1860		/* invalid if we're not a v6 endpoint */
1861		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
1862			SCTP_INP_WUNLOCK(inp);
1863			return;
1864		}
1865		/* is the v6 addr really valid ? */
1866		ifa6 = (struct in6_ifaddr *)ifa;
1867		if (IFA6_IS_DEPRECATED(ifa6) ||
1868		    (ifa6->ia6_flags &
1869		    (IN6_IFF_DETACHED | IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
1870			/* can't use an invalid address */
1871			SCTP_INP_WUNLOCK(inp);
1872			return;
1873		}
1874	} else if (ifa->ifa_addr->sa_family == AF_INET) {
1875		/* invalid if we are a v6 only endpoint */
1876		struct in6pcb *inp6;
1877
1878		inp6 = (struct in6pcb *)&inp->ip_inp.inp;
1879
1880		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
1881		    (inp6->inp_flags & IN6P_IPV6_V6ONLY)
1882		    ) {
1883			SCTP_INP_WUNLOCK(inp);
1884			return;
1885		}
1886	} else {
1887		/* invalid address family */
1888		SCTP_INP_WUNLOCK(inp);
1889		return;
1890	}
1891	/* is this endpoint subset bound ? */
1892	if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
1893		/* subset bound endpoint */
1894		if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
1895			/*
1896			 * subset bound, but ASCONFs not allowed... if
1897			 * adding, nothing to do, since not allowed if
1898			 * deleting, remove address from endpoint peer will
1899			 * have to "timeout" this addr
1900			 */
1901			if (type == SCTP_DEL_IP_ADDRESS) {
1902				sctp_del_local_addr_ep(inp, ifa);
1903			}
1904			/* no asconfs to queue for this inp... */
1905			SCTP_INP_WUNLOCK(inp);
1906			return;
1907		} else {
1908			/*
1909			 * subset bound, ASCONFs allowed... if adding, add
1910			 * address to endpoint list if deleting, remove
1911			 * address from endpoint
1912			 */
1913			if (type == SCTP_ADD_IP_ADDRESS) {
1914				sctp_add_local_addr_ep(inp, ifa);
1915			} else {
1916				sctp_del_local_addr_ep(inp, ifa);
1917			}
1918			/* drop through and notify all asocs */
1919		}
1920	}
1921	s = splnet();
1922	/* process for all associations for this endpoint */
1923	LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
1924		SCTP_TCB_LOCK(stcb);
1925		sctp_addr_mgmt_assoc(inp, stcb, ifa, type);
1926		SCTP_TCB_UNLOCK(stcb);
1927	}
1928	splx(s);
1929	SCTP_INP_WUNLOCK(inp);
1930}
1931
1932/*
1933 * restrict the use of this address
1934 */
1935static void
1936sctp_addr_mgmt_restrict_ep(struct sctp_inpcb *inp, struct ifaddr *ifa)
1937{
1938	struct sctp_tcb *stcb;
1939	int s;
1940
1941	/* is this endpoint bound to all? */
1942	if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
1943		/*
1944		 * Nothing to do for subset bound case. Allow sctp_bindx()
1945		 * to manage the address lists
1946		 */
1947		return;
1948	}
1949	s = splnet();
1950	SCTP_INP_RLOCK(inp);
1951	/* process for all associations for this endpoint */
1952	LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
1953		/* put this address on the "pending/do not use yet" list */
1954		SCTP_TCB_LOCK(stcb);
1955		sctp_add_local_addr_assoc(stcb, ifa);
1956		SCTP_TCB_UNLOCK(stcb);
1957	}
1958	splx(s);
1959	SCTP_INP_RUNLOCK(inp);
1960}
1961
1962/*
1963 * this is only called for kernel initiated address changes eg. it will check
1964 * the PCB_FLAGS_AUTO_ASCONF flag
1965 */
1966static void
1967sctp_addr_mgmt(struct ifaddr *ifa, uint16_t type)
1968{
1969	struct sockaddr *sa;
1970	struct sctp_inpcb *inp;
1971
1972	/* make sure we care about this interface... */
1973	if (!sctp_is_desired_interface_type(ifa)) {
1974		return;
1975	}
1976	sa = ifa->ifa_addr;
1977	if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
1978		return;
1979
1980#ifdef SCTP_DEBUG
1981	if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
1982		if (type == SCTP_ADD_IP_ADDRESS)
1983			printf("sctp_addr_mgmt: kernel adds ");
1984		else
1985			printf("sctp_addr_mgmt: kernel deletes ");
1986		sctp_print_address(sa);
1987	}
1988#endif				/* SCTP_DEBUG */
1989
1990	/* go through all our PCB's */
1991	LIST_FOREACH(inp, &sctppcbinfo.listhead, sctp_list) {
1992		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF)) {
1993			sctp_addr_mgmt_ep(inp, ifa, type);
1994		} else {
1995			/* this address is going away anyways... */
1996			if (type == SCTP_DEL_IP_ADDRESS)
1997				return;
1998			/* (temporarily) restrict this address */
1999			sctp_addr_mgmt_restrict_ep(inp, ifa);
2000		}
2001		/* else, not allowing automatic asconf's, so ignore */
2002	}
2003}
2004
2005/*
2006 * add/delete IP address requests from kernel (via routing change) assumed
2007 * that the address is non-broadcast, non-multicast all addresses are passed
2008 * from any type of interface-- need to filter duplicate addresses may get
2009 * requested
2010 */
2011
2012void
2013sctp_add_ip_address(struct ifaddr *ifa)
2014{
2015	sctp_addr_mgmt(ifa, SCTP_ADD_IP_ADDRESS);
2016}
2017
2018void
2019sctp_delete_ip_address(struct ifaddr *ifa)
2020{
2021	struct sctp_inpcb *inp;
2022
2023	/* process the delete */
2024	sctp_addr_mgmt(ifa, SCTP_DEL_IP_ADDRESS);
2025
2026	/*
2027	 * need to remove this ifaddr from any cached routes and also any
2028	 * from any assoc "restricted/pending" lists
2029	 */
2030	/* make sure we care about this interface... */
2031	if (!sctp_is_desired_interface_type(ifa)) {
2032		return;
2033	}
2034	/* go through all our PCB's */
2035	SCTP_INP_INFO_RLOCK();
2036	LIST_FOREACH(inp, &sctppcbinfo.listhead, sctp_list) {
2037		struct sctp_tcb *stcb;
2038		struct sctp_laddr *laddr, *laddr_next;
2039
2040		/* process for all associations for this endpoint */
2041		SCTP_INP_RLOCK(inp);
2042		LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
2043			struct sctp_nets *net;
2044
2045			/* process through the nets list */
2046			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
2047				struct rtentry *rt;
2048
2049				/* delete this address if cached */
2050				rt = net->ro.ro_rt;
2051				if (rt != NULL && rt->rt_ifa == ifa) {
2052					/* RTFREE(rt); */
2053					net->ro.ro_rt = NULL;
2054				}
2055			}	/* for each net */
2056			/* process through the asoc "pending" list */
2057			laddr = LIST_FIRST(&stcb->asoc.sctp_local_addr_list);
2058			while (laddr != NULL) {
2059				laddr_next = LIST_NEXT(laddr, sctp_nxt_addr);
2060				/* remove if in use */
2061				if (laddr->ifa == ifa) {
2062					sctp_remove_laddr(laddr);
2063				}
2064				laddr = laddr_next;
2065			}	/* while */
2066		}		/* for each stcb */
2067		/* process through the inp bound addr list */
2068		laddr = LIST_FIRST(&inp->sctp_addr_list);
2069		while (laddr != NULL) {
2070			laddr_next = LIST_NEXT(laddr, sctp_nxt_addr);
2071			/* remove if in use */
2072			if (laddr->ifa == ifa) {
2073				sctp_remove_laddr(laddr);
2074			}
2075			laddr = laddr_next;
2076		}
2077		SCTP_INP_RUNLOCK(inp);
2078	}
2079	SCTP_INP_INFO_RUNLOCK();
2080}
2081
2082/*
2083 * sa is the sockaddr to ask the peer to set primary to returns: 0 =
2084 * completed, -1 = error
2085 */
2086int32_t
2087sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa)
2088{
2089	/* NOTE: we currently don't check the validity of the address! */
2090
2091	/* queue an ASCONF:SET_PRIM_ADDR to be sent */
2092	if (!sctp_asconf_queue_add_sa(stcb, sa, SCTP_SET_PRIM_ADDR)) {
2093		/* set primary queuing succeeded */
2094		if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
2095			sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
2096			    stcb->sctp_ep, stcb,
2097			    stcb->asoc.primary_destination);
2098		}
2099#ifdef SCTP_DEBUG
2100		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
2101			printf("set_primary_ip_address_sa: queued on tcb=%p, ",
2102			    stcb);
2103			sctp_print_address(sa);
2104		}
2105#endif				/* SCTP_DEBUG */
2106	} else {
2107#ifdef SCTP_DEBUG
2108		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
2109			printf("set_primary_ip_address_sa: failed to add to queue on tcb=%p, ",
2110			    stcb);
2111			sctp_print_address(sa);
2112		}
2113#endif				/* SCTP_DEBUG */
2114		return (-1);
2115	}
2116	return (0);
2117}
2118
2119void
2120sctp_set_primary_ip_address(struct ifaddr *ifa)
2121{
2122	struct sctp_inpcb *inp;
2123
2124	/* make sure we care about this interface... */
2125	if (!sctp_is_desired_interface_type(ifa)) {
2126		return;
2127	}
2128	/* go through all our PCB's */
2129	LIST_FOREACH(inp, &sctppcbinfo.listhead, sctp_list) {
2130		struct sctp_tcb *stcb;
2131
2132		/* process for all associations for this endpoint */
2133		LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
2134			/* queue an ASCONF:SET_PRIM_ADDR to be sent */
2135			if (!sctp_asconf_queue_add(stcb, ifa,
2136			    SCTP_SET_PRIM_ADDR)) {
2137				/* set primary queuing succeeded */
2138				if (SCTP_GET_STATE(&stcb->asoc) ==
2139				    SCTP_STATE_OPEN) {
2140					sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
2141					    stcb->sctp_ep, stcb,
2142					    stcb->asoc.primary_destination);
2143				}
2144#ifdef SCTP_DEBUG
2145				if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
2146					printf("set_primary_ip_address: queued on stcb=%p, ",
2147					    stcb);
2148					sctp_print_address(ifa->ifa_addr);
2149				}
2150#endif				/* SCTP_DEBUG */
2151			}
2152		}		/* for each stcb */
2153	}			/* for each inp */
2154}
2155
2156static struct sockaddr *
2157sctp_find_valid_localaddr(struct sctp_tcb *stcb)
2158{
2159	struct ifnet *ifn;
2160	struct ifaddr *ifa;
2161
2162
2163	TAILQ_FOREACH(ifn, &ifnet, if_list) {
2164		if (stcb->asoc.loopback_scope == 0 && ifn->if_type == IFT_LOOP) {
2165			/* Skip if loopback_scope not set */
2166			continue;
2167		}
2168		TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) {
2169			if (ifa->ifa_addr->sa_family == AF_INET &&
2170			    stcb->asoc.ipv4_addr_legal) {
2171				struct sockaddr_in *sin;
2172
2173				sin = (struct sockaddr_in *)ifa->ifa_addr;
2174				if (sin->sin_addr.s_addr == 0) {
2175					/* skip unspecifed addresses */
2176					continue;
2177				}
2178				if (stcb->asoc.ipv4_local_scope == 0 &&
2179				    IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))
2180					continue;
2181
2182				if (sctp_is_addr_restricted(stcb,
2183				    ifa->ifa_addr))
2184					continue;
2185				/* found a valid local v4 address to use */
2186				return (ifa->ifa_addr);
2187			} else if (ifa->ifa_addr->sa_family == AF_INET6 &&
2188			    stcb->asoc.ipv6_addr_legal) {
2189				struct sockaddr_in6 *sin6;
2190				struct in6_ifaddr *ifa6;
2191
2192				ifa6 = (struct in6_ifaddr *)ifa;
2193				if (IFA6_IS_DEPRECATED(ifa6) ||
2194				    (ifa6->ia6_flags & (IN6_IFF_DETACHED |
2195				    IN6_IFF_ANYCAST | IN6_IFF_NOTREADY)))
2196					continue;
2197
2198				sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
2199				if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
2200					/* we skip unspecifed addresses */
2201					continue;
2202				}
2203				if (stcb->asoc.local_scope == 0 &&
2204				    IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
2205					continue;
2206				if (stcb->asoc.site_scope == 0 &&
2207				    IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))
2208					continue;
2209
2210				/* found a valid local v6 address to use */
2211				return (ifa->ifa_addr);
2212			}
2213		}
2214	}
2215	/* no valid addresses found */
2216	return (NULL);
2217}
2218
2219static struct sockaddr *
2220sctp_find_valid_localaddr_ep(struct sctp_tcb *stcb)
2221{
2222	struct sctp_laddr *laddr;
2223
2224	LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) {
2225		if (laddr->ifa == NULL) {
2226			continue;
2227		}
2228		if (laddr->ifa->ifa_addr == NULL) {
2229			continue;
2230		}
2231		/* is the address restricted ? */
2232		if (sctp_is_addr_restricted(stcb, laddr->ifa->ifa_addr))
2233			continue;
2234
2235		/* found a valid local address to use */
2236		return (laddr->ifa->ifa_addr);
2237	}
2238	/* no valid addresses found */
2239	return (NULL);
2240}
2241
2242/*
2243 * builds an ASCONF chunk from queued ASCONF params returns NULL on error (no
2244 * mbuf, no ASCONF params queued, etc)
2245 */
2246struct mbuf *
2247sctp_compose_asconf(struct sctp_tcb *stcb)
2248{
2249	struct mbuf *m_asconf, *m_asconf_chk;
2250	struct sctp_asconf_addr *aa;
2251	struct sctp_asconf_chunk *acp;
2252	struct sctp_asconf_paramhdr *aph;
2253	struct sctp_asconf_addr_param *aap;
2254	uint32_t p_length;
2255	uint32_t correlation_id = 1;	/* 0 is reserved... */
2256	caddr_t ptr, lookup_ptr;
2257	uint8_t lookup_used = 0;
2258
2259	/* are there any asconf params to send? */
2260	if (TAILQ_EMPTY(&stcb->asoc.asconf_queue)) {
2261		return (NULL);
2262	}
2263	/*
2264	 * get a chunk header mbuf and a cluster for the asconf params since
2265	 * it's simpler to fill in the asconf chunk header lookup address on
2266	 * the fly
2267	 */
2268	m_asconf_chk = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_chunk), 1, M_DONTWAIT, 1, MT_DATA);
2269	if (m_asconf_chk == NULL) {
2270		/* no mbuf's */
2271#ifdef SCTP_DEBUG
2272		if (sctp_debug_on & SCTP_DEBUG_ASCONF1)
2273			printf("compose_asconf: couldn't get chunk mbuf!\n");
2274#endif				/* SCTP_DEBUG */
2275		return (NULL);
2276	}
2277	m_asconf = sctp_get_mbuf_for_msg(MCLBYTES, 1, M_DONTWAIT, 1, MT_DATA);
2278	if (m_asconf == NULL) {
2279		/* no mbuf's */
2280#ifdef SCTP_DEBUG
2281		if (sctp_debug_on & SCTP_DEBUG_ASCONF1)
2282			printf("compose_asconf: couldn't get mbuf!\n");
2283#endif				/* SCTP_DEBUG */
2284		sctp_m_freem(m_asconf_chk);
2285		return (NULL);
2286	}
2287	m_asconf_chk->m_len = sizeof(struct sctp_asconf_chunk);
2288	m_asconf->m_len = 0;
2289	acp = mtod(m_asconf_chk, struct sctp_asconf_chunk *);
2290	bzero(acp, sizeof(struct sctp_asconf_chunk));
2291	/* save pointers to lookup address and asconf params */
2292	lookup_ptr = (caddr_t)(acp + 1);	/* after the header */
2293	ptr = mtod(m_asconf, caddr_t);	/* beginning of cluster */
2294
2295	/* fill in chunk header info */
2296	acp->ch.chunk_type = SCTP_ASCONF;
2297	acp->ch.chunk_flags = 0;
2298	acp->serial_number = htonl(stcb->asoc.asconf_seq_out);
2299
2300	/* add parameters... up to smallest MTU allowed */
2301	TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) {
2302		/* get the parameter length */
2303		p_length = SCTP_SIZE32(aa->ap.aph.ph.param_length);
2304		/* will it fit in current chunk? */
2305		if (m_asconf->m_len + p_length > stcb->asoc.smallest_mtu) {
2306			/* won't fit, so we're done with this chunk */
2307			break;
2308		}
2309		/* assign (and store) a correlation id */
2310		aa->ap.aph.correlation_id = correlation_id++;
2311
2312		/*
2313		 * fill in address if we're doing a delete this is a simple
2314		 * way for us to fill in the correlation address, which
2315		 * should only be used by the peer if we're deleting our
2316		 * source address and adding a new address (e.g. renumbering
2317		 * case)
2318		 */
2319		if (lookup_used == 0 &&
2320		    aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS) {
2321			struct sctp_ipv6addr_param *lookup;
2322			uint16_t p_size, addr_size;
2323
2324			lookup = (struct sctp_ipv6addr_param *)lookup_ptr;
2325			lookup->ph.param_type =
2326			    htons(aa->ap.addrp.ph.param_type);
2327			if (aa->ap.addrp.ph.param_type == SCTP_IPV6_ADDRESS) {
2328				/* copy IPv6 address */
2329				p_size = sizeof(struct sctp_ipv6addr_param);
2330				addr_size = sizeof(struct in6_addr);
2331			} else {
2332				/* copy IPv4 address */
2333				p_size = sizeof(struct sctp_ipv4addr_param);
2334				addr_size = sizeof(struct in_addr);
2335			}
2336			lookup->ph.param_length = htons(SCTP_SIZE32(p_size));
2337			memcpy(lookup->addr, &aa->ap.addrp.addr, addr_size);
2338			m_asconf_chk->m_len += SCTP_SIZE32(p_size);
2339			lookup_used = 1;
2340		}
2341		/* copy into current space */
2342		memcpy(ptr, &aa->ap, p_length);
2343
2344		/* network elements and update lengths */
2345		aph = (struct sctp_asconf_paramhdr *)ptr;
2346		aap = (struct sctp_asconf_addr_param *)ptr;
2347		/* correlation_id is transparent to peer, no htonl needed */
2348		aph->ph.param_type = htons(aph->ph.param_type);
2349		aph->ph.param_length = htons(aph->ph.param_length);
2350		aap->addrp.ph.param_type = htons(aap->addrp.ph.param_type);
2351		aap->addrp.ph.param_length = htons(aap->addrp.ph.param_length);
2352
2353		m_asconf->m_len += SCTP_SIZE32(p_length);
2354		ptr += SCTP_SIZE32(p_length);
2355
2356		/*
2357		 * these params are removed off the pending list upon
2358		 * getting an ASCONF-ACK back from the peer, just set flag
2359		 */
2360		aa->sent = 1;
2361	}
2362	/* check to see if the lookup addr has been populated yet */
2363	if (lookup_used == 0) {
2364		/* NOTE: if the address param is optional, can skip this... */
2365		/* add any valid (existing) address... */
2366		struct sctp_ipv6addr_param *lookup;
2367		uint16_t p_size, addr_size;
2368		struct sockaddr *found_addr;
2369		caddr_t addr_ptr;
2370
2371		if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL)
2372			found_addr = sctp_find_valid_localaddr(stcb);
2373		else
2374			found_addr = sctp_find_valid_localaddr_ep(stcb);
2375
2376		lookup = (struct sctp_ipv6addr_param *)lookup_ptr;
2377		if (found_addr != NULL) {
2378			if (found_addr->sa_family == AF_INET6) {
2379				/* copy IPv6 address */
2380				lookup->ph.param_type =
2381				    htons(SCTP_IPV6_ADDRESS);
2382				p_size = sizeof(struct sctp_ipv6addr_param);
2383				addr_size = sizeof(struct in6_addr);
2384				addr_ptr = (caddr_t)&((struct sockaddr_in6 *)
2385				    found_addr)->sin6_addr;
2386			} else {
2387				/* copy IPv4 address */
2388				lookup->ph.param_type =
2389				    htons(SCTP_IPV4_ADDRESS);
2390				p_size = sizeof(struct sctp_ipv4addr_param);
2391				addr_size = sizeof(struct in_addr);
2392				addr_ptr = (caddr_t)&((struct sockaddr_in *)
2393				    found_addr)->sin_addr;
2394			}
2395			lookup->ph.param_length = htons(SCTP_SIZE32(p_size));
2396			memcpy(lookup->addr, addr_ptr, addr_size);
2397			m_asconf_chk->m_len += SCTP_SIZE32(p_size);
2398			lookup_used = 1;
2399		} else {
2400			/* uh oh... don't have any address?? */
2401#ifdef SCTP_DEBUG
2402			if (sctp_debug_on & SCTP_DEBUG_ASCONF1)
2403				printf("compose_asconf: no lookup addr!\n");
2404#endif				/* SCTP_DEBUG */
2405			/* for now, we send a IPv4 address of 0.0.0.0 */
2406			lookup->ph.param_type = htons(SCTP_IPV4_ADDRESS);
2407			lookup->ph.param_length = htons(SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param)));
2408			bzero(lookup->addr, sizeof(struct in_addr));
2409			m_asconf_chk->m_len += SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param));
2410			lookup_used = 1;
2411		}
2412	}
2413	/* chain it all together */
2414	m_asconf_chk->m_next = m_asconf;
2415	m_asconf_chk->m_pkthdr.len = m_asconf_chk->m_len + m_asconf->m_len;
2416	acp->ch.chunk_length = ntohs(m_asconf_chk->m_pkthdr.len);
2417
2418	/* update "sent" flag */
2419	stcb->asoc.asconf_sent++;
2420
2421	return (m_asconf_chk);
2422}
2423
2424/*
2425 * section to handle address changes before an association is up eg. changes
2426 * during INIT/INIT-ACK/COOKIE-ECHO handshake
2427 */
2428
2429/*
2430 * processes the (local) addresses in the INIT-ACK chunk
2431 */
2432static void
2433sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m,
2434    unsigned int offset, unsigned int length)
2435{
2436	struct sctp_paramhdr tmp_param, *ph;
2437	uint16_t plen, ptype;
2438	struct sctp_ipv6addr_param addr_store;
2439	struct sockaddr_in6 sin6;
2440	struct sockaddr_in sin;
2441	struct sockaddr *sa;
2442	struct ifaddr *ifa;
2443
2444#ifdef SCTP_DEBUG
2445	if (sctp_debug_on & SCTP_DEBUG_ASCONF2) {
2446		printf("processing init-ack addresses\n");
2447	}
2448#endif				/* SCTP_DEBUG */
2449
2450	/* convert to upper bound */
2451	length += offset;
2452
2453	if ((offset + sizeof(struct sctp_paramhdr)) > length) {
2454		return;
2455	}
2456	/* init the addresses */
2457	bzero(&sin6, sizeof(sin6));
2458	sin6.sin6_family = AF_INET6;
2459	sin6.sin6_len = sizeof(sin6);
2460	sin6.sin6_port = stcb->rport;
2461
2462	bzero(&sin, sizeof(sin));
2463	sin.sin_len = sizeof(sin);
2464	sin.sin_family = AF_INET;
2465	sin.sin_port = stcb->rport;
2466
2467	/* go through the addresses in the init-ack */
2468	ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset,
2469	    sizeof(struct sctp_paramhdr), (uint8_t *) & tmp_param);
2470	while (ph != NULL) {
2471		ptype = ntohs(ph->param_type);
2472		plen = ntohs(ph->param_length);
2473		if (ptype == SCTP_IPV6_ADDRESS) {
2474			struct sctp_ipv6addr_param *a6p;
2475
2476			/* get the entire IPv6 address param */
2477			a6p = (struct sctp_ipv6addr_param *)
2478			    sctp_m_getptr(m, offset,
2479			    sizeof(struct sctp_ipv6addr_param),
2480			    (uint8_t *) & addr_store);
2481			if (plen != sizeof(struct sctp_ipv6addr_param) ||
2482			    a6p == NULL) {
2483				return;
2484			}
2485			memcpy(&sin6.sin6_addr, a6p->addr,
2486			    sizeof(struct in6_addr));
2487			sa = (struct sockaddr *)&sin6;
2488		} else if (ptype == SCTP_IPV4_ADDRESS) {
2489			struct sctp_ipv4addr_param *a4p;
2490
2491			/* get the entire IPv4 address param */
2492			a4p = (struct sctp_ipv4addr_param *)sctp_m_getptr(m, offset, sizeof(struct sctp_ipv4addr_param), (uint8_t *) & addr_store);
2493			if (plen != sizeof(struct sctp_ipv4addr_param) ||
2494			    a4p == NULL) {
2495				return;
2496			}
2497			sin.sin_addr.s_addr = a4p->addr;
2498			sa = (struct sockaddr *)&sin;
2499		} else {
2500			goto next_addr;
2501		}
2502
2503		/* see if this address really (still) exists */
2504		ifa = sctp_find_ifa_by_addr(sa);
2505		if (ifa == NULL) {
2506			/* address doesn't exist anymore */
2507			int status;
2508
2509			/* are ASCONFs allowed ? */
2510			if ((sctp_is_feature_on(stcb->sctp_ep,
2511			    SCTP_PCB_FLAGS_DO_ASCONF)) &&
2512			    stcb->asoc.peer_supports_asconf) {
2513				/* queue an ASCONF DEL_IP_ADDRESS */
2514				status = sctp_asconf_queue_add_sa(stcb, sa,
2515				    SCTP_DEL_IP_ADDRESS);
2516				/*
2517				 * if queued ok, and in correct state, set
2518				 * the ASCONF timer
2519				 */
2520				if (status == 0 &&
2521				    SCTP_GET_STATE(&stcb->asoc) ==
2522				    SCTP_STATE_OPEN) {
2523					sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
2524					    stcb->sctp_ep, stcb,
2525					    stcb->asoc.primary_destination);
2526				}
2527			}
2528		} else {
2529			/* address still exists */
2530			/*
2531			 * if subset bound, ep addr's managed by default if
2532			 * not doing ASCONF, add the address to the assoc
2533			 */
2534			if ((stcb->sctp_ep->sctp_flags &
2535			    SCTP_PCB_FLAGS_BOUNDALL) == 0 &&
2536			    (sctp_is_feature_off(stcb->sctp_ep,
2537			    SCTP_PCB_FLAGS_DO_ASCONF))) {
2538#ifdef SCTP_DEBUG
2539				if (sctp_debug_on & SCTP_DEBUG_ASCONF2) {
2540					printf("process_initack_addrs: adding local addr to asoc\n");
2541				}
2542#endif				/* SCTP_DEBUG */
2543				sctp_add_local_addr_assoc(stcb, ifa);
2544			}
2545		}
2546
2547next_addr:
2548		/*
2549		 * Sanity check:  Make sure the length isn't 0, otherwise
2550		 * we'll be stuck in this loop for a long time...
2551		 */
2552		if (SCTP_SIZE32(plen) == 0) {
2553#ifdef SCTP_DEBUG
2554			printf("process_initack_addrs: bad len (%d) type=%xh\n",
2555			    plen, ptype);
2556#endif
2557			return;
2558		}
2559		/* get next parameter */
2560		offset += SCTP_SIZE32(plen);
2561		if ((offset + sizeof(struct sctp_paramhdr)) > length)
2562			return;
2563		ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset,
2564		    sizeof(struct sctp_paramhdr), (uint8_t *) & tmp_param);
2565	}			/* while */
2566}
2567
2568/* FIX ME: need to verify return result for v6 address type if v6 disabled */
2569/*
2570 * checks to see if a specific address is in the initack address list returns
2571 * 1 if found, 0 if not
2572 */
2573static uint32_t
2574sctp_addr_in_initack(struct sctp_tcb *stcb, struct mbuf *m, uint32_t offset,
2575    uint32_t length, struct sockaddr *sa)
2576{
2577	struct sctp_paramhdr tmp_param, *ph;
2578	uint16_t plen, ptype;
2579	struct sctp_ipv6addr_param addr_store;
2580	struct sockaddr_in *sin;
2581	struct sctp_ipv4addr_param *a4p;
2582
2583#ifdef INET6
2584	struct sockaddr_in6 *sin6, sin6_tmp;
2585	struct sctp_ipv6addr_param *a6p;
2586
2587#endif				/* INET6 */
2588
2589	if (
2590#ifdef INET6
2591	    (sa->sa_family != AF_INET6) &&
2592#endif				/* INET6 */
2593	    (sa->sa_family != AF_INET))
2594		return (0);
2595
2596#ifdef SCTP_DEBUG
2597	if (sctp_debug_on & SCTP_DEBUG_ASCONF2) {
2598		printf("find_initack_addr: starting search for ");
2599		sctp_print_address(sa);
2600	}
2601#endif				/* SCTP_DEBUG */
2602	/* convert to upper bound */
2603	length += offset;
2604
2605	if ((offset + sizeof(struct sctp_paramhdr)) > length) {
2606#ifdef SCTP_DEBUG
2607		if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
2608			printf("find_initack_addr: invalid offset?\n");
2609		}
2610#endif				/* SCTP_DEBUG */
2611		return (0);
2612	}
2613	/* go through the addresses in the init-ack */
2614	ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset,
2615	    sizeof(struct sctp_paramhdr), (uint8_t *) & tmp_param);
2616	while (ph != NULL) {
2617		ptype = ntohs(ph->param_type);
2618		plen = ntohs(ph->param_length);
2619#ifdef INET6
2620		if (ptype == SCTP_IPV6_ADDRESS && sa->sa_family == AF_INET6) {
2621			/* get the entire IPv6 address param */
2622			a6p = (struct sctp_ipv6addr_param *)
2623			    sctp_m_getptr(m, offset,
2624			    sizeof(struct sctp_ipv6addr_param),
2625			    (uint8_t *) & addr_store);
2626			if (plen != sizeof(struct sctp_ipv6addr_param) ||
2627			    ph == NULL) {
2628				return (0);
2629			}
2630			sin6 = (struct sockaddr_in6 *)sa;
2631			if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) {
2632				/* create a copy and clear scope */
2633				memcpy(&sin6_tmp, sin6,
2634				    sizeof(struct sockaddr_in6));
2635				sin6 = &sin6_tmp;
2636				in6_clearscope(&sin6->sin6_addr);
2637			}
2638			if (memcmp(&sin6->sin6_addr, a6p->addr,
2639			    sizeof(struct in6_addr)) == 0) {
2640				/* found it */
2641				return (1);
2642			}
2643		} else
2644#endif				/* INET6 */
2645
2646			if (ptype == SCTP_IPV4_ADDRESS &&
2647		    sa->sa_family == AF_INET) {
2648			/* get the entire IPv4 address param */
2649			a4p = (struct sctp_ipv4addr_param *)sctp_m_getptr(m,
2650			    offset, sizeof(struct sctp_ipv4addr_param),
2651			    (uint8_t *) & addr_store);
2652			if (plen != sizeof(struct sctp_ipv4addr_param) ||
2653			    ph == NULL) {
2654				return (0);
2655			}
2656			sin = (struct sockaddr_in *)sa;
2657			if (sin->sin_addr.s_addr == a4p->addr) {
2658				/* found it */
2659				return (1);
2660			}
2661		}
2662		/* get next parameter */
2663		offset += SCTP_SIZE32(plen);
2664		if (offset + sizeof(struct sctp_paramhdr) > length)
2665			return (0);
2666		ph = (struct sctp_paramhdr *)
2667		    sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr),
2668		    (uint8_t *) & tmp_param);
2669	}			/* while */
2670	/* not found! */
2671	return (0);
2672}
2673
2674/*
2675 * makes sure that the current endpoint local addr list is consistent with
2676 * the new association (eg. subset bound, asconf allowed) adds addresses as
2677 * necessary
2678 */
2679static void
2680sctp_check_address_list_ep(struct sctp_tcb *stcb, struct mbuf *m, int offset,
2681    int length, struct sockaddr *init_addr)
2682{
2683	struct sctp_laddr *laddr;
2684
2685	/* go through the endpoint list */
2686	LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) {
2687		/* be paranoid and validate the laddr */
2688		if (laddr->ifa == NULL) {
2689#ifdef SCTP_DEBUG
2690			if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
2691				printf("check_addr_list_ep: laddr->ifa is NULL");
2692			}
2693#endif				/* SCTP_DEBUG */
2694			continue;
2695		}
2696		if (laddr->ifa->ifa_addr == NULL) {
2697#ifdef SCTP_DEBUG
2698			if (sctp_debug_on & SCTP_DEBUG_ASCONF1) {
2699				printf("check_addr_list_ep: laddr->ifa->ifa_addr is NULL");
2700			}
2701#endif				/* SCTP_DEBUG */
2702			continue;
2703		}
2704		/* do i have it implicitly? */
2705		if (sctp_cmpaddr(laddr->ifa->ifa_addr, init_addr)) {
2706			continue;
2707		}
2708		/* check to see if in the init-ack */
2709		if (!sctp_addr_in_initack(stcb, m, offset, length,
2710		    laddr->ifa->ifa_addr)) {
2711			/* try to add it */
2712			sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb, laddr->ifa,
2713			    SCTP_ADD_IP_ADDRESS);
2714		}
2715	}
2716}
2717
2718/*
2719 * makes sure that the current kernel address list is consistent with the new
2720 * association (with all addrs bound) adds addresses as necessary
2721 */
2722static void
2723sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset,
2724    int length, struct sockaddr *init_addr,
2725    uint16_t local_scope, uint16_t site_scope,
2726    uint16_t ipv4_scope, uint16_t loopback_scope)
2727{
2728	struct ifnet *ifn;
2729	struct ifaddr *ifa;
2730
2731	/* go through all our known interfaces */
2732	TAILQ_FOREACH(ifn, &ifnet, if_list) {
2733		if (loopback_scope == 0 && ifn->if_type == IFT_LOOP) {
2734			/* skip loopback interface */
2735			continue;
2736		}
2737		/* go through each interface address */
2738		TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) {
2739			/* do i have it implicitly? */
2740			if (sctp_cmpaddr(ifa->ifa_addr, init_addr)) {
2741				continue;
2742			}
2743			/* check to see if in the init-ack */
2744			if (!sctp_addr_in_initack(stcb, m, offset, length,
2745			    ifa->ifa_addr)) {
2746				/* try to add it */
2747				sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb,
2748				    ifa, SCTP_ADD_IP_ADDRESS);
2749			}
2750		}		/* end foreach ifa */
2751	}			/* end foreach ifn */
2752}
2753
2754/*
2755 * validates an init-ack chunk (from a cookie-echo) with current addresses
2756 * adds addresses from the init-ack into our local address list, if needed
2757 * queues asconf adds/deletes addresses as needed and makes appropriate list
2758 * changes for source address selection m, offset: points to the start of the
2759 * address list in an init-ack chunk length: total length of the address
2760 * params only init_addr: address where my INIT-ACK was sent from
2761 */
2762void
2763sctp_check_address_list(struct sctp_tcb *stcb, struct mbuf *m, int offset,
2764    int length, struct sockaddr *init_addr,
2765    uint16_t local_scope, uint16_t site_scope,
2766    uint16_t ipv4_scope, uint16_t loopback_scope)
2767{
2768	/* process the local addresses in the initack */
2769	sctp_process_initack_addresses(stcb, m, offset, length);
2770
2771	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
2772		/* bound all case */
2773		sctp_check_address_list_all(stcb, m, offset, length, init_addr,
2774		    local_scope, site_scope, ipv4_scope, loopback_scope);
2775	} else {
2776		/* subset bound case */
2777		if (sctp_is_feature_on(stcb->sctp_ep,
2778		    SCTP_PCB_FLAGS_DO_ASCONF)) {
2779			/* asconf's allowed */
2780			sctp_check_address_list_ep(stcb, m, offset, length,
2781			    init_addr);
2782		}
2783		/* else, no asconfs allowed, so what we sent is what we get */
2784	}
2785}
2786
2787/*
2788 * sctp_bindx() support
2789 */
2790uint32_t
2791sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, uint16_t type)
2792{
2793	struct ifaddr *ifa;
2794
2795
2796	if (sa->sa_len == 0)
2797		return (EINVAL);
2798
2799	ifa = sctp_find_ifa_by_addr(sa);
2800	if (ifa != NULL) {
2801#ifdef INET6
2802		if (ifa->ifa_addr->sa_family == AF_INET6) {
2803			struct in6_ifaddr *ifa6;
2804
2805			ifa6 = (struct in6_ifaddr *)ifa;
2806			if (IFA6_IS_DEPRECATED(ifa6) ||
2807			    (ifa6->ia6_flags & (IN6_IFF_DETACHED |
2808			    IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
2809				/* Can't bind a non-existent addr. */
2810				return (EINVAL);
2811			}
2812		}
2813#endif				/* INET6 */
2814		/* add this address */
2815		sctp_addr_mgmt_ep(inp, ifa, type);
2816	} else {
2817		/* invalid address! */
2818		return (EADDRNOTAVAIL);
2819	}
2820	return (0);
2821}
2822
2823void
2824sctp_addr_change(struct ifaddr *ifa, int cmd)
2825{
2826	struct sctp_laddr *wi;
2827
2828	wi = (struct sctp_laddr *)SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr);
2829	if (wi == NULL) {
2830		/*
2831		 * Gak, what can we do? We have lost an address change can
2832		 * you say HOSED?
2833		 */
2834#ifdef SCTP_DEBUG
2835		if (sctp_debug_on & SCTP_DEBUG_PCB1) {
2836			printf("Lost and address change ???\n");
2837		}
2838#endif				/* SCTP_DEBUG */
2839		return;
2840	}
2841	SCTP_INCR_LADDR_COUNT();
2842	bzero(wi, sizeof(*wi));
2843	wi->ifa = ifa;
2844	IFAREF(ifa);
2845
2846	wi->action = cmd;
2847	SCTP_IPI_ADDR_LOCK();
2848	/*
2849	 * Should this really be a tailq? As it is we will process the
2850	 * newest first :-0
2851	 */
2852	LIST_INSERT_HEAD(&sctppcbinfo.addr_wq, wi, sctp_nxt_addr);
2853	sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
2854	    (struct sctp_inpcb *)NULL,
2855	    (struct sctp_tcb *)NULL,
2856	    (struct sctp_nets *)NULL);
2857	SCTP_IPI_ADDR_UNLOCK();
2858}
2859