1163953Srrs/*-
2169382Srrs * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
3235828Stuexen * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
4235828Stuexen * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
5163953Srrs *
6163953Srrs * Redistribution and use in source and binary forms, with or without
7163953Srrs * modification, are permitted provided that the following conditions are met:
8163953Srrs *
9163953Srrs * a) Redistributions of source code must retain the above copyright notice,
10228653Stuexen *    this list of conditions and the following disclaimer.
11163953Srrs *
12163953Srrs * b) Redistributions in binary form must reproduce the above copyright
13163953Srrs *    notice, this list of conditions and the following disclaimer in
14228653Stuexen *    the documentation and/or other materials provided with the distribution.
15163953Srrs *
16163953Srrs * c) Neither the name of Cisco Systems, Inc. nor the names of its
17163953Srrs *    contributors may be used to endorse or promote products derived
18163953Srrs *    from this software without specific prior written permission.
19163953Srrs *
20163953Srrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21163953Srrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22163953Srrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24163953Srrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25163953Srrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26163953Srrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27163953Srrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28163953Srrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29163953Srrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30163953Srrs * THE POSSIBILITY OF SUCH DAMAGE.
31163953Srrs */
32163953Srrs
33163953Srrs#include <sys/cdefs.h>
34163957Srrs__FBSDID("$FreeBSD: stable/11/sys/netinet/sctp_asconf.c 361476 2020-05-25 20:17:34Z tuexen $");
35235828Stuexen
36163953Srrs#include <netinet/sctp_os.h>
37163953Srrs#include <netinet/sctp_var.h>
38167598Srrs#include <netinet/sctp_sysctl.h>
39163953Srrs#include <netinet/sctp_pcb.h>
40163953Srrs#include <netinet/sctp_header.h>
41163953Srrs#include <netinet/sctputil.h>
42163953Srrs#include <netinet/sctp_output.h>
43163953Srrs#include <netinet/sctp_asconf.h>
44172091Srrs#include <netinet/sctp_timer.h>
45163953Srrs
46163953Srrs/*
47163953Srrs * debug flags:
48163953Srrs * SCTP_DEBUG_ASCONF1: protocol info, general info and errors
49163953Srrs * SCTP_DEBUG_ASCONF2: detailed info
50163953Srrs */
51163953Srrs
52163953Srrs
53163953Srrs/*
54237715Stuexen * RFC 5061
55163953Srrs *
56163953Srrs * An ASCONF parameter queue exists per asoc which holds the pending address
57163953Srrs * operations.  Lists are updated upon receipt of ASCONF-ACK.
58163953Srrs *
59171477Srrs * A restricted_addrs list exists per assoc to hold local addresses that are
60171477Srrs * not (yet) usable by the assoc as a source address.  These addresses are
61171477Srrs * either pending an ASCONF operation (and exist on the ASCONF parameter
62171477Srrs * queue), or they are permanently restricted (the peer has returned an
63171477Srrs * ERROR indication to an ASCONF(ADD), or the peer does not support ASCONF).
64171477Srrs *
65163953Srrs * Deleted addresses are always immediately removed from the lists as they will
66163953Srrs * (shortly) no longer exist in the kernel.  We send ASCONFs as a courtesy,
67163953Srrs * only if allowed.
68163953Srrs */
69163953Srrs
70163953Srrs/*
71171477Srrs * ASCONF parameter processing.
72171477Srrs * response_required: set if a reply is required (eg. SUCCESS_REPORT).
73171477Srrs * returns a mbuf to an "error" response parameter or NULL/"success" if ok.
74171477Srrs * FIX: allocating this many mbufs on the fly is pretty inefficient...
75163953Srrs */
76163953Srrsstatic struct mbuf *
77163953Srrssctp_asconf_success_response(uint32_t id)
78163953Srrs{
79163953Srrs	struct mbuf *m_reply = NULL;
80163953Srrs	struct sctp_asconf_paramhdr *aph;
81163953Srrs
82163953Srrs	m_reply = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_paramhdr),
83243882Sglebius	    0, M_NOWAIT, 1, MT_DATA);
84163953Srrs	if (m_reply == NULL) {
85169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
86169420Srrs		    "asconf_success_response: couldn't get mbuf!\n");
87228907Stuexen		return (NULL);
88163953Srrs	}
89163953Srrs	aph = mtod(m_reply, struct sctp_asconf_paramhdr *);
90163953Srrs	aph->correlation_id = id;
91163953Srrs	aph->ph.param_type = htons(SCTP_SUCCESS_REPORT);
92163953Srrs	aph->ph.param_length = sizeof(struct sctp_asconf_paramhdr);
93165647Srrs	SCTP_BUF_LEN(m_reply) = aph->ph.param_length;
94163953Srrs	aph->ph.param_length = htons(aph->ph.param_length);
95163953Srrs
96228907Stuexen	return (m_reply);
97163953Srrs}
98163953Srrs
99163953Srrsstatic struct mbuf *
100310773Stuexensctp_asconf_error_response(uint32_t id, uint16_t cause, uint8_t *error_tlv,
101163953Srrs    uint16_t tlv_length)
102163953Srrs{
103163953Srrs	struct mbuf *m_reply = NULL;
104163953Srrs	struct sctp_asconf_paramhdr *aph;
105163953Srrs	struct sctp_error_cause *error;
106360740Stuexen	size_t buf_len;
107360740Stuexen	uint16_t i, param_length, cause_length, padding_length;
108163953Srrs	uint8_t *tlv;
109163953Srrs
110360740Stuexen	if (error_tlv == NULL) {
111360740Stuexen		tlv_length = 0;
112360740Stuexen	}
113360740Stuexen	cause_length = sizeof(struct sctp_error_cause) + tlv_length;
114360740Stuexen	param_length = sizeof(struct sctp_asconf_paramhdr) + cause_length;
115360740Stuexen	padding_length = tlv_length % 4;
116360740Stuexen	if (padding_length != 0) {
117360740Stuexen		padding_length = 4 - padding_length;
118360740Stuexen	}
119360740Stuexen	buf_len = param_length + padding_length;
120360740Stuexen	if (buf_len > MLEN) {
121360740Stuexen		SCTPDBG(SCTP_DEBUG_ASCONF1,
122360740Stuexen		    "asconf_error_response: tlv_length (%xh) too big\n",
123360740Stuexen		    tlv_length);
124360740Stuexen		return (NULL);
125360740Stuexen	}
126360740Stuexen	m_reply = sctp_get_mbuf_for_msg(buf_len, 0, M_NOWAIT, 1, MT_DATA);
127163953Srrs	if (m_reply == NULL) {
128169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
129169420Srrs		    "asconf_error_response: couldn't get mbuf!\n");
130228907Stuexen		return (NULL);
131163953Srrs	}
132163953Srrs	aph = mtod(m_reply, struct sctp_asconf_paramhdr *);
133360740Stuexen	aph->ph.param_type = htons(SCTP_ERROR_CAUSE_IND);
134360740Stuexen	aph->ph.param_length = htons(param_length);
135360740Stuexen	aph->correlation_id = id;
136163953Srrs	error = (struct sctp_error_cause *)(aph + 1);
137163953Srrs	error->code = htons(cause);
138360740Stuexen	error->length = htons(cause_length);
139163953Srrs	if (error_tlv != NULL) {
140310773Stuexen		tlv = (uint8_t *)(error + 1);
141163953Srrs		memcpy(tlv, error_tlv, tlv_length);
142360740Stuexen		for (i = 0; i < padding_length; i++) {
143360740Stuexen			tlv[tlv_length + i] = 0;
144360740Stuexen		}
145163953Srrs	}
146360740Stuexen	SCTP_BUF_LEN(m_reply) = buf_len;
147228907Stuexen	return (m_reply);
148163953Srrs}
149163953Srrs
150163953Srrsstatic struct mbuf *
151237715Stuexensctp_process_asconf_add_ip(struct sockaddr *src, struct sctp_asconf_paramhdr *aph,
152224641Stuexen    struct sctp_tcb *stcb, int send_hb, int response_required)
153163953Srrs{
154224641Stuexen	struct sctp_nets *net;
155163953Srrs	struct mbuf *m_reply = NULL;
156271221Stuexen	union sctp_sockstore store;
157221249Stuexen	struct sctp_paramhdr *ph;
158257555Stuexen	uint16_t param_type, aparam_length;
159257555Stuexen#if defined(INET) || defined(INET6)
160257555Stuexen	uint16_t param_length;
161257555Stuexen#endif
162163953Srrs	struct sockaddr *sa;
163163953Srrs	int zero_address = 0;
164225571Stuexen	int bad_address = 0;
165221249Stuexen#ifdef INET
166221249Stuexen	struct sockaddr_in *sin;
167221249Stuexen	struct sctp_ipv4addr_param *v4addr;
168221249Stuexen#endif
169163953Srrs#ifdef INET6
170163953Srrs	struct sockaddr_in6 *sin6;
171163953Srrs	struct sctp_ipv6addr_param *v6addr;
172221249Stuexen#endif
173163953Srrs
174163953Srrs	aparam_length = ntohs(aph->ph.param_length);
175360739Stuexen	if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) {
176360739Stuexen		return (NULL);
177360739Stuexen	}
178221249Stuexen	ph = (struct sctp_paramhdr *)(aph + 1);
179221249Stuexen	param_type = ntohs(ph->param_type);
180257555Stuexen#if defined(INET) || defined(INET6)
181221249Stuexen	param_length = ntohs(ph->param_length);
182360739Stuexen	if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) {
183360739Stuexen		return (NULL);
184360739Stuexen	}
185257555Stuexen#endif
186271221Stuexen	sa = &store.sa;
187163953Srrs	switch (param_type) {
188221249Stuexen#ifdef INET
189163953Srrs	case SCTP_IPV4_ADDRESS:
190163953Srrs		if (param_length != sizeof(struct sctp_ipv4addr_param)) {
191163953Srrs			/* invalid param size */
192228907Stuexen			return (NULL);
193163953Srrs		}
194221249Stuexen		v4addr = (struct sctp_ipv4addr_param *)ph;
195271221Stuexen		sin = &store.sin;
196332172Stuexen		memset(sin, 0, sizeof(*sin));
197163953Srrs		sin->sin_family = AF_INET;
198163953Srrs		sin->sin_len = sizeof(struct sockaddr_in);
199163953Srrs		sin->sin_port = stcb->rport;
200163953Srrs		sin->sin_addr.s_addr = v4addr->addr;
201225571Stuexen		if ((sin->sin_addr.s_addr == INADDR_BROADCAST) ||
202225571Stuexen		    IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
203225584Stuexen			bad_address = 1;
204225571Stuexen		}
205163953Srrs		if (sin->sin_addr.s_addr == INADDR_ANY)
206163953Srrs			zero_address = 1;
207169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: adding ");
208169420Srrs		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
209163953Srrs		break;
210221249Stuexen#endif
211221249Stuexen#ifdef INET6
212163953Srrs	case SCTP_IPV6_ADDRESS:
213163953Srrs		if (param_length != sizeof(struct sctp_ipv6addr_param)) {
214163953Srrs			/* invalid param size */
215228907Stuexen			return (NULL);
216163953Srrs		}
217221249Stuexen		v6addr = (struct sctp_ipv6addr_param *)ph;
218271221Stuexen		sin6 = &store.sin6;
219332172Stuexen		memset(sin6, 0, sizeof(*sin6));
220163953Srrs		sin6->sin6_family = AF_INET6;
221163953Srrs		sin6->sin6_len = sizeof(struct sockaddr_in6);
222163953Srrs		sin6->sin6_port = stcb->rport;
223163953Srrs		memcpy((caddr_t)&sin6->sin6_addr, v6addr->addr,
224163953Srrs		    sizeof(struct in6_addr));
225225571Stuexen		if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
226225571Stuexen			bad_address = 1;
227225571Stuexen		}
228163953Srrs		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
229163953Srrs			zero_address = 1;
230169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: adding ");
231169420Srrs		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
232221249Stuexen		break;
233169420Srrs#endif
234163953Srrs	default:
235163953Srrs		m_reply = sctp_asconf_error_response(aph->correlation_id,
236310773Stuexen		    SCTP_CAUSE_INVALID_PARAM, (uint8_t *)aph,
237163953Srrs		    aparam_length);
238228907Stuexen		return (m_reply);
239163953Srrs	}			/* end switch */
240163953Srrs
241163953Srrs	/* if 0.0.0.0/::0, add the source address instead */
242179783Srrs	if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) {
243237715Stuexen		sa = src;
244169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
245169420Srrs		    "process_asconf_add_ip: using source addr ");
246237715Stuexen		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src);
247163953Srrs	}
248360738Stuexen	net = NULL;
249163953Srrs	/* add the address */
250225571Stuexen	if (bad_address) {
251225571Stuexen		m_reply = sctp_asconf_error_response(aph->correlation_id,
252310773Stuexen		    SCTP_CAUSE_INVALID_PARAM, (uint8_t *)aph,
253225571Stuexen		    aparam_length);
254298847Stuexen	} else if (sctp_add_remote_addr(stcb, sa, &net, stcb->asoc.port,
255298847Stuexen		    SCTP_DONOT_SETSCOPE,
256165220Srrs	    SCTP_ADDR_DYNAMIC_ADDED) != 0) {
257169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
258169420Srrs		    "process_asconf_add_ip: error adding address\n");
259163953Srrs		m_reply = sctp_asconf_error_response(aph->correlation_id,
260310773Stuexen		    SCTP_CAUSE_RESOURCE_SHORTAGE, (uint8_t *)aph,
261163953Srrs		    aparam_length);
262163953Srrs	} else {
263163953Srrs		if (response_required) {
264163953Srrs			m_reply =
265163953Srrs			    sctp_asconf_success_response(aph->correlation_id);
266163953Srrs		}
267360738Stuexen		if (net != NULL) {
268360738Stuexen			/* notify upper layer */
269360738Stuexen			sctp_ulp_notify(SCTP_NOTIFY_ASCONF_ADD_IP, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
270360738Stuexen			sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net);
271360738Stuexen			sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep,
272360738Stuexen			    stcb, net);
273360738Stuexen			if (send_hb) {
274360738Stuexen				sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
275360738Stuexen			}
276224641Stuexen		}
277163953Srrs	}
278228907Stuexen	return (m_reply);
279163953Srrs}
280163953Srrs
281163953Srrsstatic int
282171572Srrssctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb, struct sockaddr *src)
283163953Srrs{
284360744Stuexen	struct sctp_nets *src_net, *net, *nnet;
285163953Srrs
286163953Srrs	/* make sure the source address exists as a destination net */
287163953Srrs	src_net = sctp_findnet(stcb, src);
288163953Srrs	if (src_net == NULL) {
289163953Srrs		/* not found */
290228907Stuexen		return (-1);
291163953Srrs	}
292347154Stuexen
293163953Srrs	/* delete all destination addresses except the source */
294360744Stuexen	TAILQ_FOREACH_SAFE(net, &stcb->asoc.nets, sctp_next, nnet) {
295163953Srrs		if (net != src_net) {
296163953Srrs			/* delete this address */
297169420Srrs			SCTPDBG(SCTP_DEBUG_ASCONF1,
298169420Srrs			    "asconf_del_remote_addrs_except: deleting ");
299169420Srrs			SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1,
300169420Srrs			    (struct sockaddr *)&net->ro._l_addr);
301163953Srrs			/* notify upper layer */
302163953Srrs			sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0,
303172090Srrs			    (struct sockaddr *)&net->ro._l_addr, SCTP_SO_NOT_LOCKED);
304360744Stuexen			sctp_remove_net(stcb, net);
305163953Srrs		}
306163953Srrs	}
307228907Stuexen	return (0);
308163953Srrs}
309163953Srrs
310163953Srrsstatic struct mbuf *
311237715Stuexensctp_process_asconf_delete_ip(struct sockaddr *src,
312237715Stuexen    struct sctp_asconf_paramhdr *aph,
313163953Srrs    struct sctp_tcb *stcb, int response_required)
314163953Srrs{
315163953Srrs	struct mbuf *m_reply = NULL;
316271221Stuexen	union sctp_sockstore store;
317221249Stuexen	struct sctp_paramhdr *ph;
318257555Stuexen	uint16_t param_type, aparam_length;
319257555Stuexen#if defined(INET) || defined(INET6)
320257555Stuexen	uint16_t param_length;
321257555Stuexen#endif
322163953Srrs	struct sockaddr *sa;
323163953Srrs	int zero_address = 0;
324163953Srrs	int result;
325221249Stuexen#ifdef INET
326221249Stuexen	struct sockaddr_in *sin;
327221249Stuexen	struct sctp_ipv4addr_param *v4addr;
328221249Stuexen#endif
329163953Srrs#ifdef INET6
330163953Srrs	struct sockaddr_in6 *sin6;
331163953Srrs	struct sctp_ipv6addr_param *v6addr;
332221249Stuexen#endif
333163953Srrs
334163953Srrs	aparam_length = ntohs(aph->ph.param_length);
335360739Stuexen	if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) {
336360739Stuexen		return (NULL);
337360739Stuexen	}
338360746Stuexen	ph = (struct sctp_paramhdr *)(aph + 1);
339360746Stuexen	param_type = ntohs(ph->param_type);
340257555Stuexen#if defined(INET) || defined(INET6)
341221249Stuexen	param_length = ntohs(ph->param_length);
342360739Stuexen	if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) {
343360739Stuexen		return (NULL);
344360739Stuexen	}
345257555Stuexen#endif
346271221Stuexen	sa = &store.sa;
347163953Srrs	switch (param_type) {
348221249Stuexen#ifdef INET
349163953Srrs	case SCTP_IPV4_ADDRESS:
350163953Srrs		if (param_length != sizeof(struct sctp_ipv4addr_param)) {
351163953Srrs			/* invalid param size */
352228907Stuexen			return (NULL);
353163953Srrs		}
354221249Stuexen		v4addr = (struct sctp_ipv4addr_param *)ph;
355271221Stuexen		sin = &store.sin;
356332172Stuexen		memset(sin, 0, sizeof(*sin));
357163953Srrs		sin->sin_family = AF_INET;
358163953Srrs		sin->sin_len = sizeof(struct sockaddr_in);
359163953Srrs		sin->sin_port = stcb->rport;
360163953Srrs		sin->sin_addr.s_addr = v4addr->addr;
361163953Srrs		if (sin->sin_addr.s_addr == INADDR_ANY)
362163953Srrs			zero_address = 1;
363169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
364169420Srrs		    "process_asconf_delete_ip: deleting ");
365169420Srrs		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
366163953Srrs		break;
367221249Stuexen#endif
368221249Stuexen#ifdef INET6
369163953Srrs	case SCTP_IPV6_ADDRESS:
370163953Srrs		if (param_length != sizeof(struct sctp_ipv6addr_param)) {
371163953Srrs			/* invalid param size */
372228907Stuexen			return (NULL);
373163953Srrs		}
374221249Stuexen		v6addr = (struct sctp_ipv6addr_param *)ph;
375271221Stuexen		sin6 = &store.sin6;
376332172Stuexen		memset(sin6, 0, sizeof(*sin6));
377163953Srrs		sin6->sin6_family = AF_INET6;
378163953Srrs		sin6->sin6_len = sizeof(struct sockaddr_in6);
379163953Srrs		sin6->sin6_port = stcb->rport;
380163953Srrs		memcpy(&sin6->sin6_addr, v6addr->addr,
381163953Srrs		    sizeof(struct in6_addr));
382163953Srrs		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
383163953Srrs			zero_address = 1;
384169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
385169420Srrs		    "process_asconf_delete_ip: deleting ");
386169420Srrs		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
387221249Stuexen		break;
388169420Srrs#endif
389163953Srrs	default:
390163953Srrs		m_reply = sctp_asconf_error_response(aph->correlation_id,
391310773Stuexen		    SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *)aph,
392163953Srrs		    aparam_length);
393228907Stuexen		return (m_reply);
394163953Srrs	}
395163953Srrs
396163953Srrs	/* make sure the source address is not being deleted */
397237715Stuexen	if (sctp_cmpaddr(sa, src)) {
398163953Srrs		/* trying to delete the source address! */
399169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: tried to delete source addr\n");
400163953Srrs		m_reply = sctp_asconf_error_response(aph->correlation_id,
401310773Stuexen		    SCTP_CAUSE_DELETING_SRC_ADDR, (uint8_t *)aph,
402163953Srrs		    aparam_length);
403228907Stuexen		return (m_reply);
404163953Srrs	}
405347154Stuexen
406163953Srrs	/* if deleting 0.0.0.0/::0, delete all addresses except src addr */
407179783Srrs	if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) {
408237715Stuexen		result = sctp_asconf_del_remote_addrs_except(stcb, src);
409163953Srrs
410163953Srrs		if (result) {
411163953Srrs			/* src address did not exist? */
412169420Srrs			SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: src addr does not exist?\n");
413163953Srrs			/* what error to reply with?? */
414163953Srrs			m_reply =
415163953Srrs			    sctp_asconf_error_response(aph->correlation_id,
416310773Stuexen			    SCTP_CAUSE_REQUEST_REFUSED, (uint8_t *)aph,
417163953Srrs			    aparam_length);
418163953Srrs		} else if (response_required) {
419163953Srrs			m_reply =
420163953Srrs			    sctp_asconf_success_response(aph->correlation_id);
421163953Srrs		}
422228907Stuexen		return (m_reply);
423163953Srrs	}
424347154Stuexen
425163953Srrs	/* delete the address */
426163953Srrs	result = sctp_del_remote_addr(stcb, sa);
427163953Srrs	/*
428163953Srrs	 * note if result == -2, the address doesn't exist in the asoc but
429163953Srrs	 * since it's being deleted anyways, we just ack the delete -- but
430163953Srrs	 * this probably means something has already gone awry
431163953Srrs	 */
432163953Srrs	if (result == -1) {
433163953Srrs		/* only one address in the asoc */
434169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: tried to delete last IP addr!\n");
435163953Srrs		m_reply = sctp_asconf_error_response(aph->correlation_id,
436310773Stuexen		    SCTP_CAUSE_DELETING_LAST_ADDR, (uint8_t *)aph,
437163953Srrs		    aparam_length);
438163953Srrs	} else {
439163953Srrs		if (response_required) {
440163953Srrs			m_reply = sctp_asconf_success_response(aph->correlation_id);
441163953Srrs		}
442163953Srrs		/* notify upper layer */
443172090Srrs		sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
444163953Srrs	}
445228907Stuexen	return (m_reply);
446163953Srrs}
447163953Srrs
448163953Srrsstatic struct mbuf *
449237715Stuexensctp_process_asconf_set_primary(struct sockaddr *src,
450171572Srrs    struct sctp_asconf_paramhdr *aph,
451171572Srrs    struct sctp_tcb *stcb, int response_required)
452163953Srrs{
453163953Srrs	struct mbuf *m_reply = NULL;
454271221Stuexen	union sctp_sockstore store;
455221249Stuexen	struct sctp_paramhdr *ph;
456257555Stuexen	uint16_t param_type, aparam_length;
457257555Stuexen#if defined(INET) || defined(INET6)
458257555Stuexen	uint16_t param_length;
459257555Stuexen#endif
460163953Srrs	struct sockaddr *sa;
461163953Srrs	int zero_address = 0;
462221249Stuexen#ifdef INET
463221249Stuexen	struct sockaddr_in *sin;
464221249Stuexen	struct sctp_ipv4addr_param *v4addr;
465221249Stuexen#endif
466163953Srrs#ifdef INET6
467163953Srrs	struct sockaddr_in6 *sin6;
468163953Srrs	struct sctp_ipv6addr_param *v6addr;
469221249Stuexen#endif
470163953Srrs
471163953Srrs	aparam_length = ntohs(aph->ph.param_length);
472360739Stuexen	if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) {
473360739Stuexen		return (NULL);
474360739Stuexen	}
475221249Stuexen	ph = (struct sctp_paramhdr *)(aph + 1);
476221249Stuexen	param_type = ntohs(ph->param_type);
477257555Stuexen#if defined(INET) || defined(INET6)
478221249Stuexen	param_length = ntohs(ph->param_length);
479360739Stuexen	if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) {
480360739Stuexen		return (NULL);
481360739Stuexen	}
482257555Stuexen#endif
483271221Stuexen	sa = &store.sa;
484163953Srrs	switch (param_type) {
485221249Stuexen#ifdef INET
486163953Srrs	case SCTP_IPV4_ADDRESS:
487163953Srrs		if (param_length != sizeof(struct sctp_ipv4addr_param)) {
488163953Srrs			/* invalid param size */
489228907Stuexen			return (NULL);
490163953Srrs		}
491221249Stuexen		v4addr = (struct sctp_ipv4addr_param *)ph;
492271221Stuexen		sin = &store.sin;
493332172Stuexen		memset(sin, 0, sizeof(*sin));
494163953Srrs		sin->sin_family = AF_INET;
495163953Srrs		sin->sin_len = sizeof(struct sockaddr_in);
496163953Srrs		sin->sin_addr.s_addr = v4addr->addr;
497163953Srrs		if (sin->sin_addr.s_addr == INADDR_ANY)
498163953Srrs			zero_address = 1;
499169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_set_primary: ");
500169420Srrs		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
501163953Srrs		break;
502221249Stuexen#endif
503221249Stuexen#ifdef INET6
504163953Srrs	case SCTP_IPV6_ADDRESS:
505163953Srrs		if (param_length != sizeof(struct sctp_ipv6addr_param)) {
506163953Srrs			/* invalid param size */
507228907Stuexen			return (NULL);
508163953Srrs		}
509221249Stuexen		v6addr = (struct sctp_ipv6addr_param *)ph;
510271221Stuexen		sin6 = &store.sin6;
511332172Stuexen		memset(sin6, 0, sizeof(*sin6));
512163953Srrs		sin6->sin6_family = AF_INET6;
513163953Srrs		sin6->sin6_len = sizeof(struct sockaddr_in6);
514163953Srrs		memcpy((caddr_t)&sin6->sin6_addr, v6addr->addr,
515163953Srrs		    sizeof(struct in6_addr));
516163953Srrs		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
517163953Srrs			zero_address = 1;
518169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_set_primary: ");
519169420Srrs		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
520221249Stuexen		break;
521169420Srrs#endif
522163953Srrs	default:
523163953Srrs		m_reply = sctp_asconf_error_response(aph->correlation_id,
524310773Stuexen		    SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *)aph,
525163953Srrs		    aparam_length);
526228907Stuexen		return (m_reply);
527163953Srrs	}
528163953Srrs
529163953Srrs	/* if 0.0.0.0/::0, use the source address instead */
530179783Srrs	if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) {
531237715Stuexen		sa = src;
532169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
533169420Srrs		    "process_asconf_set_primary: using source addr ");
534237715Stuexen		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src);
535163953Srrs	}
536163953Srrs	/* set the primary address */
537163953Srrs	if (sctp_set_primary_addr(stcb, sa, NULL) == 0) {
538169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
539169420Srrs		    "process_asconf_set_primary: primary address set\n");
540163953Srrs		/* notify upper layer */
541172090Srrs		sctp_ulp_notify(SCTP_NOTIFY_ASCONF_SET_PRIMARY, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
542224641Stuexen		if ((stcb->asoc.primary_destination->dest_state & SCTP_ADDR_REACHABLE) &&
543224641Stuexen		    (!(stcb->asoc.primary_destination->dest_state & SCTP_ADDR_PF)) &&
544224641Stuexen		    (stcb->asoc.alternate)) {
545224641Stuexen			sctp_free_remote_addr(stcb->asoc.alternate);
546224641Stuexen			stcb->asoc.alternate = NULL;
547224641Stuexen		}
548163953Srrs		if (response_required) {
549163953Srrs			m_reply = sctp_asconf_success_response(aph->correlation_id);
550163953Srrs		}
551172091Srrs		/*
552172091Srrs		 * Mobility adaptation. Ideally, when the reception of SET
553172091Srrs		 * PRIMARY with DELETE IP ADDRESS of the previous primary
554172091Srrs		 * destination, unacknowledged DATA are retransmitted
555172091Srrs		 * immediately to the new primary destination for seamless
556206137Stuexen		 * handover. If the destination is UNCONFIRMED and marked to
557206137Stuexen		 * REQ_PRIM, The retransmission occur when reception of the
558206137Stuexen		 * HEARTBEAT-ACK.  (See sctp_handle_heartbeat_ack in
559172091Srrs		 * sctp_input.c) Also, when change of the primary
560172091Srrs		 * destination, it is better that all subsequent new DATA
561172091Srrs		 * containing already queued DATA are transmitted to the new
562172091Srrs		 * primary destination. (by micchie)
563172091Srrs		 */
564172091Srrs		if ((sctp_is_mobility_feature_on(stcb->sctp_ep,
565172091Srrs		    SCTP_MOBILITY_BASE) ||
566172091Srrs		    sctp_is_mobility_feature_on(stcb->sctp_ep,
567172091Srrs		    SCTP_MOBILITY_FASTHANDOFF)) &&
568172091Srrs		    sctp_is_mobility_feature_on(stcb->sctp_ep,
569172091Srrs		    SCTP_MOBILITY_PRIM_DELETED) &&
570172091Srrs		    (stcb->asoc.primary_destination->dest_state &
571172091Srrs		    SCTP_ADDR_UNCONFIRMED) == 0) {
572172091Srrs
573283650Stuexen			sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED,
574283650Stuexen			    stcb->sctp_ep, stcb, NULL,
575283650Stuexen			    SCTP_FROM_SCTP_ASCONF + SCTP_LOC_1);
576172091Srrs			if (sctp_is_mobility_feature_on(stcb->sctp_ep,
577172091Srrs			    SCTP_MOBILITY_FASTHANDOFF)) {
578172091Srrs				sctp_assoc_immediate_retrans(stcb,
579172091Srrs				    stcb->asoc.primary_destination);
580172091Srrs			}
581172091Srrs			if (sctp_is_mobility_feature_on(stcb->sctp_ep,
582172091Srrs			    SCTP_MOBILITY_BASE)) {
583212712Stuexen				sctp_move_chunks_from_net(stcb,
584212712Stuexen				    stcb->asoc.deleted_primary);
585172091Srrs			}
586172091Srrs			sctp_delete_prim_timer(stcb->sctp_ep, stcb,
587172091Srrs			    stcb->asoc.deleted_primary);
588172091Srrs		}
589163953Srrs	} else {
590163953Srrs		/* couldn't set the requested primary address! */
591169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
592169420Srrs		    "process_asconf_set_primary: set primary failed!\n");
593163953Srrs		/* must have been an invalid address, so report */
594163953Srrs		m_reply = sctp_asconf_error_response(aph->correlation_id,
595310773Stuexen		    SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *)aph,
596163953Srrs		    aparam_length);
597163953Srrs	}
598163953Srrs
599228907Stuexen	return (m_reply);
600163953Srrs}
601163953Srrs
602163953Srrs/*
603163953Srrs * handles an ASCONF chunk.
604163953Srrs * if all parameters are processed ok, send a plain (empty) ASCONF-ACK
605163953Srrs */
606163953Srrsvoid
607163953Srrssctp_handle_asconf(struct mbuf *m, unsigned int offset,
608237715Stuexen    struct sockaddr *src,
609171990Srrs    struct sctp_asconf_chunk *cp, struct sctp_tcb *stcb,
610171990Srrs    int first)
611163953Srrs{
612163953Srrs	struct sctp_association *asoc;
613163953Srrs	uint32_t serial_num;
614171990Srrs	struct mbuf *n, *m_ack, *m_result, *m_tail;
615163953Srrs	struct sctp_asconf_ack_chunk *ack_cp;
616277046Stuexen	struct sctp_asconf_paramhdr *aph;
617163953Srrs	struct sctp_ipv6addr_param *p_addr;
618224641Stuexen	unsigned int asconf_limit, cnt;
619163953Srrs	int error = 0;		/* did an error occur? */
620163953Srrs
621163953Srrs	/* asconf param buffer */
622166675Srrs	uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE];
623171990Srrs	struct sctp_asconf_ack *ack, *ack_next;
624163953Srrs
625163953Srrs	/* verify minimum length */
626163953Srrs	if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_asconf_chunk)) {
627169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
628169420Srrs		    "handle_asconf: chunk too small = %xh\n",
629169420Srrs		    ntohs(cp->ch.chunk_length));
630163953Srrs		return;
631163953Srrs	}
632163953Srrs	asoc = &stcb->asoc;
633163953Srrs	serial_num = ntohl(cp->serial_number);
634163953Srrs
635216825Stuexen	if (SCTP_TSN_GE(asoc->asconf_seq_in, serial_num)) {
636163953Srrs		/* got a duplicate ASCONF */
637169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
638169420Srrs		    "handle_asconf: got duplicate serial number = %xh\n",
639169420Srrs		    serial_num);
640163953Srrs		return;
641163953Srrs	} else if (serial_num != (asoc->asconf_seq_in + 1)) {
642169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: incorrect serial number = %xh (expected next = %xh)\n",
643169420Srrs		    serial_num, asoc->asconf_seq_in + 1);
644163953Srrs		return;
645163953Srrs	}
646347154Stuexen
647163953Srrs	/* it's the expected "next" sequence number, so process it */
648163953Srrs	asoc->asconf_seq_in = serial_num;	/* update sequence */
649163953Srrs	/* get length of all the param's in the ASCONF */
650163953Srrs	asconf_limit = offset + ntohs(cp->ch.chunk_length);
651169420Srrs	SCTPDBG(SCTP_DEBUG_ASCONF1,
652169420Srrs	    "handle_asconf: asconf_limit=%u, sequence=%xh\n",
653169420Srrs	    asconf_limit, serial_num);
654171990Srrs
655171990Srrs	if (first) {
656171990Srrs		/* delete old cache */
657221249Stuexen		SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: Now processing first ASCONF. Try to delete old cache\n");
658171990Srrs
659216822Stuexen		TAILQ_FOREACH_SAFE(ack, &asoc->asconf_ack_sent, next, ack_next) {
660171990Srrs			if (ack->serial_number == serial_num)
661171990Srrs				break;
662171990Srrs			SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: delete old(%u) < first(%u)\n",
663171990Srrs			    ack->serial_number, serial_num);
664216822Stuexen			TAILQ_REMOVE(&asoc->asconf_ack_sent, ack, next);
665171990Srrs			if (ack->data != NULL) {
666171990Srrs				sctp_m_freem(ack->data);
667171990Srrs			}
668179783Srrs			SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asconf_ack), ack);
669171990Srrs		}
670163953Srrs	}
671347154Stuexen
672165647Srrs	m_ack = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_ack_chunk), 0,
673243882Sglebius	    M_NOWAIT, 1, MT_DATA);
674163953Srrs	if (m_ack == NULL) {
675169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
676169420Srrs		    "handle_asconf: couldn't get mbuf!\n");
677163953Srrs		return;
678163953Srrs	}
679163953Srrs	m_tail = m_ack;		/* current reply chain's tail */
680163953Srrs
681163953Srrs	/* fill in ASCONF-ACK header */
682163953Srrs	ack_cp = mtod(m_ack, struct sctp_asconf_ack_chunk *);
683163953Srrs	ack_cp->ch.chunk_type = SCTP_ASCONF_ACK;
684163953Srrs	ack_cp->ch.chunk_flags = 0;
685163953Srrs	ack_cp->serial_number = htonl(serial_num);
686163953Srrs	/* set initial lengths (eg. just an ASCONF-ACK), ntohx at the end! */
687165647Srrs	SCTP_BUF_LEN(m_ack) = sizeof(struct sctp_asconf_ack_chunk);
688163953Srrs	ack_cp->ch.chunk_length = sizeof(struct sctp_asconf_ack_chunk);
689163953Srrs
690163953Srrs	/* skip the lookup address parameter */
691163953Srrs	offset += sizeof(struct sctp_asconf_chunk);
692310773Stuexen	p_addr = (struct sctp_ipv6addr_param *)sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr), (uint8_t *)&aparam_buf);
693163953Srrs	if (p_addr == NULL) {
694169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
695169420Srrs		    "handle_asconf: couldn't get lookup addr!\n");
696163953Srrs		/* respond with a missing/invalid mandatory parameter error */
697347650Stuexen		sctp_m_freem(m_ack);
698163953Srrs		return;
699163953Srrs	}
700360741Stuexen	/* skip lookup addr */
701360741Stuexen	offset += SCTP_SIZE32(ntohs(p_addr->ph.param_length));
702163953Srrs	/* get pointer to first asconf param in ASCONF */
703310773Stuexen	aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, sizeof(struct sctp_asconf_paramhdr), (uint8_t *)&aparam_buf);
704163953Srrs	if (aph == NULL) {
705169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1, "Empty ASCONF received?\n");
706163953Srrs		goto send_reply;
707163953Srrs	}
708163953Srrs	/* process through all parameters */
709224641Stuexen	cnt = 0;
710163953Srrs	while (aph != NULL) {
711163953Srrs		unsigned int param_length, param_type;
712163953Srrs
713163953Srrs		param_type = ntohs(aph->ph.param_type);
714163953Srrs		param_length = ntohs(aph->ph.param_length);
715163953Srrs		if (offset + param_length > asconf_limit) {
716163953Srrs			/* parameter goes beyond end of chunk! */
717163953Srrs			sctp_m_freem(m_ack);
718163953Srrs			return;
719163953Srrs		}
720163953Srrs		m_result = NULL;
721163953Srrs
722163953Srrs		if (param_length > sizeof(aparam_buf)) {
723169420Srrs			SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: param length (%u) larger than buffer size!\n", param_length);
724163953Srrs			sctp_m_freem(m_ack);
725163953Srrs			return;
726163953Srrs		}
727163953Srrs		if (param_length <= sizeof(struct sctp_paramhdr)) {
728169420Srrs			SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: param length (%u) too short\n", param_length);
729163953Srrs			sctp_m_freem(m_ack);
730360734Stuexen			return;
731163953Srrs		}
732163953Srrs		/* get the entire parameter */
733163953Srrs		aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, param_length, aparam_buf);
734163953Srrs		if (aph == NULL) {
735169420Srrs			SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: couldn't get entire param\n");
736163953Srrs			sctp_m_freem(m_ack);
737163953Srrs			return;
738163953Srrs		}
739163953Srrs		switch (param_type) {
740163953Srrs		case SCTP_ADD_IP_ADDRESS:
741237715Stuexen			m_result = sctp_process_asconf_add_ip(src, aph, stcb,
742224641Stuexen			    (cnt < SCTP_BASE_SYSCTL(sctp_hb_maxburst)), error);
743224641Stuexen			cnt++;
744163953Srrs			break;
745163953Srrs		case SCTP_DEL_IP_ADDRESS:
746237715Stuexen			m_result = sctp_process_asconf_delete_ip(src, aph, stcb,
747163953Srrs			    error);
748163953Srrs			break;
749163953Srrs		case SCTP_ERROR_CAUSE_IND:
750163953Srrs			/* not valid in an ASCONF chunk */
751163953Srrs			break;
752163953Srrs		case SCTP_SET_PRIM_ADDR:
753237715Stuexen			m_result = sctp_process_asconf_set_primary(src, aph,
754163953Srrs			    stcb, error);
755163953Srrs			break;
756185694Srrs		case SCTP_NAT_VTAGS:
757185694Srrs			SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: sees a NAT VTAG state parameter\n");
758185694Srrs			break;
759163953Srrs		case SCTP_SUCCESS_REPORT:
760163953Srrs			/* not valid in an ASCONF chunk */
761163953Srrs			break;
762163953Srrs		case SCTP_ULP_ADAPTATION:
763163953Srrs			/* FIX */
764163953Srrs			break;
765163953Srrs		default:
766163953Srrs			if ((param_type & 0x8000) == 0) {
767163953Srrs				/* Been told to STOP at this param */
768163953Srrs				asconf_limit = offset;
769163953Srrs				/*
770163953Srrs				 * FIX FIX - We need to call
771163953Srrs				 * sctp_arethere_unrecognized_parameters()
772163953Srrs				 * to get a operr and send it for any
773163953Srrs				 * param's with the 0x4000 bit set OR do it
774163953Srrs				 * here ourselves... note we still must STOP
775163953Srrs				 * if the 0x8000 bit is clear.
776163953Srrs				 */
777163953Srrs			}
778163953Srrs			/* unknown/invalid param type */
779163953Srrs			break;
780163953Srrs		}		/* switch */
781163953Srrs
782163953Srrs		/* add any (error) result to the reply mbuf chain */
783163953Srrs		if (m_result != NULL) {
784165647Srrs			SCTP_BUF_NEXT(m_tail) = m_result;
785163953Srrs			m_tail = m_result;
786165647Srrs			ack_cp->ch.chunk_length += SCTP_BUF_LEN(m_result);
787163953Srrs			/* set flag to force success reports */
788163953Srrs			error = 1;
789163953Srrs		}
790163953Srrs		offset += SCTP_SIZE32(param_length);
791163953Srrs		/* update remaining ASCONF message length to process */
792163953Srrs		if (offset >= asconf_limit) {
793163953Srrs			/* no more data in the mbuf chain */
794163953Srrs			break;
795163953Srrs		}
796163953Srrs		/* get pointer to next asconf param */
797163953Srrs		aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset,
798163953Srrs		    sizeof(struct sctp_asconf_paramhdr),
799310773Stuexen		    (uint8_t *)&aparam_buf);
800163953Srrs		if (aph == NULL) {
801163953Srrs			/* can't get an asconf paramhdr */
802169420Srrs			SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: can't get asconf param hdr!\n");
803163953Srrs			/* FIX ME - add error here... */
804163953Srrs		}
805169420Srrs	}
806163953Srrs
807163953Srrssend_reply:
808163953Srrs	ack_cp->ch.chunk_length = htons(ack_cp->ch.chunk_length);
809163953Srrs	/* save the ASCONF-ACK reply */
810179783Srrs	ack = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_asconf_ack),
811171990Srrs	    struct sctp_asconf_ack);
812171990Srrs	if (ack == NULL) {
813171990Srrs		sctp_m_freem(m_ack);
814171990Srrs		return;
815171990Srrs	}
816171990Srrs	ack->serial_number = serial_num;
817171990Srrs	ack->last_sent_to = NULL;
818171990Srrs	ack->data = m_ack;
819209178Stuexen	ack->len = 0;
820221249Stuexen	for (n = m_ack; n != NULL; n = SCTP_BUF_NEXT(n)) {
821171990Srrs		ack->len += SCTP_BUF_LEN(n);
822171990Srrs	}
823171990Srrs	TAILQ_INSERT_TAIL(&stcb->asoc.asconf_ack_sent, ack, next);
824163953Srrs
825163953Srrs	/* see if last_control_chunk_from is set properly (use IP src addr) */
826163953Srrs	if (stcb->asoc.last_control_chunk_from == NULL) {
827163953Srrs		/*
828163953Srrs		 * this could happen if the source address was just newly
829163953Srrs		 * added
830163953Srrs		 */
831169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: looking up net for IP source address\n");
832236515Stuexen		SCTPDBG(SCTP_DEBUG_ASCONF1, "Looking for IP source: ");
833236515Stuexen		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src);
834236515Stuexen		/* look up the from address */
835236515Stuexen		stcb->asoc.last_control_chunk_from = sctp_findnet(stcb, src);
836236515Stuexen#ifdef SCTP_DEBUG
837236515Stuexen		if (stcb->asoc.last_control_chunk_from == NULL) {
838236515Stuexen			SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: IP source address not found?!\n");
839163953Srrs		}
840169420Srrs#endif
841163953Srrs	}
842163953Srrs}
843163953Srrs
844163953Srrs/*
845163953Srrs * does the address match? returns 0 if not, 1 if so
846163953Srrs */
847163953Srrsstatic uint32_t
848163953Srrssctp_asconf_addr_match(struct sctp_asconf_addr *aa, struct sockaddr *sa)
849163953Srrs{
850221249Stuexen	switch (sa->sa_family) {
851163953Srrs#ifdef INET6
852221249Stuexen	case AF_INET6:
853221249Stuexen		{
854221249Stuexen			/* XXX scopeid */
855221249Stuexen			struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
856163953Srrs
857221249Stuexen			if ((aa->ap.addrp.ph.param_type == SCTP_IPV6_ADDRESS) &&
858221249Stuexen			    (memcmp(&aa->ap.addrp.addr, &sin6->sin6_addr,
859221249Stuexen			    sizeof(struct in6_addr)) == 0)) {
860221249Stuexen				return (1);
861221249Stuexen			}
862221249Stuexen			break;
863163953Srrs		}
864221249Stuexen#endif
865221249Stuexen#ifdef INET
866221249Stuexen	case AF_INET:
867221249Stuexen		{
868221249Stuexen			struct sockaddr_in *sin = (struct sockaddr_in *)sa;
869163953Srrs
870221249Stuexen			if ((aa->ap.addrp.ph.param_type == SCTP_IPV4_ADDRESS) &&
871221249Stuexen			    (memcmp(&aa->ap.addrp.addr, &sin->sin_addr,
872221249Stuexen			    sizeof(struct in_addr)) == 0)) {
873221249Stuexen				return (1);
874221249Stuexen			}
875221249Stuexen			break;
876163953Srrs		}
877221249Stuexen#endif
878221249Stuexen	default:
879221249Stuexen		break;
880163953Srrs	}
881163953Srrs	return (0);
882163953Srrs}
883163953Srrs
884163953Srrs/*
885179157Srrs * does the address match? returns 0 if not, 1 if so
886179157Srrs */
887179157Srrsstatic uint32_t
888221249Stuexensctp_addr_match(struct sctp_paramhdr *ph, struct sockaddr *sa)
889179157Srrs{
890257555Stuexen#if defined(INET) || defined(INET6)
891179157Srrs	uint16_t param_type, param_length;
892179157Srrs
893221249Stuexen	param_type = ntohs(ph->param_type);
894221249Stuexen	param_length = ntohs(ph->param_length);
895257555Stuexen#endif
896221249Stuexen	switch (sa->sa_family) {
897179157Srrs#ifdef INET6
898221249Stuexen	case AF_INET6:
899221249Stuexen		{
900221249Stuexen			/* XXX scopeid */
901221249Stuexen			struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
902221249Stuexen			struct sctp_ipv6addr_param *v6addr;
903179157Srrs
904221249Stuexen			v6addr = (struct sctp_ipv6addr_param *)ph;
905221249Stuexen			if ((param_type == SCTP_IPV6_ADDRESS) &&
906257555Stuexen			    (param_length == sizeof(struct sctp_ipv6addr_param)) &&
907221249Stuexen			    (memcmp(&v6addr->addr, &sin6->sin6_addr,
908221249Stuexen			    sizeof(struct in6_addr)) == 0)) {
909221249Stuexen				return (1);
910221249Stuexen			}
911221249Stuexen			break;
912179157Srrs		}
913180955Srrs#endif
914221249Stuexen#ifdef INET
915221249Stuexen	case AF_INET:
916221249Stuexen		{
917221249Stuexen			struct sockaddr_in *sin = (struct sockaddr_in *)sa;
918221249Stuexen			struct sctp_ipv4addr_param *v4addr;
919179157Srrs
920221249Stuexen			v4addr = (struct sctp_ipv4addr_param *)ph;
921221249Stuexen			if ((param_type == SCTP_IPV4_ADDRESS) &&
922257555Stuexen			    (param_length == sizeof(struct sctp_ipv4addr_param)) &&
923221249Stuexen			    (memcmp(&v4addr->addr, &sin->sin_addr,
924221249Stuexen			    sizeof(struct in_addr)) == 0)) {
925221249Stuexen				return (1);
926221249Stuexen			}
927221249Stuexen			break;
928179157Srrs		}
929221249Stuexen#endif
930221249Stuexen	default:
931221249Stuexen		break;
932179157Srrs	}
933179157Srrs	return (0);
934179157Srrs}
935179157Srrs
936179157Srrs/*
937163953Srrs * Cleanup for non-responded/OP ERR'd ASCONF
938163953Srrs */
939163953Srrsvoid
940163953Srrssctp_asconf_cleanup(struct sctp_tcb *stcb, struct sctp_nets *net)
941163953Srrs{
942163953Srrs	/*
943163953Srrs	 * clear out any existing asconfs going out
944163953Srrs	 */
945169655Srrs	sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net,
946169655Srrs	    SCTP_FROM_SCTP_ASCONF + SCTP_LOC_2);
947179157Srrs	stcb->asoc.asconf_seq_out_acked = stcb->asoc.asconf_seq_out;
948163953Srrs	/* remove the old ASCONF on our outbound queue */
949163953Srrs	sctp_toss_old_asconf(stcb);
950163953Srrs}
951163953Srrs
952163953Srrs/*
953171858Srrs * cleanup any cached source addresses that may be topologically
954171858Srrs * incorrect after a new address has been added to this interface.
955171858Srrs */
956171858Srrsstatic void
957171858Srrssctp_asconf_nets_cleanup(struct sctp_tcb *stcb, struct sctp_ifn *ifn)
958171858Srrs{
959171858Srrs	struct sctp_nets *net;
960171858Srrs
961171858Srrs	/*
962171858Srrs	 * Ideally, we want to only clear cached routes and source addresses
963171858Srrs	 * that are topologically incorrect.  But since there is no easy way
964171858Srrs	 * to know whether the newly added address on the ifn would cause a
965171858Srrs	 * routing change (i.e. a new egress interface would be chosen)
966171858Srrs	 * without doing a new routing lookup and source address selection,
967171858Srrs	 * we will (for now) just flush any cached route using a different
968171858Srrs	 * ifn (and cached source addrs) and let output re-choose them
969171858Srrs	 * during the next send on that net.
970171858Srrs	 */
971171858Srrs	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
972171858Srrs		/*
973171858Srrs		 * clear any cached route (and cached source address) if the
974171858Srrs		 * route's interface is NOT the same as the address change.
975171858Srrs		 * If it's the same interface, just clear the cached source
976171858Srrs		 * address.
977171858Srrs		 */
978171858Srrs		if (SCTP_ROUTE_HAS_VALID_IFN(&net->ro) &&
979209178Stuexen		    ((ifn == NULL) ||
980209178Stuexen		    (SCTP_GET_IF_INDEX_FROM_ROUTE(&net->ro) != ifn->ifn_index))) {
981171858Srrs			/* clear any cached route */
982171858Srrs			RTFREE(net->ro.ro_rt);
983171858Srrs			net->ro.ro_rt = NULL;
984171858Srrs		}
985171858Srrs		/* clear any cached source address */
986171858Srrs		if (net->src_addr_selected) {
987171858Srrs			sctp_free_ifa(net->ro._s_addr);
988171858Srrs			net->ro._s_addr = NULL;
989171858Srrs			net->src_addr_selected = 0;
990171858Srrs		}
991171858Srrs	}
992171858Srrs}
993171858Srrs
994172091Srrs
995172091Srrsvoid
996172091Srrssctp_assoc_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *dstnet)
997172091Srrs{
998172091Srrs	int error;
999172091Srrs
1000172118Srrs	if (dstnet->dest_state & SCTP_ADDR_UNCONFIRMED) {
1001172118Srrs		return;
1002172118Srrs	}
1003172091Srrs	if (stcb->asoc.deleted_primary == NULL) {
1004172091Srrs		return;
1005172091Srrs	}
1006347154Stuexen
1007172091Srrs	if (!TAILQ_EMPTY(&stcb->asoc.sent_queue)) {
1008172157Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1, "assoc_immediate_retrans: Deleted primary is ");
1009172091Srrs		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.deleted_primary->ro._l_addr.sa);
1010172091Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1, "Current Primary is ");
1011172091Srrs		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.primary_destination->ro._l_addr.sa);
1012172091Srrs		sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb,
1013172091Srrs		    stcb->asoc.deleted_primary,
1014283650Stuexen		    SCTP_FROM_SCTP_ASCONF + SCTP_LOC_3);
1015172091Srrs		stcb->asoc.num_send_timers_up--;
1016172091Srrs		if (stcb->asoc.num_send_timers_up < 0) {
1017172091Srrs			stcb->asoc.num_send_timers_up = 0;
1018172091Srrs		}
1019172091Srrs		SCTP_TCB_LOCK_ASSERT(stcb);
1020172091Srrs		error = sctp_t3rxt_timer(stcb->sctp_ep, stcb,
1021172091Srrs		    stcb->asoc.deleted_primary);
1022172091Srrs		if (error) {
1023172091Srrs			SCTP_INP_DECR_REF(stcb->sctp_ep);
1024172091Srrs			return;
1025172091Srrs		}
1026172091Srrs		SCTP_TCB_LOCK_ASSERT(stcb);
1027172091Srrs#ifdef SCTP_AUDITING_ENABLED
1028207099Stuexen		sctp_auditing(4, stcb->sctp_ep, stcb, stcb->asoc.deleted_primary);
1029172091Srrs#endif
1030172091Srrs		sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
1031172091Srrs		if ((stcb->asoc.num_send_timers_up == 0) &&
1032172091Srrs		    (stcb->asoc.sent_queue_cnt > 0)) {
1033172091Srrs			struct sctp_tmit_chunk *chk;
1034172091Srrs
1035361471Stuexen			TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
1036361471Stuexen				if (chk->whoTo != NULL) {
1037361471Stuexen					break;
1038361471Stuexen				}
1039361471Stuexen			}
1040361471Stuexen			if (chk != NULL) {
1041361471Stuexen				sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, chk->whoTo);
1042361471Stuexen			}
1043172091Srrs		}
1044172091Srrs	}
1045172091Srrs	return;
1046172091Srrs}
1047172091Srrs
1048171990Srrsstatic int
1049171990Srrs    sctp_asconf_queue_mgmt(struct sctp_tcb *, struct sctp_ifa *, uint16_t);
1050171990Srrs
1051172091Srrsvoid
1052171990Srrssctp_net_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *net)
1053171990Srrs{
1054171990Srrs	struct sctp_tmit_chunk *chk;
1055171990Srrs
1056172157Srrs	SCTPDBG(SCTP_DEBUG_ASCONF1, "net_immediate_retrans: RTO is %d\n", net->RTO);
1057171990Srrs	sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net,
1058283650Stuexen	    SCTP_FROM_SCTP_ASCONF + SCTP_LOC_4);
1059171990Srrs	stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
1060171990Srrs	net->error_count = 0;
1061171990Srrs	TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
1062171990Srrs		if (chk->whoTo == net) {
1063172091Srrs			if (chk->sent < SCTP_DATAGRAM_RESEND) {
1064172091Srrs				chk->sent = SCTP_DATAGRAM_RESEND;
1065172091Srrs				sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
1066172396Srrs				sctp_flight_size_decrease(chk);
1067172396Srrs				sctp_total_flight_decrease(stcb, chk);
1068172396Srrs				net->marked_retrans++;
1069172396Srrs				stcb->asoc.marked_retrans++;
1070172091Srrs			}
1071171990Srrs		}
1072171990Srrs	}
1073172396Srrs	if (net->marked_retrans) {
1074172396Srrs		sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
1075172396Srrs	}
1076171990Srrs}
1077171990Srrs
1078171990Srrsstatic void
1079171990Srrssctp_path_check_and_react(struct sctp_tcb *stcb, struct sctp_ifa *newifa)
1080171990Srrs{
1081171990Srrs	struct sctp_nets *net;
1082171990Srrs	int addrnum, changed;
1083171990Srrs
1084171990Srrs	/*
1085171990Srrs	 * If number of local valid addresses is 1, the valid address is
1086206137Stuexen	 * probably newly added address. Several valid addresses in this
1087171990Srrs	 * association.  A source address may not be changed.  Additionally,
1088171990Srrs	 * they can be configured on a same interface as "alias" addresses.
1089171990Srrs	 * (by micchie)
1090171990Srrs	 */
1091171990Srrs	addrnum = sctp_local_addr_count(stcb);
1092171990Srrs	SCTPDBG(SCTP_DEBUG_ASCONF1, "p_check_react(): %d local addresses\n",
1093171990Srrs	    addrnum);
1094171990Srrs	if (addrnum == 1) {
1095171990Srrs		TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1096171990Srrs			/* clear any cached route and source address */
1097171990Srrs			if (net->ro.ro_rt) {
1098171990Srrs				RTFREE(net->ro.ro_rt);
1099171990Srrs				net->ro.ro_rt = NULL;
1100171990Srrs			}
1101171990Srrs			if (net->src_addr_selected) {
1102171990Srrs				sctp_free_ifa(net->ro._s_addr);
1103171990Srrs				net->ro._s_addr = NULL;
1104171990Srrs				net->src_addr_selected = 0;
1105171990Srrs			}
1106171990Srrs			/* Retransmit unacknowledged DATA chunks immediately */
1107171990Srrs			if (sctp_is_mobility_feature_on(stcb->sctp_ep,
1108171990Srrs			    SCTP_MOBILITY_FASTHANDOFF)) {
1109171990Srrs				sctp_net_immediate_retrans(stcb, net);
1110171990Srrs			}
1111171990Srrs			/* also, SET PRIMARY is maybe already sent */
1112171990Srrs		}
1113171990Srrs		return;
1114171990Srrs	}
1115347154Stuexen
1116171990Srrs	/* Multiple local addresses exsist in the association.  */
1117171990Srrs	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1118171990Srrs		/* clear any cached route and source address */
1119171990Srrs		if (net->ro.ro_rt) {
1120171990Srrs			RTFREE(net->ro.ro_rt);
1121171990Srrs			net->ro.ro_rt = NULL;
1122171990Srrs		}
1123171990Srrs		if (net->src_addr_selected) {
1124171990Srrs			sctp_free_ifa(net->ro._s_addr);
1125171990Srrs			net->ro._s_addr = NULL;
1126171990Srrs			net->src_addr_selected = 0;
1127171990Srrs		}
1128171990Srrs		/*
1129171990Srrs		 * Check if the nexthop is corresponding to the new address.
1130171990Srrs		 * If the new address is corresponding to the current
1131206137Stuexen		 * nexthop, the path will be changed. If the new address is
1132171990Srrs		 * NOT corresponding to the current nexthop, the path will
1133171990Srrs		 * not be changed.
1134171990Srrs		 */
1135310773Stuexen		SCTP_RTALLOC((sctp_route_t *)&net->ro,
1136284515Stuexen		    stcb->sctp_ep->def_vrf_id,
1137284515Stuexen		    stcb->sctp_ep->fibnum);
1138171990Srrs		if (net->ro.ro_rt == NULL)
1139171990Srrs			continue;
1140171990Srrs
1141172137Srrs		changed = 0;
1142221249Stuexen		switch (net->ro._l_addr.sa.sa_family) {
1143221249Stuexen#ifdef INET
1144221249Stuexen		case AF_INET:
1145310773Stuexen			if (sctp_v4src_match_nexthop(newifa, (sctp_route_t *)&net->ro)) {
1146171990Srrs				changed = 1;
1147221249Stuexen			}
1148221249Stuexen			break;
1149221249Stuexen#endif
1150178251Srrs#ifdef INET6
1151221249Stuexen		case AF_INET6:
1152171990Srrs			if (sctp_v6src_match_nexthop(
1153310773Stuexen			    &newifa->address.sin6, (sctp_route_t *)&net->ro)) {
1154171990Srrs				changed = 1;
1155221249Stuexen			}
1156221249Stuexen			break;
1157221249Stuexen#endif
1158221249Stuexen		default:
1159221249Stuexen			break;
1160171990Srrs		}
1161171990Srrs		/*
1162171990Srrs		 * if the newly added address does not relate routing
1163171990Srrs		 * information, we skip.
1164171990Srrs		 */
1165171990Srrs		if (changed == 0)
1166171990Srrs			continue;
1167171990Srrs		/* Retransmit unacknowledged DATA chunks immediately */
1168171990Srrs		if (sctp_is_mobility_feature_on(stcb->sctp_ep,
1169171990Srrs		    SCTP_MOBILITY_FASTHANDOFF)) {
1170171990Srrs			sctp_net_immediate_retrans(stcb, net);
1171171990Srrs		}
1172171990Srrs		/* Send SET PRIMARY for this new address */
1173171990Srrs		if (net == stcb->asoc.primary_destination) {
1174171990Srrs			(void)sctp_asconf_queue_mgmt(stcb, newifa,
1175171990Srrs			    SCTP_SET_PRIM_ADDR);
1176171990Srrs		}
1177171990Srrs	}
1178171990Srrs}
1179171990Srrs
1180171858Srrs/*
1181163953Srrs * process an ADD/DELETE IP ack from peer.
1182171572Srrs * addr: corresponding sctp_ifa to the address being added/deleted.
1183163953Srrs * type: SCTP_ADD_IP_ADDRESS or SCTP_DEL_IP_ADDRESS.
1184163953Srrs * flag: 1=success, 0=failure.
1185163953Srrs */
1186163953Srrsstatic void
1187228653Stuexensctp_asconf_addr_mgmt_ack(struct sctp_tcb *stcb, struct sctp_ifa *addr, uint32_t flag)
1188163953Srrs{
1189163953Srrs	/*
1190163953Srrs	 * do the necessary asoc list work- if we get a failure indication,
1191171858Srrs	 * leave the address on the assoc's restricted list.  If we get a
1192171858Srrs	 * success indication, remove the address from the restricted list.
1193163953Srrs	 */
1194163953Srrs	/*
1195163953Srrs	 * Note: this will only occur for ADD_IP_ADDRESS, since
1196163953Srrs	 * DEL_IP_ADDRESS is never actually added to the list...
1197163953Srrs	 */
1198163953Srrs	if (flag) {
1199171572Srrs		/* success case, so remove from the restricted list */
1200171572Srrs		sctp_del_local_addr_restricted(stcb, addr);
1201171858Srrs
1202172190Srrs		if (sctp_is_mobility_feature_on(stcb->sctp_ep,
1203172396Srrs		    SCTP_MOBILITY_BASE) ||
1204172396Srrs		    sctp_is_mobility_feature_on(stcb->sctp_ep,
1205172396Srrs		    SCTP_MOBILITY_FASTHANDOFF)) {
1206171990Srrs			sctp_path_check_and_react(stcb, addr);
1207171990Srrs			return;
1208171990Srrs		}
1209172190Srrs		/* clear any cached/topologically incorrect source addresses */
1210171858Srrs		sctp_asconf_nets_cleanup(stcb, addr->ifn_p);
1211163953Srrs	}
1212163953Srrs	/* else, leave it on the list */
1213163953Srrs}
1214163953Srrs
1215163953Srrs/*
1216171572Srrs * add an asconf add/delete/set primary IP address parameter to the queue.
1217163953Srrs * type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR.
1218171572Srrs * returns 0 if queued, -1 if not queued/removed.
1219171572Srrs * NOTE: if adding, but a delete for the same address is already scheduled
1220171572Srrs * (and not yet sent out), simply remove it from queue.  Same for deleting
1221171572Srrs * an address already scheduled for add.  If a duplicate operation is found,
1222171572Srrs * ignore the new one.
1223163953Srrs */
1224171572Srrsstatic int
1225171572Srrssctp_asconf_queue_mgmt(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
1226171477Srrs    uint16_t type)
1227163953Srrs{
1228163953Srrs	struct sctp_asconf_addr *aa, *aa_next;
1229163953Srrs
1230163953Srrs	/* make sure the request isn't already in the queue */
1231216822Stuexen	TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) {
1232163953Srrs		/* address match? */
1233167598Srrs		if (sctp_asconf_addr_match(aa, &ifa->address.sa) == 0)
1234163953Srrs			continue;
1235179157Srrs		/*
1236179157Srrs		 * is the request already in queue but not sent? pass the
1237179157Srrs		 * request already sent in order to resolve the following
1238179157Srrs		 * case: 1. arrival of ADD, then sent 2. arrival of DEL. we
1239179157Srrs		 * can't remove the ADD request already sent 3. arrival of
1240179157Srrs		 * ADD
1241179157Srrs		 */
1242179157Srrs		if (aa->ap.aph.ph.param_type == type && aa->sent == 0) {
1243163953Srrs			return (-1);
1244163953Srrs		}
1245163953Srrs		/* is the negative request already in queue, and not sent */
1246171572Srrs		if ((aa->sent == 0) && (type == SCTP_ADD_IP_ADDRESS) &&
1247171572Srrs		    (aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS)) {
1248171572Srrs			/* add requested, delete already queued */
1249163953Srrs			TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
1250171572Srrs			/* remove the ifa from the restricted list */
1251171572Srrs			sctp_del_local_addr_restricted(stcb, ifa);
1252171572Srrs			/* free the asconf param */
1253170091Srrs			SCTP_FREE(aa, SCTP_M_ASC_ADDR);
1254171572Srrs			SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_mgmt: add removes queued entry\n");
1255163953Srrs			return (-1);
1256163953Srrs		}
1257171572Srrs		if ((aa->sent == 0) && (type == SCTP_DEL_IP_ADDRESS) &&
1258171572Srrs		    (aa->ap.aph.ph.param_type == SCTP_ADD_IP_ADDRESS)) {
1259171572Srrs			/* delete requested, add already queued */
1260171572Srrs			TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
1261171572Srrs			/* remove the aa->ifa from the restricted list */
1262171572Srrs			sctp_del_local_addr_restricted(stcb, aa->ifa);
1263171572Srrs			/* free the asconf param */
1264171572Srrs			SCTP_FREE(aa, SCTP_M_ASC_ADDR);
1265171572Srrs			SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_mgmt: delete removes queued entry\n");
1266171572Srrs			return (-1);
1267171572Srrs		}
1268163953Srrs	}			/* for each aa */
1269163953Srrs
1270163953Srrs	/* adding new request to the queue */
1271171572Srrs	SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
1272171572Srrs	    SCTP_M_ASC_ADDR);
1273163953Srrs	if (aa == NULL) {
1274163953Srrs		/* didn't get memory */
1275171572Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1, "asconf_queue_mgmt: failed to get memory!\n");
1276163953Srrs		return (-1);
1277163953Srrs	}
1278185694Srrs	aa->special_del = 0;
1279163953Srrs	/* fill in asconf address parameter fields */
1280163953Srrs	/* top level elements are "networked" during send */
1281163953Srrs	aa->ap.aph.ph.param_type = type;
1282163953Srrs	aa->ifa = ifa;
1283168299Srrs	atomic_add_int(&ifa->refcount, 1);
1284163953Srrs	/* correlation_id filled in during send routine later... */
1285221249Stuexen	switch (ifa->address.sa.sa_family) {
1286221249Stuexen#ifdef INET6
1287221249Stuexen	case AF_INET6:
1288221249Stuexen		{
1289221249Stuexen			struct sockaddr_in6 *sin6;
1290163953Srrs
1291271221Stuexen			sin6 = &ifa->address.sin6;
1292221249Stuexen			aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
1293221249Stuexen			aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param));
1294221249Stuexen			aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) +
1295221249Stuexen			    sizeof(struct sctp_ipv6addr_param);
1296221249Stuexen			memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr,
1297221249Stuexen			    sizeof(struct in6_addr));
1298221249Stuexen			break;
1299221249Stuexen		}
1300221249Stuexen#endif
1301221249Stuexen#ifdef INET
1302221249Stuexen	case AF_INET:
1303221249Stuexen		{
1304221249Stuexen			struct sockaddr_in *sin;
1305163953Srrs
1306271221Stuexen			sin = &ifa->address.sin;
1307221249Stuexen			aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
1308221249Stuexen			aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv4addr_param));
1309221249Stuexen			aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) +
1310221249Stuexen			    sizeof(struct sctp_ipv4addr_param);
1311221249Stuexen			memcpy(&aa->ap.addrp.addr, &sin->sin_addr,
1312221249Stuexen			    sizeof(struct in_addr));
1313221249Stuexen			break;
1314221249Stuexen		}
1315221249Stuexen#endif
1316221249Stuexen	default:
1317163953Srrs		/* invalid family! */
1318170091Srrs		SCTP_FREE(aa, SCTP_M_ASC_ADDR);
1319172190Srrs		sctp_free_ifa(ifa);
1320163953Srrs		return (-1);
1321163953Srrs	}
1322163953Srrs	aa->sent = 0;		/* clear sent flag */
1323163953Srrs
1324179157Srrs	TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
1325163953Srrs#ifdef SCTP_DEBUG
1326218232Srrs	if (SCTP_BASE_SYSCTL(sctp_debug_on) & SCTP_DEBUG_ASCONF2) {
1327179157Srrs		if (type == SCTP_ADD_IP_ADDRESS) {
1328179157Srrs			SCTP_PRINTF("asconf_queue_mgmt: inserted asconf ADD_IP_ADDRESS: ");
1329253493Stuexen			SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa);
1330179157Srrs		} else if (type == SCTP_DEL_IP_ADDRESS) {
1331179157Srrs			SCTP_PRINTF("asconf_queue_mgmt: appended asconf DEL_IP_ADDRESS: ");
1332253493Stuexen			SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa);
1333179157Srrs		} else {
1334179157Srrs			SCTP_PRINTF("asconf_queue_mgmt: appended asconf SET_PRIM_ADDR: ");
1335253493Stuexen			SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa);
1336163953Srrs		}
1337179157Srrs	}
1338169420Srrs#endif
1339163953Srrs
1340163953Srrs	return (0);
1341163953Srrs}
1342163953Srrs
1343171572Srrs
1344163953Srrs/*
1345171572Srrs * add an asconf operation for the given ifa and type.
1346171572Srrs * type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR.
1347171572Srrs * returns 0 if completed, -1 if not completed, 1 if immediate send is
1348171572Srrs * advisable.
1349171572Srrs */
1350171572Srrsstatic int
1351171572Srrssctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
1352171572Srrs    uint16_t type)
1353171572Srrs{
1354171572Srrs	uint32_t status;
1355171572Srrs	int pending_delete_queued = 0;
1356284393Stuexen	int last;
1357171572Srrs
1358171572Srrs	/* see if peer supports ASCONF */
1359269858Stuexen	if (stcb->asoc.asconf_supported == 0) {
1360171572Srrs		return (-1);
1361171572Srrs	}
1362347154Stuexen
1363171572Srrs	/*
1364171572Srrs	 * if this is deleting the last address from the assoc, mark it as
1365171572Srrs	 * pending.
1366171572Srrs	 */
1367284393Stuexen	if ((type == SCTP_DEL_IP_ADDRESS) && !stcb->asoc.asconf_del_pending) {
1368284393Stuexen		if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1369284393Stuexen			last = (sctp_local_addr_count(stcb) == 0);
1370284393Stuexen		} else {
1371284393Stuexen			last = (sctp_local_addr_count(stcb) == 1);
1372284393Stuexen		}
1373284393Stuexen		if (last) {
1374284393Stuexen			/* set the pending delete info only */
1375284393Stuexen			stcb->asoc.asconf_del_pending = 1;
1376284393Stuexen			stcb->asoc.asconf_addr_del_pending = ifa;
1377284393Stuexen			atomic_add_int(&ifa->refcount, 1);
1378284393Stuexen			SCTPDBG(SCTP_DEBUG_ASCONF2,
1379284393Stuexen			    "asconf_queue_add: mark delete last address pending\n");
1380284393Stuexen			return (-1);
1381284393Stuexen		}
1382171572Srrs	}
1383347154Stuexen
1384179157Srrs	/* queue an asconf parameter */
1385179157Srrs	status = sctp_asconf_queue_mgmt(stcb, ifa, type);
1386179157Srrs
1387171572Srrs	/*
1388171572Srrs	 * if this is an add, and there is a delete also pending (i.e. the
1389171572Srrs	 * last local address is being changed), queue the pending delete
1390171572Srrs	 * too.
1391171572Srrs	 */
1392179157Srrs	if ((type == SCTP_ADD_IP_ADDRESS) && stcb->asoc.asconf_del_pending && (status == 0)) {
1393171572Srrs		/* queue in the pending delete */
1394171572Srrs		if (sctp_asconf_queue_mgmt(stcb,
1395171572Srrs		    stcb->asoc.asconf_addr_del_pending,
1396171572Srrs		    SCTP_DEL_IP_ADDRESS) == 0) {
1397360728Stuexen			SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_add: queuing pending delete\n");
1398171572Srrs			pending_delete_queued = 1;
1399171572Srrs			/* clear out the pending delete info */
1400171572Srrs			stcb->asoc.asconf_del_pending = 0;
1401171572Srrs			sctp_free_ifa(stcb->asoc.asconf_addr_del_pending);
1402171572Srrs			stcb->asoc.asconf_addr_del_pending = NULL;
1403171572Srrs		}
1404171572Srrs	}
1405347154Stuexen
1406179157Srrs	if (pending_delete_queued) {
1407171572Srrs		struct sctp_nets *net;
1408171572Srrs
1409171572Srrs		/*
1410171572Srrs		 * since we know that the only/last address is now being
1411171572Srrs		 * changed in this case, reset the cwnd/rto on all nets to
1412171572Srrs		 * start as a new address and path.  Also clear the error
1413171572Srrs		 * counts to give the assoc the best chance to complete the
1414171572Srrs		 * address change.
1415171572Srrs		 */
1416171572Srrs		TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1417171572Srrs			stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb,
1418171572Srrs			    net);
1419171572Srrs			net->RTO = 0;
1420171572Srrs			net->error_count = 0;
1421171572Srrs		}
1422171572Srrs		stcb->asoc.overall_error_count = 0;
1423179783Srrs		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
1424171943Srrs			sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
1425171943Srrs			    stcb->asoc.overall_error_count,
1426171943Srrs			    0,
1427171943Srrs			    SCTP_FROM_SCTP_ASCONF,
1428171943Srrs			    __LINE__);
1429171943Srrs		}
1430347154Stuexen
1431171572Srrs		/* queue in an advisory set primary too */
1432171572Srrs		(void)sctp_asconf_queue_mgmt(stcb, ifa, SCTP_SET_PRIM_ADDR);
1433171572Srrs		/* let caller know we should send this out immediately */
1434171572Srrs		status = 1;
1435171572Srrs	}
1436171572Srrs	return (status);
1437171572Srrs}
1438171572Srrs
1439172190Srrs/*-
1440172190Srrs * add an asconf delete IP address parameter to the queue by sockaddr and
1441172190Srrs * possibly with no sctp_ifa available.  This is only called by the routine
1442172190Srrs * that checks the addresses in an INIT-ACK against the current address list.
1443163953Srrs * returns 0 if completed, non-zero if not completed.
1444172190Srrs * NOTE: if an add is already scheduled (and not yet sent out), simply
1445172190Srrs * remove it from queue.  If a duplicate operation is found, ignore the
1446172190Srrs * new one.
1447163953Srrs */
1448171572Srrsstatic int
1449172190Srrssctp_asconf_queue_sa_delete(struct sctp_tcb *stcb, struct sockaddr *sa)
1450163953Srrs{
1451168299Srrs	struct sctp_ifa *ifa;
1452163953Srrs	struct sctp_asconf_addr *aa, *aa_next;
1453163953Srrs
1454169420Srrs	if (stcb == NULL) {
1455169420Srrs		return (-1);
1456169420Srrs	}
1457163953Srrs	/* see if peer supports ASCONF */
1458269858Stuexen	if (stcb->asoc.asconf_supported == 0) {
1459163953Srrs		return (-1);
1460163953Srrs	}
1461163953Srrs	/* make sure the request isn't already in the queue */
1462216822Stuexen	TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) {
1463163953Srrs		/* address match? */
1464163953Srrs		if (sctp_asconf_addr_match(aa, sa) == 0)
1465163953Srrs			continue;
1466163953Srrs		/* is the request already in queue (sent or not) */
1467172190Srrs		if (aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS) {
1468163953Srrs			return (-1);
1469163953Srrs		}
1470163953Srrs		/* is the negative request already in queue, and not sent */
1471163953Srrs		if (aa->sent == 1)
1472163953Srrs			continue;
1473172190Srrs		if (aa->ap.aph.ph.param_type == SCTP_ADD_IP_ADDRESS) {
1474172190Srrs			/* add already queued, so remove existing entry */
1475163953Srrs			TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
1476171572Srrs			sctp_del_local_addr_restricted(stcb, aa->ifa);
1477163953Srrs			/* free the entry */
1478170091Srrs			SCTP_FREE(aa, SCTP_M_ASC_ADDR);
1479163953Srrs			return (-1);
1480163953Srrs		}
1481163953Srrs	}			/* for each aa */
1482172190Srrs
1483172190Srrs	/* find any existing ifa-- NOTE ifa CAN be allowed to be NULL */
1484277033Stuexen	ifa = sctp_find_ifa_by_addr(sa, stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED);
1485163953Srrs
1486163953Srrs	/* adding new request to the queue */
1487171572Srrs	SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
1488171572Srrs	    SCTP_M_ASC_ADDR);
1489163953Srrs	if (aa == NULL) {
1490163953Srrs		/* didn't get memory */
1491169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
1492172190Srrs		    "sctp_asconf_queue_sa_delete: failed to get memory!\n");
1493163953Srrs		return (-1);
1494163953Srrs	}
1495185694Srrs	aa->special_del = 0;
1496163953Srrs	/* fill in asconf address parameter fields */
1497163953Srrs	/* top level elements are "networked" during send */
1498172190Srrs	aa->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS;
1499168299Srrs	aa->ifa = ifa;
1500172190Srrs	if (ifa)
1501172190Srrs		atomic_add_int(&ifa->refcount, 1);
1502163953Srrs	/* correlation_id filled in during send routine later... */
1503221249Stuexen	switch (sa->sa_family) {
1504221249Stuexen#ifdef INET6
1505221249Stuexen	case AF_INET6:
1506221249Stuexen		{
1507221249Stuexen			/* IPv6 address */
1508221249Stuexen			struct sockaddr_in6 *sin6;
1509163953Srrs
1510221249Stuexen			sin6 = (struct sockaddr_in6 *)sa;
1511221249Stuexen			aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
1512221249Stuexen			aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param));
1513221249Stuexen			aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_ipv6addr_param);
1514221249Stuexen			memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr,
1515221249Stuexen			    sizeof(struct in6_addr));
1516221249Stuexen			break;
1517221249Stuexen		}
1518221249Stuexen#endif
1519221249Stuexen#ifdef INET
1520221249Stuexen	case AF_INET:
1521221249Stuexen		{
1522221249Stuexen			/* IPv4 address */
1523221249Stuexen			struct sockaddr_in *sin = (struct sockaddr_in *)sa;
1524163953Srrs
1525221249Stuexen			aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
1526221249Stuexen			aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv4addr_param));
1527221249Stuexen			aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_ipv4addr_param);
1528221249Stuexen			memcpy(&aa->ap.addrp.addr, &sin->sin_addr,
1529221249Stuexen			    sizeof(struct in_addr));
1530221249Stuexen			break;
1531221249Stuexen		}
1532221249Stuexen#endif
1533221249Stuexen	default:
1534163953Srrs		/* invalid family! */
1535170091Srrs		SCTP_FREE(aa, SCTP_M_ASC_ADDR);
1536172190Srrs		if (ifa)
1537172190Srrs			sctp_free_ifa(ifa);
1538163953Srrs		return (-1);
1539163953Srrs	}
1540163953Srrs	aa->sent = 0;		/* clear sent flag */
1541163953Srrs
1542172190Srrs	/* delete goes to the back of the queue */
1543172190Srrs	TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
1544163953Srrs
1545172218Srrs	/* sa_ignore MEMLEAK {memory is put on the tailq} */
1546163953Srrs	return (0);
1547163953Srrs}
1548163953Srrs
1549163953Srrs/*
1550163953Srrs * find a specific asconf param on our "sent" queue
1551163953Srrs */
1552163953Srrsstatic struct sctp_asconf_addr *
1553163953Srrssctp_asconf_find_param(struct sctp_tcb *stcb, uint32_t correlation_id)
1554163953Srrs{
1555163953Srrs	struct sctp_asconf_addr *aa;
1556163953Srrs
1557163953Srrs	TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) {
1558163953Srrs		if (aa->ap.aph.correlation_id == correlation_id &&
1559163953Srrs		    aa->sent == 1) {
1560163953Srrs			/* found it */
1561163953Srrs			return (aa);
1562163953Srrs		}
1563163953Srrs	}
1564163953Srrs	/* didn't find it */
1565163953Srrs	return (NULL);
1566163953Srrs}
1567163953Srrs
1568163953Srrs/*
1569163953Srrs * process an SCTP_ERROR_CAUSE_IND for a ASCONF-ACK parameter and do
1570163953Srrs * notifications based on the error response
1571163953Srrs */
1572163953Srrsstatic void
1573269858Stuexensctp_asconf_process_error(struct sctp_tcb *stcb SCTP_UNUSED,
1574163953Srrs    struct sctp_asconf_paramhdr *aph)
1575163953Srrs{
1576163953Srrs	struct sctp_error_cause *eh;
1577163953Srrs	struct sctp_paramhdr *ph;
1578163953Srrs	uint16_t param_type;
1579163953Srrs	uint16_t error_code;
1580163953Srrs
1581163953Srrs	eh = (struct sctp_error_cause *)(aph + 1);
1582163953Srrs	ph = (struct sctp_paramhdr *)(eh + 1);
1583163953Srrs	/* validate lengths */
1584163953Srrs	if (htons(eh->length) + sizeof(struct sctp_error_cause) >
1585163953Srrs	    htons(aph->ph.param_length)) {
1586163953Srrs		/* invalid error cause length */
1587169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
1588169420Srrs		    "asconf_process_error: cause element too long\n");
1589163953Srrs		return;
1590163953Srrs	}
1591163953Srrs	if (htons(ph->param_length) + sizeof(struct sctp_paramhdr) >
1592163953Srrs	    htons(eh->length)) {
1593163953Srrs		/* invalid included TLV length */
1594169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
1595169420Srrs		    "asconf_process_error: included TLV too long\n");
1596163953Srrs		return;
1597163953Srrs	}
1598163953Srrs	/* which error code ? */
1599163953Srrs	error_code = ntohs(eh->code);
1600163953Srrs	param_type = ntohs(aph->ph.param_type);
1601163953Srrs	/* FIX: this should go back up the REMOTE_ERROR ULP notify */
1602163953Srrs	switch (error_code) {
1603163953Srrs	case SCTP_CAUSE_RESOURCE_SHORTAGE:
1604163953Srrs		/* we allow ourselves to "try again" for this error */
1605163953Srrs		break;
1606163953Srrs	default:
1607163953Srrs		/* peer can't handle it... */
1608163953Srrs		switch (param_type) {
1609163953Srrs		case SCTP_ADD_IP_ADDRESS:
1610163953Srrs		case SCTP_DEL_IP_ADDRESS:
1611163953Srrs		case SCTP_SET_PRIM_ADDR:
1612163953Srrs			break;
1613163953Srrs		default:
1614163953Srrs			break;
1615163953Srrs		}
1616163953Srrs	}
1617163953Srrs}
1618163953Srrs
1619163953Srrs/*
1620171477Srrs * process an asconf queue param.
1621171477Srrs * aparam: parameter to process, will be removed from the queue.
1622171477Srrs * flag: 1=success case, 0=failure case
1623163953Srrs */
1624163953Srrsstatic void
1625163953Srrssctp_asconf_process_param_ack(struct sctp_tcb *stcb,
1626163953Srrs    struct sctp_asconf_addr *aparam, uint32_t flag)
1627163953Srrs{
1628163953Srrs	uint16_t param_type;
1629163953Srrs
1630163953Srrs	/* process this param */
1631163953Srrs	param_type = aparam->ap.aph.ph.param_type;
1632163953Srrs	switch (param_type) {
1633163953Srrs	case SCTP_ADD_IP_ADDRESS:
1634169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
1635169420Srrs		    "process_param_ack: added IP address\n");
1636228653Stuexen		sctp_asconf_addr_mgmt_ack(stcb, aparam->ifa, flag);
1637163953Srrs		break;
1638163953Srrs	case SCTP_DEL_IP_ADDRESS:
1639169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
1640169420Srrs		    "process_param_ack: deleted IP address\n");
1641163953Srrs		/* nothing really to do... lists already updated */
1642163953Srrs		break;
1643163953Srrs	case SCTP_SET_PRIM_ADDR:
1644179157Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
1645179157Srrs		    "process_param_ack: set primary IP address\n");
1646163953Srrs		/* nothing to do... peer may start using this addr */
1647163953Srrs		break;
1648163953Srrs	default:
1649163953Srrs		/* should NEVER happen */
1650163953Srrs		break;
1651163953Srrs	}
1652163953Srrs
1653163953Srrs	/* remove the param and free it */
1654163953Srrs	TAILQ_REMOVE(&stcb->asoc.asconf_queue, aparam, next);
1655172190Srrs	if (aparam->ifa)
1656172190Srrs		sctp_free_ifa(aparam->ifa);
1657170091Srrs	SCTP_FREE(aparam, SCTP_M_ASC_ADDR);
1658163953Srrs}
1659163953Srrs
1660163953Srrs/*
1661163953Srrs * cleanup from a bad asconf ack parameter
1662163953Srrs */
1663163953Srrsstatic void
1664269858Stuexensctp_asconf_ack_clear(struct sctp_tcb *stcb SCTP_UNUSED)
1665163953Srrs{
1666163953Srrs	/* assume peer doesn't really know how to do asconfs */
1667163953Srrs	/* XXX we could free the pending queue here */
1668269858Stuexen
1669163953Srrs}
1670163953Srrs
1671163953Srrsvoid
1672163953Srrssctp_handle_asconf_ack(struct mbuf *m, int offset,
1673163953Srrs    struct sctp_asconf_ack_chunk *cp, struct sctp_tcb *stcb,
1674172190Srrs    struct sctp_nets *net, int *abort_no_unlock)
1675163953Srrs{
1676163953Srrs	struct sctp_association *asoc;
1677163953Srrs	uint32_t serial_num;
1678163953Srrs	uint16_t ack_length;
1679163953Srrs	struct sctp_asconf_paramhdr *aph;
1680163953Srrs	struct sctp_asconf_addr *aa, *aa_next;
1681163953Srrs	uint32_t last_error_id = 0;	/* last error correlation id */
1682163953Srrs	uint32_t id;
1683163953Srrs	struct sctp_asconf_addr *ap;
1684163953Srrs
1685163953Srrs	/* asconf param buffer */
1686166675Srrs	uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE];
1687163953Srrs
1688163953Srrs	/* verify minimum length */
1689163953Srrs	if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_asconf_ack_chunk)) {
1690169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
1691169420Srrs		    "handle_asconf_ack: chunk too small = %xh\n",
1692169420Srrs		    ntohs(cp->ch.chunk_length));
1693163953Srrs		return;
1694163953Srrs	}
1695163953Srrs	asoc = &stcb->asoc;
1696163953Srrs	serial_num = ntohl(cp->serial_number);
1697163953Srrs
1698163953Srrs	/*
1699163953Srrs	 * NOTE: we may want to handle this differently- currently, we will
1700163953Srrs	 * abort when we get an ack for the expected serial number + 1 (eg.
1701163953Srrs	 * we didn't send it), process an ack normally if it is the expected
1702163953Srrs	 * serial number, and re-send the previous ack for *ALL* other
1703163953Srrs	 * serial numbers
1704163953Srrs	 */
1705163953Srrs
1706163953Srrs	/*
1707163953Srrs	 * if the serial number is the next expected, but I didn't send it,
1708163953Srrs	 * abort the asoc, since someone probably just hijacked us...
1709163953Srrs	 */
1710163953Srrs	if (serial_num == (asoc->asconf_seq_out + 1)) {
1711285925Stuexen		struct mbuf *op_err;
1712285925Stuexen		char msg[SCTP_DIAG_INFO_LEN];
1713285925Stuexen
1714169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf_ack: got unexpected next serial number! Aborting asoc!\n");
1715285925Stuexen		snprintf(msg, sizeof(msg), "Never sent serial number %8.8x",
1716285925Stuexen		    serial_num);
1717285925Stuexen		op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
1718285925Stuexen		sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, SCTP_SO_NOT_LOCKED);
1719172190Srrs		*abort_no_unlock = 1;
1720163953Srrs		return;
1721163953Srrs	}
1722179157Srrs	if (serial_num != asoc->asconf_seq_out_acked + 1) {
1723163953Srrs		/* got a duplicate/unexpected ASCONF-ACK */
1724169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf_ack: got duplicate/unexpected serial number = %xh (expected = %xh)\n",
1725179157Srrs		    serial_num, asoc->asconf_seq_out_acked + 1);
1726163953Srrs		return;
1727163953Srrs	}
1728347154Stuexen
1729179157Srrs	if (serial_num == asoc->asconf_seq_out - 1) {
1730179157Srrs		/* stop our timer */
1731179157Srrs		sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net,
1732283650Stuexen		    SCTP_FROM_SCTP_ASCONF + SCTP_LOC_5);
1733163953Srrs	}
1734347154Stuexen
1735163953Srrs	/* process the ASCONF-ACK contents */
1736163953Srrs	ack_length = ntohs(cp->ch.chunk_length) -
1737163953Srrs	    sizeof(struct sctp_asconf_ack_chunk);
1738163953Srrs	offset += sizeof(struct sctp_asconf_ack_chunk);
1739163953Srrs	/* process through all parameters */
1740163953Srrs	while (ack_length >= sizeof(struct sctp_asconf_paramhdr)) {
1741163953Srrs		unsigned int param_length, param_type;
1742163953Srrs
1743163953Srrs		/* get pointer to next asconf parameter */
1744163953Srrs		aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset,
1745163953Srrs		    sizeof(struct sctp_asconf_paramhdr), aparam_buf);
1746163953Srrs		if (aph == NULL) {
1747163953Srrs			/* can't get an asconf paramhdr */
1748163953Srrs			sctp_asconf_ack_clear(stcb);
1749163953Srrs			return;
1750163953Srrs		}
1751163953Srrs		param_type = ntohs(aph->ph.param_type);
1752163953Srrs		param_length = ntohs(aph->ph.param_length);
1753163953Srrs		if (param_length > ack_length) {
1754163953Srrs			sctp_asconf_ack_clear(stcb);
1755163953Srrs			return;
1756163953Srrs		}
1757163953Srrs		if (param_length < sizeof(struct sctp_paramhdr)) {
1758163953Srrs			sctp_asconf_ack_clear(stcb);
1759163953Srrs			return;
1760163953Srrs		}
1761163953Srrs		/* get the complete parameter... */
1762163953Srrs		if (param_length > sizeof(aparam_buf)) {
1763169420Srrs			SCTPDBG(SCTP_DEBUG_ASCONF1,
1764169420Srrs			    "param length (%u) larger than buffer size!\n", param_length);
1765163953Srrs			sctp_asconf_ack_clear(stcb);
1766163953Srrs			return;
1767163953Srrs		}
1768163953Srrs		aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, param_length, aparam_buf);
1769163953Srrs		if (aph == NULL) {
1770163953Srrs			sctp_asconf_ack_clear(stcb);
1771163953Srrs			return;
1772163953Srrs		}
1773163953Srrs		/* correlation_id is transparent to peer, no ntohl needed */
1774163953Srrs		id = aph->correlation_id;
1775163953Srrs
1776163953Srrs		switch (param_type) {
1777163953Srrs		case SCTP_ERROR_CAUSE_IND:
1778163953Srrs			last_error_id = id;
1779163953Srrs			/* find the corresponding asconf param in our queue */
1780163953Srrs			ap = sctp_asconf_find_param(stcb, id);
1781163953Srrs			if (ap == NULL) {
1782163953Srrs				/* hmm... can't find this in our queue! */
1783163953Srrs				break;
1784163953Srrs			}
1785163953Srrs			/* process the parameter, failed flag */
1786163953Srrs			sctp_asconf_process_param_ack(stcb, ap, 0);
1787163953Srrs			/* process the error response */
1788163953Srrs			sctp_asconf_process_error(stcb, aph);
1789163953Srrs			break;
1790163953Srrs		case SCTP_SUCCESS_REPORT:
1791163953Srrs			/* find the corresponding asconf param in our queue */
1792163953Srrs			ap = sctp_asconf_find_param(stcb, id);
1793163953Srrs			if (ap == NULL) {
1794163953Srrs				/* hmm... can't find this in our queue! */
1795163953Srrs				break;
1796163953Srrs			}
1797163953Srrs			/* process the parameter, success flag */
1798163953Srrs			sctp_asconf_process_param_ack(stcb, ap, 1);
1799163953Srrs			break;
1800163953Srrs		default:
1801163953Srrs			break;
1802163953Srrs		}		/* switch */
1803163953Srrs
1804163953Srrs		/* update remaining ASCONF-ACK message length to process */
1805361476Stuexen		if (ack_length > SCTP_SIZE32(param_length)) {
1806361476Stuexen			ack_length -= SCTP_SIZE32(param_length);
1807361476Stuexen		} else {
1808163953Srrs			break;
1809163953Srrs		}
1810163953Srrs		offset += SCTP_SIZE32(param_length);
1811163953Srrs	}			/* while */
1812163953Srrs
1813163953Srrs	/*
1814163953Srrs	 * if there are any "sent" params still on the queue, these are
1815163953Srrs	 * implicitly "success", or "failed" (if we got an error back) ...
1816163953Srrs	 * so process these appropriately
1817310218Stuexen	 *
1818163953Srrs	 * we assume that the correlation_id's are monotonically increasing
1819163953Srrs	 * beginning from 1 and that we don't have *that* many outstanding
1820163953Srrs	 * at any given time
1821163953Srrs	 */
1822163953Srrs	if (last_error_id == 0)
1823347154Stuexen		last_error_id--;	/* set to "max" value */
1824216822Stuexen	TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) {
1825163953Srrs		if (aa->sent == 1) {
1826163953Srrs			/*
1827163953Srrs			 * implicitly successful or failed if correlation_id
1828163953Srrs			 * < last_error_id, then success else, failure
1829163953Srrs			 */
1830163953Srrs			if (aa->ap.aph.correlation_id < last_error_id)
1831171477Srrs				sctp_asconf_process_param_ack(stcb, aa, 1);
1832163953Srrs			else
1833171477Srrs				sctp_asconf_process_param_ack(stcb, aa, 0);
1834163953Srrs		} else {
1835163953Srrs			/*
1836163953Srrs			 * since we always process in order (FIFO queue) if
1837163953Srrs			 * we reach one that hasn't been sent, the rest
1838163953Srrs			 * should not have been sent either. so, we're
1839163953Srrs			 * done...
1840163953Srrs			 */
1841163953Srrs			break;
1842163953Srrs		}
1843163953Srrs	}
1844163953Srrs
1845163953Srrs	/* update the next sequence number to use */
1846179157Srrs	asoc->asconf_seq_out_acked++;
1847163953Srrs	/* remove the old ASCONF on our outbound queue */
1848163953Srrs	sctp_toss_old_asconf(stcb);
1849163953Srrs	if (!TAILQ_EMPTY(&stcb->asoc.asconf_queue)) {
1850171572Srrs#ifdef SCTP_TIMER_BASED_ASCONF
1851163953Srrs		/* we have more params, so restart our timer */
1852163953Srrs		sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep,
1853163953Srrs		    stcb, net);
1854171572Srrs#else
1855171572Srrs		/* we have more params, so send out more */
1856172190Srrs		sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED);
1857171572Srrs#endif
1858163953Srrs	}
1859163953Srrs}
1860163953Srrs
1861178251Srrs#ifdef INET6
1862163953Srrsstatic uint32_t
1863163953Srrssctp_is_scopeid_in_nets(struct sctp_tcb *stcb, struct sockaddr *sa)
1864163953Srrs{
1865163953Srrs	struct sockaddr_in6 *sin6, *net6;
1866163953Srrs	struct sctp_nets *net;
1867163953Srrs
1868163953Srrs	if (sa->sa_family != AF_INET6) {
1869163953Srrs		/* wrong family */
1870163953Srrs		return (0);
1871163953Srrs	}
1872163953Srrs	sin6 = (struct sockaddr_in6 *)sa;
1873163953Srrs	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) == 0) {
1874163953Srrs		/* not link local address */
1875163953Srrs		return (0);
1876163953Srrs	}
1877163953Srrs	/* hunt through our destination nets list for this scope_id */
1878163953Srrs	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1879163953Srrs		if (((struct sockaddr *)(&net->ro._l_addr))->sa_family !=
1880163953Srrs		    AF_INET6)
1881163953Srrs			continue;
1882163953Srrs		net6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1883163953Srrs		if (IN6_IS_ADDR_LINKLOCAL(&net6->sin6_addr) == 0)
1884163953Srrs			continue;
1885163953Srrs		if (sctp_is_same_scope(sin6, net6)) {
1886163953Srrs			/* found one */
1887163953Srrs			return (1);
1888163953Srrs		}
1889163953Srrs	}
1890163953Srrs	/* didn't find one */
1891163953Srrs	return (0);
1892163953Srrs}
1893178251Srrs#endif
1894178251Srrs
1895163953Srrs/*
1896163953Srrs * address management functions
1897163953Srrs */
1898163953Srrsstatic void
1899163953Srrssctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1900172190Srrs    struct sctp_ifa *ifa, uint16_t type, int addr_locked)
1901163953Srrs{
1902163953Srrs	int status;
1903163953Srrs
1904224641Stuexen	if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0 ||
1905163953Srrs	    sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
1906163953Srrs		/* subset bound, no ASCONF allowed case, so ignore */
1907163953Srrs		return;
1908163953Srrs	}
1909163953Srrs	/*
1910163953Srrs	 * note: we know this is not the subset bound, no ASCONF case eg.
1911163953Srrs	 * this is boundall or subset bound w/ASCONF allowed
1912163953Srrs	 */
1913163953Srrs
1914267674Stuexen	/* first, make sure that the address is IPv4 or IPv6 and not jailed */
1915221249Stuexen	switch (ifa->address.sa.sa_family) {
1916221249Stuexen#ifdef INET6
1917221249Stuexen	case AF_INET6:
1918267674Stuexen		if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
1919267674Stuexen		    &ifa->address.sin6.sin6_addr) != 0) {
1920267674Stuexen			return;
1921267674Stuexen		}
1922221249Stuexen		break;
1923221249Stuexen#endif
1924221249Stuexen#ifdef INET
1925221249Stuexen	case AF_INET:
1926267674Stuexen		if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
1927267674Stuexen		    &ifa->address.sin.sin_addr) != 0) {
1928267674Stuexen			return;
1929267674Stuexen		}
1930221249Stuexen		break;
1931221249Stuexen#endif
1932221249Stuexen	default:
1933163953Srrs		return;
1934163953Srrs	}
1935221249Stuexen#ifdef INET6
1936163953Srrs	/* make sure we're "allowed" to add this type of addr */
1937167598Srrs	if (ifa->address.sa.sa_family == AF_INET6) {
1938163953Srrs		/* invalid if we're not a v6 endpoint */
1939163953Srrs		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0)
1940163953Srrs			return;
1941163953Srrs		/* is the v6 addr really valid ? */
1942167598Srrs		if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
1943163953Srrs			return;
1944163953Srrs		}
1945163953Srrs	}
1946221249Stuexen#endif
1947163953Srrs	/* put this address on the "pending/do not use yet" list */
1948171572Srrs	sctp_add_local_addr_restricted(stcb, ifa);
1949163953Srrs	/*
1950163953Srrs	 * check address scope if address is out of scope, don't queue
1951163953Srrs	 * anything... note: this would leave the address on both inp and
1952163953Srrs	 * asoc lists
1953163953Srrs	 */
1954178251Srrs	switch (ifa->address.sa.sa_family) {
1955178251Srrs#ifdef INET6
1956178251Srrs	case AF_INET6:
1957178251Srrs		{
1958178251Srrs			struct sockaddr_in6 *sin6;
1959163953Srrs
1960271221Stuexen			sin6 = &ifa->address.sin6;
1961178251Srrs			if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
1962178251Srrs				/* we skip unspecifed addresses */
1963163953Srrs				return;
1964163953Srrs			}
1965178251Srrs			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1966246595Stuexen				if (stcb->asoc.scope.local_scope == 0) {
1967178251Srrs					return;
1968178251Srrs				}
1969178251Srrs				/* is it the right link local scope? */
1970178251Srrs				if (sctp_is_scopeid_in_nets(stcb, &ifa->address.sa) == 0) {
1971178251Srrs					return;
1972178251Srrs				}
1973178251Srrs			}
1974246595Stuexen			if (stcb->asoc.scope.site_scope == 0 &&
1975178251Srrs			    IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
1976163953Srrs				return;
1977163953Srrs			}
1978178251Srrs			break;
1979163953Srrs		}
1980178251Srrs#endif
1981221249Stuexen#ifdef INET
1982178251Srrs	case AF_INET:
1983178251Srrs		{
1984178251Srrs			struct sockaddr_in *sin;
1985178251Srrs			struct in6pcb *inp6;
1986163953Srrs
1987178251Srrs			inp6 = (struct in6pcb *)&inp->ip_inp.inp;
1988178251Srrs			/* invalid if we are a v6 only endpoint */
1989178251Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
1990178251Srrs			    SCTP_IPV6_V6ONLY(inp6))
1991178251Srrs				return;
1992163953Srrs
1993271221Stuexen			sin = &ifa->address.sin;
1994178251Srrs			if (sin->sin_addr.s_addr == 0) {
1995178251Srrs				/* we skip unspecifed addresses */
1996178251Srrs				return;
1997178251Srrs			}
1998246595Stuexen			if (stcb->asoc.scope.ipv4_local_scope == 0 &&
1999178251Srrs			    IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) {
2000178251Srrs				return;
2001178251Srrs			}
2002178251Srrs			break;
2003163953Srrs		}
2004221249Stuexen#endif
2005178251Srrs	default:
2006163953Srrs		/* else, not AF_INET or AF_INET6, so skip */
2007163953Srrs		return;
2008163953Srrs	}
2009163953Srrs
2010163953Srrs	/* queue an asconf for this address add/delete */
2011163953Srrs	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
2012163953Srrs		/* does the peer do asconf? */
2013269858Stuexen		if (stcb->asoc.asconf_supported) {
2014163953Srrs			/* queue an asconf for this addr */
2015163953Srrs			status = sctp_asconf_queue_add(stcb, ifa, type);
2016171572Srrs
2017163953Srrs			/*
2018171572Srrs			 * if queued ok, and in the open state, send out the
2019171572Srrs			 * ASCONF.  If in the non-open state, these will be
2020171572Srrs			 * sent when the state goes open.
2021163953Srrs			 */
2022163953Srrs			if (status == 0 &&
2023347165Stuexen			    ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
2024347165Stuexen			    (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED))) {
2025171572Srrs#ifdef SCTP_TIMER_BASED_ASCONF
2026163953Srrs				sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp,
2027163953Srrs				    stcb, stcb->asoc.primary_destination);
2028171572Srrs#else
2029224641Stuexen				sctp_send_asconf(stcb, NULL, addr_locked);
2030171572Srrs#endif
2031163953Srrs			}
2032163953Srrs		}
2033163953Srrs	}
2034163953Srrs}
2035163953Srrs
2036167598Srrs
2037167598Srrsint
2038228653Stuexensctp_asconf_iterator_ep(struct sctp_inpcb *inp, void *ptr, uint32_t val SCTP_UNUSED)
2039163953Srrs{
2040167598Srrs	struct sctp_asconf_iterator *asc;
2041167598Srrs	struct sctp_ifa *ifa;
2042167598Srrs	struct sctp_laddr *l;
2043167598Srrs	int cnt_invalid = 0;
2044163953Srrs
2045167598Srrs	asc = (struct sctp_asconf_iterator *)ptr;
2046167598Srrs	LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) {
2047167598Srrs		ifa = l->ifa;
2048221249Stuexen		switch (ifa->address.sa.sa_family) {
2049221249Stuexen#ifdef INET6
2050221249Stuexen		case AF_INET6:
2051167598Srrs			/* invalid if we're not a v6 endpoint */
2052167598Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
2053167598Srrs				cnt_invalid++;
2054167598Srrs				if (asc->cnt == cnt_invalid)
2055167598Srrs					return (1);
2056167598Srrs			}
2057221249Stuexen			break;
2058221249Stuexen#endif
2059221249Stuexen#ifdef INET
2060221249Stuexen		case AF_INET:
2061221249Stuexen			{
2062221249Stuexen				/* invalid if we are a v6 only endpoint */
2063221249Stuexen				struct in6pcb *inp6;
2064163953Srrs
2065221249Stuexen				inp6 = (struct in6pcb *)&inp->ip_inp.inp;
2066221249Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
2067221249Stuexen				    SCTP_IPV6_V6ONLY(inp6)) {
2068221249Stuexen					cnt_invalid++;
2069221249Stuexen					if (asc->cnt == cnt_invalid)
2070221249Stuexen						return (1);
2071221249Stuexen				}
2072221249Stuexen				break;
2073163953Srrs			}
2074221249Stuexen#endif
2075221249Stuexen		default:
2076167598Srrs			/* invalid address family */
2077167598Srrs			cnt_invalid++;
2078167598Srrs			if (asc->cnt == cnt_invalid)
2079167598Srrs				return (1);
2080163953Srrs		}
2081163953Srrs	}
2082167598Srrs	return (0);
2083163953Srrs}
2084163953Srrs
2085171572Srrsstatic int
2086228653Stuexensctp_asconf_iterator_ep_end(struct sctp_inpcb *inp, void *ptr, uint32_t val SCTP_UNUSED)
2087163953Srrs{
2088167598Srrs	struct sctp_ifa *ifa;
2089167598Srrs	struct sctp_asconf_iterator *asc;
2090167598Srrs	struct sctp_laddr *laddr, *nladdr, *l;
2091163953Srrs
2092167598Srrs	/* Only for specific case not bound all */
2093167598Srrs	asc = (struct sctp_asconf_iterator *)ptr;
2094167598Srrs	LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) {
2095167598Srrs		ifa = l->ifa;
2096167598Srrs		if (l->action == SCTP_ADD_IP_ADDRESS) {
2097169655Srrs			LIST_FOREACH(laddr, &inp->sctp_addr_list,
2098169655Srrs			    sctp_nxt_addr) {
2099167598Srrs				if (laddr->ifa == ifa) {
2100167598Srrs					laddr->action = 0;
2101167598Srrs					break;
2102167598Srrs				}
2103347154Stuexen
2104167598Srrs			}
2105167598Srrs		} else if (l->action == SCTP_DEL_IP_ADDRESS) {
2106216822Stuexen			LIST_FOREACH_SAFE(laddr, &inp->sctp_addr_list, sctp_nxt_addr, nladdr) {
2107167598Srrs				/* remove only after all guys are done */
2108167598Srrs				if (laddr->ifa == ifa) {
2109167598Srrs					sctp_del_local_addr_ep(inp, ifa);
2110167598Srrs				}
2111167598Srrs			}
2112167598Srrs		}
2113163953Srrs	}
2114167598Srrs	return (0);
2115163953Srrs}
2116163953Srrs
2117167598Srrsvoid
2118171572Srrssctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
2119228653Stuexen    void *ptr, uint32_t val SCTP_UNUSED)
2120163953Srrs{
2121167598Srrs	struct sctp_asconf_iterator *asc;
2122167598Srrs	struct sctp_ifa *ifa;
2123167598Srrs	struct sctp_laddr *l;
2124167598Srrs	int cnt_invalid = 0;
2125167598Srrs	int type, status;
2126171572Srrs	int num_queued = 0;
2127163953Srrs
2128167598Srrs	asc = (struct sctp_asconf_iterator *)ptr;
2129167598Srrs	LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) {
2130167598Srrs		ifa = l->ifa;
2131167598Srrs		type = l->action;
2132170751Srrs
2133170751Srrs		/* address's vrf_id must be the vrf_id of the assoc */
2134170751Srrs		if (ifa->vrf_id != stcb->asoc.vrf_id) {
2135170751Srrs			continue;
2136170751Srrs		}
2137347154Stuexen
2138167598Srrs		/* Same checks again for assoc */
2139178251Srrs		switch (ifa->address.sa.sa_family) {
2140178251Srrs#ifdef INET6
2141178251Srrs		case AF_INET6:
2142178251Srrs			{
2143178251Srrs				/* invalid if we're not a v6 endpoint */
2144178251Srrs				struct sockaddr_in6 *sin6;
2145163953Srrs
2146178251Srrs				if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
2147178251Srrs					cnt_invalid++;
2148178251Srrs					if (asc->cnt == cnt_invalid)
2149178251Srrs						return;
2150178251Srrs					else
2151178251Srrs						continue;
2152167598Srrs				}
2153271221Stuexen				sin6 = &ifa->address.sin6;
2154178251Srrs				if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
2155178251Srrs					/* we skip unspecifed addresses */
2156167598Srrs					continue;
2157167598Srrs				}
2158267674Stuexen				if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
2159267674Stuexen				    &sin6->sin6_addr) != 0) {
2160267674Stuexen					continue;
2161267674Stuexen				}
2162178251Srrs				if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
2163246595Stuexen					if (stcb->asoc.scope.local_scope == 0) {
2164178251Srrs						continue;
2165178251Srrs					}
2166178251Srrs					/* is it the right link local scope? */
2167178251Srrs					if (sctp_is_scopeid_in_nets(stcb, &ifa->address.sa) == 0) {
2168178251Srrs						continue;
2169178251Srrs					}
2170178251Srrs				}
2171178251Srrs				break;
2172167598Srrs			}
2173178251Srrs#endif
2174221249Stuexen#ifdef INET
2175178251Srrs		case AF_INET:
2176178251Srrs			{
2177178251Srrs				/* invalid if we are a v6 only endpoint */
2178178251Srrs				struct in6pcb *inp6;
2179178251Srrs				struct sockaddr_in *sin;
2180163953Srrs
2181178251Srrs				inp6 = (struct in6pcb *)&inp->ip_inp.inp;
2182178251Srrs				/* invalid if we are a v6 only endpoint */
2183178251Srrs				if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
2184178251Srrs				    SCTP_IPV6_V6ONLY(inp6))
2185178251Srrs					continue;
2186167598Srrs
2187271221Stuexen				sin = &ifa->address.sin;
2188178251Srrs				if (sin->sin_addr.s_addr == 0) {
2189178251Srrs					/* we skip unspecifed addresses */
2190167598Srrs					continue;
2191178251Srrs				}
2192267674Stuexen				if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
2193267674Stuexen				    &sin->sin_addr) != 0) {
2194267674Stuexen					continue;
2195267674Stuexen				}
2196246595Stuexen				if (stcb->asoc.scope.ipv4_local_scope == 0 &&
2197178251Srrs				    IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) {
2198201758Smbr					continue;
2199178251Srrs				}
2200178251Srrs				if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
2201178251Srrs				    SCTP_IPV6_V6ONLY(inp6)) {
2202178251Srrs					cnt_invalid++;
2203178251Srrs					if (asc->cnt == cnt_invalid)
2204178251Srrs						return;
2205178251Srrs					else
2206178251Srrs						continue;
2207178251Srrs				}
2208178251Srrs				break;
2209167598Srrs			}
2210221249Stuexen#endif
2211178251Srrs		default:
2212167598Srrs			/* invalid address family */
2213167598Srrs			cnt_invalid++;
2214167598Srrs			if (asc->cnt == cnt_invalid)
2215163953Srrs				return;
2216167598Srrs			else
2217167598Srrs				continue;
2218178251Srrs			break;
2219163953Srrs		}
2220163953Srrs
2221167598Srrs		if (type == SCTP_ADD_IP_ADDRESS) {
2222171572Srrs			/* prevent this address from being used as a source */
2223171572Srrs			sctp_add_local_addr_restricted(stcb, ifa);
2224167598Srrs		} else if (type == SCTP_DEL_IP_ADDRESS) {
2225163953Srrs			struct sctp_nets *net;
2226163953Srrs
2227163953Srrs			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
2228169352Srrs				sctp_rtentry_t *rt;
2229163953Srrs
2230163953Srrs				/* delete this address if cached */
2231172091Srrs				if (net->ro._s_addr == ifa) {
2232167598Srrs					sctp_free_ifa(net->ro._s_addr);
2233167598Srrs					net->ro._s_addr = NULL;
2234167598Srrs					net->src_addr_selected = 0;
2235167598Srrs					rt = net->ro.ro_rt;
2236167598Srrs					if (rt) {
2237167598Srrs						RTFREE(rt);
2238167598Srrs						net->ro.ro_rt = NULL;
2239167598Srrs					}
2240167598Srrs					/*
2241167598Srrs					 * Now we deleted our src address,
2242167598Srrs					 * should we not also now reset the
2243167598Srrs					 * cwnd/rto to start as if its a new
2244167598Srrs					 * address?
2245167598Srrs					 */
2246171440Srrs					stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
2247170428Srrs					net->RTO = 0;
2248167598Srrs
2249163953Srrs				}
2250167598Srrs			}
2251167598Srrs		} else if (type == SCTP_SET_PRIM_ADDR) {
2252167598Srrs			if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
2253171572Srrs				/* must validate the ifa is in the ep */
2254167598Srrs				if (sctp_is_addr_in_ep(stcb->sctp_ep, ifa) == 0) {
2255167598Srrs					continue;
2256163953Srrs				}
2257167598Srrs			} else {
2258167598Srrs				/* Need to check scopes for this guy */
2259246595Stuexen				if (sctp_is_address_in_scope(ifa, &stcb->asoc.scope, 0) == 0) {
2260167598Srrs					continue;
2261167598Srrs				}
2262163953Srrs			}
2263163953Srrs		}
2264167598Srrs		/* queue an asconf for this address add/delete */
2265171572Srrs		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF) &&
2266269858Stuexen		    stcb->asoc.asconf_supported == 1) {
2267171572Srrs			/* queue an asconf for this addr */
2268171572Srrs			status = sctp_asconf_queue_add(stcb, ifa, type);
2269171572Srrs			/*
2270171572Srrs			 * if queued ok, and in the open state, update the
2271171572Srrs			 * count of queued params.  If in the non-open
2272171572Srrs			 * state, these get sent when the assoc goes open.
2273171572Srrs			 */
2274347165Stuexen			if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
2275347165Stuexen			    (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
2276171572Srrs				if (status >= 0) {
2277171572Srrs					num_queued++;
2278167598Srrs				}
2279167598Srrs			}
2280167598Srrs		}
2281163953Srrs	}
2282171572Srrs	/*
2283171572Srrs	 * If we have queued params in the open state, send out an ASCONF.
2284171572Srrs	 */
2285171572Srrs	if (num_queued > 0) {
2286224641Stuexen		sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
2287171572Srrs	}
2288163953Srrs}
2289163953Srrs
2290171572Srrsvoid
2291228653Stuexensctp_asconf_iterator_end(void *ptr, uint32_t val SCTP_UNUSED)
2292167598Srrs{
2293167598Srrs	struct sctp_asconf_iterator *asc;
2294167598Srrs	struct sctp_ifa *ifa;
2295216822Stuexen	struct sctp_laddr *l, *nl;
2296167598Srrs
2297167598Srrs	asc = (struct sctp_asconf_iterator *)ptr;
2298216822Stuexen	LIST_FOREACH_SAFE(l, &asc->list_of_work, sctp_nxt_addr, nl) {
2299167598Srrs		ifa = l->ifa;
2300167598Srrs		if (l->action == SCTP_ADD_IP_ADDRESS) {
2301167598Srrs			/* Clear the defer use flag */
2302167598Srrs			ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE;
2303167598Srrs		}
2304167598Srrs		sctp_free_ifa(ifa);
2305179783Srrs		SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_laddr), l);
2306167598Srrs		SCTP_DECR_LADDR_COUNT();
2307167598Srrs	}
2308170091Srrs	SCTP_FREE(asc, SCTP_M_ASC_IT);
2309167598Srrs}
2310167598Srrs
2311163953Srrs/*
2312171572Srrs * sa is the sockaddr to ask the peer to set primary to.
2313171572Srrs * returns: 0 = completed, -1 = error
2314163953Srrs */
2315171943Srrsint32_t
2316163953Srrssctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa)
2317163953Srrs{
2318172190Srrs	uint32_t vrf_id;
2319172190Srrs	struct sctp_ifa *ifa;
2320163953Srrs
2321172190Srrs	/* find the ifa for the desired set primary */
2322172218Srrs	vrf_id = stcb->asoc.vrf_id;
2323172190Srrs	ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED);
2324172190Srrs	if (ifa == NULL) {
2325172190Srrs		/* Invalid address */
2326172190Srrs		return (-1);
2327172190Srrs	}
2328347154Stuexen
2329163953Srrs	/* queue an ASCONF:SET_PRIM_ADDR to be sent */
2330172190Srrs	if (!sctp_asconf_queue_add(stcb, ifa, SCTP_SET_PRIM_ADDR)) {
2331163953Srrs		/* set primary queuing succeeded */
2332171572Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
2333171572Srrs		    "set_primary_ip_address_sa: queued on tcb=%p, ",
2334240148Stuexen		    (void *)stcb);
2335171572Srrs		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
2336347165Stuexen		if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
2337347165Stuexen		    (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
2338171572Srrs#ifdef SCTP_TIMER_BASED_ASCONF
2339163953Srrs			sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
2340163953Srrs			    stcb->sctp_ep, stcb,
2341163953Srrs			    stcb->asoc.primary_destination);
2342171572Srrs#else
2343224641Stuexen			sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
2344171572Srrs#endif
2345163953Srrs		}
2346163953Srrs	} else {
2347169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1, "set_primary_ip_address_sa: failed to add to queue on tcb=%p, ",
2348240148Stuexen		    (void *)stcb);
2349169420Srrs		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
2350163953Srrs		return (-1);
2351163953Srrs	}
2352163953Srrs	return (0);
2353163953Srrs}
2354163953Srrs
2355179157Srrsint
2356179157Srrssctp_is_addr_pending(struct sctp_tcb *stcb, struct sctp_ifa *sctp_ifa)
2357179157Srrs{
2358179157Srrs	struct sctp_tmit_chunk *chk, *nchk;
2359179157Srrs	unsigned int offset, asconf_limit;
2360179157Srrs	struct sctp_asconf_chunk *acp;
2361179157Srrs	struct sctp_asconf_paramhdr *aph;
2362179157Srrs	uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE];
2363221249Stuexen	struct sctp_paramhdr *ph;
2364179157Srrs	int add_cnt, del_cnt;
2365179157Srrs	uint16_t last_param_type;
2366179157Srrs
2367179157Srrs	add_cnt = del_cnt = 0;
2368179157Srrs	last_param_type = 0;
2369216822Stuexen	TAILQ_FOREACH_SAFE(chk, &stcb->asoc.asconf_send_queue, sctp_next, nchk) {
2370179157Srrs		if (chk->data == NULL) {
2371179157Srrs			SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: No mbuf data?\n");
2372179157Srrs			continue;
2373179157Srrs		}
2374179157Srrs		offset = 0;
2375179157Srrs		acp = mtod(chk->data, struct sctp_asconf_chunk *);
2376179157Srrs		offset += sizeof(struct sctp_asconf_chunk);
2377179157Srrs		asconf_limit = ntohs(acp->ch.chunk_length);
2378221249Stuexen		ph = (struct sctp_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_paramhdr), aparam_buf);
2379221249Stuexen		if (ph == NULL) {
2380179157Srrs			SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: couldn't get lookup addr!\n");
2381179157Srrs			continue;
2382179157Srrs		}
2383221249Stuexen		offset += ntohs(ph->param_length);
2384179157Srrs
2385179157Srrs		aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_asconf_paramhdr), aparam_buf);
2386179157Srrs		if (aph == NULL) {
2387179157Srrs			SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: Empty ASCONF will be sent?\n");
2388179157Srrs			continue;
2389179157Srrs		}
2390179157Srrs		while (aph != NULL) {
2391179157Srrs			unsigned int param_length, param_type;
2392179157Srrs
2393179157Srrs			param_type = ntohs(aph->ph.param_type);
2394179157Srrs			param_length = ntohs(aph->ph.param_length);
2395179157Srrs			if (offset + param_length > asconf_limit) {
2396179157Srrs				/* parameter goes beyond end of chunk! */
2397179157Srrs				break;
2398179157Srrs			}
2399179157Srrs			if (param_length > sizeof(aparam_buf)) {
2400179157Srrs				SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: param length (%u) larger than buffer size!\n", param_length);
2401179157Srrs				break;
2402179157Srrs			}
2403179157Srrs			if (param_length <= sizeof(struct sctp_paramhdr)) {
2404179157Srrs				SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: param length(%u) too short\n", param_length);
2405179157Srrs				break;
2406179157Srrs			}
2407347154Stuexen
2408179157Srrs			aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, param_length, aparam_buf);
2409179157Srrs			if (aph == NULL) {
2410179157Srrs				SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: couldn't get entire param\n");
2411179157Srrs				break;
2412179157Srrs			}
2413347154Stuexen
2414221249Stuexen			ph = (struct sctp_paramhdr *)(aph + 1);
2415221249Stuexen			if (sctp_addr_match(ph, &sctp_ifa->address.sa) != 0) {
2416179157Srrs				switch (param_type) {
2417179157Srrs				case SCTP_ADD_IP_ADDRESS:
2418179157Srrs					add_cnt++;
2419179157Srrs					break;
2420179157Srrs				case SCTP_DEL_IP_ADDRESS:
2421179157Srrs					del_cnt++;
2422179157Srrs					break;
2423179157Srrs				default:
2424179157Srrs					break;
2425179157Srrs				}
2426179157Srrs				last_param_type = param_type;
2427179157Srrs			}
2428347154Stuexen
2429179157Srrs			offset += SCTP_SIZE32(param_length);
2430179157Srrs			if (offset >= asconf_limit) {
2431179157Srrs				/* no more data in the mbuf chain */
2432179157Srrs				break;
2433179157Srrs			}
2434179157Srrs			/* get pointer to next asconf param */
2435179157Srrs			aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_asconf_paramhdr), aparam_buf);
2436179157Srrs		}
2437179157Srrs	}
2438179157Srrs
2439310773Stuexen	/*
2440310773Stuexen	 * we want to find the sequences which consist of ADD -> DEL -> ADD
2441310773Stuexen	 * or DEL -> ADD
2442310773Stuexen	 */
2443179157Srrs	if (add_cnt > del_cnt ||
2444179157Srrs	    (add_cnt == del_cnt && last_param_type == SCTP_ADD_IP_ADDRESS)) {
2445228907Stuexen		return (1);
2446179157Srrs	}
2447228907Stuexen	return (0);
2448179157Srrs}
2449179157Srrs
2450163953Srrsstatic struct sockaddr *
2451172190Srrssctp_find_valid_localaddr(struct sctp_tcb *stcb, int addr_locked)
2452163953Srrs{
2453167598Srrs	struct sctp_vrf *vrf = NULL;
2454167598Srrs	struct sctp_ifn *sctp_ifn;
2455167598Srrs	struct sctp_ifa *sctp_ifa;
2456163953Srrs
2457172190Srrs	if (addr_locked == SCTP_ADDR_NOT_LOCKED)
2458172218Srrs		SCTP_IPI_ADDR_RLOCK();
2459167598Srrs	vrf = sctp_find_vrf(stcb->asoc.vrf_id);
2460169420Srrs	if (vrf == NULL) {
2461172190Srrs		if (addr_locked == SCTP_ADDR_NOT_LOCKED)
2462172218Srrs			SCTP_IPI_ADDR_RUNLOCK();
2463169420Srrs		return (NULL);
2464169420Srrs	}
2465167598Srrs	LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
2466246595Stuexen		if (stcb->asoc.scope.loopback_scope == 0 &&
2467167598Srrs		    SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
2468163953Srrs			/* Skip if loopback_scope not set */
2469163953Srrs			continue;
2470163953Srrs		}
2471167598Srrs		LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
2472221249Stuexen			switch (sctp_ifa->address.sa.sa_family) {
2473221249Stuexen#ifdef INET
2474221249Stuexen			case AF_INET:
2475246595Stuexen				if (stcb->asoc.scope.ipv4_addr_legal) {
2476221249Stuexen					struct sockaddr_in *sin;
2477163953Srrs
2478271221Stuexen					sin = &sctp_ifa->address.sin;
2479221249Stuexen					if (sin->sin_addr.s_addr == 0) {
2480221249Stuexen						/* skip unspecifed addresses */
2481221249Stuexen						continue;
2482221249Stuexen					}
2483267674Stuexen					if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred,
2484267674Stuexen					    &sin->sin_addr) != 0) {
2485267674Stuexen						continue;
2486267674Stuexen					}
2487246595Stuexen					if (stcb->asoc.scope.ipv4_local_scope == 0 &&
2488221249Stuexen					    IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))
2489221249Stuexen						continue;
2490221249Stuexen
2491221249Stuexen					if (sctp_is_addr_restricted(stcb, sctp_ifa) &&
2492221249Stuexen					    (!sctp_is_addr_pending(stcb, sctp_ifa)))
2493221249Stuexen						continue;
2494310773Stuexen					/*
2495310773Stuexen					 * found a valid local v4 address to
2496310773Stuexen					 * use
2497310773Stuexen					 */
2498221249Stuexen					if (addr_locked == SCTP_ADDR_NOT_LOCKED)
2499221249Stuexen						SCTP_IPI_ADDR_RUNLOCK();
2500221249Stuexen					return (&sctp_ifa->address.sa);
2501163953Srrs				}
2502221249Stuexen				break;
2503221249Stuexen#endif
2504221249Stuexen#ifdef INET6
2505221249Stuexen			case AF_INET6:
2506246595Stuexen				if (stcb->asoc.scope.ipv6_addr_legal) {
2507221249Stuexen					struct sockaddr_in6 *sin6;
2508163953Srrs
2509221249Stuexen					if (sctp_ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
2510221249Stuexen						continue;
2511221249Stuexen					}
2512347154Stuexen
2513271221Stuexen					sin6 = &sctp_ifa->address.sin6;
2514221249Stuexen					if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
2515310773Stuexen						/*
2516310773Stuexen						 * we skip unspecifed
2517310773Stuexen						 * addresses
2518310773Stuexen						 */
2519221249Stuexen						continue;
2520221249Stuexen					}
2521267674Stuexen					if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred,
2522267674Stuexen					    &sin6->sin6_addr) != 0) {
2523267674Stuexen						continue;
2524267674Stuexen					}
2525246595Stuexen					if (stcb->asoc.scope.local_scope == 0 &&
2526221249Stuexen					    IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
2527221249Stuexen						continue;
2528246595Stuexen					if (stcb->asoc.scope.site_scope == 0 &&
2529221249Stuexen					    IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))
2530221249Stuexen						continue;
2531163953Srrs
2532221249Stuexen					if (sctp_is_addr_restricted(stcb, sctp_ifa) &&
2533221249Stuexen					    (!sctp_is_addr_pending(stcb, sctp_ifa)))
2534221249Stuexen						continue;
2535310773Stuexen					/*
2536310773Stuexen					 * found a valid local v6 address to
2537310773Stuexen					 * use
2538310773Stuexen					 */
2539221249Stuexen					if (addr_locked == SCTP_ADDR_NOT_LOCKED)
2540221249Stuexen						SCTP_IPI_ADDR_RUNLOCK();
2541221249Stuexen					return (&sctp_ifa->address.sa);
2542167598Srrs				}
2543221249Stuexen				break;
2544221249Stuexen#endif
2545221249Stuexen			default:
2546221249Stuexen				break;
2547163953Srrs			}
2548163953Srrs		}
2549163953Srrs	}
2550163953Srrs	/* no valid addresses found */
2551172190Srrs	if (addr_locked == SCTP_ADDR_NOT_LOCKED)
2552172218Srrs		SCTP_IPI_ADDR_RUNLOCK();
2553163953Srrs	return (NULL);
2554163953Srrs}
2555163953Srrs
2556163953Srrsstatic struct sockaddr *
2557163953Srrssctp_find_valid_localaddr_ep(struct sctp_tcb *stcb)
2558163953Srrs{
2559163953Srrs	struct sctp_laddr *laddr;
2560163953Srrs
2561163953Srrs	LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) {
2562163953Srrs		if (laddr->ifa == NULL) {
2563163953Srrs			continue;
2564163953Srrs		}
2565163953Srrs		/* is the address restricted ? */
2566179157Srrs		if (sctp_is_addr_restricted(stcb, laddr->ifa) &&
2567179157Srrs		    (!sctp_is_addr_pending(stcb, laddr->ifa)))
2568163953Srrs			continue;
2569163953Srrs
2570163953Srrs		/* found a valid local address to use */
2571167598Srrs		return (&laddr->ifa->address.sa);
2572163953Srrs	}
2573163953Srrs	/* no valid addresses found */
2574163953Srrs	return (NULL);
2575163953Srrs}
2576163953Srrs
2577163953Srrs/*
2578171477Srrs * builds an ASCONF chunk from queued ASCONF params.
2579171477Srrs * returns NULL on error (no mbuf, no ASCONF params queued, etc).
2580163953Srrs */
2581163953Srrsstruct mbuf *
2582172190Srrssctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked)
2583163953Srrs{
2584163953Srrs	struct mbuf *m_asconf, *m_asconf_chk;
2585163953Srrs	struct sctp_asconf_addr *aa;
2586163953Srrs	struct sctp_asconf_chunk *acp;
2587163953Srrs	struct sctp_asconf_paramhdr *aph;
2588163953Srrs	struct sctp_asconf_addr_param *aap;
2589163953Srrs	uint32_t p_length;
2590163953Srrs	uint32_t correlation_id = 1;	/* 0 is reserved... */
2591163953Srrs	caddr_t ptr, lookup_ptr;
2592163953Srrs	uint8_t lookup_used = 0;
2593163953Srrs
2594163953Srrs	/* are there any asconf params to send? */
2595179157Srrs	TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) {
2596179157Srrs		if (aa->sent == 0)
2597179157Srrs			break;
2598163953Srrs	}
2599179157Srrs	if (aa == NULL)
2600171572Srrs		return (NULL);
2601179157Srrs
2602163953Srrs	/*
2603163953Srrs	 * get a chunk header mbuf and a cluster for the asconf params since
2604163953Srrs	 * it's simpler to fill in the asconf chunk header lookup address on
2605163953Srrs	 * the fly
2606163953Srrs	 */
2607243882Sglebius	m_asconf_chk = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_chunk), 0, M_NOWAIT, 1, MT_DATA);
2608163953Srrs	if (m_asconf_chk == NULL) {
2609163953Srrs		/* no mbuf's */
2610169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
2611169420Srrs		    "compose_asconf: couldn't get chunk mbuf!\n");
2612163953Srrs		return (NULL);
2613163953Srrs	}
2614243882Sglebius	m_asconf = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
2615163953Srrs	if (m_asconf == NULL) {
2616163953Srrs		/* no mbuf's */
2617169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
2618169420Srrs		    "compose_asconf: couldn't get mbuf!\n");
2619163953Srrs		sctp_m_freem(m_asconf_chk);
2620163953Srrs		return (NULL);
2621163953Srrs	}
2622165647Srrs	SCTP_BUF_LEN(m_asconf_chk) = sizeof(struct sctp_asconf_chunk);
2623165647Srrs	SCTP_BUF_LEN(m_asconf) = 0;
2624163953Srrs	acp = mtod(m_asconf_chk, struct sctp_asconf_chunk *);
2625332172Stuexen	memset(acp, 0, sizeof(struct sctp_asconf_chunk));
2626163953Srrs	/* save pointers to lookup address and asconf params */
2627163953Srrs	lookup_ptr = (caddr_t)(acp + 1);	/* after the header */
2628163953Srrs	ptr = mtod(m_asconf, caddr_t);	/* beginning of cluster */
2629163953Srrs
2630163953Srrs	/* fill in chunk header info */
2631163953Srrs	acp->ch.chunk_type = SCTP_ASCONF;
2632163953Srrs	acp->ch.chunk_flags = 0;
2633163953Srrs	acp->serial_number = htonl(stcb->asoc.asconf_seq_out);
2634179157Srrs	stcb->asoc.asconf_seq_out++;
2635163953Srrs
2636163953Srrs	/* add parameters... up to smallest MTU allowed */
2637163953Srrs	TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) {
2638179157Srrs		if (aa->sent)
2639179157Srrs			continue;
2640163953Srrs		/* get the parameter length */
2641163953Srrs		p_length = SCTP_SIZE32(aa->ap.aph.ph.param_length);
2642163953Srrs		/* will it fit in current chunk? */
2643257803Stuexen		if ((SCTP_BUF_LEN(m_asconf) + p_length > stcb->asoc.smallest_mtu) ||
2644257803Stuexen		    (SCTP_BUF_LEN(m_asconf) + p_length > MCLBYTES)) {
2645163953Srrs			/* won't fit, so we're done with this chunk */
2646163953Srrs			break;
2647163953Srrs		}
2648163953Srrs		/* assign (and store) a correlation id */
2649163953Srrs		aa->ap.aph.correlation_id = correlation_id++;
2650163953Srrs
2651163953Srrs		/*
2652163953Srrs		 * fill in address if we're doing a delete this is a simple
2653163953Srrs		 * way for us to fill in the correlation address, which
2654163953Srrs		 * should only be used by the peer if we're deleting our
2655163953Srrs		 * source address and adding a new address (e.g. renumbering
2656163953Srrs		 * case)
2657163953Srrs		 */
2658163953Srrs		if (lookup_used == 0 &&
2659185694Srrs		    (aa->special_del == 0) &&
2660163953Srrs		    aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS) {
2661163953Srrs			struct sctp_ipv6addr_param *lookup;
2662163953Srrs			uint16_t p_size, addr_size;
2663163953Srrs
2664163953Srrs			lookup = (struct sctp_ipv6addr_param *)lookup_ptr;
2665163953Srrs			lookup->ph.param_type =
2666163953Srrs			    htons(aa->ap.addrp.ph.param_type);
2667163953Srrs			if (aa->ap.addrp.ph.param_type == SCTP_IPV6_ADDRESS) {
2668163953Srrs				/* copy IPv6 address */
2669163953Srrs				p_size = sizeof(struct sctp_ipv6addr_param);
2670163953Srrs				addr_size = sizeof(struct in6_addr);
2671163953Srrs			} else {
2672163953Srrs				/* copy IPv4 address */
2673163953Srrs				p_size = sizeof(struct sctp_ipv4addr_param);
2674163953Srrs				addr_size = sizeof(struct in_addr);
2675163953Srrs			}
2676163953Srrs			lookup->ph.param_length = htons(SCTP_SIZE32(p_size));
2677163953Srrs			memcpy(lookup->addr, &aa->ap.addrp.addr, addr_size);
2678165647Srrs			SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(p_size);
2679163953Srrs			lookup_used = 1;
2680163953Srrs		}
2681163953Srrs		/* copy into current space */
2682163953Srrs		memcpy(ptr, &aa->ap, p_length);
2683163953Srrs
2684163953Srrs		/* network elements and update lengths */
2685163953Srrs		aph = (struct sctp_asconf_paramhdr *)ptr;
2686163953Srrs		aap = (struct sctp_asconf_addr_param *)ptr;
2687163953Srrs		/* correlation_id is transparent to peer, no htonl needed */
2688163953Srrs		aph->ph.param_type = htons(aph->ph.param_type);
2689163953Srrs		aph->ph.param_length = htons(aph->ph.param_length);
2690163953Srrs		aap->addrp.ph.param_type = htons(aap->addrp.ph.param_type);
2691163953Srrs		aap->addrp.ph.param_length = htons(aap->addrp.ph.param_length);
2692163953Srrs
2693165647Srrs		SCTP_BUF_LEN(m_asconf) += SCTP_SIZE32(p_length);
2694163953Srrs		ptr += SCTP_SIZE32(p_length);
2695163953Srrs
2696163953Srrs		/*
2697163953Srrs		 * these params are removed off the pending list upon
2698163953Srrs		 * getting an ASCONF-ACK back from the peer, just set flag
2699163953Srrs		 */
2700163953Srrs		aa->sent = 1;
2701163953Srrs	}
2702163953Srrs	/* check to see if the lookup addr has been populated yet */
2703163953Srrs	if (lookup_used == 0) {
2704163953Srrs		/* NOTE: if the address param is optional, can skip this... */
2705163953Srrs		/* add any valid (existing) address... */
2706163953Srrs		struct sctp_ipv6addr_param *lookup;
2707163953Srrs		uint16_t p_size, addr_size;
2708163953Srrs		struct sockaddr *found_addr;
2709163953Srrs		caddr_t addr_ptr;
2710163953Srrs
2711163953Srrs		if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL)
2712172190Srrs			found_addr = sctp_find_valid_localaddr(stcb,
2713172190Srrs			    addr_locked);
2714163953Srrs		else
2715163953Srrs			found_addr = sctp_find_valid_localaddr_ep(stcb);
2716163953Srrs
2717163953Srrs		lookup = (struct sctp_ipv6addr_param *)lookup_ptr;
2718163953Srrs		if (found_addr != NULL) {
2719221249Stuexen			switch (found_addr->sa_family) {
2720221249Stuexen#ifdef INET6
2721221249Stuexen			case AF_INET6:
2722163953Srrs				/* copy IPv6 address */
2723163953Srrs				lookup->ph.param_type =
2724163953Srrs				    htons(SCTP_IPV6_ADDRESS);
2725163953Srrs				p_size = sizeof(struct sctp_ipv6addr_param);
2726163953Srrs				addr_size = sizeof(struct in6_addr);
2727163953Srrs				addr_ptr = (caddr_t)&((struct sockaddr_in6 *)
2728163953Srrs				    found_addr)->sin6_addr;
2729221249Stuexen				break;
2730221249Stuexen#endif
2731221249Stuexen#ifdef INET
2732221249Stuexen			case AF_INET:
2733163953Srrs				/* copy IPv4 address */
2734163953Srrs				lookup->ph.param_type =
2735163953Srrs				    htons(SCTP_IPV4_ADDRESS);
2736163953Srrs				p_size = sizeof(struct sctp_ipv4addr_param);
2737163953Srrs				addr_size = sizeof(struct in_addr);
2738163953Srrs				addr_ptr = (caddr_t)&((struct sockaddr_in *)
2739163953Srrs				    found_addr)->sin_addr;
2740221249Stuexen				break;
2741221249Stuexen#endif
2742221249Stuexen			default:
2743221249Stuexen				p_size = 0;
2744221249Stuexen				addr_size = 0;
2745221249Stuexen				addr_ptr = NULL;
2746221249Stuexen				break;
2747163953Srrs			}
2748163953Srrs			lookup->ph.param_length = htons(SCTP_SIZE32(p_size));
2749163953Srrs			memcpy(lookup->addr, addr_ptr, addr_size);
2750165647Srrs			SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(p_size);
2751163953Srrs		} else {
2752163953Srrs			/* uh oh... don't have any address?? */
2753169420Srrs			SCTPDBG(SCTP_DEBUG_ASCONF1,
2754169420Srrs			    "compose_asconf: no lookup addr!\n");
2755221249Stuexen			/* XXX for now, we send a IPv4 address of 0.0.0.0 */
2756163953Srrs			lookup->ph.param_type = htons(SCTP_IPV4_ADDRESS);
2757163953Srrs			lookup->ph.param_length = htons(SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param)));
2758332172Stuexen			memset(lookup->addr, 0, sizeof(struct in_addr));
2759165647Srrs			SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param));
2760163953Srrs		}
2761163953Srrs	}
2762163953Srrs	/* chain it all together */
2763165647Srrs	SCTP_BUF_NEXT(m_asconf_chk) = m_asconf;
2764169655Srrs	*retlen = SCTP_BUF_LEN(m_asconf_chk) + SCTP_BUF_LEN(m_asconf);
2765257800Stuexen	acp->ch.chunk_length = htons(*retlen);
2766163953Srrs
2767163953Srrs	return (m_asconf_chk);
2768163953Srrs}
2769163953Srrs
2770163953Srrs/*
2771163953Srrs * section to handle address changes before an association is up eg. changes
2772163953Srrs * during INIT/INIT-ACK/COOKIE-ECHO handshake
2773163953Srrs */
2774163953Srrs
2775163953Srrs/*
2776163953Srrs * processes the (local) addresses in the INIT-ACK chunk
2777163953Srrs */
2778163953Srrsstatic void
2779163953Srrssctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m,
2780163953Srrs    unsigned int offset, unsigned int length)
2781163953Srrs{
2782163953Srrs	struct sctp_paramhdr tmp_param, *ph;
2783163953Srrs	uint16_t plen, ptype;
2784167598Srrs	struct sctp_ifa *sctp_ifa;
2785271228Stuexen	union sctp_sockstore store;
2786221249Stuexen#ifdef INET6
2787238501Stuexen	struct sctp_ipv6addr_param addr6_store;
2788221249Stuexen#endif
2789221249Stuexen#ifdef INET
2790238501Stuexen	struct sctp_ipv4addr_param addr4_store;
2791221249Stuexen#endif
2792163953Srrs
2793169420Srrs	SCTPDBG(SCTP_DEBUG_ASCONF2, "processing init-ack addresses\n");
2794169420Srrs	if (stcb == NULL)	/* Un-needed check for SA */
2795169420Srrs		return;
2796163953Srrs
2797163953Srrs	/* convert to upper bound */
2798163953Srrs	length += offset;
2799163953Srrs
2800163953Srrs	if ((offset + sizeof(struct sctp_paramhdr)) > length) {
2801163953Srrs		return;
2802163953Srrs	}
2803163953Srrs	/* go through the addresses in the init-ack */
2804221249Stuexen	ph = (struct sctp_paramhdr *)
2805221249Stuexen	    sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr),
2806310773Stuexen	    (uint8_t *)&tmp_param);
2807163953Srrs	while (ph != NULL) {
2808163953Srrs		ptype = ntohs(ph->param_type);
2809163953Srrs		plen = ntohs(ph->param_length);
2810221249Stuexen		switch (ptype) {
2811221249Stuexen#ifdef INET6
2812221249Stuexen		case SCTP_IPV6_ADDRESS:
2813221249Stuexen			{
2814221249Stuexen				struct sctp_ipv6addr_param *a6p;
2815163953Srrs
2816221249Stuexen				/* get the entire IPv6 address param */
2817221249Stuexen				a6p = (struct sctp_ipv6addr_param *)
2818221249Stuexen				    sctp_m_getptr(m, offset,
2819221249Stuexen				    sizeof(struct sctp_ipv6addr_param),
2820310773Stuexen				    (uint8_t *)&addr6_store);
2821221249Stuexen				if (plen != sizeof(struct sctp_ipv6addr_param) ||
2822221249Stuexen				    a6p == NULL) {
2823221249Stuexen					return;
2824221249Stuexen				}
2825271228Stuexen				memset(&store, 0, sizeof(union sctp_sockstore));
2826271228Stuexen				store.sin6.sin6_family = AF_INET6;
2827271228Stuexen				store.sin6.sin6_len = sizeof(struct sockaddr_in6);
2828271228Stuexen				store.sin6.sin6_port = stcb->rport;
2829271228Stuexen				memcpy(&store.sin6.sin6_addr, a6p->addr, sizeof(struct in6_addr));
2830221249Stuexen				break;
2831163953Srrs			}
2832221249Stuexen#endif
2833221249Stuexen#ifdef INET
2834221249Stuexen		case SCTP_IPV4_ADDRESS:
2835221249Stuexen			{
2836221249Stuexen				struct sctp_ipv4addr_param *a4p;
2837163953Srrs
2838221249Stuexen				/* get the entire IPv4 address param */
2839221249Stuexen				a4p = (struct sctp_ipv4addr_param *)sctp_m_getptr(m, offset,
2840221249Stuexen				    sizeof(struct sctp_ipv4addr_param),
2841310773Stuexen				    (uint8_t *)&addr4_store);
2842221249Stuexen				if (plen != sizeof(struct sctp_ipv4addr_param) ||
2843221249Stuexen				    a4p == NULL) {
2844221249Stuexen					return;
2845221249Stuexen				}
2846271228Stuexen				memset(&store, 0, sizeof(union sctp_sockstore));
2847271228Stuexen				store.sin.sin_family = AF_INET;
2848271228Stuexen				store.sin.sin_len = sizeof(struct sockaddr_in);
2849271228Stuexen				store.sin.sin_port = stcb->rport;
2850271228Stuexen				store.sin.sin_addr.s_addr = a4p->addr;
2851221410Stuexen				break;
2852163953Srrs			}
2853221249Stuexen#endif
2854221249Stuexen		default:
2855163953Srrs			goto next_addr;
2856163953Srrs		}
2857163953Srrs
2858163953Srrs		/* see if this address really (still) exists */
2859277033Stuexen		sctp_ifa = sctp_find_ifa_by_addr(&store.sa, stcb->asoc.vrf_id,
2860172190Srrs		    SCTP_ADDR_NOT_LOCKED);
2861167598Srrs		if (sctp_ifa == NULL) {
2862163953Srrs			/* address doesn't exist anymore */
2863163953Srrs			int status;
2864163953Srrs
2865163953Srrs			/* are ASCONFs allowed ? */
2866163953Srrs			if ((sctp_is_feature_on(stcb->sctp_ep,
2867163953Srrs			    SCTP_PCB_FLAGS_DO_ASCONF)) &&
2868269858Stuexen			    stcb->asoc.asconf_supported) {
2869163953Srrs				/* queue an ASCONF DEL_IP_ADDRESS */
2870271228Stuexen				status = sctp_asconf_queue_sa_delete(stcb, &store.sa);
2871163953Srrs				/*
2872171572Srrs				 * if queued ok, and in correct state, send
2873171572Srrs				 * out the ASCONF.
2874163953Srrs				 */
2875163953Srrs				if (status == 0 &&
2876347165Stuexen				    SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) {
2877171572Srrs#ifdef SCTP_TIMER_BASED_ASCONF
2878163953Srrs					sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
2879163953Srrs					    stcb->sctp_ep, stcb,
2880163953Srrs					    stcb->asoc.primary_destination);
2881171572Srrs#else
2882224641Stuexen					sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
2883171572Srrs#endif
2884163953Srrs				}
2885163953Srrs			}
2886163953Srrs		}
2887347154Stuexen
2888163953Srrsnext_addr:
2889163953Srrs		/*
2890163953Srrs		 * Sanity check:  Make sure the length isn't 0, otherwise
2891163953Srrs		 * we'll be stuck in this loop for a long time...
2892163953Srrs		 */
2893163953Srrs		if (SCTP_SIZE32(plen) == 0) {
2894169420Srrs			SCTP_PRINTF("process_initack_addrs: bad len (%d) type=%xh\n",
2895163953Srrs			    plen, ptype);
2896163953Srrs			return;
2897163953Srrs		}
2898163953Srrs		/* get next parameter */
2899163953Srrs		offset += SCTP_SIZE32(plen);
2900163953Srrs		if ((offset + sizeof(struct sctp_paramhdr)) > length)
2901163953Srrs			return;
2902163953Srrs		ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset,
2903310773Stuexen		    sizeof(struct sctp_paramhdr), (uint8_t *)&tmp_param);
2904163953Srrs	}			/* while */
2905163953Srrs}
2906163953Srrs
2907163953Srrs/* FIX ME: need to verify return result for v6 address type if v6 disabled */
2908163953Srrs/*
2909163953Srrs * checks to see if a specific address is in the initack address list returns
2910163953Srrs * 1 if found, 0 if not
2911163953Srrs */
2912163953Srrsstatic uint32_t
2913228653Stuexensctp_addr_in_initack(struct mbuf *m, uint32_t offset, uint32_t length, struct sockaddr *sa)
2914163953Srrs{
2915163953Srrs	struct sctp_paramhdr tmp_param, *ph;
2916163953Srrs	uint16_t plen, ptype;
2917221249Stuexen#ifdef INET
2918163953Srrs	struct sockaddr_in *sin;
2919163953Srrs	struct sctp_ipv4addr_param *a4p;
2920238501Stuexen	struct sctp_ipv6addr_param addr4_store;
2921221249Stuexen#endif
2922163953Srrs#ifdef INET6
2923167598Srrs	struct sockaddr_in6 *sin6;
2924163953Srrs	struct sctp_ipv6addr_param *a6p;
2925238501Stuexen	struct sctp_ipv6addr_param addr6_store;
2926167598Srrs	struct sockaddr_in6 sin6_tmp;
2927221249Stuexen#endif
2928163953Srrs
2929221249Stuexen	switch (sa->sa_family) {
2930221249Stuexen#ifdef INET
2931221249Stuexen	case AF_INET:
2932221249Stuexen		break;
2933221249Stuexen#endif
2934163953Srrs#ifdef INET6
2935221249Stuexen	case AF_INET6:
2936221249Stuexen		break;
2937221249Stuexen#endif
2938221249Stuexen	default:
2939163953Srrs		return (0);
2940221249Stuexen	}
2941163953Srrs
2942169420Srrs	SCTPDBG(SCTP_DEBUG_ASCONF2, "find_initack_addr: starting search for ");
2943169420Srrs	SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, sa);
2944163953Srrs	/* convert to upper bound */
2945163953Srrs	length += offset;
2946163953Srrs
2947163953Srrs	if ((offset + sizeof(struct sctp_paramhdr)) > length) {
2948169420Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
2949169420Srrs		    "find_initack_addr: invalid offset?\n");
2950163953Srrs		return (0);
2951163953Srrs	}
2952163953Srrs	/* go through the addresses in the init-ack */
2953163953Srrs	ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset,
2954310773Stuexen	    sizeof(struct sctp_paramhdr), (uint8_t *)&tmp_param);
2955163953Srrs	while (ph != NULL) {
2956163953Srrs		ptype = ntohs(ph->param_type);
2957163953Srrs		plen = ntohs(ph->param_length);
2958221249Stuexen		switch (ptype) {
2959163953Srrs#ifdef INET6
2960221249Stuexen		case SCTP_IPV6_ADDRESS:
2961221249Stuexen			if (sa->sa_family == AF_INET6) {
2962221249Stuexen				/* get the entire IPv6 address param */
2963221249Stuexen				if (plen != sizeof(struct sctp_ipv6addr_param)) {
2964221249Stuexen					break;
2965221249Stuexen				}
2966221249Stuexen				/* get the entire IPv6 address param */
2967221249Stuexen				a6p = (struct sctp_ipv6addr_param *)
2968221249Stuexen				    sctp_m_getptr(m, offset,
2969221249Stuexen				    sizeof(struct sctp_ipv6addr_param),
2970310773Stuexen				    (uint8_t *)&addr6_store);
2971221249Stuexen				if (a6p == NULL) {
2972221249Stuexen					return (0);
2973221249Stuexen				}
2974221249Stuexen				sin6 = (struct sockaddr_in6 *)sa;
2975221249Stuexen				if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) {
2976221249Stuexen					/* create a copy and clear scope */
2977221249Stuexen					memcpy(&sin6_tmp, sin6,
2978221249Stuexen					    sizeof(struct sockaddr_in6));
2979221249Stuexen					sin6 = &sin6_tmp;
2980221249Stuexen					in6_clearscope(&sin6->sin6_addr);
2981221249Stuexen				}
2982221249Stuexen				if (memcmp(&sin6->sin6_addr, a6p->addr,
2983221249Stuexen				    sizeof(struct in6_addr)) == 0) {
2984221249Stuexen					/* found it */
2985221249Stuexen					return (1);
2986221249Stuexen				}
2987163953Srrs			}
2988221249Stuexen			break;
2989163953Srrs#endif				/* INET6 */
2990221249Stuexen#ifdef INET
2991221249Stuexen		case SCTP_IPV4_ADDRESS:
2992221249Stuexen			if (sa->sa_family == AF_INET) {
2993221249Stuexen				if (plen != sizeof(struct sctp_ipv4addr_param)) {
2994221249Stuexen					break;
2995221249Stuexen				}
2996221249Stuexen				/* get the entire IPv4 address param */
2997221249Stuexen				a4p = (struct sctp_ipv4addr_param *)
2998221249Stuexen				    sctp_m_getptr(m, offset,
2999221249Stuexen				    sizeof(struct sctp_ipv4addr_param),
3000310773Stuexen				    (uint8_t *)&addr4_store);
3001221249Stuexen				if (a4p == NULL) {
3002221249Stuexen					return (0);
3003221249Stuexen				}
3004221249Stuexen				sin = (struct sockaddr_in *)sa;
3005221249Stuexen				if (sin->sin_addr.s_addr == a4p->addr) {
3006221249Stuexen					/* found it */
3007221249Stuexen					return (1);
3008221249Stuexen				}
3009163953Srrs			}
3010221249Stuexen			break;
3011221249Stuexen#endif
3012221249Stuexen		default:
3013221249Stuexen			break;
3014163953Srrs		}
3015163953Srrs		/* get next parameter */
3016163953Srrs		offset += SCTP_SIZE32(plen);
3017221249Stuexen		if (offset + sizeof(struct sctp_paramhdr) > length) {
3018163953Srrs			return (0);
3019221249Stuexen		}
3020163953Srrs		ph = (struct sctp_paramhdr *)
3021163953Srrs		    sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr),
3022310773Stuexen		    (uint8_t *)&tmp_param);
3023163953Srrs	}			/* while */
3024163953Srrs	/* not found! */
3025163953Srrs	return (0);
3026163953Srrs}
3027163953Srrs
3028163953Srrs/*
3029163953Srrs * makes sure that the current endpoint local addr list is consistent with
3030163953Srrs * the new association (eg. subset bound, asconf allowed) adds addresses as
3031163953Srrs * necessary
3032163953Srrs */
3033163953Srrsstatic void
3034163953Srrssctp_check_address_list_ep(struct sctp_tcb *stcb, struct mbuf *m, int offset,
3035163953Srrs    int length, struct sockaddr *init_addr)
3036163953Srrs{
3037163953Srrs	struct sctp_laddr *laddr;
3038163953Srrs
3039163953Srrs	/* go through the endpoint list */
3040163953Srrs	LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) {
3041163953Srrs		/* be paranoid and validate the laddr */
3042163953Srrs		if (laddr->ifa == NULL) {
3043169420Srrs			SCTPDBG(SCTP_DEBUG_ASCONF1,
3044169420Srrs			    "check_addr_list_ep: laddr->ifa is NULL");
3045163953Srrs			continue;
3046163953Srrs		}
3047163953Srrs		/* do i have it implicitly? */
3048167598Srrs		if (sctp_cmpaddr(&laddr->ifa->address.sa, init_addr)) {
3049163953Srrs			continue;
3050163953Srrs		}
3051163953Srrs		/* check to see if in the init-ack */
3052228653Stuexen		if (!sctp_addr_in_initack(m, offset, length, &laddr->ifa->address.sa)) {
3053163953Srrs			/* try to add it */
3054163953Srrs			sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb, laddr->ifa,
3055172190Srrs			    SCTP_ADD_IP_ADDRESS, SCTP_ADDR_NOT_LOCKED);
3056163953Srrs		}
3057163953Srrs	}
3058163953Srrs}
3059163953Srrs
3060163953Srrs/*
3061163953Srrs * makes sure that the current kernel address list is consistent with the new
3062163953Srrs * association (with all addrs bound) adds addresses as necessary
3063163953Srrs */
3064163953Srrsstatic void
3065163953Srrssctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset,
3066163953Srrs    int length, struct sockaddr *init_addr,
3067163953Srrs    uint16_t local_scope, uint16_t site_scope,
3068163953Srrs    uint16_t ipv4_scope, uint16_t loopback_scope)
3069163953Srrs{
3070167598Srrs	struct sctp_vrf *vrf = NULL;
3071167598Srrs	struct sctp_ifn *sctp_ifn;
3072167598Srrs	struct sctp_ifa *sctp_ifa;
3073167598Srrs	uint32_t vrf_id;
3074228653Stuexen#ifdef INET
3075228653Stuexen	struct sockaddr_in *sin;
3076228653Stuexen#endif
3077228653Stuexen#ifdef INET6
3078228653Stuexen	struct sockaddr_in6 *sin6;
3079228653Stuexen#endif
3080228653Stuexen
3081168299Srrs	if (stcb) {
3082168299Srrs		vrf_id = stcb->asoc.vrf_id;
3083168299Srrs	} else {
3084169420Srrs		return;
3085168299Srrs	}
3086172218Srrs	SCTP_IPI_ADDR_RLOCK();
3087167598Srrs	vrf = sctp_find_vrf(vrf_id);
3088167598Srrs	if (vrf == NULL) {
3089172218Srrs		SCTP_IPI_ADDR_RUNLOCK();
3090167598Srrs		return;
3091167598Srrs	}
3092163953Srrs	/* go through all our known interfaces */
3093167598Srrs	LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
3094167598Srrs		if (loopback_scope == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
3095163953Srrs			/* skip loopback interface */
3096163953Srrs			continue;
3097163953Srrs		}
3098163953Srrs		/* go through each interface address */
3099167598Srrs		LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
3100163953Srrs			/* do i have it implicitly? */
3101167598Srrs			if (sctp_cmpaddr(&sctp_ifa->address.sa, init_addr)) {
3102163953Srrs				continue;
3103163953Srrs			}
3104228653Stuexen			switch (sctp_ifa->address.sa.sa_family) {
3105228653Stuexen#ifdef INET
3106228653Stuexen			case AF_INET:
3107271221Stuexen				sin = &sctp_ifa->address.sin;
3108267674Stuexen				if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred,
3109267674Stuexen				    &sin->sin_addr) != 0) {
3110267674Stuexen					continue;
3111267674Stuexen				}
3112228653Stuexen				if ((ipv4_scope == 0) &&
3113228653Stuexen				    (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
3114228653Stuexen					/* private address not in scope */
3115228653Stuexen					continue;
3116228653Stuexen				}
3117228653Stuexen				break;
3118228653Stuexen#endif
3119228653Stuexen#ifdef INET6
3120228653Stuexen			case AF_INET6:
3121271221Stuexen				sin6 = &sctp_ifa->address.sin6;
3122267674Stuexen				if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred,
3123267674Stuexen				    &sin6->sin6_addr) != 0) {
3124267674Stuexen					continue;
3125267674Stuexen				}
3126228653Stuexen				if ((local_scope == 0) &&
3127228653Stuexen				    (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) {
3128228653Stuexen					continue;
3129228653Stuexen				}
3130228653Stuexen				if ((site_scope == 0) &&
3131228653Stuexen				    (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
3132228653Stuexen					continue;
3133228653Stuexen				}
3134228653Stuexen				break;
3135228653Stuexen#endif
3136228653Stuexen			default:
3137228653Stuexen				break;
3138228653Stuexen			}
3139163953Srrs			/* check to see if in the init-ack */
3140228653Stuexen			if (!sctp_addr_in_initack(m, offset, length, &sctp_ifa->address.sa)) {
3141163953Srrs				/* try to add it */
3142163953Srrs				sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb,
3143172190Srrs				    sctp_ifa, SCTP_ADD_IP_ADDRESS,
3144172190Srrs				    SCTP_ADDR_LOCKED);
3145163953Srrs			}
3146163953Srrs		}		/* end foreach ifa */
3147163953Srrs	}			/* end foreach ifn */
3148172218Srrs	SCTP_IPI_ADDR_RUNLOCK();
3149163953Srrs}
3150163953Srrs
3151163953Srrs/*
3152163953Srrs * validates an init-ack chunk (from a cookie-echo) with current addresses
3153163953Srrs * adds addresses from the init-ack into our local address list, if needed
3154163953Srrs * queues asconf adds/deletes addresses as needed and makes appropriate list
3155163953Srrs * changes for source address selection m, offset: points to the start of the
3156163953Srrs * address list in an init-ack chunk length: total length of the address
3157163953Srrs * params only init_addr: address where my INIT-ACK was sent from
3158163953Srrs */
3159163953Srrsvoid
3160163953Srrssctp_check_address_list(struct sctp_tcb *stcb, struct mbuf *m, int offset,
3161163953Srrs    int length, struct sockaddr *init_addr,
3162163953Srrs    uint16_t local_scope, uint16_t site_scope,
3163163953Srrs    uint16_t ipv4_scope, uint16_t loopback_scope)
3164163953Srrs{
3165163953Srrs	/* process the local addresses in the initack */
3166163953Srrs	sctp_process_initack_addresses(stcb, m, offset, length);
3167163953Srrs
3168163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
3169163953Srrs		/* bound all case */
3170163953Srrs		sctp_check_address_list_all(stcb, m, offset, length, init_addr,
3171163953Srrs		    local_scope, site_scope, ipv4_scope, loopback_scope);
3172163953Srrs	} else {
3173163953Srrs		/* subset bound case */
3174163953Srrs		if (sctp_is_feature_on(stcb->sctp_ep,
3175163953Srrs		    SCTP_PCB_FLAGS_DO_ASCONF)) {
3176163953Srrs			/* asconf's allowed */
3177163953Srrs			sctp_check_address_list_ep(stcb, m, offset, length,
3178163953Srrs			    init_addr);
3179163953Srrs		}
3180163953Srrs		/* else, no asconfs allowed, so what we sent is what we get */
3181163953Srrs	}
3182163953Srrs}
3183163953Srrs
3184163953Srrs/*
3185163953Srrs * sctp_bindx() support
3186163953Srrs */
3187163953Srrsuint32_t
3188169655Srrssctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
3189170744Srrs    uint32_t type, uint32_t vrf_id, struct sctp_ifa *sctp_ifap)
3190163953Srrs{
3191167598Srrs	struct sctp_ifa *ifa;
3192218521Stuexen	struct sctp_laddr *laddr, *nladdr;
3193163953Srrs
3194167598Srrs	if (sa->sa_len == 0) {
3195171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EINVAL);
3196163953Srrs		return (EINVAL);
3197167598Srrs	}
3198170744Srrs	if (sctp_ifap) {
3199170744Srrs		ifa = sctp_ifap;
3200170744Srrs	} else if (type == SCTP_ADD_IP_ADDRESS) {
3201167598Srrs		/* For an add the address MUST be on the system */
3202172091Srrs		ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED);
3203167598Srrs	} else if (type == SCTP_DEL_IP_ADDRESS) {
3204167598Srrs		/* For a delete we need to find it in the inp */
3205172091Srrs		ifa = sctp_find_ifa_in_ep(inp, sa, SCTP_ADDR_NOT_LOCKED);
3206167598Srrs	} else {
3207167598Srrs		ifa = NULL;
3208167598Srrs	}
3209163953Srrs	if (ifa != NULL) {
3210167598Srrs		if (type == SCTP_ADD_IP_ADDRESS) {
3211167598Srrs			sctp_add_local_addr_ep(inp, ifa, type);
3212167598Srrs		} else if (type == SCTP_DEL_IP_ADDRESS) {
3213169655Srrs			if (inp->laddr_count < 2) {
3214169655Srrs				/* can't delete the last local address */
3215171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EINVAL);
3216169655Srrs				return (EINVAL);
3217169655Srrs			}
3218169655Srrs			LIST_FOREACH(laddr, &inp->sctp_addr_list,
3219169655Srrs			    sctp_nxt_addr) {
3220167598Srrs				if (ifa == laddr->ifa) {
3221167598Srrs					/* Mark in the delete */
3222167598Srrs					laddr->action = type;
3223167598Srrs				}
3224163953Srrs			}
3225163953Srrs		}
3226218521Stuexen		if (LIST_EMPTY(&inp->sctp_asoc_list)) {
3227199372Stuexen			/*
3228199372Stuexen			 * There is no need to start the iterator if the inp
3229199372Stuexen			 * has no associations.
3230199372Stuexen			 */
3231218521Stuexen			if (type == SCTP_DEL_IP_ADDRESS) {
3232218521Stuexen				LIST_FOREACH_SAFE(laddr, &inp->sctp_addr_list, sctp_nxt_addr, nladdr) {
3233218521Stuexen					if (laddr->ifa == ifa) {
3234218521Stuexen						sctp_del_local_addr_ep(inp, ifa);
3235218521Stuexen					}
3236218521Stuexen				}
3237218521Stuexen			}
3238218521Stuexen		} else {
3239199372Stuexen			struct sctp_asconf_iterator *asc;
3240199372Stuexen			struct sctp_laddr *wi;
3241295668Stuexen			int ret;
3242199372Stuexen
3243199372Stuexen			SCTP_MALLOC(asc, struct sctp_asconf_iterator *,
3244199372Stuexen			    sizeof(struct sctp_asconf_iterator),
3245199372Stuexen			    SCTP_M_ASC_IT);
3246199372Stuexen			if (asc == NULL) {
3247199372Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, ENOMEM);
3248199372Stuexen				return (ENOMEM);
3249199372Stuexen			}
3250199372Stuexen			wi = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr);
3251199372Stuexen			if (wi == NULL) {
3252199372Stuexen				SCTP_FREE(asc, SCTP_M_ASC_IT);
3253199372Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, ENOMEM);
3254199372Stuexen				return (ENOMEM);
3255199372Stuexen			}
3256199372Stuexen			LIST_INIT(&asc->list_of_work);
3257199372Stuexen			asc->cnt = 1;
3258199372Stuexen			SCTP_INCR_LADDR_COUNT();
3259199372Stuexen			wi->ifa = ifa;
3260199372Stuexen			wi->action = type;
3261199372Stuexen			atomic_add_int(&ifa->refcount, 1);
3262199372Stuexen			LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr);
3263295668Stuexen			ret = sctp_initiate_iterator(sctp_asconf_iterator_ep,
3264199372Stuexen			    sctp_asconf_iterator_stcb,
3265199372Stuexen			    sctp_asconf_iterator_ep_end,
3266199372Stuexen			    SCTP_PCB_ANY_FLAGS,
3267199372Stuexen			    SCTP_PCB_ANY_FEATURES,
3268199372Stuexen			    SCTP_ASOC_ANY_STATE,
3269199372Stuexen			    (void *)asc, 0,
3270199372Stuexen			    sctp_asconf_iterator_end, inp, 0);
3271295670Stuexen			if (ret) {
3272295668Stuexen				SCTP_PRINTF("Failed to initiate iterator for addr_mgmt_ep_sa\n");
3273295668Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EFAULT);
3274295668Stuexen				sctp_asconf_iterator_end(asc, 0);
3275295668Stuexen				return (EFAULT);
3276295668Stuexen			}
3277199372Stuexen		}
3278199372Stuexen		return (0);
3279163953Srrs	} else {
3280163953Srrs		/* invalid address! */
3281171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EADDRNOTAVAIL);
3282163953Srrs		return (EADDRNOTAVAIL);
3283163953Srrs	}
3284163953Srrs}
3285185694Srrs
3286185694Srrsvoid
3287185694Srrssctp_asconf_send_nat_state_update(struct sctp_tcb *stcb,
3288185694Srrs    struct sctp_nets *net)
3289185694Srrs{
3290185694Srrs	struct sctp_asconf_addr *aa;
3291185694Srrs	struct sctp_ifa *sctp_ifap;
3292185694Srrs	struct sctp_asconf_tag_param *vtag;
3293221249Stuexen#ifdef INET
3294185694Srrs	struct sockaddr_in *to;
3295221249Stuexen#endif
3296185694Srrs#ifdef INET6
3297185694Srrs	struct sockaddr_in6 *to6;
3298185694Srrs#endif
3299185694Srrs	if (net == NULL) {
3300185694Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: Missing net\n");
3301185694Srrs		return;
3302185694Srrs	}
3303185694Srrs	if (stcb == NULL) {
3304185694Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: Missing stcb\n");
3305185694Srrs		return;
3306185694Srrs	}
3307185694Srrs	/*
3308185694Srrs	 * Need to have in the asconf: - vtagparam(my_vtag/peer_vtag) -
3309185694Srrs	 * add(0.0.0.0) - del(0.0.0.0) - Any global addresses add(addr)
3310185694Srrs	 */
3311185694Srrs	SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
3312185694Srrs	    SCTP_M_ASC_ADDR);
3313185694Srrs	if (aa == NULL) {
3314185694Srrs		/* didn't get memory */
3315185694Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
3316185694Srrs		    "sctp_asconf_send_nat_state_update: failed to get memory!\n");
3317185694Srrs		return;
3318185694Srrs	}
3319185694Srrs	aa->special_del = 0;
3320185694Srrs	/* fill in asconf address parameter fields */
3321185694Srrs	/* top level elements are "networked" during send */
3322185694Srrs	aa->ifa = NULL;
3323185694Srrs	aa->sent = 0;		/* clear sent flag */
3324185694Srrs	vtag = (struct sctp_asconf_tag_param *)&aa->ap.aph;
3325185694Srrs	vtag->aph.ph.param_type = SCTP_NAT_VTAGS;
3326185694Srrs	vtag->aph.ph.param_length = sizeof(struct sctp_asconf_tag_param);
3327185694Srrs	vtag->local_vtag = htonl(stcb->asoc.my_vtag);
3328185694Srrs	vtag->remote_vtag = htonl(stcb->asoc.peer_vtag);
3329185694Srrs	TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
3330185694Srrs
3331185694Srrs	SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
3332185694Srrs	    SCTP_M_ASC_ADDR);
3333185694Srrs	if (aa == NULL) {
3334185694Srrs		/* didn't get memory */
3335185694Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
3336185694Srrs		    "sctp_asconf_send_nat_state_update: failed to get memory!\n");
3337185694Srrs		return;
3338185694Srrs	}
3339185694Srrs	memset(aa, 0, sizeof(struct sctp_asconf_addr));
3340185694Srrs	/* fill in asconf address parameter fields */
3341185694Srrs	/* ADD(0.0.0.0) */
3342221249Stuexen	switch (net->ro._l_addr.sa.sa_family) {
3343221249Stuexen#ifdef INET
3344221249Stuexen	case AF_INET:
3345185694Srrs		aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
3346185694Srrs		aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param);
3347185694Srrs		aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
3348185694Srrs		aa->ap.addrp.ph.param_length = sizeof(struct sctp_ipv4addr_param);
3349185694Srrs		/* No need to add an address, we are using 0.0.0.0 */
3350185694Srrs		TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
3351221249Stuexen		break;
3352221249Stuexen#endif
3353185694Srrs#ifdef INET6
3354221249Stuexen	case AF_INET6:
3355185694Srrs		aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
3356185694Srrs		aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param);
3357185694Srrs		aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
3358185694Srrs		aa->ap.addrp.ph.param_length = sizeof(struct sctp_ipv6addr_param);
3359185694Srrs		/* No need to add an address, we are using 0.0.0.0 */
3360185694Srrs		TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
3361221249Stuexen		break;
3362221249Stuexen#endif
3363277347Stuexen	default:
3364277347Stuexen		SCTPDBG(SCTP_DEBUG_ASCONF1,
3365277347Stuexen		    "sctp_asconf_send_nat_state_update: unknown address family\n");
3366277347Stuexen		SCTP_FREE(aa, SCTP_M_ASC_ADDR);
3367277347Stuexen		return;
3368185694Srrs	}
3369185694Srrs	SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
3370185694Srrs	    SCTP_M_ASC_ADDR);
3371185694Srrs	if (aa == NULL) {
3372185694Srrs		/* didn't get memory */
3373185694Srrs		SCTPDBG(SCTP_DEBUG_ASCONF1,
3374185694Srrs		    "sctp_asconf_send_nat_state_update: failed to get memory!\n");
3375185694Srrs		return;
3376185694Srrs	}
3377185694Srrs	memset(aa, 0, sizeof(struct sctp_asconf_addr));
3378185694Srrs	/* fill in asconf address parameter fields */
3379185694Srrs	/* ADD(0.0.0.0) */
3380221249Stuexen	switch (net->ro._l_addr.sa.sa_family) {
3381221249Stuexen#ifdef INET
3382221249Stuexen	case AF_INET:
3383185694Srrs		aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
3384185694Srrs		aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param);
3385185694Srrs		aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
3386185694Srrs		aa->ap.addrp.ph.param_length = sizeof(struct sctp_ipv4addr_param);
3387185694Srrs		/* No need to add an address, we are using 0.0.0.0 */
3388185694Srrs		TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
3389221249Stuexen		break;
3390221249Stuexen#endif
3391185694Srrs#ifdef INET6
3392221249Stuexen	case AF_INET6:
3393185694Srrs		aa->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS;
3394185694Srrs		aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param);
3395185694Srrs		aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
3396185694Srrs		aa->ap.addrp.ph.param_length = sizeof(struct sctp_ipv6addr_param);
3397185694Srrs		/* No need to add an address, we are using 0.0.0.0 */
3398185694Srrs		TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
3399221249Stuexen		break;
3400221249Stuexen#endif
3401277347Stuexen	default:
3402277347Stuexen		SCTPDBG(SCTP_DEBUG_ASCONF1,
3403277347Stuexen		    "sctp_asconf_send_nat_state_update: unknown address family\n");
3404277347Stuexen		SCTP_FREE(aa, SCTP_M_ASC_ADDR);
3405277347Stuexen		return;
3406185694Srrs	}
3407185694Srrs	/* Now we must hunt the addresses and add all global addresses */
3408185694Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
3409185694Srrs		struct sctp_vrf *vrf = NULL;
3410185694Srrs		struct sctp_ifn *sctp_ifnp;
3411185694Srrs		uint32_t vrf_id;
3412185694Srrs
3413185694Srrs		vrf_id = stcb->sctp_ep->def_vrf_id;
3414185694Srrs		vrf = sctp_find_vrf(vrf_id);
3415185694Srrs		if (vrf == NULL) {
3416185694Srrs			goto skip_rest;
3417185694Srrs		}
3418347154Stuexen
3419185694Srrs		SCTP_IPI_ADDR_RLOCK();
3420185694Srrs		LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) {
3421185694Srrs			LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) {
3422221249Stuexen				switch (sctp_ifap->address.sa.sa_family) {
3423221249Stuexen#ifdef INET
3424221249Stuexen				case AF_INET:
3425185694Srrs					to = &sctp_ifap->address.sin;
3426267674Stuexen					if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred,
3427267674Stuexen					    &to->sin_addr) != 0) {
3428267674Stuexen						continue;
3429267674Stuexen					}
3430185694Srrs					if (IN4_ISPRIVATE_ADDRESS(&to->sin_addr)) {
3431185694Srrs						continue;
3432185694Srrs					}
3433185694Srrs					if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) {
3434185694Srrs						continue;
3435185694Srrs					}
3436221249Stuexen					break;
3437221249Stuexen#endif
3438185694Srrs#ifdef INET6
3439221249Stuexen				case AF_INET6:
3440185694Srrs					to6 = &sctp_ifap->address.sin6;
3441267674Stuexen					if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred,
3442267674Stuexen					    &to6->sin6_addr) != 0) {
3443267674Stuexen						continue;
3444267674Stuexen					}
3445185694Srrs					if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) {
3446185694Srrs						continue;
3447185694Srrs					}
3448185694Srrs					if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) {
3449185694Srrs						continue;
3450185694Srrs					}
3451221249Stuexen					break;
3452221249Stuexen#endif
3453221249Stuexen				default:
3454221249Stuexen					continue;
3455185694Srrs				}
3456185694Srrs				sctp_asconf_queue_mgmt(stcb, sctp_ifap, SCTP_ADD_IP_ADDRESS);
3457185694Srrs			}
3458185694Srrs		}
3459185694Srrs		SCTP_IPI_ADDR_RUNLOCK();
3460185694Srrs	} else {
3461185694Srrs		struct sctp_laddr *laddr;
3462185694Srrs
3463185694Srrs		LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) {
3464185694Srrs			if (laddr->ifa == NULL) {
3465185694Srrs				continue;
3466185694Srrs			}
3467185694Srrs			if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED)
3468185694Srrs				/*
3469185694Srrs				 * Address being deleted by the system, dont
3470185694Srrs				 * list.
3471185694Srrs				 */
3472185694Srrs				continue;
3473185694Srrs			if (laddr->action == SCTP_DEL_IP_ADDRESS) {
3474185694Srrs				/*
3475185694Srrs				 * Address being deleted on this ep don't
3476185694Srrs				 * list.
3477185694Srrs				 */
3478185694Srrs				continue;
3479185694Srrs			}
3480185694Srrs			sctp_ifap = laddr->ifa;
3481221249Stuexen			switch (sctp_ifap->address.sa.sa_family) {
3482221249Stuexen#ifdef INET
3483221249Stuexen			case AF_INET:
3484185694Srrs				to = &sctp_ifap->address.sin;
3485185694Srrs				if (IN4_ISPRIVATE_ADDRESS(&to->sin_addr)) {
3486185694Srrs					continue;
3487185694Srrs				}
3488185694Srrs				if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) {
3489185694Srrs					continue;
3490185694Srrs				}
3491221249Stuexen				break;
3492221249Stuexen#endif
3493185694Srrs#ifdef INET6
3494221249Stuexen			case AF_INET6:
3495185694Srrs				to6 = &sctp_ifap->address.sin6;
3496185694Srrs				if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) {
3497185694Srrs					continue;
3498185694Srrs				}
3499185694Srrs				if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) {
3500185694Srrs					continue;
3501185694Srrs				}
3502221249Stuexen				break;
3503221249Stuexen#endif
3504221249Stuexen			default:
3505221249Stuexen				continue;
3506185694Srrs			}
3507185694Srrs			sctp_asconf_queue_mgmt(stcb, sctp_ifap, SCTP_ADD_IP_ADDRESS);
3508185694Srrs		}
3509185694Srrs	}
3510185694Srrsskip_rest:
3511185694Srrs	/* Now we must send the asconf into the queue */
3512224641Stuexen	sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED);
3513185694Srrs}
3514