netwerk/sctp/src/netinet/sctp_usrreq.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/netwerk/sctp/src/netinet/sctp_usrreq.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,8057 @@
     1.4 +/*-
     1.5 + * Copyright (c) 2001-2008, 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_usrreq.c 259943 2013-12-27 13:07:00Z tuexen $");
    1.39 +#endif
    1.40 +
    1.41 +#include <netinet/sctp_os.h>
    1.42 +#ifdef __FreeBSD__
    1.43 +#include <sys/proc.h>
    1.44 +#endif
    1.45 +#include <netinet/sctp_pcb.h>
    1.46 +#include <netinet/sctp_header.h>
    1.47 +#include <netinet/sctp_var.h>
    1.48 +#ifdef INET6
    1.49 +#if defined(__Userspace_os_FreeBSD)
    1.50 +#include <netinet6/sctp6_var.h>
    1.51 +#endif
    1.52 +#endif
    1.53 +#include <netinet/sctp_sysctl.h>
    1.54 +#include <netinet/sctp_output.h>
    1.55 +#include <netinet/sctp_uio.h>
    1.56 +#include <netinet/sctp_asconf.h>
    1.57 +#include <netinet/sctputil.h>
    1.58 +#include <netinet/sctp_indata.h>
    1.59 +#include <netinet/sctp_timer.h>
    1.60 +#include <netinet/sctp_auth.h>
    1.61 +#include <netinet/sctp_bsd_addr.h>
    1.62 +#if defined(__Userspace__)
    1.63 +#include <netinet/sctp_callout.h>
    1.64 +#endif
    1.65 +#if !defined(__Userspace_os_Windows)
    1.66 +#include <netinet/udp.h>
    1.67 +#endif
    1.68 +
    1.69 +#if defined(HAVE_SCTP_PEELOFF_SOCKOPT)
    1.70 +#include <netinet/sctp_peeloff.h>
    1.71 +#endif				/* HAVE_SCTP_PEELOFF_SOCKOPT */
    1.72 +
    1.73 +#if defined(__APPLE__)
    1.74 +#define APPLE_FILE_NO 7
    1.75 +#endif
    1.76 +
    1.77 +extern struct sctp_cc_functions sctp_cc_functions[];
    1.78 +extern struct sctp_ss_functions sctp_ss_functions[];
    1.79 +
    1.80 +void
    1.81 +#if defined(__Userspace__)
    1.82 +sctp_init(uint16_t port,
    1.83 +          int (*conn_output)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df),
    1.84 +          void (*debug_printf)(const char *format, ...))
    1.85 +#elif defined(__APPLE__) && (!defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) &&!defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION))
    1.86 +sctp_init(struct protosw *pp SCTP_UNUSED, struct domain *dp SCTP_UNUSED)
    1.87 +#else
    1.88 +sctp_init(void)
    1.89 +#endif
    1.90 +{
    1.91 +#if !defined(__Panda__) && !defined(__Userspace__)
    1.92 +	u_long sb_max_adj;
    1.93 +
    1.94 +#endif
    1.95 +#if defined(__Userspace__)
    1.96 +#if defined(__Userspace_os_Windows)
    1.97 +#if defined(INET) || defined(INET6)
    1.98 +	WSADATA wsaData;
    1.99 +
   1.100 +	if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
   1.101 +		SCTP_PRINTF("WSAStartup failed\n");
   1.102 +		exit (-1);
   1.103 +	}
   1.104 +#endif
   1.105 +	InitializeConditionVariable(&accept_cond);
   1.106 +	InitializeCriticalSection(&accept_mtx);
   1.107 +#else
   1.108 +	pthread_cond_init(&accept_cond, NULL);
   1.109 +	pthread_mutex_init(&accept_mtx, NULL);
   1.110 +#endif
   1.111 +#endif
   1.112 +	/* Initialize and modify the sysctled variables */
   1.113 +	sctp_init_sysctls();
   1.114 +#if defined(__Userspace__)
   1.115 +#if defined(__Userspace_os_Windows)
   1.116 +	srand((unsigned int)time(NULL));
   1.117 +#else
   1.118 +	srandom(getpid()); /* so inp->sctp_ep.random_numbers are truly random... */
   1.119 +#endif
   1.120 +#endif
   1.121 +#if defined(__Panda__)
   1.122 +	sctp_sendspace = SB_MAX;
   1.123 +	sctp_recvspace = SB_MAX;
   1.124 +
   1.125 +#elif defined(__Userspace__)
   1.126 +	SCTP_BASE_SYSCTL(sctp_sendspace) = SB_MAX;
   1.127 +	SCTP_BASE_SYSCTL(sctp_recvspace) = SB_RAW;
   1.128 +	SCTP_BASE_SYSCTL(sctp_udp_tunneling_port) = port;
   1.129 +#else
   1.130 +#if !defined(__APPLE__)
   1.131 +	if ((nmbclusters / 8) > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE)
   1.132 +		SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue) = (nmbclusters / 8);
   1.133 +#endif
   1.134 +	/*
   1.135 +	 * Allow a user to take no more than 1/2 the number of clusters or
   1.136 +	 * the SB_MAX whichever is smaller for the send window.
   1.137 +	 */
   1.138 +#if defined(__APPLE__)
   1.139 +	sb_max_adj = (u_long)((u_quad_t) (sb_max) * MCLBYTES / (MSIZE + MCLBYTES));
   1.140 +#else
   1.141 +	sb_max_adj = (u_long)((u_quad_t) (SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES));
   1.142 +#endif
   1.143 +#if defined(__APPLE__)
   1.144 +	SCTP_BASE_SYSCTL(sctp_sendspace) = sb_max_adj;
   1.145 +#else
   1.146 +	SCTP_BASE_SYSCTL(sctp_sendspace) = min(sb_max_adj,
   1.147 +	    (((uint32_t)nmbclusters / 2) * SCTP_DEFAULT_MAXSEGMENT));
   1.148 +#endif
   1.149 +	/*
   1.150 +	 * Now for the recv window, should we take the same amount? or
   1.151 +	 * should I do 1/2 the SB_MAX instead in the SB_MAX min above. For
   1.152 +	 * now I will just copy.
   1.153 +	 */
   1.154 +	SCTP_BASE_SYSCTL(sctp_recvspace) = SCTP_BASE_SYSCTL(sctp_sendspace);
   1.155 +#endif
   1.156 +	SCTP_BASE_VAR(first_time) = 0;
   1.157 +	SCTP_BASE_VAR(sctp_pcb_initialized) = 0;
   1.158 +#if defined(__Userspace__)
   1.159 +#if !defined(__Userspace_os_Windows)
   1.160 +#if defined(INET) || defined(INET6)
   1.161 +	SCTP_BASE_VAR(userspace_route) = -1;
   1.162 +#endif
   1.163 +#endif
   1.164 +#ifdef INET
   1.165 +	SCTP_BASE_VAR(userspace_rawsctp) = -1;
   1.166 +	SCTP_BASE_VAR(userspace_udpsctp) = -1;
   1.167 +#endif
   1.168 +#ifdef INET6
   1.169 +	SCTP_BASE_VAR(userspace_rawsctp6) = -1;
   1.170 +	SCTP_BASE_VAR(userspace_udpsctp6) = -1;
   1.171 +#endif
   1.172 +	SCTP_BASE_VAR(timer_thread_should_exit) = 0;
   1.173 +	SCTP_BASE_VAR(conn_output) = conn_output;
   1.174 +	SCTP_BASE_VAR(debug_printf) = debug_printf;
   1.175 +#endif
   1.176 +	sctp_pcb_init();
   1.177 +#if defined(__Userspace__)
   1.178 +	sctp_start_timer();
   1.179 +#endif
   1.180 +#if defined(SCTP_PACKET_LOGGING)
   1.181 +	SCTP_BASE_VAR(packet_log_writers) = 0;
   1.182 +	SCTP_BASE_VAR(packet_log_end) = 0;
   1.183 +	bzero(&SCTP_BASE_VAR(packet_log_buffer), SCTP_PACKET_LOG_SIZE);
   1.184 +#endif
   1.185 +#if defined(__APPLE__)
   1.186 +	SCTP_BASE_VAR(sctp_main_timer_ticks) = 0;
   1.187 +	sctp_start_main_timer();
   1.188 +	timeout(sctp_delayed_startup, NULL, 1);
   1.189 +#endif
   1.190 +}
   1.191 +
   1.192 +void
   1.193 +sctp_finish(void)
   1.194 +{
   1.195 +#if defined(__APPLE__)
   1.196 +	untimeout(sctp_delayed_startup, NULL);
   1.197 +	sctp_over_udp_stop();
   1.198 +	sctp_address_monitor_stop();
   1.199 +	sctp_stop_main_timer();
   1.200 +#endif
   1.201 +#if defined(__Userspace__)
   1.202 +#if defined(INET) || defined(INET6)
   1.203 +	recv_thread_destroy();
   1.204 +#endif
   1.205 +#if !defined(__Userspace_os_Windows)
   1.206 +#if defined(INET) || defined(INET6)
   1.207 +	if (SCTP_BASE_VAR(userspace_route) != -1) {
   1.208 +		pthread_join(SCTP_BASE_VAR(recvthreadroute), NULL);
   1.209 +	}
   1.210 +#endif
   1.211 +#endif
   1.212 +#ifdef INET
   1.213 +	if (SCTP_BASE_VAR(userspace_rawsctp) != -1) {
   1.214 +#if defined(__Userspace_os_Windows)
   1.215 +		WaitForSingleObject(SCTP_BASE_VAR(recvthreadraw), INFINITE);
   1.216 +		CloseHandle(SCTP_BASE_VAR(recvthreadraw));
   1.217 +#else
   1.218 +		pthread_join(SCTP_BASE_VAR(recvthreadraw), NULL);
   1.219 +#endif
   1.220 +	}
   1.221 +	if (SCTP_BASE_VAR(userspace_udpsctp) != -1) {
   1.222 +#if defined(__Userspace_os_Windows)
   1.223 +		WaitForSingleObject(SCTP_BASE_VAR(recvthreadudp), INFINITE);
   1.224 +		CloseHandle(SCTP_BASE_VAR(recvthreadudp));
   1.225 +#else
   1.226 +		pthread_join(SCTP_BASE_VAR(recvthreadudp), NULL);
   1.227 +#endif
   1.228 +	}
   1.229 +#endif
   1.230 +#ifdef INET6
   1.231 +	if (SCTP_BASE_VAR(userspace_rawsctp6) != -1) {
   1.232 +#if defined(__Userspace_os_Windows)
   1.233 +		WaitForSingleObject(SCTP_BASE_VAR(recvthreadraw6), INFINITE);
   1.234 +		CloseHandle(SCTP_BASE_VAR(recvthreadraw6));
   1.235 +#else
   1.236 +		pthread_join(SCTP_BASE_VAR(recvthreadraw6), NULL);
   1.237 +#endif
   1.238 +	}
   1.239 +	if (SCTP_BASE_VAR(userspace_udpsctp6) != -1) {
   1.240 +#if defined(__Userspace_os_Windows)
   1.241 +		WaitForSingleObject(SCTP_BASE_VAR(recvthreadudp6), INFINITE);
   1.242 +		CloseHandle(SCTP_BASE_VAR(recvthreadudp6));
   1.243 +#else
   1.244 +		pthread_join(SCTP_BASE_VAR(recvthreadudp6), NULL);
   1.245 +#endif
   1.246 +	}
   1.247 +#endif
   1.248 +	SCTP_BASE_VAR(timer_thread_should_exit) = 1;
   1.249 +#if defined(__Userspace_os_Windows)
   1.250 +	WaitForSingleObject(SCTP_BASE_VAR(timer_thread), INFINITE);
   1.251 +	CloseHandle(SCTP_BASE_VAR(timer_thread));
   1.252 +#else
   1.253 +	pthread_join(SCTP_BASE_VAR(timer_thread), NULL);
   1.254 +#endif
   1.255 +#endif
   1.256 +	sctp_pcb_finish();
   1.257 +#if defined(__Userspace__)
   1.258 +#if defined(__Userspace_os_Windows)
   1.259 +	DeleteConditionVariable(&accept_cond);
   1.260 +	DeleteCriticalSection(&accept_mtx);
   1.261 +#else
   1.262 +	pthread_cond_destroy(&accept_cond);
   1.263 +	pthread_mutex_destroy(&accept_mtx);
   1.264 +#endif
   1.265 +#endif
   1.266 +#if defined(__Windows__)
   1.267 +	sctp_finish_sysctls();
   1.268 +#if defined(INET) || defined(INET6)
   1.269 +	WSACleanup();
   1.270 +#endif
   1.271 +#endif
   1.272 +}
   1.273 +
   1.274 +
   1.275 +
   1.276 +void
   1.277 +sctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint16_t nxtsz)
   1.278 +{
   1.279 +	struct sctp_tmit_chunk *chk;
   1.280 +	uint16_t overhead;
   1.281 +
   1.282 +	/* Adjust that too */
   1.283 +	stcb->asoc.smallest_mtu = nxtsz;
   1.284 +	/* now off to subtract IP_DF flag if needed */
   1.285 +	overhead = IP_HDR_SIZE;
   1.286 +	if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) {
   1.287 +		overhead += sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id);
   1.288 +	}
   1.289 +	TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
   1.290 +		if ((chk->send_size + overhead) > nxtsz) {
   1.291 +			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
   1.292 +		}
   1.293 +	}
   1.294 +	TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
   1.295 +		if ((chk->send_size + overhead) > nxtsz) {
   1.296 +			/*
   1.297 +			 * For this guy we also mark for immediate resend
   1.298 +			 * since we sent to big of chunk
   1.299 +			 */
   1.300 +			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
   1.301 +			if (chk->sent < SCTP_DATAGRAM_RESEND) {
   1.302 +				sctp_flight_size_decrease(chk);
   1.303 +				sctp_total_flight_decrease(stcb, chk);
   1.304 +			}
   1.305 +			if (chk->sent != SCTP_DATAGRAM_RESEND) {
   1.306 +				sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
   1.307 +			}
   1.308 +			chk->sent = SCTP_DATAGRAM_RESEND;
   1.309 +			chk->rec.data.doing_fast_retransmit = 0;
   1.310 +			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
   1.311 +				sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU,
   1.312 +					       chk->whoTo->flight_size,
   1.313 +					       chk->book_size,
   1.314 +					       (uintptr_t)chk->whoTo,
   1.315 +					       chk->rec.data.TSN_seq);
   1.316 +			}
   1.317 +			/* Clear any time so NO RTT is being done */
   1.318 +			chk->do_rtt = 0;
   1.319 +		}
   1.320 +	}
   1.321 +}
   1.322 +
   1.323 +#ifdef INET
   1.324 +#if !defined(__Userspace__)
   1.325 +#if defined(__Panda__) || defined(__Windows__)
   1.326 +void
   1.327 +#else
   1.328 +static void
   1.329 +#endif
   1.330 +sctp_notify_mbuf(struct sctp_inpcb *inp,
   1.331 +    struct sctp_tcb *stcb,
   1.332 +    struct sctp_nets *net,
   1.333 +    struct ip *ip,
   1.334 +    struct sctphdr *sh)
   1.335 +{
   1.336 +	struct icmp *icmph;
   1.337 +	int totsz, tmr_stopped = 0;
   1.338 +	uint16_t nxtsz;
   1.339 +
   1.340 +	/* protection */
   1.341 +	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
   1.342 +	    (ip == NULL) || (sh == NULL)) {
   1.343 +		if (stcb != NULL) {
   1.344 +			SCTP_TCB_UNLOCK(stcb);
   1.345 +		}
   1.346 +		return;
   1.347 +	}
   1.348 +	/* First job is to verify the vtag matches what I would send */
   1.349 +	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
   1.350 +		SCTP_TCB_UNLOCK(stcb);
   1.351 +		return;
   1.352 +	}
   1.353 +	icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
   1.354 +	    sizeof(struct ip)));
   1.355 +	if (icmph->icmp_type != ICMP_UNREACH) {
   1.356 +		/* We only care about unreachable */
   1.357 +		SCTP_TCB_UNLOCK(stcb);
   1.358 +		return;
   1.359 +	}
   1.360 +	if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) {
   1.361 +		/* not a unreachable message due to frag. */
   1.362 +		SCTP_TCB_UNLOCK(stcb);
   1.363 +		return;
   1.364 +	}
   1.365 +#if defined(__FreeBSD__) && __FreeBSD_version >= 1000000
   1.366 +	totsz = ntohs(ip->ip_len);
   1.367 +#else
   1.368 +	totsz = ip->ip_len;
   1.369 +#endif
   1.370 +
   1.371 +	nxtsz = ntohs(icmph->icmp_nextmtu);
   1.372 +	if (nxtsz == 0) {
   1.373 +		/*
   1.374 +		 * old type router that does not tell us what the next size
   1.375 +		 * mtu is. Rats we will have to guess (in a educated fashion
   1.376 +		 * of course)
   1.377 +		 */
   1.378 +		nxtsz = sctp_get_prev_mtu(totsz);
   1.379 +	}
   1.380 +	/* Stop any PMTU timer */
   1.381 +	if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
   1.382 +		tmr_stopped = 1;
   1.383 +		sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
   1.384 +				SCTP_FROM_SCTP_USRREQ+SCTP_LOC_1);
   1.385 +	}
   1.386 +	/* Adjust destination size limit */
   1.387 +	if (net->mtu > nxtsz) {
   1.388 +		net->mtu = nxtsz;
   1.389 +		if (net->port) {
   1.390 +			net->mtu -= sizeof(struct udphdr);
   1.391 +		}
   1.392 +	}
   1.393 +	/* now what about the ep? */
   1.394 +	if (stcb->asoc.smallest_mtu > nxtsz) {
   1.395 +		sctp_pathmtu_adjustment(stcb, nxtsz);
   1.396 +	}
   1.397 +	if (tmr_stopped)
   1.398 +		sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
   1.399 +
   1.400 +	SCTP_TCB_UNLOCK(stcb);
   1.401 +}
   1.402 +#endif
   1.403 +#endif
   1.404 +
   1.405 +void
   1.406 +sctp_notify(struct sctp_inpcb *inp,
   1.407 +    struct ip *ip,
   1.408 +    struct sctphdr *sh,
   1.409 +    struct sockaddr *to,
   1.410 +    struct sctp_tcb *stcb,
   1.411 +    struct sctp_nets *net)
   1.412 +{
   1.413 +#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
   1.414 +	struct socket *so;
   1.415 +
   1.416 +#endif
   1.417 +	struct icmp *icmph;
   1.418 +
   1.419 +	/* protection */
   1.420 +	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
   1.421 +	    (sh == NULL) || (to == NULL)) {
   1.422 +		if (stcb)
   1.423 +			SCTP_TCB_UNLOCK(stcb);
   1.424 +		return;
   1.425 +	}
   1.426 +	/* First job is to verify the vtag matches what I would send */
   1.427 +	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
   1.428 +		SCTP_TCB_UNLOCK(stcb);
   1.429 +		return;
   1.430 +	}
   1.431 +
   1.432 +	icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
   1.433 +					       sizeof(struct ip)));
   1.434 +	if (icmph->icmp_type != ICMP_UNREACH) {
   1.435 +		/* We only care about unreachable */
   1.436 +		SCTP_TCB_UNLOCK(stcb);
   1.437 +		return;
   1.438 +	}
   1.439 +	if ((icmph->icmp_code == ICMP_UNREACH_NET) ||
   1.440 +	    (icmph->icmp_code == ICMP_UNREACH_HOST) ||
   1.441 +	    (icmph->icmp_code == ICMP_UNREACH_NET_UNKNOWN) ||
   1.442 +	    (icmph->icmp_code == ICMP_UNREACH_HOST_UNKNOWN) ||
   1.443 +	    (icmph->icmp_code == ICMP_UNREACH_ISOLATED) ||
   1.444 +	    (icmph->icmp_code == ICMP_UNREACH_NET_PROHIB) ||
   1.445 +	    (icmph->icmp_code == ICMP_UNREACH_HOST_PROHIB) ||
   1.446 +#if defined(__Panda__)
   1.447 +	    (icmph->icmp_code == ICMP_UNREACH_ADMIN)) {
   1.448 +#elif defined(__Userspace_os_NetBSD)
   1.449 +	    (icmph->icmp_code == ICMP_UNREACH_ADMIN_PROHIBIT)) {
   1.450 +#else
   1.451 +	    (icmph->icmp_code == ICMP_UNREACH_FILTER_PROHIB)) {
   1.452 +#endif
   1.453 +
   1.454 +		/*
   1.455 +		 * Hmm reachablity problems we must examine closely. If its
   1.456 +		 * not reachable, we may have lost a network. Or if there is
   1.457 +		 * NO protocol at the other end named SCTP. well we consider
   1.458 +		 * it a OOTB abort.
   1.459 +		 */
   1.460 +		if (net->dest_state & SCTP_ADDR_REACHABLE) {
   1.461 +			/* Ok that destination is NOT reachable */
   1.462 +			net->dest_state &= ~SCTP_ADDR_REACHABLE;
   1.463 +			net->dest_state &= ~SCTP_ADDR_PF;
   1.464 +			sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
   1.465 +					stcb, 0,
   1.466 +					(void *)net, SCTP_SO_NOT_LOCKED);
   1.467 +		}
   1.468 +		SCTP_TCB_UNLOCK(stcb);
   1.469 +	} else  if ((icmph->icmp_code == ICMP_UNREACH_PROTOCOL) ||
   1.470 +		    (icmph->icmp_code == ICMP_UNREACH_PORT)) {
   1.471 +		/*
   1.472 +		 * Here the peer is either playing tricks on us,
   1.473 +		 * including an address that belongs to someone who
   1.474 +		 * does not support SCTP OR was a userland
   1.475 +		 * implementation that shutdown and now is dead. In
   1.476 +		 * either case treat it like a OOTB abort with no
   1.477 +		 * TCB
   1.478 +		 */
   1.479 +		sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED);
   1.480 +#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
   1.481 +		so = SCTP_INP_SO(inp);
   1.482 +		atomic_add_int(&stcb->asoc.refcnt, 1);
   1.483 +		SCTP_TCB_UNLOCK(stcb);
   1.484 +		SCTP_SOCKET_LOCK(so, 1);
   1.485 +		SCTP_TCB_LOCK(stcb);
   1.486 +		atomic_subtract_int(&stcb->asoc.refcnt, 1);
   1.487 +#endif
   1.488 +		(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_2);
   1.489 +#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
   1.490 +		SCTP_SOCKET_UNLOCK(so, 1);
   1.491 +		/* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed.*/
   1.492 +#endif
   1.493 +		/* no need to unlock here, since the TCB is gone */
   1.494 +	} else {
   1.495 +		SCTP_TCB_UNLOCK(stcb);
   1.496 +	}
   1.497 +}
   1.498 +
   1.499 +#ifdef INET
   1.500 +#if !defined(__Panda__) && !defined(__Userspace__)
   1.501 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
   1.502 +void
   1.503 +#else
   1.504 +void *
   1.505 +#endif
   1.506 +sctp_ctlinput(cmd, sa, vip)
   1.507 +	int cmd;
   1.508 +	struct sockaddr *sa;
   1.509 +	void *vip;
   1.510 +{
   1.511 +	struct ip *ip = vip;
   1.512 +	struct sctphdr *sh;
   1.513 +	uint32_t vrf_id;
   1.514 +	/* FIX, for non-bsd is this right? */
   1.515 +	vrf_id = SCTP_DEFAULT_VRFID;
   1.516 +	if (sa->sa_family != AF_INET ||
   1.517 +	    ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) {
   1.518 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
   1.519 +		return;
   1.520 +#else
   1.521 +		return (NULL);
   1.522 +#endif
   1.523 +	}
   1.524 +	if (PRC_IS_REDIRECT(cmd)) {
   1.525 +		ip = 0;
   1.526 +	} else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) {
   1.527 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
   1.528 +		return;
   1.529 +#else
   1.530 +		return (NULL);
   1.531 +#endif
   1.532 +	}
   1.533 +	if (ip) {
   1.534 +		struct sctp_inpcb *inp = NULL;
   1.535 +		struct sctp_tcb *stcb = NULL;
   1.536 +		struct sctp_nets *net = NULL;
   1.537 +		struct sockaddr_in to, from;
   1.538 +
   1.539 +		sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2));
   1.540 +		bzero(&to, sizeof(to));
   1.541 +		bzero(&from, sizeof(from));
   1.542 +		from.sin_family = to.sin_family = AF_INET;
   1.543 +#ifdef HAVE_SIN_LEN
   1.544 +		from.sin_len = to.sin_len = sizeof(to);
   1.545 +#endif
   1.546 +		from.sin_port = sh->src_port;
   1.547 +		from.sin_addr = ip->ip_src;
   1.548 +		to.sin_port = sh->dest_port;
   1.549 +		to.sin_addr = ip->ip_dst;
   1.550 +
   1.551 +		/*
   1.552 +		 * 'to' holds the dest of the packet that failed to be sent.
   1.553 +		 * 'from' holds our local endpoint address. Thus we reverse
   1.554 +		 * the to and the from in the lookup.
   1.555 +		 */
   1.556 +		stcb = sctp_findassociation_addr_sa((struct sockaddr *)&to,
   1.557 +		    (struct sockaddr *)&from,
   1.558 +		    &inp, &net, 1, vrf_id);
   1.559 +		if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
   1.560 +			if (cmd != PRC_MSGSIZE) {
   1.561 +				sctp_notify(inp, ip, sh,
   1.562 +				    (struct sockaddr *)&to, stcb,
   1.563 +				    net);
   1.564 +			} else {
   1.565 +				/* handle possible ICMP size messages */
   1.566 +				sctp_notify_mbuf(inp, stcb, net, ip, sh);
   1.567 +			}
   1.568 +		} else {
   1.569 +#if defined(__FreeBSD__) && __FreeBSD_version < 500000
   1.570 +			/*
   1.571 +			 * XXX must be fixed for 5.x and higher, leave for
   1.572 +			 * 4.x
   1.573 +			 */
   1.574 +			if (PRC_IS_REDIRECT(cmd) && inp) {
   1.575 +				in_rtchange((struct inpcb *)inp,
   1.576 +				    inetctlerrmap[cmd]);
   1.577 +			}
   1.578 +#endif
   1.579 +			if ((stcb == NULL) && (inp != NULL)) {
   1.580 +				/* reduce ref-count */
   1.581 +				SCTP_INP_WLOCK(inp);
   1.582 +				SCTP_INP_DECR_REF(inp);
   1.583 +				SCTP_INP_WUNLOCK(inp);
   1.584 +			}
   1.585 +			if (stcb) {
   1.586 +				SCTP_TCB_UNLOCK(stcb);
   1.587 +			}
   1.588 +		}
   1.589 +	}
   1.590 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
   1.591 +	return;
   1.592 +#else
   1.593 +	return (NULL);
   1.594 +#endif
   1.595 +}
   1.596 +#endif
   1.597 +#endif
   1.598 +
   1.599 +#if defined(__FreeBSD__)
   1.600 +static int
   1.601 +sctp_getcred(SYSCTL_HANDLER_ARGS)
   1.602 +{
   1.603 +	struct xucred xuc;
   1.604 +	struct sockaddr_in addrs[2];
   1.605 +	struct sctp_inpcb *inp;
   1.606 +	struct sctp_nets *net;
   1.607 +	struct sctp_tcb *stcb;
   1.608 +	int error;
   1.609 +	uint32_t vrf_id;
   1.610 +
   1.611 +	/* FIX, for non-bsd is this right? */
   1.612 +	vrf_id = SCTP_DEFAULT_VRFID;
   1.613 +
   1.614 +#if __FreeBSD_version > 602000
   1.615 +	error = priv_check(req->td, PRIV_NETINET_GETCRED);
   1.616 +
   1.617 +#elif __FreeBSD_version >= 500000
   1.618 +	error = suser(req->td);
   1.619 +#else
   1.620 +	error = suser(req->p);
   1.621 +#endif
   1.622 +	if (error)
   1.623 +		return (error);
   1.624 +
   1.625 +	error = SYSCTL_IN(req, addrs, sizeof(addrs));
   1.626 +	if (error)
   1.627 +		return (error);
   1.628 +
   1.629 +	stcb = sctp_findassociation_addr_sa(sintosa(&addrs[1]),
   1.630 +	    sintosa(&addrs[0]),
   1.631 +	    &inp, &net, 1, vrf_id);
   1.632 +	if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
   1.633 +		if ((inp != NULL) && (stcb == NULL)) {
   1.634 +			/* reduce ref-count */
   1.635 +			SCTP_INP_WLOCK(inp);
   1.636 +			SCTP_INP_DECR_REF(inp);
   1.637 +			goto cred_can_cont;
   1.638 +		}
   1.639 +
   1.640 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
   1.641 +		error = ENOENT;
   1.642 +		goto out;
   1.643 +	}
   1.644 +	SCTP_TCB_UNLOCK(stcb);
   1.645 +	/* We use the write lock here, only
   1.646 +	 * since in the error leg we need it.
   1.647 +	 * If we used RLOCK, then we would have
   1.648 +	 * to wlock/decr/unlock/rlock. Which
   1.649 +	 * in theory could create a hole. Better
   1.650 +	 * to use higher wlock.
   1.651 +	 */
   1.652 +	SCTP_INP_WLOCK(inp);
   1.653 + cred_can_cont:
   1.654 +	error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
   1.655 +	if (error) {
   1.656 +		SCTP_INP_WUNLOCK(inp);
   1.657 +		goto out;
   1.658 +	}
   1.659 +	cru2x(inp->sctp_socket->so_cred, &xuc);
   1.660 +	SCTP_INP_WUNLOCK(inp);
   1.661 +	error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
   1.662 +out:
   1.663 +	return (error);
   1.664 +}
   1.665 +
   1.666 +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
   1.667 +    0, 0, sctp_getcred, "S,ucred", "Get the ucred of a SCTP connection");
   1.668 +#endif				/* #if defined(__FreeBSD__) */
   1.669 +
   1.670 +
   1.671 +#ifdef INET
   1.672 +#if defined(__Panda__) || defined(__Windows__) || defined(__Userspace__)
   1.673 +int
   1.674 +#elif defined(__FreeBSD__) && __FreeBSD_version > 690000
   1.675 +static void
   1.676 +#else
   1.677 +static int
   1.678 +#endif
   1.679 +sctp_abort(struct socket *so)
   1.680 +{
   1.681 +	struct sctp_inpcb *inp;
   1.682 +	uint32_t flags;
   1.683 +
   1.684 +	inp = (struct sctp_inpcb *)so->so_pcb;
   1.685 +	if (inp == NULL) {
   1.686 +#if defined(__FreeBSD__) && __FreeBSD_version > 690000
   1.687 +		return;
   1.688 +#else
   1.689 +		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
   1.690 +		return (EINVAL);
   1.691 +#endif
   1.692 +	}
   1.693 +
   1.694 + sctp_must_try_again:
   1.695 +	flags = inp->sctp_flags;
   1.696 +#ifdef SCTP_LOG_CLOSING
   1.697 +	sctp_log_closing(inp, NULL, 17);
   1.698 +#endif
   1.699 +	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
   1.700 +	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
   1.701 +#ifdef SCTP_LOG_CLOSING
   1.702 +		sctp_log_closing(inp, NULL, 16);
   1.703 +#endif
   1.704 +		sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
   1.705 +				SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
   1.706 +		SOCK_LOCK(so);
   1.707 +		SCTP_SB_CLEAR(so->so_snd);
   1.708 +		/* same for the rcv ones, they are only
   1.709 +		 * here for the accounting/select.
   1.710 +		 */
   1.711 +		SCTP_SB_CLEAR(so->so_rcv);
   1.712 +
   1.713 +#if defined(__APPLE__)
   1.714 +		so->so_usecount--;
   1.715 +#else
   1.716 +		/* Now null out the reference, we are completely detached. */
   1.717 +		so->so_pcb = NULL;
   1.718 +#endif
   1.719 +		SOCK_UNLOCK(so);
   1.720 +	} else {
   1.721 +		flags = inp->sctp_flags;
   1.722 +		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
   1.723 +			goto sctp_must_try_again;
   1.724 +		}
   1.725 +	}
   1.726 +#if defined(__FreeBSD__) && __FreeBSD_version > 690000
   1.727 +	return;
   1.728 +#else
   1.729 +	return (0);
   1.730 +#endif
   1.731 +}
   1.732 +
   1.733 +#if defined(__Panda__) || defined(__Userspace__)
   1.734 +int
   1.735 +#else
   1.736 +static int
   1.737 +#endif
   1.738 +#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
   1.739 +sctp_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED)
   1.740 +#elif defined(__Panda__) || defined(__Userspace__)
   1.741 +sctp_attach(struct socket *so, int proto SCTP_UNUSED, uint32_t vrf_id)
   1.742 +#elif defined(__Windows__)
   1.743 +sctp_attach(struct socket *so, int proto SCTP_UNUSED, PKTHREAD p SCTP_UNUSED)
   1.744 +#else
   1.745 +sctp_attach(struct socket *so, int proto SCTP_UNUSED, struct proc *p SCTP_UNUSED)
   1.746 +#endif
   1.747 +{
   1.748 +	struct sctp_inpcb *inp;
   1.749 +	struct inpcb *ip_inp;
   1.750 +	int error;
   1.751 +#if !defined(__Panda__) && !defined(__Userspace__)
   1.752 +	uint32_t vrf_id = SCTP_DEFAULT_VRFID;
   1.753 +#endif
   1.754 +#ifdef IPSEC
   1.755 +	uint32_t flags;
   1.756 +#endif
   1.757 +
   1.758 +	inp = (struct sctp_inpcb *)so->so_pcb;
   1.759 +	if (inp != 0) {
   1.760 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
   1.761 +		return (EINVAL);
   1.762 +	}
   1.763 +	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
   1.764 +		error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace));
   1.765 +		if (error) {
   1.766 +			return (error);
   1.767 +		}
   1.768 +	}
   1.769 +	error = sctp_inpcb_alloc(so, vrf_id);
   1.770 +	if (error) {
   1.771 +		return (error);
   1.772 +	}
   1.773 +	inp = (struct sctp_inpcb *)so->so_pcb;
   1.774 +	SCTP_INP_WLOCK(inp);
   1.775 +	inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6;	/* I'm not v6! */
   1.776 +	ip_inp = &inp->ip_inp.inp;
   1.777 +	ip_inp->inp_vflag |= INP_IPV4;
   1.778 +	ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
   1.779 +#ifdef IPSEC
   1.780 +#if !(defined(__APPLE__))
   1.781 +	error = ipsec_init_policy(so, &ip_inp->inp_sp);
   1.782 +#ifdef SCTP_LOG_CLOSING
   1.783 +	sctp_log_closing(inp, NULL, 17);
   1.784 +#endif
   1.785 +	if (error != 0) {
   1.786 +	try_again:
   1.787 +		flags = inp->sctp_flags;
   1.788 +		if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
   1.789 +		    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
   1.790 +#ifdef SCTP_LOG_CLOSING
   1.791 +			sctp_log_closing(inp, NULL, 15);
   1.792 +#endif
   1.793 +			SCTP_INP_WUNLOCK(inp);
   1.794 +			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
   1.795 +					SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
   1.796 +		} else {
   1.797 +			flags = inp->sctp_flags;
   1.798 +			if ((flags &  SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
   1.799 +				goto try_again;
   1.800 +			} else {
   1.801 +				SCTP_INP_WUNLOCK(inp);
   1.802 +			}
   1.803 +		}
   1.804 +		return (error);
   1.805 +	}
   1.806 +#endif
   1.807 +#endif				/* IPSEC */
   1.808 +	SCTP_INP_WUNLOCK(inp);
   1.809 +	return (0);
   1.810 +}
   1.811 +
   1.812 +#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
   1.813 +static int
   1.814 +sctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
   1.815 +{
   1.816 +#elif defined(__FreeBSD__) || defined(__APPLE__)
   1.817 +static int
   1.818 +sctp_bind(struct socket *so, struct sockaddr *addr, struct proc *p) {
   1.819 +#elif defined(__Panda__) || defined(__Userspace__)
   1.820 +int
   1.821 +sctp_bind(struct socket *so, struct sockaddr *addr) {
   1.822 +	void *p = NULL;
   1.823 +#elif defined(__Windows__)
   1.824 +static int
   1.825 +sctp_bind(struct socket *so, struct sockaddr *addr, PKTHREAD p) {
   1.826 +#else
   1.827 +static int
   1.828 +sctp_bind(struct socket *so, struct mbuf *nam, struct proc *p)
   1.829 +{
   1.830 +	struct sockaddr *addr = nam ? mtod(nam, struct sockaddr *): NULL;
   1.831 +
   1.832 +#endif
   1.833 +	struct sctp_inpcb *inp;
   1.834 +
   1.835 +	inp = (struct sctp_inpcb *)so->so_pcb;
   1.836 +	if (inp == NULL) {
   1.837 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
   1.838 +		return (EINVAL);
   1.839 +	}
   1.840 +	if (addr != NULL) {
   1.841 +#ifdef HAVE_SA_LEN
   1.842 +		if ((addr->sa_family != AF_INET) ||
   1.843 +		    (addr->sa_len != sizeof(struct sockaddr_in))) {
   1.844 +#else
   1.845 +		if (addr->sa_family != AF_INET) {
   1.846 +#endif
   1.847 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
   1.848 +			return (EINVAL);
   1.849 +		}
   1.850 +	}
   1.851 +	return (sctp_inpcb_bind(so, addr, NULL, p));
   1.852 +}
   1.853 +
   1.854 +#endif
   1.855 +#if defined(__Userspace__)
   1.856 +
   1.857 +int
   1.858 +sctpconn_attach(struct socket *so, int proto SCTP_UNUSED, uint32_t vrf_id)
   1.859 +{
   1.860 +	struct sctp_inpcb *inp;
   1.861 +	struct inpcb *ip_inp;
   1.862 +	int error;
   1.863 +
   1.864 +	inp = (struct sctp_inpcb *)so->so_pcb;
   1.865 +	if (inp != NULL) {
   1.866 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
   1.867 +		return (EINVAL);
   1.868 +	}
   1.869 +	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
   1.870 +		error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace));
   1.871 +		if (error) {
   1.872 +			return (error);
   1.873 +		}
   1.874 +	}
   1.875 +	error = sctp_inpcb_alloc(so, vrf_id);
   1.876 +	if (error) {
   1.877 +		return (error);
   1.878 +	}
   1.879 +	inp = (struct sctp_inpcb *)so->so_pcb;
   1.880 +	SCTP_INP_WLOCK(inp);
   1.881 +	inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6;
   1.882 +	inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_CONN;
   1.883 +	ip_inp = &inp->ip_inp.inp;
   1.884 +	ip_inp->inp_vflag |= INP_CONN;
   1.885 +	ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
   1.886 +	SCTP_INP_WUNLOCK(inp);
   1.887 +	return (0);
   1.888 +}
   1.889 +
   1.890 +int
   1.891 +sctpconn_bind(struct socket *so, struct sockaddr *addr)
   1.892 +{
   1.893 +	struct sctp_inpcb *inp;
   1.894 +
   1.895 +	inp = (struct sctp_inpcb *)so->so_pcb;
   1.896 +	if (inp == NULL) {
   1.897 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
   1.898 +		return (EINVAL);
   1.899 +	}
   1.900 +	if (addr != NULL) {
   1.901 +#ifdef HAVE_SA_LEN
   1.902 +		if ((addr->sa_family != AF_CONN) ||
   1.903 +		    (addr->sa_len != sizeof(struct sockaddr_conn))) {
   1.904 +#else
   1.905 +		if (addr->sa_family != AF_CONN) {
   1.906 +#endif
   1.907 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
   1.908 +			return (EINVAL);
   1.909 +		}
   1.910 +	}
   1.911 +	return (sctp_inpcb_bind(so, addr, NULL, NULL));
   1.912 +}
   1.913 +
   1.914 +#endif
   1.915 +#if (defined(__FreeBSD__) && __FreeBSD_version > 690000) || defined(__Windows__) || defined(__Userspace__)
   1.916 +void
   1.917 +sctp_close(struct socket *so)
   1.918 +{
   1.919 +	struct sctp_inpcb *inp;
   1.920 +	uint32_t flags;
   1.921 +
   1.922 +	inp = (struct sctp_inpcb *)so->so_pcb;
   1.923 +	if (inp == NULL)
   1.924 +		return;
   1.925 +
   1.926 +	/* Inform all the lower layer assoc that we
   1.927 +	 * are done.
   1.928 +	 */
   1.929 + sctp_must_try_again:
   1.930 +	flags = inp->sctp_flags;
   1.931 +#ifdef SCTP_LOG_CLOSING
   1.932 +	sctp_log_closing(inp, NULL, 17);
   1.933 +#endif
   1.934 +	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
   1.935 +	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
   1.936 +#if defined(__Userspace__)
   1.937 +		if (((so->so_options & SCTP_SO_LINGER) && (so->so_linger == 0)) ||
   1.938 +		    (so->so_rcv.sb_cc > 0)) {
   1.939 +#else
   1.940 +		if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
   1.941 +		    (so->so_rcv.sb_cc > 0)) {
   1.942 +#endif
   1.943 +#ifdef SCTP_LOG_CLOSING
   1.944 +			sctp_log_closing(inp, NULL, 13);
   1.945 +#endif
   1.946 +			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
   1.947 +					SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
   1.948 +		} else {
   1.949 +#ifdef SCTP_LOG_CLOSING
   1.950 +			sctp_log_closing(inp, NULL, 14);
   1.951 +#endif
   1.952 +			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE,
   1.953 +					SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
   1.954 +		}
   1.955 +		/* The socket is now detached, no matter what
   1.956 +		 * the state of the SCTP association.
   1.957 +		 */
   1.958 +		SOCK_LOCK(so);
   1.959 +		SCTP_SB_CLEAR(so->so_snd);
   1.960 +		/* same for the rcv ones, they are only
   1.961 +		 * here for the accounting/select.
   1.962 +		 */
   1.963 +		SCTP_SB_CLEAR(so->so_rcv);
   1.964 +
   1.965 +#if !defined(__APPLE__)
   1.966 +		/* Now null out the reference, we are completely detached. */
   1.967 +		so->so_pcb = NULL;
   1.968 +#endif
   1.969 +		SOCK_UNLOCK(so);
   1.970 +	} else {
   1.971 +		flags = inp->sctp_flags;
   1.972 +		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
   1.973 +			goto sctp_must_try_again;
   1.974 +		}
   1.975 +	}
   1.976 +	return;
   1.977 +}
   1.978 +
   1.979 +#else
   1.980 +
   1.981 +
   1.982 +int
   1.983 +sctp_detach(struct socket *so)
   1.984 +{
   1.985 +	struct sctp_inpcb *inp;
   1.986 +	uint32_t flags;
   1.987 +
   1.988 +	inp = (struct sctp_inpcb *)so->so_pcb;
   1.989 +	if (inp == NULL) {
   1.990 +#if defined(__FreeBSD__) && __FreeBSD_version > 690000
   1.991 +		return;
   1.992 +#else
   1.993 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
   1.994 +		return (EINVAL);
   1.995 +#endif
   1.996 +	}
   1.997 + sctp_must_try_again:
   1.998 +	flags = inp->sctp_flags;
   1.999 +#ifdef SCTP_LOG_CLOSING
  1.1000 +	sctp_log_closing(inp, NULL, 17);
  1.1001 +#endif
  1.1002 +	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
  1.1003 +	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
  1.1004 +#if defined(__Userspace__)
  1.1005 +		if (((so->so_options & SCTP_SO_LINGER) && (so->so_linger == 0)) ||
  1.1006 +		    (so->so_rcv.sb_cc > 0)) {
  1.1007 +#else
  1.1008 +		if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
  1.1009 +		    (so->so_rcv.sb_cc > 0)) {
  1.1010 +#endif
  1.1011 +#ifdef SCTP_LOG_CLOSING
  1.1012 +			sctp_log_closing(inp, NULL, 13);
  1.1013 +#endif
  1.1014 +			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
  1.1015 +					SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
  1.1016 +		} else {
  1.1017 +#ifdef SCTP_LOG_CLOSING
  1.1018 +			sctp_log_closing(inp, NULL, 13);
  1.1019 +#endif
  1.1020 +			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE,
  1.1021 +					SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
  1.1022 +		}
  1.1023 +		/* The socket is now detached, no matter what
  1.1024 +		 * the state of the SCTP association.
  1.1025 +		 */
  1.1026 +		SCTP_SB_CLEAR(so->so_snd);
  1.1027 +		/* same for the rcv ones, they are only
  1.1028 +		 * here for the accounting/select.
  1.1029 +		 */
  1.1030 +		SCTP_SB_CLEAR(so->so_rcv);
  1.1031 +#if !defined(__APPLE__)
  1.1032 +		/* Now disconnect */
  1.1033 +		so->so_pcb = NULL;
  1.1034 +#endif
  1.1035 +	} else {
  1.1036 +		flags = inp->sctp_flags;
  1.1037 +		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
  1.1038 +			goto sctp_must_try_again;
  1.1039 +		}
  1.1040 +	}
  1.1041 +#if defined(__FreeBSD__) && __FreeBSD_version > 690000
  1.1042 +	return;
  1.1043 +#else
  1.1044 +	return (0);
  1.1045 +#endif
  1.1046 +}
  1.1047 +#endif
  1.1048 +
  1.1049 +#if defined(__Userspace__)
  1.1050 +/* __Userspace__ is not calling sctp_sendm */
  1.1051 +#endif
  1.1052 +#if !(defined(__Panda__) || defined(__Windows__))
  1.1053 +int
  1.1054 +#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
  1.1055 +sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
  1.1056 +    struct mbuf *control, struct thread *p);
  1.1057 +
  1.1058 +#else
  1.1059 +sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
  1.1060 +    struct mbuf *control, struct proc *p);
  1.1061 +
  1.1062 +#endif
  1.1063 +
  1.1064 +int
  1.1065 +#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
  1.1066 +sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
  1.1067 +    struct mbuf *control, struct thread *p)
  1.1068 +{
  1.1069 +#else
  1.1070 +sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
  1.1071 +    struct mbuf *control, struct proc *p)
  1.1072 +{
  1.1073 +#endif
  1.1074 +	struct sctp_inpcb *inp;
  1.1075 +	int error;
  1.1076 +
  1.1077 +	inp = (struct sctp_inpcb *)so->so_pcb;
  1.1078 +	if (inp == NULL) {
  1.1079 +		if (control) {
  1.1080 +			sctp_m_freem(control);
  1.1081 +			control = NULL;
  1.1082 +		}
  1.1083 +		SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.1084 +		sctp_m_freem(m);
  1.1085 +		return (EINVAL);
  1.1086 +	}
  1.1087 +	/* Got to have an to address if we are NOT a connected socket */
  1.1088 +	if ((addr == NULL) &&
  1.1089 +	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) ||
  1.1090 +	    (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE))) {
  1.1091 +		goto connected_type;
  1.1092 +	} else if (addr == NULL) {
  1.1093 +		SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ);
  1.1094 +		error = EDESTADDRREQ;
  1.1095 +		sctp_m_freem(m);
  1.1096 +		if (control) {
  1.1097 +			sctp_m_freem(control);
  1.1098 +			control = NULL;
  1.1099 +		}
  1.1100 +		return (error);
  1.1101 +	}
  1.1102 +#ifdef INET6
  1.1103 +	if (addr->sa_family != AF_INET) {
  1.1104 +		/* must be a v4 address! */
  1.1105 +		SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ);
  1.1106 +		sctp_m_freem(m);
  1.1107 +		if (control) {
  1.1108 +			sctp_m_freem(control);
  1.1109 +			control = NULL;
  1.1110 +		}
  1.1111 +		error = EDESTADDRREQ;
  1.1112 +		return (error);
  1.1113 +	}
  1.1114 +#endif				/* INET6 */
  1.1115 +connected_type:
  1.1116 +	/* now what about control */
  1.1117 +	if (control) {
  1.1118 +		if (inp->control) {
  1.1119 +			SCTP_PRINTF("huh? control set?\n");
  1.1120 +			sctp_m_freem(inp->control);
  1.1121 +			inp->control = NULL;
  1.1122 +		}
  1.1123 +		inp->control = control;
  1.1124 +	}
  1.1125 +	/* Place the data */
  1.1126 +	if (inp->pkt) {
  1.1127 +		SCTP_BUF_NEXT(inp->pkt_last) = m;
  1.1128 +		inp->pkt_last = m;
  1.1129 +	} else {
  1.1130 +		inp->pkt_last = inp->pkt = m;
  1.1131 +	}
  1.1132 +	if (
  1.1133 +#if defined(__FreeBSD__) || defined(__APPLE__)
  1.1134 +	/* FreeBSD uses a flag passed */
  1.1135 +	    ((flags & PRUS_MORETOCOME) == 0)
  1.1136 +#else
  1.1137 +	    1			/* Open BSD does not have any "more to come"
  1.1138 +				 * indication */
  1.1139 +#endif
  1.1140 +	    ) {
  1.1141 +		/*
  1.1142 +		 * note with the current version this code will only be used
  1.1143 +		 * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for
  1.1144 +		 * re-defining sosend to use the sctp_sosend. One can
  1.1145 +		 * optionally switch back to this code (by changing back the
  1.1146 +		 * definitions) but this is not advisable. This code is used
  1.1147 +		 * by FreeBSD when sending a file with sendfile() though.
  1.1148 +		 */
  1.1149 +		int ret;
  1.1150 +
  1.1151 +		ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
  1.1152 +		inp->pkt = NULL;
  1.1153 +		inp->control = NULL;
  1.1154 +		return (ret);
  1.1155 +	} else {
  1.1156 +		return (0);
  1.1157 +	}
  1.1158 +}
  1.1159 +#endif
  1.1160 +
  1.1161 +int
  1.1162 +sctp_disconnect(struct socket *so)
  1.1163 +{
  1.1164 +	struct sctp_inpcb *inp;
  1.1165 +
  1.1166 +	inp = (struct sctp_inpcb *)so->so_pcb;
  1.1167 +	if (inp == NULL) {
  1.1168 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
  1.1169 +		return (ENOTCONN);
  1.1170 +	}
  1.1171 +	SCTP_INP_RLOCK(inp);
  1.1172 +	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.1173 +	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
  1.1174 +		if (LIST_EMPTY(&inp->sctp_asoc_list)) {
  1.1175 +			/* No connection */
  1.1176 +			SCTP_INP_RUNLOCK(inp);
  1.1177 +			return (0);
  1.1178 +		} else {
  1.1179 +			struct sctp_association *asoc;
  1.1180 +			struct sctp_tcb *stcb;
  1.1181 +
  1.1182 +			stcb = LIST_FIRST(&inp->sctp_asoc_list);
  1.1183 +			if (stcb == NULL) {
  1.1184 +				SCTP_INP_RUNLOCK(inp);
  1.1185 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.1186 +				return (EINVAL);
  1.1187 +			}
  1.1188 +			SCTP_TCB_LOCK(stcb);
  1.1189 +			asoc = &stcb->asoc;
  1.1190 +			if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
  1.1191 +				/* We are about to be freed, out of here */
  1.1192 +				SCTP_TCB_UNLOCK(stcb);
  1.1193 +				SCTP_INP_RUNLOCK(inp);
  1.1194 +				return (0);
  1.1195 +			}
  1.1196 +#if defined(__Userspace__)
  1.1197 +			if (((so->so_options & SCTP_SO_LINGER) &&
  1.1198 +			     (so->so_linger == 0)) ||
  1.1199 +			    (so->so_rcv.sb_cc > 0)) {
  1.1200 +#else
  1.1201 +			if (((so->so_options & SO_LINGER) &&
  1.1202 +			     (so->so_linger == 0)) ||
  1.1203 +			    (so->so_rcv.sb_cc > 0)) {
  1.1204 +#endif
  1.1205 +				if (SCTP_GET_STATE(asoc) !=
  1.1206 +				    SCTP_STATE_COOKIE_WAIT) {
  1.1207 +					/* Left with Data unread */
  1.1208 +					struct mbuf *err;
  1.1209 +
  1.1210 +					err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA);
  1.1211 +					if (err) {
  1.1212 +						/*
  1.1213 +						 * Fill in the user
  1.1214 +						 * initiated abort
  1.1215 +						 */
  1.1216 +						struct sctp_paramhdr *ph;
  1.1217 +
  1.1218 +						ph = mtod(err, struct sctp_paramhdr *);
  1.1219 +						SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr);
  1.1220 +						ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
  1.1221 +						ph->param_length = htons(SCTP_BUF_LEN(err));
  1.1222 +					}
  1.1223 +					sctp_send_abort_tcb(stcb, err, SCTP_SO_LOCKED);
  1.1224 +					SCTP_STAT_INCR_COUNTER32(sctps_aborted);
  1.1225 +				}
  1.1226 +				SCTP_INP_RUNLOCK(inp);
  1.1227 +				if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
  1.1228 +				    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
  1.1229 +					SCTP_STAT_DECR_GAUGE32(sctps_currestab);
  1.1230 +				}
  1.1231 +				(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_3);
  1.1232 +				/* No unlock tcb assoc is gone */
  1.1233 +				return (0);
  1.1234 +			}
  1.1235 +			if (TAILQ_EMPTY(&asoc->send_queue) &&
  1.1236 +			    TAILQ_EMPTY(&asoc->sent_queue) &&
  1.1237 +			    (asoc->stream_queue_cnt == 0)) {
  1.1238 +				/* there is nothing queued to send, so done */
  1.1239 +				if (asoc->locked_on_sending) {
  1.1240 +					goto abort_anyway;
  1.1241 +				}
  1.1242 +				if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
  1.1243 +				    (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
  1.1244 +					/* only send SHUTDOWN 1st time thru */
  1.1245 +					struct sctp_nets *netp;
  1.1246 +
  1.1247 +					if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
  1.1248 +					    (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
  1.1249 +						SCTP_STAT_DECR_GAUGE32(sctps_currestab);
  1.1250 +					}
  1.1251 +					SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
  1.1252 +					SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
  1.1253 +					sctp_stop_timers_for_shutdown(stcb);
  1.1254 +					if (stcb->asoc.alternate) {
  1.1255 +						netp = stcb->asoc.alternate;
  1.1256 +					} else {
  1.1257 +						netp = stcb->asoc.primary_destination;
  1.1258 +					}
  1.1259 +					sctp_send_shutdown(stcb,netp);
  1.1260 +					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
  1.1261 +							 stcb->sctp_ep, stcb, netp);
  1.1262 +					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
  1.1263 +							 stcb->sctp_ep, stcb, netp);
  1.1264 +					sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
  1.1265 +				}
  1.1266 +			} else {
  1.1267 +				/*
  1.1268 +				 * we still got (or just got) data to send,
  1.1269 +				 * so set SHUTDOWN_PENDING
  1.1270 +				 */
  1.1271 +				/*
  1.1272 +				 * XXX sockets draft says that SCTP_EOF
  1.1273 +				 * should be sent with no data. currently,
  1.1274 +				 * we will allow user data to be sent first
  1.1275 +				 * and move to SHUTDOWN-PENDING
  1.1276 +				 */
  1.1277 +				struct sctp_nets *netp;
  1.1278 +				if (stcb->asoc.alternate) {
  1.1279 +					netp = stcb->asoc.alternate;
  1.1280 +				} else {
  1.1281 +					netp = stcb->asoc.primary_destination;
  1.1282 +				}
  1.1283 +
  1.1284 +				asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
  1.1285 +				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
  1.1286 +						 netp);
  1.1287 +				if (asoc->locked_on_sending) {
  1.1288 +					/* Locked to send out the data */
  1.1289 +					struct sctp_stream_queue_pending *sp;
  1.1290 +					sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
  1.1291 +					if (sp == NULL) {
  1.1292 +						SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n",
  1.1293 +							    asoc->locked_on_sending->stream_no);
  1.1294 +					} else {
  1.1295 +						if ((sp->length == 0) && (sp->msg_is_complete == 0))
  1.1296 +							asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
  1.1297 +					}
  1.1298 +				}
  1.1299 +				if (TAILQ_EMPTY(&asoc->send_queue) &&
  1.1300 +				    TAILQ_EMPTY(&asoc->sent_queue) &&
  1.1301 +				    (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
  1.1302 +					struct mbuf *op_err;
  1.1303 +				abort_anyway:
  1.1304 +					op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr),
  1.1305 +								       0, M_NOWAIT, 1, MT_DATA);
  1.1306 +					if (op_err) {
  1.1307 +						/* Fill in the user initiated abort */
  1.1308 +						struct sctp_paramhdr *ph;
  1.1309 +
  1.1310 +						SCTP_BUF_LEN(op_err) = sizeof(struct sctp_paramhdr);
  1.1311 +						ph = mtod(op_err, struct sctp_paramhdr *);
  1.1312 +						ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
  1.1313 +						ph->param_length = htons(SCTP_BUF_LEN(op_err));
  1.1314 +					}
  1.1315 +					stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ+SCTP_LOC_4;
  1.1316 +					sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED);
  1.1317 +					SCTP_STAT_INCR_COUNTER32(sctps_aborted);
  1.1318 +					if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
  1.1319 +					    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
  1.1320 +						SCTP_STAT_DECR_GAUGE32(sctps_currestab);
  1.1321 +					}
  1.1322 +					SCTP_INP_RUNLOCK(inp);
  1.1323 +					(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_5);
  1.1324 +					return (0);
  1.1325 +				} else {
  1.1326 +					sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
  1.1327 +				}
  1.1328 +			}
  1.1329 +			soisdisconnecting(so);
  1.1330 +			SCTP_TCB_UNLOCK(stcb);
  1.1331 +			SCTP_INP_RUNLOCK(inp);
  1.1332 +			return (0);
  1.1333 +		}
  1.1334 +		/* not reached */
  1.1335 +	} else {
  1.1336 +		/* UDP model does not support this */
  1.1337 +		SCTP_INP_RUNLOCK(inp);
  1.1338 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
  1.1339 +		return (EOPNOTSUPP);
  1.1340 +	}
  1.1341 +}
  1.1342 +
  1.1343 +#if defined(__FreeBSD__) || defined(__Windows__) || defined(__Userspace__)
  1.1344 +int
  1.1345 +sctp_flush(struct socket *so, int how)
  1.1346 +{
  1.1347 +        /*
  1.1348 +	 * We will just clear out the values and let
  1.1349 +	 * subsequent close clear out the data, if any.
  1.1350 +	 * Note if the user did a shutdown(SHUT_RD) they
  1.1351 +	 * will not be able to read the data, the socket
  1.1352 +	 * will block that from happening.
  1.1353 +	 */
  1.1354 +	struct sctp_inpcb *inp;
  1.1355 +
  1.1356 +	inp = (struct sctp_inpcb *)so->so_pcb;
  1.1357 +	if (inp == NULL) {
  1.1358 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.1359 +		return (EINVAL);
  1.1360 +	}
  1.1361 +	SCTP_INP_RLOCK(inp);
  1.1362 +	/* For the 1 to many model this does nothing */
  1.1363 +	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
  1.1364 +		SCTP_INP_RUNLOCK(inp);
  1.1365 +		return (0);
  1.1366 +	}
  1.1367 +	SCTP_INP_RUNLOCK(inp);
  1.1368 +        if ((how == PRU_FLUSH_RD) || (how == PRU_FLUSH_RDWR)) {
  1.1369 +		/* First make sure the sb will be happy, we don't
  1.1370 +		 * use these except maybe the count
  1.1371 +		 */
  1.1372 +		SCTP_INP_WLOCK(inp);
  1.1373 +		SCTP_INP_READ_LOCK(inp);
  1.1374 +		inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ;
  1.1375 +		SCTP_INP_READ_UNLOCK(inp);
  1.1376 +		SCTP_INP_WUNLOCK(inp);
  1.1377 +		so->so_rcv.sb_cc = 0;
  1.1378 +		so->so_rcv.sb_mbcnt = 0;
  1.1379 +		so->so_rcv.sb_mb = NULL;
  1.1380 +	}
  1.1381 +        if ((how == PRU_FLUSH_WR) || (how == PRU_FLUSH_RDWR)) {
  1.1382 +		/* First make sure the sb will be happy, we don't
  1.1383 +		 * use these except maybe the count
  1.1384 +		 */
  1.1385 +		so->so_snd.sb_cc = 0;
  1.1386 +		so->so_snd.sb_mbcnt = 0;
  1.1387 +		so->so_snd.sb_mb = NULL;
  1.1388 +
  1.1389 +	}
  1.1390 +	return (0);
  1.1391 +}
  1.1392 +#endif
  1.1393 +
  1.1394 +int
  1.1395 +sctp_shutdown(struct socket *so)
  1.1396 +{
  1.1397 +	struct sctp_inpcb *inp;
  1.1398 +
  1.1399 +	inp = (struct sctp_inpcb *)so->so_pcb;
  1.1400 +	if (inp == NULL) {
  1.1401 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.1402 +		return (EINVAL);
  1.1403 +	}
  1.1404 +	SCTP_INP_RLOCK(inp);
  1.1405 +	/* For UDP model this is a invalid call */
  1.1406 +	if (!((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.1407 +	      (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) {
  1.1408 +		/* Restore the flags that the soshutdown took away. */
  1.1409 +#if (defined(__FreeBSD__) && __FreeBSD_version >= 502115) || defined(__Windows__)
  1.1410 +		SOCKBUF_LOCK(&so->so_rcv);
  1.1411 +		so->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
  1.1412 +		SOCKBUF_UNLOCK(&so->so_rcv);
  1.1413 +#else
  1.1414 +		so->so_state &= ~SS_CANTRCVMORE;
  1.1415 +#endif
  1.1416 +		/* This proc will wakeup for read and do nothing (I hope) */
  1.1417 +		SCTP_INP_RUNLOCK(inp);
  1.1418 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
  1.1419 +		return (EOPNOTSUPP);
  1.1420 +	}
  1.1421 +	/*
  1.1422 +	 * Ok if we reach here its the TCP model and it is either a SHUT_WR
  1.1423 +	 * or SHUT_RDWR. This means we put the shutdown flag against it.
  1.1424 +	 */
  1.1425 +	{
  1.1426 +		struct sctp_tcb *stcb;
  1.1427 +		struct sctp_association *asoc;
  1.1428 +
  1.1429 +		if ((so->so_state &
  1.1430 +		     (SS_ISCONNECTED|SS_ISCONNECTING|SS_ISDISCONNECTING)) == 0) {
  1.1431 +			SCTP_INP_RUNLOCK(inp);
  1.1432 +			return (ENOTCONN);
  1.1433 +		}
  1.1434 +		socantsendmore(so);
  1.1435 +
  1.1436 +		stcb = LIST_FIRST(&inp->sctp_asoc_list);
  1.1437 +		if (stcb == NULL) {
  1.1438 +			/*
  1.1439 +			 * Ok we hit the case that the shutdown call was
  1.1440 +			 * made after an abort or something. Nothing to do
  1.1441 +			 * now.
  1.1442 +			 */
  1.1443 +			SCTP_INP_RUNLOCK(inp);
  1.1444 +			return (0);
  1.1445 +		}
  1.1446 +		SCTP_TCB_LOCK(stcb);
  1.1447 +		asoc = &stcb->asoc;
  1.1448 +		if (TAILQ_EMPTY(&asoc->send_queue) &&
  1.1449 +		    TAILQ_EMPTY(&asoc->sent_queue) &&
  1.1450 +		    (asoc->stream_queue_cnt == 0)) {
  1.1451 +			if (asoc->locked_on_sending) {
  1.1452 +				goto abort_anyway;
  1.1453 +			}
  1.1454 +			/* there is nothing queued to send, so I'm done... */
  1.1455 +			if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
  1.1456 +				/* only send SHUTDOWN the first time through */
  1.1457 +				struct sctp_nets *netp;
  1.1458 +
  1.1459 +				if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
  1.1460 +				    (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
  1.1461 +					SCTP_STAT_DECR_GAUGE32(sctps_currestab);
  1.1462 +				}
  1.1463 +				SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
  1.1464 +				SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
  1.1465 +				sctp_stop_timers_for_shutdown(stcb);
  1.1466 +				if (stcb->asoc.alternate) {
  1.1467 +					netp = stcb->asoc.alternate;
  1.1468 +				} else {
  1.1469 +					netp = stcb->asoc.primary_destination;
  1.1470 +				}
  1.1471 +				sctp_send_shutdown(stcb, netp);
  1.1472 +				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
  1.1473 +						 stcb->sctp_ep, stcb, netp);
  1.1474 +				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
  1.1475 +						 stcb->sctp_ep, stcb, netp);
  1.1476 +				sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
  1.1477 +			}
  1.1478 +		} else {
  1.1479 +			/*
  1.1480 +			 * we still got (or just got) data to send, so set
  1.1481 +			 * SHUTDOWN_PENDING
  1.1482 +			 */
  1.1483 +			struct sctp_nets *netp;
  1.1484 +			if (stcb->asoc.alternate) {
  1.1485 +				netp = stcb->asoc.alternate;
  1.1486 +			} else {
  1.1487 +				netp = stcb->asoc.primary_destination;
  1.1488 +			}
  1.1489 +
  1.1490 +			asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
  1.1491 +			sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
  1.1492 +					 netp);
  1.1493 +
  1.1494 +			if (asoc->locked_on_sending) {
  1.1495 +				/* Locked to send out the data */
  1.1496 +				struct sctp_stream_queue_pending *sp;
  1.1497 +				sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
  1.1498 +				if (sp == NULL) {
  1.1499 +					SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n",
  1.1500 +						    asoc->locked_on_sending->stream_no);
  1.1501 +				} else {
  1.1502 +					if ((sp->length == 0)  && (sp-> msg_is_complete == 0)) {
  1.1503 +						asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
  1.1504 +					}
  1.1505 +				}
  1.1506 +			}
  1.1507 +			if (TAILQ_EMPTY(&asoc->send_queue) &&
  1.1508 +			    TAILQ_EMPTY(&asoc->sent_queue) &&
  1.1509 +			    (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
  1.1510 +				struct mbuf *op_err;
  1.1511 +			abort_anyway:
  1.1512 +				op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr),
  1.1513 +							       0, M_NOWAIT, 1, MT_DATA);
  1.1514 +				if (op_err) {
  1.1515 +					/* Fill in the user initiated abort */
  1.1516 +					struct sctp_paramhdr *ph;
  1.1517 +
  1.1518 +					SCTP_BUF_LEN(op_err) = sizeof(struct sctp_paramhdr);
  1.1519 +					ph = mtod(op_err, struct sctp_paramhdr *);
  1.1520 +					ph->param_type = htons( SCTP_CAUSE_USER_INITIATED_ABT);
  1.1521 +					ph->param_length = htons(SCTP_BUF_LEN(op_err));
  1.1522 +				}
  1.1523 +				stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ+SCTP_LOC_6;
  1.1524 +				sctp_abort_an_association(stcb->sctp_ep, stcb,
  1.1525 +							  op_err, SCTP_SO_LOCKED);
  1.1526 +				goto skip_unlock;
  1.1527 +			} else {
  1.1528 +				sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
  1.1529 +			}
  1.1530 +		}
  1.1531 +		SCTP_TCB_UNLOCK(stcb);
  1.1532 +	}
  1.1533 + skip_unlock:
  1.1534 +	SCTP_INP_RUNLOCK(inp);
  1.1535 +	return (0);
  1.1536 +}
  1.1537 +
  1.1538 +/*
  1.1539 + * copies a "user" presentable address and removes embedded scope, etc.
  1.1540 + * returns 0 on success, 1 on error
  1.1541 + */
  1.1542 +static uint32_t
  1.1543 +sctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa)
  1.1544 +{
  1.1545 +#ifdef INET6
  1.1546 +#if defined(SCTP_EMBEDDED_V6_SCOPE)
  1.1547 +	struct sockaddr_in6 lsa6;
  1.1548 +
  1.1549 +	sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa,
  1.1550 +	    &lsa6);
  1.1551 +#endif
  1.1552 +#endif
  1.1553 +#ifdef HAVE_SA_LEN
  1.1554 +	memcpy(ss, sa, sa->sa_len);
  1.1555 +#else
  1.1556 +	switch (sa->sa_family) {
  1.1557 +#ifdef INET
  1.1558 +	case AF_INET:
  1.1559 +		memcpy(ss, sa, sizeof(struct sockaddr_in));
  1.1560 +		break;
  1.1561 +#endif
  1.1562 +#ifdef INET6
  1.1563 +	case AF_INET6:
  1.1564 +		memcpy(ss, sa, sizeof(struct sockaddr_in6));
  1.1565 +		break;
  1.1566 +#endif
  1.1567 +#if defined(__Userspace__)
  1.1568 +	case AF_CONN:
  1.1569 +		memcpy(ss, sa, sizeof(struct sockaddr_conn));
  1.1570 +		break;
  1.1571 +#endif
  1.1572 +	default:
  1.1573 +		/* TSNH */
  1.1574 +		break;
  1.1575 +	}
  1.1576 +#endif
  1.1577 +	return (0);
  1.1578 +}
  1.1579 +
  1.1580 +
  1.1581 +
  1.1582 +/*
  1.1583 + * NOTE: assumes addr lock is held
  1.1584 + */
  1.1585 +static size_t
  1.1586 +sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
  1.1587 +			   struct sctp_tcb *stcb,
  1.1588 +			   size_t limit,
  1.1589 +			   struct sockaddr_storage *sas,
  1.1590 +			   uint32_t vrf_id)
  1.1591 +{
  1.1592 +	struct sctp_ifn *sctp_ifn;
  1.1593 +	struct sctp_ifa *sctp_ifa;
  1.1594 +	size_t actual;
  1.1595 +	int loopback_scope;
  1.1596 +#if defined(INET)
  1.1597 +	int ipv4_local_scope, ipv4_addr_legal;
  1.1598 +#endif
  1.1599 +#if defined(INET6)
  1.1600 +	int local_scope, site_scope, ipv6_addr_legal;
  1.1601 +#endif
  1.1602 +#if defined(__Userspace__)
  1.1603 +	int conn_addr_legal;
  1.1604 +#endif
  1.1605 +	struct sctp_vrf *vrf;
  1.1606 +
  1.1607 +	actual = 0;
  1.1608 +	if (limit <= 0)
  1.1609 +		return (actual);
  1.1610 +
  1.1611 +	if (stcb) {
  1.1612 +		/* Turn on all the appropriate scope */
  1.1613 +		loopback_scope = stcb->asoc.scope.loopback_scope;
  1.1614 +#if defined(INET)
  1.1615 +		ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope;
  1.1616 +		ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal;
  1.1617 +#endif
  1.1618 +#if defined(INET6)
  1.1619 +		local_scope = stcb->asoc.scope.local_scope;
  1.1620 +		site_scope = stcb->asoc.scope.site_scope;
  1.1621 +		ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal;
  1.1622 +#endif
  1.1623 +#if defined(__Userspace__)
  1.1624 +		conn_addr_legal = stcb->asoc.scope.conn_addr_legal;
  1.1625 +#endif
  1.1626 +	} else {
  1.1627 +		/* Use generic values for endpoints. */
  1.1628 +		loopback_scope = 1;
  1.1629 +#if defined(INET)
  1.1630 +		ipv4_local_scope = 1;
  1.1631 +#endif
  1.1632 +#if defined(INET6)
  1.1633 +		local_scope = 1;
  1.1634 +		site_scope = 1;
  1.1635 +#endif
  1.1636 +		if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
  1.1637 +#if defined(INET6)
  1.1638 +			ipv6_addr_legal = 1;
  1.1639 +#endif
  1.1640 +#if defined(INET)
  1.1641 +			if (SCTP_IPV6_V6ONLY(inp)) {
  1.1642 +				ipv4_addr_legal = 0;
  1.1643 +			} else {
  1.1644 +				ipv4_addr_legal = 1;
  1.1645 +			}
  1.1646 +#endif
  1.1647 +#if defined(__Userspace__)
  1.1648 +			conn_addr_legal = 0;
  1.1649 +#endif
  1.1650 +		} else {
  1.1651 +#if defined(INET6)
  1.1652 +			ipv6_addr_legal = 0;
  1.1653 +#endif
  1.1654 +#if defined(__Userspace__)
  1.1655 +			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) {
  1.1656 +				conn_addr_legal = 1;
  1.1657 +#if defined(INET)
  1.1658 +				ipv4_addr_legal = 0;
  1.1659 +#endif
  1.1660 +			} else {
  1.1661 +				conn_addr_legal = 0;
  1.1662 +#if defined(INET)
  1.1663 +				ipv4_addr_legal = 1;
  1.1664 +#endif
  1.1665 +			}
  1.1666 +#else
  1.1667 +#if defined(INET)
  1.1668 +			ipv4_addr_legal = 1;
  1.1669 +#endif
  1.1670 +#endif
  1.1671 +		}
  1.1672 +	}
  1.1673 +	vrf = sctp_find_vrf(vrf_id);
  1.1674 +	if (vrf == NULL) {
  1.1675 +		return (0);
  1.1676 +	}
  1.1677 +	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
  1.1678 +		LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
  1.1679 +			if ((loopback_scope == 0) &&
  1.1680 +			    SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
  1.1681 +				/* Skip loopback if loopback_scope not set */
  1.1682 +				continue;
  1.1683 +			}
  1.1684 +			LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
  1.1685 +				if (stcb) {
  1.1686 +					/*
  1.1687 +					 * For the BOUND-ALL case, the list
  1.1688 +					 * associated with a TCB is Always
  1.1689 +					 * considered a reverse list.. i.e.
  1.1690 +					 * it lists addresses that are NOT
  1.1691 +					 * part of the association. If this
  1.1692 +					 * is one of those we must skip it.
  1.1693 +					 */
  1.1694 +					if (sctp_is_addr_restricted(stcb,
  1.1695 +								    sctp_ifa)) {
  1.1696 +						continue;
  1.1697 +					}
  1.1698 +				}
  1.1699 +				switch (sctp_ifa->address.sa.sa_family) {
  1.1700 +#ifdef INET
  1.1701 +				case AF_INET:
  1.1702 +					if (ipv4_addr_legal) {
  1.1703 +						struct sockaddr_in *sin;
  1.1704 +
  1.1705 +						sin = (struct sockaddr_in *)&sctp_ifa->address.sa;
  1.1706 +						if (sin->sin_addr.s_addr == 0) {
  1.1707 +							/*
  1.1708 +							 * we skip unspecifed
  1.1709 +							 * addresses
  1.1710 +							 */
  1.1711 +							continue;
  1.1712 +						}
  1.1713 +						if ((ipv4_local_scope == 0) &&
  1.1714 +						    (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
  1.1715 +							continue;
  1.1716 +						}
  1.1717 +#ifdef INET6
  1.1718 +						if (sctp_is_feature_on(inp,SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
  1.1719 +							in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas);
  1.1720 +							((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
  1.1721 +							sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6));
  1.1722 +							actual += sizeof(struct sockaddr_in6);
  1.1723 +						} else {
  1.1724 +#endif
  1.1725 +							memcpy(sas, sin, sizeof(*sin));
  1.1726 +							((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport;
  1.1727 +							sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin));
  1.1728 +							actual += sizeof(*sin);
  1.1729 +#ifdef INET6
  1.1730 +						}
  1.1731 +#endif
  1.1732 +						if (actual >= limit) {
  1.1733 +							return (actual);
  1.1734 +						}
  1.1735 +					} else {
  1.1736 +						continue;
  1.1737 +					}
  1.1738 +					break;
  1.1739 +#endif
  1.1740 +#ifdef INET6
  1.1741 +				case AF_INET6:
  1.1742 +					if (ipv6_addr_legal) {
  1.1743 +						struct sockaddr_in6 *sin6;
  1.1744 +
  1.1745 +#if defined(SCTP_EMBEDDED_V6_SCOPE) && !defined(SCTP_KAME)
  1.1746 +						struct sockaddr_in6 lsa6;
  1.1747 +#endif
  1.1748 +						sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa;
  1.1749 +						if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
  1.1750 +							/*
  1.1751 +							 * we skip unspecifed
  1.1752 +							 * addresses
  1.1753 +							 */
  1.1754 +							continue;
  1.1755 +						}
  1.1756 +						if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
  1.1757 +							if (local_scope == 0)
  1.1758 +								continue;
  1.1759 +#if defined(SCTP_EMBEDDED_V6_SCOPE)
  1.1760 +							if (sin6->sin6_scope_id == 0) {
  1.1761 +#ifdef SCTP_KAME
  1.1762 +								if (sa6_recoverscope(sin6) != 0)
  1.1763 +									/*
  1.1764 +									 * bad link
  1.1765 +									 * local
  1.1766 +									 * address
  1.1767 +									 */
  1.1768 +									continue;
  1.1769 +#else
  1.1770 +								lsa6 = *sin6;
  1.1771 +								if (in6_recoverscope(&lsa6,
  1.1772 +										     &lsa6.sin6_addr,
  1.1773 +										     NULL))
  1.1774 +									/*
  1.1775 +									 * bad link
  1.1776 +									 * local
  1.1777 +									 * address
  1.1778 +									 */
  1.1779 +								continue;
  1.1780 +								sin6 = &lsa6;
  1.1781 +#endif				/* SCTP_KAME */
  1.1782 +							}
  1.1783 +#endif /* SCTP_EMBEDDED_V6_SCOPE */
  1.1784 +						}
  1.1785 +						if ((site_scope == 0) &&
  1.1786 +						    (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
  1.1787 +							continue;
  1.1788 +						}
  1.1789 +						memcpy(sas, sin6, sizeof(*sin6));
  1.1790 +						((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
  1.1791 +						sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6));
  1.1792 +						actual += sizeof(*sin6);
  1.1793 +						if (actual >= limit) {
  1.1794 +							return (actual);
  1.1795 +						}
  1.1796 +					} else {
  1.1797 +						continue;
  1.1798 +					}
  1.1799 +					break;
  1.1800 +#endif
  1.1801 +#if defined(__Userspace__)
  1.1802 +				case AF_CONN:
  1.1803 +					if (conn_addr_legal) {
  1.1804 +						memcpy(sas, &sctp_ifa->address.sconn, sizeof(struct sockaddr_conn));
  1.1805 +						((struct sockaddr_conn *)sas)->sconn_port = inp->sctp_lport;
  1.1806 +						sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_conn));
  1.1807 +						actual += sizeof(struct sockaddr_conn);
  1.1808 +						if (actual >= limit) {
  1.1809 +							return (actual);
  1.1810 +						}
  1.1811 +					} else {
  1.1812 +						continue;
  1.1813 +					}
  1.1814 +#endif
  1.1815 +				default:
  1.1816 +					/* TSNH */
  1.1817 +					break;
  1.1818 +				}
  1.1819 +			}
  1.1820 +		}
  1.1821 +	} else {
  1.1822 +		struct sctp_laddr *laddr;
  1.1823 +#ifndef HAVE_SA_LEN
  1.1824 +		uint32_t sa_len = 0;
  1.1825 +#endif
  1.1826 +
  1.1827 +		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
  1.1828 +			if (stcb) {
  1.1829 +				if (sctp_is_addr_restricted(stcb, laddr->ifa)) {
  1.1830 +					continue;
  1.1831 +				}
  1.1832 +			}
  1.1833 +			if (sctp_fill_user_address(sas, &laddr->ifa->address.sa))
  1.1834 +				continue;
  1.1835 +			switch (laddr->ifa->address.sa.sa_family) {
  1.1836 +#ifdef INET
  1.1837 +			case AF_INET:
  1.1838 +				((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport;
  1.1839 +				break;
  1.1840 +#endif
  1.1841 +#ifdef INET6
  1.1842 +			case AF_INET6:
  1.1843 +				((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
  1.1844 +				break;
  1.1845 +#endif
  1.1846 +#if defined(__Userspace__)
  1.1847 +			case AF_CONN:
  1.1848 +				((struct sockaddr_conn *)sas)->sconn_port = inp->sctp_lport;
  1.1849 +				break;
  1.1850 +#endif
  1.1851 +			default:
  1.1852 +				/* TSNH */
  1.1853 +				break;
  1.1854 +			}
  1.1855 +#ifdef HAVE_SA_LEN
  1.1856 +			sas = (struct sockaddr_storage *)((caddr_t)sas +
  1.1857 +							  laddr->ifa->address.sa.sa_len);
  1.1858 +			actual += laddr->ifa->address.sa.sa_len;
  1.1859 +#else
  1.1860 +			switch (laddr->ifa->address.sa.sa_family) {
  1.1861 +#ifdef INET
  1.1862 +			case AF_INET:
  1.1863 +				sa_len = sizeof(struct sockaddr_in);
  1.1864 +				break;
  1.1865 +#endif
  1.1866 +#ifdef INET6
  1.1867 +			case AF_INET6:
  1.1868 +				sa_len = sizeof(struct sockaddr_in6);
  1.1869 +				break;
  1.1870 +#endif
  1.1871 +#if defined(__Userspace__)
  1.1872 +			case AF_CONN:
  1.1873 +				sa_len = sizeof(struct sockaddr_conn);
  1.1874 +				break;
  1.1875 +#endif
  1.1876 +			default:
  1.1877 +				/* TSNH */
  1.1878 +				break;
  1.1879 +			}
  1.1880 +			sas = (struct sockaddr_storage *)((caddr_t)sas + sa_len);
  1.1881 +			actual += sa_len;
  1.1882 +#endif
  1.1883 +			if (actual >= limit) {
  1.1884 +				return (actual);
  1.1885 +			}
  1.1886 +		}
  1.1887 +	}
  1.1888 +	return (actual);
  1.1889 +}
  1.1890 +
  1.1891 +static size_t
  1.1892 +sctp_fill_up_addresses(struct sctp_inpcb *inp,
  1.1893 +                       struct sctp_tcb *stcb,
  1.1894 +                       size_t limit,
  1.1895 +                       struct sockaddr_storage *sas)
  1.1896 +{
  1.1897 +	size_t size = 0;
  1.1898 +#ifdef SCTP_MVRF
  1.1899 +	uint32_t id;
  1.1900 +#endif
  1.1901 +
  1.1902 +	SCTP_IPI_ADDR_RLOCK();
  1.1903 +#ifdef SCTP_MVRF
  1.1904 +/*
  1.1905 + * FIX ME: ?? this WILL report duplicate addresses if they appear
  1.1906 + * in more than one VRF.
  1.1907 + */
  1.1908 +	/* fill up addresses for all VRFs on the endpoint */
  1.1909 +	for (id = 0; (id < inp->num_vrfs) && (size < limit); id++) {
  1.1910 +		size += sctp_fill_up_addresses_vrf(inp, stcb, limit, sas,
  1.1911 +						   inp->m_vrf_ids[id]);
  1.1912 +		sas = (struct sockaddr_storage *)((caddr_t)sas + size);
  1.1913 +	}
  1.1914 +#else
  1.1915 +	/* fill up addresses for the endpoint's default vrf */
  1.1916 +	size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas,
  1.1917 +					  inp->def_vrf_id);
  1.1918 +#endif
  1.1919 +	SCTP_IPI_ADDR_RUNLOCK();
  1.1920 +	return (size);
  1.1921 +}
  1.1922 +
  1.1923 +/*
  1.1924 + * NOTE: assumes addr lock is held
  1.1925 + */
  1.1926 +static int
  1.1927 +sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id)
  1.1928 +{
  1.1929 +	int cnt = 0;
  1.1930 +	struct sctp_vrf *vrf = NULL;
  1.1931 +
  1.1932 +	/*
  1.1933 +	 * In both sub-set bound an bound_all cases we return the MAXIMUM
  1.1934 +	 * number of addresses that you COULD get. In reality the sub-set
  1.1935 +	 * bound may have an exclusion list for a given TCB OR in the
  1.1936 +	 * bound-all case a TCB may NOT include the loopback or other
  1.1937 +	 * addresses as well.
  1.1938 +	 */
  1.1939 +	vrf = sctp_find_vrf(vrf_id);
  1.1940 +	if (vrf == NULL) {
  1.1941 +		return (0);
  1.1942 +	}
  1.1943 +	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
  1.1944 +		struct sctp_ifn *sctp_ifn;
  1.1945 +		struct sctp_ifa *sctp_ifa;
  1.1946 +
  1.1947 +		LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
  1.1948 +			LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
  1.1949 +				/* Count them if they are the right type */
  1.1950 +				switch (sctp_ifa->address.sa.sa_family) {
  1.1951 +#ifdef INET
  1.1952 +				case AF_INET:
  1.1953 +					if (sctp_is_feature_on(inp,SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
  1.1954 +						cnt += sizeof(struct sockaddr_in6);
  1.1955 +					else
  1.1956 +						cnt += sizeof(struct sockaddr_in);
  1.1957 +					break;
  1.1958 +#endif
  1.1959 +#ifdef INET6
  1.1960 +				case AF_INET6:
  1.1961 +					cnt += sizeof(struct sockaddr_in6);
  1.1962 +					break;
  1.1963 +#endif
  1.1964 +#if defined(__Userspace__)
  1.1965 +				case AF_CONN:
  1.1966 +					cnt += sizeof(struct sockaddr_conn);
  1.1967 +					break;
  1.1968 +#endif
  1.1969 +				default:
  1.1970 +					break;
  1.1971 +				}
  1.1972 +			}
  1.1973 +		}
  1.1974 +	} else {
  1.1975 +		struct sctp_laddr *laddr;
  1.1976 +
  1.1977 +		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
  1.1978 +			switch (laddr->ifa->address.sa.sa_family) {
  1.1979 +#ifdef INET
  1.1980 +			case AF_INET:
  1.1981 +				if (sctp_is_feature_on(inp,SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
  1.1982 +					cnt += sizeof(struct sockaddr_in6);
  1.1983 +				else
  1.1984 +					cnt += sizeof(struct sockaddr_in);
  1.1985 +				break;
  1.1986 +#endif
  1.1987 +#ifdef INET6
  1.1988 +			case AF_INET6:
  1.1989 +				cnt += sizeof(struct sockaddr_in6);
  1.1990 +				break;
  1.1991 +#endif
  1.1992 +#if defined(__Userspace__)
  1.1993 +			case AF_CONN:
  1.1994 +				cnt += sizeof(struct sockaddr_conn);
  1.1995 +				break;
  1.1996 +#endif
  1.1997 +			default:
  1.1998 +				break;
  1.1999 +			}
  1.2000 +		}
  1.2001 +	}
  1.2002 +	return (cnt);
  1.2003 +}
  1.2004 +
  1.2005 +static int
  1.2006 +sctp_count_max_addresses(struct sctp_inpcb *inp)
  1.2007 +{
  1.2008 +	int cnt = 0;
  1.2009 +#ifdef SCTP_MVRF
  1.2010 +	int id;
  1.2011 +#endif
  1.2012 +
  1.2013 +	SCTP_IPI_ADDR_RLOCK();
  1.2014 +#ifdef SCTP_MVRF
  1.2015 +/*
  1.2016 + * FIX ME: ?? this WILL count duplicate addresses if they appear
  1.2017 + * in more than one VRF.
  1.2018 + */
  1.2019 +	/* count addresses for all VRFs on the endpoint */
  1.2020 +	for (id = 0; id < inp->num_vrfs; id++) {
  1.2021 +		cnt += sctp_count_max_addresses_vrf(inp, inp->m_vrf_ids[id]);
  1.2022 +	}
  1.2023 +#else
  1.2024 +	/* count addresses for the endpoint's default VRF */
  1.2025 +	cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id);
  1.2026 +#endif
  1.2027 +	SCTP_IPI_ADDR_RUNLOCK();
  1.2028 +	return (cnt);
  1.2029 +}
  1.2030 +
  1.2031 +static int
  1.2032 +sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
  1.2033 +		  size_t optsize, void *p, int delay)
  1.2034 +{
  1.2035 +	int error = 0;
  1.2036 +	int creat_lock_on = 0;
  1.2037 +	struct sctp_tcb *stcb = NULL;
  1.2038 +	struct sockaddr *sa;
  1.2039 +	int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr;
  1.2040 +	uint32_t vrf_id;
  1.2041 +	int bad_addresses = 0;
  1.2042 +	sctp_assoc_t *a_id;
  1.2043 +
  1.2044 +	SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n");
  1.2045 +
  1.2046 +	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
  1.2047 +	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
  1.2048 +		/* We are already connected AND the TCP model */
  1.2049 +		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
  1.2050 +		return (EADDRINUSE);
  1.2051 +	}
  1.2052 +
  1.2053 +	if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) &&
  1.2054 +	    (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) {
  1.2055 +		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.2056 +		return (EINVAL);
  1.2057 +	}
  1.2058 +
  1.2059 +	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
  1.2060 +		SCTP_INP_RLOCK(inp);
  1.2061 +		stcb = LIST_FIRST(&inp->sctp_asoc_list);
  1.2062 +		SCTP_INP_RUNLOCK(inp);
  1.2063 +	}
  1.2064 +	if (stcb) {
  1.2065 +		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
  1.2066 +		return (EALREADY);
  1.2067 +	}
  1.2068 +	SCTP_INP_INCR_REF(inp);
  1.2069 +	SCTP_ASOC_CREATE_LOCK(inp);
  1.2070 +	creat_lock_on = 1;
  1.2071 +	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
  1.2072 +	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
  1.2073 +		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
  1.2074 +		error = EFAULT;
  1.2075 +		goto out_now;
  1.2076 +	}
  1.2077 +	totaddrp = (int *)optval;
  1.2078 +	totaddr = *totaddrp;
  1.2079 +	sa = (struct sockaddr *)(totaddrp + 1);
  1.2080 +	stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses);
  1.2081 +	if ((stcb != NULL) || bad_addresses) {
  1.2082 +		/* Already have or am bring up an association */
  1.2083 +		SCTP_ASOC_CREATE_UNLOCK(inp);
  1.2084 +		creat_lock_on = 0;
  1.2085 +		if (stcb)
  1.2086 +			SCTP_TCB_UNLOCK(stcb);
  1.2087 +		if (bad_addresses == 0) {
  1.2088 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
  1.2089 +			error = EALREADY;
  1.2090 +		}
  1.2091 +		goto out_now;
  1.2092 +	}
  1.2093 +#ifdef INET6
  1.2094 +	if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
  1.2095 +	    (num_v6 > 0)) {
  1.2096 +		error = EINVAL;
  1.2097 +		goto out_now;
  1.2098 +	}
  1.2099 +	if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
  1.2100 +	    (num_v4 > 0)) {
  1.2101 +		struct in6pcb *inp6;
  1.2102 +
  1.2103 +		inp6 = (struct in6pcb *)inp;
  1.2104 +		if (SCTP_IPV6_V6ONLY(inp6)) {
  1.2105 +			/*
  1.2106 +			 * if IPV6_V6ONLY flag, ignore connections destined
  1.2107 +			 * to a v4 addr or v4-mapped addr
  1.2108 +			 */
  1.2109 +			SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.2110 +			error = EINVAL;
  1.2111 +			goto out_now;
  1.2112 +		}
  1.2113 +	}
  1.2114 +#endif				/* INET6 */
  1.2115 +	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
  1.2116 +	    SCTP_PCB_FLAGS_UNBOUND) {
  1.2117 +		/* Bind a ephemeral port */
  1.2118 +		error = sctp_inpcb_bind(so, NULL, NULL, p);
  1.2119 +		if (error) {
  1.2120 +			goto out_now;
  1.2121 +		}
  1.2122 +	}
  1.2123 +
  1.2124 +	/* FIX ME: do we want to pass in a vrf on the connect call? */
  1.2125 +	vrf_id = inp->def_vrf_id;
  1.2126 +
  1.2127 +
  1.2128 +	/* We are GOOD to go */
  1.2129 +	stcb = sctp_aloc_assoc(inp, sa, &error, 0, vrf_id,
  1.2130 +#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
  1.2131 +			       (struct thread *)p
  1.2132 +#elif defined(__Windows__)
  1.2133 +			       (PKTHREAD)p
  1.2134 +#else
  1.2135 +			       (struct proc *)p
  1.2136 +#endif
  1.2137 +		);
  1.2138 +	if (stcb == NULL) {
  1.2139 +		/* Gak! no memory */
  1.2140 +		goto out_now;
  1.2141 +	}
  1.2142 +	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
  1.2143 +		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
  1.2144 +		/* Set the connected flag so we can queue data */
  1.2145 +		soisconnecting(so);
  1.2146 +	}
  1.2147 +	SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
  1.2148 +	/* move to second address */
  1.2149 +	switch (sa->sa_family) {
  1.2150 +#ifdef INET
  1.2151 +	case AF_INET:
  1.2152 +		sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in));
  1.2153 +		break;
  1.2154 +#endif
  1.2155 +#ifdef INET6
  1.2156 +	case AF_INET6:
  1.2157 +		sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6));
  1.2158 +		break;
  1.2159 +#endif
  1.2160 +	default:
  1.2161 +		break;
  1.2162 +	}
  1.2163 +
  1.2164 +	error = 0;
  1.2165 +	sctp_connectx_helper_add(stcb, sa, (totaddr-1), &error);
  1.2166 +	/* Fill in the return id */
  1.2167 +	if (error) {
  1.2168 +		(void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_6);
  1.2169 +		goto out_now;
  1.2170 +	}
  1.2171 +	a_id = (sctp_assoc_t *)optval;
  1.2172 +	*a_id = sctp_get_associd(stcb);
  1.2173 +
  1.2174 +	/* initialize authentication parameters for the assoc */
  1.2175 +	sctp_initialize_auth_params(inp, stcb);
  1.2176 +
  1.2177 +	if (delay) {
  1.2178 +		/* doing delayed connection */
  1.2179 +		stcb->asoc.delayed_connection = 1;
  1.2180 +		sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination);
  1.2181 +	} else {
  1.2182 +		(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
  1.2183 +		sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
  1.2184 +	}
  1.2185 +	SCTP_TCB_UNLOCK(stcb);
  1.2186 +	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
  1.2187 +		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
  1.2188 +		/* Set the connected flag so we can queue data */
  1.2189 +		soisconnecting(so);
  1.2190 +	}
  1.2191 + out_now:
  1.2192 +	if (creat_lock_on) {
  1.2193 +		SCTP_ASOC_CREATE_UNLOCK(inp);
  1.2194 +	}
  1.2195 +	SCTP_INP_DECR_REF(inp);
  1.2196 +	return (error);
  1.2197 +}
  1.2198 +
  1.2199 +#define SCTP_FIND_STCB(inp, stcb, assoc_id) { \
  1.2200 +	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||\
  1.2201 +	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { \
  1.2202 +		SCTP_INP_RLOCK(inp); \
  1.2203 +		stcb = LIST_FIRST(&inp->sctp_asoc_list); \
  1.2204 +		if (stcb) { \
  1.2205 +			SCTP_TCB_LOCK(stcb); \
  1.2206 +                } \
  1.2207 +		SCTP_INP_RUNLOCK(inp); \
  1.2208 +	} else if (assoc_id > SCTP_ALL_ASSOC) { \
  1.2209 +		stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \
  1.2210 +		if (stcb == NULL) { \
  1.2211 +		        SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \
  1.2212 +			error = ENOENT; \
  1.2213 +			break; \
  1.2214 +		} \
  1.2215 +	} else { \
  1.2216 +		stcb = NULL; \
  1.2217 +        } \
  1.2218 +  }
  1.2219 +
  1.2220 +
  1.2221 +#define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\
  1.2222 +	if (size < sizeof(type)) { \
  1.2223 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); \
  1.2224 +		error = EINVAL; \
  1.2225 +		break; \
  1.2226 +	} else { \
  1.2227 +		destp = (type *)srcp; \
  1.2228 +	} \
  1.2229 +      }
  1.2230 +
  1.2231 +#if defined(__Panda__) || defined(__Userspace__)
  1.2232 +int
  1.2233 +#else
  1.2234 +static int
  1.2235 +#endif
  1.2236 +sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
  1.2237 +	    void *p) {
  1.2238 +	struct sctp_inpcb *inp = NULL;
  1.2239 +	int error, val = 0;
  1.2240 +	struct sctp_tcb *stcb = NULL;
  1.2241 +
  1.2242 +	if (optval == NULL) {
  1.2243 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.2244 +		return (EINVAL);
  1.2245 +	}
  1.2246 +
  1.2247 +	inp = (struct sctp_inpcb *)so->so_pcb;
  1.2248 +	if (inp == NULL) {
  1.2249 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.2250 +		return EINVAL;
  1.2251 +	}
  1.2252 +	error = 0;
  1.2253 +
  1.2254 +	switch (optname) {
  1.2255 +	case SCTP_NODELAY:
  1.2256 +	case SCTP_AUTOCLOSE:
  1.2257 +	case SCTP_EXPLICIT_EOR:
  1.2258 +	case SCTP_AUTO_ASCONF:
  1.2259 +	case SCTP_DISABLE_FRAGMENTS:
  1.2260 +	case SCTP_I_WANT_MAPPED_V4_ADDR:
  1.2261 +	case SCTP_USE_EXT_RCVINFO:
  1.2262 +		SCTP_INP_RLOCK(inp);
  1.2263 +		switch (optname) {
  1.2264 +		case SCTP_DISABLE_FRAGMENTS:
  1.2265 +			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT);
  1.2266 +			break;
  1.2267 +		case SCTP_I_WANT_MAPPED_V4_ADDR:
  1.2268 +			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4);
  1.2269 +			break;
  1.2270 +		case SCTP_AUTO_ASCONF:
  1.2271 +			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
  1.2272 +				/* only valid for bound all sockets */
  1.2273 +				val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF);
  1.2274 +			} else {
  1.2275 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.2276 +				error = EINVAL;
  1.2277 +				goto flags_out;
  1.2278 +			}
  1.2279 +			break;
  1.2280 +		case SCTP_EXPLICIT_EOR:
  1.2281 +			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
  1.2282 +			break;
  1.2283 +		case SCTP_NODELAY:
  1.2284 +			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY);
  1.2285 +			break;
  1.2286 +		case SCTP_USE_EXT_RCVINFO:
  1.2287 +			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO);
  1.2288 +			break;
  1.2289 +		case SCTP_AUTOCLOSE:
  1.2290 +			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE))
  1.2291 +				val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time);
  1.2292 +			else
  1.2293 +				val = 0;
  1.2294 +			break;
  1.2295 +
  1.2296 +		default:
  1.2297 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
  1.2298 +			error = ENOPROTOOPT;
  1.2299 +		} /* end switch (sopt->sopt_name) */
  1.2300 +		if (*optsize < sizeof(val)) {
  1.2301 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.2302 +			error = EINVAL;
  1.2303 +		}
  1.2304 +	flags_out:
  1.2305 +		SCTP_INP_RUNLOCK(inp);
  1.2306 +		if (error == 0) {
  1.2307 +			/* return the option value */
  1.2308 +			*(int *)optval = val;
  1.2309 +			*optsize = sizeof(val);
  1.2310 +		}
  1.2311 +		break;
  1.2312 +        case SCTP_GET_PACKET_LOG:
  1.2313 +	{
  1.2314 +#ifdef  SCTP_PACKET_LOGGING
  1.2315 +		uint8_t *target;
  1.2316 +		int ret;
  1.2317 +
  1.2318 +		SCTP_CHECK_AND_CAST(target, optval, uint8_t, *optsize);
  1.2319 +		ret = sctp_copy_out_packet_log(target , (int)*optsize);
  1.2320 +		*optsize = ret;
  1.2321 +#else
  1.2322 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
  1.2323 +		error = EOPNOTSUPP;
  1.2324 +#endif
  1.2325 +		break;
  1.2326 +	}
  1.2327 +	case SCTP_REUSE_PORT:
  1.2328 +	{
  1.2329 +		uint32_t *value;
  1.2330 +
  1.2331 +		if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) {
  1.2332 +			/* Can't do this for a 1-m socket */
  1.2333 +			error = EINVAL;
  1.2334 +			break;
  1.2335 +		}
  1.2336 +		SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
  1.2337 +		*value = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE);
  1.2338 +		*optsize = sizeof(uint32_t);
  1.2339 +		break;
  1.2340 +	}
  1.2341 +	case SCTP_PARTIAL_DELIVERY_POINT:
  1.2342 +	{
  1.2343 +		uint32_t *value;
  1.2344 +
  1.2345 +		SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
  1.2346 +		*value = inp->partial_delivery_point;
  1.2347 +		*optsize = sizeof(uint32_t);
  1.2348 +		break;
  1.2349 +	}
  1.2350 +	case SCTP_FRAGMENT_INTERLEAVE:
  1.2351 +	{
  1.2352 +		uint32_t *value;
  1.2353 +
  1.2354 +		SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
  1.2355 +		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) {
  1.2356 +			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) {
  1.2357 +				*value = SCTP_FRAG_LEVEL_2;
  1.2358 +			} else {
  1.2359 +				*value = SCTP_FRAG_LEVEL_1;
  1.2360 +			}
  1.2361 +		} else {
  1.2362 +			*value = SCTP_FRAG_LEVEL_0;
  1.2363 +		}
  1.2364 +		*optsize = sizeof(uint32_t);
  1.2365 +		break;
  1.2366 +	}
  1.2367 +	case SCTP_CMT_ON_OFF:
  1.2368 +	{
  1.2369 +		struct sctp_assoc_value *av;
  1.2370 +
  1.2371 +		SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
  1.2372 +		SCTP_FIND_STCB(inp, stcb, av->assoc_id);
  1.2373 +		if (stcb) {
  1.2374 +			av->assoc_value = stcb->asoc.sctp_cmt_on_off;
  1.2375 +			SCTP_TCB_UNLOCK(stcb);
  1.2376 +		} else {
  1.2377 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.2378 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.2379 +			    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
  1.2380 +				SCTP_INP_RLOCK(inp);
  1.2381 +				av->assoc_value = inp->sctp_cmt_on_off;
  1.2382 +				SCTP_INP_RUNLOCK(inp);
  1.2383 +			} else {
  1.2384 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.2385 +				error = EINVAL;
  1.2386 +			}
  1.2387 +		}
  1.2388 +		if (error == 0) {
  1.2389 +			*optsize = sizeof(struct sctp_assoc_value);
  1.2390 +		}
  1.2391 +		break;
  1.2392 +	}
  1.2393 +	case SCTP_PLUGGABLE_CC:
  1.2394 +	{
  1.2395 +		struct sctp_assoc_value *av;
  1.2396 +
  1.2397 +		SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
  1.2398 +		SCTP_FIND_STCB(inp, stcb, av->assoc_id);
  1.2399 +		if (stcb) {
  1.2400 +			av->assoc_value = stcb->asoc.congestion_control_module;
  1.2401 +			SCTP_TCB_UNLOCK(stcb);
  1.2402 +		} else {
  1.2403 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.2404 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.2405 +			    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
  1.2406 +				SCTP_INP_RLOCK(inp);
  1.2407 +				av->assoc_value = inp->sctp_ep.sctp_default_cc_module;
  1.2408 +				SCTP_INP_RUNLOCK(inp);
  1.2409 +			} else {
  1.2410 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.2411 +				error = EINVAL;
  1.2412 +			}
  1.2413 +		}
  1.2414 +		if (error == 0) {
  1.2415 +			*optsize = sizeof(struct sctp_assoc_value);
  1.2416 +		}
  1.2417 +		break;
  1.2418 +	}
  1.2419 +	case SCTP_CC_OPTION:
  1.2420 +	{
  1.2421 +		struct sctp_cc_option *cc_opt;
  1.2422 +
  1.2423 +		SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, *optsize);
  1.2424 +		SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id);
  1.2425 +		if (stcb == NULL) {
  1.2426 +			error = EINVAL;
  1.2427 +		} else {
  1.2428 +			if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) {
  1.2429 +				error = ENOTSUP;
  1.2430 +			} else {
  1.2431 +				error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option)(stcb, 0, cc_opt);
  1.2432 +				*optsize = sizeof(struct sctp_cc_option);
  1.2433 +			}
  1.2434 +			SCTP_TCB_UNLOCK(stcb);
  1.2435 +		}
  1.2436 +		break;
  1.2437 +	}
  1.2438 +	case SCTP_PLUGGABLE_SS:
  1.2439 +	{
  1.2440 +		struct sctp_assoc_value *av;
  1.2441 +
  1.2442 +		SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
  1.2443 +		SCTP_FIND_STCB(inp, stcb, av->assoc_id);
  1.2444 +		if (stcb) {
  1.2445 +			av->assoc_value = stcb->asoc.stream_scheduling_module;
  1.2446 +			SCTP_TCB_UNLOCK(stcb);
  1.2447 +		} else {
  1.2448 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.2449 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.2450 +			    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
  1.2451 +				SCTP_INP_RLOCK(inp);
  1.2452 +				av->assoc_value = inp->sctp_ep.sctp_default_ss_module;
  1.2453 +				SCTP_INP_RUNLOCK(inp);
  1.2454 +			} else {
  1.2455 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.2456 +				error = EINVAL;
  1.2457 +			}
  1.2458 +		}
  1.2459 +		if (error == 0) {
  1.2460 +			*optsize = sizeof(struct sctp_assoc_value);
  1.2461 +		}
  1.2462 +		break;
  1.2463 +	}
  1.2464 +	case SCTP_SS_VALUE:
  1.2465 +	{
  1.2466 +		struct sctp_stream_value *av;
  1.2467 +
  1.2468 +		SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize);
  1.2469 +		SCTP_FIND_STCB(inp, stcb, av->assoc_id);
  1.2470 +		if (stcb) {
  1.2471 +			if (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
  1.2472 +			                                              &av->stream_value) < 0) {
  1.2473 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.2474 +				error = EINVAL;
  1.2475 +			} else {
  1.2476 +				*optsize = sizeof(struct sctp_stream_value);
  1.2477 +			}
  1.2478 +			SCTP_TCB_UNLOCK(stcb);
  1.2479 +		} else {
  1.2480 +			/* Can't get stream value without association */
  1.2481 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.2482 +			error = EINVAL;
  1.2483 +		}
  1.2484 +		break;
  1.2485 +	}
  1.2486 +	case SCTP_GET_ADDR_LEN:
  1.2487 +	{
  1.2488 +		struct sctp_assoc_value *av;
  1.2489 +
  1.2490 +		SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
  1.2491 +		error = EINVAL;
  1.2492 +#ifdef INET
  1.2493 +		if (av->assoc_value == AF_INET) {
  1.2494 +			av->assoc_value = sizeof(struct sockaddr_in);
  1.2495 +			error = 0;
  1.2496 +		}
  1.2497 +#endif
  1.2498 +#ifdef INET6
  1.2499 +		if (av->assoc_value == AF_INET6) {
  1.2500 +			av->assoc_value = sizeof(struct sockaddr_in6);
  1.2501 +			error = 0;
  1.2502 +		}
  1.2503 +#endif
  1.2504 +#if defined(__Userspace__)
  1.2505 +		if (av->assoc_value == AF_CONN) {
  1.2506 +			av->assoc_value = sizeof(struct sockaddr_conn);
  1.2507 +			error = 0;
  1.2508 +		}
  1.2509 +#endif
  1.2510 +		if (error) {
  1.2511 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.2512 +		} else {
  1.2513 +			*optsize = sizeof(struct sctp_assoc_value);
  1.2514 +		}
  1.2515 +		break;
  1.2516 +	}
  1.2517 +	case SCTP_GET_ASSOC_NUMBER:
  1.2518 +	{
  1.2519 +		uint32_t *value, cnt;
  1.2520 +
  1.2521 +		SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
  1.2522 +		cnt = 0;
  1.2523 +		SCTP_INP_RLOCK(inp);
  1.2524 +		LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.2525 +			cnt++;
  1.2526 +		}
  1.2527 +		SCTP_INP_RUNLOCK(inp);
  1.2528 +		*value = cnt;
  1.2529 +		*optsize = sizeof(uint32_t);
  1.2530 +		break;
  1.2531 +	}
  1.2532 +	case SCTP_GET_ASSOC_ID_LIST:
  1.2533 +	{
  1.2534 +		struct sctp_assoc_ids *ids;
  1.2535 +		unsigned int at, limit;
  1.2536 +
  1.2537 +		SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize);
  1.2538 +		at = 0;
  1.2539 +		limit = (*optsize-sizeof(uint32_t))/ sizeof(sctp_assoc_t);
  1.2540 +		SCTP_INP_RLOCK(inp);
  1.2541 +		LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.2542 +			if (at < limit) {
  1.2543 +				ids->gaids_assoc_id[at++] = sctp_get_associd(stcb);
  1.2544 +			} else {
  1.2545 +				error = EINVAL;
  1.2546 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.2547 +				break;
  1.2548 +			}
  1.2549 +		}
  1.2550 +		SCTP_INP_RUNLOCK(inp);
  1.2551 +		if (error == 0) {
  1.2552 +			ids->gaids_number_of_ids = at;
  1.2553 +			*optsize = ((at * sizeof(sctp_assoc_t)) + sizeof(uint32_t));
  1.2554 +		}
  1.2555 +		break;
  1.2556 +	}
  1.2557 +	case SCTP_CONTEXT:
  1.2558 +	{
  1.2559 +		struct sctp_assoc_value *av;
  1.2560 +
  1.2561 +		SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
  1.2562 +		SCTP_FIND_STCB(inp, stcb, av->assoc_id);
  1.2563 +
  1.2564 +		if (stcb) {
  1.2565 +			av->assoc_value = stcb->asoc.context;
  1.2566 +			SCTP_TCB_UNLOCK(stcb);
  1.2567 +		} else {
  1.2568 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.2569 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.2570 +			    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
  1.2571 +				SCTP_INP_RLOCK(inp);
  1.2572 +				av->assoc_value = inp->sctp_context;
  1.2573 +				SCTP_INP_RUNLOCK(inp);
  1.2574 +			} else {
  1.2575 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.2576 +				error = EINVAL;
  1.2577 +			}
  1.2578 +		}
  1.2579 +		if (error == 0) {
  1.2580 +			*optsize = sizeof(struct sctp_assoc_value);
  1.2581 +		}
  1.2582 +		break;
  1.2583 +	}
  1.2584 +	case SCTP_VRF_ID:
  1.2585 +	{
  1.2586 +		uint32_t *default_vrfid;
  1.2587 +
  1.2588 +		SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize);
  1.2589 +		*default_vrfid = inp->def_vrf_id;
  1.2590 +		*optsize = sizeof(uint32_t);
  1.2591 +		break;
  1.2592 +	}
  1.2593 +	case SCTP_GET_ASOC_VRF:
  1.2594 +	{
  1.2595 +		struct sctp_assoc_value *id;
  1.2596 +
  1.2597 +		SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize);
  1.2598 +		SCTP_FIND_STCB(inp, stcb, id->assoc_id);
  1.2599 +		if (stcb == NULL) {
  1.2600 +			error = EINVAL;
  1.2601 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.2602 +		} else {
  1.2603 +			id->assoc_value = stcb->asoc.vrf_id;
  1.2604 +			*optsize = sizeof(struct sctp_assoc_value);
  1.2605 +		}
  1.2606 +		break;
  1.2607 +	}
  1.2608 +	case SCTP_GET_VRF_IDS:
  1.2609 +	{
  1.2610 +#ifdef SCTP_MVRF
  1.2611 +		int siz_needed;
  1.2612 +		uint32_t *vrf_ids;
  1.2613 +
  1.2614 +		SCTP_CHECK_AND_CAST(vrf_ids, optval, uint32_t, *optsize);
  1.2615 +		siz_needed = inp->num_vrfs * sizeof(uint32_t);
  1.2616 +		if (*optsize < siz_needed) {
  1.2617 +			error = EINVAL;
  1.2618 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.2619 +		} else {
  1.2620 +			memcpy(vrf_ids, inp->m_vrf_ids, siz_needed);
  1.2621 +			*optsize = siz_needed;
  1.2622 +		}
  1.2623 +#else
  1.2624 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
  1.2625 +		error = EOPNOTSUPP;
  1.2626 +#endif
  1.2627 +		break;
  1.2628 +	}
  1.2629 +	case SCTP_GET_NONCE_VALUES:
  1.2630 +	{
  1.2631 +		struct sctp_get_nonce_values *gnv;
  1.2632 +
  1.2633 +		SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize);
  1.2634 +		SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id);
  1.2635 +
  1.2636 +		if (stcb) {
  1.2637 +			gnv->gn_peers_tag = stcb->asoc.peer_vtag;
  1.2638 +			gnv->gn_local_tag = stcb->asoc.my_vtag;
  1.2639 +			SCTP_TCB_UNLOCK(stcb);
  1.2640 +			*optsize = sizeof(struct sctp_get_nonce_values);
  1.2641 +		} else {
  1.2642 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
  1.2643 +			error = ENOTCONN;
  1.2644 +		}
  1.2645 +		break;
  1.2646 +	}
  1.2647 +	case SCTP_DELAYED_SACK:
  1.2648 +	{
  1.2649 +		struct sctp_sack_info *sack;
  1.2650 +
  1.2651 +		SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, *optsize);
  1.2652 +		SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id);
  1.2653 +		if (stcb) {
  1.2654 +			sack->sack_delay = stcb->asoc.delayed_ack;
  1.2655 +			sack->sack_freq = stcb->asoc.sack_freq;
  1.2656 +			SCTP_TCB_UNLOCK(stcb);
  1.2657 +		} else {
  1.2658 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.2659 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.2660 +			    (sack->sack_assoc_id == SCTP_FUTURE_ASSOC)) {
  1.2661 +				SCTP_INP_RLOCK(inp);
  1.2662 +				sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
  1.2663 +				sack->sack_freq = inp->sctp_ep.sctp_sack_freq;
  1.2664 +				SCTP_INP_RUNLOCK(inp);
  1.2665 +			} else {
  1.2666 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.2667 +				error = EINVAL;
  1.2668 +			}
  1.2669 +		}
  1.2670 +		if (error == 0) {
  1.2671 +			*optsize = sizeof(struct sctp_sack_info);
  1.2672 +		}
  1.2673 +		break;
  1.2674 +	}
  1.2675 +	case SCTP_GET_SNDBUF_USE:
  1.2676 +	{
  1.2677 +		struct sctp_sockstat *ss;
  1.2678 +
  1.2679 +		SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize);
  1.2680 +		SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id);
  1.2681 +
  1.2682 +		if (stcb) {
  1.2683 +			ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size;
  1.2684 +			ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue +
  1.2685 +						 stcb->asoc.size_on_all_streams);
  1.2686 +			SCTP_TCB_UNLOCK(stcb);
  1.2687 +			*optsize = sizeof(struct sctp_sockstat);
  1.2688 +		} else {
  1.2689 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
  1.2690 +			error = ENOTCONN;
  1.2691 +		}
  1.2692 +		break;
  1.2693 +	}
  1.2694 +	case SCTP_MAX_BURST:
  1.2695 +	{
  1.2696 +#if defined(__FreeBSD__) && __FreeBSD_version < 900000
  1.2697 +		uint8_t *value;
  1.2698 +
  1.2699 +		SCTP_CHECK_AND_CAST(value, optval, uint8_t, *optsize);
  1.2700 +
  1.2701 +		SCTP_INP_RLOCK(inp);
  1.2702 +		if (inp->sctp_ep.max_burst < 256) {
  1.2703 +			*value = inp->sctp_ep.max_burst;
  1.2704 +		} else {
  1.2705 +			*value = 255;
  1.2706 +		}
  1.2707 +		SCTP_INP_RUNLOCK(inp);
  1.2708 +		*optsize = sizeof(uint8_t);
  1.2709 +#else
  1.2710 +		struct sctp_assoc_value *av;
  1.2711 +
  1.2712 +		SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
  1.2713 +		SCTP_FIND_STCB(inp, stcb, av->assoc_id);
  1.2714 +
  1.2715 +		if (stcb) {
  1.2716 +			av->assoc_value = stcb->asoc.max_burst;
  1.2717 +			SCTP_TCB_UNLOCK(stcb);
  1.2718 +		} else {
  1.2719 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.2720 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.2721 +			    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
  1.2722 +				SCTP_INP_RLOCK(inp);
  1.2723 +				av->assoc_value = inp->sctp_ep.max_burst;
  1.2724 +				SCTP_INP_RUNLOCK(inp);
  1.2725 +			} else {
  1.2726 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.2727 +				error = EINVAL;
  1.2728 +			}
  1.2729 +		}
  1.2730 +		if (error == 0) {
  1.2731 +			*optsize = sizeof(struct sctp_assoc_value);
  1.2732 +		}
  1.2733 +#endif
  1.2734 +		break;
  1.2735 +	}
  1.2736 +	case SCTP_MAXSEG:
  1.2737 +	{
  1.2738 +		struct sctp_assoc_value *av;
  1.2739 +		int ovh;
  1.2740 +
  1.2741 +		SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
  1.2742 +		SCTP_FIND_STCB(inp, stcb, av->assoc_id);
  1.2743 +
  1.2744 +		if (stcb) {
  1.2745 +			av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc);
  1.2746 +			SCTP_TCB_UNLOCK(stcb);
  1.2747 +		} else {
  1.2748 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.2749 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.2750 +			    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
  1.2751 +				SCTP_INP_RLOCK(inp);
  1.2752 +				if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
  1.2753 +					ovh = SCTP_MED_OVERHEAD;
  1.2754 +				} else {
  1.2755 +					ovh = SCTP_MED_V4_OVERHEAD;
  1.2756 +				}
  1.2757 +				if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT)
  1.2758 +					av->assoc_value = 0;
  1.2759 +				else
  1.2760 +					av->assoc_value = inp->sctp_frag_point - ovh;
  1.2761 +				SCTP_INP_RUNLOCK(inp);
  1.2762 +			} else {
  1.2763 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.2764 +				error = EINVAL;
  1.2765 +			}
  1.2766 +		}
  1.2767 +		if (error == 0) {
  1.2768 +			*optsize = sizeof(struct sctp_assoc_value);
  1.2769 +		}
  1.2770 +		break;
  1.2771 +	}
  1.2772 +	case SCTP_GET_STAT_LOG:
  1.2773 +		error = sctp_fill_stat_log(optval, optsize);
  1.2774 +		break;
  1.2775 +	case SCTP_EVENTS:
  1.2776 +	{
  1.2777 +		struct sctp_event_subscribe *events;
  1.2778 +
  1.2779 +		SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize);
  1.2780 +		memset(events, 0, sizeof(struct sctp_event_subscribe));
  1.2781 +		SCTP_INP_RLOCK(inp);
  1.2782 +		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT))
  1.2783 +			events->sctp_data_io_event = 1;
  1.2784 +
  1.2785 +		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT))
  1.2786 +			events->sctp_association_event = 1;
  1.2787 +
  1.2788 +		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT))
  1.2789 +			events->sctp_address_event = 1;
  1.2790 +
  1.2791 +		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT))
  1.2792 +			events->sctp_send_failure_event = 1;
  1.2793 +
  1.2794 +		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR))
  1.2795 +			events->sctp_peer_error_event = 1;
  1.2796 +
  1.2797 +		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT))
  1.2798 +			events->sctp_shutdown_event = 1;
  1.2799 +
  1.2800 +		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT))
  1.2801 +			events->sctp_partial_delivery_event = 1;
  1.2802 +
  1.2803 +		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT))
  1.2804 +			events->sctp_adaptation_layer_event = 1;
  1.2805 +
  1.2806 +		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT))
  1.2807 +			events->sctp_authentication_event = 1;
  1.2808 +
  1.2809 +		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT))
  1.2810 +			events->sctp_sender_dry_event = 1;
  1.2811 +
  1.2812 +		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT))
  1.2813 +			events->sctp_stream_reset_event = 1;
  1.2814 +		SCTP_INP_RUNLOCK(inp);
  1.2815 +		*optsize = sizeof(struct sctp_event_subscribe);
  1.2816 +		break;
  1.2817 +	}
  1.2818 +	case SCTP_ADAPTATION_LAYER:
  1.2819 +	{
  1.2820 +		uint32_t *value;
  1.2821 +
  1.2822 +		SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
  1.2823 +
  1.2824 +		SCTP_INP_RLOCK(inp);
  1.2825 +		*value = inp->sctp_ep.adaptation_layer_indicator;
  1.2826 +		SCTP_INP_RUNLOCK(inp);
  1.2827 +		*optsize = sizeof(uint32_t);
  1.2828 +		break;
  1.2829 +	}
  1.2830 +	case SCTP_SET_INITIAL_DBG_SEQ:
  1.2831 +	{
  1.2832 +		uint32_t *value;
  1.2833 +
  1.2834 +		SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
  1.2835 +		SCTP_INP_RLOCK(inp);
  1.2836 +		*value = inp->sctp_ep.initial_sequence_debug;
  1.2837 +		SCTP_INP_RUNLOCK(inp);
  1.2838 +		*optsize = sizeof(uint32_t);
  1.2839 +		break;
  1.2840 +	}
  1.2841 +	case SCTP_GET_LOCAL_ADDR_SIZE:
  1.2842 +	{
  1.2843 +		uint32_t *value;
  1.2844 +
  1.2845 +		SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
  1.2846 +		SCTP_INP_RLOCK(inp);
  1.2847 +		*value = sctp_count_max_addresses(inp);
  1.2848 +		SCTP_INP_RUNLOCK(inp);
  1.2849 +		*optsize = sizeof(uint32_t);
  1.2850 +		break;
  1.2851 +	}
  1.2852 +	case SCTP_GET_REMOTE_ADDR_SIZE:
  1.2853 +	{
  1.2854 +		uint32_t *value;
  1.2855 +		size_t size;
  1.2856 +		struct sctp_nets *net;
  1.2857 +
  1.2858 +		SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
  1.2859 +		/* FIXME MT: change to sctp_assoc_value? */
  1.2860 +		SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) *value);
  1.2861 +
  1.2862 +		if (stcb) {
  1.2863 +			size = 0;
  1.2864 +			/* Count the sizes */
  1.2865 +			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1.2866 +				if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
  1.2867 +					size += sizeof(struct sockaddr_in6);
  1.2868 +				} else {
  1.2869 +					switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) {
  1.2870 +#ifdef INET
  1.2871 +					case AF_INET:
  1.2872 +						size += sizeof(struct sockaddr_in);
  1.2873 +						break;
  1.2874 +#endif
  1.2875 +#ifdef INET6
  1.2876 +					case AF_INET6:
  1.2877 +						size += sizeof(struct sockaddr_in6);
  1.2878 +						break;
  1.2879 +#endif
  1.2880 +#if defined(__Userspace__)
  1.2881 +					case AF_CONN:
  1.2882 +						size += sizeof(struct sockaddr_conn);
  1.2883 +						break;
  1.2884 +#endif
  1.2885 +					default:
  1.2886 +						break;
  1.2887 +					}
  1.2888 +				}
  1.2889 +			}
  1.2890 +			SCTP_TCB_UNLOCK(stcb);
  1.2891 +			*value = (uint32_t) size;
  1.2892 +			*optsize = sizeof(uint32_t);
  1.2893 +		} else {
  1.2894 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
  1.2895 +			error = ENOTCONN;
  1.2896 +		}
  1.2897 +		break;
  1.2898 +	}
  1.2899 +	case SCTP_GET_PEER_ADDRESSES:
  1.2900 +		/*
  1.2901 +		 * Get the address information, an array is passed in to
  1.2902 +		 * fill up we pack it.
  1.2903 +		 */
  1.2904 +	{
  1.2905 +		size_t cpsz, left;
  1.2906 +		struct sockaddr_storage *sas;
  1.2907 +		struct sctp_nets *net;
  1.2908 +		struct sctp_getaddresses *saddr;
  1.2909 +
  1.2910 +		SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
  1.2911 +		SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
  1.2912 +
  1.2913 +		if (stcb) {
  1.2914 +			left = (*optsize) - sizeof(struct sctp_getaddresses);
  1.2915 +			*optsize = sizeof(struct sctp_getaddresses);
  1.2916 +			sas = (struct sockaddr_storage *)&saddr->addr[0];
  1.2917 +
  1.2918 +			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1.2919 +				if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
  1.2920 +					cpsz = sizeof(struct sockaddr_in6);
  1.2921 +				} else {
  1.2922 +					switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) {
  1.2923 +#ifdef INET
  1.2924 +					case AF_INET:
  1.2925 +						cpsz = sizeof(struct sockaddr_in);
  1.2926 +						break;
  1.2927 +#endif
  1.2928 +#ifdef INET6
  1.2929 +					case AF_INET6:
  1.2930 +						cpsz = sizeof(struct sockaddr_in6);
  1.2931 +						break;
  1.2932 +#endif
  1.2933 +#if defined(__Userspace__)
  1.2934 +					case AF_CONN:
  1.2935 +						cpsz = sizeof(struct sockaddr_conn);
  1.2936 +						break;
  1.2937 +#endif
  1.2938 +					default:
  1.2939 +						cpsz = 0;
  1.2940 +						break;
  1.2941 +					}
  1.2942 +				}
  1.2943 +				if (cpsz == 0) {
  1.2944 +					break;
  1.2945 +				}
  1.2946 +				if (left < cpsz) {
  1.2947 +					/* not enough room. */
  1.2948 +					break;
  1.2949 +				}
  1.2950 +#if defined(INET) && defined(INET6)
  1.2951 +				if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) &&
  1.2952 +				    (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET)) {
  1.2953 +					/* Must map the address */
  1.2954 +					in6_sin_2_v4mapsin6((struct sockaddr_in *)&net->ro._l_addr,
  1.2955 +							    (struct sockaddr_in6 *)sas);
  1.2956 +				} else {
  1.2957 +#endif
  1.2958 +					memcpy(sas, &net->ro._l_addr, cpsz);
  1.2959 +#if defined(INET) && defined(INET6)
  1.2960 +				}
  1.2961 +#endif
  1.2962 +				((struct sockaddr_in *)sas)->sin_port = stcb->rport;
  1.2963 +
  1.2964 +				sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz);
  1.2965 +				left -= cpsz;
  1.2966 +				*optsize += cpsz;
  1.2967 +			}
  1.2968 +			SCTP_TCB_UNLOCK(stcb);
  1.2969 +		} else {
  1.2970 +		        SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
  1.2971 +			error = ENOENT;
  1.2972 +		}
  1.2973 +		break;
  1.2974 +	}
  1.2975 +	case SCTP_GET_LOCAL_ADDRESSES:
  1.2976 +	{
  1.2977 +		size_t limit, actual;
  1.2978 +		struct sockaddr_storage *sas;
  1.2979 +		struct sctp_getaddresses *saddr;
  1.2980 +
  1.2981 +		SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
  1.2982 +		SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
  1.2983 +
  1.2984 +		sas = (struct sockaddr_storage *)&saddr->addr[0];
  1.2985 +		limit = *optsize - sizeof(sctp_assoc_t);
  1.2986 +		actual = sctp_fill_up_addresses(inp, stcb, limit, sas);
  1.2987 +		if (stcb) {
  1.2988 +			SCTP_TCB_UNLOCK(stcb);
  1.2989 +		}
  1.2990 +		*optsize = sizeof(struct sockaddr_storage) + actual;
  1.2991 +		break;
  1.2992 +	}
  1.2993 +	case SCTP_PEER_ADDR_PARAMS:
  1.2994 +	{
  1.2995 +		struct sctp_paddrparams *paddrp;
  1.2996 +		struct sctp_nets *net;
  1.2997 +
  1.2998 +		SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize);
  1.2999 +		SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
  1.3000 +
  1.3001 +		net = NULL;
  1.3002 +		if (stcb) {
  1.3003 +			net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
  1.3004 +		} else {
  1.3005 +			/* We increment here since sctp_findassociation_ep_addr() wil
  1.3006 +			 * do a decrement if it finds the stcb as long as the locked
  1.3007 +			 * tcb (last argument) is NOT a TCB.. aka NULL.
  1.3008 +			 */
  1.3009 +			SCTP_INP_INCR_REF(inp);
  1.3010 +			stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddrp->spp_address, &net, NULL, NULL);
  1.3011 +			if (stcb == NULL) {
  1.3012 +				SCTP_INP_DECR_REF(inp);
  1.3013 +			}
  1.3014 +		}
  1.3015 +		if (stcb && (net == NULL)) {
  1.3016 +			struct sockaddr *sa;
  1.3017 +
  1.3018 +			sa = (struct sockaddr *)&paddrp->spp_address;
  1.3019 +#ifdef INET
  1.3020 +			if (sa->sa_family == AF_INET) {
  1.3021 +				struct sockaddr_in *sin;
  1.3022 +
  1.3023 +				sin = (struct sockaddr_in *)sa;
  1.3024 +				if (sin->sin_addr.s_addr) {
  1.3025 +					error = EINVAL;
  1.3026 +					SCTP_TCB_UNLOCK(stcb);
  1.3027 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.3028 +					break;
  1.3029 +				}
  1.3030 +			} else
  1.3031 +#endif
  1.3032 +#ifdef INET6
  1.3033 +			if (sa->sa_family == AF_INET6) {
  1.3034 +				struct sockaddr_in6 *sin6;
  1.3035 +
  1.3036 +				sin6 = (struct sockaddr_in6 *)sa;
  1.3037 +				if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
  1.3038 +					error = EINVAL;
  1.3039 +					SCTP_TCB_UNLOCK(stcb);
  1.3040 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.3041 +					break;
  1.3042 +				}
  1.3043 +			} else
  1.3044 +#endif
  1.3045 +#if defined(__Userspace__)
  1.3046 +			if (sa->sa_family == AF_CONN) {
  1.3047 +				struct sockaddr_conn *sconn;
  1.3048 +
  1.3049 +				sconn = (struct sockaddr_conn *)sa;
  1.3050 +				if (sconn->sconn_addr != NULL) {
  1.3051 +					error = EINVAL;
  1.3052 +					SCTP_TCB_UNLOCK(stcb);
  1.3053 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.3054 +					break;
  1.3055 +				}
  1.3056 +			} else
  1.3057 +#endif
  1.3058 +			{
  1.3059 +				error = EAFNOSUPPORT;
  1.3060 +				SCTP_TCB_UNLOCK(stcb);
  1.3061 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.3062 +				break;
  1.3063 +			}
  1.3064 +		}
  1.3065 +
  1.3066 +		if (stcb) {
  1.3067 +			/* Applies to the specific association */
  1.3068 +			paddrp->spp_flags = 0;
  1.3069 +			if (net) {
  1.3070 +				int ovh;
  1.3071 +				if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
  1.3072 +					ovh = SCTP_MED_OVERHEAD;
  1.3073 +				} else {
  1.3074 +					ovh = SCTP_MED_V4_OVERHEAD;
  1.3075 +				}
  1.3076 +
  1.3077 +				paddrp->spp_hbinterval = net->heart_beat_delay;
  1.3078 +				paddrp->spp_pathmaxrxt = net->failure_threshold;
  1.3079 +				paddrp->spp_pathmtu = net->mtu - ovh;
  1.3080 +				/* get flags for HB */
  1.3081 +				if (net->dest_state & SCTP_ADDR_NOHB) {
  1.3082 +					paddrp->spp_flags |= SPP_HB_DISABLE;
  1.3083 +				} else {
  1.3084 +					paddrp->spp_flags |= SPP_HB_ENABLE;
  1.3085 +				}
  1.3086 +				/* get flags for PMTU */
  1.3087 +				if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
  1.3088 +					paddrp->spp_flags |= SPP_PMTUD_ENABLE;
  1.3089 +				} else {
  1.3090 +					paddrp->spp_flags |= SPP_PMTUD_DISABLE;
  1.3091 +				}
  1.3092 +				if (net->dscp & 0x01) {
  1.3093 +					paddrp->spp_dscp = net->dscp & 0xfc;
  1.3094 +					paddrp->spp_flags |= SPP_DSCP;
  1.3095 +				}
  1.3096 +#ifdef INET6
  1.3097 +				if ((net->ro._l_addr.sa.sa_family == AF_INET6) &&
  1.3098 +				    (net->flowlabel & 0x80000000)) {
  1.3099 +					paddrp->spp_ipv6_flowlabel = net->flowlabel & 0x000fffff;
  1.3100 +					paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
  1.3101 +				}
  1.3102 +#endif
  1.3103 +			} else {
  1.3104 +				/*
  1.3105 +				 * No destination so return default
  1.3106 +				 * value
  1.3107 +				 */
  1.3108 +				paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure;
  1.3109 +				paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc);
  1.3110 +				if (stcb->asoc.default_dscp & 0x01) {
  1.3111 +					paddrp->spp_dscp = stcb->asoc.default_dscp & 0xfc;
  1.3112 +					paddrp->spp_flags |= SPP_DSCP;
  1.3113 +				}
  1.3114 +#ifdef INET6
  1.3115 +				if (stcb->asoc.default_flowlabel & 0x80000000) {
  1.3116 +					paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel & 0x000fffff;
  1.3117 +					paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
  1.3118 +				}
  1.3119 +#endif
  1.3120 +				/* default settings should be these */
  1.3121 +				if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
  1.3122 +					paddrp->spp_flags |= SPP_HB_DISABLE;
  1.3123 +				} else {
  1.3124 +					paddrp->spp_flags |= SPP_HB_ENABLE;
  1.3125 +				}
  1.3126 +				if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) {
  1.3127 +					paddrp->spp_flags |= SPP_PMTUD_DISABLE;
  1.3128 +				} else {
  1.3129 +					paddrp->spp_flags |= SPP_PMTUD_ENABLE;
  1.3130 +				}
  1.3131 +				paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay;
  1.3132 +			}
  1.3133 +			paddrp->spp_assoc_id = sctp_get_associd(stcb);
  1.3134 +			SCTP_TCB_UNLOCK(stcb);
  1.3135 +		} else {
  1.3136 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.3137 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.3138 +			    (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) {
  1.3139 +				/* Use endpoint defaults */
  1.3140 +				SCTP_INP_RLOCK(inp);
  1.3141 +				paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure;
  1.3142 +				paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
  1.3143 +				paddrp->spp_assoc_id = SCTP_FUTURE_ASSOC;
  1.3144 +				/* get inp's default */
  1.3145 +				if (inp->sctp_ep.default_dscp & 0x01) {
  1.3146 +					paddrp->spp_dscp = inp->sctp_ep.default_dscp & 0xfc;
  1.3147 +					paddrp->spp_flags |= SPP_DSCP;
  1.3148 +				}
  1.3149 +#ifdef INET6
  1.3150 +				if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
  1.3151 +				    (inp->sctp_ep.default_flowlabel & 0x80000000)) {
  1.3152 +					paddrp->spp_ipv6_flowlabel = inp->sctp_ep.default_flowlabel & 0x000fffff;
  1.3153 +					paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
  1.3154 +				}
  1.3155 +#endif
  1.3156 +				/* can't return this */
  1.3157 +				paddrp->spp_pathmtu = 0;
  1.3158 +
  1.3159 +				if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
  1.3160 +					paddrp->spp_flags |= SPP_HB_ENABLE;
  1.3161 +				} else {
  1.3162 +					paddrp->spp_flags |= SPP_HB_DISABLE;
  1.3163 +				}
  1.3164 +				if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) {
  1.3165 +					paddrp->spp_flags |= SPP_PMTUD_ENABLE;
  1.3166 +				} else {
  1.3167 +					paddrp->spp_flags |= SPP_PMTUD_DISABLE;
  1.3168 +				}
  1.3169 +				SCTP_INP_RUNLOCK(inp);
  1.3170 +			} else {
  1.3171 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.3172 +				error = EINVAL;
  1.3173 +			}
  1.3174 +		}
  1.3175 +		if (error == 0) {
  1.3176 +			*optsize = sizeof(struct sctp_paddrparams);
  1.3177 +		}
  1.3178 +		break;
  1.3179 +	}
  1.3180 +	case SCTP_GET_PEER_ADDR_INFO:
  1.3181 +	{
  1.3182 +		struct sctp_paddrinfo *paddri;
  1.3183 +		struct sctp_nets *net;
  1.3184 +
  1.3185 +		SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize);
  1.3186 +		SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id);
  1.3187 +
  1.3188 +		net = NULL;
  1.3189 +		if (stcb) {
  1.3190 +			net = sctp_findnet(stcb, (struct sockaddr *)&paddri->spinfo_address);
  1.3191 +		} else {
  1.3192 +			/* We increment here since sctp_findassociation_ep_addr() wil
  1.3193 +			 * do a decrement if it finds the stcb as long as the locked
  1.3194 +			 * tcb (last argument) is NOT a TCB.. aka NULL.
  1.3195 +			 */
  1.3196 +			SCTP_INP_INCR_REF(inp);
  1.3197 +			stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddri->spinfo_address, &net, NULL, NULL);
  1.3198 +			if (stcb == NULL) {
  1.3199 +				SCTP_INP_DECR_REF(inp);
  1.3200 +			}
  1.3201 +		}
  1.3202 +
  1.3203 +		if ((stcb) && (net)) {
  1.3204 +			if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
  1.3205 +				/* It's unconfirmed */
  1.3206 +				paddri->spinfo_state = SCTP_UNCONFIRMED;
  1.3207 +			} else if (net->dest_state & SCTP_ADDR_REACHABLE) {
  1.3208 +				/* It's active */
  1.3209 +				paddri->spinfo_state = SCTP_ACTIVE;
  1.3210 +			} else {
  1.3211 +				/* It's inactive */
  1.3212 +				paddri->spinfo_state = SCTP_INACTIVE;
  1.3213 +			}
  1.3214 +			paddri->spinfo_cwnd = net->cwnd;
  1.3215 +			paddri->spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
  1.3216 +			paddri->spinfo_rto = net->RTO;
  1.3217 +			paddri->spinfo_assoc_id = sctp_get_associd(stcb);
  1.3218 +			paddri->spinfo_mtu = net->mtu;
  1.3219 +			SCTP_TCB_UNLOCK(stcb);
  1.3220 +			*optsize = sizeof(struct sctp_paddrinfo);
  1.3221 +		} else {
  1.3222 +			if (stcb) {
  1.3223 +				SCTP_TCB_UNLOCK(stcb);
  1.3224 +			}
  1.3225 +		        SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
  1.3226 +			error = ENOENT;
  1.3227 +		}
  1.3228 +		break;
  1.3229 +	}
  1.3230 +	case SCTP_PCB_STATUS:
  1.3231 +	{
  1.3232 +		struct sctp_pcbinfo *spcb;
  1.3233 +
  1.3234 +		SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize);
  1.3235 +		sctp_fill_pcbinfo(spcb);
  1.3236 +		*optsize = sizeof(struct sctp_pcbinfo);
  1.3237 +		break;
  1.3238 +	}
  1.3239 +	case SCTP_STATUS:
  1.3240 +	{
  1.3241 +		struct sctp_nets *net;
  1.3242 +		struct sctp_status *sstat;
  1.3243 +
  1.3244 +		SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize);
  1.3245 +		SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id);
  1.3246 +
  1.3247 +		if (stcb == NULL) {
  1.3248 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.3249 +			error = EINVAL;
  1.3250 +			break;
  1.3251 +		}
  1.3252 +		/*
  1.3253 +		 * I think passing the state is fine since
  1.3254 +		 * sctp_constants.h will be available to the user
  1.3255 +		 * land.
  1.3256 +		 */
  1.3257 +		sstat->sstat_state = stcb->asoc.state;
  1.3258 +		sstat->sstat_assoc_id = sctp_get_associd(stcb);
  1.3259 +		sstat->sstat_rwnd = stcb->asoc.peers_rwnd;
  1.3260 +		sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt;
  1.3261 +		/*
  1.3262 +		 * We can't include chunks that have been passed to
  1.3263 +		 * the socket layer. Only things in queue.
  1.3264 +		 */
  1.3265 +		sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue +
  1.3266 +					 stcb->asoc.cnt_on_all_streams);
  1.3267 +
  1.3268 +
  1.3269 +		sstat->sstat_instrms = stcb->asoc.streamincnt;
  1.3270 +		sstat->sstat_outstrms = stcb->asoc.streamoutcnt;
  1.3271 +		sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc);
  1.3272 +#ifdef HAVE_SA_LEN
  1.3273 +		memcpy(&sstat->sstat_primary.spinfo_address,
  1.3274 +		       &stcb->asoc.primary_destination->ro._l_addr,
  1.3275 +		       ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len);
  1.3276 +#else
  1.3277 +		if (stcb->asoc.primary_destination->ro._l_addr.sa.sa_family == AF_INET) {
  1.3278 +			memcpy(&sstat->sstat_primary.spinfo_address,
  1.3279 +			       &stcb->asoc.primary_destination->ro._l_addr,
  1.3280 +			       sizeof(struct sockaddr_in));
  1.3281 +		} else {
  1.3282 +			memcpy(&sstat->sstat_primary.spinfo_address,
  1.3283 +			       &stcb->asoc.primary_destination->ro._l_addr,
  1.3284 +			       sizeof(struct sockaddr_in6));
  1.3285 +		}
  1.3286 +#endif
  1.3287 +		net = stcb->asoc.primary_destination;
  1.3288 +		((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport;
  1.3289 +		/*
  1.3290 +		 * Again the user can get info from sctp_constants.h
  1.3291 +		 * for what the state of the network is.
  1.3292 +		 */
  1.3293 +		if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
  1.3294 +			/* It's unconfirmed */
  1.3295 +			sstat->sstat_primary.spinfo_state = SCTP_UNCONFIRMED;
  1.3296 +		} else if (net->dest_state & SCTP_ADDR_REACHABLE) {
  1.3297 +			/* It's active */
  1.3298 +			sstat->sstat_primary.spinfo_state = SCTP_ACTIVE;
  1.3299 +		} else {
  1.3300 +			/* It's inactive */
  1.3301 +			sstat->sstat_primary.spinfo_state = SCTP_INACTIVE;
  1.3302 +		}
  1.3303 +		sstat->sstat_primary.spinfo_cwnd = net->cwnd;
  1.3304 +		sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
  1.3305 +		sstat->sstat_primary.spinfo_rto = net->RTO;
  1.3306 +		sstat->sstat_primary.spinfo_mtu = net->mtu;
  1.3307 +		sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb);
  1.3308 +		SCTP_TCB_UNLOCK(stcb);
  1.3309 +		*optsize = sizeof(struct sctp_status);
  1.3310 +		break;
  1.3311 +	}
  1.3312 +	case SCTP_RTOINFO:
  1.3313 +	{
  1.3314 +		struct sctp_rtoinfo *srto;
  1.3315 +
  1.3316 +		SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize);
  1.3317 +		SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
  1.3318 +
  1.3319 +		if (stcb) {
  1.3320 +			srto->srto_initial = stcb->asoc.initial_rto;
  1.3321 +			srto->srto_max = stcb->asoc.maxrto;
  1.3322 +			srto->srto_min = stcb->asoc.minrto;
  1.3323 +			SCTP_TCB_UNLOCK(stcb);
  1.3324 +		} else {
  1.3325 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.3326 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.3327 +			    (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) {
  1.3328 +				SCTP_INP_RLOCK(inp);
  1.3329 +				srto->srto_initial = inp->sctp_ep.initial_rto;
  1.3330 +				srto->srto_max = inp->sctp_ep.sctp_maxrto;
  1.3331 +				srto->srto_min = inp->sctp_ep.sctp_minrto;
  1.3332 +				SCTP_INP_RUNLOCK(inp);
  1.3333 +			} else {
  1.3334 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.3335 +				error = EINVAL;
  1.3336 +			}
  1.3337 +		}
  1.3338 +		if (error == 0) {
  1.3339 +			*optsize = sizeof(struct sctp_rtoinfo);
  1.3340 +		}
  1.3341 +		break;
  1.3342 +	}
  1.3343 +	case SCTP_TIMEOUTS:
  1.3344 +	{
  1.3345 +		struct sctp_timeouts *stimo;
  1.3346 +
  1.3347 +		SCTP_CHECK_AND_CAST(stimo, optval, struct sctp_timeouts, *optsize);
  1.3348 +		SCTP_FIND_STCB(inp, stcb, stimo->stimo_assoc_id);
  1.3349 +
  1.3350 +		if (stcb) {
  1.3351 +			stimo->stimo_init= stcb->asoc.timoinit;
  1.3352 +			stimo->stimo_data= stcb->asoc.timodata;
  1.3353 +			stimo->stimo_sack= stcb->asoc.timosack;
  1.3354 +			stimo->stimo_shutdown= stcb->asoc.timoshutdown;
  1.3355 +			stimo->stimo_heartbeat= stcb->asoc.timoheartbeat;
  1.3356 +			stimo->stimo_cookie= stcb->asoc.timocookie;
  1.3357 +			stimo->stimo_shutdownack= stcb->asoc.timoshutdownack;
  1.3358 +			SCTP_TCB_UNLOCK(stcb);
  1.3359 +			*optsize = sizeof(struct sctp_timeouts);
  1.3360 +		} else {
  1.3361 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.3362 +			error = EINVAL;
  1.3363 +		}
  1.3364 +		break;
  1.3365 +	}
  1.3366 +	case SCTP_ASSOCINFO:
  1.3367 +	{
  1.3368 +		struct sctp_assocparams *sasoc;
  1.3369 +
  1.3370 +		SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize);
  1.3371 +		SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
  1.3372 +
  1.3373 +		if (stcb) {
  1.3374 +			sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life);
  1.3375 +			sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times;
  1.3376 +			sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
  1.3377 +			sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd;
  1.3378 +			sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd;
  1.3379 +			SCTP_TCB_UNLOCK(stcb);
  1.3380 +		} else {
  1.3381 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.3382 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.3383 +			    (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) {
  1.3384 +				SCTP_INP_RLOCK(inp);
  1.3385 +				sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life);
  1.3386 +				sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times;
  1.3387 +				sasoc->sasoc_number_peer_destinations = 0;
  1.3388 +				sasoc->sasoc_peer_rwnd = 0;
  1.3389 +				sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv);
  1.3390 +				SCTP_INP_RUNLOCK(inp);
  1.3391 +			} else {
  1.3392 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.3393 +				error = EINVAL;
  1.3394 +			}
  1.3395 +		}
  1.3396 +		if (error == 0) {
  1.3397 +			*optsize = sizeof(struct sctp_assocparams);
  1.3398 +		}
  1.3399 +		break;
  1.3400 +	}
  1.3401 +	case SCTP_DEFAULT_SEND_PARAM:
  1.3402 +	{
  1.3403 +		struct sctp_sndrcvinfo *s_info;
  1.3404 +
  1.3405 +		SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize);
  1.3406 +		SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
  1.3407 +
  1.3408 +		if (stcb) {
  1.3409 +			memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send));
  1.3410 +			SCTP_TCB_UNLOCK(stcb);
  1.3411 +		} else {
  1.3412 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.3413 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.3414 +			    (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC)) {
  1.3415 +				SCTP_INP_RLOCK(inp);
  1.3416 +				memcpy(s_info, &inp->def_send, sizeof(inp->def_send));
  1.3417 +				SCTP_INP_RUNLOCK(inp);
  1.3418 +			} else {
  1.3419 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.3420 +				error = EINVAL;
  1.3421 +			}
  1.3422 +		}
  1.3423 +		if (error == 0) {
  1.3424 +			*optsize = sizeof(struct sctp_sndrcvinfo);
  1.3425 +		}
  1.3426 +		break;
  1.3427 +	}
  1.3428 +	case SCTP_INITMSG:
  1.3429 +	{
  1.3430 +		struct sctp_initmsg *sinit;
  1.3431 +
  1.3432 +		SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize);
  1.3433 +		SCTP_INP_RLOCK(inp);
  1.3434 +		sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count;
  1.3435 +		sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome;
  1.3436 +		sinit->sinit_max_attempts = inp->sctp_ep.max_init_times;
  1.3437 +		sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max;
  1.3438 +		SCTP_INP_RUNLOCK(inp);
  1.3439 +		*optsize = sizeof(struct sctp_initmsg);
  1.3440 +		break;
  1.3441 +	}
  1.3442 +	case SCTP_PRIMARY_ADDR:
  1.3443 +		/* we allow a "get" operation on this */
  1.3444 +	{
  1.3445 +		struct sctp_setprim *ssp;
  1.3446 +
  1.3447 +		SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize);
  1.3448 +		SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id);
  1.3449 +
  1.3450 +		if (stcb) {
  1.3451 +			/* simply copy out the sockaddr_storage... */
  1.3452 +			size_t len;
  1.3453 +
  1.3454 +			len = *optsize;
  1.3455 +#ifdef HAVE_SA_LEN
  1.3456 +			if (len > stcb->asoc.primary_destination->ro._l_addr.sa.sa_len)
  1.3457 +				len = stcb->asoc.primary_destination->ro._l_addr.sa.sa_len;
  1.3458 +#else
  1.3459 +			if (stcb->asoc.primary_destination->ro._l_addr.sa.sa_family == AF_INET &&
  1.3460 +			    len > sizeof(struct sockaddr_in))
  1.3461 +				len = sizeof(struct sockaddr_in);
  1.3462 +			else if (
  1.3463 +			    stcb->asoc.primary_destination->ro._l_addr.sa.sa_family == AF_INET6 &&
  1.3464 +			    len > sizeof(struct sockaddr_in6))
  1.3465 +				len = sizeof(struct sockaddr_in6);
  1.3466 +#endif
  1.3467 +
  1.3468 +			memcpy(&ssp->ssp_addr,
  1.3469 +			       &stcb->asoc.primary_destination->ro._l_addr,
  1.3470 +			       len);
  1.3471 +			SCTP_TCB_UNLOCK(stcb);
  1.3472 +			*optsize = sizeof(struct sctp_setprim);
  1.3473 +		} else {
  1.3474 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.3475 +			error = EINVAL;
  1.3476 +		}
  1.3477 +		break;
  1.3478 +	}
  1.3479 +	case SCTP_HMAC_IDENT:
  1.3480 +	{
  1.3481 +		struct sctp_hmacalgo *shmac;
  1.3482 +		sctp_hmaclist_t *hmaclist;
  1.3483 +		uint32_t size;
  1.3484 +		int i;
  1.3485 +
  1.3486 +		SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize);
  1.3487 +
  1.3488 +		SCTP_INP_RLOCK(inp);
  1.3489 +		hmaclist = inp->sctp_ep.local_hmacs;
  1.3490 +		if (hmaclist == NULL) {
  1.3491 +			/* no HMACs to return */
  1.3492 +			*optsize = sizeof(*shmac);
  1.3493 +			SCTP_INP_RUNLOCK(inp);
  1.3494 +			break;
  1.3495 +		}
  1.3496 +		/* is there room for all of the hmac ids? */
  1.3497 +		size = sizeof(*shmac) + (hmaclist->num_algo *
  1.3498 +					 sizeof(shmac->shmac_idents[0]));
  1.3499 +		if ((size_t)(*optsize) < size) {
  1.3500 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.3501 +			error = EINVAL;
  1.3502 +			SCTP_INP_RUNLOCK(inp);
  1.3503 +			break;
  1.3504 +		}
  1.3505 +		/* copy in the list */
  1.3506 +		shmac->shmac_number_of_idents = hmaclist->num_algo;
  1.3507 +		for (i = 0; i < hmaclist->num_algo; i++) {
  1.3508 +			shmac->shmac_idents[i] = hmaclist->hmac[i];
  1.3509 +		}
  1.3510 +		SCTP_INP_RUNLOCK(inp);
  1.3511 +		*optsize = size;
  1.3512 +		break;
  1.3513 +	}
  1.3514 +	case SCTP_AUTH_ACTIVE_KEY:
  1.3515 +	{
  1.3516 +		struct sctp_authkeyid *scact;
  1.3517 +
  1.3518 +		SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize);
  1.3519 +		SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
  1.3520 +
  1.3521 +		if (stcb) {
  1.3522 +			/* get the active key on the assoc */
  1.3523 +			scact->scact_keynumber = stcb->asoc.authinfo.active_keyid;
  1.3524 +			SCTP_TCB_UNLOCK(stcb);
  1.3525 +		} else {
  1.3526 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.3527 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.3528 +			    (scact->scact_assoc_id == SCTP_FUTURE_ASSOC)) {
  1.3529 +				/* get the endpoint active key */
  1.3530 +				SCTP_INP_RLOCK(inp);
  1.3531 +				scact->scact_keynumber = inp->sctp_ep.default_keyid;
  1.3532 +				SCTP_INP_RUNLOCK(inp);
  1.3533 +			} else {
  1.3534 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.3535 +				error = EINVAL;
  1.3536 +			}
  1.3537 +		}
  1.3538 +		if (error == 0) {
  1.3539 +			*optsize = sizeof(struct sctp_authkeyid);
  1.3540 +		}
  1.3541 +		break;
  1.3542 +	}
  1.3543 +	case SCTP_LOCAL_AUTH_CHUNKS:
  1.3544 +	{
  1.3545 +		struct sctp_authchunks *sac;
  1.3546 +		sctp_auth_chklist_t *chklist = NULL;
  1.3547 +		size_t size = 0;
  1.3548 +
  1.3549 +		SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
  1.3550 +		SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
  1.3551 +
  1.3552 +		if (stcb) {
  1.3553 +			/* get off the assoc */
  1.3554 +			chklist = stcb->asoc.local_auth_chunks;
  1.3555 +			/* is there enough space? */
  1.3556 +			size = sctp_auth_get_chklist_size(chklist);
  1.3557 +			if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
  1.3558 +				error = EINVAL;
  1.3559 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.3560 +			} else {
  1.3561 +				/* copy in the chunks */
  1.3562 +				(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
  1.3563 +				sac->gauth_number_of_chunks = (uint32_t)size;
  1.3564 +				*optsize = sizeof(struct sctp_authchunks) + size;
  1.3565 +			}
  1.3566 +			SCTP_TCB_UNLOCK(stcb);
  1.3567 +		} else {
  1.3568 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.3569 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.3570 +			    (sac->gauth_assoc_id == SCTP_FUTURE_ASSOC)) {
  1.3571 +				/* get off the endpoint */
  1.3572 +				SCTP_INP_RLOCK(inp);
  1.3573 +				chklist = inp->sctp_ep.local_auth_chunks;
  1.3574 +				/* is there enough space? */
  1.3575 +				size = sctp_auth_get_chklist_size(chklist);
  1.3576 +				if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
  1.3577 +					error = EINVAL;
  1.3578 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.3579 +				} else {
  1.3580 +					/* copy in the chunks */
  1.3581 +					(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
  1.3582 +					sac->gauth_number_of_chunks = (uint32_t)size;
  1.3583 +					*optsize = sizeof(struct sctp_authchunks) + size;
  1.3584 +				}
  1.3585 +				SCTP_INP_RUNLOCK(inp);
  1.3586 +			} else {
  1.3587 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.3588 +				error = EINVAL;
  1.3589 +			}
  1.3590 +		}
  1.3591 +		break;
  1.3592 +	}
  1.3593 +	case SCTP_PEER_AUTH_CHUNKS:
  1.3594 +	{
  1.3595 +		struct sctp_authchunks *sac;
  1.3596 +		sctp_auth_chklist_t *chklist = NULL;
  1.3597 +		size_t size = 0;
  1.3598 +
  1.3599 +		SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
  1.3600 +		SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
  1.3601 +
  1.3602 +		if (stcb) {
  1.3603 +			/* get off the assoc */
  1.3604 +			chklist = stcb->asoc.peer_auth_chunks;
  1.3605 +			/* is there enough space? */
  1.3606 +			size = sctp_auth_get_chklist_size(chklist);
  1.3607 +			if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
  1.3608 +				error = EINVAL;
  1.3609 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.3610 +			} else {
  1.3611 +				/* copy in the chunks */
  1.3612 +				(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
  1.3613 +				sac->gauth_number_of_chunks = (uint32_t)size;
  1.3614 +				*optsize = sizeof(struct sctp_authchunks) + size;
  1.3615 +			}
  1.3616 +			SCTP_TCB_UNLOCK(stcb);
  1.3617 +		} else {
  1.3618 +		        SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
  1.3619 +			error = ENOENT;
  1.3620 +		}
  1.3621 +		break;
  1.3622 +	}
  1.3623 +#if defined(HAVE_SCTP_PEELOFF_SOCKOPT)
  1.3624 +	case SCTP_PEELOFF:
  1.3625 +	{
  1.3626 +		struct sctp_peeloff_opt *peeloff;
  1.3627 +
  1.3628 +		SCTP_CHECK_AND_CAST(peeloff, optval, struct sctp_peeloff_opt, *optsize);
  1.3629 +		/* do the peeloff */
  1.3630 +		error = sctp_peeloff_option(p, peeloff);
  1.3631 +		if (error == 0) {
  1.3632 +			*optsize = sizeof(struct sctp_peeloff_opt);
  1.3633 +		}
  1.3634 +	}
  1.3635 +	break;
  1.3636 +#endif /* HAVE_SCTP_PEELOFF_SOCKOPT */
  1.3637 +	case SCTP_EVENT:
  1.3638 +	{
  1.3639 +		struct sctp_event *event;
  1.3640 +		uint32_t event_type;
  1.3641 +
  1.3642 +		SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, *optsize);
  1.3643 +		SCTP_FIND_STCB(inp, stcb, event->se_assoc_id);
  1.3644 +
  1.3645 +		switch (event->se_type) {
  1.3646 +		case SCTP_ASSOC_CHANGE:
  1.3647 +			event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT;
  1.3648 +			break;
  1.3649 +		case SCTP_PEER_ADDR_CHANGE:
  1.3650 +			event_type = SCTP_PCB_FLAGS_RECVPADDREVNT;
  1.3651 +			break;
  1.3652 +		case SCTP_REMOTE_ERROR:
  1.3653 +			event_type = SCTP_PCB_FLAGS_RECVPEERERR;
  1.3654 +			break;
  1.3655 +		case SCTP_SEND_FAILED:
  1.3656 +			event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT;
  1.3657 +			break;
  1.3658 +		case SCTP_SHUTDOWN_EVENT:
  1.3659 +			event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT;
  1.3660 +			break;
  1.3661 +		case SCTP_ADAPTATION_INDICATION:
  1.3662 +			event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT;
  1.3663 +			break;
  1.3664 +		case SCTP_PARTIAL_DELIVERY_EVENT:
  1.3665 +			event_type = SCTP_PCB_FLAGS_PDAPIEVNT;
  1.3666 +			break;
  1.3667 +		case SCTP_AUTHENTICATION_EVENT:
  1.3668 +			event_type = SCTP_PCB_FLAGS_AUTHEVNT;
  1.3669 +			break;
  1.3670 +		case SCTP_STREAM_RESET_EVENT:
  1.3671 +			event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT;
  1.3672 +			break;
  1.3673 +		case SCTP_SENDER_DRY_EVENT:
  1.3674 +			event_type = SCTP_PCB_FLAGS_DRYEVNT;
  1.3675 +			break;
  1.3676 +		case SCTP_NOTIFICATIONS_STOPPED_EVENT:
  1.3677 +			event_type = 0;
  1.3678 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
  1.3679 +			error = ENOTSUP;
  1.3680 +			break;
  1.3681 +		case SCTP_ASSOC_RESET_EVENT:
  1.3682 +			event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT;
  1.3683 +			break;
  1.3684 +		case SCTP_STREAM_CHANGE_EVENT:
  1.3685 +			event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT;
  1.3686 +			break;
  1.3687 +		case SCTP_SEND_FAILED_EVENT:
  1.3688 +			event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT;
  1.3689 +			break;
  1.3690 +		default:
  1.3691 +			event_type = 0;
  1.3692 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.3693 +			error = EINVAL;
  1.3694 +			break;
  1.3695 +		}
  1.3696 +		if (event_type > 0) {
  1.3697 +			if (stcb) {
  1.3698 +				event->se_on = sctp_stcb_is_feature_on(inp, stcb, event_type);
  1.3699 +				SCTP_TCB_UNLOCK(stcb);
  1.3700 +			} else {
  1.3701 +				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.3702 +				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.3703 +				    (event->se_assoc_id == SCTP_FUTURE_ASSOC)) {
  1.3704 +					SCTP_INP_RLOCK(inp);
  1.3705 +					event->se_on = sctp_is_feature_on(inp, event_type);
  1.3706 +					SCTP_INP_RUNLOCK(inp);
  1.3707 +				} else {
  1.3708 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.3709 +					error = EINVAL;
  1.3710 +				}
  1.3711 +			}
  1.3712 +		}
  1.3713 +		if (error == 0) {
  1.3714 +			*optsize = sizeof(struct sctp_event);
  1.3715 +		}
  1.3716 +		break;
  1.3717 +	}
  1.3718 +	case SCTP_RECVRCVINFO:
  1.3719 +	{
  1.3720 +		int onoff;
  1.3721 +
  1.3722 +		if (*optsize < sizeof(int)) {
  1.3723 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.3724 +			error = EINVAL;
  1.3725 +		} else {
  1.3726 +			SCTP_INP_RLOCK(inp);
  1.3727 +			onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
  1.3728 +			SCTP_INP_RUNLOCK(inp);
  1.3729 +		}
  1.3730 +		if (error == 0) {
  1.3731 +			/* return the option value */
  1.3732 +			*(int *)optval = onoff;
  1.3733 +			*optsize = sizeof(int);
  1.3734 +		}
  1.3735 +		break;
  1.3736 +	}
  1.3737 +	case SCTP_RECVNXTINFO:
  1.3738 +	{
  1.3739 +		int onoff;
  1.3740 +
  1.3741 +		if (*optsize < sizeof(int)) {
  1.3742 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.3743 +			error = EINVAL;
  1.3744 +		} else {
  1.3745 +			SCTP_INP_RLOCK(inp);
  1.3746 +			onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
  1.3747 +			SCTP_INP_RUNLOCK(inp);
  1.3748 +		}
  1.3749 +		if (error == 0) {
  1.3750 +			/* return the option value */
  1.3751 +			*(int *)optval = onoff;
  1.3752 +			*optsize = sizeof(int);
  1.3753 +		}
  1.3754 +		break;
  1.3755 +	}
  1.3756 +	case SCTP_DEFAULT_SNDINFO:
  1.3757 +	{
  1.3758 +		struct sctp_sndinfo *info;
  1.3759 +
  1.3760 +		SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, *optsize);
  1.3761 +		SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id);
  1.3762 +
  1.3763 +		if (stcb) {
  1.3764 +			info->snd_sid = stcb->asoc.def_send.sinfo_stream;
  1.3765 +			info->snd_flags = stcb->asoc.def_send.sinfo_flags;
  1.3766 +			info->snd_flags &= 0xfff0;
  1.3767 +			info->snd_ppid = stcb->asoc.def_send.sinfo_ppid;
  1.3768 +			info->snd_context = stcb->asoc.def_send.sinfo_context;
  1.3769 +			SCTP_TCB_UNLOCK(stcb);
  1.3770 +		} else {
  1.3771 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.3772 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.3773 +			    (info->snd_assoc_id == SCTP_FUTURE_ASSOC)) {
  1.3774 +				SCTP_INP_RLOCK(inp);
  1.3775 +				info->snd_sid = inp->def_send.sinfo_stream;
  1.3776 +				info->snd_flags = inp->def_send.sinfo_flags;
  1.3777 +				info->snd_flags &= 0xfff0;
  1.3778 +				info->snd_ppid = inp->def_send.sinfo_ppid;
  1.3779 +				info->snd_context = inp->def_send.sinfo_context;
  1.3780 +				SCTP_INP_RUNLOCK(inp);
  1.3781 +			} else {
  1.3782 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.3783 +				error = EINVAL;
  1.3784 +			}
  1.3785 +		}
  1.3786 +		if (error == 0) {
  1.3787 +			*optsize = sizeof(struct sctp_sndinfo);
  1.3788 +		}
  1.3789 +		break;
  1.3790 +	}
  1.3791 +	case SCTP_DEFAULT_PRINFO:
  1.3792 +	{
  1.3793 +		struct sctp_default_prinfo *info;
  1.3794 +
  1.3795 +		SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, *optsize);
  1.3796 +		SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id);
  1.3797 +
  1.3798 +		if (stcb) {
  1.3799 +			info->pr_policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
  1.3800 +			info->pr_value = stcb->asoc.def_send.sinfo_timetolive;
  1.3801 +			SCTP_TCB_UNLOCK(stcb);
  1.3802 +		} else {
  1.3803 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.3804 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.3805 +			    (info->pr_assoc_id == SCTP_FUTURE_ASSOC)) {
  1.3806 +				SCTP_INP_RLOCK(inp);
  1.3807 +				info->pr_policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags);
  1.3808 +				info->pr_value = inp->def_send.sinfo_timetolive;
  1.3809 +				SCTP_INP_RUNLOCK(inp);
  1.3810 +			} else {
  1.3811 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.3812 +				error = EINVAL;
  1.3813 +			}
  1.3814 +		}
  1.3815 +		if (error == 0) {
  1.3816 +			*optsize = sizeof(struct sctp_default_prinfo);
  1.3817 +		}
  1.3818 +		break;
  1.3819 +	}
  1.3820 +	case SCTP_PEER_ADDR_THLDS:
  1.3821 +	{
  1.3822 +		struct sctp_paddrthlds *thlds;
  1.3823 +		struct sctp_nets *net;
  1.3824 +
  1.3825 +		SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, *optsize);
  1.3826 +		SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
  1.3827 +
  1.3828 +		net = NULL;
  1.3829 +		if (stcb) {
  1.3830 +			net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_address);
  1.3831 +		} else {
  1.3832 +			/* We increment here since sctp_findassociation_ep_addr() wil
  1.3833 +			 * do a decrement if it finds the stcb as long as the locked
  1.3834 +			 * tcb (last argument) is NOT a TCB.. aka NULL.
  1.3835 +			 */
  1.3836 +			SCTP_INP_INCR_REF(inp);
  1.3837 +			stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&thlds->spt_address, &net, NULL, NULL);
  1.3838 +			if (stcb == NULL) {
  1.3839 +				SCTP_INP_DECR_REF(inp);
  1.3840 +			}
  1.3841 +		}
  1.3842 +		if (stcb && (net == NULL)) {
  1.3843 +			struct sockaddr *sa;
  1.3844 +
  1.3845 +			sa = (struct sockaddr *)&thlds->spt_address;
  1.3846 +#ifdef INET
  1.3847 +			if (sa->sa_family == AF_INET) {
  1.3848 +				struct sockaddr_in *sin;
  1.3849 +
  1.3850 +				sin = (struct sockaddr_in *)sa;
  1.3851 +				if (sin->sin_addr.s_addr) {
  1.3852 +					error = EINVAL;
  1.3853 +					SCTP_TCB_UNLOCK(stcb);
  1.3854 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.3855 +					break;
  1.3856 +				}
  1.3857 +			} else
  1.3858 +#endif
  1.3859 +#ifdef INET6
  1.3860 +			if (sa->sa_family == AF_INET6) {
  1.3861 +				struct sockaddr_in6 *sin6;
  1.3862 +
  1.3863 +				sin6 = (struct sockaddr_in6 *)sa;
  1.3864 +				if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
  1.3865 +					error = EINVAL;
  1.3866 +					SCTP_TCB_UNLOCK(stcb);
  1.3867 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.3868 +					break;
  1.3869 +				}
  1.3870 +			} else
  1.3871 +#endif
  1.3872 +#if defined(__Userspace__)
  1.3873 +			if (sa->sa_family == AF_CONN) {
  1.3874 +				struct sockaddr_conn *sconn;
  1.3875 +
  1.3876 +				sconn = (struct sockaddr_conn *)sa;
  1.3877 +				if (sconn->sconn_addr != NULL) {
  1.3878 +					error = EINVAL;
  1.3879 +					SCTP_TCB_UNLOCK(stcb);
  1.3880 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.3881 +					break;
  1.3882 +				}
  1.3883 +			} else
  1.3884 +#endif
  1.3885 +			{
  1.3886 +				error = EAFNOSUPPORT;
  1.3887 +				SCTP_TCB_UNLOCK(stcb);
  1.3888 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.3889 +				break;
  1.3890 +			}
  1.3891 +		}
  1.3892 +
  1.3893 +		if (stcb) {
  1.3894 +			if (net) {
  1.3895 +				thlds->spt_pathmaxrxt = net->failure_threshold;
  1.3896 +				thlds->spt_pathpfthld = net->pf_threshold;
  1.3897 +			} else {
  1.3898 +				thlds->spt_pathmaxrxt = stcb->asoc.def_net_failure;
  1.3899 +				thlds->spt_pathpfthld = stcb->asoc.def_net_pf_threshold;
  1.3900 +			}
  1.3901 +			thlds->spt_assoc_id = sctp_get_associd(stcb);
  1.3902 +			SCTP_TCB_UNLOCK(stcb);
  1.3903 +		} else {
  1.3904 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.3905 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.3906 +			    (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) {
  1.3907 +				/* Use endpoint defaults */
  1.3908 +				SCTP_INP_RLOCK(inp);
  1.3909 +				thlds->spt_pathmaxrxt = inp->sctp_ep.def_net_failure;
  1.3910 +				thlds->spt_pathpfthld = inp->sctp_ep.def_net_pf_threshold;
  1.3911 +				SCTP_INP_RUNLOCK(inp);
  1.3912 +			} else {
  1.3913 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.3914 +				error = EINVAL;
  1.3915 +			}
  1.3916 +		}
  1.3917 +		if (error == 0) {
  1.3918 +			*optsize = sizeof(struct sctp_paddrthlds);
  1.3919 +		}
  1.3920 +		break;
  1.3921 +	}
  1.3922 +	case SCTP_REMOTE_UDP_ENCAPS_PORT:
  1.3923 +	{
  1.3924 +		struct sctp_udpencaps *encaps;
  1.3925 +		struct sctp_nets *net;
  1.3926 +
  1.3927 +		SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, *optsize);
  1.3928 +		SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id);
  1.3929 +
  1.3930 +		if (stcb) {
  1.3931 +			net = sctp_findnet(stcb, (struct sockaddr *)&encaps->sue_address);
  1.3932 +		} else {
  1.3933 +			/* We increment here since sctp_findassociation_ep_addr() wil
  1.3934 +			 * do a decrement if it finds the stcb as long as the locked
  1.3935 +			 * tcb (last argument) is NOT a TCB.. aka NULL.
  1.3936 +			 */
  1.3937 +			net = NULL;
  1.3938 +			SCTP_INP_INCR_REF(inp);
  1.3939 +			stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&encaps->sue_address, &net, NULL, NULL);
  1.3940 +			if (stcb == NULL) {
  1.3941 +				SCTP_INP_DECR_REF(inp);
  1.3942 +			}
  1.3943 +		}
  1.3944 +		if (stcb && (net == NULL)) {
  1.3945 +			struct sockaddr *sa;
  1.3946 +
  1.3947 +			sa = (struct sockaddr *)&encaps->sue_address;
  1.3948 +#ifdef INET
  1.3949 +			if (sa->sa_family == AF_INET) {
  1.3950 +				struct sockaddr_in *sin;
  1.3951 +
  1.3952 +				sin = (struct sockaddr_in *)sa;
  1.3953 +				if (sin->sin_addr.s_addr) {
  1.3954 +					error = EINVAL;
  1.3955 +					SCTP_TCB_UNLOCK(stcb);
  1.3956 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.3957 +					break;
  1.3958 +				}
  1.3959 +			} else
  1.3960 +#endif
  1.3961 +#ifdef INET6
  1.3962 +			if (sa->sa_family == AF_INET6) {
  1.3963 +				struct sockaddr_in6 *sin6;
  1.3964 +
  1.3965 +				sin6 = (struct sockaddr_in6 *)sa;
  1.3966 +				if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
  1.3967 +					error = EINVAL;
  1.3968 +					SCTP_TCB_UNLOCK(stcb);
  1.3969 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.3970 +					break;
  1.3971 +				}
  1.3972 +			} else
  1.3973 +#endif
  1.3974 +#if defined(__Userspace__)
  1.3975 +			if (sa->sa_family == AF_CONN) {
  1.3976 +				struct sockaddr_conn *sconn;
  1.3977 +
  1.3978 +				sconn = (struct sockaddr_conn *)sa;
  1.3979 +				if (sconn->sconn_addr != NULL) {
  1.3980 +					error = EINVAL;
  1.3981 +					SCTP_TCB_UNLOCK(stcb);
  1.3982 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.3983 +					break;
  1.3984 +				}
  1.3985 +			} else
  1.3986 +#endif
  1.3987 +			{
  1.3988 +				error = EAFNOSUPPORT;
  1.3989 +				SCTP_TCB_UNLOCK(stcb);
  1.3990 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.3991 +				break;
  1.3992 +			}
  1.3993 +		}
  1.3994 +
  1.3995 +		if (stcb) {
  1.3996 +			if (net) {
  1.3997 +				encaps->sue_port = net->port;
  1.3998 +			} else {
  1.3999 +				encaps->sue_port = stcb->asoc.port;
  1.4000 +			}
  1.4001 +			SCTP_TCB_UNLOCK(stcb);
  1.4002 +		} else {
  1.4003 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.4004 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.4005 +			    (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) {
  1.4006 +				SCTP_INP_RLOCK(inp);
  1.4007 +				encaps->sue_port = inp->sctp_ep.port;
  1.4008 +				SCTP_INP_RUNLOCK(inp);
  1.4009 +			} else {
  1.4010 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4011 +				error = EINVAL;
  1.4012 +			}
  1.4013 +		}
  1.4014 +		if (error == 0) {
  1.4015 +			*optsize = sizeof(struct sctp_udpencaps);
  1.4016 +		}
  1.4017 +		break;
  1.4018 +	}
  1.4019 +	case SCTP_ENABLE_STREAM_RESET:
  1.4020 +	{
  1.4021 +		struct sctp_assoc_value *av;
  1.4022 +
  1.4023 +		SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
  1.4024 +		SCTP_FIND_STCB(inp, stcb, av->assoc_id);
  1.4025 +
  1.4026 +		if (stcb) {
  1.4027 +			av->assoc_value = (uint32_t)stcb->asoc.local_strreset_support;
  1.4028 +			SCTP_TCB_UNLOCK(stcb);
  1.4029 +		} else {
  1.4030 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.4031 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.4032 +			    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
  1.4033 +				SCTP_INP_RLOCK(inp);
  1.4034 +				av->assoc_value = (uint32_t)inp->local_strreset_support;
  1.4035 +				SCTP_INP_RUNLOCK(inp);
  1.4036 +			} else {
  1.4037 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4038 +				error = EINVAL;
  1.4039 +			}
  1.4040 +		}
  1.4041 +		if (error == 0) {
  1.4042 +			*optsize = sizeof(struct sctp_assoc_value);
  1.4043 +		}
  1.4044 +		break;
  1.4045 +	}
  1.4046 +	default:
  1.4047 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
  1.4048 +		error = ENOPROTOOPT;
  1.4049 +		break;
  1.4050 +	} /* end switch (sopt->sopt_name) */
  1.4051 +	if (error) {
  1.4052 +		*optsize = 0;
  1.4053 +	}
  1.4054 +	return (error);
  1.4055 +}
  1.4056 +
  1.4057 +#if defined(__Panda__) || defined(__Userspace__)
  1.4058 +int
  1.4059 +#else
  1.4060 +static int
  1.4061 +#endif
  1.4062 +sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
  1.4063 +	    void *p)
  1.4064 +{
  1.4065 +	int error, set_opt;
  1.4066 +	uint32_t *mopt;
  1.4067 +	struct sctp_tcb *stcb = NULL;
  1.4068 +	struct sctp_inpcb *inp = NULL;
  1.4069 +	uint32_t vrf_id;
  1.4070 +
  1.4071 +	if (optval == NULL) {
  1.4072 +		SCTP_PRINTF("optval is NULL\n");
  1.4073 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4074 +		return (EINVAL);
  1.4075 +	}
  1.4076 +	inp = (struct sctp_inpcb *)so->so_pcb;
  1.4077 +	if (inp == NULL) {
  1.4078 +		SCTP_PRINTF("inp is NULL?\n");
  1.4079 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4080 +		return (EINVAL);
  1.4081 +	}
  1.4082 +	vrf_id = inp->def_vrf_id;
  1.4083 +
  1.4084 +	error = 0;
  1.4085 +	switch (optname) {
  1.4086 +	case SCTP_NODELAY:
  1.4087 +	case SCTP_AUTOCLOSE:
  1.4088 +	case SCTP_AUTO_ASCONF:
  1.4089 +	case SCTP_EXPLICIT_EOR:
  1.4090 +	case SCTP_DISABLE_FRAGMENTS:
  1.4091 +	case SCTP_USE_EXT_RCVINFO:
  1.4092 +	case SCTP_I_WANT_MAPPED_V4_ADDR:
  1.4093 +		/* copy in the option value */
  1.4094 +		SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize);
  1.4095 +		set_opt = 0;
  1.4096 +		if (error)
  1.4097 +			break;
  1.4098 +		switch (optname) {
  1.4099 +		case SCTP_DISABLE_FRAGMENTS:
  1.4100 +			set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT;
  1.4101 +			break;
  1.4102 +		case SCTP_AUTO_ASCONF:
  1.4103 +			/*
  1.4104 +			 * NOTE: we don't really support this flag
  1.4105 +			 */
  1.4106 +			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
  1.4107 +				/* only valid for bound all sockets */
  1.4108 +				if ((SCTP_BASE_SYSCTL(sctp_auto_asconf) == 0) &&
  1.4109 +				    (*mopt != 0)) {
  1.4110 +					/* forbidden by admin */
  1.4111 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM);
  1.4112 +					return (EPERM);
  1.4113 +				}
  1.4114 +				set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF;
  1.4115 +			} else {
  1.4116 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4117 +				return (EINVAL);
  1.4118 +			}
  1.4119 +			break;
  1.4120 +		case SCTP_EXPLICIT_EOR:
  1.4121 +			set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR;
  1.4122 +			break;
  1.4123 +		case SCTP_USE_EXT_RCVINFO:
  1.4124 +			set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO;
  1.4125 +			break;
  1.4126 +		case SCTP_I_WANT_MAPPED_V4_ADDR:
  1.4127 +			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
  1.4128 +				set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4;
  1.4129 +			} else {
  1.4130 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4131 +				return (EINVAL);
  1.4132 +			}
  1.4133 +			break;
  1.4134 +		case SCTP_NODELAY:
  1.4135 +			set_opt = SCTP_PCB_FLAGS_NODELAY;
  1.4136 +			break;
  1.4137 +		case SCTP_AUTOCLOSE:
  1.4138 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.4139 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
  1.4140 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4141 +				return (EINVAL);
  1.4142 +			}
  1.4143 +			set_opt = SCTP_PCB_FLAGS_AUTOCLOSE;
  1.4144 +			/*
  1.4145 +			 * The value is in ticks. Note this does not effect
  1.4146 +			 * old associations, only new ones.
  1.4147 +			 */
  1.4148 +			inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt);
  1.4149 +			break;
  1.4150 +		}
  1.4151 +		SCTP_INP_WLOCK(inp);
  1.4152 +		if (*mopt != 0) {
  1.4153 +			sctp_feature_on(inp, set_opt);
  1.4154 +		} else {
  1.4155 +			sctp_feature_off(inp, set_opt);
  1.4156 +		}
  1.4157 +		SCTP_INP_WUNLOCK(inp);
  1.4158 +		break;
  1.4159 +	case SCTP_REUSE_PORT:
  1.4160 +	{
  1.4161 +		SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize);
  1.4162 +		if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND)  == 0) {
  1.4163 +			/* Can't set it after we are bound */
  1.4164 +			error = EINVAL;
  1.4165 +			break;
  1.4166 +		}
  1.4167 +		if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) {
  1.4168 +			/* Can't do this for a 1-m socket */
  1.4169 +			error = EINVAL;
  1.4170 +			break;
  1.4171 +		}
  1.4172 +		if (optval)
  1.4173 +			sctp_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE);
  1.4174 +		else
  1.4175 +			sctp_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE);
  1.4176 +		break;
  1.4177 +	}
  1.4178 +	case SCTP_PARTIAL_DELIVERY_POINT:
  1.4179 +	{
  1.4180 +		uint32_t *value;
  1.4181 +
  1.4182 +		SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
  1.4183 +		if (*value > SCTP_SB_LIMIT_RCV(so)) {
  1.4184 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4185 +			error = EINVAL;
  1.4186 +			break;
  1.4187 +		}
  1.4188 +		inp->partial_delivery_point = *value;
  1.4189 +		break;
  1.4190 +	}
  1.4191 +	case SCTP_FRAGMENT_INTERLEAVE:
  1.4192 +		/* not yet until we re-write sctp_recvmsg() */
  1.4193 +	{
  1.4194 +		uint32_t *level;
  1.4195 +
  1.4196 +		SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize);
  1.4197 +		if (*level == SCTP_FRAG_LEVEL_2) {
  1.4198 +			sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
  1.4199 +			sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
  1.4200 +		} else if (*level == SCTP_FRAG_LEVEL_1) {
  1.4201 +			sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
  1.4202 +			sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
  1.4203 +		} else if (*level == SCTP_FRAG_LEVEL_0) {
  1.4204 +			sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
  1.4205 +			sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
  1.4206 +
  1.4207 +		} else {
  1.4208 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4209 +			error = EINVAL;
  1.4210 +		}
  1.4211 +		break;
  1.4212 +	}
  1.4213 +	case SCTP_CMT_ON_OFF:
  1.4214 +		if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) {
  1.4215 +			struct sctp_assoc_value *av;
  1.4216 +
  1.4217 +			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
  1.4218 +			if (av->assoc_value > SCTP_CMT_MAX) {
  1.4219 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4220 +				error = EINVAL;
  1.4221 +				break;
  1.4222 +			}
  1.4223 +			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
  1.4224 +			if (stcb) {
  1.4225 +				stcb->asoc.sctp_cmt_on_off = av->assoc_value;
  1.4226 +				SCTP_TCB_UNLOCK(stcb);
  1.4227 +			} else {
  1.4228 +				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.4229 +				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.4230 +				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
  1.4231 +				    (av->assoc_id == SCTP_ALL_ASSOC)) {
  1.4232 +					SCTP_INP_WLOCK(inp);
  1.4233 +					inp->sctp_cmt_on_off = av->assoc_value;
  1.4234 +					SCTP_INP_WUNLOCK(inp);
  1.4235 +				}
  1.4236 +				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
  1.4237 +				    (av->assoc_id == SCTP_ALL_ASSOC)) {
  1.4238 +					SCTP_INP_RLOCK(inp);
  1.4239 +					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.4240 +						SCTP_TCB_LOCK(stcb);
  1.4241 +						stcb->asoc.sctp_cmt_on_off = av->assoc_value;
  1.4242 +						SCTP_TCB_UNLOCK(stcb);
  1.4243 +					}
  1.4244 +					SCTP_INP_RUNLOCK(inp);
  1.4245 +				}
  1.4246 +			}
  1.4247 +		} else {
  1.4248 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
  1.4249 +			error = ENOPROTOOPT;
  1.4250 +		}
  1.4251 +		break;
  1.4252 +	case SCTP_PLUGGABLE_CC:
  1.4253 +	{
  1.4254 +		struct sctp_assoc_value *av;
  1.4255 +		struct sctp_nets *net;
  1.4256 +
  1.4257 +		SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
  1.4258 +		if ((av->assoc_value != SCTP_CC_RFC2581) &&
  1.4259 +		    (av->assoc_value != SCTP_CC_HSTCP) &&
  1.4260 +		    (av->assoc_value != SCTP_CC_HTCP) &&
  1.4261 +		    (av->assoc_value != SCTP_CC_RTCC)) {
  1.4262 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4263 +			error = EINVAL;
  1.4264 +			break;
  1.4265 +		}
  1.4266 +		SCTP_FIND_STCB(inp, stcb, av->assoc_id);
  1.4267 +		if (stcb) {
  1.4268 +			stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value];
  1.4269 +			stcb->asoc.congestion_control_module = av->assoc_value;
  1.4270 +			if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) {
  1.4271 +				TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1.4272 +					stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
  1.4273 +				}
  1.4274 +			}
  1.4275 +			SCTP_TCB_UNLOCK(stcb);
  1.4276 +		} else {
  1.4277 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.4278 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.4279 +			    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
  1.4280 +			    (av->assoc_id == SCTP_ALL_ASSOC)) {
  1.4281 +				SCTP_INP_WLOCK(inp);
  1.4282 +				inp->sctp_ep.sctp_default_cc_module = av->assoc_value;
  1.4283 +				SCTP_INP_WUNLOCK(inp);
  1.4284 +			}
  1.4285 +			if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
  1.4286 +			    (av->assoc_id == SCTP_ALL_ASSOC)) {
  1.4287 +				SCTP_INP_RLOCK(inp);
  1.4288 +				LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.4289 +					SCTP_TCB_LOCK(stcb);
  1.4290 +					stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value];
  1.4291 +					stcb->asoc.congestion_control_module = av->assoc_value;
  1.4292 +					if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) {
  1.4293 +						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1.4294 +							stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
  1.4295 +						}
  1.4296 +					}
  1.4297 +					SCTP_TCB_UNLOCK(stcb);
  1.4298 +				}
  1.4299 +				SCTP_INP_RUNLOCK(inp);
  1.4300 +			}
  1.4301 +		}
  1.4302 +		break;
  1.4303 +	}
  1.4304 +	case SCTP_CC_OPTION:
  1.4305 +	{
  1.4306 +		struct sctp_cc_option *cc_opt;
  1.4307 +
  1.4308 +		SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, optsize);
  1.4309 +		SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id);
  1.4310 +		if (stcb == NULL) {
  1.4311 +			if (cc_opt->aid_value.assoc_id == SCTP_CURRENT_ASSOC) {
  1.4312 +				SCTP_INP_RLOCK(inp);
  1.4313 +				LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.4314 +					SCTP_TCB_LOCK(stcb);
  1.4315 +					if (stcb->asoc.cc_functions.sctp_cwnd_socket_option) {
  1.4316 +						(*stcb->asoc.cc_functions.sctp_cwnd_socket_option)(stcb, 1, cc_opt);
  1.4317 +					}
  1.4318 +					SCTP_TCB_UNLOCK(stcb);
  1.4319 +				}
  1.4320 +				SCTP_INP_RUNLOCK(inp);
  1.4321 +			} else {
  1.4322 +				error = EINVAL;
  1.4323 +			}
  1.4324 +		} else {
  1.4325 +			if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) {
  1.4326 +				error = ENOTSUP;
  1.4327 +			} else {
  1.4328 +				error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option)(stcb, 1,
  1.4329 +											   cc_opt);
  1.4330 +			}
  1.4331 +			SCTP_TCB_UNLOCK(stcb);
  1.4332 +		}
  1.4333 +		break;
  1.4334 +	}
  1.4335 +	case SCTP_PLUGGABLE_SS:
  1.4336 +	{
  1.4337 +		struct sctp_assoc_value *av;
  1.4338 +
  1.4339 +		SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
  1.4340 +		if ((av->assoc_value != SCTP_SS_DEFAULT) &&
  1.4341 +		    (av->assoc_value != SCTP_SS_ROUND_ROBIN) &&
  1.4342 +		    (av->assoc_value != SCTP_SS_ROUND_ROBIN_PACKET) &&
  1.4343 +		    (av->assoc_value != SCTP_SS_PRIORITY) &&
  1.4344 +		    (av->assoc_value != SCTP_SS_FAIR_BANDWITH) &&
  1.4345 +		    (av->assoc_value != SCTP_SS_FIRST_COME)) {
  1.4346 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4347 +			error = EINVAL;
  1.4348 +			break;
  1.4349 +		}
  1.4350 +		SCTP_FIND_STCB(inp, stcb, av->assoc_id);
  1.4351 +		if (stcb) {
  1.4352 +			stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1);
  1.4353 +			stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
  1.4354 +			stcb->asoc.stream_scheduling_module = av->assoc_value;
  1.4355 +			stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
  1.4356 +			SCTP_TCB_UNLOCK(stcb);
  1.4357 +		} else {
  1.4358 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.4359 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.4360 +			    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
  1.4361 +			    (av->assoc_id == SCTP_ALL_ASSOC)) {
  1.4362 +				SCTP_INP_WLOCK(inp);
  1.4363 +				inp->sctp_ep.sctp_default_ss_module = av->assoc_value;
  1.4364 +				SCTP_INP_WUNLOCK(inp);
  1.4365 +			}
  1.4366 +			if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
  1.4367 +			    (av->assoc_id == SCTP_ALL_ASSOC)) {
  1.4368 +				SCTP_INP_RLOCK(inp);
  1.4369 +				LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.4370 +					SCTP_TCB_LOCK(stcb);
  1.4371 +					stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1);
  1.4372 +					stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
  1.4373 +					stcb->asoc.stream_scheduling_module = av->assoc_value;
  1.4374 +					stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
  1.4375 +					SCTP_TCB_UNLOCK(stcb);
  1.4376 +				}
  1.4377 +				SCTP_INP_RUNLOCK(inp);
  1.4378 +			}
  1.4379 +		}
  1.4380 +		break;
  1.4381 +	}
  1.4382 +	case SCTP_SS_VALUE:
  1.4383 +	{
  1.4384 +		struct sctp_stream_value *av;
  1.4385 +
  1.4386 +		SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize);
  1.4387 +		SCTP_FIND_STCB(inp, stcb, av->assoc_id);
  1.4388 +		if (stcb) {
  1.4389 +			if (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
  1.4390 +			                                              av->stream_value) < 0) {
  1.4391 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4392 +				error = EINVAL;
  1.4393 +			}
  1.4394 +			SCTP_TCB_UNLOCK(stcb);
  1.4395 +		} else {
  1.4396 +			if (av->assoc_id == SCTP_CURRENT_ASSOC) {
  1.4397 +				SCTP_INP_RLOCK(inp);
  1.4398 +				LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.4399 +					SCTP_TCB_LOCK(stcb);
  1.4400 +					stcb->asoc.ss_functions.sctp_ss_set_value(stcb,
  1.4401 +					                                          &stcb->asoc,
  1.4402 +					                                          &stcb->asoc.strmout[av->stream_id],
  1.4403 +					                                          av->stream_value);
  1.4404 +					SCTP_TCB_UNLOCK(stcb);
  1.4405 +				}
  1.4406 +				SCTP_INP_RUNLOCK(inp);
  1.4407 +
  1.4408 +			} else {
  1.4409 +				/* Can't set stream value without association */
  1.4410 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4411 +				error = EINVAL;
  1.4412 +			}
  1.4413 +		}
  1.4414 +		break;
  1.4415 +	}
  1.4416 +	case SCTP_CLR_STAT_LOG:
  1.4417 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
  1.4418 +		error = EOPNOTSUPP;
  1.4419 +		break;
  1.4420 +	case SCTP_CONTEXT:
  1.4421 +	{
  1.4422 +		struct sctp_assoc_value *av;
  1.4423 +
  1.4424 +		SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
  1.4425 +		SCTP_FIND_STCB(inp, stcb, av->assoc_id);
  1.4426 +
  1.4427 +		if (stcb) {
  1.4428 +			stcb->asoc.context = av->assoc_value;
  1.4429 +			SCTP_TCB_UNLOCK(stcb);
  1.4430 +		} else {
  1.4431 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.4432 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.4433 +			    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
  1.4434 +			    (av->assoc_id == SCTP_ALL_ASSOC)) {
  1.4435 +				SCTP_INP_WLOCK(inp);
  1.4436 +				inp->sctp_context = av->assoc_value;
  1.4437 +				SCTP_INP_WUNLOCK(inp);
  1.4438 +			}
  1.4439 +			if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
  1.4440 +			    (av->assoc_id == SCTP_ALL_ASSOC)) {
  1.4441 +				SCTP_INP_RLOCK(inp);
  1.4442 +				LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.4443 +					SCTP_TCB_LOCK(stcb);
  1.4444 +					stcb->asoc.context = av->assoc_value;
  1.4445 +					SCTP_TCB_UNLOCK(stcb);
  1.4446 +				}
  1.4447 +				SCTP_INP_RUNLOCK(inp);
  1.4448 +			}
  1.4449 +		}
  1.4450 +		break;
  1.4451 +	}
  1.4452 +	case SCTP_VRF_ID:
  1.4453 +	{
  1.4454 +		uint32_t *default_vrfid;
  1.4455 +#ifdef SCTP_MVRF
  1.4456 +		int i;
  1.4457 +#endif
  1.4458 +		SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize);
  1.4459 +		if (*default_vrfid > SCTP_MAX_VRF_ID) {
  1.4460 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4461 +			error = EINVAL;
  1.4462 +			break;
  1.4463 +		}
  1.4464 +#ifdef SCTP_MVRF
  1.4465 +		for (i = 0; i < inp->num_vrfs; i++) {
  1.4466 +			/* The VRF must be in the VRF list */
  1.4467 +			if (*default_vrfid == inp->m_vrf_ids[i]) {
  1.4468 +				SCTP_INP_WLOCK(inp);
  1.4469 + 				inp->def_vrf_id = *default_vrfid;
  1.4470 +				SCTP_INP_WUNLOCK(inp);
  1.4471 +				goto sctp_done;
  1.4472 +			}
  1.4473 +		}
  1.4474 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4475 +		error = EINVAL;
  1.4476 +#else
  1.4477 +		inp->def_vrf_id = *default_vrfid;
  1.4478 +#endif
  1.4479 +#ifdef SCTP_MVRF
  1.4480 +	sctp_done:
  1.4481 +#endif
  1.4482 +		break;
  1.4483 +	}
  1.4484 +	case SCTP_DEL_VRF_ID:
  1.4485 +	{
  1.4486 +#ifdef SCTP_MVRF
  1.4487 +		uint32_t *del_vrfid;
  1.4488 +		int i, fnd = 0;
  1.4489 +
  1.4490 +		SCTP_CHECK_AND_CAST(del_vrfid, optval, uint32_t, optsize);
  1.4491 +		if (*del_vrfid > SCTP_MAX_VRF_ID) {
  1.4492 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4493 +			error = EINVAL;
  1.4494 +			break;
  1.4495 +		}
  1.4496 +		if (inp->num_vrfs == 1) {
  1.4497 +			/* Can't delete last one */
  1.4498 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4499 +			error = EINVAL;
  1.4500 +			break;
  1.4501 +		}
  1.4502 +		if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) {
  1.4503 +			/* Can't add more once you are bound */
  1.4504 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4505 +			error = EINVAL;
  1.4506 +			break;
  1.4507 +		}
  1.4508 +		SCTP_INP_WLOCK(inp);
  1.4509 +		for (i = 0; i < inp->num_vrfs; i++) {
  1.4510 +			if (*del_vrfid == inp->m_vrf_ids[i]) {
  1.4511 +				fnd = 1;
  1.4512 +				break;
  1.4513 +			}
  1.4514 +		}
  1.4515 +		if (!fnd) {
  1.4516 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4517 +			error = EINVAL;
  1.4518 +			break;
  1.4519 +		}
  1.4520 +		if (i != (inp->num_vrfs - 1)) {
  1.4521 +			/* Take bottom one and move to this slot */
  1.4522 +			inp->m_vrf_ids[i] = inp->m_vrf_ids[(inp->num_vrfs-1)];
  1.4523 +		}
  1.4524 +		if (*del_vrfid == inp->def_vrf_id) {
  1.4525 +			/* Take the first one as the new default */
  1.4526 +			inp->def_vrf_id = inp->m_vrf_ids[0];
  1.4527 +		}
  1.4528 +		/* Drop the number by one killing last one */
  1.4529 +		inp->num_vrfs--;
  1.4530 +#else
  1.4531 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
  1.4532 +		error = EOPNOTSUPP;
  1.4533 +#endif
  1.4534 +		break;
  1.4535 +	}
  1.4536 +	case SCTP_ADD_VRF_ID:
  1.4537 +	{
  1.4538 +#ifdef SCTP_MVRF
  1.4539 +		uint32_t *add_vrfid;
  1.4540 +		int i;
  1.4541 +
  1.4542 +		SCTP_CHECK_AND_CAST(add_vrfid, optval, uint32_t, optsize);
  1.4543 +		if (*add_vrfid > SCTP_MAX_VRF_ID) {
  1.4544 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4545 +			error = EINVAL;
  1.4546 +			break;
  1.4547 +		}
  1.4548 +		if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) {
  1.4549 +			/* Can't add more once you are bound */
  1.4550 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4551 +			error = EINVAL;
  1.4552 +			break;
  1.4553 +		}
  1.4554 +		SCTP_INP_WLOCK(inp);
  1.4555 +		/* Verify its not already here */
  1.4556 +		for (i = 0; i < inp->num_vrfs; i++) {
  1.4557 +			if (*add_vrfid == inp->m_vrf_ids[i]) {
  1.4558 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
  1.4559 +				error = EALREADY;
  1.4560 +				SCTP_INP_WUNLOCK(inp);
  1.4561 +				break;
  1.4562 +			}
  1.4563 +		}
  1.4564 +		if ((inp->num_vrfs + 1) > inp->vrf_size) {
  1.4565 +			/* need to grow array */
  1.4566 +			uint32_t *tarray;
  1.4567 +			SCTP_MALLOC(tarray, uint32_t *,
  1.4568 +				    (sizeof(uint32_t) * (inp->vrf_size + SCTP_DEFAULT_VRF_SIZE)),
  1.4569 +				    SCTP_M_MVRF);
  1.4570 +			if (tarray == NULL) {
  1.4571 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
  1.4572 +				error = ENOMEM;
  1.4573 +				SCTP_INP_WUNLOCK(inp);
  1.4574 +				break;
  1.4575 +			}
  1.4576 +			memcpy(tarray, inp->m_vrf_ids, (sizeof(uint32_t) * inp->vrf_size));
  1.4577 +			SCTP_FREE(inp->m_vrf_ids, SCTP_M_MVRF);
  1.4578 +			inp->m_vrf_ids = tarray;
  1.4579 +			inp->vrf_size += SCTP_DEFAULT_VRF_SIZE;
  1.4580 +		}
  1.4581 +		inp->m_vrf_ids[inp->num_vrfs] = *add_vrfid;
  1.4582 +		inp->num_vrfs++;
  1.4583 +		SCTP_INP_WUNLOCK(inp);
  1.4584 +#else
  1.4585 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
  1.4586 +		error = EOPNOTSUPP;
  1.4587 +#endif
  1.4588 +	 	break;
  1.4589 +	}
  1.4590 +	case SCTP_DELAYED_SACK:
  1.4591 +	{
  1.4592 +		struct sctp_sack_info *sack;
  1.4593 +
  1.4594 +		SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize);
  1.4595 +		SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id);
  1.4596 +		if (sack->sack_delay) {
  1.4597 +			if (sack->sack_delay > SCTP_MAX_SACK_DELAY)
  1.4598 +				sack->sack_delay = SCTP_MAX_SACK_DELAY;
  1.4599 +			if (MSEC_TO_TICKS(sack->sack_delay) < 1) {
  1.4600 +				sack->sack_delay = TICKS_TO_MSEC(1);
  1.4601 +			}
  1.4602 +		}
  1.4603 +		if (stcb) {
  1.4604 +			if (sack->sack_delay) {
  1.4605 +				stcb->asoc.delayed_ack = sack->sack_delay;
  1.4606 +			}
  1.4607 +			if (sack->sack_freq) {
  1.4608 +				stcb->asoc.sack_freq = sack->sack_freq;
  1.4609 +			}
  1.4610 +			SCTP_TCB_UNLOCK(stcb);
  1.4611 +		} else {
  1.4612 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.4613 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.4614 +			    (sack->sack_assoc_id == SCTP_FUTURE_ASSOC) ||
  1.4615 +			    (sack->sack_assoc_id == SCTP_ALL_ASSOC)) {
  1.4616 +				SCTP_INP_WLOCK(inp);
  1.4617 +				if (sack->sack_delay) {
  1.4618 +					inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay);
  1.4619 +				}
  1.4620 +				if (sack->sack_freq) {
  1.4621 +					inp->sctp_ep.sctp_sack_freq = sack->sack_freq;
  1.4622 +				}
  1.4623 +				SCTP_INP_WUNLOCK(inp);
  1.4624 +			}
  1.4625 +			if ((sack->sack_assoc_id == SCTP_CURRENT_ASSOC) ||
  1.4626 +			    (sack->sack_assoc_id == SCTP_ALL_ASSOC)) {
  1.4627 +				SCTP_INP_RLOCK(inp);
  1.4628 +				LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.4629 +					SCTP_TCB_LOCK(stcb);
  1.4630 +					if (sack->sack_delay) {
  1.4631 +						stcb->asoc.delayed_ack = sack->sack_delay;
  1.4632 +					}
  1.4633 +					if (sack->sack_freq) {
  1.4634 +						stcb->asoc.sack_freq = sack->sack_freq;
  1.4635 +					}
  1.4636 +					SCTP_TCB_UNLOCK(stcb);
  1.4637 +				}
  1.4638 +				SCTP_INP_RUNLOCK(inp);
  1.4639 +			}
  1.4640 +		}
  1.4641 +		break;
  1.4642 +	}
  1.4643 +	case SCTP_AUTH_CHUNK:
  1.4644 +	{
  1.4645 +		struct sctp_authchunk *sauth;
  1.4646 +
  1.4647 +		SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize);
  1.4648 +
  1.4649 +		SCTP_INP_WLOCK(inp);
  1.4650 +		if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) {
  1.4651 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4652 +			error = EINVAL;
  1.4653 +		}
  1.4654 +		SCTP_INP_WUNLOCK(inp);
  1.4655 +		break;
  1.4656 +	}
  1.4657 +	case SCTP_AUTH_KEY:
  1.4658 +	{
  1.4659 +		struct sctp_authkey *sca;
  1.4660 +		struct sctp_keyhead *shared_keys;
  1.4661 +		sctp_sharedkey_t *shared_key;
  1.4662 +		sctp_key_t *key = NULL;
  1.4663 +		size_t size;
  1.4664 +
  1.4665 +		SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize);
  1.4666 +		if (sca->sca_keylength == 0) {
  1.4667 +			size = optsize - sizeof(struct sctp_authkey);
  1.4668 +		} else {
  1.4669 +		        if (sca->sca_keylength + sizeof(struct sctp_authkey) <= optsize) {
  1.4670 +				size = sca->sca_keylength;
  1.4671 +			} else {
  1.4672 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4673 +				error = EINVAL;
  1.4674 +				break;
  1.4675 +			}
  1.4676 +		}
  1.4677 +		SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id);
  1.4678 +
  1.4679 +		if (stcb) {
  1.4680 +			shared_keys = &stcb->asoc.shared_keys;
  1.4681 +			/* clear the cached keys for this key id */
  1.4682 +			sctp_clear_cachedkeys(stcb, sca->sca_keynumber);
  1.4683 +			/*
  1.4684 +			 * create the new shared key and
  1.4685 +			 * insert/replace it
  1.4686 +			 */
  1.4687 +			if (size > 0) {
  1.4688 +				key = sctp_set_key(sca->sca_key, (uint32_t) size);
  1.4689 +				if (key == NULL) {
  1.4690 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
  1.4691 +					error = ENOMEM;
  1.4692 +					SCTP_TCB_UNLOCK(stcb);
  1.4693 +					break;
  1.4694 +				}
  1.4695 +			}
  1.4696 +			shared_key = sctp_alloc_sharedkey();
  1.4697 +			if (shared_key == NULL) {
  1.4698 +				sctp_free_key(key);
  1.4699 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
  1.4700 +				error = ENOMEM;
  1.4701 +				SCTP_TCB_UNLOCK(stcb);
  1.4702 +				break;
  1.4703 +			}
  1.4704 +			shared_key->key = key;
  1.4705 +			shared_key->keyid = sca->sca_keynumber;
  1.4706 +			error = sctp_insert_sharedkey(shared_keys, shared_key);
  1.4707 +			SCTP_TCB_UNLOCK(stcb);
  1.4708 +		} else {
  1.4709 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.4710 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.4711 +			    (sca->sca_assoc_id == SCTP_FUTURE_ASSOC) ||
  1.4712 +			    (sca->sca_assoc_id == SCTP_ALL_ASSOC)) {
  1.4713 +				SCTP_INP_WLOCK(inp);
  1.4714 +				shared_keys = &inp->sctp_ep.shared_keys;
  1.4715 +				/*
  1.4716 +				 * clear the cached keys on all assocs for
  1.4717 +				 * this key id
  1.4718 +				 */
  1.4719 +				sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber);
  1.4720 +				/*
  1.4721 +				 * create the new shared key and
  1.4722 +				 * insert/replace it
  1.4723 +				 */
  1.4724 +				if (size > 0) {
  1.4725 +					key = sctp_set_key(sca->sca_key, (uint32_t) size);
  1.4726 +					if (key == NULL) {
  1.4727 +						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
  1.4728 +						error = ENOMEM;
  1.4729 +						SCTP_INP_WUNLOCK(inp);
  1.4730 +						break;
  1.4731 +					}
  1.4732 +				}
  1.4733 +				shared_key = sctp_alloc_sharedkey();
  1.4734 +				if (shared_key == NULL) {
  1.4735 +					sctp_free_key(key);
  1.4736 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
  1.4737 +					error = ENOMEM;
  1.4738 +					SCTP_INP_WUNLOCK(inp);
  1.4739 +					break;
  1.4740 +				}
  1.4741 +				shared_key->key = key;
  1.4742 +				shared_key->keyid = sca->sca_keynumber;
  1.4743 +				error = sctp_insert_sharedkey(shared_keys, shared_key);
  1.4744 +				SCTP_INP_WUNLOCK(inp);
  1.4745 +			}
  1.4746 +			if ((sca->sca_assoc_id == SCTP_CURRENT_ASSOC) ||
  1.4747 +			    (sca->sca_assoc_id == SCTP_ALL_ASSOC)) {
  1.4748 +				SCTP_INP_RLOCK(inp);
  1.4749 +				LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.4750 +					SCTP_TCB_LOCK(stcb);
  1.4751 +					shared_keys = &stcb->asoc.shared_keys;
  1.4752 +					/* clear the cached keys for this key id */
  1.4753 +					sctp_clear_cachedkeys(stcb, sca->sca_keynumber);
  1.4754 +					/*
  1.4755 +					 * create the new shared key and
  1.4756 +					 * insert/replace it
  1.4757 +					 */
  1.4758 +					if (size > 0) {
  1.4759 +						key = sctp_set_key(sca->sca_key, (uint32_t) size);
  1.4760 +						if (key == NULL) {
  1.4761 +							SCTP_TCB_UNLOCK(stcb);
  1.4762 +							continue;
  1.4763 +						}
  1.4764 +					}
  1.4765 +					shared_key = sctp_alloc_sharedkey();
  1.4766 +					if (shared_key == NULL) {
  1.4767 +						sctp_free_key(key);
  1.4768 +						SCTP_TCB_UNLOCK(stcb);
  1.4769 +						continue;
  1.4770 +					}
  1.4771 +					shared_key->key = key;
  1.4772 +					shared_key->keyid = sca->sca_keynumber;
  1.4773 +					error = sctp_insert_sharedkey(shared_keys, shared_key);
  1.4774 +					SCTP_TCB_UNLOCK(stcb);
  1.4775 +				}
  1.4776 +				SCTP_INP_RUNLOCK(inp);
  1.4777 +			}
  1.4778 +		}
  1.4779 +		break;
  1.4780 +	}
  1.4781 +	case SCTP_HMAC_IDENT:
  1.4782 +	{
  1.4783 +		struct sctp_hmacalgo *shmac;
  1.4784 +		sctp_hmaclist_t *hmaclist;
  1.4785 +		uint16_t hmacid;
  1.4786 +		uint32_t i;
  1.4787 +
  1.4788 +		SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize);
  1.4789 +		if (optsize < sizeof(struct sctp_hmacalgo) + shmac->shmac_number_of_idents * sizeof(uint16_t)) {
  1.4790 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4791 +			error = EINVAL;
  1.4792 +			break;
  1.4793 +		}
  1.4794 +
  1.4795 +		hmaclist = sctp_alloc_hmaclist(shmac->shmac_number_of_idents);
  1.4796 +		if (hmaclist == NULL) {
  1.4797 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
  1.4798 +			error = ENOMEM;
  1.4799 +			break;
  1.4800 +		}
  1.4801 +		for (i = 0; i < shmac->shmac_number_of_idents; i++) {
  1.4802 +			hmacid = shmac->shmac_idents[i];
  1.4803 +			if (sctp_auth_add_hmacid(hmaclist, hmacid)) {
  1.4804 +				/* invalid HMACs were found */;
  1.4805 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4806 +				error = EINVAL;
  1.4807 +				sctp_free_hmaclist(hmaclist);
  1.4808 +				goto sctp_set_hmac_done;
  1.4809 +			}
  1.4810 +		}
  1.4811 +		for (i = 0; i < hmaclist->num_algo; i++) {
  1.4812 +			if (hmaclist->hmac[i] == SCTP_AUTH_HMAC_ID_SHA1) {
  1.4813 +				/* already in list */
  1.4814 +				break;
  1.4815 +			}
  1.4816 +		}
  1.4817 +		if (i == hmaclist->num_algo) {
  1.4818 +			/* not found in list */
  1.4819 +			sctp_free_hmaclist(hmaclist);
  1.4820 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4821 +			error = EINVAL;
  1.4822 +			break;
  1.4823 +		}
  1.4824 +		/* set it on the endpoint */
  1.4825 +		SCTP_INP_WLOCK(inp);
  1.4826 +		if (inp->sctp_ep.local_hmacs)
  1.4827 +			sctp_free_hmaclist(inp->sctp_ep.local_hmacs);
  1.4828 +		inp->sctp_ep.local_hmacs = hmaclist;
  1.4829 +		SCTP_INP_WUNLOCK(inp);
  1.4830 +	sctp_set_hmac_done:
  1.4831 +		break;
  1.4832 +	}
  1.4833 +	case SCTP_AUTH_ACTIVE_KEY:
  1.4834 +	{
  1.4835 +		struct sctp_authkeyid *scact;
  1.4836 +
  1.4837 +		SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize);
  1.4838 +		SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
  1.4839 +
  1.4840 +		/* set the active key on the right place */
  1.4841 +		if (stcb) {
  1.4842 +			/* set the active key on the assoc */
  1.4843 +			if (sctp_auth_setactivekey(stcb,
  1.4844 +						   scact->scact_keynumber)) {
  1.4845 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
  1.4846 +						    SCTP_FROM_SCTP_USRREQ,
  1.4847 +						    EINVAL);
  1.4848 +				error = EINVAL;
  1.4849 +			}
  1.4850 +			SCTP_TCB_UNLOCK(stcb);
  1.4851 +		} else {
  1.4852 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.4853 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.4854 +			    (scact->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
  1.4855 +			    (scact->scact_assoc_id == SCTP_ALL_ASSOC)) {
  1.4856 +				SCTP_INP_WLOCK(inp);
  1.4857 +				if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) {
  1.4858 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4859 +					error = EINVAL;
  1.4860 +				}
  1.4861 +				SCTP_INP_WUNLOCK(inp);
  1.4862 +			}
  1.4863 +			if ((scact->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
  1.4864 +			    (scact->scact_assoc_id == SCTP_ALL_ASSOC)) {
  1.4865 +				SCTP_INP_RLOCK(inp);
  1.4866 +				LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.4867 +					SCTP_TCB_LOCK(stcb);
  1.4868 +					sctp_auth_setactivekey(stcb, scact->scact_keynumber);
  1.4869 +					SCTP_TCB_UNLOCK(stcb);
  1.4870 +				}
  1.4871 +				SCTP_INP_RUNLOCK(inp);
  1.4872 +			}
  1.4873 +		}
  1.4874 +		break;
  1.4875 +	}
  1.4876 +	case SCTP_AUTH_DELETE_KEY:
  1.4877 +	{
  1.4878 +		struct sctp_authkeyid *scdel;
  1.4879 +
  1.4880 +		SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize);
  1.4881 +		SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id);
  1.4882 +
  1.4883 +		/* delete the key from the right place */
  1.4884 +		if (stcb) {
  1.4885 +			if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) {
  1.4886 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4887 +				error = EINVAL;
  1.4888 +			}
  1.4889 +			SCTP_TCB_UNLOCK(stcb);
  1.4890 +		} else {
  1.4891 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.4892 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.4893 +			    (scdel->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
  1.4894 +			    (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) {
  1.4895 +				SCTP_INP_WLOCK(inp);
  1.4896 +				if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) {
  1.4897 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4898 +					error = EINVAL;
  1.4899 +				}
  1.4900 +				SCTP_INP_WUNLOCK(inp);
  1.4901 +			}
  1.4902 +			if ((scdel->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
  1.4903 +			    (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) {
  1.4904 +				SCTP_INP_RLOCK(inp);
  1.4905 +				LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.4906 +					SCTP_TCB_LOCK(stcb);
  1.4907 +					sctp_delete_sharedkey(stcb, scdel->scact_keynumber);
  1.4908 +					SCTP_TCB_UNLOCK(stcb);
  1.4909 +				}
  1.4910 +				SCTP_INP_RUNLOCK(inp);
  1.4911 +			}
  1.4912 +		}
  1.4913 +		break;
  1.4914 +	}
  1.4915 +	case SCTP_AUTH_DEACTIVATE_KEY:
  1.4916 +	{
  1.4917 +		struct sctp_authkeyid *keyid;
  1.4918 +
  1.4919 +		SCTP_CHECK_AND_CAST(keyid, optval, struct sctp_authkeyid, optsize);
  1.4920 +		SCTP_FIND_STCB(inp, stcb, keyid->scact_assoc_id);
  1.4921 +
  1.4922 +		/* deactivate the key from the right place */
  1.4923 +		if (stcb) {
  1.4924 +			if (sctp_deact_sharedkey(stcb, keyid->scact_keynumber)) {
  1.4925 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4926 +				error = EINVAL;
  1.4927 +			}
  1.4928 +			SCTP_TCB_UNLOCK(stcb);
  1.4929 +		} else {
  1.4930 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.4931 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.4932 +			    (keyid->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
  1.4933 +			    (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) {
  1.4934 +				SCTP_INP_WLOCK(inp);
  1.4935 +				if (sctp_deact_sharedkey_ep(inp, keyid->scact_keynumber)) {
  1.4936 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4937 +					error = EINVAL;
  1.4938 +				}
  1.4939 +				SCTP_INP_WUNLOCK(inp);
  1.4940 +			}
  1.4941 +			if ((keyid->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
  1.4942 +			    (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) {
  1.4943 +				SCTP_INP_RLOCK(inp);
  1.4944 +				LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.4945 +					SCTP_TCB_LOCK(stcb);
  1.4946 +					sctp_deact_sharedkey(stcb, keyid->scact_keynumber);
  1.4947 +					SCTP_TCB_UNLOCK(stcb);
  1.4948 +				}
  1.4949 +				SCTP_INP_RUNLOCK(inp);
  1.4950 +			}
  1.4951 +		}
  1.4952 +		break;
  1.4953 +	}
  1.4954 +	case SCTP_ENABLE_STREAM_RESET:
  1.4955 +	{
  1.4956 +		struct sctp_assoc_value *av;
  1.4957 +
  1.4958 +		SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
  1.4959 +		if (av->assoc_value & (~SCTP_ENABLE_VALUE_MASK)) {
  1.4960 +		        SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.4961 +			error = EINVAL;
  1.4962 +			break;
  1.4963 +		}
  1.4964 +		SCTP_FIND_STCB(inp, stcb, av->assoc_id);
  1.4965 +		if (stcb) {
  1.4966 +			stcb->asoc.local_strreset_support = (uint8_t)av->assoc_value;
  1.4967 +			SCTP_TCB_UNLOCK(stcb);
  1.4968 +		} else {
  1.4969 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.4970 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.4971 +			    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
  1.4972 +			    (av->assoc_id == SCTP_ALL_ASSOC)) {
  1.4973 +				SCTP_INP_WLOCK(inp);
  1.4974 +				inp->local_strreset_support = (uint8_t)av->assoc_value;
  1.4975 +				SCTP_INP_WUNLOCK(inp);
  1.4976 +			}
  1.4977 +			if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
  1.4978 +			    (av->assoc_id == SCTP_ALL_ASSOC)) {
  1.4979 +				SCTP_INP_RLOCK(inp);
  1.4980 +				LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.4981 +					SCTP_TCB_LOCK(stcb);
  1.4982 +					stcb->asoc.local_strreset_support = (uint8_t)av->assoc_value;
  1.4983 +					SCTP_TCB_UNLOCK(stcb);
  1.4984 +				}
  1.4985 +				SCTP_INP_RUNLOCK(inp);
  1.4986 +			}
  1.4987 +
  1.4988 +		}
  1.4989 +		break;
  1.4990 +	}
  1.4991 +	case SCTP_RESET_STREAMS:
  1.4992 +	{
  1.4993 +		struct sctp_reset_streams *strrst;
  1.4994 +		int i, send_out = 0;
  1.4995 +		int send_in = 0;
  1.4996 +
  1.4997 +		SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_reset_streams, optsize);
  1.4998 +		SCTP_FIND_STCB(inp, stcb, strrst->srs_assoc_id);
  1.4999 +		if (stcb == NULL) {
  1.5000 +		        SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
  1.5001 +			error = ENOENT;
  1.5002 +			break;
  1.5003 +		}
  1.5004 +		if (stcb->asoc.peer_supports_strreset == 0) {
  1.5005 +			/*
  1.5006 +			 * Peer does not support the chunk type.
  1.5007 +			 */
  1.5008 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
  1.5009 +			error = EOPNOTSUPP;
  1.5010 +			SCTP_TCB_UNLOCK(stcb);
  1.5011 +			break;
  1.5012 +		}
  1.5013 +		if (stcb->asoc.stream_reset_outstanding) {
  1.5014 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
  1.5015 +			error = EALREADY;
  1.5016 +			SCTP_TCB_UNLOCK(stcb);
  1.5017 +			break;
  1.5018 +		}
  1.5019 +		if (strrst->srs_flags & SCTP_STREAM_RESET_INCOMING) {
  1.5020 +			send_in = 1;
  1.5021 +		}
  1.5022 +		if (strrst->srs_flags & SCTP_STREAM_RESET_OUTGOING) {
  1.5023 +			send_out = 1;
  1.5024 +		}
  1.5025 +		if ((send_in == 0) && (send_out == 0)) {
  1.5026 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.5027 +			error = EINVAL;
  1.5028 +			SCTP_TCB_UNLOCK(stcb);
  1.5029 +			break;
  1.5030 +		}
  1.5031 +		for (i = 0; i < strrst->srs_number_streams; i++) {
  1.5032 +			if ((send_in) &&
  1.5033 +			    (strrst->srs_stream_list[i] > stcb->asoc.streamincnt)) {
  1.5034 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.5035 +				error = EINVAL;
  1.5036 +				break;
  1.5037 +			}
  1.5038 +			if ((send_out) &&
  1.5039 +			    (strrst->srs_stream_list[i] > stcb->asoc.streamoutcnt)) {
  1.5040 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.5041 +				error = EINVAL;
  1.5042 +				break;
  1.5043 +			}
  1.5044 +		}
  1.5045 +		if (error) {
  1.5046 +			SCTP_TCB_UNLOCK(stcb);
  1.5047 +			break;
  1.5048 +		}
  1.5049 +		error = sctp_send_str_reset_req(stcb, strrst->srs_number_streams,
  1.5050 +						strrst->srs_stream_list,
  1.5051 +						send_out, send_in, 0, 0, 0, 0, 0);
  1.5052 +
  1.5053 +		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
  1.5054 +		SCTP_TCB_UNLOCK(stcb);
  1.5055 +		break;
  1.5056 +	}
  1.5057 +	case SCTP_ADD_STREAMS:
  1.5058 +	{
  1.5059 +		struct sctp_add_streams *stradd;
  1.5060 +		uint8_t addstream = 0;
  1.5061 +		uint16_t add_o_strmcnt = 0;
  1.5062 +		uint16_t add_i_strmcnt = 0;
  1.5063 +
  1.5064 +		SCTP_CHECK_AND_CAST(stradd, optval, struct sctp_add_streams, optsize);
  1.5065 +		SCTP_FIND_STCB(inp, stcb, stradd->sas_assoc_id);
  1.5066 +		if (stcb == NULL) {
  1.5067 +		        SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
  1.5068 +			error = ENOENT;
  1.5069 +			break;
  1.5070 +		}
  1.5071 +		if (stcb->asoc.peer_supports_strreset == 0) {
  1.5072 +			/*
  1.5073 +			 * Peer does not support the chunk type.
  1.5074 +			 */
  1.5075 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
  1.5076 +			error = EOPNOTSUPP;
  1.5077 +			SCTP_TCB_UNLOCK(stcb);
  1.5078 +			break;
  1.5079 +		}
  1.5080 +		if (stcb->asoc.stream_reset_outstanding) {
  1.5081 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
  1.5082 +			error = EALREADY;
  1.5083 +			SCTP_TCB_UNLOCK(stcb);
  1.5084 +			break;
  1.5085 +		}
  1.5086 +		if ((stradd->sas_outstrms == 0) &&
  1.5087 +		    (stradd->sas_instrms == 0)) {
  1.5088 +			error = EINVAL;
  1.5089 +			goto skip_stuff;
  1.5090 +		}
  1.5091 +		if (stradd->sas_outstrms) {
  1.5092 +			addstream = 1;
  1.5093 +			/* We allocate here */
  1.5094 +			add_o_strmcnt = stradd->sas_outstrms;
  1.5095 +			if ((((int)add_o_strmcnt) + ((int)stcb->asoc.streamoutcnt)) > 0x0000ffff) {
  1.5096 +				/* You can't have more than 64k */
  1.5097 +				error = EINVAL;
  1.5098 +				goto skip_stuff;
  1.5099 +			}
  1.5100 +		}
  1.5101 +		if (stradd->sas_instrms) {
  1.5102 +			int cnt;
  1.5103 +
  1.5104 +			addstream |= 2;
  1.5105 +			/* We allocate inside sctp_send_str_reset_req() */
  1.5106 +			add_i_strmcnt = stradd->sas_instrms;
  1.5107 +			cnt = add_i_strmcnt;
  1.5108 +			cnt += stcb->asoc.streamincnt;
  1.5109 +			if (cnt > 0x0000ffff) {
  1.5110 +				/* You can't have more than 64k */
  1.5111 +				error = EINVAL;
  1.5112 +				goto skip_stuff;
  1.5113 +			}
  1.5114 +			if (cnt > (int)stcb->asoc.max_inbound_streams) {
  1.5115 +				/* More than you are allowed */
  1.5116 +				error = EINVAL;
  1.5117 +				goto skip_stuff;
  1.5118 +			}
  1.5119 +		}
  1.5120 +		error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 0, addstream, add_o_strmcnt, add_i_strmcnt, 0);
  1.5121 +		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
  1.5122 +	skip_stuff:
  1.5123 +		SCTP_TCB_UNLOCK(stcb);
  1.5124 +		break;
  1.5125 +	}
  1.5126 +	case SCTP_RESET_ASSOC:
  1.5127 +	{
  1.5128 +		uint32_t *value;
  1.5129 +
  1.5130 +		SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
  1.5131 +		SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) *value);
  1.5132 +		if (stcb == NULL) {
  1.5133 +		        SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
  1.5134 +			error = ENOENT;
  1.5135 +			break;
  1.5136 +		}
  1.5137 +		if (stcb->asoc.peer_supports_strreset == 0) {
  1.5138 +			/*
  1.5139 +			 * Peer does not support the chunk type.
  1.5140 +			 */
  1.5141 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
  1.5142 +			error = EOPNOTSUPP;
  1.5143 +			SCTP_TCB_UNLOCK(stcb);
  1.5144 +			break;
  1.5145 +		}
  1.5146 +		if (stcb->asoc.stream_reset_outstanding) {
  1.5147 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
  1.5148 +			error = EALREADY;
  1.5149 +			SCTP_TCB_UNLOCK(stcb);
  1.5150 +			break;
  1.5151 +		}
  1.5152 +		error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 1, 0, 0, 0, 0);
  1.5153 +		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
  1.5154 +		SCTP_TCB_UNLOCK(stcb);
  1.5155 +		break;
  1.5156 +	}
  1.5157 +	case SCTP_CONNECT_X:
  1.5158 +		if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
  1.5159 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.5160 +			error = EINVAL;
  1.5161 +			break;
  1.5162 +		}
  1.5163 +		error = sctp_do_connect_x(so, inp, optval, optsize, p, 0);
  1.5164 +		break;
  1.5165 +	case SCTP_CONNECT_X_DELAYED:
  1.5166 +		if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
  1.5167 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.5168 +			error = EINVAL;
  1.5169 +			break;
  1.5170 +		}
  1.5171 +		error = sctp_do_connect_x(so, inp, optval, optsize, p, 1);
  1.5172 +		break;
  1.5173 +	case SCTP_CONNECT_X_COMPLETE:
  1.5174 +	{
  1.5175 +		struct sockaddr *sa;
  1.5176 +		struct sctp_nets *net;
  1.5177 +
  1.5178 +		/* FIXME MT: check correct? */
  1.5179 +		SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize);
  1.5180 +
  1.5181 +		/* find tcb */
  1.5182 +		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
  1.5183 +			SCTP_INP_RLOCK(inp);
  1.5184 +			stcb = LIST_FIRST(&inp->sctp_asoc_list);
  1.5185 +			if (stcb) {
  1.5186 +				SCTP_TCB_LOCK(stcb);
  1.5187 +				net = sctp_findnet(stcb, sa);
  1.5188 +			}
  1.5189 +			SCTP_INP_RUNLOCK(inp);
  1.5190 +		} else {
  1.5191 +			/* We increment here since sctp_findassociation_ep_addr() wil
  1.5192 +			 * do a decrement if it finds the stcb as long as the locked
  1.5193 +			 * tcb (last argument) is NOT a TCB.. aka NULL.
  1.5194 +			 */
  1.5195 +			SCTP_INP_INCR_REF(inp);
  1.5196 +			stcb = sctp_findassociation_ep_addr(&inp, sa, &net, NULL, NULL);
  1.5197 +			if (stcb == NULL) {
  1.5198 +				SCTP_INP_DECR_REF(inp);
  1.5199 +			}
  1.5200 +		}
  1.5201 +
  1.5202 +		if (stcb == NULL) {
  1.5203 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
  1.5204 +			error = ENOENT;
  1.5205 +			break;
  1.5206 +		}
  1.5207 +		if (stcb->asoc.delayed_connection == 1) {
  1.5208 +			stcb->asoc.delayed_connection = 0;
  1.5209 +			(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
  1.5210 +			sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb,
  1.5211 +					stcb->asoc.primary_destination,
  1.5212 +					SCTP_FROM_SCTP_USRREQ+SCTP_LOC_9);
  1.5213 +			sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
  1.5214 +		} else {
  1.5215 +			/*
  1.5216 +			 * already expired or did not use delayed
  1.5217 +			 * connectx
  1.5218 +			 */
  1.5219 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
  1.5220 +			error = EALREADY;
  1.5221 +		}
  1.5222 +		SCTP_TCB_UNLOCK(stcb);
  1.5223 +		break;
  1.5224 +	}
  1.5225 +	case SCTP_MAX_BURST:
  1.5226 +	{
  1.5227 +#if defined(__FreeBSD__) && __FreeBSD_version < 900000
  1.5228 +		uint8_t *burst;
  1.5229 +
  1.5230 +		SCTP_CHECK_AND_CAST(burst, optval, uint8_t, optsize);
  1.5231 +
  1.5232 +		SCTP_INP_WLOCK(inp);
  1.5233 +		inp->sctp_ep.max_burst = *burst;
  1.5234 +		SCTP_INP_WUNLOCK(inp);
  1.5235 +#else
  1.5236 +		struct sctp_assoc_value *av;
  1.5237 +
  1.5238 +		SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
  1.5239 +		SCTP_FIND_STCB(inp, stcb, av->assoc_id);
  1.5240 +
  1.5241 +		if (stcb) {
  1.5242 +			stcb->asoc.max_burst = av->assoc_value;
  1.5243 +			SCTP_TCB_UNLOCK(stcb);
  1.5244 +		} else {
  1.5245 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.5246 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.5247 +			    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
  1.5248 +			    (av->assoc_id == SCTP_ALL_ASSOC)) {
  1.5249 +				SCTP_INP_WLOCK(inp);
  1.5250 +				inp->sctp_ep.max_burst = av->assoc_value;
  1.5251 +				SCTP_INP_WUNLOCK(inp);
  1.5252 +			}
  1.5253 +			if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
  1.5254 +			    (av->assoc_id == SCTP_ALL_ASSOC)) {
  1.5255 +				SCTP_INP_RLOCK(inp);
  1.5256 +				LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.5257 +					SCTP_TCB_LOCK(stcb);
  1.5258 +					stcb->asoc.max_burst = av->assoc_value;
  1.5259 +					SCTP_TCB_UNLOCK(stcb);
  1.5260 +				}
  1.5261 +				SCTP_INP_RUNLOCK(inp);
  1.5262 +			}
  1.5263 +		}
  1.5264 +#endif
  1.5265 +		break;
  1.5266 +	}
  1.5267 +	case SCTP_MAXSEG:
  1.5268 +	{
  1.5269 +		struct sctp_assoc_value *av;
  1.5270 +		int ovh;
  1.5271 +
  1.5272 +		SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
  1.5273 +		SCTP_FIND_STCB(inp, stcb, av->assoc_id);
  1.5274 +
  1.5275 +		if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
  1.5276 +			ovh = SCTP_MED_OVERHEAD;
  1.5277 +		} else {
  1.5278 +			ovh = SCTP_MED_V4_OVERHEAD;
  1.5279 +		}
  1.5280 +		if (stcb) {
  1.5281 +			if (av->assoc_value) {
  1.5282 +				stcb->asoc.sctp_frag_point = (av->assoc_value + ovh);
  1.5283 +			} else {
  1.5284 +				stcb->asoc.sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
  1.5285 +			}
  1.5286 +			SCTP_TCB_UNLOCK(stcb);
  1.5287 +		} else {
  1.5288 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.5289 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.5290 +			    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
  1.5291 +				SCTP_INP_WLOCK(inp);
  1.5292 +				/* FIXME MT: I think this is not in tune with the API ID */
  1.5293 +				if (av->assoc_value) {
  1.5294 +					inp->sctp_frag_point = (av->assoc_value + ovh);
  1.5295 +				} else {
  1.5296 +					inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
  1.5297 +				}
  1.5298 +				SCTP_INP_WUNLOCK(inp);
  1.5299 +			} else {
  1.5300 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.5301 +				error = EINVAL;
  1.5302 +			}
  1.5303 +		}
  1.5304 +		break;
  1.5305 +	}
  1.5306 +	case SCTP_EVENTS:
  1.5307 +	{
  1.5308 +		struct sctp_event_subscribe *events;
  1.5309 +
  1.5310 +		SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize);
  1.5311 +
  1.5312 +		SCTP_INP_WLOCK(inp);
  1.5313 +		if (events->sctp_data_io_event) {
  1.5314 +			sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
  1.5315 +		} else {
  1.5316 +			sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
  1.5317 +		}
  1.5318 +
  1.5319 +		if (events->sctp_association_event) {
  1.5320 +			sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
  1.5321 +		} else {
  1.5322 +			sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
  1.5323 +		}
  1.5324 +
  1.5325 +		if (events->sctp_address_event) {
  1.5326 +			sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
  1.5327 +		} else {
  1.5328 +			sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
  1.5329 +		}
  1.5330 +
  1.5331 +		if (events->sctp_send_failure_event) {
  1.5332 +			sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
  1.5333 +		} else {
  1.5334 +			sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
  1.5335 +		}
  1.5336 +
  1.5337 +		if (events->sctp_peer_error_event) {
  1.5338 +			sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR);
  1.5339 +		} else {
  1.5340 +			sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR);
  1.5341 +		}
  1.5342 +
  1.5343 +		if (events->sctp_shutdown_event) {
  1.5344 +			sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
  1.5345 +		} else {
  1.5346 +			sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
  1.5347 +		}
  1.5348 +
  1.5349 +		if (events->sctp_partial_delivery_event) {
  1.5350 +			sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
  1.5351 +		} else {
  1.5352 +			sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
  1.5353 +		}
  1.5354 +
  1.5355 +		if (events->sctp_adaptation_layer_event) {
  1.5356 +			sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
  1.5357 +		} else {
  1.5358 +			sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
  1.5359 +		}
  1.5360 +
  1.5361 +		if (events->sctp_authentication_event) {
  1.5362 +			sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT);
  1.5363 +		} else {
  1.5364 +			sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT);
  1.5365 +		}
  1.5366 +
  1.5367 +		if (events->sctp_sender_dry_event) {
  1.5368 +			sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT);
  1.5369 +		} else {
  1.5370 +			sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT);
  1.5371 +		}
  1.5372 +
  1.5373 +		if (events->sctp_stream_reset_event) {
  1.5374 +			sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
  1.5375 +		} else {
  1.5376 +			sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
  1.5377 +		}
  1.5378 +		SCTP_INP_WUNLOCK(inp);
  1.5379 +
  1.5380 +		SCTP_INP_RLOCK(inp);
  1.5381 +		LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.5382 +			SCTP_TCB_LOCK(stcb);
  1.5383 +			if (events->sctp_association_event) {
  1.5384 +				sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT);
  1.5385 +			} else {
  1.5386 +				sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT);
  1.5387 +			}
  1.5388 +			if (events->sctp_address_event) {
  1.5389 +				sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT);
  1.5390 +			} else {
  1.5391 +				sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT);
  1.5392 +			}
  1.5393 +			if (events->sctp_send_failure_event) {
  1.5394 +				sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
  1.5395 +			} else {
  1.5396 +				sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
  1.5397 +			}
  1.5398 +			if (events->sctp_peer_error_event) {
  1.5399 +				sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR);
  1.5400 +			} else {
  1.5401 +				sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR);
  1.5402 +			}
  1.5403 +			if (events->sctp_shutdown_event) {
  1.5404 +				sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
  1.5405 +			} else {
  1.5406 +				sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
  1.5407 +			}
  1.5408 +			if (events->sctp_partial_delivery_event) {
  1.5409 +				sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT);
  1.5410 +			} else {
  1.5411 +				sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT);
  1.5412 +			}
  1.5413 +			if (events->sctp_adaptation_layer_event) {
  1.5414 +				sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
  1.5415 +			} else {
  1.5416 +				sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
  1.5417 +			}
  1.5418 +			if (events->sctp_authentication_event) {
  1.5419 +				sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT);
  1.5420 +			} else {
  1.5421 +				sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT);
  1.5422 +			}
  1.5423 +			if (events->sctp_sender_dry_event) {
  1.5424 +				sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT);
  1.5425 +			} else {
  1.5426 +				sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT);
  1.5427 +			}
  1.5428 +			if (events->sctp_stream_reset_event) {
  1.5429 +				sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
  1.5430 +			} else {
  1.5431 +				sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
  1.5432 +			}
  1.5433 +			SCTP_TCB_UNLOCK(stcb);
  1.5434 +		}
  1.5435 +		/* Send up the sender dry event only for 1-to-1 style sockets. */
  1.5436 +		if (events->sctp_sender_dry_event) {
  1.5437 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.5438 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
  1.5439 +				stcb = LIST_FIRST(&inp->sctp_asoc_list);
  1.5440 +				if (stcb) {
  1.5441 +					SCTP_TCB_LOCK(stcb);
  1.5442 +					if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
  1.5443 +					    TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
  1.5444 +					    (stcb->asoc.stream_queue_cnt == 0)) {
  1.5445 +						sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb,  0, NULL, SCTP_SO_LOCKED);
  1.5446 +					}
  1.5447 +					SCTP_TCB_UNLOCK(stcb);
  1.5448 +				}
  1.5449 +			}
  1.5450 +		}
  1.5451 +		SCTP_INP_RUNLOCK(inp);
  1.5452 +		break;
  1.5453 +	}
  1.5454 +	case SCTP_ADAPTATION_LAYER:
  1.5455 +	{
  1.5456 +		struct sctp_setadaptation *adap_bits;
  1.5457 +
  1.5458 +		SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize);
  1.5459 +		SCTP_INP_WLOCK(inp);
  1.5460 +		inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind;
  1.5461 +		inp->sctp_ep.adaptation_layer_indicator_provided = 1;
  1.5462 +		SCTP_INP_WUNLOCK(inp);
  1.5463 +		break;
  1.5464 +	}
  1.5465 +#ifdef SCTP_DEBUG
  1.5466 +	case SCTP_SET_INITIAL_DBG_SEQ:
  1.5467 +	{
  1.5468 +		uint32_t *vvv;
  1.5469 +
  1.5470 +		SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize);
  1.5471 +		SCTP_INP_WLOCK(inp);
  1.5472 +		inp->sctp_ep.initial_sequence_debug = *vvv;
  1.5473 +		SCTP_INP_WUNLOCK(inp);
  1.5474 +		break;
  1.5475 +	}
  1.5476 +#endif
  1.5477 +	case SCTP_DEFAULT_SEND_PARAM:
  1.5478 +	{
  1.5479 +		struct sctp_sndrcvinfo *s_info;
  1.5480 +
  1.5481 +		SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize);
  1.5482 +		SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
  1.5483 +
  1.5484 +		if (stcb) {
  1.5485 +			if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) {
  1.5486 +				memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send)));
  1.5487 +			} else {
  1.5488 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.5489 +				error = EINVAL;
  1.5490 +			}
  1.5491 +			SCTP_TCB_UNLOCK(stcb);
  1.5492 +		} else {
  1.5493 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.5494 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.5495 +			    (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) ||
  1.5496 +			    (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) {
  1.5497 +				SCTP_INP_WLOCK(inp);
  1.5498 +				memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send)));
  1.5499 +				SCTP_INP_WUNLOCK(inp);
  1.5500 +			}
  1.5501 +			if ((s_info->sinfo_assoc_id == SCTP_CURRENT_ASSOC) ||
  1.5502 +			    (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) {
  1.5503 +				SCTP_INP_RLOCK(inp);
  1.5504 +				LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.5505 +					SCTP_TCB_LOCK(stcb);
  1.5506 +					if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) {
  1.5507 +						memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send)));
  1.5508 +					}
  1.5509 +					SCTP_TCB_UNLOCK(stcb);
  1.5510 +				}
  1.5511 +				SCTP_INP_RUNLOCK(inp);
  1.5512 +			}
  1.5513 +		}
  1.5514 +		break;
  1.5515 +	}
  1.5516 +	case SCTP_PEER_ADDR_PARAMS:
  1.5517 +	{
  1.5518 +		struct sctp_paddrparams *paddrp;
  1.5519 +		struct sctp_nets *net;
  1.5520 +
  1.5521 +		SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize);
  1.5522 +		SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
  1.5523 +		net = NULL;
  1.5524 +		if (stcb) {
  1.5525 +			net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
  1.5526 +		} else {
  1.5527 +			/* We increment here since sctp_findassociation_ep_addr() wil
  1.5528 +			 * do a decrement if it finds the stcb as long as the locked
  1.5529 +			 * tcb (last argument) is NOT a TCB.. aka NULL.
  1.5530 +			 */
  1.5531 +			SCTP_INP_INCR_REF(inp);
  1.5532 +			stcb = sctp_findassociation_ep_addr(&inp,
  1.5533 +							    (struct sockaddr *)&paddrp->spp_address,
  1.5534 +							    &net, NULL, NULL);
  1.5535 +			if (stcb == NULL) {
  1.5536 +				SCTP_INP_DECR_REF(inp);
  1.5537 +			}
  1.5538 +		}
  1.5539 +		if (stcb && (net == NULL)) {
  1.5540 +			struct sockaddr *sa;
  1.5541 +
  1.5542 +			sa = (struct sockaddr *)&paddrp->spp_address;
  1.5543 +#ifdef INET
  1.5544 +			if (sa->sa_family == AF_INET) {
  1.5545 +
  1.5546 +				struct sockaddr_in *sin;
  1.5547 +				sin = (struct sockaddr_in *)sa;
  1.5548 +				if (sin->sin_addr.s_addr) {
  1.5549 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.5550 +					SCTP_TCB_UNLOCK(stcb);
  1.5551 +					error = EINVAL;
  1.5552 +					break;
  1.5553 +				}
  1.5554 +			} else
  1.5555 +#endif
  1.5556 +#ifdef INET6
  1.5557 +			if (sa->sa_family == AF_INET6) {
  1.5558 +				struct sockaddr_in6 *sin6;
  1.5559 +
  1.5560 +				sin6 = (struct sockaddr_in6 *)sa;
  1.5561 +				if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
  1.5562 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.5563 +					SCTP_TCB_UNLOCK(stcb);
  1.5564 +					error = EINVAL;
  1.5565 +					break;
  1.5566 +				}
  1.5567 +			} else
  1.5568 +#endif
  1.5569 +#if defined(__Userspace__)
  1.5570 +			if (sa->sa_family == AF_CONN) {
  1.5571 +				struct sockaddr_conn *sconn;
  1.5572 +
  1.5573 +				sconn = (struct sockaddr_conn *)sa;
  1.5574 +				if (sconn->sconn_addr != NULL) {
  1.5575 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.5576 +					SCTP_TCB_UNLOCK(stcb);
  1.5577 +					error = EINVAL;
  1.5578 +					break;
  1.5579 +				}
  1.5580 +			} else
  1.5581 +#endif
  1.5582 +			{
  1.5583 +				error = EAFNOSUPPORT;
  1.5584 +				SCTP_TCB_UNLOCK(stcb);
  1.5585 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.5586 +				break;
  1.5587 +			}
  1.5588 +		}
  1.5589 +		/* sanity checks */
  1.5590 +		if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) {
  1.5591 +			if (stcb)
  1.5592 +				SCTP_TCB_UNLOCK(stcb);
  1.5593 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.5594 +			return (EINVAL);
  1.5595 +		}
  1.5596 +
  1.5597 +		if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) {
  1.5598 +			if (stcb)
  1.5599 +				SCTP_TCB_UNLOCK(stcb);
  1.5600 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.5601 +			return (EINVAL);
  1.5602 +		}
  1.5603 +
  1.5604 +		if (stcb) {
  1.5605 +			/************************TCB SPECIFIC SET ******************/
  1.5606 +			/*
  1.5607 +			 * do we change the timer for HB, we run
  1.5608 +			 * only one?
  1.5609 +			 */
  1.5610 +			int ovh = 0;
  1.5611 +
  1.5612 +			if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
  1.5613 +				ovh = SCTP_MED_OVERHEAD;
  1.5614 +			} else {
  1.5615 +				ovh = SCTP_MED_V4_OVERHEAD;
  1.5616 +			}
  1.5617 +
  1.5618 +			/* network sets ? */
  1.5619 +			if (net) {
  1.5620 +				/************************NET SPECIFIC SET ******************/
  1.5621 +				if (paddrp->spp_flags & SPP_HB_DISABLE) {
  1.5622 +					if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
  1.5623 +					    !(net->dest_state & SCTP_ADDR_NOHB)) {
  1.5624 +						sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
  1.5625 +								SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10);
  1.5626 +					}
  1.5627 +					net->dest_state |= SCTP_ADDR_NOHB;
  1.5628 +				}
  1.5629 +				if (paddrp->spp_flags & SPP_HB_ENABLE) {
  1.5630 +					if (paddrp->spp_hbinterval) {
  1.5631 +						net->heart_beat_delay = paddrp->spp_hbinterval;
  1.5632 +					} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
  1.5633 +						net->heart_beat_delay = 0;
  1.5634 +					}
  1.5635 +					sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
  1.5636 +					                SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10);
  1.5637 +					sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
  1.5638 +					net->dest_state &= ~SCTP_ADDR_NOHB;
  1.5639 +				}
  1.5640 +				if (paddrp->spp_flags & SPP_HB_DEMAND) {
  1.5641 +					/* on demand HB */
  1.5642 +					sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
  1.5643 +					sctp_chunk_output(inp, stcb,  SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED);
  1.5644 +					sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
  1.5645 +				}
  1.5646 +				if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
  1.5647 +					if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
  1.5648 +						sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
  1.5649 +								SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10);
  1.5650 +					}
  1.5651 +					net->dest_state |= SCTP_ADDR_NO_PMTUD;
  1.5652 +					net->mtu = paddrp->spp_pathmtu + ovh;
  1.5653 +					if (net->mtu < stcb->asoc.smallest_mtu) {
  1.5654 +						sctp_pathmtu_adjustment(stcb, net->mtu);
  1.5655 +					}
  1.5656 +				}
  1.5657 +				if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
  1.5658 +					if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
  1.5659 +						sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
  1.5660 +					}
  1.5661 +					net->dest_state &= ~SCTP_ADDR_NO_PMTUD;
  1.5662 +				}
  1.5663 +				if (paddrp->spp_pathmaxrxt) {
  1.5664 +					if (net->dest_state & SCTP_ADDR_PF) {
  1.5665 +						if (net->error_count > paddrp->spp_pathmaxrxt) {
  1.5666 +							net->dest_state &= ~SCTP_ADDR_PF;
  1.5667 +						}
  1.5668 +					} else {
  1.5669 +						if ((net->error_count <= paddrp->spp_pathmaxrxt) &&
  1.5670 +						    (net->error_count > net->pf_threshold)) {
  1.5671 +							net->dest_state |= SCTP_ADDR_PF;
  1.5672 +							sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
  1.5673 +							sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
  1.5674 +							sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
  1.5675 +						}
  1.5676 +					}
  1.5677 +					if (net->dest_state & SCTP_ADDR_REACHABLE) {
  1.5678 +						if (net->error_count > paddrp->spp_pathmaxrxt) {
  1.5679 +					    		net->dest_state &= ~SCTP_ADDR_REACHABLE;
  1.5680 +							sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
  1.5681 +						}
  1.5682 +					} else {
  1.5683 +						if (net->error_count <= paddrp->spp_pathmaxrxt) {
  1.5684 +							net->dest_state |= SCTP_ADDR_REACHABLE;
  1.5685 +							sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
  1.5686 +						}
  1.5687 +					}
  1.5688 +					net->failure_threshold = paddrp->spp_pathmaxrxt;
  1.5689 +				}
  1.5690 +				if (paddrp->spp_flags & SPP_DSCP) {
  1.5691 +					net->dscp = paddrp->spp_dscp & 0xfc;
  1.5692 +					net->dscp |= 0x01;
  1.5693 +				}
  1.5694 +#ifdef INET6
  1.5695 +				if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
  1.5696 +					if (net->ro._l_addr.sa.sa_family == AF_INET6) {
  1.5697 +						net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
  1.5698 +						net->flowlabel |= 0x80000000;
  1.5699 +					}
  1.5700 +				}
  1.5701 +#endif
  1.5702 +			} else {
  1.5703 +				/************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/
  1.5704 +				if (paddrp->spp_pathmaxrxt) {
  1.5705 +					stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt;
  1.5706 +					TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1.5707 +						if (net->dest_state & SCTP_ADDR_PF) {
  1.5708 +							if (net->error_count > paddrp->spp_pathmaxrxt) {
  1.5709 +								net->dest_state &= ~SCTP_ADDR_PF;
  1.5710 +							}
  1.5711 +						} else {
  1.5712 +							if ((net->error_count <= paddrp->spp_pathmaxrxt) &&
  1.5713 +							    (net->error_count > net->pf_threshold)) {
  1.5714 +								net->dest_state |= SCTP_ADDR_PF;
  1.5715 +								sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
  1.5716 +								sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
  1.5717 +								sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
  1.5718 +							}
  1.5719 +						}
  1.5720 +						if (net->dest_state & SCTP_ADDR_REACHABLE) {
  1.5721 +							if (net->error_count > paddrp->spp_pathmaxrxt) {
  1.5722 +						    		net->dest_state &= ~SCTP_ADDR_REACHABLE;
  1.5723 +								sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
  1.5724 +							}
  1.5725 +						} else {
  1.5726 +							if (net->error_count <= paddrp->spp_pathmaxrxt) {
  1.5727 +								net->dest_state |= SCTP_ADDR_REACHABLE;
  1.5728 +								sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
  1.5729 +							}
  1.5730 +						}
  1.5731 +						net->failure_threshold = paddrp->spp_pathmaxrxt;
  1.5732 +					}
  1.5733 +				}
  1.5734 +
  1.5735 +				if (paddrp->spp_flags & SPP_HB_ENABLE) {
  1.5736 +					if (paddrp->spp_hbinterval) {
  1.5737 +						stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval;
  1.5738 +					} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
  1.5739 +						stcb->asoc.heart_beat_delay = 0;
  1.5740 +					}
  1.5741 +					/* Turn back on the timer */
  1.5742 +					TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1.5743 +						if (paddrp->spp_hbinterval) {
  1.5744 +							net->heart_beat_delay = paddrp->spp_hbinterval;
  1.5745 +						} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
  1.5746 +							net->heart_beat_delay = 0;
  1.5747 +						}
  1.5748 +						if (net->dest_state & SCTP_ADDR_NOHB) {
  1.5749 +							net->dest_state &= ~SCTP_ADDR_NOHB;
  1.5750 +						}
  1.5751 +						sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
  1.5752 +								SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10);
  1.5753 +						sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
  1.5754 +					}
  1.5755 +					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
  1.5756 +				}
  1.5757 +				if (paddrp->spp_flags & SPP_HB_DISABLE) {
  1.5758 +					TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1.5759 +						if (!(net->dest_state & SCTP_ADDR_NOHB)) {
  1.5760 +							net->dest_state |= SCTP_ADDR_NOHB;
  1.5761 +							if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
  1.5762 +								sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10);
  1.5763 +							}
  1.5764 +						}
  1.5765 +					}
  1.5766 +					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
  1.5767 +				}
  1.5768 +				if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
  1.5769 +					TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1.5770 +						if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
  1.5771 +							sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
  1.5772 +									SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10);
  1.5773 +						}
  1.5774 +						net->dest_state |= SCTP_ADDR_NO_PMTUD;
  1.5775 +						net->mtu = paddrp->spp_pathmtu + ovh;
  1.5776 +						if (net->mtu < stcb->asoc.smallest_mtu) {
  1.5777 +							sctp_pathmtu_adjustment(stcb, net->mtu);
  1.5778 +						}
  1.5779 +					}
  1.5780 +					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
  1.5781 +				}
  1.5782 +				if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
  1.5783 +					TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1.5784 +						if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
  1.5785 +							sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
  1.5786 +						}
  1.5787 +						net->dest_state &= ~SCTP_ADDR_NO_PMTUD;
  1.5788 +					}
  1.5789 +					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
  1.5790 +				}
  1.5791 +				if (paddrp->spp_flags & SPP_DSCP) {
  1.5792 +					TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1.5793 +						net->dscp = paddrp->spp_dscp & 0xfc;
  1.5794 +						net->dscp |= 0x01;
  1.5795 +					}
  1.5796 +					stcb->asoc.default_dscp = paddrp->spp_dscp & 0xfc;
  1.5797 +					stcb->asoc.default_dscp |= 0x01;
  1.5798 +				}
  1.5799 +#ifdef INET6
  1.5800 +				if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
  1.5801 +					TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1.5802 +						if (net->ro._l_addr.sa.sa_family == AF_INET6) {
  1.5803 +							net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
  1.5804 +							net->flowlabel |= 0x80000000;
  1.5805 +						}
  1.5806 +					}
  1.5807 +					stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
  1.5808 +					stcb->asoc.default_flowlabel |= 0x80000000;
  1.5809 +				}
  1.5810 +#endif
  1.5811 +			}
  1.5812 +			SCTP_TCB_UNLOCK(stcb);
  1.5813 +		} else {
  1.5814 +			/************************NO TCB, SET TO default stuff ******************/
  1.5815 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.5816 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.5817 +			    (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) {
  1.5818 +				SCTP_INP_WLOCK(inp);
  1.5819 +				/*
  1.5820 +				 * For the TOS/FLOWLABEL stuff you set it
  1.5821 +				 * with the options on the socket
  1.5822 +				 */
  1.5823 +				if (paddrp->spp_pathmaxrxt) {
  1.5824 +					inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt;
  1.5825 +				}
  1.5826 +
  1.5827 +				if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO)
  1.5828 +					inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
  1.5829 +				else if (paddrp->spp_hbinterval) {
  1.5830 +					if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL)
  1.5831 +						paddrp->spp_hbinterval= SCTP_MAX_HB_INTERVAL;
  1.5832 +					inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
  1.5833 +				}
  1.5834 +
  1.5835 +				if (paddrp->spp_flags & SPP_HB_ENABLE) {
  1.5836 +					if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
  1.5837 +						inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
  1.5838 +					} else if (paddrp->spp_hbinterval) {
  1.5839 +						inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
  1.5840 +					}
  1.5841 +					sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
  1.5842 +				} else if (paddrp->spp_flags & SPP_HB_DISABLE) {
  1.5843 +					sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
  1.5844 +				}
  1.5845 +				if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
  1.5846 +					sctp_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
  1.5847 +				} else if (paddrp->spp_flags & SPP_PMTUD_DISABLE) {
  1.5848 +					sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
  1.5849 +				}
  1.5850 +				if (paddrp->spp_flags & SPP_DSCP) {
  1.5851 +					inp->sctp_ep.default_dscp = paddrp->spp_dscp & 0xfc;
  1.5852 +					inp->sctp_ep.default_dscp |= 0x01;
  1.5853 +				}
  1.5854 +#ifdef INET6
  1.5855 +				if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
  1.5856 +					if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
  1.5857 +						inp->sctp_ep.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
  1.5858 +						inp->sctp_ep.default_flowlabel |= 0x80000000;
  1.5859 +					}
  1.5860 +				}
  1.5861 +#endif
  1.5862 +				SCTP_INP_WUNLOCK(inp);
  1.5863 +			} else {
  1.5864 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.5865 +				error = EINVAL;
  1.5866 +			}
  1.5867 +		}
  1.5868 +		break;
  1.5869 +	}
  1.5870 +	case SCTP_RTOINFO:
  1.5871 +	{
  1.5872 +		struct sctp_rtoinfo *srto;
  1.5873 +		uint32_t new_init, new_min, new_max;
  1.5874 +
  1.5875 +		SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize);
  1.5876 +		SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
  1.5877 +
  1.5878 +		if (stcb) {
  1.5879 +			if (srto->srto_initial)
  1.5880 +				new_init = srto->srto_initial;
  1.5881 +			else
  1.5882 +				new_init = stcb->asoc.initial_rto;
  1.5883 +			if (srto->srto_max)
  1.5884 +				new_max = srto->srto_max;
  1.5885 +			else
  1.5886 +				new_max = stcb->asoc.maxrto;
  1.5887 +			if (srto->srto_min)
  1.5888 +				new_min = srto->srto_min;
  1.5889 +			else
  1.5890 +				new_min = stcb->asoc.minrto;
  1.5891 +			if ((new_min <= new_init) && (new_init <= new_max)) {
  1.5892 +				stcb->asoc.initial_rto = new_init;
  1.5893 +				stcb->asoc.maxrto = new_max;
  1.5894 +				stcb->asoc.minrto = new_min;
  1.5895 +			} else {
  1.5896 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.5897 +				error = EINVAL;
  1.5898 +			}
  1.5899 +			SCTP_TCB_UNLOCK(stcb);
  1.5900 +		} else {
  1.5901 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.5902 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.5903 +			    (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) {
  1.5904 +				SCTP_INP_WLOCK(inp);
  1.5905 +				if (srto->srto_initial)
  1.5906 +					new_init = srto->srto_initial;
  1.5907 +				else
  1.5908 +					new_init = inp->sctp_ep.initial_rto;
  1.5909 +				if (srto->srto_max)
  1.5910 +					new_max = srto->srto_max;
  1.5911 +				else
  1.5912 +					new_max = inp->sctp_ep.sctp_maxrto;
  1.5913 +				if (srto->srto_min)
  1.5914 +					new_min = srto->srto_min;
  1.5915 +				else
  1.5916 +					new_min = inp->sctp_ep.sctp_minrto;
  1.5917 +				if ((new_min <= new_init) && (new_init <= new_max)) {
  1.5918 +					inp->sctp_ep.initial_rto = new_init;
  1.5919 +					inp->sctp_ep.sctp_maxrto = new_max;
  1.5920 +					inp->sctp_ep.sctp_minrto = new_min;
  1.5921 +				} else {
  1.5922 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.5923 +					error = EINVAL;
  1.5924 +				}
  1.5925 +				SCTP_INP_WUNLOCK(inp);
  1.5926 +			} else {
  1.5927 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.5928 +				error = EINVAL;
  1.5929 +			}
  1.5930 +		}
  1.5931 +		break;
  1.5932 +	}
  1.5933 +	case SCTP_ASSOCINFO:
  1.5934 +	{
  1.5935 +		struct sctp_assocparams *sasoc;
  1.5936 +
  1.5937 +		SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize);
  1.5938 +		SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
  1.5939 +		if (sasoc->sasoc_cookie_life) {
  1.5940 +			/* boundary check the cookie life */
  1.5941 +			if (sasoc->sasoc_cookie_life < 1000)
  1.5942 +				sasoc->sasoc_cookie_life = 1000;
  1.5943 +			if (sasoc->sasoc_cookie_life > SCTP_MAX_COOKIE_LIFE) {
  1.5944 +				sasoc->sasoc_cookie_life = SCTP_MAX_COOKIE_LIFE;
  1.5945 +			}
  1.5946 +		}
  1.5947 +		if (stcb) {
  1.5948 +			if (sasoc->sasoc_asocmaxrxt)
  1.5949 +				stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt;
  1.5950 +			if (sasoc->sasoc_cookie_life) {
  1.5951 +				stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
  1.5952 +			}
  1.5953 +			SCTP_TCB_UNLOCK(stcb);
  1.5954 +		} else {
  1.5955 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.5956 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.5957 +			    (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) {
  1.5958 +				SCTP_INP_WLOCK(inp);
  1.5959 +				if (sasoc->sasoc_asocmaxrxt)
  1.5960 +					inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt;
  1.5961 +				if (sasoc->sasoc_cookie_life) {
  1.5962 +					inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
  1.5963 +				}
  1.5964 +				SCTP_INP_WUNLOCK(inp);
  1.5965 +			} else {
  1.5966 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.5967 +				error = EINVAL;
  1.5968 +			}
  1.5969 +		}
  1.5970 +		break;
  1.5971 +	}
  1.5972 +	case SCTP_INITMSG:
  1.5973 +	{
  1.5974 +		struct sctp_initmsg *sinit;
  1.5975 +
  1.5976 +		SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize);
  1.5977 +		SCTP_INP_WLOCK(inp);
  1.5978 +		if (sinit->sinit_num_ostreams)
  1.5979 +			inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams;
  1.5980 +
  1.5981 +		if (sinit->sinit_max_instreams)
  1.5982 +			inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams;
  1.5983 +
  1.5984 +		if (sinit->sinit_max_attempts)
  1.5985 +			inp->sctp_ep.max_init_times = sinit->sinit_max_attempts;
  1.5986 +
  1.5987 +		if (sinit->sinit_max_init_timeo)
  1.5988 +			inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo;
  1.5989 +		SCTP_INP_WUNLOCK(inp);
  1.5990 +		break;
  1.5991 +	}
  1.5992 +	case SCTP_PRIMARY_ADDR:
  1.5993 +	{
  1.5994 +		struct sctp_setprim *spa;
  1.5995 +		struct sctp_nets *net;
  1.5996 +
  1.5997 +		SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize);
  1.5998 +		SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id);
  1.5999 +
  1.6000 +		net = NULL;
  1.6001 +		if (stcb) {
  1.6002 +			net = sctp_findnet(stcb, (struct sockaddr *)&spa->ssp_addr);
  1.6003 +		} else {
  1.6004 +			/* We increment here since sctp_findassociation_ep_addr() wil
  1.6005 +			 * do a decrement if it finds the stcb as long as the locked
  1.6006 +			 * tcb (last argument) is NOT a TCB.. aka NULL.
  1.6007 +			 */
  1.6008 +			SCTP_INP_INCR_REF(inp);
  1.6009 +			stcb = sctp_findassociation_ep_addr(&inp,
  1.6010 +							    (struct sockaddr *)&spa->ssp_addr,
  1.6011 +							    &net, NULL, NULL);
  1.6012 +			if (stcb == NULL) {
  1.6013 +				SCTP_INP_DECR_REF(inp);
  1.6014 +			}
  1.6015 +		}
  1.6016 +
  1.6017 +		if ((stcb) && (net)) {
  1.6018 +			if ((net != stcb->asoc.primary_destination) &&
  1.6019 +			    (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) {
  1.6020 +				/* Ok we need to set it */
  1.6021 +				if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) {
  1.6022 +					if ((stcb->asoc.alternate) &&
  1.6023 +					    (!(net->dest_state & SCTP_ADDR_PF)) &&
  1.6024 +					    (net->dest_state & SCTP_ADDR_REACHABLE)) {
  1.6025 +						sctp_free_remote_addr(stcb->asoc.alternate);
  1.6026 +						stcb->asoc.alternate = NULL;
  1.6027 +					}
  1.6028 +				}
  1.6029 +			}
  1.6030 +		} else {
  1.6031 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6032 +			error = EINVAL;
  1.6033 +		}
  1.6034 +		if (stcb) {
  1.6035 +			SCTP_TCB_UNLOCK(stcb);
  1.6036 +		}
  1.6037 +		break;
  1.6038 +	}
  1.6039 +	case SCTP_SET_DYNAMIC_PRIMARY:
  1.6040 +	{
  1.6041 +		union sctp_sockstore *ss;
  1.6042 +#ifdef SCTP_MVRF
  1.6043 +		int i, fnd = 0;
  1.6044 +#endif
  1.6045 +#if !defined(__Windows__) && !defined(__Userspace__)
  1.6046 +#if defined(__APPLE__)
  1.6047 +		struct proc *proc;
  1.6048 +#endif
  1.6049 +#ifdef __FreeBSD__
  1.6050 +#if __FreeBSD_version > 602000
  1.6051 +		error = priv_check(curthread,
  1.6052 +				   PRIV_NETINET_RESERVEDPORT);
  1.6053 +#elif __FreeBSD_version >= 500000
  1.6054 +		error = suser((struct thread *)p);
  1.6055 +#else
  1.6056 +		error = suser(p);
  1.6057 +#endif
  1.6058 +#elif defined(__APPLE__)
  1.6059 +		proc = (struct proc *)p;
  1.6060 +		if (p) {
  1.6061 +			error = suser(proc->p_ucred, &proc->p_acflag);
  1.6062 +		} else {
  1.6063 +			break;
  1.6064 +		}
  1.6065 +#else
  1.6066 +		error = suser(p, 0);
  1.6067 +#endif
  1.6068 +#endif
  1.6069 +		if (error)
  1.6070 +			break;
  1.6071 +
  1.6072 +		SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize);
  1.6073 +		/* SUPER USER CHECK? */
  1.6074 +#ifdef SCTP_MVRF
  1.6075 +		for (i = 0; i < inp->num_vrfs; i++) {
  1.6076 +			if (vrf_id == inp->m_vrf_ids[i]) {
  1.6077 +				fnd = 1;
  1.6078 +				break;
  1.6079 +			}
  1.6080 +		}
  1.6081 +		if (!fnd) {
  1.6082 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6083 +			error = EINVAL;
  1.6084 +			break;
  1.6085 +		}
  1.6086 +#endif
  1.6087 +		error = sctp_dynamic_set_primary(&ss->sa, vrf_id);
  1.6088 +		break;
  1.6089 +	}
  1.6090 +	case SCTP_SET_PEER_PRIMARY_ADDR:
  1.6091 +	{
  1.6092 +		struct sctp_setpeerprim *sspp;
  1.6093 +
  1.6094 +		SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize);
  1.6095 +		SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id);
  1.6096 +		if (stcb != NULL) {
  1.6097 +			struct sctp_ifa *ifa;
  1.6098 +			ifa = sctp_find_ifa_by_addr((struct sockaddr *)&sspp->sspp_addr,
  1.6099 +						    stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED);
  1.6100 +			if (ifa == NULL) {
  1.6101 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6102 +				error = EINVAL;
  1.6103 +				goto out_of_it;
  1.6104 +			}
  1.6105 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
  1.6106 +				/* Must validate the ifa found is in our ep */
  1.6107 +				struct sctp_laddr *laddr;
  1.6108 +				int found = 0;
  1.6109 +				LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
  1.6110 +					if (laddr->ifa == NULL) {
  1.6111 +						SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n",
  1.6112 +							__FUNCTION__);
  1.6113 +						continue;
  1.6114 +					}
  1.6115 +					if (laddr->ifa == ifa) {
  1.6116 +						found = 1;
  1.6117 +						break;
  1.6118 +					}
  1.6119 +				}
  1.6120 +				if (!found) {
  1.6121 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6122 +					error = EINVAL;
  1.6123 +					goto out_of_it;
  1.6124 +				}
  1.6125 +			}
  1.6126 +			if (sctp_set_primary_ip_address_sa(stcb,
  1.6127 +							   (struct sockaddr *)&sspp->sspp_addr) != 0) {
  1.6128 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6129 +				error = EINVAL;
  1.6130 +			}
  1.6131 +		out_of_it:
  1.6132 +			SCTP_TCB_UNLOCK(stcb);
  1.6133 +		} else {
  1.6134 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6135 +			error = EINVAL;
  1.6136 +		}
  1.6137 +		break;
  1.6138 +	}
  1.6139 +	case SCTP_BINDX_ADD_ADDR:
  1.6140 +	{
  1.6141 +		struct sctp_getaddresses *addrs;
  1.6142 +#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
  1.6143 +		struct thread *td;
  1.6144 +
  1.6145 +		td = (struct thread *)p;
  1.6146 +#endif
  1.6147 +		SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses,
  1.6148 +				    optsize);
  1.6149 +#ifdef INET
  1.6150 +		if (addrs->addr->sa_family == AF_INET) {
  1.6151 +			if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) {
  1.6152 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6153 +				error = EINVAL;
  1.6154 +				break;
  1.6155 +			}
  1.6156 +#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
  1.6157 +			if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) {
  1.6158 +				SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.6159 +				break;
  1.6160 +			}
  1.6161 +#endif
  1.6162 +		} else
  1.6163 +#endif
  1.6164 +#ifdef INET6
  1.6165 +		if (addrs->addr->sa_family == AF_INET6) {
  1.6166 +			if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) {
  1.6167 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6168 +				error = EINVAL;
  1.6169 +				break;
  1.6170 +			}
  1.6171 +#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
  1.6172 +			if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
  1.6173 +											   (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
  1.6174 +			  SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.6175 +			  break;
  1.6176 +			}
  1.6177 +#endif
  1.6178 +		} else
  1.6179 +#endif
  1.6180 +		{
  1.6181 +		       error = EAFNOSUPPORT;
  1.6182 +  		       break;
  1.6183 +		}
  1.6184 +		sctp_bindx_add_address(so, inp, addrs->addr,
  1.6185 +				       addrs->sget_assoc_id, vrf_id,
  1.6186 +				       &error, p);
  1.6187 +		break;
  1.6188 +	}
  1.6189 +	case SCTP_BINDX_REM_ADDR:
  1.6190 +	{
  1.6191 +		struct sctp_getaddresses *addrs;
  1.6192 +#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
  1.6193 +		struct thread *td;
  1.6194 +		td = (struct thread *)p;
  1.6195 +
  1.6196 +#endif
  1.6197 +		SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize);
  1.6198 +#ifdef INET
  1.6199 +		if (addrs->addr->sa_family == AF_INET) {
  1.6200 +			if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) {
  1.6201 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6202 +				error = EINVAL;
  1.6203 +				break;
  1.6204 +			}
  1.6205 +#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
  1.6206 +		if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) {
  1.6207 +				SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.6208 +				break;
  1.6209 +			}
  1.6210 +#endif
  1.6211 +		} else
  1.6212 +#endif
  1.6213 +#ifdef INET6
  1.6214 +		if (addrs->addr->sa_family == AF_INET6) {
  1.6215 +			if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) {
  1.6216 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6217 +				error = EINVAL;
  1.6218 +				break;
  1.6219 +			}
  1.6220 +#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
  1.6221 +			if (td != NULL &&
  1.6222 +			    (error = prison_local_ip6(td->td_ucred,
  1.6223 +			                              &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
  1.6224 +			                              (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
  1.6225 +				SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.6226 +				break;
  1.6227 +			}
  1.6228 +#endif
  1.6229 +		} else
  1.6230 +#endif
  1.6231 +		{
  1.6232 +			error = EAFNOSUPPORT;
  1.6233 +			break;
  1.6234 +		}
  1.6235 +		sctp_bindx_delete_address(inp, addrs->addr,
  1.6236 +					  addrs->sget_assoc_id, vrf_id,
  1.6237 +					  &error);
  1.6238 +		break;
  1.6239 +	}
  1.6240 +#ifdef __APPLE__
  1.6241 +	case SCTP_LISTEN_FIX:
  1.6242 +		/* only applies to one-to-many sockets */
  1.6243 +		if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
  1.6244 +			/* make sure the ACCEPTCONN flag is OFF */
  1.6245 +			so->so_options &= ~SO_ACCEPTCONN;
  1.6246 +		} else {
  1.6247 +			/* otherwise, not allowed */
  1.6248 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6249 +			error = EINVAL;
  1.6250 +		}
  1.6251 +		break;
  1.6252 +#endif				/* __APPLE__ */
  1.6253 +	case SCTP_EVENT:
  1.6254 +	{
  1.6255 +		struct sctp_event *event;
  1.6256 +		uint32_t event_type;
  1.6257 +
  1.6258 +		SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, optsize);
  1.6259 +		SCTP_FIND_STCB(inp, stcb, event->se_assoc_id);
  1.6260 +		switch (event->se_type) {
  1.6261 +		case SCTP_ASSOC_CHANGE:
  1.6262 +			event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT;
  1.6263 +			break;
  1.6264 +		case SCTP_PEER_ADDR_CHANGE:
  1.6265 +			event_type = SCTP_PCB_FLAGS_RECVPADDREVNT;
  1.6266 +			break;
  1.6267 +		case SCTP_REMOTE_ERROR:
  1.6268 +			event_type = SCTP_PCB_FLAGS_RECVPEERERR;
  1.6269 +			break;
  1.6270 +		case SCTP_SEND_FAILED:
  1.6271 +			event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT;
  1.6272 +			break;
  1.6273 +		case SCTP_SHUTDOWN_EVENT:
  1.6274 +			event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT;
  1.6275 +			break;
  1.6276 +		case SCTP_ADAPTATION_INDICATION:
  1.6277 +			event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT;
  1.6278 +			break;
  1.6279 +		case SCTP_PARTIAL_DELIVERY_EVENT:
  1.6280 +			event_type = SCTP_PCB_FLAGS_PDAPIEVNT;
  1.6281 +			break;
  1.6282 +		case SCTP_AUTHENTICATION_EVENT:
  1.6283 +			event_type = SCTP_PCB_FLAGS_AUTHEVNT;
  1.6284 +			break;
  1.6285 +		case SCTP_STREAM_RESET_EVENT:
  1.6286 +			event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT;
  1.6287 +			break;
  1.6288 +		case SCTP_SENDER_DRY_EVENT:
  1.6289 +			event_type = SCTP_PCB_FLAGS_DRYEVNT;
  1.6290 +			break;
  1.6291 +		case SCTP_NOTIFICATIONS_STOPPED_EVENT:
  1.6292 +			event_type = 0;
  1.6293 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
  1.6294 +			error = ENOTSUP;
  1.6295 +			break;
  1.6296 +		case SCTP_ASSOC_RESET_EVENT:
  1.6297 +			event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT;
  1.6298 +			break;
  1.6299 +		case SCTP_STREAM_CHANGE_EVENT:
  1.6300 +			event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT;
  1.6301 +			break;
  1.6302 +		case SCTP_SEND_FAILED_EVENT:
  1.6303 +			event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT;
  1.6304 +			break;
  1.6305 +		default:
  1.6306 +			event_type = 0;
  1.6307 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6308 +			error = EINVAL;
  1.6309 +			break;
  1.6310 +		}
  1.6311 +		if (event_type > 0) {
  1.6312 +			if (stcb) {
  1.6313 +				if (event->se_on) {
  1.6314 +					sctp_stcb_feature_on(inp, stcb, event_type);
  1.6315 +					if (event_type == SCTP_PCB_FLAGS_DRYEVNT) {
  1.6316 +						if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
  1.6317 +						    TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
  1.6318 +						    (stcb->asoc.stream_queue_cnt == 0)) {
  1.6319 +							sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb,  0, NULL, SCTP_SO_LOCKED);
  1.6320 +						}
  1.6321 +					}
  1.6322 +				} else {
  1.6323 +					sctp_stcb_feature_off(inp, stcb, event_type);
  1.6324 +				}
  1.6325 +				SCTP_TCB_UNLOCK(stcb);
  1.6326 +			} else {
  1.6327 +				/*
  1.6328 +				 * We don't want to send up a storm of events,
  1.6329 +				 * so return an error for sender dry events
  1.6330 +				 */
  1.6331 +				if ((event_type == SCTP_PCB_FLAGS_DRYEVNT) &&
  1.6332 +				    ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) &&
  1.6333 +				    ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
  1.6334 +				    ((event->se_assoc_id == SCTP_ALL_ASSOC) ||
  1.6335 +				     (event->se_assoc_id == SCTP_CURRENT_ASSOC))) {
  1.6336 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
  1.6337 +					error = ENOTSUP;
  1.6338 +					break;
  1.6339 +				}
  1.6340 +				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.6341 +				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.6342 +				    (event->se_assoc_id == SCTP_FUTURE_ASSOC) ||
  1.6343 +				    (event->se_assoc_id == SCTP_ALL_ASSOC)) {
  1.6344 +					SCTP_INP_WLOCK(inp);
  1.6345 +					if (event->se_on) {
  1.6346 +						sctp_feature_on(inp, event_type);
  1.6347 +					} else {
  1.6348 +						sctp_feature_off(inp, event_type);
  1.6349 +					}
  1.6350 +					SCTP_INP_WUNLOCK(inp);
  1.6351 +				}
  1.6352 +				if ((event->se_assoc_id == SCTP_CURRENT_ASSOC) ||
  1.6353 +				    (event->se_assoc_id == SCTP_ALL_ASSOC)) {
  1.6354 +					SCTP_INP_RLOCK(inp);
  1.6355 +					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.6356 +						SCTP_TCB_LOCK(stcb);
  1.6357 +						if (event->se_on) {
  1.6358 +							sctp_stcb_feature_on(inp, stcb, event_type);
  1.6359 +						} else {
  1.6360 +							sctp_stcb_feature_off(inp, stcb, event_type);
  1.6361 +						}
  1.6362 +						SCTP_TCB_UNLOCK(stcb);
  1.6363 +					}
  1.6364 +					SCTP_INP_RUNLOCK(inp);
  1.6365 +				}
  1.6366 +			}
  1.6367 +		}
  1.6368 +		break;
  1.6369 +	}
  1.6370 +	case SCTP_RECVRCVINFO:
  1.6371 +	{
  1.6372 +		int *onoff;
  1.6373 +
  1.6374 +		SCTP_CHECK_AND_CAST(onoff, optval, int, optsize);
  1.6375 +		SCTP_INP_WLOCK(inp);
  1.6376 +		if (*onoff != 0) {
  1.6377 +			sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
  1.6378 +		} else {
  1.6379 +			sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
  1.6380 +		}
  1.6381 +		SCTP_INP_WUNLOCK(inp);
  1.6382 +		break;
  1.6383 +	}
  1.6384 +	case SCTP_RECVNXTINFO:
  1.6385 +	{
  1.6386 +		int *onoff;
  1.6387 +
  1.6388 +		SCTP_CHECK_AND_CAST(onoff, optval, int, optsize);
  1.6389 +		SCTP_INP_WLOCK(inp);
  1.6390 +		if (*onoff != 0) {
  1.6391 +			sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
  1.6392 +		} else {
  1.6393 +			sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
  1.6394 +		}
  1.6395 +		SCTP_INP_WUNLOCK(inp);
  1.6396 +		break;
  1.6397 +	}
  1.6398 +	case SCTP_DEFAULT_SNDINFO:
  1.6399 +	{
  1.6400 +		struct sctp_sndinfo *info;
  1.6401 +		uint16_t policy;
  1.6402 +
  1.6403 +		SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, optsize);
  1.6404 +		SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id);
  1.6405 +
  1.6406 +		if (stcb) {
  1.6407 +			if (info->snd_sid < stcb->asoc.streamoutcnt) {
  1.6408 +				stcb->asoc.def_send.sinfo_stream = info->snd_sid;
  1.6409 +				policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
  1.6410 +				stcb->asoc.def_send.sinfo_flags = info->snd_flags;
  1.6411 +				stcb->asoc.def_send.sinfo_flags |= policy;
  1.6412 +				stcb->asoc.def_send.sinfo_ppid = info->snd_ppid;
  1.6413 +				stcb->asoc.def_send.sinfo_context = info->snd_context;
  1.6414 +			} else {
  1.6415 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6416 +				error = EINVAL;
  1.6417 +			}
  1.6418 +			SCTP_TCB_UNLOCK(stcb);
  1.6419 +		} else {
  1.6420 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.6421 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.6422 +			    (info->snd_assoc_id == SCTP_FUTURE_ASSOC) ||
  1.6423 +			    (info->snd_assoc_id == SCTP_ALL_ASSOC)) {
  1.6424 +				SCTP_INP_WLOCK(inp);
  1.6425 +				inp->def_send.sinfo_stream = info->snd_sid;
  1.6426 +				policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags);
  1.6427 +				inp->def_send.sinfo_flags = info->snd_flags;
  1.6428 +				inp->def_send.sinfo_flags |= policy;
  1.6429 +				inp->def_send.sinfo_ppid = info->snd_ppid;
  1.6430 +				inp->def_send.sinfo_context = info->snd_context;
  1.6431 +				SCTP_INP_WUNLOCK(inp);
  1.6432 +			}
  1.6433 +			if ((info->snd_assoc_id == SCTP_CURRENT_ASSOC) ||
  1.6434 +			    (info->snd_assoc_id == SCTP_ALL_ASSOC)) {
  1.6435 +				SCTP_INP_RLOCK(inp);
  1.6436 +				LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.6437 +					SCTP_TCB_LOCK(stcb);
  1.6438 +					if (info->snd_sid < stcb->asoc.streamoutcnt) {
  1.6439 +						stcb->asoc.def_send.sinfo_stream = info->snd_sid;
  1.6440 +						policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
  1.6441 +						stcb->asoc.def_send.sinfo_flags = info->snd_flags;
  1.6442 +						stcb->asoc.def_send.sinfo_flags |= policy;
  1.6443 +						stcb->asoc.def_send.sinfo_ppid = info->snd_ppid;
  1.6444 +						stcb->asoc.def_send.sinfo_context = info->snd_context;
  1.6445 +					}
  1.6446 +					SCTP_TCB_UNLOCK(stcb);
  1.6447 +				}
  1.6448 +				SCTP_INP_RUNLOCK(inp);
  1.6449 +			}
  1.6450 +		}
  1.6451 +		break;
  1.6452 +	}
  1.6453 +	case SCTP_DEFAULT_PRINFO:
  1.6454 +	{
  1.6455 +		struct sctp_default_prinfo *info;
  1.6456 +
  1.6457 +		SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, optsize);
  1.6458 +		SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id);
  1.6459 +
  1.6460 +		if (PR_SCTP_INVALID_POLICY(info->pr_policy)) {
  1.6461 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6462 +			error = EINVAL;
  1.6463 +			break;
  1.6464 +		}
  1.6465 +		if (stcb) {
  1.6466 +			stcb->asoc.def_send.sinfo_flags &= 0xfff0;
  1.6467 +			stcb->asoc.def_send.sinfo_flags |= info->pr_policy;
  1.6468 +			stcb->asoc.def_send.sinfo_timetolive = info->pr_value;
  1.6469 +			SCTP_TCB_UNLOCK(stcb);
  1.6470 +		} else {
  1.6471 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.6472 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.6473 +			    (info->pr_assoc_id == SCTP_FUTURE_ASSOC) ||
  1.6474 +			    (info->pr_assoc_id == SCTP_ALL_ASSOC)) {
  1.6475 +				SCTP_INP_WLOCK(inp);
  1.6476 +				inp->def_send.sinfo_flags &= 0xfff0;
  1.6477 +				inp->def_send.sinfo_flags |= info->pr_policy;
  1.6478 +				inp->def_send.sinfo_timetolive = info->pr_value;
  1.6479 +				SCTP_INP_WUNLOCK(inp);
  1.6480 +			}
  1.6481 +			if ((info->pr_assoc_id == SCTP_CURRENT_ASSOC) ||
  1.6482 +			    (info->pr_assoc_id == SCTP_ALL_ASSOC)) {
  1.6483 +				SCTP_INP_RLOCK(inp);
  1.6484 +				LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
  1.6485 +					SCTP_TCB_LOCK(stcb);
  1.6486 +					stcb->asoc.def_send.sinfo_flags &= 0xfff0;
  1.6487 +					stcb->asoc.def_send.sinfo_flags |= info->pr_policy;
  1.6488 +					stcb->asoc.def_send.sinfo_timetolive = info->pr_value;
  1.6489 +					SCTP_TCB_UNLOCK(stcb);
  1.6490 +				}
  1.6491 +				SCTP_INP_RUNLOCK(inp);
  1.6492 +			}
  1.6493 +		}
  1.6494 +		break;
  1.6495 +	}
  1.6496 +	case SCTP_PEER_ADDR_THLDS:
  1.6497 +		/* Applies to the specific association */
  1.6498 +	{
  1.6499 +		struct sctp_paddrthlds *thlds;
  1.6500 +		struct sctp_nets *net;
  1.6501 +
  1.6502 +		SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, optsize);
  1.6503 +		SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
  1.6504 +		net = NULL;
  1.6505 +		if (stcb) {
  1.6506 +			net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_assoc_id);
  1.6507 +		} else {
  1.6508 +			/* We increment here since sctp_findassociation_ep_addr() wil
  1.6509 +			 * do a decrement if it finds the stcb as long as the locked
  1.6510 +			 * tcb (last argument) is NOT a TCB.. aka NULL.
  1.6511 +			 */
  1.6512 +			SCTP_INP_INCR_REF(inp);
  1.6513 +			stcb = sctp_findassociation_ep_addr(&inp,
  1.6514 +							    (struct sockaddr *)&thlds->spt_assoc_id,
  1.6515 +							    &net, NULL, NULL);
  1.6516 +			if (stcb == NULL) {
  1.6517 +				SCTP_INP_DECR_REF(inp);
  1.6518 +			}
  1.6519 +		}
  1.6520 +		if (stcb && (net == NULL)) {
  1.6521 +			struct sockaddr *sa;
  1.6522 +
  1.6523 +			sa = (struct sockaddr *)&thlds->spt_assoc_id;
  1.6524 +#ifdef INET
  1.6525 +			if (sa->sa_family == AF_INET) {
  1.6526 +
  1.6527 +				struct sockaddr_in *sin;
  1.6528 +				sin = (struct sockaddr_in *)sa;
  1.6529 +				if (sin->sin_addr.s_addr) {
  1.6530 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6531 +					SCTP_TCB_UNLOCK(stcb);
  1.6532 +					error = EINVAL;
  1.6533 +					break;
  1.6534 +				}
  1.6535 +			} else
  1.6536 +#endif
  1.6537 +#ifdef INET6
  1.6538 +			if (sa->sa_family == AF_INET6) {
  1.6539 +				struct sockaddr_in6 *sin6;
  1.6540 +
  1.6541 +				sin6 = (struct sockaddr_in6 *)sa;
  1.6542 +				if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
  1.6543 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6544 +					SCTP_TCB_UNLOCK(stcb);
  1.6545 +					error = EINVAL;
  1.6546 +					break;
  1.6547 +				}
  1.6548 +			} else
  1.6549 +#endif
  1.6550 +#if defined(__Userspace__)
  1.6551 +			if (sa->sa_family == AF_CONN) {
  1.6552 +				struct sockaddr_conn *sconn;
  1.6553 +
  1.6554 +				sconn = (struct sockaddr_conn *)sa;
  1.6555 +				if (sconn->sconn_addr != NULL) {
  1.6556 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6557 +					SCTP_TCB_UNLOCK(stcb);
  1.6558 +					error = EINVAL;
  1.6559 +					break;
  1.6560 +				}
  1.6561 +			} else
  1.6562 +#endif
  1.6563 +			{
  1.6564 +				error = EAFNOSUPPORT;
  1.6565 +				SCTP_TCB_UNLOCK(stcb);
  1.6566 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.6567 +				break;
  1.6568 +			}
  1.6569 +		}
  1.6570 +		if (stcb) {
  1.6571 +			if (net) {
  1.6572 +				if (net->dest_state & SCTP_ADDR_PF) {
  1.6573 +					if ((net->failure_threshold > thlds->spt_pathmaxrxt) ||
  1.6574 +					    (net->failure_threshold <= thlds->spt_pathpfthld)) {
  1.6575 +						net->dest_state &= ~SCTP_ADDR_PF;
  1.6576 +					}
  1.6577 +				} else {
  1.6578 +					if ((net->failure_threshold > thlds->spt_pathpfthld) &&
  1.6579 +					    (net->failure_threshold <= thlds->spt_pathmaxrxt)) {
  1.6580 +					    	net->dest_state |= SCTP_ADDR_PF;
  1.6581 +						sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
  1.6582 +						sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
  1.6583 +						sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
  1.6584 +					}
  1.6585 +				}
  1.6586 +				if (net->dest_state & SCTP_ADDR_REACHABLE) {
  1.6587 +					if (net->failure_threshold > thlds->spt_pathmaxrxt) {
  1.6588 +						net->dest_state &= ~SCTP_ADDR_REACHABLE;
  1.6589 +						sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
  1.6590 +					}
  1.6591 +				} else {
  1.6592 +					if (net->failure_threshold <= thlds->spt_pathmaxrxt) {
  1.6593 +						net->dest_state |= SCTP_ADDR_REACHABLE;
  1.6594 +						sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
  1.6595 +					}
  1.6596 +				}
  1.6597 +				net->failure_threshold = thlds->spt_pathmaxrxt;
  1.6598 +				net->pf_threshold = thlds->spt_pathpfthld;
  1.6599 +			} else {
  1.6600 +				TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1.6601 +					if (net->dest_state & SCTP_ADDR_PF) {
  1.6602 +						if ((net->failure_threshold > thlds->spt_pathmaxrxt) ||
  1.6603 +						    (net->failure_threshold <= thlds->spt_pathpfthld)) {
  1.6604 +							net->dest_state &= ~SCTP_ADDR_PF;
  1.6605 +						}
  1.6606 +					} else {
  1.6607 +						if ((net->failure_threshold > thlds->spt_pathpfthld) &&
  1.6608 +						    (net->failure_threshold <= thlds->spt_pathmaxrxt)) {
  1.6609 +						    	net->dest_state |= SCTP_ADDR_PF;
  1.6610 +							sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
  1.6611 +							sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
  1.6612 +							sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
  1.6613 +						}
  1.6614 +					}
  1.6615 +					if (net->dest_state & SCTP_ADDR_REACHABLE) {
  1.6616 +						if (net->failure_threshold > thlds->spt_pathmaxrxt) {
  1.6617 +							net->dest_state &= ~SCTP_ADDR_REACHABLE;
  1.6618 +							sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
  1.6619 +						}
  1.6620 +					} else {
  1.6621 +						if (net->failure_threshold <= thlds->spt_pathmaxrxt) {
  1.6622 +							net->dest_state |= SCTP_ADDR_REACHABLE;
  1.6623 +							sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
  1.6624 +						}
  1.6625 +					}
  1.6626 +					net->failure_threshold = thlds->spt_pathmaxrxt;
  1.6627 +					net->pf_threshold = thlds->spt_pathpfthld;
  1.6628 +				}
  1.6629 +				stcb->asoc.def_net_failure = thlds->spt_pathmaxrxt;
  1.6630 +				stcb->asoc.def_net_pf_threshold = thlds->spt_pathpfthld;
  1.6631 +			}
  1.6632 +		} else {
  1.6633 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.6634 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.6635 +			    (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) {
  1.6636 +				SCTP_INP_WLOCK(inp);
  1.6637 +				inp->sctp_ep.def_net_failure = thlds->spt_pathmaxrxt;
  1.6638 +				inp->sctp_ep.def_net_pf_threshold = thlds->spt_pathpfthld;
  1.6639 +				SCTP_INP_WUNLOCK(inp);
  1.6640 +			} else {
  1.6641 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6642 +				error = EINVAL;
  1.6643 +			}
  1.6644 +		}
  1.6645 +		break;
  1.6646 +	}
  1.6647 +	case SCTP_REMOTE_UDP_ENCAPS_PORT:
  1.6648 +	{
  1.6649 +		struct sctp_udpencaps *encaps;
  1.6650 +		struct sctp_nets *net;
  1.6651 +
  1.6652 +		SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, optsize);
  1.6653 +		SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id);
  1.6654 +		if (stcb) {
  1.6655 +			net = sctp_findnet(stcb, (struct sockaddr *)&encaps->sue_address);
  1.6656 +		} else {
  1.6657 +			/* We increment here since sctp_findassociation_ep_addr() wil
  1.6658 +			 * do a decrement if it finds the stcb as long as the locked
  1.6659 +			 * tcb (last argument) is NOT a TCB.. aka NULL.
  1.6660 +			 */
  1.6661 +			net = NULL;
  1.6662 +			SCTP_INP_INCR_REF(inp);
  1.6663 +			stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&encaps->sue_address, &net, NULL, NULL);
  1.6664 +			if (stcb == NULL) {
  1.6665 +				SCTP_INP_DECR_REF(inp);
  1.6666 +			}
  1.6667 +		}
  1.6668 +		if (stcb && (net == NULL)) {
  1.6669 +			struct sockaddr *sa;
  1.6670 +
  1.6671 +			sa = (struct sockaddr *)&encaps->sue_address;
  1.6672 +#ifdef INET
  1.6673 +			if (sa->sa_family == AF_INET) {
  1.6674 +
  1.6675 +				struct sockaddr_in *sin;
  1.6676 +				sin = (struct sockaddr_in *)sa;
  1.6677 +				if (sin->sin_addr.s_addr) {
  1.6678 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6679 +					SCTP_TCB_UNLOCK(stcb);
  1.6680 +					error = EINVAL;
  1.6681 +					break;
  1.6682 +				}
  1.6683 +			} else
  1.6684 +#endif
  1.6685 +#ifdef INET6
  1.6686 +			if (sa->sa_family == AF_INET6) {
  1.6687 +				struct sockaddr_in6 *sin6;
  1.6688 +
  1.6689 +				sin6 = (struct sockaddr_in6 *)sa;
  1.6690 +				if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
  1.6691 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6692 +					SCTP_TCB_UNLOCK(stcb);
  1.6693 +					error = EINVAL;
  1.6694 +					break;
  1.6695 +				}
  1.6696 +			} else
  1.6697 +#endif
  1.6698 +#if defined(__Userspace__)
  1.6699 +			if (sa->sa_family == AF_CONN) {
  1.6700 +				struct sockaddr_conn *sconn;
  1.6701 +
  1.6702 +				sconn = (struct sockaddr_conn *)sa;
  1.6703 +				if (sconn->sconn_addr != NULL) {
  1.6704 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6705 +					SCTP_TCB_UNLOCK(stcb);
  1.6706 +					error = EINVAL;
  1.6707 +					break;
  1.6708 +				}
  1.6709 +			} else
  1.6710 +#endif
  1.6711 +			{
  1.6712 +					error = EAFNOSUPPORT;
  1.6713 +					SCTP_TCB_UNLOCK(stcb);
  1.6714 +					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.6715 +					break;
  1.6716 +				}
  1.6717 +		}
  1.6718 +
  1.6719 +		if (stcb) {
  1.6720 +			if (net) {
  1.6721 +				net->port = encaps->sue_port;
  1.6722 +			} else {
  1.6723 +				stcb->asoc.port = encaps->sue_port;
  1.6724 +			}
  1.6725 +			SCTP_TCB_UNLOCK(stcb);
  1.6726 +		} else {
  1.6727 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
  1.6728 +			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
  1.6729 +			    (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) {
  1.6730 +				SCTP_INP_WLOCK(inp);
  1.6731 +				inp->sctp_ep.port = encaps->sue_port;
  1.6732 +				SCTP_INP_WUNLOCK(inp);
  1.6733 +			} else {
  1.6734 +				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6735 +				error = EINVAL;
  1.6736 +			}
  1.6737 +		}
  1.6738 +		break;
  1.6739 +	}
  1.6740 +	default:
  1.6741 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
  1.6742 +		error = ENOPROTOOPT;
  1.6743 +		break;
  1.6744 +	} /* end switch (opt) */
  1.6745 +	return (error);
  1.6746 +}
  1.6747 +
  1.6748 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
  1.6749 +int
  1.6750 +sctp_ctloutput(struct socket *so, struct sockopt *sopt)
  1.6751 +{
  1.6752 +	void *optval = NULL;
  1.6753 +	size_t optsize = 0;
  1.6754 +	void *p;
  1.6755 +	int error = 0;
  1.6756 +
  1.6757 +	if (sopt->sopt_level != IPPROTO_SCTP) {
  1.6758 +		/* wrong proto level... send back up to IP */
  1.6759 +#ifdef INET6
  1.6760 +		if (INP_CHECK_SOCKAF(so, AF_INET6))
  1.6761 +			error = ip6_ctloutput(so, sopt);
  1.6762 +#endif				/* INET6 */
  1.6763 +#if defined(INET) && defined(INET6)
  1.6764 +		else
  1.6765 +#endif
  1.6766 +#ifdef INET
  1.6767 +			error = ip_ctloutput(so, sopt);
  1.6768 +#endif
  1.6769 +		return (error);
  1.6770 +	}
  1.6771 +	optsize = sopt->sopt_valsize;
  1.6772 +	if (optsize) {
  1.6773 +		SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT);
  1.6774 +		if (optval == NULL) {
  1.6775 +			SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS);
  1.6776 +			return (ENOBUFS);
  1.6777 +		}
  1.6778 +		error = sooptcopyin(sopt, optval, optsize, optsize);
  1.6779 +		if (error) {
  1.6780 +			SCTP_FREE(optval, SCTP_M_SOCKOPT);
  1.6781 +			goto out;
  1.6782 +		}
  1.6783 +	}
  1.6784 +#if (defined(__FreeBSD__) && __FreeBSD_version >= 500000) || defined(__Windows__)
  1.6785 +	p = (void *)sopt->sopt_td;
  1.6786 +#else
  1.6787 +	p = (void *)sopt->sopt_p;
  1.6788 +#endif
  1.6789 +	if (sopt->sopt_dir == SOPT_SET) {
  1.6790 +		error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p);
  1.6791 +	} else if (sopt->sopt_dir == SOPT_GET) {
  1.6792 +		error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p);
  1.6793 +	} else {
  1.6794 +		SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6795 +		error = EINVAL;
  1.6796 +	}
  1.6797 +	if ((error == 0) && (optval != NULL)) {
  1.6798 +		error = sooptcopyout(sopt, optval, optsize);
  1.6799 +		SCTP_FREE(optval, SCTP_M_SOCKOPT);
  1.6800 +	} else if (optval != NULL) {
  1.6801 +		SCTP_FREE(optval, SCTP_M_SOCKOPT);
  1.6802 +	}
  1.6803 +out:
  1.6804 +	return (error);
  1.6805 +}
  1.6806 +#endif
  1.6807 +
  1.6808 +#ifdef INET
  1.6809 +#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
  1.6810 +static int
  1.6811 +sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
  1.6812 +{
  1.6813 +#else
  1.6814 +#if defined(__FreeBSD__) || defined(__APPLE__)
  1.6815 +static int
  1.6816 +sctp_connect(struct socket *so, struct sockaddr *addr, struct proc *p)
  1.6817 +{
  1.6818 +#elif defined(__Panda__) || defined(__Userspace__)
  1.6819 +int
  1.6820 +sctp_connect(struct socket *so, struct sockaddr *addr)
  1.6821 +{
  1.6822 +	void *p = NULL;
  1.6823 +#elif defined(__Windows__)
  1.6824 +static int
  1.6825 +sctp_connect(struct socket *so, struct sockaddr *addr, PKTHREAD p)
  1.6826 +{
  1.6827 +#else
  1.6828 +static int
  1.6829 +sctp_connect(struct socket *so, struct mbuf *nam, struct proc *p)
  1.6830 +{
  1.6831 +	struct sockaddr *addr = mtod(nam, struct sockaddr *);
  1.6832 +
  1.6833 +#endif
  1.6834 +#endif
  1.6835 +#ifdef SCTP_MVRF
  1.6836 +	int i, fnd = 0;
  1.6837 +#endif
  1.6838 +	int error = 0;
  1.6839 +	int create_lock_on = 0;
  1.6840 +	uint32_t vrf_id;
  1.6841 +	struct sctp_inpcb *inp;
  1.6842 +	struct sctp_tcb *stcb = NULL;
  1.6843 +
  1.6844 +	inp = (struct sctp_inpcb *)so->so_pcb;
  1.6845 +	if (inp == NULL) {
  1.6846 +		/* I made the same as TCP since we are not setup? */
  1.6847 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6848 +		return (ECONNRESET);
  1.6849 +	}
  1.6850 +	if (addr == NULL) {
  1.6851 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6852 +		return EINVAL;
  1.6853 +	}
  1.6854 +
  1.6855 +#if defined(__Userspace__)
  1.6856 +        /* TODO __Userspace__ falls into this code for IPv6 stuff at the moment... */
  1.6857 +#endif
  1.6858 +#if !defined(__Windows__) && !defined(__Userspace_os_Linux) && !defined(__Userspace_os_Windows)
  1.6859 +	switch (addr->sa_family) {
  1.6860 +#ifdef INET6
  1.6861 +	case AF_INET6:
  1.6862 +	{
  1.6863 +#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
  1.6864 +		struct sockaddr_in6 *sin6p;
  1.6865 +
  1.6866 +#endif
  1.6867 +		if (addr->sa_len != sizeof(struct sockaddr_in6)) {
  1.6868 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6869 +			return (EINVAL);
  1.6870 +		}
  1.6871 +#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
  1.6872 +		sin6p = (struct sockaddr_in6 *)addr;
  1.6873 +		if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6p->sin6_addr)) != 0) {
  1.6874 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.6875 +			return (error);
  1.6876 +		}
  1.6877 +#endif
  1.6878 +		break;
  1.6879 +	}
  1.6880 +#endif
  1.6881 +#ifdef INET
  1.6882 +	case AF_INET:
  1.6883 +	{
  1.6884 +#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
  1.6885 +		struct sockaddr_in *sinp;
  1.6886 +
  1.6887 +#endif
  1.6888 +#if !defined(__Userspace_os_Windows)
  1.6889 +		if (addr->sa_len != sizeof(struct sockaddr_in)) {
  1.6890 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6891 +			return (EINVAL);
  1.6892 +		}
  1.6893 +#endif
  1.6894 +#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
  1.6895 +		sinp = (struct sockaddr_in *)addr;
  1.6896 +		if (p != NULL && (error = prison_remote_ip4(p->td_ucred, &sinp->sin_addr)) != 0) {
  1.6897 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
  1.6898 +			return (error);
  1.6899 +		}
  1.6900 +#endif
  1.6901 +		break;
  1.6902 +	}
  1.6903 +#endif
  1.6904 +	default:
  1.6905 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
  1.6906 + 		return (EAFNOSUPPORT);
  1.6907 +	}
  1.6908 +#endif
  1.6909 +	SCTP_INP_INCR_REF(inp);
  1.6910 +	SCTP_ASOC_CREATE_LOCK(inp);
  1.6911 +	create_lock_on = 1;
  1.6912 +
  1.6913 +
  1.6914 +	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
  1.6915 +	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
  1.6916 +		/* Should I really unlock ? */
  1.6917 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
  1.6918 +	        error = EFAULT;
  1.6919 +		goto out_now;
  1.6920 +	}
  1.6921 +#ifdef INET6
  1.6922 +	if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
  1.6923 +	    (addr->sa_family == AF_INET6)) {
  1.6924 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6925 +		error = EINVAL;
  1.6926 +		goto out_now;
  1.6927 +	}
  1.6928 +#endif
  1.6929 +#if defined(__Userspace__)
  1.6930 +	if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) &&
  1.6931 +	    (addr->sa_family != AF_CONN)) {
  1.6932 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6933 +		error = EINVAL;
  1.6934 +		goto out_now;
  1.6935 +	}
  1.6936 +#endif
  1.6937 +	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
  1.6938 +	    SCTP_PCB_FLAGS_UNBOUND) {
  1.6939 +		/* Bind a ephemeral port */
  1.6940 +		error = sctp_inpcb_bind(so, NULL, NULL, p);
  1.6941 +		if (error) {
  1.6942 +			goto out_now;
  1.6943 +		}
  1.6944 +	}
  1.6945 +	/* Now do we connect? */
  1.6946 +	if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) &&
  1.6947 +	    (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) {
  1.6948 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6949 +		error = EINVAL;
  1.6950 +		goto out_now;
  1.6951 +	}
  1.6952 +	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
  1.6953 +	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
  1.6954 +		/* We are already connected AND the TCP model */
  1.6955 +		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
  1.6956 +		error = EADDRINUSE;
  1.6957 +		goto out_now;
  1.6958 +	}
  1.6959 +	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
  1.6960 +		SCTP_INP_RLOCK(inp);
  1.6961 +		stcb = LIST_FIRST(&inp->sctp_asoc_list);
  1.6962 +		SCTP_INP_RUNLOCK(inp);
  1.6963 +	} else {
  1.6964 +		/* We increment here since sctp_findassociation_ep_addr() will
  1.6965 +		 * do a decrement if it finds the stcb as long as the locked
  1.6966 +		 * tcb (last argument) is NOT a TCB.. aka NULL.
  1.6967 +		 */
  1.6968 +		SCTP_INP_INCR_REF(inp);
  1.6969 +		stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
  1.6970 +		if (stcb == NULL) {
  1.6971 +			SCTP_INP_DECR_REF(inp);
  1.6972 +		} else {
  1.6973 +			SCTP_TCB_UNLOCK(stcb);
  1.6974 +		}
  1.6975 +	}
  1.6976 +	if (stcb != NULL) {
  1.6977 +		/* Already have or am bring up an association */
  1.6978 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
  1.6979 +		error = EALREADY;
  1.6980 +		goto out_now;
  1.6981 +	}
  1.6982 +
  1.6983 +	vrf_id = inp->def_vrf_id;
  1.6984 +#ifdef SCTP_MVRF
  1.6985 +	for (i = 0; i < inp->num_vrfs; i++) {
  1.6986 +		if (vrf_id == inp->m_vrf_ids[i]) {
  1.6987 +			fnd = 1;
  1.6988 +			break;
  1.6989 +		}
  1.6990 +	}
  1.6991 +	if (!fnd) {
  1.6992 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.6993 +		error = EINVAL;
  1.6994 +		goto out_now;
  1.6995 +	}
  1.6996 +#endif
  1.6997 +	/* We are GOOD to go */
  1.6998 +	stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p);
  1.6999 +	if (stcb == NULL) {
  1.7000 +		/* Gak! no memory */
  1.7001 +		goto out_now;
  1.7002 +	}
  1.7003 +	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
  1.7004 +		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
  1.7005 +		/* Set the connected flag so we can queue data */
  1.7006 +		soisconnecting(so);
  1.7007 +	}
  1.7008 +	SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
  1.7009 +	(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
  1.7010 +
  1.7011 +	/* initialize authentication parameters for the assoc */
  1.7012 +	sctp_initialize_auth_params(inp, stcb);
  1.7013 +
  1.7014 +	sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
  1.7015 +	SCTP_TCB_UNLOCK(stcb);
  1.7016 + out_now:
  1.7017 +	if (create_lock_on) {
  1.7018 +		SCTP_ASOC_CREATE_UNLOCK(inp);
  1.7019 +	}
  1.7020 +
  1.7021 +	SCTP_INP_DECR_REF(inp);
  1.7022 +	return (error);
  1.7023 +}
  1.7024 +#endif
  1.7025 +
  1.7026 +#if defined(__Userspace__)
  1.7027 +int
  1.7028 +sctpconn_connect(struct socket *so, struct sockaddr *addr)
  1.7029 +{
  1.7030 +#ifdef SCTP_MVRF
  1.7031 +	int i, fnd = 0;
  1.7032 +#endif
  1.7033 +	void *p = NULL;
  1.7034 +	int error = 0;
  1.7035 +	int create_lock_on = 0;
  1.7036 +	uint32_t vrf_id;
  1.7037 +	struct sctp_inpcb *inp;
  1.7038 +	struct sctp_tcb *stcb = NULL;
  1.7039 +
  1.7040 +	inp = (struct sctp_inpcb *)so->so_pcb;
  1.7041 +	if (inp == NULL) {
  1.7042 +		/* I made the same as TCP since we are not setup? */
  1.7043 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.7044 +		return (ECONNRESET);
  1.7045 +	}
  1.7046 +	if (addr == NULL) {
  1.7047 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.7048 +		return EINVAL;
  1.7049 +	}
  1.7050 +	switch (addr->sa_family) {
  1.7051 +#ifdef INET
  1.7052 +	case AF_INET:
  1.7053 +#ifdef HAVE_SA_LEN
  1.7054 +		if (addr->sa_len != sizeof(struct sockaddr_in)) {
  1.7055 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.7056 +			return (EINVAL);
  1.7057 +		}
  1.7058 +#endif
  1.7059 +		break;
  1.7060 +#endif
  1.7061 +#ifdef INET6
  1.7062 +	case AF_INET6:
  1.7063 +#ifdef HAVE_SA_LEN
  1.7064 +		if (addr->sa_len != sizeof(struct sockaddr_in6)) {
  1.7065 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.7066 +			return (EINVAL);
  1.7067 +		}
  1.7068 +#endif
  1.7069 +		break;
  1.7070 +#endif
  1.7071 +	case AF_CONN:
  1.7072 +#ifdef HAVE_SA_LEN
  1.7073 +		if (addr->sa_len != sizeof(struct sockaddr_conn)) {
  1.7074 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.7075 +			return (EINVAL);
  1.7076 +		}
  1.7077 +#endif
  1.7078 +		break;
  1.7079 +	default:
  1.7080 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
  1.7081 + 		return (EAFNOSUPPORT);
  1.7082 +	}
  1.7083 +	SCTP_INP_INCR_REF(inp);
  1.7084 +	SCTP_ASOC_CREATE_LOCK(inp);
  1.7085 +	create_lock_on = 1;
  1.7086 +
  1.7087 +
  1.7088 +	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
  1.7089 +	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
  1.7090 +		/* Should I really unlock ? */
  1.7091 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
  1.7092 +	        error = EFAULT;
  1.7093 +		goto out_now;
  1.7094 +	}
  1.7095 +#ifdef INET6
  1.7096 +	if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
  1.7097 +	    (addr->sa_family == AF_INET6)) {
  1.7098 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.7099 +		error = EINVAL;
  1.7100 +		goto out_now;
  1.7101 +	}
  1.7102 +#endif
  1.7103 +	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == SCTP_PCB_FLAGS_UNBOUND) {
  1.7104 +		/* Bind a ephemeral port */
  1.7105 +		error = sctp_inpcb_bind(so, NULL, NULL, p);
  1.7106 +		if (error) {
  1.7107 +			goto out_now;
  1.7108 +		}
  1.7109 +	}
  1.7110 +	/* Now do we connect? */
  1.7111 +	if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) &&
  1.7112 +	    (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) {
  1.7113 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.7114 +		error = EINVAL;
  1.7115 +		goto out_now;
  1.7116 +	}
  1.7117 +	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
  1.7118 +	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
  1.7119 +		/* We are already connected AND the TCP model */
  1.7120 +		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
  1.7121 +		error = EADDRINUSE;
  1.7122 +		goto out_now;
  1.7123 +	}
  1.7124 +	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
  1.7125 +		SCTP_INP_RLOCK(inp);
  1.7126 +		stcb = LIST_FIRST(&inp->sctp_asoc_list);
  1.7127 +		SCTP_INP_RUNLOCK(inp);
  1.7128 +	} else {
  1.7129 +		/* We increment here since sctp_findassociation_ep_addr() will
  1.7130 +		 * do a decrement if it finds the stcb as long as the locked
  1.7131 +		 * tcb (last argument) is NOT a TCB.. aka NULL.
  1.7132 +		 */
  1.7133 +		SCTP_INP_INCR_REF(inp);
  1.7134 +		stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
  1.7135 +		if (stcb == NULL) {
  1.7136 +			SCTP_INP_DECR_REF(inp);
  1.7137 +		} else {
  1.7138 +			SCTP_TCB_UNLOCK(stcb);
  1.7139 +		}
  1.7140 +	}
  1.7141 +	if (stcb != NULL) {
  1.7142 +		/* Already have or am bring up an association */
  1.7143 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
  1.7144 +		error = EALREADY;
  1.7145 +		goto out_now;
  1.7146 +	}
  1.7147 +
  1.7148 +	vrf_id = inp->def_vrf_id;
  1.7149 +#ifdef SCTP_MVRF
  1.7150 +	for (i = 0; i < inp->num_vrfs; i++) {
  1.7151 +		if (vrf_id == inp->m_vrf_ids[i]) {
  1.7152 +			fnd = 1;
  1.7153 +			break;
  1.7154 +		}
  1.7155 +	}
  1.7156 +	if (!fnd) {
  1.7157 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.7158 +		error = EINVAL;
  1.7159 +		goto out_now;
  1.7160 +	}
  1.7161 +#endif
  1.7162 +	/* We are GOOD to go */
  1.7163 +	stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p);
  1.7164 +	if (stcb == NULL) {
  1.7165 +		/* Gak! no memory */
  1.7166 +		goto out_now;
  1.7167 +	}
  1.7168 +	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
  1.7169 +		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
  1.7170 +		/* Set the connected flag so we can queue data */
  1.7171 +		soisconnecting(so);
  1.7172 +	}
  1.7173 +	SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
  1.7174 +	(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
  1.7175 +
  1.7176 +	/* initialize authentication parameters for the assoc */
  1.7177 +	sctp_initialize_auth_params(inp, stcb);
  1.7178 +
  1.7179 +	sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
  1.7180 +	SCTP_TCB_UNLOCK(stcb);
  1.7181 + out_now:
  1.7182 +	if (create_lock_on) {
  1.7183 +		SCTP_ASOC_CREATE_UNLOCK(inp);
  1.7184 +	}
  1.7185 +
  1.7186 +	SCTP_INP_DECR_REF(inp);
  1.7187 +	return (error);
  1.7188 +}
  1.7189 +#endif
  1.7190 +int
  1.7191 +#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
  1.7192 +#if __FreeBSD_version >= 700000
  1.7193 +sctp_listen(struct socket *so, int backlog, struct thread *p)
  1.7194 +#else
  1.7195 +sctp_listen(struct socket *so, struct thread *p)
  1.7196 +#endif
  1.7197 +#elif defined(__Windows__)
  1.7198 +sctp_listen(struct socket *so, int backlog, PKTHREAD p)
  1.7199 +#elif defined(__Userspace__)
  1.7200 +sctp_listen(struct socket *so, int backlog, struct proc *p)
  1.7201 +#else
  1.7202 +sctp_listen(struct socket *so, struct proc *p)
  1.7203 +#endif
  1.7204 +{
  1.7205 +	/*
  1.7206 +	 * Note this module depends on the protocol processing being called
  1.7207 +	 * AFTER any socket level flags and backlog are applied to the
  1.7208 +	 * socket. The traditional way that the socket flags are applied is
  1.7209 +	 * AFTER protocol processing. We have made a change to the
  1.7210 +	 * sys/kern/uipc_socket.c module to reverse this but this MUST be in
  1.7211 +	 * place if the socket API for SCTP is to work properly.
  1.7212 +	 */
  1.7213 +
  1.7214 +	int error = 0;
  1.7215 +	struct sctp_inpcb *inp;
  1.7216 +
  1.7217 +	inp = (struct sctp_inpcb *)so->so_pcb;
  1.7218 +	if (inp == NULL) {
  1.7219 +		/* I made the same as TCP since we are not setup? */
  1.7220 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.7221 +		return (ECONNRESET);
  1.7222 +	}
  1.7223 +	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) {
  1.7224 +		/* See if we have a listener */
  1.7225 +		struct sctp_inpcb *tinp;
  1.7226 +		union sctp_sockstore store, *sp;
  1.7227 +
  1.7228 +		sp = &store;
  1.7229 +		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
  1.7230 +			/* not bound all */
  1.7231 +			struct sctp_laddr *laddr;
  1.7232 +
  1.7233 +			LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
  1.7234 +				memcpy(&store, &laddr->ifa->address, sizeof(store));
  1.7235 +				switch (sp->sa.sa_family) {
  1.7236 +#ifdef INET
  1.7237 +				case AF_INET:
  1.7238 +					sp->sin.sin_port = inp->sctp_lport;
  1.7239 +					break;
  1.7240 +#endif
  1.7241 +#ifdef INET6
  1.7242 +				case AF_INET6:
  1.7243 +					sp->sin6.sin6_port = inp->sctp_lport;
  1.7244 +					break;
  1.7245 +#endif
  1.7246 +#if defined(__Userspace__)
  1.7247 +				case AF_CONN:
  1.7248 +					sp->sconn.sconn_port = inp->sctp_lport;
  1.7249 +					break;
  1.7250 +#endif
  1.7251 +				default:
  1.7252 +					break;
  1.7253 +				}
  1.7254 +				tinp = sctp_pcb_findep(&sp->sa, 0, 0, inp->def_vrf_id);
  1.7255 +				if (tinp && (tinp != inp) &&
  1.7256 +				    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
  1.7257 +				    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
  1.7258 +				    (tinp->sctp_socket->so_qlimit)) {
  1.7259 +					/* we have a listener already and its not this inp. */
  1.7260 +					SCTP_INP_DECR_REF(tinp);
  1.7261 +					return (EADDRINUSE);
  1.7262 +				} else if (tinp) {
  1.7263 +					SCTP_INP_DECR_REF(tinp);
  1.7264 +				}
  1.7265 +			}
  1.7266 +		} else {
  1.7267 +			/* Setup a local addr bound all */
  1.7268 +			memset(&store, 0, sizeof(store));
  1.7269 +			switch (sp->sa.sa_family) {
  1.7270 +#ifdef INET
  1.7271 +			case AF_INET:
  1.7272 +				store.sin.sin_port = inp->sctp_lport;
  1.7273 +				break;
  1.7274 +#endif
  1.7275 +#ifdef INET6
  1.7276 +			case AF_INET6:
  1.7277 +				sp->sin6.sin6_port = inp->sctp_lport;
  1.7278 +				break;
  1.7279 +#endif
  1.7280 +#if defined(__Userspace__)
  1.7281 +			case AF_CONN:
  1.7282 +				sp->sconn.sconn_port = inp->sctp_lport;
  1.7283 +				break;
  1.7284 +#endif
  1.7285 +			default:
  1.7286 +				break;
  1.7287 +			}
  1.7288 +#ifdef INET6
  1.7289 +			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
  1.7290 +				store.sa.sa_family = AF_INET6;
  1.7291 +#ifdef HAVE_SA_LEN
  1.7292 +				store.sa.sa_len = sizeof(struct sockaddr_in6);
  1.7293 +#endif
  1.7294 +			}
  1.7295 +#endif
  1.7296 +#ifdef INET
  1.7297 +			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
  1.7298 +				store.sa.sa_family = AF_INET;
  1.7299 +#ifdef HAVE_SA_LEN
  1.7300 +				store.sa.sa_len = sizeof(struct sockaddr_in);
  1.7301 +#endif
  1.7302 +			}
  1.7303 +#endif
  1.7304 +			tinp = sctp_pcb_findep(&sp->sa, 0, 0, inp->def_vrf_id);
  1.7305 +			if (tinp && (tinp != inp) &&
  1.7306 +			    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
  1.7307 +			    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
  1.7308 +			    (tinp->sctp_socket->so_qlimit)) {
  1.7309 +				/* we have a listener already and its not this inp. */
  1.7310 +				SCTP_INP_DECR_REF(tinp);
  1.7311 +				return (EADDRINUSE);
  1.7312 +			} else if (tinp) {
  1.7313 +				SCTP_INP_DECR_REF(inp);
  1.7314 +			}
  1.7315 +		}
  1.7316 +	}
  1.7317 +	SCTP_INP_RLOCK(inp);
  1.7318 +#ifdef SCTP_LOCK_LOGGING
  1.7319 +	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) {
  1.7320 +		sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK);
  1.7321 +	}
  1.7322 +#endif
  1.7323 +	SOCK_LOCK(so);
  1.7324 +#if (defined(__FreeBSD__) && __FreeBSD_version > 500000) || defined(__Userspace__)
  1.7325 +	error = solisten_proto_check(so);
  1.7326 +	if (error) {
  1.7327 +		SOCK_UNLOCK(so);
  1.7328 +		SCTP_INP_RUNLOCK(inp);
  1.7329 +		return (error);
  1.7330 +	}
  1.7331 +#endif
  1.7332 +	if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) &&
  1.7333 +	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
  1.7334 +		/* The unlucky case
  1.7335 +		 * - We are in the tcp pool with this guy.
  1.7336 +		 * - Someone else is in the main inp slot.
  1.7337 +		 * - We must move this guy (the listener) to the main slot
  1.7338 +		 * - We must then move the guy that was listener to the TCP Pool.
  1.7339 +		 */
  1.7340 +		if (sctp_swap_inpcb_for_listen(inp)) {
  1.7341 +			goto in_use;
  1.7342 +		}
  1.7343 +	}
  1.7344 +
  1.7345 +	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
  1.7346 +	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
  1.7347 +		/* We are already connected AND the TCP model */
  1.7348 +	in_use:
  1.7349 +		SCTP_INP_RUNLOCK(inp);
  1.7350 +		SOCK_UNLOCK(so);
  1.7351 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
  1.7352 +		return (EADDRINUSE);
  1.7353 +	}
  1.7354 +	SCTP_INP_RUNLOCK(inp);
  1.7355 +	if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
  1.7356 +		/* We must do a bind. */
  1.7357 +		SOCK_UNLOCK(so);
  1.7358 +		if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) {
  1.7359 +			/* bind error, probably perm */
  1.7360 +			return (error);
  1.7361 +		}
  1.7362 +		SOCK_LOCK(so);
  1.7363 +	}
  1.7364 +#if (defined(__FreeBSD__) && __FreeBSD_version > 500000) || defined(__Windows__) || defined(__Userspace__)
  1.7365 +#if __FreeBSD_version >= 700000 || defined(__Windows__) || defined(__Userspace__)
  1.7366 +	/* It appears for 7.0 and on, we must always call this. */
  1.7367 +	solisten_proto(so, backlog);
  1.7368 +#else
  1.7369 +	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) == 0) {
  1.7370 +		solisten_proto(so);
  1.7371 +	}
  1.7372 +#endif
  1.7373 +#endif
  1.7374 +	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
  1.7375 +		/* remove the ACCEPTCONN flag for one-to-many sockets */
  1.7376 +#if defined(__Userspace__)
  1.7377 +		so->so_options &= ~SCTP_SO_ACCEPTCONN;
  1.7378 +#else
  1.7379 +		so->so_options &= ~SO_ACCEPTCONN;
  1.7380 +#endif
  1.7381 +	}
  1.7382 +
  1.7383 +#if __FreeBSD_version >= 700000 || defined(__Windows__) || defined(__Userspace__)
  1.7384 +	if (backlog == 0) {
  1.7385 +		/* turning off listen */
  1.7386 +#if defined(__Userspace__)
  1.7387 +		so->so_options &= ~SCTP_SO_ACCEPTCONN;
  1.7388 +#else
  1.7389 +		so->so_options &= ~SO_ACCEPTCONN;
  1.7390 +#endif
  1.7391 +	}
  1.7392 +#endif
  1.7393 +	SOCK_UNLOCK(so);
  1.7394 +	return (error);
  1.7395 +}
  1.7396 +
  1.7397 +static int sctp_defered_wakeup_cnt = 0;
  1.7398 +
  1.7399 +int
  1.7400 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
  1.7401 +sctp_accept(struct socket *so, struct sockaddr **addr)
  1.7402 +{
  1.7403 +#elif defined(__Panda__)
  1.7404 +sctp_accept(struct socket *so, struct sockaddr *addr, int *namelen,
  1.7405 +	    void *accept_info, int *accept_info_len)
  1.7406 +{
  1.7407 +#else
  1.7408 +sctp_accept(struct socket *so, struct mbuf *nam)
  1.7409 +{
  1.7410 +	struct sockaddr *addr = mtod(nam, struct sockaddr *);
  1.7411 +#endif
  1.7412 +	struct sctp_tcb *stcb;
  1.7413 +	struct sctp_inpcb *inp;
  1.7414 +	union sctp_sockstore store;
  1.7415 +#ifdef INET6
  1.7416 +#ifdef SCTP_KAME
  1.7417 +	int error;
  1.7418 +#endif /* SCTP_KAME */
  1.7419 +#endif
  1.7420 +	inp = (struct sctp_inpcb *)so->so_pcb;
  1.7421 +
  1.7422 +	if (inp == NULL) {
  1.7423 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.7424 +		return (ECONNRESET);
  1.7425 +	}
  1.7426 +	SCTP_INP_RLOCK(inp);
  1.7427 +	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
  1.7428 +		SCTP_INP_RUNLOCK(inp);
  1.7429 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
  1.7430 +		return (EOPNOTSUPP);
  1.7431 +	}
  1.7432 +	if (so->so_state & SS_ISDISCONNECTED) {
  1.7433 +		SCTP_INP_RUNLOCK(inp);
  1.7434 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED);
  1.7435 +		return (ECONNABORTED);
  1.7436 +	}
  1.7437 +	stcb = LIST_FIRST(&inp->sctp_asoc_list);
  1.7438 +	if (stcb == NULL) {
  1.7439 +		SCTP_INP_RUNLOCK(inp);
  1.7440 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.7441 +		return (ECONNRESET);
  1.7442 +	}
  1.7443 +	SCTP_TCB_LOCK(stcb);
  1.7444 +	SCTP_INP_RUNLOCK(inp);
  1.7445 +	store = stcb->asoc.primary_destination->ro._l_addr;
  1.7446 +	stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE;
  1.7447 +	SCTP_TCB_UNLOCK(stcb);
  1.7448 +	switch (store.sa.sa_family) {
  1.7449 +#ifdef INET
  1.7450 +	case AF_INET:
  1.7451 +	{
  1.7452 +		struct sockaddr_in *sin;
  1.7453 +
  1.7454 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
  1.7455 +		SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
  1.7456 +		if (sin == NULL)
  1.7457 +			return (ENOMEM);
  1.7458 +#else
  1.7459 +		sin = (struct sockaddr_in *)addr;
  1.7460 +		bzero((caddr_t)sin, sizeof(*sin));
  1.7461 +#endif
  1.7462 +		sin->sin_family = AF_INET;
  1.7463 +#ifdef HAVE_SIN_LEN
  1.7464 +		sin->sin_len = sizeof(*sin);
  1.7465 +#endif
  1.7466 +		sin->sin_port = store.sin.sin_port;
  1.7467 +		sin->sin_addr = store.sin.sin_addr;
  1.7468 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
  1.7469 +		*addr = (struct sockaddr *)sin;
  1.7470 +#elif !defined(__Panda__)
  1.7471 +		SCTP_BUF_LEN(nam) = sizeof(*sin);
  1.7472 +#endif
  1.7473 +		break;
  1.7474 +	}
  1.7475 +#endif
  1.7476 +#ifdef INET6
  1.7477 +	case AF_INET6:
  1.7478 +	{
  1.7479 +		struct sockaddr_in6 *sin6;
  1.7480 +
  1.7481 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
  1.7482 +		SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
  1.7483 +		if (sin6 == NULL)
  1.7484 +			return (ENOMEM);
  1.7485 +#else
  1.7486 +		sin6 = (struct sockaddr_in6 *)addr;
  1.7487 +		bzero((caddr_t)sin6, sizeof(*sin6));
  1.7488 +#endif
  1.7489 +		sin6->sin6_family = AF_INET6;
  1.7490 +#ifdef HAVE_SIN6_LEN
  1.7491 +		sin6->sin6_len = sizeof(*sin6);
  1.7492 +#endif
  1.7493 +		sin6->sin6_port = store.sin6.sin6_port;
  1.7494 +		sin6->sin6_addr = store.sin6.sin6_addr;
  1.7495 +#if defined(SCTP_EMBEDDED_V6_SCOPE)
  1.7496 +#ifdef SCTP_KAME
  1.7497 +		if ((error = sa6_recoverscope(sin6)) != 0) {
  1.7498 +			SCTP_FREE_SONAME(sin6);
  1.7499 +			return (error);
  1.7500 +		}
  1.7501 +#else
  1.7502 +		if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
  1.7503 +			/*
  1.7504 +			 * sin6->sin6_scope_id =
  1.7505 +			 * ntohs(sin6->sin6_addr.s6_addr16[1]);
  1.7506 +			 */
  1.7507 +			in6_recoverscope(sin6, &sin6->sin6_addr, NULL);	/* skip ifp check */
  1.7508 +		else
  1.7509 +			sin6->sin6_scope_id = 0;	/* XXX */
  1.7510 +#endif /* SCTP_KAME */
  1.7511 +#endif /* SCTP_EMBEDDED_V6_SCOPE */
  1.7512 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
  1.7513 +		*addr = (struct sockaddr *)sin6;
  1.7514 +#elif !defined(__Panda__)
  1.7515 +		SCTP_BUF_LEN(nam) = sizeof(*sin6);
  1.7516 +#endif
  1.7517 +		break;
  1.7518 +	}
  1.7519 +#endif
  1.7520 +#if defined(__Userspace__)
  1.7521 +	case AF_CONN:
  1.7522 +	{
  1.7523 +		struct sockaddr_conn *sconn;
  1.7524 +
  1.7525 +		SCTP_MALLOC_SONAME(sconn, struct sockaddr_conn *, sizeof(struct sockaddr_conn));
  1.7526 +		if (sconn == NULL) {
  1.7527 +			return (ENOMEM);
  1.7528 +		}
  1.7529 +		sconn->sconn_family = AF_CONN;
  1.7530 +#ifdef HAVE_SCONN_LEN
  1.7531 +		sconn->sconn_len = sizeof(struct sockaddr_conn);
  1.7532 +#endif
  1.7533 +		sconn->sconn_port = store.sconn.sconn_port;
  1.7534 +		sconn->sconn_addr = store.sconn.sconn_addr;
  1.7535 +		*addr = (struct sockaddr *)sconn;
  1.7536 +		break;
  1.7537 +	}
  1.7538 +#endif
  1.7539 +	default:
  1.7540 +		/* TSNH */
  1.7541 +		break;
  1.7542 +	}
  1.7543 +	/* Wake any delayed sleep action */
  1.7544 +	if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) {
  1.7545 +		SCTP_INP_WLOCK(inp);
  1.7546 +		inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE;
  1.7547 +		if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) {
  1.7548 +			inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT;
  1.7549 +			SCTP_INP_WUNLOCK(inp);
  1.7550 +			SOCKBUF_LOCK(&inp->sctp_socket->so_snd);
  1.7551 +			if (sowriteable(inp->sctp_socket)) {
  1.7552 +#if defined(__Userspace__)
  1.7553 +                            /*__Userspace__ calling sowwakup_locked because of SOCKBUF_LOCK above. */
  1.7554 +#endif
  1.7555 +#if defined(__FreeBSD__) || defined(__Windows__) || defined(__Userspace__)
  1.7556 +				sowwakeup_locked(inp->sctp_socket);
  1.7557 +#else
  1.7558 +#if defined(__APPLE__)
  1.7559 +				/* socket is locked */
  1.7560 +#endif
  1.7561 +				sowwakeup(inp->sctp_socket);
  1.7562 +#endif
  1.7563 +			} else {
  1.7564 +				SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd);
  1.7565 +			}
  1.7566 +			SCTP_INP_WLOCK(inp);
  1.7567 +		}
  1.7568 +		if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) {
  1.7569 +			inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT;
  1.7570 +			SCTP_INP_WUNLOCK(inp);
  1.7571 +			SOCKBUF_LOCK(&inp->sctp_socket->so_rcv);
  1.7572 +			if (soreadable(inp->sctp_socket)) {
  1.7573 +				sctp_defered_wakeup_cnt++;
  1.7574 +#if defined(__Userspace__)
  1.7575 +                                /*__Userspace__ calling sorwakup_locked because of SOCKBUF_LOCK above */
  1.7576 +#endif
  1.7577 +#if defined(__FreeBSD__) || defined(__Windows__) || defined(__Userspace__)
  1.7578 +				sorwakeup_locked(inp->sctp_socket);
  1.7579 +#else
  1.7580 +#if defined(__APPLE__)
  1.7581 +				/* socket is locked */
  1.7582 +#endif
  1.7583 +				sorwakeup(inp->sctp_socket);
  1.7584 +#endif
  1.7585 +			} else {
  1.7586 +				SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv);
  1.7587 +			}
  1.7588 +			SCTP_INP_WLOCK(inp);
  1.7589 +		}
  1.7590 +		SCTP_INP_WUNLOCK(inp);
  1.7591 +	}
  1.7592 +	if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
  1.7593 +		SCTP_TCB_LOCK(stcb);
  1.7594 +		sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_7);
  1.7595 +	}
  1.7596 +	return (0);
  1.7597 +}
  1.7598 +
  1.7599 +#ifdef INET
  1.7600 +int
  1.7601 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
  1.7602 +sctp_ingetaddr(struct socket *so, struct sockaddr **addr)
  1.7603 +{
  1.7604 +	struct sockaddr_in *sin;
  1.7605 +#elif defined(__Panda__)
  1.7606 +sctp_ingetaddr(struct socket *so, struct sockaddr *addr)
  1.7607 +{
  1.7608 +	struct sockaddr_in *sin = (struct sockaddr_in *)addr;
  1.7609 +#else
  1.7610 +sctp_ingetaddr(struct socket *so, struct mbuf *nam)
  1.7611 +{
  1.7612 +	struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
  1.7613 +#endif
  1.7614 +	uint32_t vrf_id;
  1.7615 +	struct sctp_inpcb *inp;
  1.7616 +	struct sctp_ifa *sctp_ifa;
  1.7617 +
  1.7618 +	/*
  1.7619 +	 * Do the malloc first in case it blocks.
  1.7620 +	 */
  1.7621 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
  1.7622 +	SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
  1.7623 +	if (sin == NULL)
  1.7624 +		return (ENOMEM);
  1.7625 +#elif defined(__Panda__)
  1.7626 +	bzero(sin, sizeof(*sin));
  1.7627 +#else
  1.7628 +	SCTP_BUF_LEN(nam) = sizeof(*sin);
  1.7629 +	memset(sin, 0, sizeof(*sin));
  1.7630 +#endif
  1.7631 +	sin->sin_family = AF_INET;
  1.7632 +#ifdef HAVE_SIN_LEN
  1.7633 +	sin->sin_len = sizeof(*sin);
  1.7634 +#endif
  1.7635 +	inp = (struct sctp_inpcb *)so->so_pcb;
  1.7636 +	if (!inp) {
  1.7637 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
  1.7638 +		SCTP_FREE_SONAME(sin);
  1.7639 +#endif
  1.7640 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.7641 +		return (ECONNRESET);
  1.7642 +	}
  1.7643 +	SCTP_INP_RLOCK(inp);
  1.7644 +	sin->sin_port = inp->sctp_lport;
  1.7645 +	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
  1.7646 +		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
  1.7647 +			struct sctp_tcb *stcb;
  1.7648 +			struct sockaddr_in *sin_a;
  1.7649 +			struct sctp_nets *net;
  1.7650 +			int fnd;
  1.7651 +
  1.7652 +			stcb = LIST_FIRST(&inp->sctp_asoc_list);
  1.7653 +			if (stcb == NULL) {
  1.7654 +				goto notConn;
  1.7655 +			}
  1.7656 +			fnd = 0;
  1.7657 +			sin_a = NULL;
  1.7658 +			SCTP_TCB_LOCK(stcb);
  1.7659 +			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1.7660 +				sin_a = (struct sockaddr_in *)&net->ro._l_addr;
  1.7661 +				if (sin_a == NULL)
  1.7662 +					/* this will make coverity happy */
  1.7663 +					continue;
  1.7664 +
  1.7665 +				if (sin_a->sin_family == AF_INET) {
  1.7666 +					fnd = 1;
  1.7667 +					break;
  1.7668 +				}
  1.7669 +			}
  1.7670 +			if ((!fnd) || (sin_a == NULL)) {
  1.7671 +				/* punt */
  1.7672 +				SCTP_TCB_UNLOCK(stcb);
  1.7673 +				goto notConn;
  1.7674 +			}
  1.7675 +
  1.7676 +			vrf_id = inp->def_vrf_id;
  1.7677 +			sctp_ifa = sctp_source_address_selection(inp,
  1.7678 +								 stcb,
  1.7679 +								 (sctp_route_t *)&net->ro,
  1.7680 +								 net, 0, vrf_id);
  1.7681 +			if (sctp_ifa) {
  1.7682 +				sin->sin_addr = sctp_ifa->address.sin.sin_addr;
  1.7683 +				sctp_free_ifa(sctp_ifa);
  1.7684 +			}
  1.7685 +			SCTP_TCB_UNLOCK(stcb);
  1.7686 +		} else {
  1.7687 +			/* For the bound all case you get back 0 */
  1.7688 +	notConn:
  1.7689 +			sin->sin_addr.s_addr = 0;
  1.7690 +		}
  1.7691 +
  1.7692 +	} else {
  1.7693 +		/* Take the first IPv4 address in the list */
  1.7694 +		struct sctp_laddr *laddr;
  1.7695 +		int fnd = 0;
  1.7696 +
  1.7697 +		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
  1.7698 +			if (laddr->ifa->address.sa.sa_family == AF_INET) {
  1.7699 +				struct sockaddr_in *sin_a;
  1.7700 +
  1.7701 +				sin_a = (struct sockaddr_in *)&laddr->ifa->address.sa;
  1.7702 +				sin->sin_addr = sin_a->sin_addr;
  1.7703 +				fnd = 1;
  1.7704 +				break;
  1.7705 +			}
  1.7706 +		}
  1.7707 +		if (!fnd) {
  1.7708 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
  1.7709 +			SCTP_FREE_SONAME(sin);
  1.7710 +#endif
  1.7711 +			SCTP_INP_RUNLOCK(inp);
  1.7712 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
  1.7713 +			return (ENOENT);
  1.7714 +		}
  1.7715 +	}
  1.7716 +	SCTP_INP_RUNLOCK(inp);
  1.7717 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
  1.7718 +	(*addr) = (struct sockaddr *)sin;
  1.7719 +#endif
  1.7720 +	return (0);
  1.7721 +}
  1.7722 +
  1.7723 +int
  1.7724 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
  1.7725 +sctp_peeraddr(struct socket *so, struct sockaddr **addr)
  1.7726 +{
  1.7727 +	struct sockaddr_in *sin;
  1.7728 +#elif defined(__Panda__)
  1.7729 +sctp_peeraddr(struct socket *so, struct sockaddr *addr)
  1.7730 +{
  1.7731 +	struct sockaddr_in *sin = (struct sockaddr_in *)addr;
  1.7732 +#else
  1.7733 +sctp_peeraddr(struct socket *so, struct mbuf *nam)
  1.7734 +{
  1.7735 +	struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
  1.7736 +
  1.7737 +#endif
  1.7738 +	int fnd;
  1.7739 +	struct sockaddr_in *sin_a;
  1.7740 +	struct sctp_inpcb *inp;
  1.7741 +	struct sctp_tcb *stcb;
  1.7742 +	struct sctp_nets *net;
  1.7743 +
  1.7744 +	/* Do the malloc first in case it blocks. */
  1.7745 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
  1.7746 +	SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
  1.7747 +	if (sin == NULL)
  1.7748 +		return (ENOMEM);
  1.7749 +#elif defined(__Panda__)
  1.7750 +	memset(sin, 0, sizeof(*sin));
  1.7751 +#else
  1.7752 +	SCTP_BUF_LEN(nam) = sizeof(*sin);
  1.7753 +	memset(sin, 0, sizeof(*sin));
  1.7754 +#endif
  1.7755 +	sin->sin_family = AF_INET;
  1.7756 +#ifdef HAVE_SIN_LEN
  1.7757 +	sin->sin_len = sizeof(*sin);
  1.7758 +#endif
  1.7759 +
  1.7760 +	inp = (struct sctp_inpcb *)so->so_pcb;
  1.7761 +	if ((inp == NULL) ||
  1.7762 +	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
  1.7763 +		/* UDP type and listeners will drop out here */
  1.7764 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
  1.7765 +		SCTP_FREE_SONAME(sin);
  1.7766 +#endif
  1.7767 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
  1.7768 +		return (ENOTCONN);
  1.7769 +	}
  1.7770 +	SCTP_INP_RLOCK(inp);
  1.7771 +	stcb = LIST_FIRST(&inp->sctp_asoc_list);
  1.7772 +	if (stcb) {
  1.7773 +		SCTP_TCB_LOCK(stcb);
  1.7774 +	}
  1.7775 +	SCTP_INP_RUNLOCK(inp);
  1.7776 +	if (stcb == NULL) {
  1.7777 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
  1.7778 +		SCTP_FREE_SONAME(sin);
  1.7779 +#endif
  1.7780 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.7781 +		return (ECONNRESET);
  1.7782 +	}
  1.7783 +	fnd = 0;
  1.7784 +	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  1.7785 +		sin_a = (struct sockaddr_in *)&net->ro._l_addr;
  1.7786 +		if (sin_a->sin_family == AF_INET) {
  1.7787 +			fnd = 1;
  1.7788 +			sin->sin_port = stcb->rport;
  1.7789 +			sin->sin_addr = sin_a->sin_addr;
  1.7790 +			break;
  1.7791 +		}
  1.7792 +	}
  1.7793 +	SCTP_TCB_UNLOCK(stcb);
  1.7794 +	if (!fnd) {
  1.7795 +		/* No IPv4 address */
  1.7796 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
  1.7797 +		SCTP_FREE_SONAME(sin);
  1.7798 +#endif
  1.7799 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
  1.7800 +		return (ENOENT);
  1.7801 +	}
  1.7802 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
  1.7803 +	(*addr) = (struct sockaddr *)sin;
  1.7804 +#endif
  1.7805 +	return (0);
  1.7806 +}
  1.7807 +
  1.7808 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
  1.7809 +struct pr_usrreqs sctp_usrreqs = {
  1.7810 +#if defined(__FreeBSD__)
  1.7811 +	.pru_abort = sctp_abort,
  1.7812 +	.pru_accept = sctp_accept,
  1.7813 +	.pru_attach = sctp_attach,
  1.7814 +	.pru_bind = sctp_bind,
  1.7815 +	.pru_connect = sctp_connect,
  1.7816 +	.pru_control = in_control,
  1.7817 +#if __FreeBSD_version >= 690000
  1.7818 +	.pru_close = sctp_close,
  1.7819 +	.pru_detach = sctp_close,
  1.7820 +	.pru_sopoll = sopoll_generic,
  1.7821 +	.pru_flush = sctp_flush,
  1.7822 +#else
  1.7823 +	.pru_detach = sctp_detach,
  1.7824 +	.pru_sopoll = sopoll,
  1.7825 +#endif
  1.7826 +	.pru_disconnect = sctp_disconnect,
  1.7827 +	.pru_listen = sctp_listen,
  1.7828 +	.pru_peeraddr = sctp_peeraddr,
  1.7829 +	.pru_send = sctp_sendm,
  1.7830 +	.pru_shutdown = sctp_shutdown,
  1.7831 +	.pru_sockaddr = sctp_ingetaddr,
  1.7832 +	.pru_sosend = sctp_sosend,
  1.7833 +	.pru_soreceive = sctp_soreceive
  1.7834 +#elif defined(__APPLE__)
  1.7835 +	.pru_abort = sctp_abort,
  1.7836 +	.pru_accept = sctp_accept,
  1.7837 +	.pru_attach = sctp_attach,
  1.7838 +	.pru_bind = sctp_bind,
  1.7839 +	.pru_connect = sctp_connect,
  1.7840 +	.pru_connect2 = pru_connect2_notsupp,
  1.7841 +	.pru_control = in_control,
  1.7842 +	.pru_detach = sctp_detach,
  1.7843 +	.pru_disconnect = sctp_disconnect,
  1.7844 +	.pru_listen = sctp_listen,
  1.7845 +	.pru_peeraddr = sctp_peeraddr,
  1.7846 +	.pru_rcvd = NULL,
  1.7847 +	.pru_rcvoob = pru_rcvoob_notsupp,
  1.7848 +	.pru_send = sctp_sendm,
  1.7849 +	.pru_sense = pru_sense_null,
  1.7850 +	.pru_shutdown = sctp_shutdown,
  1.7851 +	.pru_sockaddr = sctp_ingetaddr,
  1.7852 +	.pru_sosend = sctp_sosend,
  1.7853 +	.pru_soreceive = sctp_soreceive,
  1.7854 +	.pru_sopoll = sopoll
  1.7855 +#elif defined(__Windows__)
  1.7856 +	sctp_abort,
  1.7857 +	sctp_accept,
  1.7858 +	sctp_attach,
  1.7859 +	sctp_bind,
  1.7860 +	sctp_connect,
  1.7861 +	pru_connect2_notsupp,
  1.7862 +	NULL,
  1.7863 +	NULL,
  1.7864 +	sctp_disconnect,
  1.7865 +	sctp_listen,
  1.7866 +	sctp_peeraddr,
  1.7867 +	NULL,
  1.7868 +	pru_rcvoob_notsupp,
  1.7869 +	NULL,
  1.7870 +	pru_sense_null,
  1.7871 +	sctp_shutdown,
  1.7872 +	sctp_flush,
  1.7873 +	sctp_ingetaddr,
  1.7874 +	sctp_sosend,
  1.7875 +	sctp_soreceive,
  1.7876 +	sopoll_generic,
  1.7877 +	NULL,
  1.7878 +	sctp_close
  1.7879 +#endif
  1.7880 +};
  1.7881 +#elif !defined(__Panda__) && !defined(__Userspace__)
  1.7882 +int
  1.7883 +sctp_usrreq(so, req, m, nam, control)
  1.7884 +	struct socket *so;
  1.7885 +	int req;
  1.7886 +	struct mbuf *m, *nam, *control;
  1.7887 +{
  1.7888 +	struct proc *p = curproc;
  1.7889 +	uint32_t vrf_id;
  1.7890 +	struct sctp_vrf *vrf;
  1.7891 +	int error;
  1.7892 +	int family;
  1.7893 +	struct sctp_inpcb *inp = (struct sctp_inpcb *)so->so_pcb;
  1.7894 +
  1.7895 +	error = 0;
  1.7896 +	family = so->so_proto->pr_domain->dom_family;
  1.7897 +	if (req == PRU_CONTROL) {
  1.7898 +		switch (family) {
  1.7899 +		case PF_INET:
  1.7900 +			error = in_control(so, (long)m, (caddr_t)nam,
  1.7901 +			    (struct ifnet *)control);
  1.7902 +			break;
  1.7903 +#ifdef INET6
  1.7904 +		case PF_INET6:
  1.7905 +			error = in6_control(so, (long)m, (caddr_t)nam,
  1.7906 +			    (struct ifnet *)control, p);
  1.7907 +			break;
  1.7908 +#endif
  1.7909 +		default:
  1.7910 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
  1.7911 +			error = EAFNOSUPPORT;
  1.7912 +		}
  1.7913 +		return (error);
  1.7914 +	}
  1.7915 +	switch (req) {
  1.7916 +	case PRU_ATTACH:
  1.7917 +		error = sctp_attach(so, family, p);
  1.7918 +		break;
  1.7919 +	case PRU_DETACH:
  1.7920 +		error = sctp_detach(so);
  1.7921 +		break;
  1.7922 +	case PRU_BIND:
  1.7923 +		if (nam == NULL) {
  1.7924 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.7925 +			return (EINVAL);
  1.7926 +		}
  1.7927 +		error = sctp_bind(so, nam, p);
  1.7928 +		break;
  1.7929 +	case PRU_LISTEN:
  1.7930 +		error = sctp_listen(so, p);
  1.7931 +		break;
  1.7932 +	case PRU_CONNECT:
  1.7933 +		if (nam == NULL) {
  1.7934 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.7935 +			return (EINVAL);
  1.7936 +		}
  1.7937 +		error = sctp_connect(so, nam, p);
  1.7938 +		break;
  1.7939 +	case PRU_DISCONNECT:
  1.7940 +		error = sctp_disconnect(so);
  1.7941 +		break;
  1.7942 +	case PRU_ACCEPT:
  1.7943 +		if (nam == NULL) {
  1.7944 +			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
  1.7945 +			return (EINVAL);
  1.7946 +		}
  1.7947 +		error = sctp_accept(so, nam);
  1.7948 +		break;
  1.7949 +	case PRU_SHUTDOWN:
  1.7950 +		error = sctp_shutdown(so);
  1.7951 +		break;
  1.7952 +
  1.7953 +	case PRU_RCVD:
  1.7954 +		/*
  1.7955 +		 * For Open and Net BSD, this is real ugly. The mbuf *nam
  1.7956 +		 * that is passed (by soreceive()) is the int flags c ast as
  1.7957 +		 * a (mbuf *) yuck!
  1.7958 +		 */
  1.7959 +		break;
  1.7960 +
  1.7961 +	case PRU_SEND:
  1.7962 +		/* Flags are ignored */
  1.7963 +		{
  1.7964 +			struct sockaddr *addr;
  1.7965 +
  1.7966 +			if (nam == NULL)
  1.7967 +				addr = NULL;
  1.7968 +			else
  1.7969 +				addr = mtod(nam, struct sockaddr *);
  1.7970 +
  1.7971 +			error = sctp_sendm(so, 0, m, addr, control, p);
  1.7972 +		}
  1.7973 +		break;
  1.7974 +	case PRU_ABORT:
  1.7975 +		error = sctp_abort(so);
  1.7976 +		break;
  1.7977 +
  1.7978 +	case PRU_SENSE:
  1.7979 +		error = 0;
  1.7980 +		break;
  1.7981 +	case PRU_RCVOOB:
  1.7982 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
  1.7983 +		error = EAFNOSUPPORT;
  1.7984 +		break;
  1.7985 +	case PRU_SENDOOB:
  1.7986 +		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
  1.7987 +		error = EAFNOSUPPORT;
  1.7988 +		break;
  1.7989 +	case PRU_PEERADDR:
  1.7990 +		error = sctp_peeraddr(so, nam);
  1.7991 +		break;
  1.7992 +	case PRU_SOCKADDR:
  1.7993 +		error = sctp_ingetaddr(so, nam);
  1.7994 +		break;
  1.7995 +	case PRU_SLOWTIMO:
  1.7996 +		error = 0;
  1.7997 +		break;
  1.7998 +	default:
  1.7999 +		break;
  1.8000 +	}
  1.8001 +	return (error);
  1.8002 +}
  1.8003 +
  1.8004 +#endif
  1.8005 +#endif
  1.8006 +
  1.8007 +#if defined(__Userspace__)
  1.8008 +int
  1.8009 +register_recv_cb(struct socket *so,
  1.8010 +                 int (*receive_cb)(struct socket *sock, union sctp_sockstore addr, void *data,
  1.8011 +                 size_t datalen, struct sctp_rcvinfo, int flags, void *ulp_info))
  1.8012 +{
  1.8013 +	struct sctp_inpcb *inp;
  1.8014 +
  1.8015 +	inp = (struct sctp_inpcb *) so->so_pcb;
  1.8016 +	if (inp == NULL) {
  1.8017 +		return (0);
  1.8018 +	}
  1.8019 +	SCTP_INP_WLOCK(inp);
  1.8020 +	inp->recv_callback = receive_cb;
  1.8021 +	SCTP_INP_WUNLOCK(inp);
  1.8022 +	return (1);
  1.8023 +}
  1.8024 +
  1.8025 +int
  1.8026 +register_send_cb(struct socket *so, uint32_t sb_threshold, int (*send_cb)(struct socket *sock, uint32_t sb_free))
  1.8027 +{
  1.8028 +	struct sctp_inpcb *inp;
  1.8029 +
  1.8030 +	inp = (struct sctp_inpcb *) so->so_pcb;
  1.8031 +	if (inp == NULL) {
  1.8032 +		return (0);
  1.8033 +	}
  1.8034 +	SCTP_INP_WLOCK(inp);
  1.8035 +	inp->send_callback = send_cb;
  1.8036 +	inp->send_sb_threshold = sb_threshold;
  1.8037 +	SCTP_INP_WUNLOCK(inp);
  1.8038 +	/* FIXME change to current amount free. This will be the full buffer
  1.8039 +	 * the first time this is registered but it could be only a portion
  1.8040 +	 * of the send buffer if this is called a second time e.g. if the
  1.8041 +	 * threshold changes.
  1.8042 +	 */
  1.8043 +	return (1);
  1.8044 +}
  1.8045 +
  1.8046 +int
  1.8047 +register_ulp_info (struct socket *so, void *ulp_info)
  1.8048 +{
  1.8049 +	struct sctp_inpcb *inp;
  1.8050 +
  1.8051 +	inp = (struct sctp_inpcb *) so->so_pcb;
  1.8052 +	if (inp == NULL) {
  1.8053 +		return (0);
  1.8054 +	}
  1.8055 +	SCTP_INP_WLOCK(inp);
  1.8056 +	inp->ulp_info = ulp_info;
  1.8057 +	SCTP_INP_WUNLOCK(inp);
  1.8058 +	return (1);
  1.8059 +}
  1.8060 +#endif

mercurial