netwerk/sctp/src/netinet/sctp_asconf.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/netwerk/sctp/src/netinet/sctp_asconf.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3493 @@
     1.4 +/*-
     1.5 + * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
     1.6 + * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
     1.7 + * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
     1.8 + *
     1.9 + * Redistribution and use in source and binary forms, with or without
    1.10 + * modification, are permitted provided that the following conditions are met:
    1.11 + *
    1.12 + * a) Redistributions of source code must retain the above copyright notice,
    1.13 + *    this list of conditions and the following disclaimer.
    1.14 + *
    1.15 + * b) Redistributions in binary form must reproduce the above copyright
    1.16 + *    notice, this list of conditions and the following disclaimer in
    1.17 + *    the documentation and/or other materials provided with the distribution.
    1.18 + *
    1.19 + * c) Neither the name of Cisco Systems, Inc. nor the names of its
    1.20 + *    contributors may be used to endorse or promote products derived
    1.21 + *    from this software without specific prior written permission.
    1.22 + *
    1.23 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    1.24 + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    1.25 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    1.26 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
    1.27 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    1.28 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    1.29 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    1.30 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    1.31 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    1.32 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
    1.33 + * THE POSSIBILITY OF SUCH DAMAGE.
    1.34 + */
    1.35 +
    1.36 +#ifdef __FreeBSD__
    1.37 +#include <sys/cdefs.h>
    1.38 +__FBSDID("$FreeBSD: head/sys/netinet/sctp_asconf.c 257803 2013-11-07 17:08:09Z tuexen $");
    1.39 +#endif
    1.40 +
    1.41 +#include <netinet/sctp_os.h>
    1.42 +#include <netinet/sctp_var.h>
    1.43 +#include <netinet/sctp_sysctl.h>
    1.44 +#include <netinet/sctp_pcb.h>
    1.45 +#include <netinet/sctp_header.h>
    1.46 +#include <netinet/sctputil.h>
    1.47 +#include <netinet/sctp_output.h>
    1.48 +#include <netinet/sctp_asconf.h>
    1.49 +#include <netinet/sctp_timer.h>
    1.50 +
    1.51 +/*
    1.52 + * debug flags:
    1.53 + * SCTP_DEBUG_ASCONF1: protocol info, general info and errors
    1.54 + * SCTP_DEBUG_ASCONF2: detailed info
    1.55 + */
    1.56 +
    1.57 +#if defined(__APPLE__)
    1.58 +#define APPLE_FILE_NO 1
    1.59 +#endif
    1.60 +
    1.61 +/*
    1.62 + * RFC 5061
    1.63 + *
    1.64 + * An ASCONF parameter queue exists per asoc which holds the pending address
    1.65 + * operations.  Lists are updated upon receipt of ASCONF-ACK.
    1.66 + *
    1.67 + * A restricted_addrs list exists per assoc to hold local addresses that are
    1.68 + * not (yet) usable by the assoc as a source address.  These addresses are
    1.69 + * either pending an ASCONF operation (and exist on the ASCONF parameter
    1.70 + * queue), or they are permanently restricted (the peer has returned an
    1.71 + * ERROR indication to an ASCONF(ADD), or the peer does not support ASCONF).
    1.72 + *
    1.73 + * Deleted addresses are always immediately removed from the lists as they will
    1.74 + * (shortly) no longer exist in the kernel.  We send ASCONFs as a courtesy,
    1.75 + * only if allowed.
    1.76 + */
    1.77 +
    1.78 +/*
    1.79 + * ASCONF parameter processing.
    1.80 + * response_required: set if a reply is required (eg. SUCCESS_REPORT).
    1.81 + * returns a mbuf to an "error" response parameter or NULL/"success" if ok.
    1.82 + * FIX: allocating this many mbufs on the fly is pretty inefficient...
    1.83 + */
    1.84 +static struct mbuf *
    1.85 +sctp_asconf_success_response(uint32_t id)
    1.86 +{
    1.87 +	struct mbuf *m_reply = NULL;
    1.88 +	struct sctp_asconf_paramhdr *aph;
    1.89 +
    1.90 +	m_reply = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_paramhdr),
    1.91 +					0, M_NOWAIT, 1, MT_DATA);
    1.92 +	if (m_reply == NULL) {
    1.93 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
    1.94 +			"asconf_success_response: couldn't get mbuf!\n");
    1.95 +		return (NULL);
    1.96 +	}
    1.97 +	aph = mtod(m_reply, struct sctp_asconf_paramhdr *);
    1.98 +	aph->correlation_id = id;
    1.99 +	aph->ph.param_type = htons(SCTP_SUCCESS_REPORT);
   1.100 +	aph->ph.param_length = sizeof(struct sctp_asconf_paramhdr);
   1.101 +	SCTP_BUF_LEN(m_reply) = aph->ph.param_length;
   1.102 +	aph->ph.param_length = htons(aph->ph.param_length);
   1.103 +
   1.104 +	return (m_reply);
   1.105 +}
   1.106 +
   1.107 +static struct mbuf *
   1.108 +sctp_asconf_error_response(uint32_t id, uint16_t cause, uint8_t *error_tlv,
   1.109 +			   uint16_t tlv_length)
   1.110 +{
   1.111 +	struct mbuf *m_reply = NULL;
   1.112 +	struct sctp_asconf_paramhdr *aph;
   1.113 +	struct sctp_error_cause *error;
   1.114 +	uint8_t *tlv;
   1.115 +
   1.116 +	m_reply = sctp_get_mbuf_for_msg((sizeof(struct sctp_asconf_paramhdr) +
   1.117 +					 tlv_length +
   1.118 +					 sizeof(struct sctp_error_cause)),
   1.119 +					0, M_NOWAIT, 1, MT_DATA);
   1.120 +	if (m_reply == NULL) {
   1.121 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
   1.122 +			"asconf_error_response: couldn't get mbuf!\n");
   1.123 +		return (NULL);
   1.124 +	}
   1.125 +	aph = mtod(m_reply, struct sctp_asconf_paramhdr *);
   1.126 +	error = (struct sctp_error_cause *)(aph + 1);
   1.127 +
   1.128 +	aph->correlation_id = id;
   1.129 +	aph->ph.param_type = htons(SCTP_ERROR_CAUSE_IND);
   1.130 +	error->code = htons(cause);
   1.131 +	error->length = tlv_length + sizeof(struct sctp_error_cause);
   1.132 +	aph->ph.param_length = error->length +
   1.133 +	    sizeof(struct sctp_asconf_paramhdr);
   1.134 +
   1.135 +	if (aph->ph.param_length > MLEN) {
   1.136 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
   1.137 +			"asconf_error_response: tlv_length (%xh) too big\n",
   1.138 +			tlv_length);
   1.139 +		sctp_m_freem(m_reply);	/* discard */
   1.140 +		return (NULL);
   1.141 +	}
   1.142 +	if (error_tlv != NULL) {
   1.143 +		tlv = (uint8_t *) (error + 1);
   1.144 +		memcpy(tlv, error_tlv, tlv_length);
   1.145 +	}
   1.146 +	SCTP_BUF_LEN(m_reply) = aph->ph.param_length;
   1.147 +	error->length = htons(error->length);
   1.148 +	aph->ph.param_length = htons(aph->ph.param_length);
   1.149 +
   1.150 +	return (m_reply);
   1.151 +}
   1.152 +
   1.153 +static struct mbuf *
   1.154 +sctp_process_asconf_add_ip(struct sockaddr *src, struct sctp_asconf_paramhdr *aph,
   1.155 +                           struct sctp_tcb *stcb, int send_hb, int response_required)
   1.156 +{
   1.157 +	struct sctp_nets *net;
   1.158 +	struct mbuf *m_reply = NULL;
   1.159 +	struct sockaddr_storage sa_store;
   1.160 +	struct sctp_paramhdr *ph;
   1.161 +	uint16_t param_type, aparam_length;
   1.162 +#if defined(INET) || defined(INET6)
   1.163 +	uint16_t param_length;
   1.164 +#endif
   1.165 +	struct sockaddr *sa;
   1.166 +	int zero_address = 0;
   1.167 +	int bad_address = 0;
   1.168 +#ifdef INET
   1.169 +	struct sockaddr_in *sin;
   1.170 +	struct sctp_ipv4addr_param *v4addr;
   1.171 +#endif
   1.172 +#ifdef INET6
   1.173 +	struct sockaddr_in6 *sin6;
   1.174 +	struct sctp_ipv6addr_param *v6addr;
   1.175 +#endif
   1.176 +
   1.177 +	aparam_length = ntohs(aph->ph.param_length);
   1.178 +	ph = (struct sctp_paramhdr *)(aph + 1);
   1.179 +	param_type = ntohs(ph->param_type);
   1.180 +#if defined(INET) || defined(INET6)
   1.181 +	param_length = ntohs(ph->param_length);
   1.182 +#endif
   1.183 +	sa = (struct sockaddr *)&sa_store;
   1.184 +	switch (param_type) {
   1.185 +#ifdef INET
   1.186 +	case SCTP_IPV4_ADDRESS:
   1.187 +		if (param_length != sizeof(struct sctp_ipv4addr_param)) {
   1.188 +			/* invalid param size */
   1.189 +			return (NULL);
   1.190 +		}
   1.191 +		v4addr = (struct sctp_ipv4addr_param *)ph;
   1.192 +		sin = (struct sockaddr_in *)&sa_store;
   1.193 +		bzero(sin, sizeof(*sin));
   1.194 +		sin->sin_family = AF_INET;
   1.195 +#ifdef HAVE_SIN_LEN
   1.196 +		sin->sin_len = sizeof(struct sockaddr_in);
   1.197 +#endif
   1.198 +		sin->sin_port = stcb->rport;
   1.199 +		sin->sin_addr.s_addr = v4addr->addr;
   1.200 +		if ((sin->sin_addr.s_addr == INADDR_BROADCAST) ||
   1.201 +		    IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
   1.202 +			bad_address = 1;
   1.203 +		}
   1.204 +		if (sin->sin_addr.s_addr == INADDR_ANY)
   1.205 +			zero_address = 1;
   1.206 +		SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: adding ");
   1.207 +		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
   1.208 +		break;
   1.209 +#endif
   1.210 +#ifdef INET6
   1.211 +	case SCTP_IPV6_ADDRESS:
   1.212 +		if (param_length != sizeof(struct sctp_ipv6addr_param)) {
   1.213 +			/* invalid param size */
   1.214 +			return (NULL);
   1.215 +		}
   1.216 +		v6addr = (struct sctp_ipv6addr_param *)ph;
   1.217 +		sin6 = (struct sockaddr_in6 *)&sa_store;
   1.218 +		bzero(sin6, sizeof(*sin6));
   1.219 +		sin6->sin6_family = AF_INET6;
   1.220 +#ifdef HAVE_SIN6_LEN
   1.221 +		sin6->sin6_len = sizeof(struct sockaddr_in6);
   1.222 +#endif
   1.223 +		sin6->sin6_port = stcb->rport;
   1.224 +		memcpy((caddr_t)&sin6->sin6_addr, v6addr->addr,
   1.225 +		    sizeof(struct in6_addr));
   1.226 +		if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
   1.227 +			bad_address = 1;
   1.228 +		}
   1.229 +		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
   1.230 +			zero_address = 1;
   1.231 +		SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: adding ");
   1.232 +		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
   1.233 +		break;
   1.234 +#endif
   1.235 +	default:
   1.236 +		m_reply = sctp_asconf_error_response(aph->correlation_id,
   1.237 +		    SCTP_CAUSE_INVALID_PARAM, (uint8_t *) aph,
   1.238 +		    aparam_length);
   1.239 +		return (m_reply);
   1.240 +	}			/* end switch */
   1.241 +
   1.242 +	/* if 0.0.0.0/::0, add the source address instead */
   1.243 +	if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) {
   1.244 +		sa = src;
   1.245 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
   1.246 +		        "process_asconf_add_ip: using source addr ");
   1.247 +		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src);
   1.248 +	}
   1.249 +	/* add the address */
   1.250 +	if (bad_address) {
   1.251 +		m_reply = sctp_asconf_error_response(aph->correlation_id,
   1.252 +		    SCTP_CAUSE_INVALID_PARAM, (uint8_t *) aph,
   1.253 +		    aparam_length);
   1.254 +	} else if (sctp_add_remote_addr(stcb, sa, &net, SCTP_DONOT_SETSCOPE,
   1.255 +	                         SCTP_ADDR_DYNAMIC_ADDED) != 0) {
   1.256 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
   1.257 +			"process_asconf_add_ip: error adding address\n");
   1.258 +		m_reply = sctp_asconf_error_response(aph->correlation_id,
   1.259 +		    SCTP_CAUSE_RESOURCE_SHORTAGE, (uint8_t *) aph,
   1.260 +		    aparam_length);
   1.261 +	} else {
   1.262 +		/* notify upper layer */
   1.263 +		sctp_ulp_notify(SCTP_NOTIFY_ASCONF_ADD_IP, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
   1.264 +		if (response_required) {
   1.265 +			m_reply =
   1.266 +			    sctp_asconf_success_response(aph->correlation_id);
   1.267 +		}
   1.268 +		sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net);
   1.269 +		sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep,
   1.270 +		                 stcb, net);
   1.271 +		if (send_hb) {
   1.272 +			sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
   1.273 +		}
   1.274 +	}
   1.275 +	return (m_reply);
   1.276 +}
   1.277 +
   1.278 +static int
   1.279 +sctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb, struct sockaddr *src)
   1.280 +{
   1.281 +	struct sctp_nets *src_net, *net;
   1.282 +
   1.283 +	/* make sure the source address exists as a destination net */
   1.284 +	src_net = sctp_findnet(stcb, src);
   1.285 +	if (src_net == NULL) {
   1.286 +		/* not found */
   1.287 +		return (-1);
   1.288 +	}
   1.289 +
   1.290 +	/* delete all destination addresses except the source */
   1.291 +	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
   1.292 +		if (net != src_net) {
   1.293 +			/* delete this address */
   1.294 +			sctp_remove_net(stcb, net);
   1.295 +			SCTPDBG(SCTP_DEBUG_ASCONF1,
   1.296 +				"asconf_del_remote_addrs_except: deleting ");
   1.297 +			SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1,
   1.298 +				     (struct sockaddr *)&net->ro._l_addr);
   1.299 +			/* notify upper layer */
   1.300 +			sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0,
   1.301 +			    (struct sockaddr *)&net->ro._l_addr, SCTP_SO_NOT_LOCKED);
   1.302 +		}
   1.303 +	}
   1.304 +	return (0);
   1.305 +}
   1.306 +
   1.307 +static struct mbuf *
   1.308 +sctp_process_asconf_delete_ip(struct sockaddr *src,
   1.309 +                              struct sctp_asconf_paramhdr *aph,
   1.310 +			      struct sctp_tcb *stcb, int response_required)
   1.311 +{
   1.312 +	struct mbuf *m_reply = NULL;
   1.313 +	struct sockaddr_storage sa_store;
   1.314 +	struct sctp_paramhdr *ph;
   1.315 +	uint16_t param_type, aparam_length;
   1.316 +#if defined(INET) || defined(INET6)
   1.317 +	uint16_t param_length;
   1.318 +#endif
   1.319 +	struct sockaddr *sa;
   1.320 +	int zero_address = 0;
   1.321 +	int result;
   1.322 +#ifdef INET
   1.323 +	struct sockaddr_in *sin;
   1.324 +	struct sctp_ipv4addr_param *v4addr;
   1.325 +#endif
   1.326 +#ifdef INET6
   1.327 +	struct sockaddr_in6 *sin6;
   1.328 +	struct sctp_ipv6addr_param *v6addr;
   1.329 +#endif
   1.330 +
   1.331 +	aparam_length = ntohs(aph->ph.param_length);
   1.332 +	ph = (struct sctp_paramhdr *)(aph + 1);
   1.333 +	param_type = ntohs(ph->param_type);
   1.334 +#if defined(INET) || defined(INET6)
   1.335 +	param_length = ntohs(ph->param_length);
   1.336 +#endif
   1.337 +	sa = (struct sockaddr *)&sa_store;
   1.338 +	switch (param_type) {
   1.339 +#ifdef INET
   1.340 +	case SCTP_IPV4_ADDRESS:
   1.341 +		if (param_length != sizeof(struct sctp_ipv4addr_param)) {
   1.342 +			/* invalid param size */
   1.343 +			return (NULL);
   1.344 +		}
   1.345 +		v4addr = (struct sctp_ipv4addr_param *)ph;
   1.346 +		sin = (struct sockaddr_in *)&sa_store;
   1.347 +		bzero(sin, sizeof(*sin));
   1.348 +		sin->sin_family = AF_INET;
   1.349 +#ifdef HAVE_SIN_LEN
   1.350 +		sin->sin_len = sizeof(struct sockaddr_in);
   1.351 +#endif
   1.352 +		sin->sin_port = stcb->rport;
   1.353 +		sin->sin_addr.s_addr = v4addr->addr;
   1.354 +		if (sin->sin_addr.s_addr == INADDR_ANY)
   1.355 +			zero_address = 1;
   1.356 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
   1.357 +			"process_asconf_delete_ip: deleting ");
   1.358 +		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
   1.359 +		break;
   1.360 +#endif
   1.361 +#ifdef INET6
   1.362 +	case SCTP_IPV6_ADDRESS:
   1.363 +		if (param_length != sizeof(struct sctp_ipv6addr_param)) {
   1.364 +			/* invalid param size */
   1.365 +			return (NULL);
   1.366 +		}
   1.367 +		v6addr = (struct sctp_ipv6addr_param *)ph;
   1.368 +		sin6 = (struct sockaddr_in6 *)&sa_store;
   1.369 +		bzero(sin6, sizeof(*sin6));
   1.370 +		sin6->sin6_family = AF_INET6;
   1.371 +#ifdef HAVE_SIN6_LEN
   1.372 +		sin6->sin6_len = sizeof(struct sockaddr_in6);
   1.373 +#endif
   1.374 +		sin6->sin6_port = stcb->rport;
   1.375 +		memcpy(&sin6->sin6_addr, v6addr->addr,
   1.376 +		    sizeof(struct in6_addr));
   1.377 +		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
   1.378 +			zero_address = 1;
   1.379 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
   1.380 +			"process_asconf_delete_ip: deleting ");
   1.381 +		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
   1.382 +		break;
   1.383 +#endif
   1.384 +	default:
   1.385 +		m_reply = sctp_asconf_error_response(aph->correlation_id,
   1.386 +		    SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph,
   1.387 +		    aparam_length);
   1.388 +		return (m_reply);
   1.389 +	}
   1.390 +
   1.391 +	/* make sure the source address is not being deleted */
   1.392 +	if (sctp_cmpaddr(sa, src)) {
   1.393 +		/* trying to delete the source address! */
   1.394 +		SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: tried to delete source addr\n");
   1.395 +		m_reply = sctp_asconf_error_response(aph->correlation_id,
   1.396 +		    SCTP_CAUSE_DELETING_SRC_ADDR, (uint8_t *) aph,
   1.397 +		    aparam_length);
   1.398 +		return (m_reply);
   1.399 +	}
   1.400 +
   1.401 +	/* if deleting 0.0.0.0/::0, delete all addresses except src addr */
   1.402 +	if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) {
   1.403 +		result = sctp_asconf_del_remote_addrs_except(stcb, src);
   1.404 +
   1.405 +		if (result) {
   1.406 +			/* src address did not exist? */
   1.407 +			SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: src addr does not exist?\n");
   1.408 +			/* what error to reply with?? */
   1.409 +			m_reply =
   1.410 +			    sctp_asconf_error_response(aph->correlation_id,
   1.411 +			    SCTP_CAUSE_REQUEST_REFUSED, (uint8_t *) aph,
   1.412 +			    aparam_length);
   1.413 +		} else if (response_required) {
   1.414 +			m_reply =
   1.415 +			    sctp_asconf_success_response(aph->correlation_id);
   1.416 +		}
   1.417 +		return (m_reply);
   1.418 +	}
   1.419 +
   1.420 +	/* delete the address */
   1.421 +	result = sctp_del_remote_addr(stcb, sa);
   1.422 +	/*
   1.423 +	 * note if result == -2, the address doesn't exist in the asoc but
   1.424 +	 * since it's being deleted anyways, we just ack the delete -- but
   1.425 +	 * this probably means something has already gone awry
   1.426 +	 */
   1.427 +	if (result == -1) {
   1.428 +		/* only one address in the asoc */
   1.429 +		SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: tried to delete last IP addr!\n");
   1.430 +		m_reply = sctp_asconf_error_response(aph->correlation_id,
   1.431 +		    SCTP_CAUSE_DELETING_LAST_ADDR, (uint8_t *) aph,
   1.432 +		    aparam_length);
   1.433 +	} else {
   1.434 +		if (response_required) {
   1.435 +	 		m_reply = sctp_asconf_success_response(aph->correlation_id);
   1.436 +		}
   1.437 +		/* notify upper layer */
   1.438 +		sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
   1.439 +	}
   1.440 +	return (m_reply);
   1.441 +}
   1.442 +
   1.443 +static struct mbuf *
   1.444 +sctp_process_asconf_set_primary(struct sockaddr *src,
   1.445 +				struct sctp_asconf_paramhdr *aph,
   1.446 +				struct sctp_tcb *stcb, int response_required)
   1.447 +{
   1.448 +	struct mbuf *m_reply = NULL;
   1.449 +	struct sockaddr_storage sa_store;
   1.450 +	struct sctp_paramhdr *ph;
   1.451 +	uint16_t param_type, aparam_length;
   1.452 +#if defined(INET) || defined(INET6)
   1.453 +	uint16_t param_length;
   1.454 +#endif
   1.455 +	struct sockaddr *sa;
   1.456 +	int zero_address = 0;
   1.457 +#ifdef INET
   1.458 +	struct sockaddr_in *sin;
   1.459 +	struct sctp_ipv4addr_param *v4addr;
   1.460 +#endif
   1.461 +#ifdef INET6
   1.462 +	struct sockaddr_in6 *sin6;
   1.463 +	struct sctp_ipv6addr_param *v6addr;
   1.464 +#endif
   1.465 +
   1.466 +	aparam_length = ntohs(aph->ph.param_length);
   1.467 +	ph = (struct sctp_paramhdr *)(aph + 1);
   1.468 +	param_type = ntohs(ph->param_type);
   1.469 +#if defined(INET) || defined(INET6)
   1.470 +	param_length = ntohs(ph->param_length);
   1.471 +#endif
   1.472 +	sa = (struct sockaddr *)&sa_store;
   1.473 +	switch (param_type) {
   1.474 +#ifdef INET
   1.475 +	case SCTP_IPV4_ADDRESS:
   1.476 +		if (param_length != sizeof(struct sctp_ipv4addr_param)) {
   1.477 +			/* invalid param size */
   1.478 +			return (NULL);
   1.479 +		}
   1.480 +		v4addr = (struct sctp_ipv4addr_param *)ph;
   1.481 +		sin = (struct sockaddr_in *)&sa_store;
   1.482 +		bzero(sin, sizeof(*sin));
   1.483 +		sin->sin_family = AF_INET;
   1.484 +#ifdef HAVE_SIN_LEN
   1.485 +		sin->sin_len = sizeof(struct sockaddr_in);
   1.486 +#endif
   1.487 +		sin->sin_addr.s_addr = v4addr->addr;
   1.488 +		if (sin->sin_addr.s_addr == INADDR_ANY)
   1.489 +			zero_address = 1;
   1.490 +		SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_set_primary: ");
   1.491 +		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
   1.492 +		break;
   1.493 +#endif
   1.494 +#ifdef INET6
   1.495 +	case SCTP_IPV6_ADDRESS:
   1.496 +		if (param_length != sizeof(struct sctp_ipv6addr_param)) {
   1.497 +			/* invalid param size */
   1.498 +			return (NULL);
   1.499 +		}
   1.500 +		v6addr = (struct sctp_ipv6addr_param *)ph;
   1.501 +		sin6 = (struct sockaddr_in6 *)&sa_store;
   1.502 +		bzero(sin6, sizeof(*sin6));
   1.503 +		sin6->sin6_family = AF_INET6;
   1.504 +#ifdef HAVE_SIN6_LEN
   1.505 +		sin6->sin6_len = sizeof(struct sockaddr_in6);
   1.506 +#endif
   1.507 +		memcpy((caddr_t)&sin6->sin6_addr, v6addr->addr,
   1.508 +		    sizeof(struct in6_addr));
   1.509 +		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
   1.510 +			zero_address = 1;
   1.511 +		SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_set_primary: ");
   1.512 +		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
   1.513 +		break;
   1.514 +#endif
   1.515 +	default:
   1.516 +		m_reply = sctp_asconf_error_response(aph->correlation_id,
   1.517 +		    SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph,
   1.518 +		    aparam_length);
   1.519 +		return (m_reply);
   1.520 +	}
   1.521 +
   1.522 +	/* if 0.0.0.0/::0, use the source address instead */
   1.523 +	if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) {
   1.524 +		sa = src;
   1.525 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
   1.526 +			"process_asconf_set_primary: using source addr ");
   1.527 +		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src);
   1.528 +	}
   1.529 +	/* set the primary address */
   1.530 +	if (sctp_set_primary_addr(stcb, sa, NULL) == 0) {
   1.531 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
   1.532 +			"process_asconf_set_primary: primary address set\n");
   1.533 +		/* notify upper layer */
   1.534 +		sctp_ulp_notify(SCTP_NOTIFY_ASCONF_SET_PRIMARY, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
   1.535 +		if ((stcb->asoc.primary_destination->dest_state & SCTP_ADDR_REACHABLE) &&
   1.536 +		    (!(stcb->asoc.primary_destination->dest_state & SCTP_ADDR_PF)) &&
   1.537 +		    (stcb->asoc.alternate)) {
   1.538 +			sctp_free_remote_addr(stcb->asoc.alternate);
   1.539 +			stcb->asoc.alternate = NULL;
   1.540 +		}
   1.541 +		if (response_required) {
   1.542 +			m_reply = sctp_asconf_success_response(aph->correlation_id);
   1.543 +		}
   1.544 +		/* Mobility adaptation.
   1.545 +		   Ideally, when the reception of SET PRIMARY with DELETE IP
   1.546 +		   ADDRESS of the previous primary destination, unacknowledged
   1.547 +		   DATA are retransmitted immediately to the new primary
   1.548 +		   destination for seamless handover.
   1.549 +		   If the destination is UNCONFIRMED and marked to REQ_PRIM,
   1.550 +		   The retransmission occur when reception of the
   1.551 +		   HEARTBEAT-ACK.  (See sctp_handle_heartbeat_ack in
   1.552 +		   sctp_input.c)
   1.553 +		   Also, when change of the primary destination, it is better
   1.554 +		   that all subsequent new DATA containing already queued DATA
   1.555 +		   are transmitted to the new primary destination. (by micchie)
   1.556 +		 */
   1.557 +		if ((sctp_is_mobility_feature_on(stcb->sctp_ep,
   1.558 +				       	SCTP_MOBILITY_BASE) ||
   1.559 +		    sctp_is_mobility_feature_on(stcb->sctp_ep,
   1.560 +			    		SCTP_MOBILITY_FASTHANDOFF)) &&
   1.561 +		    sctp_is_mobility_feature_on(stcb->sctp_ep,
   1.562 +			   		 SCTP_MOBILITY_PRIM_DELETED) &&
   1.563 +		    (stcb->asoc.primary_destination->dest_state &
   1.564 +		     SCTP_ADDR_UNCONFIRMED) == 0) {
   1.565 +
   1.566 +			sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_TIMER+SCTP_LOC_7);
   1.567 +			if (sctp_is_mobility_feature_on(stcb->sctp_ep,
   1.568 +					SCTP_MOBILITY_FASTHANDOFF)) {
   1.569 +				sctp_assoc_immediate_retrans(stcb,
   1.570 +						stcb->asoc.primary_destination);
   1.571 +			}
   1.572 +			if (sctp_is_mobility_feature_on(stcb->sctp_ep,
   1.573 +					SCTP_MOBILITY_BASE)) {
   1.574 +				sctp_move_chunks_from_net(stcb,
   1.575 +						stcb->asoc.deleted_primary);
   1.576 +			}
   1.577 +			sctp_delete_prim_timer(stcb->sctp_ep, stcb,
   1.578 +						stcb->asoc.deleted_primary);
   1.579 +		}
   1.580 +	} else {
   1.581 +		/* couldn't set the requested primary address! */
   1.582 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
   1.583 +			"process_asconf_set_primary: set primary failed!\n");
   1.584 +		/* must have been an invalid address, so report */
   1.585 +		m_reply = sctp_asconf_error_response(aph->correlation_id,
   1.586 +		    SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph,
   1.587 +		    aparam_length);
   1.588 +	}
   1.589 +
   1.590 +	return (m_reply);
   1.591 +}
   1.592 +
   1.593 +/*
   1.594 + * handles an ASCONF chunk.
   1.595 + * if all parameters are processed ok, send a plain (empty) ASCONF-ACK
   1.596 + */
   1.597 +void
   1.598 +sctp_handle_asconf(struct mbuf *m, unsigned int offset,
   1.599 +                   struct sockaddr *src,
   1.600 +		   struct sctp_asconf_chunk *cp, struct sctp_tcb *stcb,
   1.601 +		   int first)
   1.602 +{
   1.603 +	struct sctp_association *asoc;
   1.604 +	uint32_t serial_num;
   1.605 +	struct mbuf *n, *m_ack, *m_result, *m_tail;
   1.606 +	struct sctp_asconf_ack_chunk *ack_cp;
   1.607 +	struct sctp_asconf_paramhdr *aph, *ack_aph;
   1.608 +	struct sctp_ipv6addr_param *p_addr;
   1.609 +	unsigned int asconf_limit, cnt;
   1.610 +	int error = 0;		/* did an error occur? */
   1.611 +
   1.612 +	/* asconf param buffer */
   1.613 +	uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE];
   1.614 +	struct sctp_asconf_ack *ack, *ack_next;
   1.615 +
   1.616 +	/* verify minimum length */
   1.617 +	if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_asconf_chunk)) {
   1.618 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
   1.619 +			"handle_asconf: chunk too small = %xh\n",
   1.620 +			ntohs(cp->ch.chunk_length));
   1.621 +		return;
   1.622 +	}
   1.623 +	asoc = &stcb->asoc;
   1.624 +	serial_num = ntohl(cp->serial_number);
   1.625 +
   1.626 +	if (SCTP_TSN_GE(asoc->asconf_seq_in, serial_num)) {
   1.627 +		/* got a duplicate ASCONF */
   1.628 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
   1.629 +			"handle_asconf: got duplicate serial number = %xh\n",
   1.630 +			serial_num);
   1.631 +		return;
   1.632 +	} else if (serial_num != (asoc->asconf_seq_in + 1)) {
   1.633 +		SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: incorrect serial number = %xh (expected next = %xh)\n",
   1.634 +			serial_num, asoc->asconf_seq_in + 1);
   1.635 +		return;
   1.636 +	}
   1.637 +
   1.638 +	/* it's the expected "next" sequence number, so process it */
   1.639 +	asoc->asconf_seq_in = serial_num;	/* update sequence */
   1.640 +	/* get length of all the param's in the ASCONF */
   1.641 +	asconf_limit = offset + ntohs(cp->ch.chunk_length);
   1.642 +	SCTPDBG(SCTP_DEBUG_ASCONF1,
   1.643 +		"handle_asconf: asconf_limit=%u, sequence=%xh\n",
   1.644 +		asconf_limit, serial_num);
   1.645 +
   1.646 +	if (first) {
   1.647 +		/* delete old cache */
   1.648 +		SCTPDBG(SCTP_DEBUG_ASCONF1,"handle_asconf: Now processing first ASCONF. Try to delete old cache\n");
   1.649 +
   1.650 +		TAILQ_FOREACH_SAFE(ack, &asoc->asconf_ack_sent, next, ack_next) {
   1.651 +			if (ack->serial_number == serial_num)
   1.652 +				break;
   1.653 +			SCTPDBG(SCTP_DEBUG_ASCONF1,"handle_asconf: delete old(%u) < first(%u)\n",
   1.654 +			    ack->serial_number, serial_num);
   1.655 +			TAILQ_REMOVE(&asoc->asconf_ack_sent, ack, next);
   1.656 +			if (ack->data != NULL) {
   1.657 +				sctp_m_freem(ack->data);
   1.658 +			}
   1.659 +			SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asconf_ack), ack);
   1.660 +		}
   1.661 +	}
   1.662 +
   1.663 +	m_ack = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_ack_chunk), 0,
   1.664 +				      M_NOWAIT, 1, MT_DATA);
   1.665 +	if (m_ack == NULL) {
   1.666 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
   1.667 +			"handle_asconf: couldn't get mbuf!\n");
   1.668 +		return;
   1.669 +	}
   1.670 +	m_tail = m_ack;		/* current reply chain's tail */
   1.671 +
   1.672 +	/* fill in ASCONF-ACK header */
   1.673 +	ack_cp = mtod(m_ack, struct sctp_asconf_ack_chunk *);
   1.674 +	ack_cp->ch.chunk_type = SCTP_ASCONF_ACK;
   1.675 +	ack_cp->ch.chunk_flags = 0;
   1.676 +	ack_cp->serial_number = htonl(serial_num);
   1.677 +	/* set initial lengths (eg. just an ASCONF-ACK), ntohx at the end! */
   1.678 +	SCTP_BUF_LEN(m_ack) = sizeof(struct sctp_asconf_ack_chunk);
   1.679 +	ack_cp->ch.chunk_length = sizeof(struct sctp_asconf_ack_chunk);
   1.680 +
   1.681 +	/* skip the lookup address parameter */
   1.682 +	offset += sizeof(struct sctp_asconf_chunk);
   1.683 +	p_addr = (struct sctp_ipv6addr_param *)sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr), (uint8_t *)&aparam_buf);
   1.684 +	if (p_addr == NULL) {
   1.685 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
   1.686 +			"handle_asconf: couldn't get lookup addr!\n");
   1.687 +		/* respond with a missing/invalid mandatory parameter error */
   1.688 +		return;
   1.689 +	}
   1.690 +	/* param_length is already validated in process_control... */
   1.691 +	offset += ntohs(p_addr->ph.param_length);	/* skip lookup addr */
   1.692 +
   1.693 +	/* get pointer to first asconf param in ASCONF-ACK */
   1.694 +	ack_aph = (struct sctp_asconf_paramhdr *)(mtod(m_ack, caddr_t) + sizeof(struct sctp_asconf_ack_chunk));
   1.695 +	if (ack_aph == NULL) {
   1.696 +		SCTPDBG(SCTP_DEBUG_ASCONF1, "Gak in asconf2\n");
   1.697 +		return;
   1.698 +	}
   1.699 +	/* get pointer to first asconf param in ASCONF */
   1.700 +	aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, sizeof(struct sctp_asconf_paramhdr), (uint8_t *)&aparam_buf);
   1.701 +	if (aph == NULL) {
   1.702 +		SCTPDBG(SCTP_DEBUG_ASCONF1, "Empty ASCONF received?\n");
   1.703 +		goto send_reply;
   1.704 +	}
   1.705 +	/* process through all parameters */
   1.706 +	cnt = 0;
   1.707 +	while (aph != NULL) {
   1.708 +		unsigned int param_length, param_type;
   1.709 +
   1.710 +		param_type = ntohs(aph->ph.param_type);
   1.711 +		param_length = ntohs(aph->ph.param_length);
   1.712 +		if (offset + param_length > asconf_limit) {
   1.713 +			/* parameter goes beyond end of chunk! */
   1.714 +			sctp_m_freem(m_ack);
   1.715 +			return;
   1.716 +		}
   1.717 +		m_result = NULL;
   1.718 +
   1.719 +		if (param_length > sizeof(aparam_buf)) {
   1.720 +			SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: param length (%u) larger than buffer size!\n", param_length);
   1.721 +			sctp_m_freem(m_ack);
   1.722 +			return;
   1.723 +		}
   1.724 +		if (param_length <= sizeof(struct sctp_paramhdr)) {
   1.725 +			SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: param length (%u) too short\n", param_length);
   1.726 +			sctp_m_freem(m_ack);
   1.727 +		}
   1.728 +		/* get the entire parameter */
   1.729 +		aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, param_length, aparam_buf);
   1.730 +		if (aph == NULL) {
   1.731 +			SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: couldn't get entire param\n");
   1.732 +			sctp_m_freem(m_ack);
   1.733 +			return;
   1.734 +		}
   1.735 +		switch (param_type) {
   1.736 +		case SCTP_ADD_IP_ADDRESS:
   1.737 +			asoc->peer_supports_asconf = 1;
   1.738 +			m_result = sctp_process_asconf_add_ip(src, aph, stcb,
   1.739 +			    (cnt < SCTP_BASE_SYSCTL(sctp_hb_maxburst)), error);
   1.740 +			cnt++;
   1.741 +			break;
   1.742 +		case SCTP_DEL_IP_ADDRESS:
   1.743 +			asoc->peer_supports_asconf = 1;
   1.744 +			m_result = sctp_process_asconf_delete_ip(src, aph, stcb,
   1.745 +			    error);
   1.746 +			break;
   1.747 +		case SCTP_ERROR_CAUSE_IND:
   1.748 +			/* not valid in an ASCONF chunk */
   1.749 +			break;
   1.750 +		case SCTP_SET_PRIM_ADDR:
   1.751 +			asoc->peer_supports_asconf = 1;
   1.752 +			m_result = sctp_process_asconf_set_primary(src, aph,
   1.753 +			    stcb, error);
   1.754 +			break;
   1.755 +		case SCTP_NAT_VTAGS:
   1.756 +		        SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: sees a NAT VTAG state parameter\n");
   1.757 +		        break;
   1.758 +		case SCTP_SUCCESS_REPORT:
   1.759 +			/* not valid in an ASCONF chunk */
   1.760 +			break;
   1.761 +		case SCTP_ULP_ADAPTATION:
   1.762 +			/* FIX */
   1.763 +			break;
   1.764 +		default:
   1.765 +			if ((param_type & 0x8000) == 0) {
   1.766 +				/* Been told to STOP at this param */
   1.767 +				asconf_limit = offset;
   1.768 +				/*
   1.769 +				 * FIX FIX - We need to call
   1.770 +				 * sctp_arethere_unrecognized_parameters()
   1.771 +				 * to get a operr and send it for any
   1.772 +				 * param's with the 0x4000 bit set OR do it
   1.773 +				 * here ourselves... note we still must STOP
   1.774 +				 * if the 0x8000 bit is clear.
   1.775 +				 */
   1.776 +			}
   1.777 +			/* unknown/invalid param type */
   1.778 +			break;
   1.779 +		} /* switch */
   1.780 +
   1.781 +		/* add any (error) result to the reply mbuf chain */
   1.782 +		if (m_result != NULL) {
   1.783 +			SCTP_BUF_NEXT(m_tail) = m_result;
   1.784 +			m_tail = m_result;
   1.785 +			/* update lengths, make sure it's aligned too */
   1.786 +			SCTP_BUF_LEN(m_result) = SCTP_SIZE32(SCTP_BUF_LEN(m_result));
   1.787 +			ack_cp->ch.chunk_length += SCTP_BUF_LEN(m_result);
   1.788 +			/* set flag to force success reports */
   1.789 +			error = 1;
   1.790 +		}
   1.791 +		offset += SCTP_SIZE32(param_length);
   1.792 +		/* update remaining ASCONF message length to process */
   1.793 +		if (offset >= asconf_limit) {
   1.794 +			/* no more data in the mbuf chain */
   1.795 +			break;
   1.796 +		}
   1.797 +		/* get pointer to next asconf param */
   1.798 +		aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset,
   1.799 +		    sizeof(struct sctp_asconf_paramhdr),
   1.800 +		    (uint8_t *)&aparam_buf);
   1.801 +		if (aph == NULL) {
   1.802 +			/* can't get an asconf paramhdr */
   1.803 +			SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: can't get asconf param hdr!\n");
   1.804 +			/* FIX ME - add error here... */
   1.805 +		}
   1.806 +	}
   1.807 +
   1.808 + send_reply:
   1.809 +	ack_cp->ch.chunk_length = htons(ack_cp->ch.chunk_length);
   1.810 +	/* save the ASCONF-ACK reply */
   1.811 +	ack = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_asconf_ack),
   1.812 +	    struct sctp_asconf_ack);
   1.813 +	if (ack == NULL) {
   1.814 +		sctp_m_freem(m_ack);
   1.815 +		return;
   1.816 +	}
   1.817 +	ack->serial_number = serial_num;
   1.818 +	ack->last_sent_to = NULL;
   1.819 +	ack->data = m_ack;
   1.820 +	ack->len = 0;
   1.821 +	for (n = m_ack; n != NULL; n = SCTP_BUF_NEXT(n)) {
   1.822 +		ack->len += SCTP_BUF_LEN(n);
   1.823 +	}
   1.824 +	TAILQ_INSERT_TAIL(&stcb->asoc.asconf_ack_sent, ack, next);
   1.825 +
   1.826 +	/* see if last_control_chunk_from is set properly (use IP src addr) */
   1.827 +	if (stcb->asoc.last_control_chunk_from == NULL) {
   1.828 +		/*
   1.829 +		 * this could happen if the source address was just newly
   1.830 +		 * added
   1.831 +		 */
   1.832 +		SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: looking up net for IP source address\n");
   1.833 +		SCTPDBG(SCTP_DEBUG_ASCONF1, "Looking for IP source: ");
   1.834 +		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src);
   1.835 +		/* look up the from address */
   1.836 +		stcb->asoc.last_control_chunk_from = sctp_findnet(stcb, src);
   1.837 +#ifdef SCTP_DEBUG
   1.838 +		if (stcb->asoc.last_control_chunk_from == NULL) {
   1.839 +			SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: IP source address not found?!\n");
   1.840 +		}
   1.841 +#endif
   1.842 +	}
   1.843 +}
   1.844 +
   1.845 +/*
   1.846 + * does the address match? returns 0 if not, 1 if so
   1.847 + */
   1.848 +static uint32_t
   1.849 +sctp_asconf_addr_match(struct sctp_asconf_addr *aa, struct sockaddr *sa)
   1.850 +{
   1.851 +	switch (sa->sa_family) {
   1.852 +#ifdef INET6
   1.853 +	case AF_INET6:
   1.854 +	{
   1.855 +		/* XXX scopeid */
   1.856 +		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
   1.857 +
   1.858 +		if ((aa->ap.addrp.ph.param_type == SCTP_IPV6_ADDRESS) &&
   1.859 +		    (memcmp(&aa->ap.addrp.addr, &sin6->sin6_addr,
   1.860 +		    sizeof(struct in6_addr)) == 0)) {
   1.861 +			return (1);
   1.862 +		}
   1.863 +		break;
   1.864 +	}
   1.865 +#endif
   1.866 +#ifdef INET
   1.867 +	case AF_INET:
   1.868 +	{
   1.869 +		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
   1.870 +
   1.871 +		if ((aa->ap.addrp.ph.param_type == SCTP_IPV4_ADDRESS) &&
   1.872 +		    (memcmp(&aa->ap.addrp.addr, &sin->sin_addr,
   1.873 +		    sizeof(struct in_addr)) == 0)) {
   1.874 +			return (1);
   1.875 +		}
   1.876 +		break;
   1.877 +	}
   1.878 +#endif
   1.879 +	default:
   1.880 +		break;
   1.881 +	}
   1.882 +	return (0);
   1.883 +}
   1.884 +
   1.885 +/*
   1.886 + * does the address match? returns 0 if not, 1 if so
   1.887 + */
   1.888 +static uint32_t
   1.889 +sctp_addr_match(struct sctp_paramhdr *ph, struct sockaddr *sa)
   1.890 +{
   1.891 +#if defined(INET) || defined(INET6)
   1.892 +	uint16_t param_type, param_length;
   1.893 +
   1.894 +	param_type = ntohs(ph->param_type);
   1.895 +	param_length = ntohs(ph->param_length);
   1.896 +#endif
   1.897 +	switch (sa->sa_family) {
   1.898 +#ifdef INET6
   1.899 +	case AF_INET6:
   1.900 +	{
   1.901 +		/* XXX scopeid */
   1.902 +		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
   1.903 +		struct sctp_ipv6addr_param *v6addr;
   1.904 +
   1.905 +		v6addr = (struct sctp_ipv6addr_param *)ph;
   1.906 +		if ((param_type == SCTP_IPV6_ADDRESS) &&
   1.907 +		    (param_length == sizeof(struct sctp_ipv6addr_param)) &&
   1.908 +		    (memcmp(&v6addr->addr, &sin6->sin6_addr,
   1.909 +		    sizeof(struct in6_addr)) == 0)) {
   1.910 +			return (1);
   1.911 +		}
   1.912 +		break;
   1.913 +	}
   1.914 +#endif
   1.915 +#ifdef INET
   1.916 +	case AF_INET:
   1.917 +	{
   1.918 +		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
   1.919 +		struct sctp_ipv4addr_param *v4addr;
   1.920 +
   1.921 +		v4addr = (struct sctp_ipv4addr_param *)ph;
   1.922 +		if ((param_type == SCTP_IPV4_ADDRESS) &&
   1.923 +		    (param_length == sizeof(struct sctp_ipv4addr_param)) &&
   1.924 +		    (memcmp(&v4addr->addr, &sin->sin_addr,
   1.925 +		    sizeof(struct in_addr)) == 0)) {
   1.926 +			return (1);
   1.927 +		}
   1.928 +		break;
   1.929 +	}
   1.930 +#endif
   1.931 +	default:
   1.932 +		break;
   1.933 +	}
   1.934 +	return (0);
   1.935 +}
   1.936 +/*
   1.937 + * Cleanup for non-responded/OP ERR'd ASCONF
   1.938 + */
   1.939 +void
   1.940 +sctp_asconf_cleanup(struct sctp_tcb *stcb, struct sctp_nets *net)
   1.941 +{
   1.942 +	/* mark peer as ASCONF incapable */
   1.943 +	stcb->asoc.peer_supports_asconf = 0;
   1.944 +	/*
   1.945 +	 * clear out any existing asconfs going out
   1.946 +	 */
   1.947 +	sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net,
   1.948 +			SCTP_FROM_SCTP_ASCONF+SCTP_LOC_2);
   1.949 +	stcb->asoc.asconf_seq_out_acked = stcb->asoc.asconf_seq_out;
   1.950 +	/* remove the old ASCONF on our outbound queue */
   1.951 +	sctp_toss_old_asconf(stcb);
   1.952 +}
   1.953 +
   1.954 +/*
   1.955 + * cleanup any cached source addresses that may be topologically
   1.956 + * incorrect after a new address has been added to this interface.
   1.957 + */
   1.958 +static void
   1.959 +sctp_asconf_nets_cleanup(struct sctp_tcb *stcb, struct sctp_ifn *ifn)
   1.960 +{
   1.961 +	struct sctp_nets *net;
   1.962 +
   1.963 +	/*
   1.964 +	 * Ideally, we want to only clear cached routes and source addresses
   1.965 +	 * that are topologically incorrect.  But since there is no easy way
   1.966 +	 * to know whether the newly added address on the ifn would cause a
   1.967 +	 * routing change (i.e. a new egress interface would be chosen)
   1.968 +	 * without doing a new routing lookup and source address selection,
   1.969 +	 * we will (for now) just flush any cached route using a different
   1.970 +	 * ifn (and cached source addrs) and let output re-choose them during
   1.971 +	 * the next send on that net.
   1.972 +	 */
   1.973 +	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
   1.974 +		/*
   1.975 +		 * clear any cached route (and cached source address) if the
   1.976 +		 * route's interface is NOT the same as the address change.
   1.977 +		 * If it's the same interface, just clear the cached source
   1.978 +		 * address.
   1.979 +		 */
   1.980 +		if (SCTP_ROUTE_HAS_VALID_IFN(&net->ro) &&
   1.981 +		    ((ifn == NULL) ||
   1.982 +		     (SCTP_GET_IF_INDEX_FROM_ROUTE(&net->ro) != ifn->ifn_index))) {
   1.983 +			/* clear any cached route */
   1.984 +			RTFREE(net->ro.ro_rt);
   1.985 +			net->ro.ro_rt = NULL;
   1.986 +		}
   1.987 +		/* clear any cached source address */
   1.988 +		if (net->src_addr_selected) {
   1.989 +			sctp_free_ifa(net->ro._s_addr);
   1.990 +			net->ro._s_addr = NULL;
   1.991 +			net->src_addr_selected = 0;
   1.992 +		}
   1.993 +	}
   1.994 +}
   1.995 +
   1.996 +
   1.997 +void
   1.998 +sctp_assoc_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *dstnet)
   1.999 +{
  1.1000 +	int error;
  1.1001 +
  1.1002 +	if (dstnet->dest_state & SCTP_ADDR_UNCONFIRMED) {
  1.1003 +		return;
  1.1004 +	}
  1.1005 +	if (stcb->asoc.deleted_primary == NULL) {
  1.1006 +		return;
  1.1007 +	}
  1.1008 +
  1.1009 +	if (!TAILQ_EMPTY(&stcb->asoc.sent_queue)) {
  1.1010 +		SCTPDBG(SCTP_DEBUG_ASCONF1, "assoc_immediate_retrans: Deleted primary is ");
  1.1011 +		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.deleted_primary->ro._l_addr.sa);
  1.1012 +		SCTPDBG(SCTP_DEBUG_ASCONF1, "Current Primary is ");
  1.1013 +		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.primary_destination->ro._l_addr.sa);
  1.1014 +		sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb,
  1.1015 +				stcb->asoc.deleted_primary,
  1.1016 +				SCTP_FROM_SCTP_TIMER+SCTP_LOC_8);
  1.1017 +		stcb->asoc.num_send_timers_up--;
  1.1018 +		if (stcb->asoc.num_send_timers_up < 0) {
  1.1019 +			stcb->asoc.num_send_timers_up = 0;
  1.1020 +		}
  1.1021 +		SCTP_TCB_LOCK_ASSERT(stcb);
  1.1022 +		error = sctp_t3rxt_timer(stcb->sctp_ep, stcb,
  1.1023 +					stcb->asoc.deleted_primary);
  1.1024 +		if (error) {
  1.1025 +			SCTP_INP_DECR_REF(stcb->sctp_ep);
  1.1026 +			return;
  1.1027 +		}
  1.1028 +		SCTP_TCB_LOCK_ASSERT(stcb);
  1.1029 +#ifdef SCTP_AUDITING_ENABLED
  1.1030 +		sctp_auditing(4, stcb->sctp_ep, stcb, stcb->asoc.deleted_primary);
  1.1031 +#endif
  1.1032 +		sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
  1.1033 +		if ((stcb->asoc.num_send_timers_up == 0) &&
  1.1034 +		    (stcb->asoc.sent_queue_cnt > 0)) {
  1.1035 +			struct sctp_tmit_chunk *chk;
  1.1036 +
  1.1037 +			chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
  1.1038 +			sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
  1.1039 +					 stcb, chk->whoTo);
  1.1040 +		}
  1.1041 +	}
  1.1042 +	return;
  1.1043 +}
  1.1044 +
  1.1045 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__)
  1.1046 +static int
  1.1047 +sctp_asconf_queue_mgmt(struct sctp_tcb *, struct sctp_ifa *, uint16_t);
  1.1048 +
  1.1049 +void
  1.1050 +sctp_net_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *net)
  1.1051 +{
  1.1052 +	struct sctp_tmit_chunk *chk;
  1.1053 +
  1.1054 +	SCTPDBG(SCTP_DEBUG_ASCONF1, "net_immediate_retrans: RTO is %d\n", net->RTO);
  1.1055 +	sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net,
  1.1056 +	    SCTP_FROM_SCTP_TIMER+SCTP_LOC_5);
  1.1057 +	stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
  1.1058 +	net->error_count = 0;
  1.1059 +	TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
  1.1060 +		if (chk->whoTo == net) {
  1.1061 +			if (chk->sent < SCTP_DATAGRAM_RESEND) {
  1.1062 +				chk->sent = SCTP_DATAGRAM_RESEND;
  1.1063 +				sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
  1.1064 +				sctp_flight_size_decrease(chk);
  1.1065 +				sctp_total_flight_decrease(stcb, chk);
  1.1066 +				net->marked_retrans++;
  1.1067 +				stcb->asoc.marked_retrans++;
  1.1068 +			}
  1.1069 +		}
  1.1070 +	}
  1.1071 +	if (net->marked_retrans) {
  1.1072 +		sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
  1.1073 +	}
  1.1074 +}
  1.1075 +
  1.1076 +static void
  1.1077 +sctp_path_check_and_react(struct sctp_tcb *stcb, struct sctp_ifa *newifa)
  1.1078 +{
  1.1079 +	struct sctp_nets *net;
  1.1080 +	int addrnum, changed;
  1.1081 +
  1.1082 +	/*   If number of local valid addresses is 1, the valid address is
  1.1083 +	     probably newly added address.
  1.1084 +	     Several valid addresses in this association.  A source address
  1.1085 +	     may not be changed.  Additionally, they can be configured on a
  1.1086 +	     same interface as "alias" addresses.  (by micchie)
  1.1087 +	 */
  1.1088 +	addrnum = sctp_local_addr_count(stcb);
  1.1089 +	SCTPDBG(SCTP_DEBUG_ASCONF1, "p_check_react(): %d local addresses\n",
  1.1090 +		addrnum);
  1.1091 +	if (addrnum == 1) {
  1.1092 +		TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1.1093 +			/* clear any cached route and source address */
  1.1094 +			if (net->ro.ro_rt) {
  1.1095 +				RTFREE(net->ro.ro_rt);
  1.1096 +				net->ro.ro_rt = NULL;
  1.1097 +			}
  1.1098 +			if (net->src_addr_selected) {
  1.1099 +				sctp_free_ifa(net->ro._s_addr);
  1.1100 +				net->ro._s_addr = NULL;
  1.1101 +				net->src_addr_selected = 0;
  1.1102 +			}
  1.1103 +			/* Retransmit unacknowledged DATA chunks immediately */
  1.1104 +			if (sctp_is_mobility_feature_on(stcb->sctp_ep,
  1.1105 +		    		SCTP_MOBILITY_FASTHANDOFF)) {
  1.1106 +				sctp_net_immediate_retrans(stcb, net);
  1.1107 +			}
  1.1108 +			/* also, SET PRIMARY is maybe already sent */
  1.1109 +		}
  1.1110 +		return;
  1.1111 +	}
  1.1112 +
  1.1113 +	/* Multiple local addresses exsist in the association.  */
  1.1114 +	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1.1115 +		/* clear any cached route and source address */
  1.1116 +		if (net->ro.ro_rt) {
  1.1117 +			RTFREE(net->ro.ro_rt);
  1.1118 +			net->ro.ro_rt = NULL;
  1.1119 +		}
  1.1120 +		if (net->src_addr_selected) {
  1.1121 +			sctp_free_ifa(net->ro._s_addr);
  1.1122 +			net->ro._s_addr = NULL;
  1.1123 +			net->src_addr_selected = 0;
  1.1124 +		}
  1.1125 +		/* Check if the nexthop is corresponding to the new address.
  1.1126 +		   If the new address is corresponding to the current nexthop,
  1.1127 +		   the path will be changed.
  1.1128 +		   If the new address is NOT corresponding to the current
  1.1129 +		   nexthop, the path will not be changed.
  1.1130 +		 */
  1.1131 +		SCTP_RTALLOC((sctp_route_t *)&net->ro,
  1.1132 +			     stcb->sctp_ep->def_vrf_id);
  1.1133 +		if (net->ro.ro_rt == NULL)
  1.1134 +			continue;
  1.1135 +
  1.1136 +		changed = 0;
  1.1137 +		switch (net->ro._l_addr.sa.sa_family) {
  1.1138 +#ifdef INET
  1.1139 +		case AF_INET:
  1.1140 +			if (sctp_v4src_match_nexthop(newifa, (sctp_route_t *)&net->ro)) {
  1.1141 +				changed = 1;
  1.1142 +			}
  1.1143 +			break;
  1.1144 +#endif
  1.1145 +#ifdef INET6
  1.1146 +		case AF_INET6:
  1.1147 +			if (sctp_v6src_match_nexthop(
  1.1148 +			    &newifa->address.sin6, (sctp_route_t *)&net->ro)) {
  1.1149 +				changed = 1;
  1.1150 +			}
  1.1151 +			break;
  1.1152 +#endif
  1.1153 +		default:
  1.1154 +			break;
  1.1155 +		}
  1.1156 +		/* if the newly added address does not relate routing
  1.1157 +		   information, we skip.
  1.1158 +		 */
  1.1159 +		if (changed == 0)
  1.1160 +			continue;
  1.1161 +		/* Retransmit unacknowledged DATA chunks immediately */
  1.1162 +		if (sctp_is_mobility_feature_on(stcb->sctp_ep,
  1.1163 +		   		SCTP_MOBILITY_FASTHANDOFF)) {
  1.1164 +			sctp_net_immediate_retrans(stcb, net);
  1.1165 +		}
  1.1166 +		/* Send SET PRIMARY for this new address */
  1.1167 +		if (net == stcb->asoc.primary_destination) {
  1.1168 +			(void)sctp_asconf_queue_mgmt(stcb, newifa,
  1.1169 +						     SCTP_SET_PRIM_ADDR);
  1.1170 +		}
  1.1171 +	}
  1.1172 +}
  1.1173 +#endif /* __FreeBSD__  __APPLE__  __Userspace__ */
  1.1174 +
  1.1175 +/*
  1.1176 + * process an ADD/DELETE IP ack from peer.
  1.1177 + * addr: corresponding sctp_ifa to the address being added/deleted.
  1.1178 + * type: SCTP_ADD_IP_ADDRESS or SCTP_DEL_IP_ADDRESS.
  1.1179 + * flag: 1=success, 0=failure.
  1.1180 + */
  1.1181 +static void
  1.1182 +sctp_asconf_addr_mgmt_ack(struct sctp_tcb *stcb, struct sctp_ifa *addr, uint32_t flag)
  1.1183 +{
  1.1184 +	/*
  1.1185 +	 * do the necessary asoc list work- if we get a failure indication,
  1.1186 +	 * leave the address on the assoc's restricted list.  If we get a
  1.1187 +	 * success indication, remove the address from the restricted list.
  1.1188 +	 */
  1.1189 +	/*
  1.1190 +	 * Note: this will only occur for ADD_IP_ADDRESS, since
  1.1191 +	 * DEL_IP_ADDRESS is never actually added to the list...
  1.1192 +	 */
  1.1193 +	if (flag) {
  1.1194 +		/* success case, so remove from the restricted list */
  1.1195 +		sctp_del_local_addr_restricted(stcb, addr);
  1.1196 +
  1.1197 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__)
  1.1198 +		if (sctp_is_mobility_feature_on(stcb->sctp_ep,
  1.1199 +						SCTP_MOBILITY_BASE) ||
  1.1200 +		    sctp_is_mobility_feature_on(stcb->sctp_ep,
  1.1201 +			    			SCTP_MOBILITY_FASTHANDOFF)) {
  1.1202 +			sctp_path_check_and_react(stcb, addr);
  1.1203 +			return;
  1.1204 +		}
  1.1205 +#endif /* __FreeBSD__ __APPLE__ __Userspace__ */
  1.1206 +		/* clear any cached/topologically incorrect source addresses */
  1.1207 +		sctp_asconf_nets_cleanup(stcb, addr->ifn_p);
  1.1208 +	}
  1.1209 +	/* else, leave it on the list */
  1.1210 +}
  1.1211 +
  1.1212 +/*
  1.1213 + * add an asconf add/delete/set primary IP address parameter to the queue.
  1.1214 + * type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR.
  1.1215 + * returns 0 if queued, -1 if not queued/removed.
  1.1216 + * NOTE: if adding, but a delete for the same address is already scheduled
  1.1217 + * (and not yet sent out), simply remove it from queue.  Same for deleting
  1.1218 + * an address already scheduled for add.  If a duplicate operation is found,
  1.1219 + * ignore the new one.
  1.1220 + */
  1.1221 +static int
  1.1222 +sctp_asconf_queue_mgmt(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
  1.1223 +		       uint16_t type)
  1.1224 +{
  1.1225 +	struct sctp_asconf_addr *aa, *aa_next;
  1.1226 +
  1.1227 +	/* make sure the request isn't already in the queue */
  1.1228 +	TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) {
  1.1229 +		/* address match? */
  1.1230 +		if (sctp_asconf_addr_match(aa, &ifa->address.sa) == 0)
  1.1231 +			continue;
  1.1232 +		/* is the request already in queue but not sent?
  1.1233 +		 * pass the request already sent in order to resolve the following case:
  1.1234 +		 *  1. arrival of ADD, then sent
  1.1235 +		 *  2. arrival of DEL. we can't remove the ADD request already sent
  1.1236 +		 *  3. arrival of ADD
  1.1237 +		 */
  1.1238 +		if (aa->ap.aph.ph.param_type == type && aa->sent == 0) {
  1.1239 +			return (-1);
  1.1240 +		}
  1.1241 +		/* is the negative request already in queue, and not sent */
  1.1242 +		if ((aa->sent == 0) && (type == SCTP_ADD_IP_ADDRESS) &&
  1.1243 +		    (aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS)) {
  1.1244 +			/* add requested, delete already queued */
  1.1245 +			TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
  1.1246 +			/* remove the ifa from the restricted list */
  1.1247 +			sctp_del_local_addr_restricted(stcb, ifa);
  1.1248 +			/* free the asconf param */
  1.1249 +			SCTP_FREE(aa, SCTP_M_ASC_ADDR);
  1.1250 +			SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_mgmt: add removes queued entry\n");
  1.1251 +			return (-1);
  1.1252 +		}
  1.1253 +		if ((aa->sent == 0) && (type == SCTP_DEL_IP_ADDRESS) &&
  1.1254 +		    (aa->ap.aph.ph.param_type == SCTP_ADD_IP_ADDRESS)) {
  1.1255 +			/* delete requested, add already queued */
  1.1256 +			TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
  1.1257 +			/* remove the aa->ifa from the restricted list */
  1.1258 +			sctp_del_local_addr_restricted(stcb, aa->ifa);
  1.1259 +			/* free the asconf param */
  1.1260 +			SCTP_FREE(aa, SCTP_M_ASC_ADDR);
  1.1261 +			SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_mgmt: delete removes queued entry\n");
  1.1262 +			return (-1);
  1.1263 +		}
  1.1264 +	} /* for each aa */
  1.1265 +
  1.1266 +	/* adding new request to the queue */
  1.1267 +	SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
  1.1268 +		    SCTP_M_ASC_ADDR);
  1.1269 +	if (aa == NULL) {
  1.1270 +		/* didn't get memory */
  1.1271 +		SCTPDBG(SCTP_DEBUG_ASCONF1, "asconf_queue_mgmt: failed to get memory!\n");
  1.1272 +		return (-1);
  1.1273 +	}
  1.1274 +	aa->special_del = 0;
  1.1275 +	/* fill in asconf address parameter fields */
  1.1276 +	/* top level elements are "networked" during send */
  1.1277 +	aa->ap.aph.ph.param_type = type;
  1.1278 +	aa->ifa = ifa;
  1.1279 +	atomic_add_int(&ifa->refcount, 1);
  1.1280 +	/* correlation_id filled in during send routine later... */
  1.1281 +	switch (ifa->address.sa.sa_family) {
  1.1282 +#ifdef INET6
  1.1283 +	case AF_INET6:
  1.1284 +	{
  1.1285 +		struct sockaddr_in6 *sin6;
  1.1286 +
  1.1287 +		sin6 = (struct sockaddr_in6 *)&ifa->address.sa;
  1.1288 +		aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
  1.1289 +		aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param));
  1.1290 +		aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) +
  1.1291 +		    sizeof(struct sctp_ipv6addr_param);
  1.1292 +		memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr,
  1.1293 +		       sizeof(struct in6_addr));
  1.1294 +		break;
  1.1295 +	}
  1.1296 +#endif
  1.1297 +#ifdef INET
  1.1298 +	case AF_INET:
  1.1299 +	{
  1.1300 +		struct sockaddr_in *sin;
  1.1301 +
  1.1302 +		sin= (struct sockaddr_in *)&ifa->address.sa;
  1.1303 +		aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
  1.1304 +		aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv4addr_param));
  1.1305 +		aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) +
  1.1306 +		    sizeof(struct sctp_ipv4addr_param);
  1.1307 +		memcpy(&aa->ap.addrp.addr, &sin->sin_addr,
  1.1308 +		       sizeof(struct in_addr));
  1.1309 +		break;
  1.1310 +	}
  1.1311 +#endif
  1.1312 +	default:
  1.1313 +		/* invalid family! */
  1.1314 +		SCTP_FREE(aa, SCTP_M_ASC_ADDR);
  1.1315 +		sctp_free_ifa(ifa);
  1.1316 +		return (-1);
  1.1317 +	}
  1.1318 +	aa->sent = 0;		/* clear sent flag */
  1.1319 +
  1.1320 +	TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
  1.1321 +#ifdef SCTP_DEBUG
  1.1322 +	if (SCTP_BASE_SYSCTL(sctp_debug_on) & SCTP_DEBUG_ASCONF2) {
  1.1323 +		if (type == SCTP_ADD_IP_ADDRESS) {
  1.1324 +			SCTP_PRINTF("asconf_queue_mgmt: inserted asconf ADD_IP_ADDRESS: ");
  1.1325 +			SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa);
  1.1326 +		} else if (type == SCTP_DEL_IP_ADDRESS) {
  1.1327 +			SCTP_PRINTF("asconf_queue_mgmt: appended asconf DEL_IP_ADDRESS: ");
  1.1328 +			SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa);
  1.1329 +		} else {
  1.1330 +			SCTP_PRINTF("asconf_queue_mgmt: appended asconf SET_PRIM_ADDR: ");
  1.1331 +			SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa);
  1.1332 +		}
  1.1333 +	}
  1.1334 +#endif
  1.1335 +
  1.1336 +	return (0);
  1.1337 +}
  1.1338 +
  1.1339 +
  1.1340 +/*
  1.1341 + * add an asconf operation for the given ifa and type.
  1.1342 + * type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR.
  1.1343 + * returns 0 if completed, -1 if not completed, 1 if immediate send is
  1.1344 + * advisable.
  1.1345 + */
  1.1346 +static int
  1.1347 +sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
  1.1348 +		      uint16_t type)
  1.1349 +{
  1.1350 +	uint32_t status;
  1.1351 +	int pending_delete_queued = 0;
  1.1352 +
  1.1353 +	/* see if peer supports ASCONF */
  1.1354 +	if (stcb->asoc.peer_supports_asconf == 0) {
  1.1355 +		return (-1);
  1.1356 +	}
  1.1357 +
  1.1358 +	/*
  1.1359 +	 * if this is deleting the last address from the assoc, mark it as
  1.1360 +	 * pending.
  1.1361 +	 */
  1.1362 +	if ((type == SCTP_DEL_IP_ADDRESS) && !stcb->asoc.asconf_del_pending &&
  1.1363 +	    (sctp_local_addr_count(stcb) < 2)) {
  1.1364 +		/* set the pending delete info only */
  1.1365 +		stcb->asoc.asconf_del_pending = 1;
  1.1366 +		stcb->asoc.asconf_addr_del_pending = ifa;
  1.1367 +		atomic_add_int(&ifa->refcount, 1);
  1.1368 +		SCTPDBG(SCTP_DEBUG_ASCONF2,
  1.1369 +			"asconf_queue_add: mark delete last address pending\n");
  1.1370 +		return (-1);
  1.1371 +	}
  1.1372 +
  1.1373 +	/* queue an asconf parameter */
  1.1374 +	status = sctp_asconf_queue_mgmt(stcb, ifa, type);
  1.1375 +
  1.1376 +	/*
  1.1377 +	 * if this is an add, and there is a delete also pending (i.e. the
  1.1378 +	 * last local address is being changed), queue the pending delete too.
  1.1379 +	 */
  1.1380 +	if ((type == SCTP_ADD_IP_ADDRESS) && stcb->asoc.asconf_del_pending && (status == 0)) {
  1.1381 +		/* queue in the pending delete */
  1.1382 +		if (sctp_asconf_queue_mgmt(stcb,
  1.1383 +					   stcb->asoc.asconf_addr_del_pending,
  1.1384 +					   SCTP_DEL_IP_ADDRESS) == 0) {
  1.1385 +			SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_add: queing pending delete\n");
  1.1386 +			pending_delete_queued = 1;
  1.1387 +			/* clear out the pending delete info */
  1.1388 +			stcb->asoc.asconf_del_pending = 0;
  1.1389 +			sctp_free_ifa(stcb->asoc.asconf_addr_del_pending);
  1.1390 +			stcb->asoc.asconf_addr_del_pending = NULL;
  1.1391 +		}
  1.1392 +	}
  1.1393 +
  1.1394 +	if (pending_delete_queued) {
  1.1395 +		struct sctp_nets *net;
  1.1396 +		/*
  1.1397 +		 * since we know that the only/last address is now being
  1.1398 +		 * changed in this case, reset the cwnd/rto on all nets to
  1.1399 +		 * start as a new address and path.  Also clear the error
  1.1400 +		 * counts to give the assoc the best chance to complete the
  1.1401 +		 * address change.
  1.1402 +		 */
  1.1403 +		TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1.1404 +			stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb,
  1.1405 +									  net);
  1.1406 +			net->RTO = 0;
  1.1407 +			net->error_count = 0;
  1.1408 +		}
  1.1409 +		stcb->asoc.overall_error_count = 0;
  1.1410 +		if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
  1.1411 +			sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
  1.1412 +				       stcb->asoc.overall_error_count,
  1.1413 +				       0,
  1.1414 +				       SCTP_FROM_SCTP_ASCONF,
  1.1415 +				       __LINE__);
  1.1416 +		}
  1.1417 +
  1.1418 +		/* queue in an advisory set primary too */
  1.1419 +		(void)sctp_asconf_queue_mgmt(stcb, ifa, SCTP_SET_PRIM_ADDR);
  1.1420 +		/* let caller know we should send this out immediately */
  1.1421 +		status = 1;
  1.1422 +	}
  1.1423 +	return (status);
  1.1424 +}
  1.1425 +
  1.1426 +/*-
  1.1427 + * add an asconf delete IP address parameter to the queue by sockaddr and
  1.1428 + * possibly with no sctp_ifa available.  This is only called by the routine
  1.1429 + * that checks the addresses in an INIT-ACK against the current address list.
  1.1430 + * returns 0 if completed, non-zero if not completed.
  1.1431 + * NOTE: if an add is already scheduled (and not yet sent out), simply
  1.1432 + * remove it from queue.  If a duplicate operation is found, ignore the
  1.1433 + * new one.
  1.1434 + */
  1.1435 +static int
  1.1436 +sctp_asconf_queue_sa_delete(struct sctp_tcb *stcb, struct sockaddr *sa)
  1.1437 +{
  1.1438 +	struct sctp_ifa *ifa;
  1.1439 +	struct sctp_asconf_addr *aa, *aa_next;
  1.1440 +	uint32_t vrf_id;
  1.1441 +
  1.1442 +	if (stcb == NULL) {
  1.1443 +		return (-1);
  1.1444 +	}
  1.1445 +	/* see if peer supports ASCONF */
  1.1446 +	if (stcb->asoc.peer_supports_asconf == 0) {
  1.1447 +		return (-1);
  1.1448 +	}
  1.1449 +	/* make sure the request isn't already in the queue */
  1.1450 +	TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) {
  1.1451 +		/* address match? */
  1.1452 +		if (sctp_asconf_addr_match(aa, sa) == 0)
  1.1453 +			continue;
  1.1454 +		/* is the request already in queue (sent or not) */
  1.1455 +		if (aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS) {
  1.1456 +			return (-1);
  1.1457 +		}
  1.1458 +		/* is the negative request already in queue, and not sent */
  1.1459 +		if (aa->sent == 1)
  1.1460 +			continue;
  1.1461 +		if (aa->ap.aph.ph.param_type == SCTP_ADD_IP_ADDRESS) {
  1.1462 +			/* add already queued, so remove existing entry */
  1.1463 +			TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
  1.1464 +			sctp_del_local_addr_restricted(stcb, aa->ifa);
  1.1465 +			/* free the entry */
  1.1466 +			SCTP_FREE(aa, SCTP_M_ASC_ADDR);
  1.1467 +			return (-1);
  1.1468 +		}
  1.1469 +	} /* for each aa */
  1.1470 +
  1.1471 +	/* find any existing ifa-- NOTE ifa CAN be allowed to be NULL */
  1.1472 +	if (stcb) {
  1.1473 +		vrf_id = stcb->asoc.vrf_id;
  1.1474 +	} else {
  1.1475 +		vrf_id = SCTP_DEFAULT_VRFID;
  1.1476 +	}
  1.1477 +	ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED);
  1.1478 +
  1.1479 +	/* adding new request to the queue */
  1.1480 +	SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
  1.1481 +		    SCTP_M_ASC_ADDR);
  1.1482 +	if (aa == NULL) {
  1.1483 +		/* didn't get memory */
  1.1484 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
  1.1485 +			"sctp_asconf_queue_sa_delete: failed to get memory!\n");
  1.1486 +		return (-1);
  1.1487 +	}
  1.1488 +	aa->special_del = 0;
  1.1489 +	/* fill in asconf address parameter fields */
  1.1490 +	/* top level elements are "networked" during send */
  1.1491 +	aa->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS;
  1.1492 +	aa->ifa = ifa;
  1.1493 +	if (ifa)
  1.1494 +		atomic_add_int(&ifa->refcount, 1);
  1.1495 +	/* correlation_id filled in during send routine later... */
  1.1496 +	switch (sa->sa_family) {
  1.1497 +#ifdef INET6
  1.1498 +	case AF_INET6:
  1.1499 +	{
  1.1500 +		/* IPv6 address */
  1.1501 +		struct sockaddr_in6 *sin6;
  1.1502 +
  1.1503 +		sin6 = (struct sockaddr_in6 *)sa;
  1.1504 +		aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
  1.1505 +		aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param));
  1.1506 +		aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_ipv6addr_param);
  1.1507 +		memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr,
  1.1508 +		    sizeof(struct in6_addr));
  1.1509 +		break;
  1.1510 +	}
  1.1511 +#endif
  1.1512 +#ifdef INET
  1.1513 +	case AF_INET:
  1.1514 +	{
  1.1515 +		/* IPv4 address */
  1.1516 +		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
  1.1517 +
  1.1518 +		aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
  1.1519 +		aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv4addr_param));
  1.1520 +		aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_ipv4addr_param);
  1.1521 +		memcpy(&aa->ap.addrp.addr, &sin->sin_addr,
  1.1522 +		    sizeof(struct in_addr));
  1.1523 +		break;
  1.1524 +	}
  1.1525 +#endif
  1.1526 +	default:
  1.1527 +		/* invalid family! */
  1.1528 +		SCTP_FREE(aa, SCTP_M_ASC_ADDR);
  1.1529 +		if (ifa)
  1.1530 +			sctp_free_ifa(ifa);
  1.1531 +		return (-1);
  1.1532 +	}
  1.1533 +	aa->sent = 0;		/* clear sent flag */
  1.1534 +
  1.1535 +	/* delete goes to the back of the queue */
  1.1536 +	TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
  1.1537 +
  1.1538 +	/* sa_ignore MEMLEAK {memory is put on the tailq} */
  1.1539 +	return (0);
  1.1540 +}
  1.1541 +
  1.1542 +/*
  1.1543 + * find a specific asconf param on our "sent" queue
  1.1544 + */
  1.1545 +static struct sctp_asconf_addr *
  1.1546 +sctp_asconf_find_param(struct sctp_tcb *stcb, uint32_t correlation_id)
  1.1547 +{
  1.1548 +	struct sctp_asconf_addr *aa;
  1.1549 +
  1.1550 +	TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) {
  1.1551 +		if (aa->ap.aph.correlation_id == correlation_id &&
  1.1552 +		    aa->sent == 1) {
  1.1553 +			/* found it */
  1.1554 +			return (aa);
  1.1555 +		}
  1.1556 +	}
  1.1557 +	/* didn't find it */
  1.1558 +	return (NULL);
  1.1559 +}
  1.1560 +
  1.1561 +/*
  1.1562 + * process an SCTP_ERROR_CAUSE_IND for a ASCONF-ACK parameter and do
  1.1563 + * notifications based on the error response
  1.1564 + */
  1.1565 +static void
  1.1566 +sctp_asconf_process_error(struct sctp_tcb *stcb,
  1.1567 +			  struct sctp_asconf_paramhdr *aph)
  1.1568 +{
  1.1569 +	struct sctp_error_cause *eh;
  1.1570 +	struct sctp_paramhdr *ph;
  1.1571 +	uint16_t param_type;
  1.1572 +	uint16_t error_code;
  1.1573 +
  1.1574 +	eh = (struct sctp_error_cause *)(aph + 1);
  1.1575 +	ph = (struct sctp_paramhdr *)(eh + 1);
  1.1576 +	/* validate lengths */
  1.1577 +	if (htons(eh->length) + sizeof(struct sctp_error_cause) >
  1.1578 +	    htons(aph->ph.param_length)) {
  1.1579 +		/* invalid error cause length */
  1.1580 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
  1.1581 +			"asconf_process_error: cause element too long\n");
  1.1582 +		return;
  1.1583 +	}
  1.1584 +	if (htons(ph->param_length) + sizeof(struct sctp_paramhdr) >
  1.1585 +	    htons(eh->length)) {
  1.1586 +		/* invalid included TLV length */
  1.1587 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
  1.1588 +			"asconf_process_error: included TLV too long\n");
  1.1589 +		return;
  1.1590 +	}
  1.1591 +	/* which error code ? */
  1.1592 +	error_code = ntohs(eh->code);
  1.1593 +	param_type = ntohs(aph->ph.param_type);
  1.1594 +	/* FIX: this should go back up the REMOTE_ERROR ULP notify */
  1.1595 +	switch (error_code) {
  1.1596 +	case SCTP_CAUSE_RESOURCE_SHORTAGE:
  1.1597 +		/* we allow ourselves to "try again" for this error */
  1.1598 +		break;
  1.1599 +	default:
  1.1600 +		/* peer can't handle it... */
  1.1601 +		switch (param_type) {
  1.1602 +		case SCTP_ADD_IP_ADDRESS:
  1.1603 +		case SCTP_DEL_IP_ADDRESS:
  1.1604 +			stcb->asoc.peer_supports_asconf = 0;
  1.1605 +			break;
  1.1606 +		case SCTP_SET_PRIM_ADDR:
  1.1607 +			stcb->asoc.peer_supports_asconf = 0;
  1.1608 +			break;
  1.1609 +		default:
  1.1610 +			break;
  1.1611 +		}
  1.1612 +	}
  1.1613 +}
  1.1614 +
  1.1615 +/*
  1.1616 + * process an asconf queue param.
  1.1617 + * aparam: parameter to process, will be removed from the queue.
  1.1618 + * flag: 1=success case, 0=failure case
  1.1619 + */
  1.1620 +static void
  1.1621 +sctp_asconf_process_param_ack(struct sctp_tcb *stcb,
  1.1622 +			      struct sctp_asconf_addr *aparam, uint32_t flag)
  1.1623 +{
  1.1624 +	uint16_t param_type;
  1.1625 +
  1.1626 +	/* process this param */
  1.1627 +	param_type = aparam->ap.aph.ph.param_type;
  1.1628 +	switch (param_type) {
  1.1629 +	case SCTP_ADD_IP_ADDRESS:
  1.1630 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
  1.1631 +			"process_param_ack: added IP address\n");
  1.1632 +		sctp_asconf_addr_mgmt_ack(stcb, aparam->ifa, flag);
  1.1633 +		break;
  1.1634 +	case SCTP_DEL_IP_ADDRESS:
  1.1635 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
  1.1636 +			"process_param_ack: deleted IP address\n");
  1.1637 +		/* nothing really to do... lists already updated */
  1.1638 +		break;
  1.1639 +	case SCTP_SET_PRIM_ADDR:
  1.1640 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
  1.1641 +			"process_param_ack: set primary IP address\n");
  1.1642 +		/* nothing to do... peer may start using this addr */
  1.1643 +		if (flag == 0)
  1.1644 +			stcb->asoc.peer_supports_asconf = 0;
  1.1645 +		break;
  1.1646 +	default:
  1.1647 +		/* should NEVER happen */
  1.1648 +		break;
  1.1649 +	}
  1.1650 +
  1.1651 +	/* remove the param and free it */
  1.1652 +	TAILQ_REMOVE(&stcb->asoc.asconf_queue, aparam, next);
  1.1653 +	if (aparam->ifa)
  1.1654 +		sctp_free_ifa(aparam->ifa);
  1.1655 +	SCTP_FREE(aparam, SCTP_M_ASC_ADDR);
  1.1656 +}
  1.1657 +
  1.1658 +/*
  1.1659 + * cleanup from a bad asconf ack parameter
  1.1660 + */
  1.1661 +static void
  1.1662 +sctp_asconf_ack_clear(struct sctp_tcb *stcb)
  1.1663 +{
  1.1664 +	/* assume peer doesn't really know how to do asconfs */
  1.1665 +	stcb->asoc.peer_supports_asconf = 0;
  1.1666 +	/* XXX we could free the pending queue here */
  1.1667 +}
  1.1668 +
  1.1669 +void
  1.1670 +sctp_handle_asconf_ack(struct mbuf *m, int offset,
  1.1671 +		       struct sctp_asconf_ack_chunk *cp, struct sctp_tcb *stcb,
  1.1672 +		       struct sctp_nets *net, int *abort_no_unlock)
  1.1673 +{
  1.1674 +	struct sctp_association *asoc;
  1.1675 +	uint32_t serial_num;
  1.1676 +	uint16_t ack_length;
  1.1677 +	struct sctp_asconf_paramhdr *aph;
  1.1678 +	struct sctp_asconf_addr *aa, *aa_next;
  1.1679 +	uint32_t last_error_id = 0;	/* last error correlation id */
  1.1680 +	uint32_t id;
  1.1681 +	struct sctp_asconf_addr *ap;
  1.1682 +
  1.1683 +	/* asconf param buffer */
  1.1684 +	uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE];
  1.1685 +
  1.1686 +	/* verify minimum length */
  1.1687 +	if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_asconf_ack_chunk)) {
  1.1688 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
  1.1689 +			"handle_asconf_ack: chunk too small = %xh\n",
  1.1690 +			ntohs(cp->ch.chunk_length));
  1.1691 +		return;
  1.1692 +	}
  1.1693 +	asoc = &stcb->asoc;
  1.1694 +	serial_num = ntohl(cp->serial_number);
  1.1695 +
  1.1696 +	/*
  1.1697 +	 * NOTE: we may want to handle this differently- currently, we will
  1.1698 +	 * abort when we get an ack for the expected serial number + 1 (eg.
  1.1699 +	 * we didn't send it), process an ack normally if it is the expected
  1.1700 +	 * serial number, and re-send the previous ack for *ALL* other
  1.1701 +	 * serial numbers
  1.1702 +	 */
  1.1703 +
  1.1704 +	/*
  1.1705 +	 * if the serial number is the next expected, but I didn't send it,
  1.1706 +	 * abort the asoc, since someone probably just hijacked us...
  1.1707 +	 */
  1.1708 +	if (serial_num == (asoc->asconf_seq_out + 1)) {
  1.1709 +		SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf_ack: got unexpected next serial number! Aborting asoc!\n");
  1.1710 +		sctp_abort_an_association(stcb->sctp_ep, stcb, NULL, SCTP_SO_NOT_LOCKED);
  1.1711 +		*abort_no_unlock = 1;
  1.1712 +		return;
  1.1713 +	}
  1.1714 +	if (serial_num != asoc->asconf_seq_out_acked + 1) {
  1.1715 +		/* got a duplicate/unexpected ASCONF-ACK */
  1.1716 +		SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf_ack: got duplicate/unexpected serial number = %xh (expected = %xh)\n",
  1.1717 +			serial_num, asoc->asconf_seq_out_acked + 1);
  1.1718 +		return;
  1.1719 +	}
  1.1720 +
  1.1721 +	if (serial_num == asoc->asconf_seq_out - 1) {
  1.1722 +		/* stop our timer */
  1.1723 +		sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net,
  1.1724 +				SCTP_FROM_SCTP_ASCONF+SCTP_LOC_3);
  1.1725 +	}
  1.1726 +
  1.1727 +	/* process the ASCONF-ACK contents */
  1.1728 +	ack_length = ntohs(cp->ch.chunk_length) -
  1.1729 +	    sizeof(struct sctp_asconf_ack_chunk);
  1.1730 +	offset += sizeof(struct sctp_asconf_ack_chunk);
  1.1731 +	/* process through all parameters */
  1.1732 +	while (ack_length >= sizeof(struct sctp_asconf_paramhdr)) {
  1.1733 +		unsigned int param_length, param_type;
  1.1734 +
  1.1735 +		/* get pointer to next asconf parameter */
  1.1736 +		aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset,
  1.1737 +		    sizeof(struct sctp_asconf_paramhdr), aparam_buf);
  1.1738 +		if (aph == NULL) {
  1.1739 +			/* can't get an asconf paramhdr */
  1.1740 +			sctp_asconf_ack_clear(stcb);
  1.1741 +			return;
  1.1742 +		}
  1.1743 +		param_type = ntohs(aph->ph.param_type);
  1.1744 +		param_length = ntohs(aph->ph.param_length);
  1.1745 +		if (param_length > ack_length) {
  1.1746 +			sctp_asconf_ack_clear(stcb);
  1.1747 +			return;
  1.1748 +		}
  1.1749 +		if (param_length < sizeof(struct sctp_paramhdr)) {
  1.1750 +			sctp_asconf_ack_clear(stcb);
  1.1751 +			return;
  1.1752 +		}
  1.1753 +		/* get the complete parameter... */
  1.1754 +		if (param_length > sizeof(aparam_buf)) {
  1.1755 +			SCTPDBG(SCTP_DEBUG_ASCONF1,
  1.1756 +				"param length (%u) larger than buffer size!\n", param_length);
  1.1757 +			sctp_asconf_ack_clear(stcb);
  1.1758 +			return;
  1.1759 +		}
  1.1760 +		aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, param_length, aparam_buf);
  1.1761 +		if (aph == NULL) {
  1.1762 +			sctp_asconf_ack_clear(stcb);
  1.1763 +			return;
  1.1764 +		}
  1.1765 +		/* correlation_id is transparent to peer, no ntohl needed */
  1.1766 +		id = aph->correlation_id;
  1.1767 +
  1.1768 +		switch (param_type) {
  1.1769 +		case SCTP_ERROR_CAUSE_IND:
  1.1770 +			last_error_id = id;
  1.1771 +			/* find the corresponding asconf param in our queue */
  1.1772 +			ap = sctp_asconf_find_param(stcb, id);
  1.1773 +			if (ap == NULL) {
  1.1774 +				/* hmm... can't find this in our queue! */
  1.1775 +				break;
  1.1776 +			}
  1.1777 +			/* process the parameter, failed flag */
  1.1778 +			sctp_asconf_process_param_ack(stcb, ap, 0);
  1.1779 +			/* process the error response */
  1.1780 +			sctp_asconf_process_error(stcb, aph);
  1.1781 +			break;
  1.1782 +		case SCTP_SUCCESS_REPORT:
  1.1783 +			/* find the corresponding asconf param in our queue */
  1.1784 +			ap = sctp_asconf_find_param(stcb, id);
  1.1785 +			if (ap == NULL) {
  1.1786 +				/* hmm... can't find this in our queue! */
  1.1787 +				break;
  1.1788 +			}
  1.1789 +			/* process the parameter, success flag */
  1.1790 +			sctp_asconf_process_param_ack(stcb, ap, 1);
  1.1791 +			break;
  1.1792 +		default:
  1.1793 +			break;
  1.1794 +		}		/* switch */
  1.1795 +
  1.1796 +		/* update remaining ASCONF-ACK message length to process */
  1.1797 +		ack_length -= SCTP_SIZE32(param_length);
  1.1798 +		if (ack_length <= 0) {
  1.1799 +			/* no more data in the mbuf chain */
  1.1800 +			break;
  1.1801 +		}
  1.1802 +		offset += SCTP_SIZE32(param_length);
  1.1803 +	} /* while */
  1.1804 +
  1.1805 +	/*
  1.1806 +	 * if there are any "sent" params still on the queue, these are
  1.1807 +	 * implicitly "success", or "failed" (if we got an error back) ...
  1.1808 +	 * so process these appropriately
  1.1809 +	 *
  1.1810 +	 * we assume that the correlation_id's are monotonically increasing
  1.1811 +	 * beginning from 1 and that we don't have *that* many outstanding
  1.1812 +	 * at any given time
  1.1813 +	 */
  1.1814 +	if (last_error_id == 0)
  1.1815 +		last_error_id--;	/* set to "max" value */
  1.1816 +	TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) {
  1.1817 +		if (aa->sent == 1) {
  1.1818 +			/*
  1.1819 +			 * implicitly successful or failed if correlation_id
  1.1820 +			 * < last_error_id, then success else, failure
  1.1821 +			 */
  1.1822 +			if (aa->ap.aph.correlation_id < last_error_id)
  1.1823 +				sctp_asconf_process_param_ack(stcb, aa, 1);
  1.1824 +			else
  1.1825 +				sctp_asconf_process_param_ack(stcb, aa, 0);
  1.1826 +		} else {
  1.1827 +			/*
  1.1828 +			 * since we always process in order (FIFO queue) if
  1.1829 +			 * we reach one that hasn't been sent, the rest
  1.1830 +			 * should not have been sent either. so, we're
  1.1831 +			 * done...
  1.1832 +			 */
  1.1833 +			break;
  1.1834 +		}
  1.1835 +	}
  1.1836 +
  1.1837 +	/* update the next sequence number to use */
  1.1838 +	asoc->asconf_seq_out_acked++;
  1.1839 +	/* remove the old ASCONF on our outbound queue */
  1.1840 +	sctp_toss_old_asconf(stcb);
  1.1841 +	if (!TAILQ_EMPTY(&stcb->asoc.asconf_queue)) {
  1.1842 +#ifdef SCTP_TIMER_BASED_ASCONF
  1.1843 +		/* we have more params, so restart our timer */
  1.1844 +		sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep,
  1.1845 +				 stcb, net);
  1.1846 +#else
  1.1847 +		/* we have more params, so send out more */
  1.1848 +		sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED);
  1.1849 +#endif
  1.1850 +	}
  1.1851 +}
  1.1852 +
  1.1853 +#ifdef INET6
  1.1854 +static uint32_t
  1.1855 +sctp_is_scopeid_in_nets(struct sctp_tcb *stcb, struct sockaddr *sa)
  1.1856 +{
  1.1857 +	struct sockaddr_in6 *sin6, *net6;
  1.1858 +	struct sctp_nets *net;
  1.1859 +
  1.1860 +	if (sa->sa_family != AF_INET6) {
  1.1861 +		/* wrong family */
  1.1862 +		return (0);
  1.1863 +	}
  1.1864 +	sin6 = (struct sockaddr_in6 *)sa;
  1.1865 +	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) == 0) {
  1.1866 +		/* not link local address */
  1.1867 +		return (0);
  1.1868 +	}
  1.1869 +	/* hunt through our destination nets list for this scope_id */
  1.1870 +	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1.1871 +		if (((struct sockaddr *)(&net->ro._l_addr))->sa_family !=
  1.1872 +		    AF_INET6)
  1.1873 +			continue;
  1.1874 +		net6 = (struct sockaddr_in6 *)&net->ro._l_addr;
  1.1875 +		if (IN6_IS_ADDR_LINKLOCAL(&net6->sin6_addr) == 0)
  1.1876 +			continue;
  1.1877 +		if (sctp_is_same_scope(sin6, net6)) {
  1.1878 +			/* found one */
  1.1879 +			return (1);
  1.1880 +		}
  1.1881 +	}
  1.1882 +	/* didn't find one */
  1.1883 +	return (0);
  1.1884 +}
  1.1885 +#endif
  1.1886 +
  1.1887 +/*
  1.1888 + * address management functions
  1.1889 + */
  1.1890 +static void
  1.1891 +sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
  1.1892 +		     struct sctp_ifa *ifa, uint16_t type, int addr_locked)
  1.1893 +{
  1.1894 +	int status;
  1.1895 +
  1.1896 +	if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0 ||
  1.1897 +	    sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
  1.1898 +		/* subset bound, no ASCONF allowed case, so ignore */
  1.1899 +		return;
  1.1900 +	}
  1.1901 +	/*
  1.1902 +	 * note: we know this is not the subset bound, no ASCONF case eg.
  1.1903 +	 * this is boundall or subset bound w/ASCONF allowed
  1.1904 +	 */
  1.1905 +
  1.1906 +	/* first, make sure it's a good address family */
  1.1907 +	switch (ifa->address.sa.sa_family) {
  1.1908 +#ifdef INET6
  1.1909 +	case AF_INET6:
  1.1910 +		break;
  1.1911 +#endif
  1.1912 +#ifdef INET
  1.1913 +	case AF_INET:
  1.1914 +		break;
  1.1915 +#endif
  1.1916 +	default:
  1.1917 +		return;
  1.1918 +	}
  1.1919 +#ifdef INET6
  1.1920 +	/* make sure we're "allowed" to add this type of addr */
  1.1921 +	if (ifa->address.sa.sa_family == AF_INET6) {
  1.1922 +		/* invalid if we're not a v6 endpoint */
  1.1923 +		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0)
  1.1924 +			return;
  1.1925 +		/* is the v6 addr really valid ? */
  1.1926 +		if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
  1.1927 +			return;
  1.1928 +		}
  1.1929 +	}
  1.1930 +#endif
  1.1931 +	/* put this address on the "pending/do not use yet" list */
  1.1932 +	sctp_add_local_addr_restricted(stcb, ifa);
  1.1933 +	/*
  1.1934 +	 * check address scope if address is out of scope, don't queue
  1.1935 +	 * anything... note: this would leave the address on both inp and
  1.1936 +	 * asoc lists
  1.1937 +	 */
  1.1938 +	switch (ifa->address.sa.sa_family) {
  1.1939 +#ifdef INET6
  1.1940 +	case AF_INET6:
  1.1941 +	{
  1.1942 +		struct sockaddr_in6 *sin6;
  1.1943 +
  1.1944 +		sin6 = (struct sockaddr_in6 *)&ifa->address.sin6;
  1.1945 +		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
  1.1946 +			/* we skip unspecifed addresses */
  1.1947 +			return;
  1.1948 +		}
  1.1949 +		if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
  1.1950 +			if (stcb->asoc.scope.local_scope == 0) {
  1.1951 +				return;
  1.1952 +			}
  1.1953 +			/* is it the right link local scope? */
  1.1954 +			if (sctp_is_scopeid_in_nets(stcb, &ifa->address.sa) == 0) {
  1.1955 +				return;
  1.1956 +			}
  1.1957 +		}
  1.1958 +		if (stcb->asoc.scope.site_scope == 0 &&
  1.1959 +		    IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
  1.1960 +			return;
  1.1961 +		}
  1.1962 +		break;
  1.1963 +	}
  1.1964 +#endif
  1.1965 +#ifdef INET
  1.1966 +	case AF_INET:
  1.1967 +	{
  1.1968 +		struct sockaddr_in *sin;
  1.1969 +		struct in6pcb *inp6;
  1.1970 +
  1.1971 +		inp6 = (struct in6pcb *)&inp->ip_inp.inp;
  1.1972 +		/* invalid if we are a v6 only endpoint */
  1.1973 +		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
  1.1974 +		    SCTP_IPV6_V6ONLY(inp6))
  1.1975 +			return;
  1.1976 +
  1.1977 +		sin = (struct sockaddr_in *)&ifa->address.sa;
  1.1978 +		if (sin->sin_addr.s_addr == 0) {
  1.1979 +			/* we skip unspecifed addresses */
  1.1980 +			return;
  1.1981 +		}
  1.1982 +		if (stcb->asoc.scope.ipv4_local_scope == 0 &&
  1.1983 +		    IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) {
  1.1984 +			return;
  1.1985 +		}
  1.1986 +		break;
  1.1987 +	}
  1.1988 +#endif
  1.1989 +	default:
  1.1990 +		/* else, not AF_INET or AF_INET6, so skip */
  1.1991 +		return;
  1.1992 +	}
  1.1993 +
  1.1994 +	/* queue an asconf for this address add/delete */
  1.1995 +	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
  1.1996 +		/* does the peer do asconf? */
  1.1997 +		if (stcb->asoc.peer_supports_asconf) {
  1.1998 +			/* queue an asconf for this addr */
  1.1999 +			status = sctp_asconf_queue_add(stcb, ifa, type);
  1.2000 +
  1.2001 +			/*
  1.2002 +			 * if queued ok, and in the open state, send out the
  1.2003 +			 * ASCONF.  If in the non-open state, these will be
  1.2004 +			 * sent when the state goes open.
  1.2005 +			 */
  1.2006 +			if (status == 0 &&
  1.2007 +			    SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
  1.2008 +#ifdef SCTP_TIMER_BASED_ASCONF
  1.2009 +				sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp,
  1.2010 +				    stcb, stcb->asoc.primary_destination);
  1.2011 +#else
  1.2012 +				sctp_send_asconf(stcb, NULL, addr_locked);
  1.2013 +#endif
  1.2014 +			}
  1.2015 +		}
  1.2016 +	}
  1.2017 +}
  1.2018 +
  1.2019 +
  1.2020 +int
  1.2021 +sctp_asconf_iterator_ep(struct sctp_inpcb *inp, void *ptr, uint32_t val SCTP_UNUSED)
  1.2022 +{
  1.2023 +	struct sctp_asconf_iterator *asc;
  1.2024 +	struct sctp_ifa *ifa;
  1.2025 +	struct sctp_laddr *l;
  1.2026 +	int cnt_invalid = 0;
  1.2027 +
  1.2028 +	asc = (struct sctp_asconf_iterator *)ptr;
  1.2029 +	LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) {
  1.2030 +		ifa = l->ifa;
  1.2031 +		switch (ifa->address.sa.sa_family) {
  1.2032 +#ifdef INET6
  1.2033 +		case AF_INET6:
  1.2034 +			/* invalid if we're not a v6 endpoint */
  1.2035 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
  1.2036 +				cnt_invalid++;
  1.2037 +				if (asc->cnt == cnt_invalid)
  1.2038 +					return (1);
  1.2039 +			}
  1.2040 +			break;
  1.2041 +#endif
  1.2042 +#ifdef INET
  1.2043 +		case AF_INET:
  1.2044 +		{
  1.2045 +			/* invalid if we are a v6 only endpoint */
  1.2046 +			struct in6pcb *inp6;
  1.2047 +			inp6 = (struct in6pcb *)&inp->ip_inp.inp;
  1.2048 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
  1.2049 +			    SCTP_IPV6_V6ONLY(inp6)) {
  1.2050 +				cnt_invalid++;
  1.2051 +				if (asc->cnt == cnt_invalid)
  1.2052 +					return (1);
  1.2053 +			}
  1.2054 +			break;
  1.2055 +		}
  1.2056 +#endif
  1.2057 +		default:
  1.2058 +			/* invalid address family */
  1.2059 +			cnt_invalid++;
  1.2060 +			if (asc->cnt == cnt_invalid)
  1.2061 +				return (1);
  1.2062 +		}
  1.2063 +	}
  1.2064 +	return (0);
  1.2065 +}
  1.2066 +
  1.2067 +static int
  1.2068 +sctp_asconf_iterator_ep_end(struct sctp_inpcb *inp, void *ptr, uint32_t val SCTP_UNUSED)
  1.2069 +{
  1.2070 +	struct sctp_ifa *ifa;
  1.2071 +	struct sctp_asconf_iterator *asc;
  1.2072 +	struct sctp_laddr *laddr, *nladdr, *l;
  1.2073 +
  1.2074 +	/* Only for specific case not bound all */
  1.2075 +	asc = (struct sctp_asconf_iterator *)ptr;
  1.2076 +	LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) {
  1.2077 +		ifa = l->ifa;
  1.2078 +		if (l->action == SCTP_ADD_IP_ADDRESS) {
  1.2079 +			LIST_FOREACH(laddr, &inp->sctp_addr_list,
  1.2080 +				     sctp_nxt_addr) {
  1.2081 +				if (laddr->ifa == ifa) {
  1.2082 +					laddr->action = 0;
  1.2083 +					break;
  1.2084 +				}
  1.2085 +
  1.2086 +			}
  1.2087 +		} else if (l->action == SCTP_DEL_IP_ADDRESS) {
  1.2088 +			LIST_FOREACH_SAFE(laddr, &inp->sctp_addr_list, sctp_nxt_addr, nladdr) {
  1.2089 +				/* remove only after all guys are done */
  1.2090 +				if (laddr->ifa == ifa) {
  1.2091 +					sctp_del_local_addr_ep(inp, ifa);
  1.2092 +				}
  1.2093 +			}
  1.2094 +		}
  1.2095 +	}
  1.2096 +	return (0);
  1.2097 +}
  1.2098 +
  1.2099 +void
  1.2100 +sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
  1.2101 +			  void *ptr, uint32_t val SCTP_UNUSED)
  1.2102 +{
  1.2103 +	struct sctp_asconf_iterator *asc;
  1.2104 +	struct sctp_ifa *ifa;
  1.2105 +	struct sctp_laddr *l;
  1.2106 +	int cnt_invalid = 0;
  1.2107 +	int type, status;
  1.2108 +	int num_queued = 0;
  1.2109 +
  1.2110 +	asc = (struct sctp_asconf_iterator *)ptr;
  1.2111 +	LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) {
  1.2112 +		ifa = l->ifa;
  1.2113 +		type = l->action;
  1.2114 +
  1.2115 +		/* address's vrf_id must be the vrf_id of the assoc */
  1.2116 +		if (ifa->vrf_id != stcb->asoc.vrf_id) {
  1.2117 +			continue;
  1.2118 +		}
  1.2119 +
  1.2120 +		/* Same checks again for assoc */
  1.2121 +		switch (ifa->address.sa.sa_family) {
  1.2122 +#ifdef INET6
  1.2123 +		case AF_INET6:
  1.2124 +		{
  1.2125 +			/* invalid if we're not a v6 endpoint */
  1.2126 +			struct sockaddr_in6 *sin6;
  1.2127 +
  1.2128 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
  1.2129 +				cnt_invalid++;
  1.2130 +				if (asc->cnt == cnt_invalid)
  1.2131 +					return;
  1.2132 +				else
  1.2133 +					continue;
  1.2134 +			}
  1.2135 +			sin6 = (struct sockaddr_in6 *)&ifa->address.sin6;
  1.2136 +			if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
  1.2137 +				/* we skip unspecifed addresses */
  1.2138 +				continue;
  1.2139 +			}
  1.2140 +			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
  1.2141 +				if (stcb->asoc.scope.local_scope == 0) {
  1.2142 +					continue;
  1.2143 +				}
  1.2144 +				/* is it the right link local scope? */
  1.2145 +				if (sctp_is_scopeid_in_nets(stcb, &ifa->address.sa) == 0) {
  1.2146 +					continue;
  1.2147 +				}
  1.2148 +			}
  1.2149 +			break;
  1.2150 +		}
  1.2151 +#endif
  1.2152 +#ifdef INET
  1.2153 +		case AF_INET:
  1.2154 +		{
  1.2155 +			/* invalid if we are a v6 only endpoint */
  1.2156 +			struct in6pcb *inp6;
  1.2157 +			struct sockaddr_in *sin;
  1.2158 +
  1.2159 +			inp6 = (struct in6pcb *)&inp->ip_inp.inp;
  1.2160 +			/* invalid if we are a v6 only endpoint */
  1.2161 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
  1.2162 +			    SCTP_IPV6_V6ONLY(inp6))
  1.2163 +				continue;
  1.2164 +
  1.2165 +			sin = (struct sockaddr_in *)&ifa->address.sa;
  1.2166 +			if (sin->sin_addr.s_addr == 0) {
  1.2167 +				/* we skip unspecifed addresses */
  1.2168 +				continue;
  1.2169 +			}
  1.2170 +			if (stcb->asoc.scope.ipv4_local_scope == 0 &&
  1.2171 +			    IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) {
  1.2172 +				continue;
  1.2173 +			}
  1.2174 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
  1.2175 +			    SCTP_IPV6_V6ONLY(inp6)) {
  1.2176 +				cnt_invalid++;
  1.2177 +				if (asc->cnt == cnt_invalid)
  1.2178 +					return;
  1.2179 +				else
  1.2180 +					continue;
  1.2181 +			}
  1.2182 +			break;
  1.2183 +		}
  1.2184 +#endif
  1.2185 +		default:
  1.2186 +			/* invalid address family */
  1.2187 +			cnt_invalid++;
  1.2188 +			if (asc->cnt == cnt_invalid)
  1.2189 +				return;
  1.2190 +			else
  1.2191 +				continue;
  1.2192 +			break;
  1.2193 +		}
  1.2194 +
  1.2195 +		if (type == SCTP_ADD_IP_ADDRESS) {
  1.2196 +			/* prevent this address from being used as a source */
  1.2197 +			sctp_add_local_addr_restricted(stcb, ifa);
  1.2198 +		} else if (type == SCTP_DEL_IP_ADDRESS) {
  1.2199 +			struct sctp_nets *net;
  1.2200 +			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1.2201 +				sctp_rtentry_t *rt;
  1.2202 +
  1.2203 +				/* delete this address if cached */
  1.2204 +				if (net->ro._s_addr == ifa) {
  1.2205 +					sctp_free_ifa(net->ro._s_addr);
  1.2206 +					net->ro._s_addr = NULL;
  1.2207 +					net->src_addr_selected = 0;
  1.2208 +					rt = net->ro.ro_rt;
  1.2209 +					if (rt) {
  1.2210 +						RTFREE(rt);
  1.2211 +						net->ro.ro_rt = NULL;
  1.2212 +					}
  1.2213 +					/*
  1.2214 +					 * Now we deleted our src address,
  1.2215 +					 * should we not also now reset the
  1.2216 +					 * cwnd/rto to start as if its a new
  1.2217 +					 * address?
  1.2218 +					 */
  1.2219 +					stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
  1.2220 +					net->RTO = 0;
  1.2221 +
  1.2222 +				}
  1.2223 +			}
  1.2224 +		} else if (type == SCTP_SET_PRIM_ADDR) {
  1.2225 +			if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
  1.2226 +				/* must validate the ifa is in the ep */
  1.2227 +				if (sctp_is_addr_in_ep(stcb->sctp_ep,ifa) == 0) {
  1.2228 +					continue;
  1.2229 +				}
  1.2230 +			} else {
  1.2231 +				/* Need to check scopes for this guy */
  1.2232 +				if (sctp_is_address_in_scope(ifa, &stcb->asoc.scope, 0) == 0) {
  1.2233 +					continue;
  1.2234 +				}
  1.2235 +			}
  1.2236 +		}
  1.2237 +		/* queue an asconf for this address add/delete */
  1.2238 +		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF) &&
  1.2239 +		    stcb->asoc.peer_supports_asconf) {
  1.2240 +			/* queue an asconf for this addr */
  1.2241 +			status = sctp_asconf_queue_add(stcb, ifa, type);
  1.2242 +			/*
  1.2243 +			 * if queued ok, and in the open state, update the
  1.2244 +			 * count of queued params.  If in the non-open state,
  1.2245 +			 * these get sent when the assoc goes open.
  1.2246 +			 */
  1.2247 +			if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
  1.2248 +				if (status >= 0) {
  1.2249 +					num_queued++;
  1.2250 +				}
  1.2251 +			}
  1.2252 +		}
  1.2253 +	}
  1.2254 +	/*
  1.2255 +	 * If we have queued params in the open state, send out an ASCONF.
  1.2256 +	 */
  1.2257 +	if (num_queued > 0) {
  1.2258 +		sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
  1.2259 +	}
  1.2260 +}
  1.2261 +
  1.2262 +void
  1.2263 +sctp_asconf_iterator_end(void *ptr, uint32_t val SCTP_UNUSED)
  1.2264 +{
  1.2265 +	struct sctp_asconf_iterator *asc;
  1.2266 +	struct sctp_ifa *ifa;
  1.2267 +	struct sctp_laddr *l, *nl;
  1.2268 +
  1.2269 +	asc = (struct sctp_asconf_iterator *)ptr;
  1.2270 +	LIST_FOREACH_SAFE(l, &asc->list_of_work, sctp_nxt_addr, nl) {
  1.2271 +		ifa = l->ifa;
  1.2272 +		if (l->action == SCTP_ADD_IP_ADDRESS) {
  1.2273 +			/* Clear the defer use flag */
  1.2274 +			ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE;
  1.2275 +		}
  1.2276 +		sctp_free_ifa(ifa);
  1.2277 +		SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_laddr), l);
  1.2278 +		SCTP_DECR_LADDR_COUNT();
  1.2279 +	}
  1.2280 +	SCTP_FREE(asc, SCTP_M_ASC_IT);
  1.2281 +}
  1.2282 +
  1.2283 +/*
  1.2284 + * sa is the sockaddr to ask the peer to set primary to.
  1.2285 + * returns: 0 = completed, -1 = error
  1.2286 + */
  1.2287 +int32_t
  1.2288 +sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa)
  1.2289 +{
  1.2290 + 	uint32_t vrf_id;
  1.2291 +	struct sctp_ifa *ifa;
  1.2292 +
  1.2293 +	/* find the ifa for the desired set primary */
  1.2294 +	vrf_id = stcb->asoc.vrf_id;
  1.2295 +	ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED);
  1.2296 +	if (ifa == NULL) {
  1.2297 +		/* Invalid address */
  1.2298 +		return (-1);
  1.2299 +	}
  1.2300 +
  1.2301 +	/* queue an ASCONF:SET_PRIM_ADDR to be sent */
  1.2302 +	if (!sctp_asconf_queue_add(stcb, ifa, SCTP_SET_PRIM_ADDR)) {
  1.2303 +		/* set primary queuing succeeded */
  1.2304 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
  1.2305 +			"set_primary_ip_address_sa: queued on tcb=%p, ",
  1.2306 +			(void *)stcb);
  1.2307 +		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
  1.2308 +		if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
  1.2309 +#ifdef SCTP_TIMER_BASED_ASCONF
  1.2310 +			sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
  1.2311 +					 stcb->sctp_ep, stcb,
  1.2312 +					 stcb->asoc.primary_destination);
  1.2313 +#else
  1.2314 +			sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
  1.2315 +#endif
  1.2316 +		}
  1.2317 +	} else {
  1.2318 +		SCTPDBG(SCTP_DEBUG_ASCONF1, "set_primary_ip_address_sa: failed to add to queue on tcb=%p, ",
  1.2319 +			(void *)stcb);
  1.2320 +		SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
  1.2321 +		return (-1);
  1.2322 +	}
  1.2323 +	return (0);
  1.2324 +}
  1.2325 +
  1.2326 +void
  1.2327 +sctp_set_primary_ip_address(struct sctp_ifa *ifa)
  1.2328 +{
  1.2329 +	struct sctp_inpcb *inp;
  1.2330 +
  1.2331 +	/* go through all our PCB's */
  1.2332 +	LIST_FOREACH(inp, &SCTP_BASE_INFO(listhead), sctp_list) {
  1.2333 +		struct sctp_tcb *stcb;
  1.2334 +
  1.2335 +		/* process for all associations for this endpoint */
  1.2336 +		LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.2337 +			/* queue an ASCONF:SET_PRIM_ADDR to be sent */
  1.2338 +			if (!sctp_asconf_queue_add(stcb, ifa,
  1.2339 +						   SCTP_SET_PRIM_ADDR)) {
  1.2340 +				/* set primary queuing succeeded */
  1.2341 +				SCTPDBG(SCTP_DEBUG_ASCONF1, "set_primary_ip_address: queued on stcb=%p, ",
  1.2342 +					(void *)stcb);
  1.2343 +				SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &ifa->address.sa);
  1.2344 +				if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
  1.2345 +#ifdef SCTP_TIMER_BASED_ASCONF
  1.2346 +					sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
  1.2347 +							 stcb->sctp_ep, stcb,
  1.2348 +							 stcb->asoc.primary_destination);
  1.2349 +#else
  1.2350 +					sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
  1.2351 +#endif
  1.2352 +				}
  1.2353 +			}
  1.2354 +		} /* for each stcb */
  1.2355 +	} /* for each inp */
  1.2356 +}
  1.2357 +
  1.2358 +int
  1.2359 +sctp_is_addr_pending(struct sctp_tcb *stcb, struct sctp_ifa *sctp_ifa)
  1.2360 +{
  1.2361 +	struct sctp_tmit_chunk *chk, *nchk;
  1.2362 +	unsigned int offset, asconf_limit;
  1.2363 +	struct sctp_asconf_chunk *acp;
  1.2364 +	struct sctp_asconf_paramhdr *aph;
  1.2365 +	uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE];
  1.2366 +	struct sctp_paramhdr *ph;
  1.2367 +	int add_cnt, del_cnt;
  1.2368 +	uint16_t last_param_type;
  1.2369 +
  1.2370 +	add_cnt = del_cnt = 0;
  1.2371 +	last_param_type = 0;
  1.2372 +	TAILQ_FOREACH_SAFE(chk, &stcb->asoc.asconf_send_queue, sctp_next, nchk) {
  1.2373 +		if (chk->data == NULL) {
  1.2374 +			SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: No mbuf data?\n");
  1.2375 +			continue;
  1.2376 +		}
  1.2377 +		offset = 0;
  1.2378 +		acp = mtod(chk->data, struct sctp_asconf_chunk *);
  1.2379 +		offset += sizeof(struct sctp_asconf_chunk);
  1.2380 +		asconf_limit = ntohs(acp->ch.chunk_length);
  1.2381 +		ph = (struct sctp_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_paramhdr), aparam_buf);
  1.2382 +		if (ph == NULL) {
  1.2383 +			SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: couldn't get lookup addr!\n");
  1.2384 +			continue;
  1.2385 +		}
  1.2386 +		offset += ntohs(ph->param_length);
  1.2387 +
  1.2388 +		aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_asconf_paramhdr), aparam_buf);
  1.2389 +		if (aph == NULL) {
  1.2390 +			SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: Empty ASCONF will be sent?\n");
  1.2391 +			continue;
  1.2392 +		}
  1.2393 +		while (aph != NULL) {
  1.2394 +			unsigned int param_length, param_type;
  1.2395 +
  1.2396 +			param_type = ntohs(aph->ph.param_type);
  1.2397 +			param_length = ntohs(aph->ph.param_length);
  1.2398 +			if (offset + param_length > asconf_limit) {
  1.2399 +				/* parameter goes beyond end of chunk! */
  1.2400 +				break;
  1.2401 +			}
  1.2402 +			if (param_length > sizeof(aparam_buf)) {
  1.2403 +				SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: param length (%u) larger than buffer size!\n", param_length);
  1.2404 +				break;
  1.2405 +			}
  1.2406 +			if (param_length <= sizeof(struct sctp_paramhdr)) {
  1.2407 +				SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: param length(%u) too short\n", param_length);
  1.2408 +				break;
  1.2409 +			}
  1.2410 +
  1.2411 +			aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, param_length, aparam_buf);
  1.2412 +			if (aph == NULL) {
  1.2413 +				SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: couldn't get entire param\n");
  1.2414 +				break;
  1.2415 +			}
  1.2416 +
  1.2417 +			ph = (struct sctp_paramhdr *)(aph + 1);
  1.2418 +			if (sctp_addr_match(ph, &sctp_ifa->address.sa) != 0) {
  1.2419 +				switch (param_type) {
  1.2420 +				case SCTP_ADD_IP_ADDRESS:
  1.2421 +					add_cnt++;
  1.2422 +					break;
  1.2423 +				case SCTP_DEL_IP_ADDRESS:
  1.2424 +					del_cnt++;
  1.2425 +					break;
  1.2426 +				default:
  1.2427 +					break;
  1.2428 +				}
  1.2429 +				last_param_type = param_type;
  1.2430 +			}
  1.2431 +
  1.2432 +			offset += SCTP_SIZE32(param_length);
  1.2433 +			if (offset >= asconf_limit) {
  1.2434 +				/* no more data in the mbuf chain */
  1.2435 +				break;
  1.2436 +			}
  1.2437 +			/* get pointer to next asconf param */
  1.2438 +			aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_asconf_paramhdr), aparam_buf);
  1.2439 +		}
  1.2440 +	}
  1.2441 +
  1.2442 +	/* we want to find the sequences which consist of ADD -> DEL -> ADD or DEL -> ADD */
  1.2443 +	if (add_cnt > del_cnt ||
  1.2444 +	    (add_cnt == del_cnt && last_param_type == SCTP_ADD_IP_ADDRESS)) {
  1.2445 +		return (1);
  1.2446 +	}
  1.2447 +	return (0);
  1.2448 +}
  1.2449 +
  1.2450 +static struct sockaddr *
  1.2451 +sctp_find_valid_localaddr(struct sctp_tcb *stcb, int addr_locked)
  1.2452 +{
  1.2453 +	struct sctp_vrf *vrf = NULL;
  1.2454 +	struct sctp_ifn *sctp_ifn;
  1.2455 +	struct sctp_ifa *sctp_ifa;
  1.2456 +
  1.2457 +	if (addr_locked == SCTP_ADDR_NOT_LOCKED)
  1.2458 +		SCTP_IPI_ADDR_RLOCK();
  1.2459 +	vrf = sctp_find_vrf(stcb->asoc.vrf_id);
  1.2460 +	if (vrf == NULL) {
  1.2461 +		if (addr_locked == SCTP_ADDR_NOT_LOCKED)
  1.2462 +			SCTP_IPI_ADDR_RUNLOCK();
  1.2463 +		return (NULL);
  1.2464 +	}
  1.2465 +	LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
  1.2466 +		if (stcb->asoc.scope.loopback_scope == 0 &&
  1.2467 +		    SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
  1.2468 +			/* Skip if loopback_scope not set */
  1.2469 +			continue;
  1.2470 +		}
  1.2471 +		LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
  1.2472 +			switch (sctp_ifa->address.sa.sa_family) {
  1.2473 +#ifdef INET
  1.2474 +			case AF_INET:
  1.2475 +				if (stcb->asoc.scope.ipv4_addr_legal) {
  1.2476 +					struct sockaddr_in *sin;
  1.2477 +
  1.2478 +					sin = (struct sockaddr_in *)&sctp_ifa->address.sa;
  1.2479 +					if (sin->sin_addr.s_addr == 0) {
  1.2480 +						/* skip unspecifed addresses */
  1.2481 +						continue;
  1.2482 +					}
  1.2483 +					if (stcb->asoc.scope.ipv4_local_scope == 0 &&
  1.2484 +					    IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))
  1.2485 +						continue;
  1.2486 +
  1.2487 +					if (sctp_is_addr_restricted(stcb, sctp_ifa) &&
  1.2488 +					    (!sctp_is_addr_pending(stcb, sctp_ifa)))
  1.2489 +						continue;
  1.2490 +					/* found a valid local v4 address to use */
  1.2491 +					if (addr_locked == SCTP_ADDR_NOT_LOCKED)
  1.2492 +						SCTP_IPI_ADDR_RUNLOCK();
  1.2493 +					return (&sctp_ifa->address.sa);
  1.2494 +				}
  1.2495 +				break;
  1.2496 +#endif
  1.2497 +#ifdef INET6
  1.2498 +			case AF_INET6:
  1.2499 +				if (stcb->asoc.scope.ipv6_addr_legal) {
  1.2500 +					struct sockaddr_in6 *sin6;
  1.2501 +
  1.2502 +					if (sctp_ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
  1.2503 +						continue;
  1.2504 +					}
  1.2505 +
  1.2506 +					sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa;
  1.2507 +					if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
  1.2508 +						/* we skip unspecifed addresses */
  1.2509 +						continue;
  1.2510 +					}
  1.2511 +					if (stcb->asoc.scope.local_scope == 0 &&
  1.2512 +					    IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
  1.2513 +						continue;
  1.2514 +					if (stcb->asoc.scope.site_scope == 0 &&
  1.2515 +					    IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))
  1.2516 +						continue;
  1.2517 +
  1.2518 +					if (sctp_is_addr_restricted(stcb, sctp_ifa) &&
  1.2519 +					    (!sctp_is_addr_pending(stcb, sctp_ifa)))
  1.2520 +						continue;
  1.2521 +					/* found a valid local v6 address to use */
  1.2522 +					if (addr_locked == SCTP_ADDR_NOT_LOCKED)
  1.2523 +						SCTP_IPI_ADDR_RUNLOCK();
  1.2524 +					return (&sctp_ifa->address.sa);
  1.2525 +				}
  1.2526 +				break;
  1.2527 +#endif
  1.2528 +			default:
  1.2529 +				break;
  1.2530 +			}
  1.2531 +		}
  1.2532 +	}
  1.2533 +	/* no valid addresses found */
  1.2534 +	if (addr_locked == SCTP_ADDR_NOT_LOCKED)
  1.2535 +		SCTP_IPI_ADDR_RUNLOCK();
  1.2536 +	return (NULL);
  1.2537 +}
  1.2538 +
  1.2539 +static struct sockaddr *
  1.2540 +sctp_find_valid_localaddr_ep(struct sctp_tcb *stcb)
  1.2541 +{
  1.2542 +	struct sctp_laddr *laddr;
  1.2543 +
  1.2544 +	LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) {
  1.2545 +		if (laddr->ifa == NULL) {
  1.2546 +			continue;
  1.2547 +		}
  1.2548 +		/* is the address restricted ? */
  1.2549 +		if (sctp_is_addr_restricted(stcb, laddr->ifa) &&
  1.2550 +		    (!sctp_is_addr_pending(stcb, laddr->ifa)))
  1.2551 +			continue;
  1.2552 +
  1.2553 +		/* found a valid local address to use */
  1.2554 +		return (&laddr->ifa->address.sa);
  1.2555 +	}
  1.2556 +	/* no valid addresses found */
  1.2557 +	return (NULL);
  1.2558 +}
  1.2559 +
  1.2560 +/*
  1.2561 + * builds an ASCONF chunk from queued ASCONF params.
  1.2562 + * returns NULL on error (no mbuf, no ASCONF params queued, etc).
  1.2563 + */
  1.2564 +struct mbuf *
  1.2565 +sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked)
  1.2566 +{
  1.2567 +	struct mbuf *m_asconf, *m_asconf_chk;
  1.2568 +	struct sctp_asconf_addr *aa;
  1.2569 +	struct sctp_asconf_chunk *acp;
  1.2570 +	struct sctp_asconf_paramhdr *aph;
  1.2571 +	struct sctp_asconf_addr_param *aap;
  1.2572 +	uint32_t p_length;
  1.2573 +	uint32_t correlation_id = 1;	/* 0 is reserved... */
  1.2574 +	caddr_t ptr, lookup_ptr;
  1.2575 +	uint8_t lookup_used = 0;
  1.2576 +
  1.2577 +	/* are there any asconf params to send? */
  1.2578 +	TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) {
  1.2579 +		if (aa->sent == 0)
  1.2580 +			break;
  1.2581 +	}
  1.2582 +	if (aa == NULL)
  1.2583 +		return (NULL);
  1.2584 +
  1.2585 +	/*
  1.2586 +	 * get a chunk header mbuf and a cluster for the asconf params since
  1.2587 +	 * it's simpler to fill in the asconf chunk header lookup address on
  1.2588 +	 * the fly
  1.2589 +	 */
  1.2590 +	m_asconf_chk = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_chunk), 0, M_NOWAIT, 1, MT_DATA);
  1.2591 +	if (m_asconf_chk == NULL) {
  1.2592 +		/* no mbuf's */
  1.2593 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
  1.2594 +			"compose_asconf: couldn't get chunk mbuf!\n");
  1.2595 +		return (NULL);
  1.2596 +	}
  1.2597 +	m_asconf = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
  1.2598 +	if (m_asconf == NULL) {
  1.2599 +		/* no mbuf's */
  1.2600 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
  1.2601 +			"compose_asconf: couldn't get mbuf!\n");
  1.2602 +		sctp_m_freem(m_asconf_chk);
  1.2603 +		return (NULL);
  1.2604 +	}
  1.2605 +	SCTP_BUF_LEN(m_asconf_chk) = sizeof(struct sctp_asconf_chunk);
  1.2606 +	SCTP_BUF_LEN(m_asconf) = 0;
  1.2607 +	acp = mtod(m_asconf_chk, struct sctp_asconf_chunk *);
  1.2608 +	bzero(acp, sizeof(struct sctp_asconf_chunk));
  1.2609 +	/* save pointers to lookup address and asconf params */
  1.2610 +	lookup_ptr = (caddr_t)(acp + 1);	/* after the header */
  1.2611 +	ptr = mtod(m_asconf, caddr_t);	/* beginning of cluster */
  1.2612 +
  1.2613 +	/* fill in chunk header info */
  1.2614 +	acp->ch.chunk_type = SCTP_ASCONF;
  1.2615 +	acp->ch.chunk_flags = 0;
  1.2616 +	acp->serial_number = htonl(stcb->asoc.asconf_seq_out);
  1.2617 +	stcb->asoc.asconf_seq_out++;
  1.2618 +
  1.2619 +	/* add parameters... up to smallest MTU allowed */
  1.2620 +	TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) {
  1.2621 +		if (aa->sent)
  1.2622 +			continue;
  1.2623 +		/* get the parameter length */
  1.2624 +		p_length = SCTP_SIZE32(aa->ap.aph.ph.param_length);
  1.2625 +		/* will it fit in current chunk? */
  1.2626 +		if ((SCTP_BUF_LEN(m_asconf) + p_length > stcb->asoc.smallest_mtu) ||
  1.2627 +		    (SCTP_BUF_LEN(m_asconf) + p_length > MCLBYTES)) {
  1.2628 +			/* won't fit, so we're done with this chunk */
  1.2629 +			break;
  1.2630 +		}
  1.2631 +		/* assign (and store) a correlation id */
  1.2632 +		aa->ap.aph.correlation_id = correlation_id++;
  1.2633 +
  1.2634 +		/*
  1.2635 +		 * fill in address if we're doing a delete this is a simple
  1.2636 +		 * way for us to fill in the correlation address, which
  1.2637 +		 * should only be used by the peer if we're deleting our
  1.2638 +		 * source address and adding a new address (e.g. renumbering
  1.2639 +		 * case)
  1.2640 +		 */
  1.2641 +		if (lookup_used == 0 &&
  1.2642 +		    (aa->special_del == 0) &&
  1.2643 +		    aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS) {
  1.2644 +			struct sctp_ipv6addr_param *lookup;
  1.2645 +			uint16_t p_size, addr_size;
  1.2646 +
  1.2647 +			lookup = (struct sctp_ipv6addr_param *)lookup_ptr;
  1.2648 +			lookup->ph.param_type =
  1.2649 +			    htons(aa->ap.addrp.ph.param_type);
  1.2650 +			if (aa->ap.addrp.ph.param_type == SCTP_IPV6_ADDRESS) {
  1.2651 +				/* copy IPv6 address */
  1.2652 +				p_size = sizeof(struct sctp_ipv6addr_param);
  1.2653 +				addr_size = sizeof(struct in6_addr);
  1.2654 +			} else {
  1.2655 +				/* copy IPv4 address */
  1.2656 +				p_size = sizeof(struct sctp_ipv4addr_param);
  1.2657 +				addr_size = sizeof(struct in_addr);
  1.2658 +			}
  1.2659 +			lookup->ph.param_length = htons(SCTP_SIZE32(p_size));
  1.2660 +			memcpy(lookup->addr, &aa->ap.addrp.addr, addr_size);
  1.2661 +			SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(p_size);
  1.2662 +			lookup_used = 1;
  1.2663 +		}
  1.2664 +		/* copy into current space */
  1.2665 +		memcpy(ptr, &aa->ap, p_length);
  1.2666 +
  1.2667 +		/* network elements and update lengths */
  1.2668 +		aph = (struct sctp_asconf_paramhdr *)ptr;
  1.2669 +		aap = (struct sctp_asconf_addr_param *)ptr;
  1.2670 +		/* correlation_id is transparent to peer, no htonl needed */
  1.2671 +		aph->ph.param_type = htons(aph->ph.param_type);
  1.2672 +		aph->ph.param_length = htons(aph->ph.param_length);
  1.2673 +		aap->addrp.ph.param_type = htons(aap->addrp.ph.param_type);
  1.2674 +		aap->addrp.ph.param_length = htons(aap->addrp.ph.param_length);
  1.2675 +
  1.2676 +		SCTP_BUF_LEN(m_asconf) += SCTP_SIZE32(p_length);
  1.2677 +		ptr += SCTP_SIZE32(p_length);
  1.2678 +
  1.2679 +		/*
  1.2680 +		 * these params are removed off the pending list upon
  1.2681 +		 * getting an ASCONF-ACK back from the peer, just set flag
  1.2682 +		 */
  1.2683 +		aa->sent = 1;
  1.2684 +	}
  1.2685 +	/* check to see if the lookup addr has been populated yet */
  1.2686 +	if (lookup_used == 0) {
  1.2687 +		/* NOTE: if the address param is optional, can skip this... */
  1.2688 +		/* add any valid (existing) address... */
  1.2689 +		struct sctp_ipv6addr_param *lookup;
  1.2690 +		uint16_t p_size, addr_size;
  1.2691 +		struct sockaddr *found_addr;
  1.2692 +		caddr_t addr_ptr;
  1.2693 +
  1.2694 +		if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL)
  1.2695 +			found_addr = sctp_find_valid_localaddr(stcb,
  1.2696 +							       addr_locked);
  1.2697 +		else
  1.2698 +			found_addr = sctp_find_valid_localaddr_ep(stcb);
  1.2699 +
  1.2700 +		lookup = (struct sctp_ipv6addr_param *)lookup_ptr;
  1.2701 +		if (found_addr != NULL) {
  1.2702 +			switch (found_addr->sa_family) {
  1.2703 +#ifdef INET6
  1.2704 +			case AF_INET6:
  1.2705 +				/* copy IPv6 address */
  1.2706 +				lookup->ph.param_type =
  1.2707 +				    htons(SCTP_IPV6_ADDRESS);
  1.2708 +				p_size = sizeof(struct sctp_ipv6addr_param);
  1.2709 +				addr_size = sizeof(struct in6_addr);
  1.2710 +				addr_ptr = (caddr_t)&((struct sockaddr_in6 *)
  1.2711 +				    found_addr)->sin6_addr;
  1.2712 +				break;
  1.2713 +#endif
  1.2714 +#ifdef INET
  1.2715 +			case AF_INET:
  1.2716 +				/* copy IPv4 address */
  1.2717 +				lookup->ph.param_type =
  1.2718 +				    htons(SCTP_IPV4_ADDRESS);
  1.2719 +				p_size = sizeof(struct sctp_ipv4addr_param);
  1.2720 +				addr_size = sizeof(struct in_addr);
  1.2721 +				addr_ptr = (caddr_t)&((struct sockaddr_in *)
  1.2722 +				    found_addr)->sin_addr;
  1.2723 +				break;
  1.2724 +#endif
  1.2725 +			default:
  1.2726 +				p_size = 0;
  1.2727 +				addr_size = 0;
  1.2728 +				addr_ptr = NULL;
  1.2729 +				break;
  1.2730 +			}
  1.2731 +			lookup->ph.param_length = htons(SCTP_SIZE32(p_size));
  1.2732 +			memcpy(lookup->addr, addr_ptr, addr_size);
  1.2733 +			SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(p_size);
  1.2734 +		} else {
  1.2735 +			/* uh oh... don't have any address?? */
  1.2736 +			SCTPDBG(SCTP_DEBUG_ASCONF1,
  1.2737 +				"compose_asconf: no lookup addr!\n");
  1.2738 +			/* XXX for now, we send a IPv4 address of 0.0.0.0 */
  1.2739 +			lookup->ph.param_type = htons(SCTP_IPV4_ADDRESS);
  1.2740 +			lookup->ph.param_length = htons(SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param)));
  1.2741 +			bzero(lookup->addr, sizeof(struct in_addr));
  1.2742 +			SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(sizeof(struct sctp_ipv4addr_param));
  1.2743 +		}
  1.2744 +	}
  1.2745 +	/* chain it all together */
  1.2746 +	SCTP_BUF_NEXT(m_asconf_chk) = m_asconf;
  1.2747 +	*retlen = SCTP_BUF_LEN(m_asconf_chk) + SCTP_BUF_LEN(m_asconf);
  1.2748 +	acp->ch.chunk_length = htons(*retlen);
  1.2749 +
  1.2750 +	return (m_asconf_chk);
  1.2751 +}
  1.2752 +
  1.2753 +/*
  1.2754 + * section to handle address changes before an association is up eg. changes
  1.2755 + * during INIT/INIT-ACK/COOKIE-ECHO handshake
  1.2756 + */
  1.2757 +
  1.2758 +/*
  1.2759 + * processes the (local) addresses in the INIT-ACK chunk
  1.2760 + */
  1.2761 +static void
  1.2762 +sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m,
  1.2763 +    unsigned int offset, unsigned int length)
  1.2764 +{
  1.2765 +	struct sctp_paramhdr tmp_param, *ph;
  1.2766 +	uint16_t plen, ptype;
  1.2767 +	struct sctp_ifa *sctp_ifa;
  1.2768 +#ifdef INET6
  1.2769 +	struct sctp_ipv6addr_param addr6_store;
  1.2770 +	struct sockaddr_in6 sin6;
  1.2771 +#endif
  1.2772 +#ifdef INET
  1.2773 +	struct sctp_ipv4addr_param addr4_store;
  1.2774 +	struct sockaddr_in sin;
  1.2775 +#endif
  1.2776 +	struct sockaddr *sa;
  1.2777 +	uint32_t vrf_id;
  1.2778 +
  1.2779 +	SCTPDBG(SCTP_DEBUG_ASCONF2, "processing init-ack addresses\n");
  1.2780 +	if (stcb == NULL) /* Un-needed check for SA */
  1.2781 +		return;
  1.2782 +
  1.2783 +	/* convert to upper bound */
  1.2784 +	length += offset;
  1.2785 +
  1.2786 +	if ((offset + sizeof(struct sctp_paramhdr)) > length) {
  1.2787 +		return;
  1.2788 +	}
  1.2789 +	/* init the addresses */
  1.2790 +#ifdef INET6
  1.2791 +	bzero(&sin6, sizeof(sin6));
  1.2792 +	sin6.sin6_family = AF_INET6;
  1.2793 +#ifdef HAVE_SIN6_LEN
  1.2794 +	sin6.sin6_len = sizeof(sin6);
  1.2795 +#endif
  1.2796 +	sin6.sin6_port = stcb->rport;
  1.2797 +#endif
  1.2798 +
  1.2799 +#ifdef INET
  1.2800 +	bzero(&sin, sizeof(sin));
  1.2801 +	sin.sin_family = AF_INET;
  1.2802 +#ifdef HAVE_SIN_LEN
  1.2803 +	sin.sin_len = sizeof(sin);
  1.2804 +#endif
  1.2805 +	sin.sin_port = stcb->rport;
  1.2806 +#endif
  1.2807 +
  1.2808 +	/* go through the addresses in the init-ack */
  1.2809 +	ph = (struct sctp_paramhdr *)
  1.2810 +	     sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr),
  1.2811 +	                   (uint8_t *)&tmp_param);
  1.2812 +	while (ph != NULL) {
  1.2813 +		ptype = ntohs(ph->param_type);
  1.2814 +		plen = ntohs(ph->param_length);
  1.2815 +		switch (ptype) {
  1.2816 +#ifdef INET6
  1.2817 +		case SCTP_IPV6_ADDRESS:
  1.2818 +		{
  1.2819 +			struct sctp_ipv6addr_param *a6p;
  1.2820 +
  1.2821 +			/* get the entire IPv6 address param */
  1.2822 +			a6p = (struct sctp_ipv6addr_param *)
  1.2823 +			    sctp_m_getptr(m, offset,
  1.2824 +			    sizeof(struct sctp_ipv6addr_param),
  1.2825 +			    (uint8_t *)&addr6_store);
  1.2826 +			if (plen != sizeof(struct sctp_ipv6addr_param) ||
  1.2827 +			    a6p == NULL) {
  1.2828 +				return;
  1.2829 +			}
  1.2830 +			memcpy(&sin6.sin6_addr, a6p->addr,
  1.2831 +			    sizeof(struct in6_addr));
  1.2832 +			sa = (struct sockaddr *)&sin6;
  1.2833 +			break;
  1.2834 +		}
  1.2835 +#endif
  1.2836 +#ifdef INET
  1.2837 +		case SCTP_IPV4_ADDRESS:
  1.2838 +		{
  1.2839 +			struct sctp_ipv4addr_param *a4p;
  1.2840 +
  1.2841 +			/* get the entire IPv4 address param */
  1.2842 +			a4p = (struct sctp_ipv4addr_param *)sctp_m_getptr(m, offset,
  1.2843 +									  sizeof(struct sctp_ipv4addr_param),
  1.2844 +									  (uint8_t *)&addr4_store);
  1.2845 +			if (plen != sizeof(struct sctp_ipv4addr_param) ||
  1.2846 +			    a4p == NULL) {
  1.2847 +				return;
  1.2848 +			}
  1.2849 +			sin.sin_addr.s_addr = a4p->addr;
  1.2850 +			sa = (struct sockaddr *)&sin;
  1.2851 +			break;
  1.2852 +		}
  1.2853 +#endif
  1.2854 +		default:
  1.2855 +			goto next_addr;
  1.2856 +		}
  1.2857 +
  1.2858 +		/* see if this address really (still) exists */
  1.2859 +		if (stcb) {
  1.2860 +			vrf_id = stcb->asoc.vrf_id;
  1.2861 +		} else {
  1.2862 +			vrf_id = SCTP_DEFAULT_VRFID;
  1.2863 +		}
  1.2864 +		sctp_ifa = sctp_find_ifa_by_addr(sa, vrf_id,
  1.2865 +						 SCTP_ADDR_NOT_LOCKED);
  1.2866 +		if (sctp_ifa == NULL) {
  1.2867 +			/* address doesn't exist anymore */
  1.2868 +			int status;
  1.2869 +
  1.2870 +			/* are ASCONFs allowed ? */
  1.2871 +			if ((sctp_is_feature_on(stcb->sctp_ep,
  1.2872 +			    SCTP_PCB_FLAGS_DO_ASCONF)) &&
  1.2873 +			    stcb->asoc.peer_supports_asconf) {
  1.2874 +				/* queue an ASCONF DEL_IP_ADDRESS */
  1.2875 +				status = sctp_asconf_queue_sa_delete(stcb, sa);
  1.2876 +				/*
  1.2877 +				 * if queued ok, and in correct state, send
  1.2878 +				 * out the ASCONF.
  1.2879 +				 */
  1.2880 +				if (status == 0 &&
  1.2881 +				    SCTP_GET_STATE(&stcb->asoc) ==
  1.2882 +				    SCTP_STATE_OPEN) {
  1.2883 +#ifdef SCTP_TIMER_BASED_ASCONF
  1.2884 +					sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
  1.2885 +							 stcb->sctp_ep, stcb,
  1.2886 +							 stcb->asoc.primary_destination);
  1.2887 +#else
  1.2888 +					sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
  1.2889 +#endif
  1.2890 +				}
  1.2891 +			}
  1.2892 +		}
  1.2893 +
  1.2894 +next_addr:
  1.2895 +		/*
  1.2896 +		 * Sanity check:  Make sure the length isn't 0, otherwise
  1.2897 +		 * we'll be stuck in this loop for a long time...
  1.2898 +		 */
  1.2899 +		if (SCTP_SIZE32(plen) == 0) {
  1.2900 +			SCTP_PRINTF("process_initack_addrs: bad len (%d) type=%xh\n",
  1.2901 +				    plen, ptype);
  1.2902 +			return;
  1.2903 +		}
  1.2904 +		/* get next parameter */
  1.2905 +		offset += SCTP_SIZE32(plen);
  1.2906 +		if ((offset + sizeof(struct sctp_paramhdr)) > length)
  1.2907 +			return;
  1.2908 +		ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset,
  1.2909 +		    sizeof(struct sctp_paramhdr), (uint8_t *) & tmp_param);
  1.2910 +	} /* while */
  1.2911 +}
  1.2912 +
  1.2913 +/* FIX ME: need to verify return result for v6 address type if v6 disabled */
  1.2914 +/*
  1.2915 + * checks to see if a specific address is in the initack address list returns
  1.2916 + * 1 if found, 0 if not
  1.2917 + */
  1.2918 +static uint32_t
  1.2919 +sctp_addr_in_initack(struct mbuf *m, uint32_t offset, uint32_t length, struct sockaddr *sa)
  1.2920 +{
  1.2921 +	struct sctp_paramhdr tmp_param, *ph;
  1.2922 +	uint16_t plen, ptype;
  1.2923 +#ifdef INET
  1.2924 +	struct sockaddr_in *sin;
  1.2925 +	struct sctp_ipv4addr_param *a4p;
  1.2926 +	struct sctp_ipv6addr_param addr4_store;
  1.2927 +#endif
  1.2928 +#ifdef INET6
  1.2929 +	struct sockaddr_in6 *sin6;
  1.2930 +	struct sctp_ipv6addr_param *a6p;
  1.2931 +	struct sctp_ipv6addr_param addr6_store;
  1.2932 +#ifdef SCTP_EMBEDDED_V6_SCOPE
  1.2933 +	struct sockaddr_in6 sin6_tmp;
  1.2934 +#endif
  1.2935 +#endif
  1.2936 +
  1.2937 +	switch (sa->sa_family) {
  1.2938 +#ifdef INET
  1.2939 +	case AF_INET:
  1.2940 +		break;
  1.2941 +#endif
  1.2942 +#ifdef INET6
  1.2943 +	case AF_INET6:
  1.2944 +		break;
  1.2945 +#endif
  1.2946 +	default:
  1.2947 +		return (0);
  1.2948 +	}
  1.2949 +
  1.2950 +	SCTPDBG(SCTP_DEBUG_ASCONF2, "find_initack_addr: starting search for ");
  1.2951 +	SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, sa);
  1.2952 +	/* convert to upper bound */
  1.2953 +	length += offset;
  1.2954 +
  1.2955 +	if ((offset + sizeof(struct sctp_paramhdr)) > length) {
  1.2956 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
  1.2957 +			"find_initack_addr: invalid offset?\n");
  1.2958 +		return (0);
  1.2959 +	}
  1.2960 +	/* go through the addresses in the init-ack */
  1.2961 +	ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset,
  1.2962 +	    sizeof(struct sctp_paramhdr), (uint8_t *) & tmp_param);
  1.2963 +	while (ph != NULL) {
  1.2964 +		ptype = ntohs(ph->param_type);
  1.2965 +		plen = ntohs(ph->param_length);
  1.2966 +		switch (ptype) {
  1.2967 +#ifdef INET6
  1.2968 +		case SCTP_IPV6_ADDRESS:
  1.2969 +			if (sa->sa_family == AF_INET6) {
  1.2970 +				/* get the entire IPv6 address param */
  1.2971 +				if (plen != sizeof(struct sctp_ipv6addr_param)) {
  1.2972 +					break;
  1.2973 +				}
  1.2974 +				/* get the entire IPv6 address param */
  1.2975 +				a6p = (struct sctp_ipv6addr_param *)
  1.2976 +				      sctp_m_getptr(m, offset,
  1.2977 +				                    sizeof(struct sctp_ipv6addr_param),
  1.2978 +				                    (uint8_t *)&addr6_store);
  1.2979 +				if (a6p == NULL) {
  1.2980 +					return (0);
  1.2981 +				}
  1.2982 +				sin6 = (struct sockaddr_in6 *)sa;
  1.2983 +#ifdef SCTP_EMBEDDED_V6_SCOPE
  1.2984 +				if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) {
  1.2985 +					/* create a copy and clear scope */
  1.2986 +					memcpy(&sin6_tmp, sin6,
  1.2987 +					       sizeof(struct sockaddr_in6));
  1.2988 +					sin6 = &sin6_tmp;
  1.2989 +					in6_clearscope(&sin6->sin6_addr);
  1.2990 +				}
  1.2991 +#endif /* SCTP_EMBEDDED_V6_SCOPE */
  1.2992 +				if (memcmp(&sin6->sin6_addr, a6p->addr,
  1.2993 +				           sizeof(struct in6_addr)) == 0) {
  1.2994 +					/* found it */
  1.2995 +					return (1);
  1.2996 +				}
  1.2997 +			}
  1.2998 +			break;
  1.2999 +#endif /* INET6 */
  1.3000 +#ifdef INET
  1.3001 +		case SCTP_IPV4_ADDRESS:
  1.3002 +			if (sa->sa_family == AF_INET) {
  1.3003 +				if (plen != sizeof(struct sctp_ipv4addr_param)) {
  1.3004 +					break;
  1.3005 +				}
  1.3006 +				/* get the entire IPv4 address param */
  1.3007 +				a4p = (struct sctp_ipv4addr_param *)
  1.3008 +				      sctp_m_getptr(m, offset,
  1.3009 +				                    sizeof(struct sctp_ipv4addr_param),
  1.3010 +				                    (uint8_t *)&addr4_store);
  1.3011 +				if (a4p == NULL) {
  1.3012 +					return (0);
  1.3013 +				}
  1.3014 +				sin = (struct sockaddr_in *)sa;
  1.3015 +				if (sin->sin_addr.s_addr == a4p->addr) {
  1.3016 +					/* found it */
  1.3017 +					return (1);
  1.3018 +				}
  1.3019 +			}
  1.3020 +			break;
  1.3021 +#endif
  1.3022 +		default:
  1.3023 +			break;
  1.3024 +		}
  1.3025 +		/* get next parameter */
  1.3026 +		offset += SCTP_SIZE32(plen);
  1.3027 +		if (offset + sizeof(struct sctp_paramhdr) > length) {
  1.3028 +			return (0);
  1.3029 +		}
  1.3030 +		ph = (struct sctp_paramhdr *)
  1.3031 +		    sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr),
  1.3032 +		    (uint8_t *) & tmp_param);
  1.3033 +	} /* while */
  1.3034 +	/* not found! */
  1.3035 +	return (0);
  1.3036 +}
  1.3037 +
  1.3038 +/*
  1.3039 + * makes sure that the current endpoint local addr list is consistent with
  1.3040 + * the new association (eg. subset bound, asconf allowed) adds addresses as
  1.3041 + * necessary
  1.3042 + */
  1.3043 +static void
  1.3044 +sctp_check_address_list_ep(struct sctp_tcb *stcb, struct mbuf *m, int offset,
  1.3045 +    int length, struct sockaddr *init_addr)
  1.3046 +{
  1.3047 +	struct sctp_laddr *laddr;
  1.3048 +
  1.3049 +	/* go through the endpoint list */
  1.3050 +	LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) {
  1.3051 +		/* be paranoid and validate the laddr */
  1.3052 +		if (laddr->ifa == NULL) {
  1.3053 +			SCTPDBG(SCTP_DEBUG_ASCONF1,
  1.3054 +				"check_addr_list_ep: laddr->ifa is NULL");
  1.3055 +			continue;
  1.3056 +		}
  1.3057 +		if (laddr->ifa == NULL) {
  1.3058 +			SCTPDBG(SCTP_DEBUG_ASCONF1, "check_addr_list_ep: laddr->ifa->ifa_addr is NULL");
  1.3059 +			continue;
  1.3060 +		}
  1.3061 +		/* do i have it implicitly? */
  1.3062 +		if (sctp_cmpaddr(&laddr->ifa->address.sa, init_addr)) {
  1.3063 +			continue;
  1.3064 +		}
  1.3065 +		/* check to see if in the init-ack */
  1.3066 +		if (!sctp_addr_in_initack(m, offset, length, &laddr->ifa->address.sa)) {
  1.3067 +			/* try to add it */
  1.3068 +			sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb, laddr->ifa,
  1.3069 +			    SCTP_ADD_IP_ADDRESS, SCTP_ADDR_NOT_LOCKED);
  1.3070 +		}
  1.3071 +	}
  1.3072 +}
  1.3073 +
  1.3074 +/*
  1.3075 + * makes sure that the current kernel address list is consistent with the new
  1.3076 + * association (with all addrs bound) adds addresses as necessary
  1.3077 + */
  1.3078 +static void
  1.3079 +sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset,
  1.3080 +    int length, struct sockaddr *init_addr,
  1.3081 +    uint16_t local_scope, uint16_t site_scope,
  1.3082 +    uint16_t ipv4_scope, uint16_t loopback_scope)
  1.3083 +{
  1.3084 +	struct sctp_vrf *vrf = NULL;
  1.3085 +	struct sctp_ifn *sctp_ifn;
  1.3086 +	struct sctp_ifa *sctp_ifa;
  1.3087 +	uint32_t vrf_id;
  1.3088 +#ifdef INET
  1.3089 +	struct sockaddr_in *sin;
  1.3090 +#endif
  1.3091 +#ifdef INET6
  1.3092 +	struct sockaddr_in6 *sin6;
  1.3093 +#endif
  1.3094 +
  1.3095 +	if (stcb) {
  1.3096 +		vrf_id = stcb->asoc.vrf_id;
  1.3097 +	} else {
  1.3098 +		return;
  1.3099 +	}
  1.3100 +	SCTP_IPI_ADDR_RLOCK();
  1.3101 +	vrf = sctp_find_vrf(vrf_id);
  1.3102 +	if (vrf == NULL) {
  1.3103 +		SCTP_IPI_ADDR_RUNLOCK();
  1.3104 +		return;
  1.3105 +	}
  1.3106 +	/* go through all our known interfaces */
  1.3107 +	LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
  1.3108 +		if (loopback_scope == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
  1.3109 +			/* skip loopback interface */
  1.3110 +			continue;
  1.3111 +		}
  1.3112 +		/* go through each interface address */
  1.3113 +		LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
  1.3114 +			/* do i have it implicitly? */
  1.3115 +			if (sctp_cmpaddr(&sctp_ifa->address.sa, init_addr)) {
  1.3116 +				continue;
  1.3117 +			}
  1.3118 +			switch (sctp_ifa->address.sa.sa_family) {
  1.3119 +#ifdef INET
  1.3120 +			case AF_INET:
  1.3121 +				sin = (struct sockaddr_in *)&sctp_ifa->address.sin;
  1.3122 +				if ((ipv4_scope == 0) &&
  1.3123 +				    (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
  1.3124 +					/* private address not in scope */
  1.3125 +					continue;
  1.3126 +				}
  1.3127 +				break;
  1.3128 +#endif
  1.3129 +#ifdef INET6
  1.3130 +			case AF_INET6:
  1.3131 +				sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sin6;
  1.3132 +				if ((local_scope == 0) &&
  1.3133 +				    (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) {
  1.3134 +					continue;
  1.3135 +				}
  1.3136 +				if ((site_scope == 0) &&
  1.3137 +				    (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
  1.3138 +					continue;
  1.3139 +				}
  1.3140 +				break;
  1.3141 +#endif
  1.3142 +			default:
  1.3143 +				break;
  1.3144 +			}
  1.3145 +			/* check to see if in the init-ack */
  1.3146 +			if (!sctp_addr_in_initack(m, offset, length, &sctp_ifa->address.sa)) {
  1.3147 +				/* try to add it */
  1.3148 +				sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb,
  1.3149 +				    sctp_ifa, SCTP_ADD_IP_ADDRESS,
  1.3150 +				    SCTP_ADDR_LOCKED);
  1.3151 +			}
  1.3152 +		} /* end foreach ifa */
  1.3153 +	} /* end foreach ifn */
  1.3154 +	SCTP_IPI_ADDR_RUNLOCK();
  1.3155 +}
  1.3156 +
  1.3157 +/*
  1.3158 + * validates an init-ack chunk (from a cookie-echo) with current addresses
  1.3159 + * adds addresses from the init-ack into our local address list, if needed
  1.3160 + * queues asconf adds/deletes addresses as needed and makes appropriate list
  1.3161 + * changes for source address selection m, offset: points to the start of the
  1.3162 + * address list in an init-ack chunk length: total length of the address
  1.3163 + * params only init_addr: address where my INIT-ACK was sent from
  1.3164 + */
  1.3165 +void
  1.3166 +sctp_check_address_list(struct sctp_tcb *stcb, struct mbuf *m, int offset,
  1.3167 +    int length, struct sockaddr *init_addr,
  1.3168 +    uint16_t local_scope, uint16_t site_scope,
  1.3169 +    uint16_t ipv4_scope, uint16_t loopback_scope)
  1.3170 +{
  1.3171 +	/* process the local addresses in the initack */
  1.3172 +	sctp_process_initack_addresses(stcb, m, offset, length);
  1.3173 +
  1.3174 +	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
  1.3175 +		/* bound all case */
  1.3176 +		sctp_check_address_list_all(stcb, m, offset, length, init_addr,
  1.3177 +		    local_scope, site_scope, ipv4_scope, loopback_scope);
  1.3178 +	} else {
  1.3179 +		/* subset bound case */
  1.3180 +		if (sctp_is_feature_on(stcb->sctp_ep,
  1.3181 +		    SCTP_PCB_FLAGS_DO_ASCONF)) {
  1.3182 +			/* asconf's allowed */
  1.3183 +			sctp_check_address_list_ep(stcb, m, offset, length,
  1.3184 +			    init_addr);
  1.3185 +		}
  1.3186 +		/* else, no asconfs allowed, so what we sent is what we get */
  1.3187 +	}
  1.3188 +}
  1.3189 +
  1.3190 +/*
  1.3191 + * sctp_bindx() support
  1.3192 + */
  1.3193 +uint32_t
  1.3194 +sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
  1.3195 +    uint32_t type, uint32_t vrf_id, struct sctp_ifa *sctp_ifap)
  1.3196 +{
  1.3197 +	struct sctp_ifa *ifa;
  1.3198 +	struct sctp_laddr *laddr, *nladdr;
  1.3199 +
  1.3200 +#ifdef HAVE_SA_LEN
  1.3201 +	if (sa->sa_len == 0) {
  1.3202 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EINVAL);
  1.3203 +		return (EINVAL);
  1.3204 +	}
  1.3205 +#endif
  1.3206 +	if (sctp_ifap) {
  1.3207 +		ifa = sctp_ifap;
  1.3208 +	} else 	if (type == SCTP_ADD_IP_ADDRESS) {
  1.3209 +		/* For an add the address MUST be on the system */
  1.3210 +		ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED);
  1.3211 +	} else if (type == SCTP_DEL_IP_ADDRESS) {
  1.3212 +		/* For a delete we need to find it in the inp */
  1.3213 +		ifa = sctp_find_ifa_in_ep(inp, sa, SCTP_ADDR_NOT_LOCKED);
  1.3214 +	} else {
  1.3215 +		ifa = NULL;
  1.3216 +	}
  1.3217 +	if (ifa != NULL) {
  1.3218 +		if (type == SCTP_ADD_IP_ADDRESS) {
  1.3219 +			sctp_add_local_addr_ep(inp, ifa, type);
  1.3220 +		} else if (type == SCTP_DEL_IP_ADDRESS) {
  1.3221 +			if (inp->laddr_count < 2) {
  1.3222 +				/* can't delete the last local address */
  1.3223 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EINVAL);
  1.3224 +				return (EINVAL);
  1.3225 +			}
  1.3226 +			LIST_FOREACH(laddr, &inp->sctp_addr_list,
  1.3227 +				     sctp_nxt_addr) {
  1.3228 +				if (ifa == laddr->ifa) {
  1.3229 +					/* Mark in the delete */
  1.3230 +					laddr->action = type;
  1.3231 +				}
  1.3232 +			}
  1.3233 +		}
  1.3234 +		if (LIST_EMPTY(&inp->sctp_asoc_list)) {
  1.3235 +			/*
  1.3236 +			 * There is no need to start the iterator if
  1.3237 +			 * the inp has no associations.
  1.3238 +			 */
  1.3239 +			if (type == SCTP_DEL_IP_ADDRESS) {
  1.3240 +				LIST_FOREACH_SAFE(laddr, &inp->sctp_addr_list, sctp_nxt_addr, nladdr) {
  1.3241 +					if (laddr->ifa == ifa) {
  1.3242 +						sctp_del_local_addr_ep(inp, ifa);
  1.3243 +					}
  1.3244 +				}
  1.3245 +			}
  1.3246 +		} else {
  1.3247 +			struct sctp_asconf_iterator *asc;
  1.3248 +			struct sctp_laddr *wi;
  1.3249 +
  1.3250 +			SCTP_MALLOC(asc, struct sctp_asconf_iterator *,
  1.3251 +			            sizeof(struct sctp_asconf_iterator),
  1.3252 +			            SCTP_M_ASC_IT);
  1.3253 +			if (asc == NULL) {
  1.3254 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, ENOMEM);
  1.3255 +				return (ENOMEM);
  1.3256 +			}
  1.3257 +			wi = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr);
  1.3258 +			if (wi == NULL) {
  1.3259 +				SCTP_FREE(asc, SCTP_M_ASC_IT);
  1.3260 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, ENOMEM);
  1.3261 +				return (ENOMEM);
  1.3262 +			}
  1.3263 +			LIST_INIT(&asc->list_of_work);
  1.3264 +			asc->cnt = 1;
  1.3265 +			SCTP_INCR_LADDR_COUNT();
  1.3266 +			wi->ifa = ifa;
  1.3267 +			wi->action = type;
  1.3268 +			atomic_add_int(&ifa->refcount, 1);
  1.3269 +			LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr);
  1.3270 +			(void)sctp_initiate_iterator(sctp_asconf_iterator_ep,
  1.3271 +			                             sctp_asconf_iterator_stcb,
  1.3272 +			                             sctp_asconf_iterator_ep_end,
  1.3273 +			                             SCTP_PCB_ANY_FLAGS,
  1.3274 +			                             SCTP_PCB_ANY_FEATURES,
  1.3275 +			                             SCTP_ASOC_ANY_STATE,
  1.3276 +			                             (void *)asc, 0,
  1.3277 +			                             sctp_asconf_iterator_end, inp, 0);
  1.3278 +		}
  1.3279 +		return (0);
  1.3280 +	} else {
  1.3281 +		/* invalid address! */
  1.3282 +		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EADDRNOTAVAIL);
  1.3283 +		return (EADDRNOTAVAIL);
  1.3284 +	}
  1.3285 +}
  1.3286 +
  1.3287 +void
  1.3288 +sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb,
  1.3289 +				  struct sctp_nets *net)
  1.3290 +{
  1.3291 +	struct sctp_asconf_addr *aa;
  1.3292 +	struct sctp_ifa *sctp_ifap;
  1.3293 +	struct sctp_asconf_tag_param *vtag;
  1.3294 +#ifdef INET
  1.3295 +	struct sockaddr_in *to;
  1.3296 +#endif
  1.3297 +#ifdef INET6
  1.3298 +	struct sockaddr_in6 *to6;
  1.3299 +#endif
  1.3300 +	if (net == NULL) {
  1.3301 +		SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: Missing net\n");
  1.3302 +		return;
  1.3303 +	}
  1.3304 +	if (stcb == NULL) {
  1.3305 +		SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: Missing stcb\n");
  1.3306 +		return;
  1.3307 +	}
  1.3308 +  /* Need to have in the asconf:
  1.3309 +   * - vtagparam(my_vtag/peer_vtag)
  1.3310 +   * - add(0.0.0.0)
  1.3311 +   * - del(0.0.0.0)
  1.3312 +   * - Any global addresses add(addr)
  1.3313 +   */
  1.3314 +	SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
  1.3315 +	            SCTP_M_ASC_ADDR);
  1.3316 +	if (aa == NULL) {
  1.3317 +		/* didn't get memory */
  1.3318 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
  1.3319 +		        "sctp_asconf_send_nat_state_update: failed to get memory!\n");
  1.3320 +		return;
  1.3321 +	}
  1.3322 +	aa->special_del = 0;
  1.3323 +	/* fill in asconf address parameter fields */
  1.3324 +	/* top level elements are "networked" during send */
  1.3325 +	aa->ifa = NULL;
  1.3326 +	aa->sent = 0;		/* clear sent flag */
  1.3327 +	vtag = (struct sctp_asconf_tag_param *)&aa->ap.aph;
  1.3328 +	vtag->aph.ph.param_type = SCTP_NAT_VTAGS;
  1.3329 +	vtag->aph.ph.param_length = sizeof(struct sctp_asconf_tag_param);
  1.3330 +	vtag->local_vtag = htonl(stcb->asoc.my_vtag);
  1.3331 +	vtag->remote_vtag = htonl(stcb->asoc.peer_vtag);
  1.3332 +	TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
  1.3333 +
  1.3334 +	SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
  1.3335 +	            SCTP_M_ASC_ADDR);
  1.3336 +	if (aa == NULL) {
  1.3337 +		/* didn't get memory */
  1.3338 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
  1.3339 +		        "sctp_asconf_send_nat_state_update: failed to get memory!\n");
  1.3340 +		return;
  1.3341 +	}
  1.3342 +	memset(aa, 0, sizeof(struct sctp_asconf_addr));
  1.3343 +	/* fill in asconf address parameter fields */
  1.3344 +	/* ADD(0.0.0.0) */
  1.3345 +	switch (net->ro._l_addr.sa.sa_family) {
  1.3346 +#ifdef INET
  1.3347 +	case AF_INET:
  1.3348 +		aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
  1.3349 +		aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param);
  1.3350 +		aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
  1.3351 +		aa->ap.addrp.ph.param_length = sizeof (struct sctp_ipv4addr_param);
  1.3352 +		/* No need to add an address, we are using 0.0.0.0 */
  1.3353 +		TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
  1.3354 +		break;
  1.3355 +#endif
  1.3356 +#ifdef INET6
  1.3357 +	case AF_INET6:
  1.3358 +		aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
  1.3359 +		aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param);
  1.3360 +		aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
  1.3361 +		aa->ap.addrp.ph.param_length = sizeof (struct sctp_ipv6addr_param);
  1.3362 +		/* No need to add an address, we are using 0.0.0.0 */
  1.3363 +		TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
  1.3364 +		break;
  1.3365 +#endif
  1.3366 +	}
  1.3367 +	SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
  1.3368 +	            SCTP_M_ASC_ADDR);
  1.3369 +	if (aa == NULL) {
  1.3370 +		/* didn't get memory */
  1.3371 +		SCTPDBG(SCTP_DEBUG_ASCONF1,
  1.3372 +		        "sctp_asconf_send_nat_state_update: failed to get memory!\n");
  1.3373 +		return;
  1.3374 +	}
  1.3375 +	memset(aa, 0, sizeof(struct sctp_asconf_addr));
  1.3376 +	/* fill in asconf address parameter fields */
  1.3377 +	/* ADD(0.0.0.0) */
  1.3378 +	switch (net->ro._l_addr.sa.sa_family) {
  1.3379 +#ifdef INET
  1.3380 +	case AF_INET:
  1.3381 +		aa->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
  1.3382 +		aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param);
  1.3383 +		aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
  1.3384 +		aa->ap.addrp.ph.param_length = sizeof (struct sctp_ipv4addr_param);
  1.3385 +		/* No need to add an address, we are using 0.0.0.0 */
  1.3386 +		TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
  1.3387 +		break;
  1.3388 +#endif
  1.3389 +#ifdef INET6
  1.3390 +	case AF_INET6:
  1.3391 +		aa->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS;
  1.3392 +		aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param);
  1.3393 +		aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
  1.3394 +		aa->ap.addrp.ph.param_length = sizeof (struct sctp_ipv6addr_param);
  1.3395 +		/* No need to add an address, we are using 0.0.0.0 */
  1.3396 +		TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
  1.3397 +		break;
  1.3398 +#endif
  1.3399 +	}
  1.3400 +	/* Now we must hunt the addresses and add all global addresses */
  1.3401 +	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
  1.3402 +		struct sctp_vrf *vrf = NULL;
  1.3403 +		struct sctp_ifn *sctp_ifnp;
  1.3404 +		uint32_t vrf_id;
  1.3405 +
  1.3406 +		vrf_id = stcb->sctp_ep->def_vrf_id;
  1.3407 +		vrf = sctp_find_vrf(vrf_id);
  1.3408 +		if (vrf == NULL) {
  1.3409 +			goto skip_rest;
  1.3410 +		}
  1.3411 +
  1.3412 +		SCTP_IPI_ADDR_RLOCK();
  1.3413 +		LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) {
  1.3414 +			LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) {
  1.3415 +				switch (sctp_ifap->address.sa.sa_family) {
  1.3416 +#ifdef INET
  1.3417 +				case AF_INET:
  1.3418 +					to = &sctp_ifap->address.sin;
  1.3419 +					if (IN4_ISPRIVATE_ADDRESS(&to->sin_addr)) {
  1.3420 +						continue;
  1.3421 +					}
  1.3422 +					if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) {
  1.3423 +						continue;
  1.3424 +					}
  1.3425 +					break;
  1.3426 +#endif
  1.3427 +#ifdef INET6
  1.3428 +				case AF_INET6:
  1.3429 +					to6 = &sctp_ifap->address.sin6;
  1.3430 +					if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) {
  1.3431 +						continue;
  1.3432 +					}
  1.3433 +					if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) {
  1.3434 +						continue;
  1.3435 +					}
  1.3436 +					break;
  1.3437 +#endif
  1.3438 +				default:
  1.3439 +					continue;
  1.3440 +				}
  1.3441 +				sctp_asconf_queue_mgmt(stcb, sctp_ifap, SCTP_ADD_IP_ADDRESS);
  1.3442 +			}
  1.3443 +		}
  1.3444 +		SCTP_IPI_ADDR_RUNLOCK();
  1.3445 +	} else {
  1.3446 +		struct sctp_laddr *laddr;
  1.3447 +
  1.3448 +		LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) {
  1.3449 +			if (laddr->ifa == NULL) {
  1.3450 +				continue;
  1.3451 +			}
  1.3452 +			if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED)
  1.3453 +				/* Address being deleted by the system, dont
  1.3454 +				 * list.
  1.3455 +				 */
  1.3456 +				continue;
  1.3457 +			if (laddr->action == SCTP_DEL_IP_ADDRESS) {
  1.3458 +				/* Address being deleted on this ep
  1.3459 +				 * don't list.
  1.3460 +				 */
  1.3461 +				continue;
  1.3462 +			}
  1.3463 +			sctp_ifap = laddr->ifa;
  1.3464 +			switch (sctp_ifap->address.sa.sa_family) {
  1.3465 +#ifdef INET
  1.3466 +			case AF_INET:
  1.3467 +				to = &sctp_ifap->address.sin;
  1.3468 +				if (IN4_ISPRIVATE_ADDRESS(&to->sin_addr)) {
  1.3469 +					continue;
  1.3470 +				}
  1.3471 +				if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) {
  1.3472 +					continue;
  1.3473 +				}
  1.3474 +				break;
  1.3475 +#endif
  1.3476 +#ifdef INET6
  1.3477 +			case AF_INET6:
  1.3478 +				to6 = &sctp_ifap->address.sin6;
  1.3479 +				if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) {
  1.3480 +					continue;
  1.3481 +				}
  1.3482 +				if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) {
  1.3483 +					continue;
  1.3484 +				}
  1.3485 +				break;
  1.3486 +#endif
  1.3487 +			default:
  1.3488 +				continue;
  1.3489 +			}
  1.3490 +			sctp_asconf_queue_mgmt(stcb, sctp_ifap, SCTP_ADD_IP_ADDRESS);
  1.3491 +		}
  1.3492 +	}
  1.3493 + skip_rest:
  1.3494 +	/* Now we must send the asconf into the queue */
  1.3495 +	sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED);
  1.3496 +}

mercurial