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