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