sctp_usrreq.c revision 235403
1163953Srrs/*- 2185694Srrs * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. 3218319Srrs * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved. 4218319Srrs * Copyright (c) 2008-2011, by Michael Tuexen. All rights reserved. 5163953Srrs * 6163953Srrs * Redistribution and use in source and binary forms, with or without 7163953Srrs * modification, are permitted provided that the following conditions are met: 8163953Srrs * 9163953Srrs * a) Redistributions of source code must retain the above copyright notice, 10228653Stuexen * this list of conditions and the following disclaimer. 11163953Srrs * 12163953Srrs * b) Redistributions in binary form must reproduce the above copyright 13163953Srrs * notice, this list of conditions and the following disclaimer in 14228653Stuexen * the documentation and/or other materials provided with the distribution. 15163953Srrs * 16163953Srrs * c) Neither the name of Cisco Systems, Inc. nor the names of its 17163953Srrs * contributors may be used to endorse or promote products derived 18163953Srrs * from this software without specific prior written permission. 19163953Srrs * 20163953Srrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21163953Srrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22163953Srrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24163953Srrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25163953Srrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26163953Srrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27163953Srrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28163953Srrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29163953Srrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30163953Srrs * THE POSSIBILITY OF SUCH DAMAGE. 31163953Srrs */ 32163953Srrs 33163953Srrs/* $KAME: sctp_usrreq.c,v 1.48 2005/03/07 23:26:08 itojun Exp $ */ 34163953Srrs 35163953Srrs#include <sys/cdefs.h> 36163953Srrs__FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 235403 2012-05-13 16:56:16Z tuexen $"); 37166086Srrs#include <netinet/sctp_os.h> 38163953Srrs#include <sys/proc.h> 39163953Srrs#include <netinet/sctp_pcb.h> 40163953Srrs#include <netinet/sctp_header.h> 41163953Srrs#include <netinet/sctp_var.h> 42167695Srrs#if defined(INET6) 43167695Srrs#endif 44167598Srrs#include <netinet/sctp_sysctl.h> 45163953Srrs#include <netinet/sctp_output.h> 46163953Srrs#include <netinet/sctp_uio.h> 47163953Srrs#include <netinet/sctp_asconf.h> 48163953Srrs#include <netinet/sctputil.h> 49163953Srrs#include <netinet/sctp_indata.h> 50163953Srrs#include <netinet/sctp_timer.h> 51163953Srrs#include <netinet/sctp_auth.h> 52170091Srrs#include <netinet/sctp_bsd_addr.h> 53185694Srrs#include <netinet/udp.h> 54164085Srrs 55163953Srrs 56163953Srrs 57217611Stuexenextern struct sctp_cc_functions sctp_cc_functions[]; 58217760Stuexenextern struct sctp_ss_functions sctp_ss_functions[]; 59170091Srrs 60163953Srrsvoid 61163953Srrssctp_init(void) 62163953Srrs{ 63163953Srrs u_long sb_max_adj; 64163953Srrs 65179783Srrs /* Initialize and modify the sysctled variables */ 66179783Srrs sctp_init_sysctls(); 67163953Srrs if ((nmbclusters / 8) > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE) 68179783Srrs SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue) = (nmbclusters / 8); 69163953Srrs /* 70163953Srrs * Allow a user to take no more than 1/2 the number of clusters or 71163953Srrs * the SB_MAX whichever is smaller for the send window. 72163953Srrs */ 73163953Srrs sb_max_adj = (u_long)((u_quad_t) (SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES)); 74179783Srrs SCTP_BASE_SYSCTL(sctp_sendspace) = min(sb_max_adj, 75170056Srrs (((uint32_t) nmbclusters / 2) * SCTP_DEFAULT_MAXSEGMENT)); 76163953Srrs /* 77163953Srrs * Now for the recv window, should we take the same amount? or 78163953Srrs * should I do 1/2 the SB_MAX instead in the SB_MAX min above. For 79163953Srrs * now I will just copy. 80163953Srrs */ 81179783Srrs SCTP_BASE_SYSCTL(sctp_recvspace) = SCTP_BASE_SYSCTL(sctp_sendspace); 82179783Srrs SCTP_BASE_VAR(first_time) = 0; 83179783Srrs SCTP_BASE_VAR(sctp_pcb_initialized) = 0; 84179783Srrs sctp_pcb_init(); 85179783Srrs#if defined(SCTP_PACKET_LOGGING) 86179783Srrs SCTP_BASE_VAR(packet_log_writers) = 0; 87179783Srrs SCTP_BASE_VAR(packet_log_end) = 0; 88179783Srrs bzero(&SCTP_BASE_VAR(packet_log_buffer), SCTP_PACKET_LOG_SIZE); 89179783Srrs#endif 90163953Srrs} 91163953Srrs 92179783Srrsvoid 93179783Srrssctp_finish(void) 94179783Srrs{ 95179783Srrs sctp_pcb_finish(); 96179783Srrs} 97163953Srrs 98166023Srrs 99163953Srrs 100179157Srrsvoid 101228653Stuexensctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint16_t nxtsz) 102163953Srrs{ 103163953Srrs struct sctp_tmit_chunk *chk; 104197257Stuexen uint16_t overhead; 105163953Srrs 106163953Srrs /* Adjust that too */ 107163953Srrs stcb->asoc.smallest_mtu = nxtsz; 108163953Srrs /* now off to subtract IP_DF flag if needed */ 109197257Stuexen overhead = IP_HDR_SIZE; 110197257Stuexen if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) { 111197257Stuexen overhead += sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); 112197257Stuexen } 113163953Srrs TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) { 114197257Stuexen if ((chk->send_size + overhead) > nxtsz) { 115163953Srrs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 116163953Srrs } 117163953Srrs } 118163953Srrs TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 119197257Stuexen if ((chk->send_size + overhead) > nxtsz) { 120163953Srrs /* 121163953Srrs * For this guy we also mark for immediate resend 122163953Srrs * since we sent to big of chunk 123163953Srrs */ 124163953Srrs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 125190689Srrs if (chk->sent < SCTP_DATAGRAM_RESEND) { 126190689Srrs sctp_flight_size_decrease(chk); 127190689Srrs sctp_total_flight_decrease(stcb, chk); 128190689Srrs } 129163953Srrs if (chk->sent != SCTP_DATAGRAM_RESEND) { 130163953Srrs sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 131163953Srrs } 132163953Srrs chk->sent = SCTP_DATAGRAM_RESEND; 133163953Srrs chk->rec.data.doing_fast_retransmit = 0; 134179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { 135170744Srrs sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU, 136170744Srrs chk->whoTo->flight_size, 137170744Srrs chk->book_size, 138170744Srrs (uintptr_t) chk->whoTo, 139170744Srrs chk->rec.data.TSN_seq); 140170744Srrs } 141163953Srrs /* Clear any time so NO RTT is being done */ 142163953Srrs chk->do_rtt = 0; 143163953Srrs } 144163953Srrs } 145163953Srrs} 146163953Srrs 147221249Stuexen#ifdef INET 148163953Srrsstatic void 149163953Srrssctp_notify_mbuf(struct sctp_inpcb *inp, 150163953Srrs struct sctp_tcb *stcb, 151163953Srrs struct sctp_nets *net, 152163953Srrs struct ip *ip, 153163953Srrs struct sctphdr *sh) 154163953Srrs{ 155163953Srrs struct icmp *icmph; 156163953Srrs int totsz, tmr_stopped = 0; 157163953Srrs uint16_t nxtsz; 158163953Srrs 159163953Srrs /* protection */ 160163953Srrs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 161163953Srrs (ip == NULL) || (sh == NULL)) { 162169420Srrs if (stcb != NULL) { 163163953Srrs SCTP_TCB_UNLOCK(stcb); 164169420Srrs } 165163953Srrs return; 166163953Srrs } 167163953Srrs /* First job is to verify the vtag matches what I would send */ 168163953Srrs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 169163953Srrs SCTP_TCB_UNLOCK(stcb); 170163953Srrs return; 171163953Srrs } 172163953Srrs icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) - 173163953Srrs sizeof(struct ip))); 174163953Srrs if (icmph->icmp_type != ICMP_UNREACH) { 175163953Srrs /* We only care about unreachable */ 176163953Srrs SCTP_TCB_UNLOCK(stcb); 177163953Srrs return; 178163953Srrs } 179163953Srrs if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) { 180163953Srrs /* not a unreachable message due to frag. */ 181163953Srrs SCTP_TCB_UNLOCK(stcb); 182163953Srrs return; 183163953Srrs } 184163953Srrs totsz = ip->ip_len; 185163953Srrs 186171943Srrs nxtsz = ntohs(icmph->icmp_nextmtu); 187163953Srrs if (nxtsz == 0) { 188163953Srrs /* 189163953Srrs * old type router that does not tell us what the next size 190163953Srrs * mtu is. Rats we will have to guess (in a educated fashion 191163953Srrs * of course) 192163953Srrs */ 193214939Stuexen nxtsz = sctp_get_prev_mtu(totsz); 194163953Srrs } 195163953Srrs /* Stop any PMTU timer */ 196165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 197163953Srrs tmr_stopped = 1; 198165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 199165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1); 200163953Srrs } 201163953Srrs /* Adjust destination size limit */ 202163953Srrs if (net->mtu > nxtsz) { 203163953Srrs net->mtu = nxtsz; 204185694Srrs if (net->port) { 205185694Srrs net->mtu -= sizeof(struct udphdr); 206185694Srrs } 207163953Srrs } 208163953Srrs /* now what about the ep? */ 209163953Srrs if (stcb->asoc.smallest_mtu > nxtsz) { 210228653Stuexen sctp_pathmtu_adjustment(stcb, nxtsz); 211163953Srrs } 212163953Srrs if (tmr_stopped) 213163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 214163953Srrs 215163953Srrs SCTP_TCB_UNLOCK(stcb); 216163953Srrs} 217163953Srrs 218221249Stuexen#endif 219163953Srrs 220163953Srrsvoid 221163953Srrssctp_notify(struct sctp_inpcb *inp, 222172091Srrs struct ip *ip, 223163953Srrs struct sctphdr *sh, 224163953Srrs struct sockaddr *to, 225163953Srrs struct sctp_tcb *stcb, 226163953Srrs struct sctp_nets *net) 227163953Srrs{ 228172090Srrs#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 229172090Srrs struct socket *so; 230172090Srrs 231172090Srrs#endif 232172091Srrs struct icmp *icmph; 233172091Srrs 234235360Stuexen /* protection */ 235163953Srrs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 236163953Srrs (sh == NULL) || (to == NULL)) { 237172091Srrs if (stcb) 238172091Srrs SCTP_TCB_UNLOCK(stcb); 239163953Srrs return; 240163953Srrs } 241163953Srrs /* First job is to verify the vtag matches what I would send */ 242163953Srrs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 243172091Srrs SCTP_TCB_UNLOCK(stcb); 244163953Srrs return; 245163953Srrs } 246172091Srrs icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) - 247172091Srrs sizeof(struct ip))); 248172091Srrs if (icmph->icmp_type != ICMP_UNREACH) { 249172091Srrs /* We only care about unreachable */ 250172091Srrs SCTP_TCB_UNLOCK(stcb); 251172091Srrs return; 252172091Srrs } 253172091Srrs if ((icmph->icmp_code == ICMP_UNREACH_NET) || 254172091Srrs (icmph->icmp_code == ICMP_UNREACH_HOST) || 255172091Srrs (icmph->icmp_code == ICMP_UNREACH_NET_UNKNOWN) || 256172091Srrs (icmph->icmp_code == ICMP_UNREACH_HOST_UNKNOWN) || 257172091Srrs (icmph->icmp_code == ICMP_UNREACH_ISOLATED) || 258172091Srrs (icmph->icmp_code == ICMP_UNREACH_NET_PROHIB) || 259172091Srrs (icmph->icmp_code == ICMP_UNREACH_HOST_PROHIB) || 260172091Srrs (icmph->icmp_code == ICMP_UNREACH_FILTER_PROHIB)) { 261163953Srrs 262163953Srrs /* 263163953Srrs * Hmm reachablity problems we must examine closely. If its 264163953Srrs * not reachable, we may have lost a network. Or if there is 265163953Srrs * NO protocol at the other end named SCTP. well we consider 266163953Srrs * it a OOTB abort. 267163953Srrs */ 268172091Srrs if (net->dest_state & SCTP_ADDR_REACHABLE) { 269172091Srrs /* Ok that destination is NOT reachable */ 270172091Srrs net->dest_state &= ~SCTP_ADDR_REACHABLE; 271224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 272172091Srrs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, 273172091Srrs stcb, SCTP_FAILED_THRESHOLD, 274172091Srrs (void *)net, SCTP_SO_NOT_LOCKED); 275172091Srrs } 276172091Srrs SCTP_TCB_UNLOCK(stcb); 277172091Srrs } else if ((icmph->icmp_code == ICMP_UNREACH_PROTOCOL) || 278172091Srrs (icmph->icmp_code == ICMP_UNREACH_PORT)) { 279172091Srrs /* 280172091Srrs * Here the peer is either playing tricks on us, including 281172091Srrs * an address that belongs to someone who does not support 282172091Srrs * SCTP OR was a userland implementation that shutdown and 283172091Srrs * now is dead. In either case treat it like a OOTB abort 284172091Srrs * with no TCB 285172091Srrs */ 286235403Stuexen sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED); 287172090Srrs#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 288172091Srrs so = SCTP_INP_SO(inp); 289172091Srrs atomic_add_int(&stcb->asoc.refcnt, 1); 290172091Srrs SCTP_TCB_UNLOCK(stcb); 291172091Srrs SCTP_SOCKET_LOCK(so, 1); 292172091Srrs SCTP_TCB_LOCK(stcb); 293172091Srrs atomic_subtract_int(&stcb->asoc.refcnt, 1); 294172090Srrs#endif 295172091Srrs (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); 296172090Srrs#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 297172091Srrs SCTP_SOCKET_UNLOCK(so, 1); 298172091Srrs /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */ 299172090Srrs#endif 300172091Srrs /* no need to unlock here, since the TCB is gone */ 301163953Srrs } else { 302172091Srrs SCTP_TCB_UNLOCK(stcb); 303163953Srrs } 304163953Srrs} 305163953Srrs 306221249Stuexen#ifdef INET 307163953Srrsvoid 308163953Srrssctp_ctlinput(cmd, sa, vip) 309163953Srrs int cmd; 310163953Srrs struct sockaddr *sa; 311163953Srrs void *vip; 312163953Srrs{ 313163953Srrs struct ip *ip = vip; 314163953Srrs struct sctphdr *sh; 315167598Srrs uint32_t vrf_id; 316163953Srrs 317168299Srrs /* FIX, for non-bsd is this right? */ 318167598Srrs vrf_id = SCTP_DEFAULT_VRFID; 319163953Srrs if (sa->sa_family != AF_INET || 320163953Srrs ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) { 321163953Srrs return; 322163953Srrs } 323163953Srrs if (PRC_IS_REDIRECT(cmd)) { 324163953Srrs ip = 0; 325163953Srrs } else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) { 326163953Srrs return; 327163953Srrs } 328163953Srrs if (ip) { 329163953Srrs struct sctp_inpcb *inp = NULL; 330163953Srrs struct sctp_tcb *stcb = NULL; 331163953Srrs struct sctp_nets *net = NULL; 332163953Srrs struct sockaddr_in to, from; 333163953Srrs 334163953Srrs sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 335163953Srrs bzero(&to, sizeof(to)); 336163953Srrs bzero(&from, sizeof(from)); 337163953Srrs from.sin_family = to.sin_family = AF_INET; 338163953Srrs from.sin_len = to.sin_len = sizeof(to); 339163953Srrs from.sin_port = sh->src_port; 340163953Srrs from.sin_addr = ip->ip_src; 341163953Srrs to.sin_port = sh->dest_port; 342163953Srrs to.sin_addr = ip->ip_dst; 343163953Srrs 344163953Srrs /* 345163953Srrs * 'to' holds the dest of the packet that failed to be sent. 346163953Srrs * 'from' holds our local endpoint address. Thus we reverse 347163953Srrs * the to and the from in the lookup. 348163953Srrs */ 349163953Srrs stcb = sctp_findassociation_addr_sa((struct sockaddr *)&from, 350163953Srrs (struct sockaddr *)&to, 351167598Srrs &inp, &net, 1, vrf_id); 352163953Srrs if (stcb != NULL && inp && (inp->sctp_socket != NULL)) { 353163953Srrs if (cmd != PRC_MSGSIZE) { 354172091Srrs sctp_notify(inp, ip, sh, 355163953Srrs (struct sockaddr *)&to, stcb, 356163953Srrs net); 357163953Srrs } else { 358163953Srrs /* handle possible ICMP size messages */ 359163953Srrs sctp_notify_mbuf(inp, stcb, net, ip, sh); 360163953Srrs } 361163953Srrs } else { 362163953Srrs if ((stcb == NULL) && (inp != NULL)) { 363163953Srrs /* reduce ref-count */ 364163953Srrs SCTP_INP_WLOCK(inp); 365163953Srrs SCTP_INP_DECR_REF(inp); 366163953Srrs SCTP_INP_WUNLOCK(inp); 367163953Srrs } 368209029Srrs if (stcb) { 369209029Srrs SCTP_TCB_UNLOCK(stcb); 370209029Srrs } 371163953Srrs } 372163953Srrs } 373163953Srrs return; 374163953Srrs} 375163953Srrs 376221249Stuexen#endif 377221249Stuexen 378163953Srrsstatic int 379163953Srrssctp_getcred(SYSCTL_HANDLER_ARGS) 380163953Srrs{ 381164085Srrs struct xucred xuc; 382163953Srrs struct sockaddr_in addrs[2]; 383163953Srrs struct sctp_inpcb *inp; 384163953Srrs struct sctp_nets *net; 385163953Srrs struct sctp_tcb *stcb; 386164085Srrs int error; 387167598Srrs uint32_t vrf_id; 388163953Srrs 389168299Srrs /* FIX, for non-bsd is this right? */ 390167598Srrs vrf_id = SCTP_DEFAULT_VRFID; 391168299Srrs 392170587Srwatson error = priv_check(req->td, PRIV_NETINET_GETCRED); 393170587Srwatson 394163953Srrs if (error) 395163953Srrs return (error); 396164039Srwatson 397163953Srrs error = SYSCTL_IN(req, addrs, sizeof(addrs)); 398163953Srrs if (error) 399163953Srrs return (error); 400163953Srrs 401163953Srrs stcb = sctp_findassociation_addr_sa(sintosa(&addrs[0]), 402163953Srrs sintosa(&addrs[1]), 403167598Srrs &inp, &net, 1, vrf_id); 404163953Srrs if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) { 405163953Srrs if ((inp != NULL) && (stcb == NULL)) { 406163953Srrs /* reduce ref-count */ 407163953Srrs SCTP_INP_WLOCK(inp); 408163953Srrs SCTP_INP_DECR_REF(inp); 409164085Srrs goto cred_can_cont; 410163953Srrs } 411171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 412163953Srrs error = ENOENT; 413163953Srrs goto out; 414163953Srrs } 415163953Srrs SCTP_TCB_UNLOCK(stcb); 416164085Srrs /* 417164085Srrs * We use the write lock here, only since in the error leg we need 418164085Srrs * it. If we used RLOCK, then we would have to 419164085Srrs * wlock/decr/unlock/rlock. Which in theory could create a hole. 420164085Srrs * Better to use higher wlock. 421164085Srrs */ 422164085Srrs SCTP_INP_WLOCK(inp); 423164085Srrscred_can_cont: 424164085Srrs error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket); 425164085Srrs if (error) { 426164085Srrs SCTP_INP_WUNLOCK(inp); 427164085Srrs goto out; 428164085Srrs } 429164085Srrs cru2x(inp->sctp_socket->so_cred, &xuc); 430164085Srrs SCTP_INP_WUNLOCK(inp); 431164085Srrs error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); 432163953Srrsout: 433163953Srrs return (error); 434163953Srrs} 435163953Srrs 436163953SrrsSYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW, 437163953Srrs 0, 0, sctp_getcred, "S,ucred", "Get the ucred of a SCTP connection"); 438163953Srrs 439163953Srrs 440221249Stuexen#ifdef INET 441163953Srrsstatic void 442163953Srrssctp_abort(struct socket *so) 443163953Srrs{ 444163953Srrs struct sctp_inpcb *inp; 445163953Srrs uint32_t flags; 446163953Srrs 447163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 448233005Stuexen if (inp == NULL) { 449163953Srrs return; 450171943Srrs } 451163953Srrssctp_must_try_again: 452163953Srrs flags = inp->sctp_flags; 453163953Srrs#ifdef SCTP_LOG_CLOSING 454163953Srrs sctp_log_closing(inp, NULL, 17); 455163953Srrs#endif 456163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 457163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 458163953Srrs#ifdef SCTP_LOG_CLOSING 459163953Srrs sctp_log_closing(inp, NULL, 16); 460163953Srrs#endif 461169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 462169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 463163953Srrs SOCK_LOCK(so); 464167695Srrs SCTP_SB_CLEAR(so->so_snd); 465163953Srrs /* 466163953Srrs * same for the rcv ones, they are only here for the 467163953Srrs * accounting/select. 468163953Srrs */ 469167695Srrs SCTP_SB_CLEAR(so->so_rcv); 470167695Srrs 471167695Srrs /* Now null out the reference, we are completely detached. */ 472163953Srrs so->so_pcb = NULL; 473163953Srrs SOCK_UNLOCK(so); 474163953Srrs } else { 475163953Srrs flags = inp->sctp_flags; 476163953Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 477163953Srrs goto sctp_must_try_again; 478163953Srrs } 479163953Srrs } 480163953Srrs return; 481163953Srrs} 482163953Srrs 483163953Srrsstatic int 484228653Stuexensctp_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED) 485163953Srrs{ 486163953Srrs struct sctp_inpcb *inp; 487163953Srrs struct inpcb *ip_inp; 488166086Srrs int error; 489170205Srrs uint32_t vrf_id = SCTP_DEFAULT_VRFID; 490185694Srrs 491171167Sgnn#ifdef IPSEC 492163953Srrs uint32_t flags; 493185694Srrs 494185435Sbz#endif 495171440Srrs 496163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 497163953Srrs if (inp != 0) { 498171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 499228907Stuexen return (EINVAL); 500163953Srrs } 501184030Srrs if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 502184030Srrs error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace)); 503184030Srrs if (error) { 504228907Stuexen return (error); 505184030Srrs } 506163953Srrs } 507170205Srrs error = sctp_inpcb_alloc(so, vrf_id); 508163953Srrs if (error) { 509228907Stuexen return (error); 510163953Srrs } 511163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 512163953Srrs SCTP_INP_WLOCK(inp); 513163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6; /* I'm not v6! */ 514163953Srrs ip_inp = &inp->ip_inp.inp; 515163953Srrs ip_inp->inp_vflag |= INP_IPV4; 516197288Srrs ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl); 517171167Sgnn#ifdef IPSEC 518171133Sgnn error = ipsec_init_policy(so, &ip_inp->inp_sp); 519163953Srrs#ifdef SCTP_LOG_CLOSING 520163953Srrs sctp_log_closing(inp, NULL, 17); 521163953Srrs#endif 522163953Srrs if (error != 0) { 523202523Srrstry_again: 524163953Srrs flags = inp->sctp_flags; 525163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 526163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 527163953Srrs#ifdef SCTP_LOG_CLOSING 528163953Srrs sctp_log_closing(inp, NULL, 15); 529163953Srrs#endif 530169352Srrs SCTP_INP_WUNLOCK(inp); 531169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 532169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 533169254Srrs } else { 534202523Srrs flags = inp->sctp_flags; 535202523Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 536202523Srrs goto try_again; 537202523Srrs } else { 538202523Srrs SCTP_INP_WUNLOCK(inp); 539202523Srrs } 540163953Srrs } 541228907Stuexen return (error); 542163953Srrs } 543171167Sgnn#endif /* IPSEC */ 544163953Srrs SCTP_INP_WUNLOCK(inp); 545228907Stuexen return (0); 546163953Srrs} 547163953Srrs 548163953Srrsstatic int 549163953Srrssctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p) 550163953Srrs{ 551171943Srrs struct sctp_inpcb *inp = NULL; 552166086Srrs int error; 553163953Srrs 554225571Stuexen#ifdef INET 555171943Srrs if (addr && addr->sa_family != AF_INET) { 556163953Srrs /* must be a v4 address! */ 557171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 558228907Stuexen return (EINVAL); 559171943Srrs } 560163953Srrs#endif /* INET6 */ 561170056Srrs if (addr && (addr->sa_len != sizeof(struct sockaddr_in))) { 562171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 563228907Stuexen return (EINVAL); 564170056Srrs } 565163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 566233005Stuexen if (inp == NULL) { 567171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 568228907Stuexen return (EINVAL); 569171943Srrs } 570171572Srrs error = sctp_inpcb_bind(so, addr, NULL, p); 571228907Stuexen return (error); 572163953Srrs} 573163953Srrs 574221249Stuexen#endif 575171990Srrsvoid 576163953Srrssctp_close(struct socket *so) 577163953Srrs{ 578163953Srrs struct sctp_inpcb *inp; 579163953Srrs uint32_t flags; 580163953Srrs 581163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 582233005Stuexen if (inp == NULL) 583163953Srrs return; 584163953Srrs 585163953Srrs /* 586163953Srrs * Inform all the lower layer assoc that we are done. 587163953Srrs */ 588163953Srrssctp_must_try_again: 589163953Srrs flags = inp->sctp_flags; 590163953Srrs#ifdef SCTP_LOG_CLOSING 591163953Srrs sctp_log_closing(inp, NULL, 17); 592163953Srrs#endif 593163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 594163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 595163953Srrs if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || 596163953Srrs (so->so_rcv.sb_cc > 0)) { 597163953Srrs#ifdef SCTP_LOG_CLOSING 598163953Srrs sctp_log_closing(inp, NULL, 13); 599163953Srrs#endif 600169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 601169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 602163953Srrs } else { 603163953Srrs#ifdef SCTP_LOG_CLOSING 604163953Srrs sctp_log_closing(inp, NULL, 14); 605163953Srrs#endif 606169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE, 607169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 608163953Srrs } 609163953Srrs /* 610163953Srrs * The socket is now detached, no matter what the state of 611163953Srrs * the SCTP association. 612163953Srrs */ 613163953Srrs SOCK_LOCK(so); 614167695Srrs SCTP_SB_CLEAR(so->so_snd); 615163953Srrs /* 616163953Srrs * same for the rcv ones, they are only here for the 617163953Srrs * accounting/select. 618163953Srrs */ 619167695Srrs SCTP_SB_CLEAR(so->so_rcv); 620167695Srrs 621167695Srrs /* Now null out the reference, we are completely detached. */ 622163953Srrs so->so_pcb = NULL; 623163953Srrs SOCK_UNLOCK(so); 624163953Srrs } else { 625163953Srrs flags = inp->sctp_flags; 626163953Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 627163953Srrs goto sctp_must_try_again; 628163953Srrs } 629163953Srrs } 630163953Srrs return; 631163953Srrs} 632163953Srrs 633163953Srrs 634163953Srrsint 635163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 636163953Srrs struct mbuf *control, struct thread *p); 637163953Srrs 638163953Srrs 639163953Srrsint 640163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 641163953Srrs struct mbuf *control, struct thread *p) 642163953Srrs{ 643163953Srrs struct sctp_inpcb *inp; 644163953Srrs int error; 645163953Srrs 646163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 647233005Stuexen if (inp == NULL) { 648163953Srrs if (control) { 649163953Srrs sctp_m_freem(control); 650163953Srrs control = NULL; 651163953Srrs } 652171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 653163953Srrs sctp_m_freem(m); 654228907Stuexen return (EINVAL); 655163953Srrs } 656163953Srrs /* Got to have an to address if we are NOT a connected socket */ 657163953Srrs if ((addr == NULL) && 658163953Srrs ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) || 659228907Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE))) { 660163953Srrs goto connected_type; 661163953Srrs } else if (addr == NULL) { 662171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); 663163953Srrs error = EDESTADDRREQ; 664163953Srrs sctp_m_freem(m); 665163953Srrs if (control) { 666163953Srrs sctp_m_freem(control); 667163953Srrs control = NULL; 668163953Srrs } 669163953Srrs return (error); 670163953Srrs } 671163953Srrs#ifdef INET6 672163953Srrs if (addr->sa_family != AF_INET) { 673163953Srrs /* must be a v4 address! */ 674171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); 675163953Srrs sctp_m_freem(m); 676163953Srrs if (control) { 677163953Srrs sctp_m_freem(control); 678163953Srrs control = NULL; 679163953Srrs } 680163953Srrs error = EDESTADDRREQ; 681223132Stuexen return (error); 682163953Srrs } 683163953Srrs#endif /* INET6 */ 684163953Srrsconnected_type: 685163953Srrs /* now what about control */ 686163953Srrs if (control) { 687163953Srrs if (inp->control) { 688169420Srrs SCTP_PRINTF("huh? control set?\n"); 689163953Srrs sctp_m_freem(inp->control); 690163953Srrs inp->control = NULL; 691163953Srrs } 692163953Srrs inp->control = control; 693163953Srrs } 694163953Srrs /* Place the data */ 695163953Srrs if (inp->pkt) { 696165647Srrs SCTP_BUF_NEXT(inp->pkt_last) = m; 697163953Srrs inp->pkt_last = m; 698163953Srrs } else { 699163953Srrs inp->pkt_last = inp->pkt = m; 700163953Srrs } 701163953Srrs if ( 702163953Srrs /* FreeBSD uses a flag passed */ 703163953Srrs ((flags & PRUS_MORETOCOME) == 0) 704163953Srrs ) { 705163953Srrs /* 706163953Srrs * note with the current version this code will only be used 707163953Srrs * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for 708163953Srrs * re-defining sosend to use the sctp_sosend. One can 709163953Srrs * optionally switch back to this code (by changing back the 710163953Srrs * definitions) but this is not advisable. This code is used 711163953Srrs * by FreeBSD when sending a file with sendfile() though. 712163953Srrs */ 713163953Srrs int ret; 714163953Srrs 715163953Srrs ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags); 716163953Srrs inp->pkt = NULL; 717163953Srrs inp->control = NULL; 718163953Srrs return (ret); 719163953Srrs } else { 720163953Srrs return (0); 721163953Srrs } 722163953Srrs} 723163953Srrs 724171990Srrsint 725163953Srrssctp_disconnect(struct socket *so) 726163953Srrs{ 727163953Srrs struct sctp_inpcb *inp; 728163953Srrs 729163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 730163953Srrs if (inp == NULL) { 731171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 732163953Srrs return (ENOTCONN); 733163953Srrs } 734163953Srrs SCTP_INP_RLOCK(inp); 735171745Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 736171745Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 737199437Stuexen if (LIST_EMPTY(&inp->sctp_asoc_list)) { 738163953Srrs /* No connection */ 739163953Srrs SCTP_INP_RUNLOCK(inp); 740163953Srrs return (0); 741163953Srrs } else { 742163953Srrs struct sctp_association *asoc; 743163953Srrs struct sctp_tcb *stcb; 744163953Srrs 745163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 746163953Srrs if (stcb == NULL) { 747163953Srrs SCTP_INP_RUNLOCK(inp); 748171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 749163953Srrs return (EINVAL); 750163953Srrs } 751163953Srrs SCTP_TCB_LOCK(stcb); 752163953Srrs asoc = &stcb->asoc; 753163953Srrs if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 754163953Srrs /* We are about to be freed, out of here */ 755163953Srrs SCTP_TCB_UNLOCK(stcb); 756163953Srrs SCTP_INP_RUNLOCK(inp); 757163953Srrs return (0); 758163953Srrs } 759163953Srrs if (((so->so_options & SO_LINGER) && 760163953Srrs (so->so_linger == 0)) || 761163953Srrs (so->so_rcv.sb_cc > 0)) { 762163953Srrs if (SCTP_GET_STATE(asoc) != 763163953Srrs SCTP_STATE_COOKIE_WAIT) { 764163953Srrs /* Left with Data unread */ 765163953Srrs struct mbuf *err; 766163953Srrs 767163953Srrs err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_DONTWAIT, 1, MT_DATA); 768163953Srrs if (err) { 769163953Srrs /* 770163953Srrs * Fill in the user 771163953Srrs * initiated abort 772163953Srrs */ 773163953Srrs struct sctp_paramhdr *ph; 774163953Srrs 775163953Srrs ph = mtod(err, struct sctp_paramhdr *); 776165647Srrs SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr); 777163953Srrs ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); 778165647Srrs ph->param_length = htons(SCTP_BUF_LEN(err)); 779163953Srrs } 780172090Srrs sctp_send_abort_tcb(stcb, err, SCTP_SO_LOCKED); 781163953Srrs SCTP_STAT_INCR_COUNTER32(sctps_aborted); 782163953Srrs } 783163953Srrs SCTP_INP_RUNLOCK(inp); 784163953Srrs if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 785163953Srrs (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 786163953Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 787163953Srrs } 788171943Srrs (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3); 789163953Srrs /* No unlock tcb assoc is gone */ 790163953Srrs return (0); 791163953Srrs } 792163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 793163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 794163953Srrs (asoc->stream_queue_cnt == 0)) { 795163953Srrs /* there is nothing queued to send, so done */ 796163953Srrs if (asoc->locked_on_sending) { 797163953Srrs goto abort_anyway; 798163953Srrs } 799166675Srrs if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) && 800166675Srrs (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { 801163953Srrs /* only send SHUTDOWN 1st time thru */ 802224641Stuexen struct sctp_nets *netp; 803224641Stuexen 804224641Stuexen if (stcb->asoc.alternate) { 805224641Stuexen netp = stcb->asoc.alternate; 806224641Stuexen } else { 807224641Stuexen netp = stcb->asoc.primary_destination; 808224641Stuexen } 809163953Srrs sctp_stop_timers_for_shutdown(stcb); 810224641Stuexen sctp_send_shutdown(stcb, netp); 811172090Srrs sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); 812166675Srrs if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 813166675Srrs (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 814166675Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 815166675Srrs } 816171943Srrs SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); 817172703Srrs SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 818163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 819224641Stuexen stcb->sctp_ep, stcb, netp); 820163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 821224641Stuexen stcb->sctp_ep, stcb, netp); 822224641Stuexen 823163953Srrs } 824163953Srrs } else { 825163953Srrs /* 826163953Srrs * we still got (or just got) data to send, 827163953Srrs * so set SHUTDOWN_PENDING 828163953Srrs */ 829163953Srrs /* 830163953Srrs * XXX sockets draft says that SCTP_EOF 831163953Srrs * should be sent with no data. currently, 832163953Srrs * we will allow user data to be sent first 833163953Srrs * and move to SHUTDOWN-PENDING 834163953Srrs */ 835224641Stuexen struct sctp_nets *netp; 836224641Stuexen 837224641Stuexen if (stcb->asoc.alternate) { 838224641Stuexen netp = stcb->asoc.alternate; 839224641Stuexen } else { 840224641Stuexen netp = stcb->asoc.primary_destination; 841224641Stuexen } 842224641Stuexen 843163953Srrs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 844163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, 845224641Stuexen netp); 846163953Srrs if (asoc->locked_on_sending) { 847163953Srrs /* Locked to send out the data */ 848163953Srrs struct sctp_stream_queue_pending *sp; 849163953Srrs 850163953Srrs sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); 851163953Srrs if (sp == NULL) { 852169420Srrs SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", 853163953Srrs asoc->locked_on_sending->stream_no); 854163953Srrs } else { 855163953Srrs if ((sp->length == 0) && (sp->msg_is_complete == 0)) 856163953Srrs asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; 857163953Srrs } 858163953Srrs } 859163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 860163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 861163953Srrs (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 862163953Srrs struct mbuf *op_err; 863163953Srrs 864163953Srrs abort_anyway: 865163953Srrs op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 866163953Srrs 0, M_DONTWAIT, 1, MT_DATA); 867163953Srrs if (op_err) { 868163953Srrs /* 869163953Srrs * Fill in the user 870163953Srrs * initiated abort 871163953Srrs */ 872163953Srrs struct sctp_paramhdr *ph; 873163953Srrs uint32_t *ippp; 874163953Srrs 875165647Srrs SCTP_BUF_LEN(op_err) = 876163953Srrs (sizeof(struct sctp_paramhdr) + sizeof(uint32_t)); 877163953Srrs ph = mtod(op_err, 878163953Srrs struct sctp_paramhdr *); 879163953Srrs ph->param_type = htons( 880163953Srrs SCTP_CAUSE_USER_INITIATED_ABT); 881165647Srrs ph->param_length = htons(SCTP_BUF_LEN(op_err)); 882163953Srrs ippp = (uint32_t *) (ph + 1); 883165220Srrs *ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4); 884163953Srrs } 885165220Srrs stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4; 886172090Srrs sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED); 887163953Srrs SCTP_STAT_INCR_COUNTER32(sctps_aborted); 888163953Srrs if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 889163953Srrs (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 890163953Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 891163953Srrs } 892163953Srrs SCTP_INP_RUNLOCK(inp); 893171943Srrs (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5); 894163953Srrs return (0); 895171990Srrs } else { 896172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); 897163953Srrs } 898163953Srrs } 899188067Srrs soisdisconnecting(so); 900163953Srrs SCTP_TCB_UNLOCK(stcb); 901163953Srrs SCTP_INP_RUNLOCK(inp); 902163953Srrs return (0); 903163953Srrs } 904163953Srrs /* not reached */ 905163953Srrs } else { 906163953Srrs /* UDP model does not support this */ 907163953Srrs SCTP_INP_RUNLOCK(inp); 908171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 909228907Stuexen return (EOPNOTSUPP); 910163953Srrs } 911163953Srrs} 912163953Srrs 913163953Srrsint 914178202Srrssctp_flush(struct socket *so, int how) 915178202Srrs{ 916178202Srrs /* 917178202Srrs * We will just clear out the values and let subsequent close clear 918178202Srrs * out the data, if any. Note if the user did a shutdown(SHUT_RD) 919178202Srrs * they will not be able to read the data, the socket will block 920178202Srrs * that from happening. 921178202Srrs */ 922209289Stuexen struct sctp_inpcb *inp; 923209289Stuexen 924209289Stuexen inp = (struct sctp_inpcb *)so->so_pcb; 925209289Stuexen if (inp == NULL) { 926209289Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 927228907Stuexen return (EINVAL); 928209289Stuexen } 929209289Stuexen SCTP_INP_RLOCK(inp); 930209289Stuexen /* For the 1 to many model this does nothing */ 931209289Stuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 932209289Stuexen SCTP_INP_RUNLOCK(inp); 933209289Stuexen return (0); 934209289Stuexen } 935209289Stuexen SCTP_INP_RUNLOCK(inp); 936178202Srrs if ((how == PRU_FLUSH_RD) || (how == PRU_FLUSH_RDWR)) { 937178202Srrs /* 938178202Srrs * First make sure the sb will be happy, we don't use these 939178202Srrs * except maybe the count 940178202Srrs */ 941209289Stuexen SCTP_INP_WLOCK(inp); 942209289Stuexen SCTP_INP_READ_LOCK(inp); 943209289Stuexen inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ; 944209289Stuexen SCTP_INP_READ_UNLOCK(inp); 945209289Stuexen SCTP_INP_WUNLOCK(inp); 946178202Srrs so->so_rcv.sb_cc = 0; 947178202Srrs so->so_rcv.sb_mbcnt = 0; 948178202Srrs so->so_rcv.sb_mb = NULL; 949178202Srrs } 950178202Srrs if ((how == PRU_FLUSH_WR) || (how == PRU_FLUSH_RDWR)) { 951178202Srrs /* 952178202Srrs * First make sure the sb will be happy, we don't use these 953178202Srrs * except maybe the count 954178202Srrs */ 955178202Srrs so->so_snd.sb_cc = 0; 956178202Srrs so->so_snd.sb_mbcnt = 0; 957178202Srrs so->so_snd.sb_mb = NULL; 958178202Srrs 959178202Srrs } 960178202Srrs return (0); 961178202Srrs} 962178202Srrs 963178202Srrsint 964163953Srrssctp_shutdown(struct socket *so) 965163953Srrs{ 966163953Srrs struct sctp_inpcb *inp; 967163953Srrs 968163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 969233005Stuexen if (inp == NULL) { 970171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 971228907Stuexen return (EINVAL); 972163953Srrs } 973163953Srrs SCTP_INP_RLOCK(inp); 974163953Srrs /* For UDP model this is a invalid call */ 975163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 976163953Srrs /* Restore the flags that the soshutdown took away. */ 977204096Stuexen SOCKBUF_LOCK(&so->so_rcv); 978163953Srrs so->so_rcv.sb_state &= ~SBS_CANTRCVMORE; 979204096Stuexen SOCKBUF_UNLOCK(&so->so_rcv); 980163953Srrs /* This proc will wakeup for read and do nothing (I hope) */ 981163953Srrs SCTP_INP_RUNLOCK(inp); 982171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 983163953Srrs return (EOPNOTSUPP); 984163953Srrs } 985163953Srrs /* 986163953Srrs * Ok if we reach here its the TCP model and it is either a SHUT_WR 987163953Srrs * or SHUT_RDWR. This means we put the shutdown flag against it. 988163953Srrs */ 989163953Srrs { 990163953Srrs struct sctp_tcb *stcb; 991163953Srrs struct sctp_association *asoc; 992163953Srrs 993188067Srrs if ((so->so_state & 994188067Srrs (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) { 995188067Srrs SCTP_INP_RUNLOCK(inp); 996188067Srrs return (ENOTCONN); 997188067Srrs } 998163953Srrs socantsendmore(so); 999163953Srrs 1000163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 1001163953Srrs if (stcb == NULL) { 1002163953Srrs /* 1003163953Srrs * Ok we hit the case that the shutdown call was 1004163953Srrs * made after an abort or something. Nothing to do 1005163953Srrs * now. 1006163953Srrs */ 1007168299Srrs SCTP_INP_RUNLOCK(inp); 1008163953Srrs return (0); 1009163953Srrs } 1010163953Srrs SCTP_TCB_LOCK(stcb); 1011163953Srrs asoc = &stcb->asoc; 1012163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 1013163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 1014163953Srrs (asoc->stream_queue_cnt == 0)) { 1015163953Srrs if (asoc->locked_on_sending) { 1016163953Srrs goto abort_anyway; 1017163953Srrs } 1018163953Srrs /* there is nothing queued to send, so I'm done... */ 1019163953Srrs if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { 1020163953Srrs /* only send SHUTDOWN the first time through */ 1021224641Stuexen struct sctp_nets *netp; 1022224641Stuexen 1023224641Stuexen if (stcb->asoc.alternate) { 1024224641Stuexen netp = stcb->asoc.alternate; 1025224641Stuexen } else { 1026224641Stuexen netp = stcb->asoc.primary_destination; 1027224641Stuexen } 1028163953Srrs sctp_stop_timers_for_shutdown(stcb); 1029224641Stuexen sctp_send_shutdown(stcb, netp); 1030172218Srrs sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); 1031166675Srrs if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 1032166675Srrs (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 1033166675Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 1034166675Srrs } 1035171943Srrs SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); 1036172703Srrs SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 1037163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 1038224641Stuexen stcb->sctp_ep, stcb, netp); 1039163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 1040224641Stuexen stcb->sctp_ep, stcb, netp); 1041163953Srrs } 1042163953Srrs } else { 1043163953Srrs /* 1044163953Srrs * we still got (or just got) data to send, so set 1045163953Srrs * SHUTDOWN_PENDING 1046163953Srrs */ 1047224641Stuexen struct sctp_nets *netp; 1048224641Stuexen 1049224641Stuexen if (stcb->asoc.alternate) { 1050224641Stuexen netp = stcb->asoc.alternate; 1051224641Stuexen } else { 1052224641Stuexen netp = stcb->asoc.primary_destination; 1053224641Stuexen } 1054224641Stuexen 1055163953Srrs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 1056163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, 1057224641Stuexen netp); 1058163953Srrs 1059163953Srrs if (asoc->locked_on_sending) { 1060163953Srrs /* Locked to send out the data */ 1061163953Srrs struct sctp_stream_queue_pending *sp; 1062163953Srrs 1063163953Srrs sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); 1064163953Srrs if (sp == NULL) { 1065169420Srrs SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", 1066163953Srrs asoc->locked_on_sending->stream_no); 1067163953Srrs } else { 1068163953Srrs if ((sp->length == 0) && (sp->msg_is_complete == 0)) { 1069163953Srrs asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; 1070163953Srrs } 1071163953Srrs } 1072163953Srrs } 1073163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 1074163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 1075163953Srrs (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 1076163953Srrs struct mbuf *op_err; 1077163953Srrs 1078163953Srrs abort_anyway: 1079163953Srrs op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 1080163953Srrs 0, M_DONTWAIT, 1, MT_DATA); 1081163953Srrs if (op_err) { 1082163953Srrs /* Fill in the user initiated abort */ 1083163953Srrs struct sctp_paramhdr *ph; 1084163953Srrs uint32_t *ippp; 1085163953Srrs 1086165647Srrs SCTP_BUF_LEN(op_err) = 1087163953Srrs sizeof(struct sctp_paramhdr) + sizeof(uint32_t); 1088163953Srrs ph = mtod(op_err, 1089163953Srrs struct sctp_paramhdr *); 1090163953Srrs ph->param_type = htons( 1091163953Srrs SCTP_CAUSE_USER_INITIATED_ABT); 1092165647Srrs ph->param_length = htons(SCTP_BUF_LEN(op_err)); 1093163953Srrs ippp = (uint32_t *) (ph + 1); 1094165220Srrs *ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6); 1095163953Srrs } 1096165220Srrs stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6; 1097163953Srrs sctp_abort_an_association(stcb->sctp_ep, stcb, 1098172090Srrs op_err, SCTP_SO_LOCKED); 1099163953Srrs goto skip_unlock; 1100171990Srrs } else { 1101172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); 1102163953Srrs } 1103163953Srrs } 1104163953Srrs SCTP_TCB_UNLOCK(stcb); 1105163953Srrs } 1106163953Srrsskip_unlock: 1107163953Srrs SCTP_INP_RUNLOCK(inp); 1108228907Stuexen return (0); 1109163953Srrs} 1110163953Srrs 1111163953Srrs/* 1112163953Srrs * copies a "user" presentable address and removes embedded scope, etc. 1113163953Srrs * returns 0 on success, 1 on error 1114163953Srrs */ 1115163953Srrsstatic uint32_t 1116163953Srrssctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa) 1117163953Srrs{ 1118178251Srrs#ifdef INET6 1119163953Srrs struct sockaddr_in6 lsa6; 1120163953Srrs 1121163953Srrs sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa, 1122163953Srrs &lsa6); 1123178251Srrs#endif 1124163953Srrs memcpy(ss, sa, sa->sa_len); 1125163953Srrs return (0); 1126163953Srrs} 1127163953Srrs 1128163953Srrs 1129163953Srrs 1130172091Srrs/* 1131172091Srrs * NOTE: assumes addr lock is held 1132172091Srrs */ 1133166675Srrsstatic size_t 1134168124Srrssctp_fill_up_addresses_vrf(struct sctp_inpcb *inp, 1135163953Srrs struct sctp_tcb *stcb, 1136166675Srrs size_t limit, 1137167598Srrs struct sockaddr_storage *sas, 1138167598Srrs uint32_t vrf_id) 1139163953Srrs{ 1140167598Srrs struct sctp_ifn *sctp_ifn; 1141167598Srrs struct sctp_ifa *sctp_ifa; 1142166675Srrs int loopback_scope, ipv4_local_scope, local_scope, site_scope; 1143166675Srrs size_t actual; 1144163953Srrs int ipv4_addr_legal, ipv6_addr_legal; 1145167598Srrs struct sctp_vrf *vrf; 1146163953Srrs 1147163953Srrs actual = 0; 1148163953Srrs if (limit <= 0) 1149163953Srrs return (actual); 1150163953Srrs 1151163953Srrs if (stcb) { 1152163953Srrs /* Turn on all the appropriate scope */ 1153163953Srrs loopback_scope = stcb->asoc.loopback_scope; 1154163953Srrs ipv4_local_scope = stcb->asoc.ipv4_local_scope; 1155163953Srrs local_scope = stcb->asoc.local_scope; 1156163953Srrs site_scope = stcb->asoc.site_scope; 1157163953Srrs } else { 1158163953Srrs /* Turn on ALL scope, since we look at the EP */ 1159163953Srrs loopback_scope = ipv4_local_scope = local_scope = 1160163953Srrs site_scope = 1; 1161163953Srrs } 1162163953Srrs ipv4_addr_legal = ipv6_addr_legal = 0; 1163163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 1164163953Srrs ipv6_addr_legal = 1; 1165166023Srrs if (SCTP_IPV6_V6ONLY(inp) == 0) { 1166163953Srrs ipv4_addr_legal = 1; 1167163953Srrs } 1168163953Srrs } else { 1169163953Srrs ipv4_addr_legal = 1; 1170163953Srrs } 1171167598Srrs vrf = sctp_find_vrf(vrf_id); 1172167598Srrs if (vrf == NULL) { 1173167598Srrs return (0); 1174167598Srrs } 1175163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1176167598Srrs LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 1177163953Srrs if ((loopback_scope == 0) && 1178167598Srrs SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { 1179163953Srrs /* Skip loopback if loopback_scope not set */ 1180163953Srrs continue; 1181163953Srrs } 1182167598Srrs LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 1183163953Srrs if (stcb) { 1184163953Srrs /* 1185163953Srrs * For the BOUND-ALL case, the list 1186163953Srrs * associated with a TCB is Always 1187163953Srrs * considered a reverse list.. i.e. 1188163953Srrs * it lists addresses that are NOT 1189163953Srrs * part of the association. If this 1190163953Srrs * is one of those we must skip it. 1191163953Srrs */ 1192163953Srrs if (sctp_is_addr_restricted(stcb, 1193167598Srrs sctp_ifa)) { 1194163953Srrs continue; 1195163953Srrs } 1196163953Srrs } 1197178251Srrs switch (sctp_ifa->address.sa.sa_family) { 1198221249Stuexen#ifdef INET 1199178251Srrs case AF_INET: 1200178251Srrs if (ipv4_addr_legal) { 1201178251Srrs struct sockaddr_in *sin; 1202163953Srrs 1203178251Srrs sin = (struct sockaddr_in *)&sctp_ifa->address.sa; 1204178251Srrs if (sin->sin_addr.s_addr == 0) { 1205178251Srrs /* 1206178251Srrs * we skip 1207178251Srrs * unspecifed 1208178251Srrs * addresses 1209178251Srrs */ 1210178251Srrs continue; 1211178251Srrs } 1212178251Srrs if ((ipv4_local_scope == 0) && 1213178251Srrs (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { 1214178251Srrs continue; 1215178251Srrs } 1216178251Srrs#ifdef INET6 1217178251Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 1218178251Srrs in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas); 1219178251Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1220178251Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6)); 1221178251Srrs actual += sizeof(struct sockaddr_in6); 1222178251Srrs } else { 1223178251Srrs#endif 1224178251Srrs memcpy(sas, sin, sizeof(*sin)); 1225178251Srrs ((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport; 1226178251Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin)); 1227178251Srrs actual += sizeof(*sin); 1228178251Srrs#ifdef INET6 1229178251Srrs } 1230178251Srrs#endif 1231178251Srrs if (actual >= limit) { 1232178251Srrs return (actual); 1233178251Srrs } 1234178251Srrs } else { 1235163953Srrs continue; 1236163953Srrs } 1237178251Srrs break; 1238221249Stuexen#endif 1239178251Srrs#ifdef INET6 1240178251Srrs case AF_INET6: 1241178251Srrs if (ipv6_addr_legal) { 1242178251Srrs struct sockaddr_in6 *sin6; 1243163953Srrs 1244178251Srrs sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa; 1245178251Srrs if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 1246178251Srrs /* 1247178251Srrs * we skip 1248178251Srrs * unspecifed 1249178251Srrs * addresses 1250178251Srrs */ 1251163953Srrs continue; 1252178251Srrs } 1253178251Srrs if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 1254178251Srrs if (local_scope == 0) 1255163953Srrs continue; 1256178251Srrs if (sin6->sin6_scope_id == 0) { 1257178251Srrs if (sa6_recoverscope(sin6) != 0) 1258178251Srrs /* 1259178251Srrs * 1260178251Srrs * bad 1261178251Srrs * 1262178251Srrs * li 1263178251Srrs * nk 1264178251Srrs * 1265178251Srrs * loc 1266178251Srrs * al 1267178251Srrs * 1268178251Srrs * add 1269178251Srrs * re 1270178251Srrs * ss 1271178251Srrs * */ 1272178251Srrs continue; 1273178251Srrs } 1274163953Srrs } 1275178251Srrs if ((site_scope == 0) && 1276178251Srrs (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { 1277178251Srrs continue; 1278178251Srrs } 1279178251Srrs memcpy(sas, sin6, sizeof(*sin6)); 1280178251Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1281178251Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6)); 1282178251Srrs actual += sizeof(*sin6); 1283178251Srrs if (actual >= limit) { 1284178251Srrs return (actual); 1285178251Srrs } 1286178251Srrs } else { 1287163953Srrs continue; 1288163953Srrs } 1289178251Srrs break; 1290178251Srrs#endif 1291178251Srrs default: 1292178251Srrs /* TSNH */ 1293178251Srrs break; 1294163953Srrs } 1295163953Srrs } 1296163953Srrs } 1297163953Srrs } else { 1298163953Srrs struct sctp_laddr *laddr; 1299163953Srrs 1300167598Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1301167598Srrs if (stcb) { 1302167598Srrs if (sctp_is_addr_restricted(stcb, laddr->ifa)) { 1303163953Srrs continue; 1304163953Srrs } 1305163953Srrs } 1306167598Srrs if (sctp_fill_user_address(sas, &laddr->ifa->address.sa)) 1307167598Srrs continue; 1308167598Srrs 1309167598Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1310167598Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + 1311167598Srrs laddr->ifa->address.sa.sa_len); 1312167598Srrs actual += laddr->ifa->address.sa.sa_len; 1313167598Srrs if (actual >= limit) { 1314167598Srrs return (actual); 1315163953Srrs } 1316163953Srrs } 1317163953Srrs } 1318163953Srrs return (actual); 1319163953Srrs} 1320163953Srrs 1321168124Srrsstatic size_t 1322168124Srrssctp_fill_up_addresses(struct sctp_inpcb *inp, 1323168124Srrs struct sctp_tcb *stcb, 1324168124Srrs size_t limit, 1325168124Srrs struct sockaddr_storage *sas) 1326168124Srrs{ 1327168124Srrs size_t size = 0; 1328168124Srrs 1329172218Srrs SCTP_IPI_ADDR_RLOCK(); 1330168124Srrs /* fill up addresses for the endpoint's default vrf */ 1331168124Srrs size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas, 1332168124Srrs inp->def_vrf_id); 1333172218Srrs SCTP_IPI_ADDR_RUNLOCK(); 1334168124Srrs return (size); 1335168124Srrs} 1336168124Srrs 1337172091Srrs/* 1338172091Srrs * NOTE: assumes addr lock is held 1339172091Srrs */ 1340163953Srrsstatic int 1341168124Srrssctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) 1342163953Srrs{ 1343163953Srrs int cnt = 0; 1344167598Srrs struct sctp_vrf *vrf = NULL; 1345163953Srrs 1346163953Srrs /* 1347163953Srrs * In both sub-set bound an bound_all cases we return the MAXIMUM 1348163953Srrs * number of addresses that you COULD get. In reality the sub-set 1349163953Srrs * bound may have an exclusion list for a given TCB OR in the 1350163953Srrs * bound-all case a TCB may NOT include the loopback or other 1351163953Srrs * addresses as well. 1352163953Srrs */ 1353167598Srrs vrf = sctp_find_vrf(vrf_id); 1354167598Srrs if (vrf == NULL) { 1355167598Srrs return (0); 1356167598Srrs } 1357163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1358167598Srrs struct sctp_ifn *sctp_ifn; 1359167598Srrs struct sctp_ifa *sctp_ifa; 1360163953Srrs 1361167598Srrs LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 1362167598Srrs LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 1363163953Srrs /* Count them if they are the right type */ 1364221249Stuexen switch (sctp_ifa->address.sa.sa_family) { 1365221249Stuexen#ifdef INET 1366221249Stuexen case AF_INET: 1367178251Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) 1368163953Srrs cnt += sizeof(struct sockaddr_in6); 1369163953Srrs else 1370163953Srrs cnt += sizeof(struct sockaddr_in); 1371221249Stuexen break; 1372221249Stuexen#endif 1373221249Stuexen#ifdef INET6 1374221249Stuexen case AF_INET6: 1375163953Srrs cnt += sizeof(struct sockaddr_in6); 1376221249Stuexen break; 1377221249Stuexen#endif 1378221249Stuexen default: 1379221249Stuexen break; 1380221249Stuexen } 1381163953Srrs } 1382163953Srrs } 1383163953Srrs } else { 1384163953Srrs struct sctp_laddr *laddr; 1385163953Srrs 1386163953Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1387221249Stuexen switch (laddr->ifa->address.sa.sa_family) { 1388221249Stuexen#ifdef INET 1389221249Stuexen case AF_INET: 1390178251Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) 1391163953Srrs cnt += sizeof(struct sockaddr_in6); 1392163953Srrs else 1393163953Srrs cnt += sizeof(struct sockaddr_in); 1394221249Stuexen break; 1395221249Stuexen#endif 1396221249Stuexen#ifdef INET6 1397221249Stuexen case AF_INET6: 1398163953Srrs cnt += sizeof(struct sockaddr_in6); 1399221249Stuexen break; 1400221249Stuexen#endif 1401221249Stuexen default: 1402221249Stuexen break; 1403221249Stuexen } 1404163953Srrs } 1405163953Srrs } 1406163953Srrs return (cnt); 1407163953Srrs} 1408163953Srrs 1409168124Srrsstatic int 1410168124Srrssctp_count_max_addresses(struct sctp_inpcb *inp) 1411168124Srrs{ 1412168124Srrs int cnt = 0; 1413166675Srrs 1414172218Srrs SCTP_IPI_ADDR_RLOCK(); 1415168124Srrs /* count addresses for the endpoint's default VRF */ 1416168124Srrs cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id); 1417172218Srrs SCTP_IPI_ADDR_RUNLOCK(); 1418168124Srrs return (cnt); 1419168124Srrs} 1420168124Srrs 1421163953Srrsstatic int 1422166675Srrssctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, 1423166675Srrs size_t optsize, void *p, int delay) 1424163953Srrs{ 1425163953Srrs int error = 0; 1426163953Srrs int creat_lock_on = 0; 1427163953Srrs struct sctp_tcb *stcb = NULL; 1428163953Srrs struct sockaddr *sa; 1429169352Srrs int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr; 1430167598Srrs uint32_t vrf_id; 1431170056Srrs int bad_addresses = 0; 1432167598Srrs sctp_assoc_t *a_id; 1433163953Srrs 1434169420Srrs SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n"); 1435163953Srrs 1436163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 1437163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 1438163953Srrs /* We are already connected AND the TCP model */ 1439171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 1440163953Srrs return (EADDRINUSE); 1441163953Srrs } 1442181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && 1443181054Srrs (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) { 1444171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1445163953Srrs return (EINVAL); 1446163953Srrs } 1447163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 1448163953Srrs SCTP_INP_RLOCK(inp); 1449163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 1450163953Srrs SCTP_INP_RUNLOCK(inp); 1451163953Srrs } 1452163953Srrs if (stcb) { 1453171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 1454163953Srrs return (EALREADY); 1455163953Srrs } 1456163953Srrs SCTP_INP_INCR_REF(inp); 1457163953Srrs SCTP_ASOC_CREATE_LOCK(inp); 1458163953Srrs creat_lock_on = 1; 1459163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 1460163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 1461171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); 1462163953Srrs error = EFAULT; 1463163953Srrs goto out_now; 1464163953Srrs } 1465166675Srrs totaddrp = (int *)optval; 1466163953Srrs totaddr = *totaddrp; 1467163953Srrs sa = (struct sockaddr *)(totaddrp + 1); 1468170056Srrs stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses); 1469170056Srrs if ((stcb != NULL) || bad_addresses) { 1470169352Srrs /* Already have or am bring up an association */ 1471169352Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1472169352Srrs creat_lock_on = 0; 1473170931Srrs if (stcb) 1474170931Srrs SCTP_TCB_UNLOCK(stcb); 1475171943Srrs if (bad_addresses == 0) { 1476171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 1477170056Srrs error = EALREADY; 1478171943Srrs } 1479169352Srrs goto out_now; 1480163953Srrs } 1481163953Srrs#ifdef INET6 1482163953Srrs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 1483163953Srrs (num_v6 > 0)) { 1484163953Srrs error = EINVAL; 1485163953Srrs goto out_now; 1486163953Srrs } 1487163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 1488163953Srrs (num_v4 > 0)) { 1489163953Srrs struct in6pcb *inp6; 1490163953Srrs 1491163953Srrs inp6 = (struct in6pcb *)inp; 1492166023Srrs if (SCTP_IPV6_V6ONLY(inp6)) { 1493163953Srrs /* 1494163953Srrs * if IPV6_V6ONLY flag, ignore connections destined 1495163953Srrs * to a v4 addr or v4-mapped addr 1496163953Srrs */ 1497171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1498163953Srrs error = EINVAL; 1499163953Srrs goto out_now; 1500163953Srrs } 1501163953Srrs } 1502163953Srrs#endif /* INET6 */ 1503163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 1504163953Srrs SCTP_PCB_FLAGS_UNBOUND) { 1505163953Srrs /* Bind a ephemeral port */ 1506171572Srrs error = sctp_inpcb_bind(so, NULL, NULL, p); 1507163953Srrs if (error) { 1508163953Srrs goto out_now; 1509163953Srrs } 1510163953Srrs } 1511167695Srrs /* FIX ME: do we want to pass in a vrf on the connect call? */ 1512167695Srrs vrf_id = inp->def_vrf_id; 1513167695Srrs 1514181054Srrs 1515163953Srrs /* We are GOOD to go */ 1516206137Stuexen stcb = sctp_aloc_assoc(inp, sa, &error, 0, vrf_id, 1517171531Srrs (struct thread *)p 1518171531Srrs ); 1519163953Srrs if (stcb == NULL) { 1520163953Srrs /* Gak! no memory */ 1521163953Srrs goto out_now; 1522163953Srrs } 1523225559Stuexen if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 1524225559Stuexen stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 1525225559Stuexen /* Set the connected flag so we can queue data */ 1526225559Stuexen soisconnecting(so); 1527225559Stuexen } 1528171943Srrs SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); 1529163953Srrs /* move to second address */ 1530221249Stuexen switch (sa->sa_family) { 1531221249Stuexen#ifdef INET 1532221249Stuexen case AF_INET: 1533163953Srrs sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in)); 1534221249Stuexen break; 1535221249Stuexen#endif 1536221249Stuexen#ifdef INET6 1537221249Stuexen case AF_INET6: 1538163953Srrs sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6)); 1539221249Stuexen break; 1540221249Stuexen#endif 1541221249Stuexen default: 1542221249Stuexen break; 1543221249Stuexen } 1544163953Srrs 1545170056Srrs error = 0; 1546223132Stuexen sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error); 1547167598Srrs /* Fill in the return id */ 1548170056Srrs if (error) { 1549207924Srrs (void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6); 1550170056Srrs goto out_now; 1551170056Srrs } 1552167598Srrs a_id = (sctp_assoc_t *) optval; 1553167598Srrs *a_id = sctp_get_associd(stcb); 1554163953Srrs 1555163953Srrs /* initialize authentication parameters for the assoc */ 1556163953Srrs sctp_initialize_auth_params(inp, stcb); 1557163953Srrs 1558163953Srrs if (delay) { 1559163953Srrs /* doing delayed connection */ 1560163953Srrs stcb->asoc.delayed_connection = 1; 1561163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination); 1562163953Srrs } else { 1563169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 1564172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 1565163953Srrs } 1566163953Srrs SCTP_TCB_UNLOCK(stcb); 1567163953Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 1568163953Srrs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 1569163953Srrs /* Set the connected flag so we can queue data */ 1570163953Srrs soisconnecting(so); 1571163953Srrs } 1572163953Srrsout_now: 1573169655Srrs if (creat_lock_on) { 1574163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1575169655Srrs } 1576163953Srrs SCTP_INP_DECR_REF(inp); 1577228907Stuexen return (error); 1578163953Srrs} 1579163953Srrs 1580169420Srrs#define SCTP_FIND_STCB(inp, stcb, assoc_id) { \ 1581169655Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||\ 1582169655Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { \ 1583166675Srrs SCTP_INP_RLOCK(inp); \ 1584166675Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); \ 1585169655Srrs if (stcb) { \ 1586166675Srrs SCTP_TCB_LOCK(stcb); \ 1587169655Srrs } \ 1588166675Srrs SCTP_INP_RUNLOCK(inp); \ 1589223132Stuexen } else if (assoc_id > SCTP_ALL_ASSOC) { \ 1590166675Srrs stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \ 1591166675Srrs if (stcb == NULL) { \ 1592171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \ 1593166675Srrs error = ENOENT; \ 1594166675Srrs break; \ 1595166675Srrs } \ 1596166675Srrs } else { \ 1597166675Srrs stcb = NULL; \ 1598169420Srrs } \ 1599169420Srrs } 1600163953Srrs 1601169420Srrs 1602234464Stuexen#define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\ 1603166675Srrs if (size < sizeof(type)) { \ 1604171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); \ 1605166675Srrs error = EINVAL; \ 1606166675Srrs break; \ 1607166675Srrs } else { \ 1608166675Srrs destp = (type *)srcp; \ 1609169420Srrs } \ 1610169420Srrs } 1611163953Srrs 1612163953Srrsstatic int 1613166675Srrssctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, 1614166675Srrs void *p) 1615163953Srrs{ 1616171943Srrs struct sctp_inpcb *inp = NULL; 1617166675Srrs int error, val = 0; 1618163953Srrs struct sctp_tcb *stcb = NULL; 1619163953Srrs 1620166675Srrs if (optval == NULL) { 1621171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1622166675Srrs return (EINVAL); 1623166675Srrs } 1624163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 1625233005Stuexen if (inp == NULL) { 1626171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1627163953Srrs return EINVAL; 1628171943Srrs } 1629163953Srrs error = 0; 1630163953Srrs 1631166675Srrs switch (optname) { 1632163953Srrs case SCTP_NODELAY: 1633163953Srrs case SCTP_AUTOCLOSE: 1634163953Srrs case SCTP_EXPLICIT_EOR: 1635163953Srrs case SCTP_AUTO_ASCONF: 1636163953Srrs case SCTP_DISABLE_FRAGMENTS: 1637163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 1638163953Srrs case SCTP_USE_EXT_RCVINFO: 1639163953Srrs SCTP_INP_RLOCK(inp); 1640166675Srrs switch (optname) { 1641163953Srrs case SCTP_DISABLE_FRAGMENTS: 1642166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT); 1643163953Srrs break; 1644163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 1645166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4); 1646163953Srrs break; 1647163953Srrs case SCTP_AUTO_ASCONF: 1648171943Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1649171943Srrs /* only valid for bound all sockets */ 1650171943Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); 1651171943Srrs } else { 1652171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1653171943Srrs error = EINVAL; 1654171943Srrs goto flags_out; 1655171943Srrs } 1656163953Srrs break; 1657163953Srrs case SCTP_EXPLICIT_EOR: 1658166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); 1659163953Srrs break; 1660163953Srrs case SCTP_NODELAY: 1661166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY); 1662163953Srrs break; 1663163953Srrs case SCTP_USE_EXT_RCVINFO: 1664166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO); 1665163953Srrs break; 1666163953Srrs case SCTP_AUTOCLOSE: 1667163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) 1668166675Srrs val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time); 1669163953Srrs else 1670166675Srrs val = 0; 1671163953Srrs break; 1672163953Srrs 1673163953Srrs default: 1674171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 1675163953Srrs error = ENOPROTOOPT; 1676163953Srrs } /* end switch (sopt->sopt_name) */ 1677166675Srrs if (*optsize < sizeof(val)) { 1678171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1679163953Srrs error = EINVAL; 1680163953Srrs } 1681171943Srrsflags_out: 1682163953Srrs SCTP_INP_RUNLOCK(inp); 1683163953Srrs if (error == 0) { 1684163953Srrs /* return the option value */ 1685166675Srrs *(int *)optval = val; 1686166675Srrs *optsize = sizeof(val); 1687163953Srrs } 1688163953Srrs break; 1689170091Srrs case SCTP_GET_PACKET_LOG: 1690170091Srrs { 1691170091Srrs#ifdef SCTP_PACKET_LOGGING 1692170091Srrs uint8_t *target; 1693170091Srrs int ret; 1694167598Srrs 1695170091Srrs SCTP_CHECK_AND_CAST(target, optval, uint8_t, *optsize); 1696170091Srrs ret = sctp_copy_out_packet_log(target, (int)*optsize); 1697170091Srrs *optsize = ret; 1698170091Srrs#else 1699171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 1700170091Srrs error = EOPNOTSUPP; 1701170091Srrs#endif 1702170091Srrs break; 1703170091Srrs } 1704181054Srrs case SCTP_REUSE_PORT: 1705181054Srrs { 1706181054Srrs uint32_t *value; 1707181054Srrs 1708181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) { 1709181054Srrs /* Can't do this for a 1-m socket */ 1710181054Srrs error = EINVAL; 1711181054Srrs break; 1712181054Srrs } 1713181054Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1714181054Srrs *value = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE); 1715181054Srrs *optsize = sizeof(uint32_t); 1716223132Stuexen break; 1717181054Srrs } 1718163953Srrs case SCTP_PARTIAL_DELIVERY_POINT: 1719163953Srrs { 1720166675Srrs uint32_t *value; 1721166675Srrs 1722166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1723166675Srrs *value = inp->partial_delivery_point; 1724166675Srrs *optsize = sizeof(uint32_t); 1725223132Stuexen break; 1726163953Srrs } 1727163953Srrs case SCTP_FRAGMENT_INTERLEAVE: 1728163953Srrs { 1729166675Srrs uint32_t *value; 1730166675Srrs 1731166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1732168943Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) { 1733168943Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) { 1734168943Srrs *value = SCTP_FRAG_LEVEL_2; 1735168943Srrs } else { 1736168943Srrs *value = SCTP_FRAG_LEVEL_1; 1737168943Srrs } 1738168943Srrs } else { 1739168943Srrs *value = SCTP_FRAG_LEVEL_0; 1740168943Srrs } 1741166675Srrs *optsize = sizeof(uint32_t); 1742223132Stuexen break; 1743163953Srrs } 1744163953Srrs case SCTP_CMT_ON_OFF: 1745163953Srrs { 1746166675Srrs struct sctp_assoc_value *av; 1747166675Srrs 1748166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1749211944Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1750211944Stuexen if (stcb) { 1751211944Stuexen av->assoc_value = stcb->asoc.sctp_cmt_on_off; 1752211944Stuexen SCTP_TCB_UNLOCK(stcb); 1753166675Srrs } else { 1754224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1755224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1756224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1757223132Stuexen SCTP_INP_RLOCK(inp); 1758223132Stuexen av->assoc_value = inp->sctp_cmt_on_off; 1759223132Stuexen SCTP_INP_RUNLOCK(inp); 1760223132Stuexen } else { 1761223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1762223132Stuexen error = EINVAL; 1763223132Stuexen } 1764163953Srrs } 1765223132Stuexen if (error == 0) { 1766223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1767223132Stuexen } 1768223132Stuexen break; 1769163953Srrs } 1770171440Srrs case SCTP_PLUGGABLE_CC: 1771171440Srrs { 1772171440Srrs struct sctp_assoc_value *av; 1773171440Srrs 1774171440Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1775171440Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1776171440Srrs if (stcb) { 1777171440Srrs av->assoc_value = stcb->asoc.congestion_control_module; 1778171440Srrs SCTP_TCB_UNLOCK(stcb); 1779171440Srrs } else { 1780224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1781224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1782224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1783223132Stuexen SCTP_INP_RLOCK(inp); 1784223132Stuexen av->assoc_value = inp->sctp_ep.sctp_default_cc_module; 1785223132Stuexen SCTP_INP_RUNLOCK(inp); 1786223132Stuexen } else { 1787223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1788223132Stuexen error = EINVAL; 1789223132Stuexen } 1790171440Srrs } 1791223132Stuexen if (error == 0) { 1792223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1793223132Stuexen } 1794223132Stuexen break; 1795171440Srrs } 1796219057Srrs case SCTP_CC_OPTION: 1797219057Srrs { 1798219057Srrs struct sctp_cc_option *cc_opt; 1799219057Srrs 1800219057Srrs SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, *optsize); 1801219057Srrs SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id); 1802219057Srrs if (stcb == NULL) { 1803219057Srrs error = EINVAL; 1804219057Srrs } else { 1805219057Srrs if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) { 1806219057Srrs error = ENOTSUP; 1807219057Srrs } else { 1808223132Stuexen error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 0, cc_opt); 1809223132Stuexen *optsize = sizeof(struct sctp_cc_option); 1810219057Srrs } 1811219057Srrs SCTP_TCB_UNLOCK(stcb); 1812219057Srrs } 1813223132Stuexen break; 1814219057Srrs } 1815217760Stuexen case SCTP_PLUGGABLE_SS: 1816217760Stuexen { 1817217760Stuexen struct sctp_assoc_value *av; 1818217760Stuexen 1819217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1820217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1821217760Stuexen if (stcb) { 1822217760Stuexen av->assoc_value = stcb->asoc.stream_scheduling_module; 1823217760Stuexen SCTP_TCB_UNLOCK(stcb); 1824217760Stuexen } else { 1825224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1826224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1827224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1828223132Stuexen SCTP_INP_RLOCK(inp); 1829223132Stuexen av->assoc_value = inp->sctp_ep.sctp_default_ss_module; 1830223132Stuexen SCTP_INP_RUNLOCK(inp); 1831223132Stuexen } else { 1832223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1833223132Stuexen error = EINVAL; 1834223132Stuexen } 1835217760Stuexen } 1836223132Stuexen if (error == 0) { 1837223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1838223132Stuexen } 1839223132Stuexen break; 1840217760Stuexen } 1841217760Stuexen case SCTP_SS_VALUE: 1842217760Stuexen { 1843217760Stuexen struct sctp_stream_value *av; 1844217760Stuexen 1845217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize); 1846217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1847217760Stuexen if (stcb) { 1848217760Stuexen if (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], 1849217760Stuexen &av->stream_value) < 0) { 1850217760Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1851217760Stuexen error = EINVAL; 1852217760Stuexen } else { 1853223132Stuexen *optsize = sizeof(struct sctp_stream_value); 1854217760Stuexen } 1855217760Stuexen SCTP_TCB_UNLOCK(stcb); 1856217760Stuexen } else { 1857217760Stuexen /* 1858217760Stuexen * Can't get stream value without 1859217760Stuexen * association 1860217760Stuexen */ 1861217760Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1862217760Stuexen error = EINVAL; 1863217760Stuexen } 1864223132Stuexen break; 1865217760Stuexen } 1866163953Srrs case SCTP_GET_ADDR_LEN: 1867163953Srrs { 1868163953Srrs struct sctp_assoc_value *av; 1869163953Srrs 1870166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1871163953Srrs error = EINVAL; 1872167598Srrs#ifdef INET 1873163953Srrs if (av->assoc_value == AF_INET) { 1874163953Srrs av->assoc_value = sizeof(struct sockaddr_in); 1875163953Srrs error = 0; 1876163953Srrs } 1877163953Srrs#endif 1878167598Srrs#ifdef INET6 1879163953Srrs if (av->assoc_value == AF_INET6) { 1880163953Srrs av->assoc_value = sizeof(struct sockaddr_in6); 1881163953Srrs error = 0; 1882163953Srrs } 1883163953Srrs#endif 1884172091Srrs if (error) { 1885171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1886223132Stuexen } else { 1887223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1888172091Srrs } 1889223132Stuexen break; 1890163953Srrs } 1891169655Srrs case SCTP_GET_ASSOC_NUMBER: 1892163953Srrs { 1893169655Srrs uint32_t *value, cnt; 1894163953Srrs 1895169655Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1896163953Srrs cnt = 0; 1897163953Srrs SCTP_INP_RLOCK(inp); 1898169655Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 1899169655Srrs cnt++; 1900163953Srrs } 1901169655Srrs SCTP_INP_RUNLOCK(inp); 1902169655Srrs *value = cnt; 1903169655Srrs *optsize = sizeof(uint32_t); 1904223132Stuexen break; 1905169655Srrs } 1906169655Srrs case SCTP_GET_ASSOC_ID_LIST: 1907169655Srrs { 1908169655Srrs struct sctp_assoc_ids *ids; 1909169655Srrs unsigned int at, limit; 1910169655Srrs 1911169655Srrs SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize); 1912163953Srrs at = 0; 1913185694Srrs limit = (*optsize - sizeof(uint32_t)) / sizeof(sctp_assoc_t); 1914169655Srrs SCTP_INP_RLOCK(inp); 1915169655Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 1916169655Srrs if (at < limit) { 1917169655Srrs ids->gaids_assoc_id[at++] = sctp_get_associd(stcb); 1918169655Srrs } else { 1919169655Srrs error = EINVAL; 1920171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1921163953Srrs break; 1922163953Srrs } 1923163953Srrs } 1924163953Srrs SCTP_INP_RUNLOCK(inp); 1925223132Stuexen if (error == 0) { 1926223132Stuexen ids->gaids_number_of_ids = at; 1927223132Stuexen *optsize = ((at * sizeof(sctp_assoc_t)) + sizeof(uint32_t)); 1928223132Stuexen } 1929223132Stuexen break; 1930163953Srrs } 1931163953Srrs case SCTP_CONTEXT: 1932163953Srrs { 1933163953Srrs struct sctp_assoc_value *av; 1934163953Srrs 1935166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1936166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1937166675Srrs 1938166675Srrs if (stcb) { 1939166675Srrs av->assoc_value = stcb->asoc.context; 1940166675Srrs SCTP_TCB_UNLOCK(stcb); 1941163953Srrs } else { 1942224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1943224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1944224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1945223132Stuexen SCTP_INP_RLOCK(inp); 1946223132Stuexen av->assoc_value = inp->sctp_context; 1947223132Stuexen SCTP_INP_RUNLOCK(inp); 1948223132Stuexen } else { 1949223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1950223132Stuexen error = EINVAL; 1951223132Stuexen } 1952163953Srrs } 1953223132Stuexen if (error == 0) { 1954223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1955223132Stuexen } 1956223132Stuexen break; 1957163953Srrs } 1958167598Srrs case SCTP_VRF_ID: 1959167598Srrs { 1960170056Srrs uint32_t *default_vrfid; 1961167598Srrs 1962170056Srrs SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize); 1963170056Srrs *default_vrfid = inp->def_vrf_id; 1964223132Stuexen *optsize = sizeof(uint32_t); 1965167598Srrs break; 1966167598Srrs } 1967167598Srrs case SCTP_GET_ASOC_VRF: 1968167598Srrs { 1969167598Srrs struct sctp_assoc_value *id; 1970167598Srrs 1971167598Srrs SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize); 1972167598Srrs SCTP_FIND_STCB(inp, stcb, id->assoc_id); 1973167598Srrs if (stcb == NULL) { 1974167598Srrs error = EINVAL; 1975171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1976223132Stuexen } else { 1977223132Stuexen id->assoc_value = stcb->asoc.vrf_id; 1978223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1979167598Srrs } 1980167598Srrs break; 1981167598Srrs } 1982167598Srrs case SCTP_GET_VRF_IDS: 1983167598Srrs { 1984171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 1985167598Srrs error = EOPNOTSUPP; 1986167598Srrs break; 1987167598Srrs } 1988163953Srrs case SCTP_GET_NONCE_VALUES: 1989163953Srrs { 1990163953Srrs struct sctp_get_nonce_values *gnv; 1991163953Srrs 1992166675Srrs SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize); 1993166675Srrs SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id); 1994166675Srrs 1995166675Srrs if (stcb) { 1996163953Srrs gnv->gn_peers_tag = stcb->asoc.peer_vtag; 1997163953Srrs gnv->gn_local_tag = stcb->asoc.my_vtag; 1998163953Srrs SCTP_TCB_UNLOCK(stcb); 1999223132Stuexen *optsize = sizeof(struct sctp_get_nonce_values); 2000166675Srrs } else { 2001171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 2002166675Srrs error = ENOTCONN; 2003163953Srrs } 2004223132Stuexen break; 2005163953Srrs } 2006170056Srrs case SCTP_DELAYED_SACK: 2007163953Srrs { 2008170056Srrs struct sctp_sack_info *sack; 2009163953Srrs 2010170056Srrs SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, *optsize); 2011170056Srrs SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); 2012166675Srrs if (stcb) { 2013170056Srrs sack->sack_delay = stcb->asoc.delayed_ack; 2014170056Srrs sack->sack_freq = stcb->asoc.sack_freq; 2015166675Srrs SCTP_TCB_UNLOCK(stcb); 2016166675Srrs } else { 2017224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2018224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2019224918Stuexen (sack->sack_assoc_id == SCTP_FUTURE_ASSOC)) { 2020223132Stuexen SCTP_INP_RLOCK(inp); 2021223132Stuexen sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); 2022223132Stuexen sack->sack_freq = inp->sctp_ep.sctp_sack_freq; 2023223132Stuexen SCTP_INP_RUNLOCK(inp); 2024223132Stuexen } else { 2025223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2026223132Stuexen error = EINVAL; 2027223132Stuexen } 2028163953Srrs } 2029223132Stuexen if (error == 0) { 2030223132Stuexen *optsize = sizeof(struct sctp_sack_info); 2031223132Stuexen } 2032223132Stuexen break; 2033163953Srrs } 2034163953Srrs case SCTP_GET_SNDBUF_USE: 2035166675Srrs { 2036163953Srrs struct sctp_sockstat *ss; 2037163953Srrs 2038166675Srrs SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize); 2039166675Srrs SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id); 2040166675Srrs 2041166675Srrs if (stcb) { 2042166675Srrs ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size; 2043166675Srrs ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue + 2044166675Srrs stcb->asoc.size_on_all_streams); 2045166675Srrs SCTP_TCB_UNLOCK(stcb); 2046223132Stuexen *optsize = sizeof(struct sctp_sockstat); 2047166675Srrs } else { 2048171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 2049163953Srrs error = ENOTCONN; 2050163953Srrs } 2051223132Stuexen break; 2052163953Srrs } 2053170056Srrs case SCTP_MAX_BURST: 2054163953Srrs { 2055217895Stuexen struct sctp_assoc_value *av; 2056163953Srrs 2057217895Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 2058217895Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2059166675Srrs 2060217895Stuexen if (stcb) { 2061217895Stuexen av->assoc_value = stcb->asoc.max_burst; 2062217895Stuexen SCTP_TCB_UNLOCK(stcb); 2063217894Stuexen } else { 2064224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2065224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2066224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 2067223132Stuexen SCTP_INP_RLOCK(inp); 2068223132Stuexen av->assoc_value = inp->sctp_ep.max_burst; 2069223132Stuexen SCTP_INP_RUNLOCK(inp); 2070223132Stuexen } else { 2071223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2072223132Stuexen error = EINVAL; 2073223132Stuexen } 2074217894Stuexen } 2075223132Stuexen if (error == 0) { 2076223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 2077223132Stuexen } 2078223132Stuexen break; 2079163953Srrs } 2080163953Srrs case SCTP_MAXSEG: 2081163953Srrs { 2082167598Srrs struct sctp_assoc_value *av; 2083163953Srrs int ovh; 2084163953Srrs 2085167598Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 2086170056Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2087163953Srrs 2088167598Srrs if (stcb) { 2089167598Srrs av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc); 2090167598Srrs SCTP_TCB_UNLOCK(stcb); 2091163953Srrs } else { 2092224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2093224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2094224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 2095223132Stuexen SCTP_INP_RLOCK(inp); 2096223132Stuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2097223132Stuexen ovh = SCTP_MED_OVERHEAD; 2098223132Stuexen } else { 2099223132Stuexen ovh = SCTP_MED_V4_OVERHEAD; 2100223132Stuexen } 2101223132Stuexen if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT) 2102223132Stuexen av->assoc_value = 0; 2103223132Stuexen else 2104223132Stuexen av->assoc_value = inp->sctp_frag_point - ovh; 2105223132Stuexen SCTP_INP_RUNLOCK(inp); 2106167598Srrs } else { 2107223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2108223132Stuexen error = EINVAL; 2109167598Srrs } 2110163953Srrs } 2111223132Stuexen if (error == 0) { 2112223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 2113223132Stuexen } 2114223132Stuexen break; 2115163953Srrs } 2116163953Srrs case SCTP_GET_STAT_LOG: 2117167598Srrs error = sctp_fill_stat_log(optval, optsize); 2118163953Srrs break; 2119163953Srrs case SCTP_EVENTS: 2120163953Srrs { 2121163953Srrs struct sctp_event_subscribe *events; 2122163953Srrs 2123166675Srrs SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize); 2124223132Stuexen memset(events, 0, sizeof(struct sctp_event_subscribe)); 2125163953Srrs SCTP_INP_RLOCK(inp); 2126163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) 2127163953Srrs events->sctp_data_io_event = 1; 2128163953Srrs 2129163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT)) 2130163953Srrs events->sctp_association_event = 1; 2131163953Srrs 2132163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT)) 2133163953Srrs events->sctp_address_event = 1; 2134163953Srrs 2135163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) 2136163953Srrs events->sctp_send_failure_event = 1; 2137163953Srrs 2138163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR)) 2139163953Srrs events->sctp_peer_error_event = 1; 2140163953Srrs 2141163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) 2142163953Srrs events->sctp_shutdown_event = 1; 2143163953Srrs 2144163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT)) 2145163953Srrs events->sctp_partial_delivery_event = 1; 2146163953Srrs 2147163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) 2148163953Srrs events->sctp_adaptation_layer_event = 1; 2149163953Srrs 2150163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT)) 2151163953Srrs events->sctp_authentication_event = 1; 2152163953Srrs 2153185694Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT)) 2154185694Srrs events->sctp_sender_dry_event = 1; 2155185694Srrs 2156163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) 2157202520Srrs events->sctp_stream_reset_event = 1; 2158163953Srrs SCTP_INP_RUNLOCK(inp); 2159166675Srrs *optsize = sizeof(struct sctp_event_subscribe); 2160223132Stuexen break; 2161163953Srrs } 2162163953Srrs case SCTP_ADAPTATION_LAYER: 2163166675Srrs { 2164166675Srrs uint32_t *value; 2165166675Srrs 2166166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2167166675Srrs 2168166675Srrs SCTP_INP_RLOCK(inp); 2169166675Srrs *value = inp->sctp_ep.adaptation_layer_indicator; 2170166675Srrs SCTP_INP_RUNLOCK(inp); 2171166675Srrs *optsize = sizeof(uint32_t); 2172223132Stuexen break; 2173163953Srrs } 2174163953Srrs case SCTP_SET_INITIAL_DBG_SEQ: 2175166675Srrs { 2176166675Srrs uint32_t *value; 2177166675Srrs 2178166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2179166675Srrs SCTP_INP_RLOCK(inp); 2180166675Srrs *value = inp->sctp_ep.initial_sequence_debug; 2181166675Srrs SCTP_INP_RUNLOCK(inp); 2182166675Srrs *optsize = sizeof(uint32_t); 2183223132Stuexen break; 2184163953Srrs } 2185163953Srrs case SCTP_GET_LOCAL_ADDR_SIZE: 2186166675Srrs { 2187166675Srrs uint32_t *value; 2188166675Srrs 2189166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2190166675Srrs SCTP_INP_RLOCK(inp); 2191168124Srrs *value = sctp_count_max_addresses(inp); 2192166675Srrs SCTP_INP_RUNLOCK(inp); 2193166675Srrs *optsize = sizeof(uint32_t); 2194223132Stuexen break; 2195163953Srrs } 2196163953Srrs case SCTP_GET_REMOTE_ADDR_SIZE: 2197163953Srrs { 2198166675Srrs uint32_t *value; 2199166675Srrs size_t size; 2200163953Srrs struct sctp_nets *net; 2201163953Srrs 2202166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2203166675Srrs /* FIXME MT: change to sctp_assoc_value? */ 2204166675Srrs SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value); 2205166675Srrs 2206166675Srrs if (stcb) { 2207166675Srrs size = 0; 2208166675Srrs /* Count the sizes */ 2209166675Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 2210221249Stuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 2211166675Srrs size += sizeof(struct sockaddr_in6); 2212166675Srrs } else { 2213221249Stuexen switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) { 2214221249Stuexen#ifdef INET 2215221249Stuexen case AF_INET: 2216221249Stuexen size += sizeof(struct sockaddr_in); 2217221249Stuexen break; 2218221249Stuexen#endif 2219221249Stuexen#ifdef INET6 2220221249Stuexen case AF_INET6: 2221221249Stuexen size += sizeof(struct sockaddr_in6); 2222221249Stuexen break; 2223221249Stuexen#endif 2224221249Stuexen default: 2225221249Stuexen break; 2226221249Stuexen } 2227166675Srrs } 2228163953Srrs } 2229166675Srrs SCTP_TCB_UNLOCK(stcb); 2230166675Srrs *value = (uint32_t) size; 2231223132Stuexen *optsize = sizeof(uint32_t); 2232166675Srrs } else { 2233171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 2234166675Srrs error = ENOTCONN; 2235163953Srrs } 2236223132Stuexen break; 2237163953Srrs } 2238163953Srrs case SCTP_GET_PEER_ADDRESSES: 2239163953Srrs /* 2240163953Srrs * Get the address information, an array is passed in to 2241163953Srrs * fill up we pack it. 2242163953Srrs */ 2243163953Srrs { 2244166675Srrs size_t cpsz, left; 2245163953Srrs struct sockaddr_storage *sas; 2246163953Srrs struct sctp_nets *net; 2247163953Srrs struct sctp_getaddresses *saddr; 2248163953Srrs 2249166675Srrs SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); 2250166675Srrs SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); 2251163953Srrs 2252166675Srrs if (stcb) { 2253166675Srrs left = (*optsize) - sizeof(struct sctp_getaddresses); 2254166675Srrs *optsize = sizeof(struct sctp_getaddresses); 2255166675Srrs sas = (struct sockaddr_storage *)&saddr->addr[0]; 2256166675Srrs 2257166675Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 2258221249Stuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 2259166675Srrs cpsz = sizeof(struct sockaddr_in6); 2260166675Srrs } else { 2261221249Stuexen switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) { 2262221249Stuexen#ifdef INET 2263221249Stuexen case AF_INET: 2264221249Stuexen cpsz = sizeof(struct sockaddr_in); 2265221249Stuexen break; 2266221249Stuexen#endif 2267221249Stuexen#ifdef INET6 2268221249Stuexen case AF_INET6: 2269221249Stuexen cpsz = sizeof(struct sockaddr_in6); 2270221249Stuexen break; 2271221249Stuexen#endif 2272221249Stuexen default: 2273221249Stuexen cpsz = 0; 2274221249Stuexen break; 2275221249Stuexen } 2276221249Stuexen } 2277221249Stuexen if (cpsz == 0) { 2278166675Srrs break; 2279166675Srrs } 2280166675Srrs if (left < cpsz) { 2281166675Srrs /* not enough room. */ 2282166675Srrs break; 2283166675Srrs } 2284221249Stuexen#if defined(INET) && defined(INET6) 2285178251Srrs if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) && 2286166675Srrs (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET)) { 2287166675Srrs /* Must map the address */ 2288166675Srrs in6_sin_2_v4mapsin6((struct sockaddr_in *)&net->ro._l_addr, 2289166675Srrs (struct sockaddr_in6 *)sas); 2290166675Srrs } else { 2291178251Srrs#endif 2292166675Srrs memcpy(sas, &net->ro._l_addr, cpsz); 2293221249Stuexen#if defined(INET) && defined(INET6) 2294166675Srrs } 2295178251Srrs#endif 2296166675Srrs ((struct sockaddr_in *)sas)->sin_port = stcb->rport; 2297166675Srrs 2298166675Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz); 2299166675Srrs left -= cpsz; 2300166675Srrs *optsize += cpsz; 2301163953Srrs } 2302166675Srrs SCTP_TCB_UNLOCK(stcb); 2303166675Srrs } else { 2304171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 2305166675Srrs error = ENOENT; 2306163953Srrs } 2307223132Stuexen break; 2308163953Srrs } 2309163953Srrs case SCTP_GET_LOCAL_ADDRESSES: 2310163953Srrs { 2311166675Srrs size_t limit, actual; 2312163953Srrs struct sockaddr_storage *sas; 2313163953Srrs struct sctp_getaddresses *saddr; 2314163953Srrs 2315166675Srrs SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); 2316166675Srrs SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); 2317163953Srrs 2318163953Srrs sas = (struct sockaddr_storage *)&saddr->addr[0]; 2319166675Srrs limit = *optsize - sizeof(sctp_assoc_t); 2320168124Srrs actual = sctp_fill_up_addresses(inp, stcb, limit, sas); 2321169655Srrs if (stcb) { 2322163953Srrs SCTP_TCB_UNLOCK(stcb); 2323169655Srrs } 2324166675Srrs *optsize = sizeof(struct sockaddr_storage) + actual; 2325223132Stuexen break; 2326163953Srrs } 2327163953Srrs case SCTP_PEER_ADDR_PARAMS: 2328163953Srrs { 2329163953Srrs struct sctp_paddrparams *paddrp; 2330163953Srrs struct sctp_nets *net; 2331163953Srrs 2332166675Srrs SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize); 2333166675Srrs SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); 2334163953Srrs 2335163953Srrs net = NULL; 2336166675Srrs if (stcb) { 2337166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address); 2338166675Srrs } else { 2339166675Srrs /* 2340166675Srrs * We increment here since 2341166675Srrs * sctp_findassociation_ep_addr() wil do a 2342166675Srrs * decrement if it finds the stcb as long as 2343166675Srrs * the locked tcb (last argument) is NOT a 2344166675Srrs * TCB.. aka NULL. 2345166675Srrs */ 2346166675Srrs SCTP_INP_INCR_REF(inp); 2347166675Srrs stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddrp->spp_address, &net, NULL, NULL); 2348163953Srrs if (stcb == NULL) { 2349166675Srrs SCTP_INP_DECR_REF(inp); 2350163953Srrs } 2351163953Srrs } 2352171943Srrs if (stcb && (net == NULL)) { 2353171943Srrs struct sockaddr *sa; 2354163953Srrs 2355171943Srrs sa = (struct sockaddr *)&paddrp->spp_address; 2356221249Stuexen#ifdef INET 2357171943Srrs if (sa->sa_family == AF_INET) { 2358171943Srrs struct sockaddr_in *sin; 2359171943Srrs 2360171943Srrs sin = (struct sockaddr_in *)sa; 2361171943Srrs if (sin->sin_addr.s_addr) { 2362171943Srrs error = EINVAL; 2363171943Srrs SCTP_TCB_UNLOCK(stcb); 2364171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2365171943Srrs break; 2366171943Srrs } 2367221249Stuexen } else 2368221249Stuexen#endif 2369221249Stuexen#ifdef INET6 2370221249Stuexen if (sa->sa_family == AF_INET6) { 2371171943Srrs struct sockaddr_in6 *sin6; 2372171943Srrs 2373171943Srrs sin6 = (struct sockaddr_in6 *)sa; 2374171943Srrs if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 2375171943Srrs error = EINVAL; 2376171943Srrs SCTP_TCB_UNLOCK(stcb); 2377171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2378171943Srrs break; 2379171943Srrs } 2380221249Stuexen } else 2381221249Stuexen#endif 2382221249Stuexen { 2383171943Srrs error = EAFNOSUPPORT; 2384171943Srrs SCTP_TCB_UNLOCK(stcb); 2385171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2386171943Srrs break; 2387171943Srrs } 2388171943Srrs } 2389163953Srrs if (stcb) { 2390224641Stuexen /* Applies to the specific association */ 2391163953Srrs paddrp->spp_flags = 0; 2392163953Srrs if (net) { 2393170056Srrs int ovh; 2394170056Srrs 2395170056Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2396170056Srrs ovh = SCTP_MED_OVERHEAD; 2397170056Srrs } else { 2398170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 2399170056Srrs } 2400170056Srrs 2401224641Stuexen paddrp->spp_hbinterval = net->heart_beat_delay; 2402163953Srrs paddrp->spp_pathmaxrxt = net->failure_threshold; 2403170056Srrs paddrp->spp_pathmtu = net->mtu - ovh; 2404163953Srrs /* get flags for HB */ 2405225635Stuexen if (net->dest_state & SCTP_ADDR_NOHB) { 2406163953Srrs paddrp->spp_flags |= SPP_HB_DISABLE; 2407225635Stuexen } else { 2408163953Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 2409225635Stuexen } 2410163953Srrs /* get flags for PMTU */ 2411225635Stuexen if (net->dest_state & SCTP_ADDR_NO_PMTUD) { 2412163953Srrs paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2413163953Srrs } else { 2414163953Srrs paddrp->spp_flags |= SPP_PMTUD_DISABLE; 2415163953Srrs } 2416225549Stuexen if (net->dscp & 0x01) { 2417226252Stuexen paddrp->spp_dscp = net->dscp & 0xfc; 2418224870Stuexen paddrp->spp_flags |= SPP_DSCP; 2419163953Srrs } 2420167598Srrs#ifdef INET6 2421225549Stuexen if ((net->ro._l_addr.sa.sa_family == AF_INET6) && 2422225549Stuexen (net->flowlabel & 0x80000000)) { 2423225549Stuexen paddrp->spp_ipv6_flowlabel = net->flowlabel & 0x000fffff; 2424163953Srrs paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2425163953Srrs } 2426163953Srrs#endif 2427163953Srrs } else { 2428163953Srrs /* 2429163953Srrs * No destination so return default 2430163953Srrs * value 2431163953Srrs */ 2432163953Srrs paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure; 2433163953Srrs paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc); 2434225549Stuexen if (stcb->asoc.default_dscp & 0x01) { 2435226252Stuexen paddrp->spp_dscp = stcb->asoc.default_dscp & 0xfc; 2436225549Stuexen paddrp->spp_flags |= SPP_DSCP; 2437225549Stuexen } 2438167598Srrs#ifdef INET6 2439225549Stuexen if (stcb->asoc.default_flowlabel & 0x80000000) { 2440225549Stuexen paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel & 0x000fffff; 2441225549Stuexen paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2442225549Stuexen } 2443163953Srrs#endif 2444163953Srrs /* default settings should be these */ 2445225635Stuexen if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { 2446224641Stuexen paddrp->spp_flags |= SPP_HB_DISABLE; 2447224641Stuexen } else { 2448163953Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 2449163953Srrs } 2450225635Stuexen if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) { 2451225635Stuexen paddrp->spp_flags |= SPP_PMTUD_DISABLE; 2452225635Stuexen } else { 2453170056Srrs paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2454170056Srrs } 2455225635Stuexen paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay; 2456163953Srrs } 2457163953Srrs paddrp->spp_assoc_id = sctp_get_associd(stcb); 2458163953Srrs SCTP_TCB_UNLOCK(stcb); 2459163953Srrs } else { 2460224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2461224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2462224918Stuexen (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) { 2463223132Stuexen /* Use endpoint defaults */ 2464223132Stuexen SCTP_INP_RLOCK(inp); 2465223132Stuexen paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure; 2466223132Stuexen paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); 2467223132Stuexen paddrp->spp_assoc_id = SCTP_FUTURE_ASSOC; 2468223132Stuexen /* get inp's default */ 2469225549Stuexen if (inp->sctp_ep.default_dscp & 0x01) { 2470226252Stuexen paddrp->spp_dscp = inp->sctp_ep.default_dscp & 0xfc; 2471225549Stuexen paddrp->spp_flags |= SPP_DSCP; 2472225549Stuexen } 2473167598Srrs#ifdef INET6 2474225549Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 2475225549Stuexen (inp->sctp_ep.default_flowlabel & 0x80000000)) { 2476225549Stuexen paddrp->spp_ipv6_flowlabel = inp->sctp_ep.default_flowlabel & 0x000fffff; 2477223132Stuexen paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2478223132Stuexen } 2479163953Srrs#endif 2480223132Stuexen /* can't return this */ 2481223132Stuexen paddrp->spp_pathmtu = 0; 2482170056Srrs 2483223132Stuexen if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { 2484223132Stuexen paddrp->spp_flags |= SPP_HB_ENABLE; 2485223132Stuexen } else { 2486223132Stuexen paddrp->spp_flags |= SPP_HB_DISABLE; 2487223132Stuexen } 2488225635Stuexen if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) { 2489225635Stuexen paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2490225635Stuexen } else { 2491225635Stuexen paddrp->spp_flags |= SPP_PMTUD_DISABLE; 2492225635Stuexen } 2493223132Stuexen SCTP_INP_RUNLOCK(inp); 2494170056Srrs } else { 2495223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2496223132Stuexen error = EINVAL; 2497170056Srrs } 2498163953Srrs } 2499223132Stuexen if (error == 0) { 2500223132Stuexen *optsize = sizeof(struct sctp_paddrparams); 2501223132Stuexen } 2502223132Stuexen break; 2503163953Srrs } 2504163953Srrs case SCTP_GET_PEER_ADDR_INFO: 2505163953Srrs { 2506163953Srrs struct sctp_paddrinfo *paddri; 2507163953Srrs struct sctp_nets *net; 2508163953Srrs 2509166675Srrs SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize); 2510166675Srrs SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id); 2511166675Srrs 2512163953Srrs net = NULL; 2513166675Srrs if (stcb) { 2514166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddri->spinfo_address); 2515166675Srrs } else { 2516166675Srrs /* 2517166675Srrs * We increment here since 2518166675Srrs * sctp_findassociation_ep_addr() wil do a 2519166675Srrs * decrement if it finds the stcb as long as 2520166675Srrs * the locked tcb (last argument) is NOT a 2521166675Srrs * TCB.. aka NULL. 2522166675Srrs */ 2523166675Srrs SCTP_INP_INCR_REF(inp); 2524166675Srrs stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddri->spinfo_address, &net, NULL, NULL); 2525166675Srrs if (stcb == NULL) { 2526166675Srrs SCTP_INP_DECR_REF(inp); 2527163953Srrs } 2528166675Srrs } 2529163953Srrs 2530166675Srrs if ((stcb) && (net)) { 2531217635Srrs if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { 2532217638Stuexen /* It's unconfirmed */ 2533217635Srrs paddri->spinfo_state = SCTP_UNCONFIRMED; 2534217635Srrs } else if (net->dest_state & SCTP_ADDR_REACHABLE) { 2535217638Stuexen /* It's active */ 2536217635Srrs paddri->spinfo_state = SCTP_ACTIVE; 2537217635Srrs } else { 2538217638Stuexen /* It's inactive */ 2539217635Srrs paddri->spinfo_state = SCTP_INACTIVE; 2540217635Srrs } 2541166675Srrs paddri->spinfo_cwnd = net->cwnd; 2542219014Stuexen paddri->spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT; 2543166675Srrs paddri->spinfo_rto = net->RTO; 2544166675Srrs paddri->spinfo_assoc_id = sctp_get_associd(stcb); 2545222029Stuexen paddri->spinfo_mtu = net->mtu; 2546166675Srrs SCTP_TCB_UNLOCK(stcb); 2547223132Stuexen *optsize = sizeof(struct sctp_paddrinfo); 2548163953Srrs } else { 2549163953Srrs if (stcb) { 2550163953Srrs SCTP_TCB_UNLOCK(stcb); 2551163953Srrs } 2552171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 2553163953Srrs error = ENOENT; 2554163953Srrs } 2555223132Stuexen break; 2556163953Srrs } 2557163953Srrs case SCTP_PCB_STATUS: 2558163953Srrs { 2559163953Srrs struct sctp_pcbinfo *spcb; 2560163953Srrs 2561166675Srrs SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize); 2562163953Srrs sctp_fill_pcbinfo(spcb); 2563166675Srrs *optsize = sizeof(struct sctp_pcbinfo); 2564223132Stuexen break; 2565163953Srrs } 2566163953Srrs case SCTP_STATUS: 2567163953Srrs { 2568163953Srrs struct sctp_nets *net; 2569163953Srrs struct sctp_status *sstat; 2570163953Srrs 2571166675Srrs SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize); 2572166675Srrs SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id); 2573163953Srrs 2574163953Srrs if (stcb == NULL) { 2575223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2576163953Srrs error = EINVAL; 2577163953Srrs break; 2578163953Srrs } 2579163953Srrs /* 2580163953Srrs * I think passing the state is fine since 2581163953Srrs * sctp_constants.h will be available to the user 2582163953Srrs * land. 2583163953Srrs */ 2584163953Srrs sstat->sstat_state = stcb->asoc.state; 2585173179Srrs sstat->sstat_assoc_id = sctp_get_associd(stcb); 2586163953Srrs sstat->sstat_rwnd = stcb->asoc.peers_rwnd; 2587163953Srrs sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt; 2588163953Srrs /* 2589163953Srrs * We can't include chunks that have been passed to 2590163953Srrs * the socket layer. Only things in queue. 2591163953Srrs */ 2592163953Srrs sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue + 2593163953Srrs stcb->asoc.cnt_on_all_streams); 2594163953Srrs 2595163953Srrs 2596163953Srrs sstat->sstat_instrms = stcb->asoc.streamincnt; 2597163953Srrs sstat->sstat_outstrms = stcb->asoc.streamoutcnt; 2598163953Srrs sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc); 2599163953Srrs memcpy(&sstat->sstat_primary.spinfo_address, 2600163953Srrs &stcb->asoc.primary_destination->ro._l_addr, 2601163953Srrs ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len); 2602163953Srrs net = stcb->asoc.primary_destination; 2603163953Srrs ((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport; 2604163953Srrs /* 2605163953Srrs * Again the user can get info from sctp_constants.h 2606163953Srrs * for what the state of the network is. 2607163953Srrs */ 2608217635Srrs if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { 2609217635Srrs /* It's unconfirmed */ 2610217635Srrs sstat->sstat_primary.spinfo_state = SCTP_UNCONFIRMED; 2611217635Srrs } else if (net->dest_state & SCTP_ADDR_REACHABLE) { 2612217638Stuexen /* It's active */ 2613217635Srrs sstat->sstat_primary.spinfo_state = SCTP_ACTIVE; 2614217635Srrs } else { 2615217638Stuexen /* It's inactive */ 2616217635Srrs sstat->sstat_primary.spinfo_state = SCTP_INACTIVE; 2617217635Srrs } 2618163953Srrs sstat->sstat_primary.spinfo_cwnd = net->cwnd; 2619219014Stuexen sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT; 2620163953Srrs sstat->sstat_primary.spinfo_rto = net->RTO; 2621163953Srrs sstat->sstat_primary.spinfo_mtu = net->mtu; 2622163953Srrs sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb); 2623163953Srrs SCTP_TCB_UNLOCK(stcb); 2624223132Stuexen *optsize = sizeof(struct sctp_status); 2625223132Stuexen break; 2626163953Srrs } 2627163953Srrs case SCTP_RTOINFO: 2628163953Srrs { 2629163953Srrs struct sctp_rtoinfo *srto; 2630163953Srrs 2631166675Srrs SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize); 2632166675Srrs SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); 2633166675Srrs 2634166675Srrs if (stcb) { 2635166675Srrs srto->srto_initial = stcb->asoc.initial_rto; 2636166675Srrs srto->srto_max = stcb->asoc.maxrto; 2637166675Srrs srto->srto_min = stcb->asoc.minrto; 2638166675Srrs SCTP_TCB_UNLOCK(stcb); 2639166675Srrs } else { 2640224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2641224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2642224918Stuexen (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) { 2643223132Stuexen SCTP_INP_RLOCK(inp); 2644223132Stuexen srto->srto_initial = inp->sctp_ep.initial_rto; 2645223132Stuexen srto->srto_max = inp->sctp_ep.sctp_maxrto; 2646223132Stuexen srto->srto_min = inp->sctp_ep.sctp_minrto; 2647223132Stuexen SCTP_INP_RUNLOCK(inp); 2648223132Stuexen } else { 2649223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2650223132Stuexen error = EINVAL; 2651223132Stuexen } 2652163953Srrs } 2653223132Stuexen if (error == 0) { 2654223132Stuexen *optsize = sizeof(struct sctp_rtoinfo); 2655223132Stuexen } 2656223132Stuexen break; 2657163953Srrs } 2658215410Stuexen case SCTP_TIMEOUTS: 2659215410Stuexen { 2660215410Stuexen struct sctp_timeouts *stimo; 2661215410Stuexen 2662215410Stuexen SCTP_CHECK_AND_CAST(stimo, optval, struct sctp_timeouts, *optsize); 2663215410Stuexen SCTP_FIND_STCB(inp, stcb, stimo->stimo_assoc_id); 2664215410Stuexen 2665215410Stuexen if (stcb) { 2666215410Stuexen stimo->stimo_init = stcb->asoc.timoinit; 2667215410Stuexen stimo->stimo_data = stcb->asoc.timodata; 2668215410Stuexen stimo->stimo_sack = stcb->asoc.timosack; 2669215410Stuexen stimo->stimo_shutdown = stcb->asoc.timoshutdown; 2670215410Stuexen stimo->stimo_heartbeat = stcb->asoc.timoheartbeat; 2671215410Stuexen stimo->stimo_cookie = stcb->asoc.timocookie; 2672215410Stuexen stimo->stimo_shutdownack = stcb->asoc.timoshutdownack; 2673215410Stuexen SCTP_TCB_UNLOCK(stcb); 2674223132Stuexen *optsize = sizeof(struct sctp_timeouts); 2675215410Stuexen } else { 2676223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2677215410Stuexen error = EINVAL; 2678215410Stuexen } 2679223132Stuexen break; 2680215410Stuexen } 2681163953Srrs case SCTP_ASSOCINFO: 2682163953Srrs { 2683163953Srrs struct sctp_assocparams *sasoc; 2684163953Srrs 2685166675Srrs SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize); 2686166675Srrs SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); 2687163953Srrs 2688163953Srrs if (stcb) { 2689171477Srrs sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life); 2690163953Srrs sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times; 2691163953Srrs sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets; 2692163953Srrs sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd; 2693163953Srrs sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd; 2694163953Srrs SCTP_TCB_UNLOCK(stcb); 2695163953Srrs } else { 2696224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2697224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2698224918Stuexen (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) { 2699223132Stuexen SCTP_INP_RLOCK(inp); 2700223132Stuexen sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life); 2701223132Stuexen sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times; 2702223132Stuexen sasoc->sasoc_number_peer_destinations = 0; 2703223132Stuexen sasoc->sasoc_peer_rwnd = 0; 2704223132Stuexen sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv); 2705223132Stuexen SCTP_INP_RUNLOCK(inp); 2706223132Stuexen } else { 2707223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2708223132Stuexen error = EINVAL; 2709223132Stuexen } 2710163953Srrs } 2711223132Stuexen if (error == 0) { 2712223132Stuexen *optsize = sizeof(struct sctp_assocparams); 2713223132Stuexen } 2714223132Stuexen break; 2715163953Srrs } 2716163953Srrs case SCTP_DEFAULT_SEND_PARAM: 2717163953Srrs { 2718163953Srrs struct sctp_sndrcvinfo *s_info; 2719163953Srrs 2720166675Srrs SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize); 2721166675Srrs SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); 2722166675Srrs 2723166675Srrs if (stcb) { 2724170056Srrs memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send)); 2725166675Srrs SCTP_TCB_UNLOCK(stcb); 2726166675Srrs } else { 2727224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2728224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2729224918Stuexen (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC)) { 2730223132Stuexen SCTP_INP_RLOCK(inp); 2731223132Stuexen memcpy(s_info, &inp->def_send, sizeof(inp->def_send)); 2732223132Stuexen SCTP_INP_RUNLOCK(inp); 2733223132Stuexen } else { 2734223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2735223132Stuexen error = EINVAL; 2736223132Stuexen } 2737163953Srrs } 2738223132Stuexen if (error == 0) { 2739223132Stuexen *optsize = sizeof(struct sctp_sndrcvinfo); 2740223132Stuexen } 2741223132Stuexen break; 2742163953Srrs } 2743163953Srrs case SCTP_INITMSG: 2744163953Srrs { 2745163953Srrs struct sctp_initmsg *sinit; 2746163953Srrs 2747166675Srrs SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize); 2748163953Srrs SCTP_INP_RLOCK(inp); 2749163953Srrs sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count; 2750163953Srrs sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome; 2751163953Srrs sinit->sinit_max_attempts = inp->sctp_ep.max_init_times; 2752163953Srrs sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max; 2753163953Srrs SCTP_INP_RUNLOCK(inp); 2754223132Stuexen *optsize = sizeof(struct sctp_initmsg); 2755223132Stuexen break; 2756163953Srrs } 2757163953Srrs case SCTP_PRIMARY_ADDR: 2758163953Srrs /* we allow a "get" operation on this */ 2759163953Srrs { 2760163953Srrs struct sctp_setprim *ssp; 2761163953Srrs 2762166675Srrs SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize); 2763166675Srrs SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id); 2764166675Srrs 2765166675Srrs if (stcb) { 2766166675Srrs /* simply copy out the sockaddr_storage... */ 2767170056Srrs int len; 2768170056Srrs 2769170056Srrs len = *optsize; 2770170056Srrs if (len > stcb->asoc.primary_destination->ro._l_addr.sa.sa_len) 2771170056Srrs len = stcb->asoc.primary_destination->ro._l_addr.sa.sa_len; 2772170056Srrs 2773170056Srrs memcpy(&ssp->ssp_addr, 2774170056Srrs &stcb->asoc.primary_destination->ro._l_addr, 2775170056Srrs len); 2776166675Srrs SCTP_TCB_UNLOCK(stcb); 2777223132Stuexen *optsize = sizeof(struct sctp_setprim); 2778166675Srrs } else { 2779223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2780163953Srrs error = EINVAL; 2781163953Srrs } 2782223132Stuexen break; 2783163953Srrs } 2784163953Srrs case SCTP_HMAC_IDENT: 2785163953Srrs { 2786163953Srrs struct sctp_hmacalgo *shmac; 2787163953Srrs sctp_hmaclist_t *hmaclist; 2788163953Srrs uint32_t size; 2789163953Srrs int i; 2790163953Srrs 2791166675Srrs SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize); 2792166675Srrs 2793163953Srrs SCTP_INP_RLOCK(inp); 2794163953Srrs hmaclist = inp->sctp_ep.local_hmacs; 2795163953Srrs if (hmaclist == NULL) { 2796163953Srrs /* no HMACs to return */ 2797166675Srrs *optsize = sizeof(*shmac); 2798168299Srrs SCTP_INP_RUNLOCK(inp); 2799163953Srrs break; 2800163953Srrs } 2801163953Srrs /* is there room for all of the hmac ids? */ 2802163953Srrs size = sizeof(*shmac) + (hmaclist->num_algo * 2803163953Srrs sizeof(shmac->shmac_idents[0])); 2804166675Srrs if ((size_t)(*optsize) < size) { 2805223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2806163953Srrs error = EINVAL; 2807163953Srrs SCTP_INP_RUNLOCK(inp); 2808163953Srrs break; 2809163953Srrs } 2810163953Srrs /* copy in the list */ 2811181054Srrs shmac->shmac_number_of_idents = hmaclist->num_algo; 2812181054Srrs for (i = 0; i < hmaclist->num_algo; i++) { 2813163953Srrs shmac->shmac_idents[i] = hmaclist->hmac[i]; 2814181054Srrs } 2815163953Srrs SCTP_INP_RUNLOCK(inp); 2816166675Srrs *optsize = size; 2817163953Srrs break; 2818163953Srrs } 2819163953Srrs case SCTP_AUTH_ACTIVE_KEY: 2820163953Srrs { 2821163953Srrs struct sctp_authkeyid *scact; 2822163953Srrs 2823166675Srrs SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize); 2824166675Srrs SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); 2825166675Srrs 2826166675Srrs if (stcb) { 2827163953Srrs /* get the active key on the assoc */ 2828185694Srrs scact->scact_keynumber = stcb->asoc.authinfo.active_keyid; 2829163953Srrs SCTP_TCB_UNLOCK(stcb); 2830163953Srrs } else { 2831224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2832224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2833224918Stuexen (scact->scact_assoc_id == SCTP_FUTURE_ASSOC)) { 2834223132Stuexen /* get the endpoint active key */ 2835223132Stuexen SCTP_INP_RLOCK(inp); 2836223132Stuexen scact->scact_keynumber = inp->sctp_ep.default_keyid; 2837223132Stuexen SCTP_INP_RUNLOCK(inp); 2838223132Stuexen } else { 2839223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2840223132Stuexen error = EINVAL; 2841223132Stuexen } 2842163953Srrs } 2843223132Stuexen if (error == 0) { 2844223132Stuexen *optsize = sizeof(struct sctp_authkeyid); 2845223132Stuexen } 2846163953Srrs break; 2847163953Srrs } 2848163953Srrs case SCTP_LOCAL_AUTH_CHUNKS: 2849163953Srrs { 2850163953Srrs struct sctp_authchunks *sac; 2851163953Srrs sctp_auth_chklist_t *chklist = NULL; 2852166675Srrs size_t size = 0; 2853163953Srrs 2854166675Srrs SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); 2855166675Srrs SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); 2856166675Srrs 2857166675Srrs if (stcb) { 2858163953Srrs /* get off the assoc */ 2859163953Srrs chklist = stcb->asoc.local_auth_chunks; 2860163953Srrs /* is there enough space? */ 2861163953Srrs size = sctp_auth_get_chklist_size(chklist); 2862166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2863163953Srrs error = EINVAL; 2864171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2865166675Srrs } else { 2866166675Srrs /* copy in the chunks */ 2867169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2868234832Stuexen sac->gauth_number_of_chunks = (uint32_t) size; 2869223132Stuexen *optsize = sizeof(struct sctp_authchunks) + size; 2870163953Srrs } 2871163953Srrs SCTP_TCB_UNLOCK(stcb); 2872163953Srrs } else { 2873224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2874224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2875224918Stuexen (sac->gauth_assoc_id == SCTP_FUTURE_ASSOC)) { 2876223132Stuexen /* get off the endpoint */ 2877223132Stuexen SCTP_INP_RLOCK(inp); 2878223132Stuexen chklist = inp->sctp_ep.local_auth_chunks; 2879223132Stuexen /* is there enough space? */ 2880223132Stuexen size = sctp_auth_get_chklist_size(chklist); 2881223132Stuexen if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2882223132Stuexen error = EINVAL; 2883223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2884223132Stuexen } else { 2885223132Stuexen /* copy in the chunks */ 2886223132Stuexen (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2887234832Stuexen sac->gauth_number_of_chunks = (uint32_t) size; 2888223132Stuexen *optsize = sizeof(struct sctp_authchunks) + size; 2889223132Stuexen } 2890223132Stuexen SCTP_INP_RUNLOCK(inp); 2891223132Stuexen } else { 2892223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2893163953Srrs error = EINVAL; 2894163953Srrs } 2895163953Srrs } 2896163953Srrs break; 2897163953Srrs } 2898163953Srrs case SCTP_PEER_AUTH_CHUNKS: 2899163953Srrs { 2900163953Srrs struct sctp_authchunks *sac; 2901163953Srrs sctp_auth_chklist_t *chklist = NULL; 2902166675Srrs size_t size = 0; 2903163953Srrs 2904166675Srrs SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); 2905166675Srrs SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); 2906166675Srrs 2907166675Srrs if (stcb) { 2908166675Srrs /* get off the assoc */ 2909166675Srrs chklist = stcb->asoc.peer_auth_chunks; 2910166675Srrs /* is there enough space? */ 2911166675Srrs size = sctp_auth_get_chklist_size(chklist); 2912166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2913166675Srrs error = EINVAL; 2914171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2915166675Srrs } else { 2916166675Srrs /* copy in the chunks */ 2917169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2918234832Stuexen sac->gauth_number_of_chunks = (uint32_t) size; 2919223132Stuexen *optsize = sizeof(struct sctp_authchunks) + size; 2920166675Srrs } 2921166675Srrs SCTP_TCB_UNLOCK(stcb); 2922166675Srrs } else { 2923171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 2924163953Srrs error = ENOENT; 2925163953Srrs } 2926163953Srrs break; 2927163953Srrs } 2928223132Stuexen case SCTP_EVENT: 2929223132Stuexen { 2930223132Stuexen struct sctp_event *event; 2931223132Stuexen uint32_t event_type; 2932163953Srrs 2933223132Stuexen SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, *optsize); 2934223132Stuexen SCTP_FIND_STCB(inp, stcb, event->se_assoc_id); 2935163953Srrs 2936223132Stuexen switch (event->se_type) { 2937223132Stuexen case SCTP_ASSOC_CHANGE: 2938223132Stuexen event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT; 2939223132Stuexen break; 2940223132Stuexen case SCTP_PEER_ADDR_CHANGE: 2941223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPADDREVNT; 2942223132Stuexen break; 2943223132Stuexen case SCTP_REMOTE_ERROR: 2944223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPEERERR; 2945223132Stuexen break; 2946223132Stuexen case SCTP_SEND_FAILED: 2947223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT; 2948223132Stuexen break; 2949223132Stuexen case SCTP_SHUTDOWN_EVENT: 2950223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT; 2951223132Stuexen break; 2952223132Stuexen case SCTP_ADAPTATION_INDICATION: 2953223132Stuexen event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT; 2954223132Stuexen break; 2955223132Stuexen case SCTP_PARTIAL_DELIVERY_EVENT: 2956223132Stuexen event_type = SCTP_PCB_FLAGS_PDAPIEVNT; 2957223132Stuexen break; 2958223132Stuexen case SCTP_AUTHENTICATION_EVENT: 2959223132Stuexen event_type = SCTP_PCB_FLAGS_AUTHEVNT; 2960223132Stuexen break; 2961223132Stuexen case SCTP_STREAM_RESET_EVENT: 2962223132Stuexen event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT; 2963223132Stuexen break; 2964223132Stuexen case SCTP_SENDER_DRY_EVENT: 2965223132Stuexen event_type = SCTP_PCB_FLAGS_DRYEVNT; 2966223132Stuexen break; 2967223132Stuexen case SCTP_NOTIFICATIONS_STOPPED_EVENT: 2968223132Stuexen event_type = 0; 2969223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); 2970223132Stuexen error = ENOTSUP; 2971223132Stuexen break; 2972235009Stuexen case SCTP_ASSOC_RESET_EVENT: 2973235009Stuexen event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT; 2974235009Stuexen break; 2975235009Stuexen case SCTP_STREAM_CHANGE_EVENT: 2976235009Stuexen event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT; 2977235009Stuexen break; 2978235075Stuexen case SCTP_SEND_FAILED_EVENT: 2979235075Stuexen event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT; 2980235075Stuexen break; 2981223132Stuexen default: 2982223132Stuexen event_type = 0; 2983223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2984223132Stuexen error = EINVAL; 2985223132Stuexen break; 2986223132Stuexen } 2987223132Stuexen if (event_type > 0) { 2988223132Stuexen if (stcb) { 2989223132Stuexen event->se_on = sctp_stcb_is_feature_on(inp, stcb, event_type); 2990223132Stuexen SCTP_TCB_UNLOCK(stcb); 2991223132Stuexen } else { 2992224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2993224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2994224918Stuexen (event->se_assoc_id == SCTP_FUTURE_ASSOC)) { 2995223132Stuexen SCTP_INP_RLOCK(inp); 2996223132Stuexen event->se_on = sctp_is_feature_on(inp, event_type); 2997223132Stuexen SCTP_INP_RUNLOCK(inp); 2998223132Stuexen } else { 2999223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3000223132Stuexen error = EINVAL; 3001223132Stuexen } 3002223132Stuexen } 3003223132Stuexen } 3004223132Stuexen if (error == 0) { 3005223132Stuexen *optsize = sizeof(struct sctp_event); 3006223132Stuexen } 3007223132Stuexen break; 3008223132Stuexen } 3009223132Stuexen case SCTP_RECVRCVINFO: 3010223132Stuexen { 3011223132Stuexen int onoff; 3012223132Stuexen 3013223132Stuexen if (*optsize < sizeof(int)) { 3014223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3015223132Stuexen error = EINVAL; 3016223132Stuexen } else { 3017230104Stuexen SCTP_INP_RLOCK(inp); 3018223132Stuexen onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO); 3019223132Stuexen SCTP_INP_RUNLOCK(inp); 3020223132Stuexen } 3021223132Stuexen if (error == 0) { 3022223132Stuexen /* return the option value */ 3023223132Stuexen *(int *)optval = onoff; 3024223132Stuexen *optsize = sizeof(int); 3025223132Stuexen } 3026223132Stuexen break; 3027223132Stuexen } 3028223132Stuexen case SCTP_RECVNXTINFO: 3029223132Stuexen { 3030223132Stuexen int onoff; 3031223132Stuexen 3032223132Stuexen if (*optsize < sizeof(int)) { 3033223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3034223132Stuexen error = EINVAL; 3035223132Stuexen } else { 3036230104Stuexen SCTP_INP_RLOCK(inp); 3037223132Stuexen onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO); 3038223132Stuexen SCTP_INP_RUNLOCK(inp); 3039223132Stuexen } 3040223132Stuexen if (error == 0) { 3041223132Stuexen /* return the option value */ 3042223132Stuexen *(int *)optval = onoff; 3043223132Stuexen *optsize = sizeof(int); 3044223132Stuexen } 3045223132Stuexen break; 3046223132Stuexen } 3047223132Stuexen case SCTP_DEFAULT_SNDINFO: 3048223132Stuexen { 3049223132Stuexen struct sctp_sndinfo *info; 3050223132Stuexen 3051223132Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, *optsize); 3052223132Stuexen SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id); 3053223132Stuexen 3054223132Stuexen if (stcb) { 3055223132Stuexen info->snd_sid = stcb->asoc.def_send.sinfo_stream; 3056223132Stuexen info->snd_flags = stcb->asoc.def_send.sinfo_flags; 3057223162Stuexen info->snd_flags &= 0xfff0; 3058223132Stuexen info->snd_ppid = stcb->asoc.def_send.sinfo_ppid; 3059223132Stuexen info->snd_context = stcb->asoc.def_send.sinfo_context; 3060223132Stuexen SCTP_TCB_UNLOCK(stcb); 3061223132Stuexen } else { 3062224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3063224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3064224918Stuexen (info->snd_assoc_id == SCTP_FUTURE_ASSOC)) { 3065223132Stuexen SCTP_INP_RLOCK(inp); 3066223132Stuexen info->snd_sid = inp->def_send.sinfo_stream; 3067223132Stuexen info->snd_flags = inp->def_send.sinfo_flags; 3068223162Stuexen info->snd_flags &= 0xfff0; 3069223132Stuexen info->snd_ppid = inp->def_send.sinfo_ppid; 3070223132Stuexen info->snd_context = inp->def_send.sinfo_context; 3071223132Stuexen SCTP_INP_RUNLOCK(inp); 3072223132Stuexen } else { 3073223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3074223132Stuexen error = EINVAL; 3075223132Stuexen } 3076223132Stuexen } 3077223132Stuexen if (error == 0) { 3078223132Stuexen *optsize = sizeof(struct sctp_sndinfo); 3079223132Stuexen } 3080223132Stuexen break; 3081223132Stuexen } 3082223162Stuexen case SCTP_DEFAULT_PRINFO: 3083223162Stuexen { 3084223162Stuexen struct sctp_default_prinfo *info; 3085223162Stuexen 3086223162Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, *optsize); 3087223162Stuexen SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id); 3088223162Stuexen 3089223162Stuexen if (stcb) { 3090223162Stuexen info->pr_policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); 3091223162Stuexen info->pr_value = stcb->asoc.def_send.sinfo_timetolive; 3092223162Stuexen SCTP_TCB_UNLOCK(stcb); 3093223162Stuexen } else { 3094224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3095224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3096224918Stuexen (info->pr_assoc_id == SCTP_FUTURE_ASSOC)) { 3097223162Stuexen SCTP_INP_RLOCK(inp); 3098223162Stuexen info->pr_policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags); 3099223162Stuexen info->pr_value = inp->def_send.sinfo_timetolive; 3100223162Stuexen SCTP_INP_RUNLOCK(inp); 3101223162Stuexen } else { 3102223162Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3103223162Stuexen error = EINVAL; 3104223162Stuexen } 3105223162Stuexen } 3106223162Stuexen if (error == 0) { 3107223162Stuexen *optsize = sizeof(struct sctp_default_prinfo); 3108223162Stuexen } 3109223162Stuexen break; 3110223162Stuexen } 3111224641Stuexen case SCTP_PEER_ADDR_THLDS: 3112224641Stuexen { 3113224641Stuexen struct sctp_paddrthlds *thlds; 3114224641Stuexen struct sctp_nets *net; 3115224641Stuexen 3116224641Stuexen SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, *optsize); 3117224641Stuexen SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id); 3118224641Stuexen 3119224641Stuexen net = NULL; 3120224641Stuexen if (stcb) { 3121224641Stuexen net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_address); 3122224641Stuexen } else { 3123224641Stuexen /* 3124224641Stuexen * We increment here since 3125224641Stuexen * sctp_findassociation_ep_addr() wil do a 3126224641Stuexen * decrement if it finds the stcb as long as 3127224641Stuexen * the locked tcb (last argument) is NOT a 3128224641Stuexen * TCB.. aka NULL. 3129224641Stuexen */ 3130224641Stuexen SCTP_INP_INCR_REF(inp); 3131224641Stuexen stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&thlds->spt_address, &net, NULL, NULL); 3132224641Stuexen if (stcb == NULL) { 3133224641Stuexen SCTP_INP_DECR_REF(inp); 3134224641Stuexen } 3135224641Stuexen } 3136224641Stuexen if (stcb && (net == NULL)) { 3137224641Stuexen struct sockaddr *sa; 3138224641Stuexen 3139224641Stuexen sa = (struct sockaddr *)&thlds->spt_address; 3140224641Stuexen#ifdef INET 3141224641Stuexen if (sa->sa_family == AF_INET) { 3142224641Stuexen struct sockaddr_in *sin; 3143224641Stuexen 3144224641Stuexen sin = (struct sockaddr_in *)sa; 3145224641Stuexen if (sin->sin_addr.s_addr) { 3146224641Stuexen error = EINVAL; 3147224641Stuexen SCTP_TCB_UNLOCK(stcb); 3148224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3149224641Stuexen break; 3150224641Stuexen } 3151224641Stuexen } else 3152224641Stuexen#endif 3153224641Stuexen#ifdef INET6 3154224641Stuexen if (sa->sa_family == AF_INET6) { 3155224641Stuexen struct sockaddr_in6 *sin6; 3156224641Stuexen 3157224641Stuexen sin6 = (struct sockaddr_in6 *)sa; 3158224641Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 3159224641Stuexen error = EINVAL; 3160224641Stuexen SCTP_TCB_UNLOCK(stcb); 3161224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3162224641Stuexen break; 3163224641Stuexen } 3164224641Stuexen } else 3165224641Stuexen#endif 3166224641Stuexen { 3167224641Stuexen error = EAFNOSUPPORT; 3168224641Stuexen SCTP_TCB_UNLOCK(stcb); 3169224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3170224641Stuexen break; 3171224641Stuexen } 3172224641Stuexen } 3173224641Stuexen if (stcb) { 3174224641Stuexen if (net) { 3175224641Stuexen thlds->spt_pathmaxrxt = net->failure_threshold; 3176224641Stuexen thlds->spt_pathpfthld = net->pf_threshold; 3177224641Stuexen } else { 3178224641Stuexen thlds->spt_pathmaxrxt = stcb->asoc.def_net_failure; 3179224641Stuexen thlds->spt_pathpfthld = stcb->asoc.def_net_pf_threshold; 3180224641Stuexen } 3181224641Stuexen thlds->spt_assoc_id = sctp_get_associd(stcb); 3182224641Stuexen SCTP_TCB_UNLOCK(stcb); 3183224641Stuexen } else { 3184224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3185224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3186224918Stuexen (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) { 3187224641Stuexen /* Use endpoint defaults */ 3188224641Stuexen SCTP_INP_RLOCK(inp); 3189224641Stuexen thlds->spt_pathmaxrxt = inp->sctp_ep.def_net_failure; 3190224641Stuexen thlds->spt_pathpfthld = inp->sctp_ep.def_net_pf_threshold; 3191224641Stuexen SCTP_INP_RUNLOCK(inp); 3192224641Stuexen } else { 3193224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3194224641Stuexen error = EINVAL; 3195224641Stuexen } 3196224641Stuexen } 3197224641Stuexen if (error == 0) { 3198224641Stuexen *optsize = sizeof(struct sctp_paddrthlds); 3199224641Stuexen } 3200224641Stuexen break; 3201224641Stuexen } 3202227755Stuexen case SCTP_REMOTE_UDP_ENCAPS_PORT: 3203227755Stuexen { 3204227755Stuexen struct sctp_udpencaps *encaps; 3205227755Stuexen struct sctp_nets *net; 3206227755Stuexen 3207227755Stuexen SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, *optsize); 3208227755Stuexen SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id); 3209227755Stuexen 3210227755Stuexen if (stcb) { 3211227755Stuexen net = sctp_findnet(stcb, (struct sockaddr *)&encaps->sue_address); 3212227755Stuexen } else { 3213227755Stuexen /* 3214227755Stuexen * We increment here since 3215227755Stuexen * sctp_findassociation_ep_addr() wil do a 3216227755Stuexen * decrement if it finds the stcb as long as 3217227755Stuexen * the locked tcb (last argument) is NOT a 3218227755Stuexen * TCB.. aka NULL. 3219227755Stuexen */ 3220227755Stuexen net = NULL; 3221227755Stuexen SCTP_INP_INCR_REF(inp); 3222227755Stuexen stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&encaps->sue_address, &net, NULL, NULL); 3223227755Stuexen if (stcb == NULL) { 3224227755Stuexen SCTP_INP_DECR_REF(inp); 3225227755Stuexen } 3226227755Stuexen } 3227227755Stuexen if (stcb && (net == NULL)) { 3228227755Stuexen struct sockaddr *sa; 3229227755Stuexen 3230227755Stuexen sa = (struct sockaddr *)&encaps->sue_address; 3231227755Stuexen#ifdef INET 3232227755Stuexen if (sa->sa_family == AF_INET) { 3233227755Stuexen struct sockaddr_in *sin; 3234227755Stuexen 3235227755Stuexen sin = (struct sockaddr_in *)sa; 3236227755Stuexen if (sin->sin_addr.s_addr) { 3237227755Stuexen error = EINVAL; 3238227755Stuexen SCTP_TCB_UNLOCK(stcb); 3239227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3240227755Stuexen break; 3241227755Stuexen } 3242227755Stuexen } else 3243227755Stuexen#endif 3244227755Stuexen#ifdef INET6 3245227755Stuexen if (sa->sa_family == AF_INET6) { 3246227755Stuexen struct sockaddr_in6 *sin6; 3247227755Stuexen 3248227755Stuexen sin6 = (struct sockaddr_in6 *)sa; 3249227755Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 3250227755Stuexen error = EINVAL; 3251227755Stuexen SCTP_TCB_UNLOCK(stcb); 3252227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3253227755Stuexen break; 3254227755Stuexen } 3255227755Stuexen } else 3256227755Stuexen#endif 3257227755Stuexen { 3258227755Stuexen error = EAFNOSUPPORT; 3259227755Stuexen SCTP_TCB_UNLOCK(stcb); 3260227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3261227755Stuexen break; 3262227755Stuexen } 3263227755Stuexen } 3264227755Stuexen if (stcb) { 3265227755Stuexen if (net) { 3266227755Stuexen encaps->sue_port = net->port; 3267227755Stuexen } else { 3268227755Stuexen encaps->sue_port = stcb->asoc.port; 3269227755Stuexen } 3270227755Stuexen SCTP_TCB_UNLOCK(stcb); 3271227755Stuexen } else { 3272227755Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3273227755Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3274227755Stuexen (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) { 3275227755Stuexen SCTP_INP_RLOCK(inp); 3276227755Stuexen encaps->sue_port = inp->sctp_ep.port; 3277227755Stuexen SCTP_INP_RUNLOCK(inp); 3278227755Stuexen } else { 3279227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3280227755Stuexen error = EINVAL; 3281227755Stuexen } 3282227755Stuexen } 3283227755Stuexen if (error == 0) { 3284227755Stuexen *optsize = sizeof(struct sctp_paddrparams); 3285227755Stuexen } 3286227755Stuexen break; 3287227755Stuexen } 3288235021Stuexen case SCTP_ENABLE_STREAM_RESET: 3289235021Stuexen { 3290235021Stuexen struct sctp_assoc_value *av; 3291235021Stuexen 3292235021Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3293235021Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3294235021Stuexen 3295235021Stuexen if (stcb) { 3296235021Stuexen av->assoc_value = (uint32_t) stcb->asoc.local_strreset_support; 3297235021Stuexen SCTP_TCB_UNLOCK(stcb); 3298235021Stuexen } else { 3299235021Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3300235021Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3301235021Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3302235021Stuexen SCTP_INP_RLOCK(inp); 3303235021Stuexen av->assoc_value = (uint32_t) inp->local_strreset_support; 3304235021Stuexen SCTP_INP_RUNLOCK(inp); 3305235021Stuexen } else { 3306235021Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3307235021Stuexen error = EINVAL; 3308235021Stuexen } 3309235021Stuexen } 3310235021Stuexen if (error == 0) { 3311235021Stuexen *optsize = sizeof(struct sctp_assoc_value); 3312235021Stuexen } 3313235021Stuexen break; 3314235021Stuexen } 3315163953Srrs default: 3316171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 3317163953Srrs error = ENOPROTOOPT; 3318163953Srrs break; 3319163953Srrs } /* end switch (sopt->sopt_name) */ 3320223132Stuexen if (error) { 3321223132Stuexen *optsize = 0; 3322223132Stuexen } 3323163953Srrs return (error); 3324163953Srrs} 3325163953Srrs 3326163953Srrsstatic int 3327166675Srrssctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, 3328166675Srrs void *p) 3329163953Srrs{ 3330166675Srrs int error, set_opt; 3331166675Srrs uint32_t *mopt; 3332163953Srrs struct sctp_tcb *stcb = NULL; 3333171943Srrs struct sctp_inpcb *inp = NULL; 3334167598Srrs uint32_t vrf_id; 3335163953Srrs 3336166675Srrs if (optval == NULL) { 3337169420Srrs SCTP_PRINTF("optval is NULL\n"); 3338171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3339163953Srrs return (EINVAL); 3340163953Srrs } 3341163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3342233005Stuexen if (inp == NULL) { 3343169420Srrs SCTP_PRINTF("inp is NULL?\n"); 3344171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3345228907Stuexen return (EINVAL); 3346167598Srrs } 3347168299Srrs vrf_id = inp->def_vrf_id; 3348163953Srrs 3349163953Srrs error = 0; 3350166675Srrs switch (optname) { 3351163953Srrs case SCTP_NODELAY: 3352163953Srrs case SCTP_AUTOCLOSE: 3353163953Srrs case SCTP_AUTO_ASCONF: 3354163953Srrs case SCTP_EXPLICIT_EOR: 3355163953Srrs case SCTP_DISABLE_FRAGMENTS: 3356163953Srrs case SCTP_USE_EXT_RCVINFO: 3357163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 3358163953Srrs /* copy in the option value */ 3359166675Srrs SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); 3360163953Srrs set_opt = 0; 3361163953Srrs if (error) 3362163953Srrs break; 3363166675Srrs switch (optname) { 3364163953Srrs case SCTP_DISABLE_FRAGMENTS: 3365163953Srrs set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT; 3366163953Srrs break; 3367163953Srrs case SCTP_AUTO_ASCONF: 3368171943Srrs /* 3369171943Srrs * NOTE: we don't really support this flag 3370171943Srrs */ 3371171943Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 3372171943Srrs /* only valid for bound all sockets */ 3373224641Stuexen if ((SCTP_BASE_SYSCTL(sctp_auto_asconf) == 0) && 3374224641Stuexen (*mopt != 0)) { 3375224641Stuexen /* forbidden by admin */ 3376224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM); 3377224641Stuexen return (EPERM); 3378224641Stuexen } 3379171943Srrs set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF; 3380171943Srrs } else { 3381171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3382171943Srrs return (EINVAL); 3383171943Srrs } 3384163953Srrs break; 3385163953Srrs case SCTP_EXPLICIT_EOR: 3386163953Srrs set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR; 3387163953Srrs break; 3388163953Srrs case SCTP_USE_EXT_RCVINFO: 3389163953Srrs set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO; 3390163953Srrs break; 3391163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 3392163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 3393163953Srrs set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4; 3394163953Srrs } else { 3395171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3396163953Srrs return (EINVAL); 3397163953Srrs } 3398163953Srrs break; 3399163953Srrs case SCTP_NODELAY: 3400163953Srrs set_opt = SCTP_PCB_FLAGS_NODELAY; 3401163953Srrs break; 3402163953Srrs case SCTP_AUTOCLOSE: 3403170056Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3404170056Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 3405171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3406170056Srrs return (EINVAL); 3407170056Srrs } 3408163953Srrs set_opt = SCTP_PCB_FLAGS_AUTOCLOSE; 3409163953Srrs /* 3410163953Srrs * The value is in ticks. Note this does not effect 3411163953Srrs * old associations, only new ones. 3412163953Srrs */ 3413163953Srrs inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt); 3414163953Srrs break; 3415163953Srrs } 3416163953Srrs SCTP_INP_WLOCK(inp); 3417163953Srrs if (*mopt != 0) { 3418163953Srrs sctp_feature_on(inp, set_opt); 3419163953Srrs } else { 3420163953Srrs sctp_feature_off(inp, set_opt); 3421163953Srrs } 3422163953Srrs SCTP_INP_WUNLOCK(inp); 3423163953Srrs break; 3424181054Srrs case SCTP_REUSE_PORT: 3425181054Srrs { 3426181054Srrs SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); 3427181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) { 3428181054Srrs /* Can't set it after we are bound */ 3429181054Srrs error = EINVAL; 3430181054Srrs break; 3431181054Srrs } 3432181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) { 3433181054Srrs /* Can't do this for a 1-m socket */ 3434181054Srrs error = EINVAL; 3435181054Srrs break; 3436181054Srrs } 3437181054Srrs if (optval) 3438181054Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE); 3439181054Srrs else 3440181054Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE); 3441223132Stuexen break; 3442181054Srrs } 3443163953Srrs case SCTP_PARTIAL_DELIVERY_POINT: 3444163953Srrs { 3445166675Srrs uint32_t *value; 3446166675Srrs 3447166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); 3448167736Srrs if (*value > SCTP_SB_LIMIT_RCV(so)) { 3449171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3450167736Srrs error = EINVAL; 3451167736Srrs break; 3452167736Srrs } 3453166675Srrs inp->partial_delivery_point = *value; 3454223132Stuexen break; 3455163953Srrs } 3456163953Srrs case SCTP_FRAGMENT_INTERLEAVE: 3457163953Srrs /* not yet until we re-write sctp_recvmsg() */ 3458163953Srrs { 3459168943Srrs uint32_t *level; 3460163953Srrs 3461168943Srrs SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize); 3462168943Srrs if (*level == SCTP_FRAG_LEVEL_2) { 3463163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 3464168943Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 3465168943Srrs } else if (*level == SCTP_FRAG_LEVEL_1) { 3466168943Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 3467168943Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 3468168943Srrs } else if (*level == SCTP_FRAG_LEVEL_0) { 3469170056Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 3470168943Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 3471168943Srrs 3472163953Srrs } else { 3473171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3474168943Srrs error = EINVAL; 3475163953Srrs } 3476223132Stuexen break; 3477163953Srrs } 3478163953Srrs case SCTP_CMT_ON_OFF: 3479211944Stuexen if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { 3480163953Srrs struct sctp_assoc_value *av; 3481163953Srrs 3482166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 3483223132Stuexen if (av->assoc_value > SCTP_CMT_MAX) { 3484223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3485223132Stuexen error = EINVAL; 3486223132Stuexen break; 3487223132Stuexen } 3488211944Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3489211944Stuexen if (stcb) { 3490223132Stuexen stcb->asoc.sctp_cmt_on_off = av->assoc_value; 3491211944Stuexen SCTP_TCB_UNLOCK(stcb); 3492166675Srrs } else { 3493224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3494224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3495224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 3496223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3497221460Stuexen SCTP_INP_WLOCK(inp); 3498221460Stuexen inp->sctp_cmt_on_off = av->assoc_value; 3499221460Stuexen SCTP_INP_WUNLOCK(inp); 3500216669Stuexen } 3501223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 3502223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3503223132Stuexen SCTP_INP_RLOCK(inp); 3504223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3505223132Stuexen SCTP_TCB_LOCK(stcb); 3506223132Stuexen stcb->asoc.sctp_cmt_on_off = av->assoc_value; 3507223132Stuexen SCTP_TCB_UNLOCK(stcb); 3508223132Stuexen } 3509224918Stuexen SCTP_INP_RUNLOCK(inp); 3510223132Stuexen } 3511163953Srrs } 3512211944Stuexen } else { 3513211944Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 3514211944Stuexen error = ENOPROTOOPT; 3515163953Srrs } 3516163953Srrs break; 3517171440Srrs case SCTP_PLUGGABLE_CC: 3518171440Srrs { 3519171440Srrs struct sctp_assoc_value *av; 3520219057Srrs struct sctp_nets *net; 3521171440Srrs 3522171440Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 3523223132Stuexen if ((av->assoc_value != SCTP_CC_RFC2581) && 3524223132Stuexen (av->assoc_value != SCTP_CC_HSTCP) && 3525223132Stuexen (av->assoc_value != SCTP_CC_HTCP) && 3526223132Stuexen (av->assoc_value != SCTP_CC_RTCC)) { 3527223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3528223132Stuexen error = EINVAL; 3529223132Stuexen break; 3530223132Stuexen } 3531171440Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3532171440Srrs if (stcb) { 3533223132Stuexen stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value]; 3534223132Stuexen stcb->asoc.congestion_control_module = av->assoc_value; 3535223132Stuexen if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) { 3536223132Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3537223132Stuexen stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); 3538219057Srrs } 3539171440Srrs } 3540217611Stuexen SCTP_TCB_UNLOCK(stcb); 3541171440Srrs } else { 3542224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3543224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3544224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 3545223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3546217611Stuexen SCTP_INP_WLOCK(inp); 3547171440Srrs inp->sctp_ep.sctp_default_cc_module = av->assoc_value; 3548217611Stuexen SCTP_INP_WUNLOCK(inp); 3549217760Stuexen } 3550223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 3551223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3552223132Stuexen SCTP_INP_RLOCK(inp); 3553223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3554223132Stuexen SCTP_TCB_LOCK(stcb); 3555223132Stuexen stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value]; 3556223132Stuexen stcb->asoc.congestion_control_module = av->assoc_value; 3557223132Stuexen if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) { 3558223132Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3559223132Stuexen stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); 3560223132Stuexen } 3561223132Stuexen } 3562223132Stuexen SCTP_TCB_UNLOCK(stcb); 3563223132Stuexen } 3564223132Stuexen SCTP_INP_RUNLOCK(inp); 3565223132Stuexen } 3566171440Srrs } 3567223132Stuexen break; 3568171440Srrs } 3569219057Srrs case SCTP_CC_OPTION: 3570219057Srrs { 3571219057Srrs struct sctp_cc_option *cc_opt; 3572219057Srrs 3573219057Srrs SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, optsize); 3574219057Srrs SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id); 3575219057Srrs if (stcb == NULL) { 3576223132Stuexen if (cc_opt->aid_value.assoc_id == SCTP_CURRENT_ASSOC) { 3577223132Stuexen SCTP_INP_RLOCK(inp); 3578223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3579223132Stuexen SCTP_TCB_LOCK(stcb); 3580223132Stuexen if (stcb->asoc.cc_functions.sctp_cwnd_socket_option) { 3581223132Stuexen (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1, cc_opt); 3582223132Stuexen } 3583223132Stuexen SCTP_TCB_UNLOCK(stcb); 3584223132Stuexen } 3585223132Stuexen SCTP_INP_RUNLOCK(inp); 3586223132Stuexen } else { 3587223132Stuexen error = EINVAL; 3588223132Stuexen } 3589219057Srrs } else { 3590219057Srrs if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) { 3591219057Srrs error = ENOTSUP; 3592219057Srrs } else { 3593219057Srrs error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1, 3594219057Srrs cc_opt); 3595219057Srrs } 3596219057Srrs SCTP_TCB_UNLOCK(stcb); 3597219057Srrs } 3598223132Stuexen break; 3599219057Srrs } 3600217760Stuexen case SCTP_PLUGGABLE_SS: 3601217760Stuexen { 3602217760Stuexen struct sctp_assoc_value *av; 3603217760Stuexen 3604217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 3605223132Stuexen if ((av->assoc_value != SCTP_SS_DEFAULT) && 3606223132Stuexen (av->assoc_value != SCTP_SS_ROUND_ROBIN) && 3607223132Stuexen (av->assoc_value != SCTP_SS_ROUND_ROBIN_PACKET) && 3608223132Stuexen (av->assoc_value != SCTP_SS_PRIORITY) && 3609223132Stuexen (av->assoc_value != SCTP_SS_FAIR_BANDWITH) && 3610223132Stuexen (av->assoc_value != SCTP_SS_FIRST_COME)) { 3611223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3612223132Stuexen error = EINVAL; 3613223132Stuexen break; 3614223132Stuexen } 3615217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3616217760Stuexen if (stcb) { 3617223132Stuexen stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1); 3618223132Stuexen stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value]; 3619223132Stuexen stcb->asoc.stream_scheduling_module = av->assoc_value; 3620223132Stuexen stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1); 3621217760Stuexen SCTP_TCB_UNLOCK(stcb); 3622217760Stuexen } else { 3623224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3624224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3625224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 3626223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3627217760Stuexen SCTP_INP_WLOCK(inp); 3628217760Stuexen inp->sctp_ep.sctp_default_ss_module = av->assoc_value; 3629217760Stuexen SCTP_INP_WUNLOCK(inp); 3630217760Stuexen } 3631223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 3632223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3633223132Stuexen SCTP_INP_RLOCK(inp); 3634223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3635223132Stuexen SCTP_TCB_LOCK(stcb); 3636223132Stuexen stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1); 3637223132Stuexen stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value]; 3638223132Stuexen stcb->asoc.stream_scheduling_module = av->assoc_value; 3639223132Stuexen stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1); 3640223132Stuexen SCTP_TCB_UNLOCK(stcb); 3641223132Stuexen } 3642223132Stuexen SCTP_INP_RUNLOCK(inp); 3643223132Stuexen } 3644217760Stuexen } 3645223132Stuexen break; 3646217760Stuexen } 3647217760Stuexen case SCTP_SS_VALUE: 3648217760Stuexen { 3649217760Stuexen struct sctp_stream_value *av; 3650217760Stuexen 3651217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize); 3652217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3653217760Stuexen if (stcb) { 3654217760Stuexen if (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], 3655217760Stuexen av->stream_value) < 0) { 3656217760Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3657217760Stuexen error = EINVAL; 3658217760Stuexen } 3659217760Stuexen SCTP_TCB_UNLOCK(stcb); 3660217760Stuexen } else { 3661223132Stuexen if (av->assoc_id == SCTP_CURRENT_ASSOC) { 3662223132Stuexen SCTP_INP_RLOCK(inp); 3663223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3664223132Stuexen SCTP_TCB_LOCK(stcb); 3665223132Stuexen stcb->asoc.ss_functions.sctp_ss_set_value(stcb, 3666223132Stuexen &stcb->asoc, 3667223132Stuexen &stcb->asoc.strmout[av->stream_id], 3668223132Stuexen av->stream_value); 3669223132Stuexen SCTP_TCB_UNLOCK(stcb); 3670223132Stuexen } 3671223132Stuexen SCTP_INP_RUNLOCK(inp); 3672223132Stuexen 3673223132Stuexen } else { 3674223132Stuexen /* 3675223132Stuexen * Can't set stream value without 3676223132Stuexen * association 3677223132Stuexen */ 3678223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3679223132Stuexen error = EINVAL; 3680223132Stuexen } 3681217760Stuexen } 3682223132Stuexen break; 3683217760Stuexen } 3684163953Srrs case SCTP_CLR_STAT_LOG: 3685171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 3686163953Srrs error = EOPNOTSUPP; 3687163953Srrs break; 3688163953Srrs case SCTP_CONTEXT: 3689163953Srrs { 3690163953Srrs struct sctp_assoc_value *av; 3691163953Srrs 3692166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 3693166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3694166675Srrs 3695166675Srrs if (stcb) { 3696166675Srrs stcb->asoc.context = av->assoc_value; 3697166675Srrs SCTP_TCB_UNLOCK(stcb); 3698163953Srrs } else { 3699224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3700224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3701224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 3702223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3703223132Stuexen SCTP_INP_WLOCK(inp); 3704223132Stuexen inp->sctp_context = av->assoc_value; 3705223132Stuexen SCTP_INP_WUNLOCK(inp); 3706223132Stuexen } 3707223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 3708223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3709223132Stuexen SCTP_INP_RLOCK(inp); 3710223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3711223132Stuexen SCTP_TCB_LOCK(stcb); 3712223132Stuexen stcb->asoc.context = av->assoc_value; 3713223132Stuexen SCTP_TCB_UNLOCK(stcb); 3714223132Stuexen } 3715223132Stuexen SCTP_INP_RUNLOCK(inp); 3716223132Stuexen } 3717163953Srrs } 3718223132Stuexen break; 3719163953Srrs } 3720167598Srrs case SCTP_VRF_ID: 3721167598Srrs { 3722170056Srrs uint32_t *default_vrfid; 3723167598Srrs 3724170056Srrs SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize); 3725170056Srrs if (*default_vrfid > SCTP_MAX_VRF_ID) { 3726171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3727167598Srrs error = EINVAL; 3728167598Srrs break; 3729167598Srrs } 3730170056Srrs inp->def_vrf_id = *default_vrfid; 3731167598Srrs break; 3732167598Srrs } 3733167598Srrs case SCTP_DEL_VRF_ID: 3734167598Srrs { 3735171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 3736167598Srrs error = EOPNOTSUPP; 3737167598Srrs break; 3738167598Srrs } 3739167598Srrs case SCTP_ADD_VRF_ID: 3740167598Srrs { 3741171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 3742167598Srrs error = EOPNOTSUPP; 3743167598Srrs break; 3744167598Srrs } 3745170056Srrs case SCTP_DELAYED_SACK: 3746163953Srrs { 3747170056Srrs struct sctp_sack_info *sack; 3748163953Srrs 3749170056Srrs SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize); 3750170056Srrs SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); 3751171477Srrs if (sack->sack_delay) { 3752171477Srrs if (sack->sack_delay > SCTP_MAX_SACK_DELAY) 3753171477Srrs sack->sack_delay = SCTP_MAX_SACK_DELAY; 3754223132Stuexen if (MSEC_TO_TICKS(sack->sack_delay) < 1) { 3755223132Stuexen sack->sack_delay = TICKS_TO_MSEC(1); 3756223132Stuexen } 3757171477Srrs } 3758166675Srrs if (stcb) { 3759170056Srrs if (sack->sack_delay) { 3760170056Srrs stcb->asoc.delayed_ack = sack->sack_delay; 3761170056Srrs } 3762170056Srrs if (sack->sack_freq) { 3763170056Srrs stcb->asoc.sack_freq = sack->sack_freq; 3764170056Srrs } 3765166675Srrs SCTP_TCB_UNLOCK(stcb); 3766166675Srrs } else { 3767224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3768224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3769224918Stuexen (sack->sack_assoc_id == SCTP_FUTURE_ASSOC) || 3770223132Stuexen (sack->sack_assoc_id == SCTP_ALL_ASSOC)) { 3771223132Stuexen SCTP_INP_WLOCK(inp); 3772223132Stuexen if (sack->sack_delay) { 3773223132Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay); 3774170056Srrs } 3775223132Stuexen if (sack->sack_freq) { 3776223132Stuexen inp->sctp_ep.sctp_sack_freq = sack->sack_freq; 3777223132Stuexen } 3778223132Stuexen SCTP_INP_WUNLOCK(inp); 3779170056Srrs } 3780223132Stuexen if ((sack->sack_assoc_id == SCTP_CURRENT_ASSOC) || 3781223132Stuexen (sack->sack_assoc_id == SCTP_ALL_ASSOC)) { 3782223132Stuexen SCTP_INP_RLOCK(inp); 3783223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3784223132Stuexen SCTP_TCB_LOCK(stcb); 3785223132Stuexen if (sack->sack_delay) { 3786223132Stuexen stcb->asoc.delayed_ack = sack->sack_delay; 3787223132Stuexen } 3788223132Stuexen if (sack->sack_freq) { 3789223132Stuexen stcb->asoc.sack_freq = sack->sack_freq; 3790223132Stuexen } 3791223132Stuexen SCTP_TCB_UNLOCK(stcb); 3792223132Stuexen } 3793223132Stuexen SCTP_INP_RUNLOCK(inp); 3794170056Srrs } 3795163953Srrs } 3796166675Srrs break; 3797163953Srrs } 3798163953Srrs case SCTP_AUTH_CHUNK: 3799163953Srrs { 3800163953Srrs struct sctp_authchunk *sauth; 3801163953Srrs 3802166675Srrs SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize); 3803166675Srrs 3804166675Srrs SCTP_INP_WLOCK(inp); 3805171943Srrs if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) { 3806171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3807163953Srrs error = EINVAL; 3808171943Srrs } 3809166675Srrs SCTP_INP_WUNLOCK(inp); 3810163953Srrs break; 3811163953Srrs } 3812163953Srrs case SCTP_AUTH_KEY: 3813163953Srrs { 3814163953Srrs struct sctp_authkey *sca; 3815163953Srrs struct sctp_keyhead *shared_keys; 3816163953Srrs sctp_sharedkey_t *shared_key; 3817163953Srrs sctp_key_t *key = NULL; 3818166675Srrs size_t size; 3819163953Srrs 3820166675Srrs SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize); 3821223697Stuexen if (sca->sca_keylength == 0) { 3822223697Stuexen size = optsize - sizeof(struct sctp_authkey); 3823223697Stuexen } else { 3824223697Stuexen if (sca->sca_keylength + sizeof(struct sctp_authkey) <= optsize) { 3825223697Stuexen size = sca->sca_keylength; 3826223697Stuexen } else { 3827223697Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3828223697Stuexen error = EINVAL; 3829223697Stuexen break; 3830223697Stuexen } 3831223697Stuexen } 3832169420Srrs SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id); 3833166675Srrs 3834166675Srrs if (stcb) { 3835163953Srrs shared_keys = &stcb->asoc.shared_keys; 3836163953Srrs /* clear the cached keys for this key id */ 3837163953Srrs sctp_clear_cachedkeys(stcb, sca->sca_keynumber); 3838163953Srrs /* 3839163953Srrs * create the new shared key and 3840163953Srrs * insert/replace it 3841163953Srrs */ 3842163953Srrs if (size > 0) { 3843163953Srrs key = sctp_set_key(sca->sca_key, (uint32_t) size); 3844163953Srrs if (key == NULL) { 3845171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3846163953Srrs error = ENOMEM; 3847163953Srrs SCTP_TCB_UNLOCK(stcb); 3848163953Srrs break; 3849163953Srrs } 3850163953Srrs } 3851163953Srrs shared_key = sctp_alloc_sharedkey(); 3852163953Srrs if (shared_key == NULL) { 3853163953Srrs sctp_free_key(key); 3854171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3855163953Srrs error = ENOMEM; 3856163953Srrs SCTP_TCB_UNLOCK(stcb); 3857163953Srrs break; 3858163953Srrs } 3859163953Srrs shared_key->key = key; 3860163953Srrs shared_key->keyid = sca->sca_keynumber; 3861185694Srrs error = sctp_insert_sharedkey(shared_keys, shared_key); 3862163953Srrs SCTP_TCB_UNLOCK(stcb); 3863163953Srrs } else { 3864224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3865224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3866224918Stuexen (sca->sca_assoc_id == SCTP_FUTURE_ASSOC) || 3867223132Stuexen (sca->sca_assoc_id == SCTP_ALL_ASSOC)) { 3868223132Stuexen SCTP_INP_WLOCK(inp); 3869223132Stuexen shared_keys = &inp->sctp_ep.shared_keys; 3870223132Stuexen /* 3871223132Stuexen * clear the cached keys on all 3872223132Stuexen * assocs for this key id 3873223132Stuexen */ 3874223132Stuexen sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber); 3875223132Stuexen /* 3876223132Stuexen * create the new shared key and 3877223132Stuexen * insert/replace it 3878223132Stuexen */ 3879223132Stuexen if (size > 0) { 3880223132Stuexen key = sctp_set_key(sca->sca_key, (uint32_t) size); 3881223132Stuexen if (key == NULL) { 3882223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3883223132Stuexen error = ENOMEM; 3884223132Stuexen SCTP_INP_WUNLOCK(inp); 3885223132Stuexen break; 3886223132Stuexen } 3887223132Stuexen } 3888223132Stuexen shared_key = sctp_alloc_sharedkey(); 3889223132Stuexen if (shared_key == NULL) { 3890223132Stuexen sctp_free_key(key); 3891171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3892163953Srrs error = ENOMEM; 3893163953Srrs SCTP_INP_WUNLOCK(inp); 3894163953Srrs break; 3895163953Srrs } 3896223132Stuexen shared_key->key = key; 3897223132Stuexen shared_key->keyid = sca->sca_keynumber; 3898223132Stuexen error = sctp_insert_sharedkey(shared_keys, shared_key); 3899163953Srrs SCTP_INP_WUNLOCK(inp); 3900163953Srrs } 3901223132Stuexen if ((sca->sca_assoc_id == SCTP_CURRENT_ASSOC) || 3902223132Stuexen (sca->sca_assoc_id == SCTP_ALL_ASSOC)) { 3903223132Stuexen SCTP_INP_RLOCK(inp); 3904223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3905223132Stuexen SCTP_TCB_LOCK(stcb); 3906223132Stuexen shared_keys = &stcb->asoc.shared_keys; 3907223132Stuexen /* 3908223132Stuexen * clear the cached keys for 3909223132Stuexen * this key id 3910223132Stuexen */ 3911223132Stuexen sctp_clear_cachedkeys(stcb, sca->sca_keynumber); 3912223132Stuexen /* 3913223132Stuexen * create the new shared key 3914223132Stuexen * and insert/replace it 3915223132Stuexen */ 3916223132Stuexen if (size > 0) { 3917223132Stuexen key = sctp_set_key(sca->sca_key, (uint32_t) size); 3918223132Stuexen if (key == NULL) { 3919223132Stuexen SCTP_TCB_UNLOCK(stcb); 3920223132Stuexen continue; 3921223132Stuexen } 3922223132Stuexen } 3923223132Stuexen shared_key = sctp_alloc_sharedkey(); 3924223132Stuexen if (shared_key == NULL) { 3925223132Stuexen sctp_free_key(key); 3926223132Stuexen SCTP_TCB_UNLOCK(stcb); 3927223132Stuexen continue; 3928223132Stuexen } 3929223132Stuexen shared_key->key = key; 3930223132Stuexen shared_key->keyid = sca->sca_keynumber; 3931223132Stuexen error = sctp_insert_sharedkey(shared_keys, shared_key); 3932223132Stuexen SCTP_TCB_UNLOCK(stcb); 3933223132Stuexen } 3934223132Stuexen SCTP_INP_RUNLOCK(inp); 3935223132Stuexen } 3936163953Srrs } 3937163953Srrs break; 3938163953Srrs } 3939163953Srrs case SCTP_HMAC_IDENT: 3940163953Srrs { 3941163953Srrs struct sctp_hmacalgo *shmac; 3942163953Srrs sctp_hmaclist_t *hmaclist; 3943181054Srrs uint16_t hmacid; 3944181054Srrs uint32_t i; 3945181054Srrs size_t found; 3946181054Srrs 3947166675Srrs SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize); 3948181054Srrs if (optsize < sizeof(struct sctp_hmacalgo) + shmac->shmac_number_of_idents * sizeof(uint16_t)) { 3949181054Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3950181054Srrs error = EINVAL; 3951181054Srrs break; 3952181054Srrs } 3953181054Srrs hmaclist = sctp_alloc_hmaclist(shmac->shmac_number_of_idents); 3954163953Srrs if (hmaclist == NULL) { 3955171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3956163953Srrs error = ENOMEM; 3957163953Srrs break; 3958163953Srrs } 3959181054Srrs for (i = 0; i < shmac->shmac_number_of_idents; i++) { 3960163953Srrs hmacid = shmac->shmac_idents[i]; 3961181054Srrs if (sctp_auth_add_hmacid(hmaclist, hmacid)) { 3962163953Srrs /* invalid HMACs were found */ ; 3963171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3964163953Srrs error = EINVAL; 3965164085Srrs sctp_free_hmaclist(hmaclist); 3966163953Srrs goto sctp_set_hmac_done; 3967163953Srrs } 3968163953Srrs } 3969170056Srrs found = 0; 3970170056Srrs for (i = 0; i < hmaclist->num_algo; i++) { 3971170056Srrs if (hmaclist->hmac[i] == SCTP_AUTH_HMAC_ID_SHA1) { 3972170056Srrs /* already in list */ 3973170056Srrs found = 1; 3974170056Srrs } 3975170056Srrs } 3976170056Srrs if (!found) { 3977170056Srrs sctp_free_hmaclist(hmaclist); 3978171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3979170056Srrs error = EINVAL; 3980170056Srrs break; 3981170056Srrs } 3982163953Srrs /* set it on the endpoint */ 3983163953Srrs SCTP_INP_WLOCK(inp); 3984163953Srrs if (inp->sctp_ep.local_hmacs) 3985163953Srrs sctp_free_hmaclist(inp->sctp_ep.local_hmacs); 3986163953Srrs inp->sctp_ep.local_hmacs = hmaclist; 3987163953Srrs SCTP_INP_WUNLOCK(inp); 3988163953Srrs sctp_set_hmac_done: 3989163953Srrs break; 3990163953Srrs } 3991163953Srrs case SCTP_AUTH_ACTIVE_KEY: 3992163953Srrs { 3993163953Srrs struct sctp_authkeyid *scact; 3994163953Srrs 3995223132Stuexen SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize); 3996166675Srrs SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); 3997166675Srrs 3998163953Srrs /* set the active key on the right place */ 3999166675Srrs if (stcb) { 4000163953Srrs /* set the active key on the assoc */ 4001185694Srrs if (sctp_auth_setactivekey(stcb, 4002185694Srrs scact->scact_keynumber)) { 4003185694Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, 4004185694Srrs SCTP_FROM_SCTP_USRREQ, 4005185694Srrs EINVAL); 4006163953Srrs error = EINVAL; 4007171943Srrs } 4008163953Srrs SCTP_TCB_UNLOCK(stcb); 4009163953Srrs } else { 4010224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4011224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4012224918Stuexen (scact->scact_assoc_id == SCTP_FUTURE_ASSOC) || 4013223132Stuexen (scact->scact_assoc_id == SCTP_ALL_ASSOC)) { 4014223132Stuexen SCTP_INP_WLOCK(inp); 4015223132Stuexen if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) { 4016223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4017223132Stuexen error = EINVAL; 4018223132Stuexen } 4019223132Stuexen SCTP_INP_WUNLOCK(inp); 4020171943Srrs } 4021223132Stuexen if ((scact->scact_assoc_id == SCTP_CURRENT_ASSOC) || 4022223132Stuexen (scact->scact_assoc_id == SCTP_ALL_ASSOC)) { 4023223132Stuexen SCTP_INP_RLOCK(inp); 4024223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4025223132Stuexen SCTP_TCB_LOCK(stcb); 4026223132Stuexen sctp_auth_setactivekey(stcb, scact->scact_keynumber); 4027223132Stuexen SCTP_TCB_UNLOCK(stcb); 4028223132Stuexen } 4029223132Stuexen SCTP_INP_RUNLOCK(inp); 4030223132Stuexen } 4031163953Srrs } 4032163953Srrs break; 4033163953Srrs } 4034163953Srrs case SCTP_AUTH_DELETE_KEY: 4035163953Srrs { 4036163953Srrs struct sctp_authkeyid *scdel; 4037163953Srrs 4038223132Stuexen SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize); 4039166675Srrs SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id); 4040166675Srrs 4041163953Srrs /* delete the key from the right place */ 4042166675Srrs if (stcb) { 4043223132Stuexen if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) { 4044223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4045163953Srrs error = EINVAL; 4046171943Srrs } 4047163953Srrs SCTP_TCB_UNLOCK(stcb); 4048163953Srrs } else { 4049224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4050224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4051224918Stuexen (scdel->scact_assoc_id == SCTP_FUTURE_ASSOC) || 4052223132Stuexen (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) { 4053223132Stuexen SCTP_INP_WLOCK(inp); 4054223132Stuexen if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) { 4055223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4056223132Stuexen error = EINVAL; 4057223132Stuexen } 4058223132Stuexen SCTP_INP_WUNLOCK(inp); 4059171943Srrs } 4060223132Stuexen if ((scdel->scact_assoc_id == SCTP_CURRENT_ASSOC) || 4061223132Stuexen (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) { 4062223132Stuexen SCTP_INP_RLOCK(inp); 4063223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4064223132Stuexen SCTP_TCB_LOCK(stcb); 4065223132Stuexen sctp_delete_sharedkey(stcb, scdel->scact_keynumber); 4066223132Stuexen SCTP_TCB_UNLOCK(stcb); 4067223132Stuexen } 4068223132Stuexen SCTP_INP_RUNLOCK(inp); 4069223132Stuexen } 4070163953Srrs } 4071163953Srrs break; 4072163953Srrs } 4073185694Srrs case SCTP_AUTH_DEACTIVATE_KEY: 4074185694Srrs { 4075185694Srrs struct sctp_authkeyid *keyid; 4076163953Srrs 4077223132Stuexen SCTP_CHECK_AND_CAST(keyid, optval, struct sctp_authkeyid, optsize); 4078185694Srrs SCTP_FIND_STCB(inp, stcb, keyid->scact_assoc_id); 4079185694Srrs 4080185694Srrs /* deactivate the key from the right place */ 4081185694Srrs if (stcb) { 4082223132Stuexen if (sctp_deact_sharedkey(stcb, keyid->scact_keynumber)) { 4083223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4084185694Srrs error = EINVAL; 4085185694Srrs } 4086185694Srrs SCTP_TCB_UNLOCK(stcb); 4087185694Srrs } else { 4088224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4089224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4090224918Stuexen (keyid->scact_assoc_id == SCTP_FUTURE_ASSOC) || 4091223132Stuexen (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) { 4092223132Stuexen SCTP_INP_WLOCK(inp); 4093223132Stuexen if (sctp_deact_sharedkey_ep(inp, keyid->scact_keynumber)) { 4094223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4095223132Stuexen error = EINVAL; 4096223132Stuexen } 4097223132Stuexen SCTP_INP_WUNLOCK(inp); 4098185694Srrs } 4099223132Stuexen if ((keyid->scact_assoc_id == SCTP_CURRENT_ASSOC) || 4100223132Stuexen (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) { 4101223132Stuexen SCTP_INP_RLOCK(inp); 4102223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4103223132Stuexen SCTP_TCB_LOCK(stcb); 4104223132Stuexen sctp_deact_sharedkey(stcb, keyid->scact_keynumber); 4105223132Stuexen SCTP_TCB_UNLOCK(stcb); 4106223132Stuexen } 4107223132Stuexen SCTP_INP_RUNLOCK(inp); 4108223132Stuexen } 4109185694Srrs } 4110185694Srrs break; 4111185694Srrs } 4112233660Srrs case SCTP_ENABLE_STREAM_RESET: 4113233660Srrs { 4114233660Srrs struct sctp_assoc_value *av; 4115185694Srrs 4116233660Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 4117233660Srrs if (av->assoc_value & (~SCTP_ENABLE_VALUE_MASK)) { 4118233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4119233660Srrs error = EINVAL; 4120233660Srrs break; 4121233660Srrs } 4122233660Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4123233660Srrs if (stcb) { 4124235021Stuexen stcb->asoc.local_strreset_support = (uint8_t) av->assoc_value; 4125233660Srrs SCTP_TCB_UNLOCK(stcb); 4126233660Srrs } else { 4127233660Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4128233660Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4129233660Srrs (av->assoc_id == SCTP_FUTURE_ASSOC) || 4130233660Srrs (av->assoc_id == SCTP_ALL_ASSOC)) { 4131233660Srrs SCTP_INP_WLOCK(inp); 4132235021Stuexen inp->local_strreset_support = (uint8_t) av->assoc_value; 4133233660Srrs SCTP_INP_WUNLOCK(inp); 4134233660Srrs } 4135233660Srrs if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 4136233660Srrs (av->assoc_id == SCTP_ALL_ASSOC)) { 4137233660Srrs SCTP_INP_RLOCK(inp); 4138233660Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4139233660Srrs SCTP_TCB_LOCK(stcb); 4140235021Stuexen stcb->asoc.local_strreset_support = (uint8_t) av->assoc_value; 4141233660Srrs SCTP_TCB_UNLOCK(stcb); 4142233660Srrs } 4143233660Srrs SCTP_INP_RUNLOCK(inp); 4144233660Srrs } 4145233660Srrs } 4146233660Srrs break; 4147233660Srrs } 4148163953Srrs case SCTP_RESET_STREAMS: 4149163953Srrs { 4150233660Srrs struct sctp_reset_streams *strrst; 4151233660Srrs int i, send_out = 0; 4152233660Srrs int send_in = 0; 4153163953Srrs 4154233660Srrs SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_reset_streams, optsize); 4155233660Srrs SCTP_FIND_STCB(inp, stcb, strrst->srs_assoc_id); 4156163953Srrs if (stcb == NULL) { 4157171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4158163953Srrs error = ENOENT; 4159163953Srrs break; 4160163953Srrs } 4161163953Srrs if (stcb->asoc.peer_supports_strreset == 0) { 4162163953Srrs /* 4163233660Srrs * Peer does not support the chunk type. 4164163953Srrs */ 4165233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4166233660Srrs error = EOPNOTSUPP; 4167163953Srrs SCTP_TCB_UNLOCK(stcb); 4168163953Srrs break; 4169163953Srrs } 4170163953Srrs if (stcb->asoc.stream_reset_outstanding) { 4171171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4172163953Srrs error = EALREADY; 4173163953Srrs SCTP_TCB_UNLOCK(stcb); 4174163953Srrs break; 4175163953Srrs } 4176233660Srrs if (strrst->srs_flags & SCTP_STREAM_RESET_INCOMING) { 4177163953Srrs send_in = 1; 4178233660Srrs } 4179233660Srrs if (strrst->srs_flags & SCTP_STREAM_RESET_OUTGOING) { 4180163953Srrs send_out = 1; 4181233660Srrs } 4182233660Srrs if ((send_in == 0) && (send_out == 0)) { 4183233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4184233660Srrs error = EINVAL; 4185233660Srrs SCTP_TCB_UNLOCK(stcb); 4186233660Srrs break; 4187233660Srrs } 4188233660Srrs for (i = 0; i < strrst->srs_number_streams; i++) { 4189233660Srrs if ((send_in) && 4190233660Srrs (strrst->srs_stream_list[i] > stcb->asoc.streamincnt)) { 4191233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4192188854Srrs error = EINVAL; 4193233660Srrs break; 4194188854Srrs } 4195233660Srrs if ((send_out) && 4196233660Srrs (strrst->srs_stream_list[i] > stcb->asoc.streamoutcnt)) { 4197233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4198233660Srrs error = EINVAL; 4199233660Srrs break; 4200188854Srrs } 4201233660Srrs } 4202233660Srrs if (error) { 4203233660Srrs SCTP_TCB_UNLOCK(stcb); 4204233660Srrs break; 4205233660Srrs } 4206233660Srrs error = sctp_send_str_reset_req(stcb, strrst->srs_number_streams, 4207233660Srrs strrst->srs_stream_list, 4208233660Srrs send_out, send_in, 0, 0, 0, 0, 0); 4209233660Srrs 4210233660Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); 4211233660Srrs SCTP_TCB_UNLOCK(stcb); 4212233660Srrs break; 4213233660Srrs } 4214233660Srrs case SCTP_ADD_STREAMS: 4215233660Srrs { 4216233660Srrs struct sctp_add_streams *stradd; 4217233660Srrs uint8_t addstream = 0; 4218233660Srrs uint16_t add_o_strmcnt = 0; 4219233660Srrs uint16_t add_i_strmcnt = 0; 4220233660Srrs 4221233660Srrs SCTP_CHECK_AND_CAST(stradd, optval, struct sctp_add_streams, optsize); 4222233660Srrs SCTP_FIND_STCB(inp, stcb, stradd->sas_assoc_id); 4223233660Srrs if (stcb == NULL) { 4224233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4225233660Srrs error = ENOENT; 4226233660Srrs break; 4227233660Srrs } 4228235057Stuexen if (stcb->asoc.peer_supports_strreset == 0) { 4229235057Stuexen /* 4230235057Stuexen * Peer does not support the chunk type. 4231235057Stuexen */ 4232235057Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4233235057Stuexen error = EOPNOTSUPP; 4234235057Stuexen SCTP_TCB_UNLOCK(stcb); 4235235057Stuexen break; 4236235057Stuexen } 4237235057Stuexen if (stcb->asoc.stream_reset_outstanding) { 4238235057Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4239235057Stuexen error = EALREADY; 4240235057Stuexen SCTP_TCB_UNLOCK(stcb); 4241235057Stuexen break; 4242235057Stuexen } 4243233660Srrs if ((stradd->sas_outstrms == 0) && 4244233660Srrs (stradd->sas_instrms == 0)) { 4245233660Srrs error = EINVAL; 4246233660Srrs goto skip_stuff; 4247233660Srrs } 4248233660Srrs if (stradd->sas_outstrms) { 4249188854Srrs addstream = 1; 4250188854Srrs /* We allocate here */ 4251233660Srrs add_o_strmcnt = stradd->sas_outstrms; 4252233660Srrs if ((((int)add_o_strmcnt) + ((int)stcb->asoc.streamoutcnt)) > 0x0000ffff) { 4253188854Srrs /* You can't have more than 64k */ 4254188854Srrs error = EINVAL; 4255188854Srrs goto skip_stuff; 4256188854Srrs } 4257163953Srrs } 4258233660Srrs if (stradd->sas_instrms) { 4259233660Srrs int cnt; 4260163953Srrs 4261233660Srrs addstream |= 2; 4262233660Srrs /* 4263233660Srrs * We allocate inside 4264233660Srrs * sctp_send_str_reset_req() 4265233660Srrs */ 4266233660Srrs add_i_strmcnt = stradd->sas_instrms; 4267233660Srrs cnt = add_i_strmcnt; 4268233660Srrs cnt += stcb->asoc.streamincnt; 4269233660Srrs if (cnt > 0x0000ffff) { 4270233660Srrs /* You can't have more than 64k */ 4271163953Srrs error = EINVAL; 4272233660Srrs goto skip_stuff; 4273163953Srrs } 4274233660Srrs if (cnt > (int)stcb->asoc.max_inbound_streams) { 4275233660Srrs /* More than you are allowed */ 4276163953Srrs error = EINVAL; 4277233660Srrs goto skip_stuff; 4278163953Srrs } 4279163953Srrs } 4280233660Srrs error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 0, addstream, add_o_strmcnt, add_i_strmcnt, 0); 4281233660Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); 4282188854Srrs skip_stuff: 4283233660Srrs SCTP_TCB_UNLOCK(stcb); 4284233660Srrs break; 4285233660Srrs } 4286233660Srrs case SCTP_RESET_ASSOC: 4287233660Srrs { 4288233660Srrs uint32_t *value; 4289233660Srrs 4290233660Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); 4291233660Srrs SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value); 4292233660Srrs if (stcb == NULL) { 4293233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4294233660Srrs error = ENOENT; 4295233660Srrs break; 4296233660Srrs } 4297233660Srrs if (stcb->asoc.peer_supports_strreset == 0) { 4298233660Srrs /* 4299233660Srrs * Peer does not support the chunk type. 4300233660Srrs */ 4301233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4302233660Srrs error = EOPNOTSUPP; 4303163953Srrs SCTP_TCB_UNLOCK(stcb); 4304163953Srrs break; 4305163953Srrs } 4306233660Srrs if (stcb->asoc.stream_reset_outstanding) { 4307233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4308233660Srrs error = EALREADY; 4309233660Srrs SCTP_TCB_UNLOCK(stcb); 4310233660Srrs break; 4311233660Srrs } 4312233660Srrs error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 1, 0, 0, 0, 0); 4313172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); 4314163953Srrs SCTP_TCB_UNLOCK(stcb); 4315223132Stuexen break; 4316163953Srrs } 4317163953Srrs case SCTP_CONNECT_X: 4318166675Srrs if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { 4319171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4320163953Srrs error = EINVAL; 4321163953Srrs break; 4322163953Srrs } 4323166675Srrs error = sctp_do_connect_x(so, inp, optval, optsize, p, 0); 4324163953Srrs break; 4325163953Srrs case SCTP_CONNECT_X_DELAYED: 4326166675Srrs if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { 4327171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4328163953Srrs error = EINVAL; 4329163953Srrs break; 4330163953Srrs } 4331166675Srrs error = sctp_do_connect_x(so, inp, optval, optsize, p, 1); 4332163953Srrs break; 4333163953Srrs case SCTP_CONNECT_X_COMPLETE: 4334163953Srrs { 4335163953Srrs struct sockaddr *sa; 4336163953Srrs struct sctp_nets *net; 4337163953Srrs 4338166675Srrs /* FIXME MT: check correct? */ 4339166675Srrs SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize); 4340166675Srrs 4341163953Srrs /* find tcb */ 4342163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 4343163953Srrs SCTP_INP_RLOCK(inp); 4344163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 4345163953Srrs if (stcb) { 4346163953Srrs SCTP_TCB_LOCK(stcb); 4347163953Srrs net = sctp_findnet(stcb, sa); 4348163953Srrs } 4349163953Srrs SCTP_INP_RUNLOCK(inp); 4350163953Srrs } else { 4351166675Srrs /* 4352166675Srrs * We increment here since 4353166675Srrs * sctp_findassociation_ep_addr() wil do a 4354166675Srrs * decrement if it finds the stcb as long as 4355166675Srrs * the locked tcb (last argument) is NOT a 4356166675Srrs * TCB.. aka NULL. 4357166675Srrs */ 4358163953Srrs SCTP_INP_INCR_REF(inp); 4359163953Srrs stcb = sctp_findassociation_ep_addr(&inp, sa, &net, NULL, NULL); 4360163953Srrs if (stcb == NULL) { 4361163953Srrs SCTP_INP_DECR_REF(inp); 4362163953Srrs } 4363163953Srrs } 4364163953Srrs 4365163953Srrs if (stcb == NULL) { 4366171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4367163953Srrs error = ENOENT; 4368163953Srrs break; 4369163953Srrs } 4370163953Srrs if (stcb->asoc.delayed_connection == 1) { 4371163953Srrs stcb->asoc.delayed_connection = 0; 4372169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 4373165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, 4374165220Srrs stcb->asoc.primary_destination, 4375165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9); 4376172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 4377163953Srrs } else { 4378163953Srrs /* 4379163953Srrs * already expired or did not use delayed 4380163953Srrs * connectx 4381163953Srrs */ 4382171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4383163953Srrs error = EALREADY; 4384163953Srrs } 4385163953Srrs SCTP_TCB_UNLOCK(stcb); 4386223132Stuexen break; 4387163953Srrs } 4388170056Srrs case SCTP_MAX_BURST: 4389163953Srrs { 4390217895Stuexen struct sctp_assoc_value *av; 4391163953Srrs 4392217895Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 4393217895Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4394166675Srrs 4395217895Stuexen if (stcb) { 4396217895Stuexen stcb->asoc.max_burst = av->assoc_value; 4397217895Stuexen SCTP_TCB_UNLOCK(stcb); 4398217895Stuexen } else { 4399224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4400224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4401224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 4402223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 4403223132Stuexen SCTP_INP_WLOCK(inp); 4404223132Stuexen inp->sctp_ep.max_burst = av->assoc_value; 4405223132Stuexen SCTP_INP_WUNLOCK(inp); 4406223132Stuexen } 4407223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 4408223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 4409223132Stuexen SCTP_INP_RLOCK(inp); 4410223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4411223132Stuexen SCTP_TCB_LOCK(stcb); 4412223132Stuexen stcb->asoc.max_burst = av->assoc_value; 4413223132Stuexen SCTP_TCB_UNLOCK(stcb); 4414223132Stuexen } 4415223132Stuexen SCTP_INP_RUNLOCK(inp); 4416223132Stuexen } 4417217895Stuexen } 4418223132Stuexen break; 4419163953Srrs } 4420163953Srrs case SCTP_MAXSEG: 4421163953Srrs { 4422167598Srrs struct sctp_assoc_value *av; 4423163953Srrs int ovh; 4424163953Srrs 4425167598Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 4426167598Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4427166675Srrs 4428170056Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 4429170056Srrs ovh = SCTP_MED_OVERHEAD; 4430170056Srrs } else { 4431170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 4432170056Srrs } 4433167598Srrs if (stcb) { 4434170056Srrs if (av->assoc_value) { 4435170056Srrs stcb->asoc.sctp_frag_point = (av->assoc_value + ovh); 4436170056Srrs } else { 4437170056Srrs stcb->asoc.sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; 4438170056Srrs } 4439167598Srrs SCTP_TCB_UNLOCK(stcb); 4440163953Srrs } else { 4441224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4442224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4443224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 4444223132Stuexen SCTP_INP_WLOCK(inp); 4445223132Stuexen /* 4446223132Stuexen * FIXME MT: I think this is not in 4447223132Stuexen * tune with the API ID 4448223132Stuexen */ 4449223132Stuexen if (av->assoc_value) { 4450223132Stuexen inp->sctp_frag_point = (av->assoc_value + ovh); 4451223132Stuexen } else { 4452223132Stuexen inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; 4453223132Stuexen } 4454223132Stuexen SCTP_INP_WUNLOCK(inp); 4455167598Srrs } else { 4456223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4457223132Stuexen error = EINVAL; 4458167598Srrs } 4459163953Srrs } 4460223132Stuexen break; 4461163953Srrs } 4462163953Srrs case SCTP_EVENTS: 4463163953Srrs { 4464163953Srrs struct sctp_event_subscribe *events; 4465163953Srrs 4466166675Srrs SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize); 4467166675Srrs 4468163953Srrs SCTP_INP_WLOCK(inp); 4469163953Srrs if (events->sctp_data_io_event) { 4470163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); 4471163953Srrs } else { 4472163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); 4473163953Srrs } 4474163953Srrs 4475163953Srrs if (events->sctp_association_event) { 4476163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); 4477163953Srrs } else { 4478163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); 4479163953Srrs } 4480163953Srrs 4481163953Srrs if (events->sctp_address_event) { 4482163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); 4483163953Srrs } else { 4484163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); 4485163953Srrs } 4486163953Srrs 4487163953Srrs if (events->sctp_send_failure_event) { 4488163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 4489163953Srrs } else { 4490163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 4491163953Srrs } 4492163953Srrs 4493163953Srrs if (events->sctp_peer_error_event) { 4494163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR); 4495163953Srrs } else { 4496163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR); 4497163953Srrs } 4498163953Srrs 4499163953Srrs if (events->sctp_shutdown_event) { 4500163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 4501163953Srrs } else { 4502163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 4503163953Srrs } 4504163953Srrs 4505163953Srrs if (events->sctp_partial_delivery_event) { 4506163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT); 4507163953Srrs } else { 4508163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT); 4509163953Srrs } 4510163953Srrs 4511163953Srrs if (events->sctp_adaptation_layer_event) { 4512163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 4513163953Srrs } else { 4514163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 4515163953Srrs } 4516163953Srrs 4517163953Srrs if (events->sctp_authentication_event) { 4518163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT); 4519163953Srrs } else { 4520163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT); 4521163953Srrs } 4522163953Srrs 4523185694Srrs if (events->sctp_sender_dry_event) { 4524185694Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT); 4525185694Srrs } else { 4526185694Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT); 4527185694Srrs } 4528185694Srrs 4529202520Srrs if (events->sctp_stream_reset_event) { 4530163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 4531163953Srrs } else { 4532163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 4533163953Srrs } 4534163953Srrs SCTP_INP_WUNLOCK(inp); 4535223132Stuexen 4536223132Stuexen SCTP_INP_RLOCK(inp); 4537223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4538223132Stuexen SCTP_TCB_LOCK(stcb); 4539223132Stuexen if (events->sctp_association_event) { 4540223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT); 4541223132Stuexen } else { 4542223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT); 4543223132Stuexen } 4544223132Stuexen if (events->sctp_address_event) { 4545223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT); 4546223132Stuexen } else { 4547223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT); 4548223132Stuexen } 4549223132Stuexen if (events->sctp_send_failure_event) { 4550223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 4551223132Stuexen } else { 4552223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 4553223132Stuexen } 4554223132Stuexen if (events->sctp_peer_error_event) { 4555223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR); 4556223132Stuexen } else { 4557223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR); 4558223132Stuexen } 4559223132Stuexen if (events->sctp_shutdown_event) { 4560223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 4561223132Stuexen } else { 4562223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 4563223132Stuexen } 4564223132Stuexen if (events->sctp_partial_delivery_event) { 4565223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT); 4566223132Stuexen } else { 4567223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT); 4568223132Stuexen } 4569223132Stuexen if (events->sctp_adaptation_layer_event) { 4570223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 4571223132Stuexen } else { 4572223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 4573223132Stuexen } 4574223132Stuexen if (events->sctp_authentication_event) { 4575223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT); 4576223132Stuexen } else { 4577223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT); 4578223132Stuexen } 4579223132Stuexen if (events->sctp_sender_dry_event) { 4580223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT); 4581223132Stuexen } else { 4582223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT); 4583223132Stuexen } 4584223132Stuexen if (events->sctp_stream_reset_event) { 4585223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 4586223132Stuexen } else { 4587223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 4588223132Stuexen } 4589223132Stuexen SCTP_TCB_UNLOCK(stcb); 4590223132Stuexen } 4591223132Stuexen /* 4592223132Stuexen * Send up the sender dry event only for 1-to-1 4593223132Stuexen * style sockets. 4594223132Stuexen */ 4595223132Stuexen if (events->sctp_sender_dry_event) { 4596223132Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4597223132Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 4598223132Stuexen stcb = LIST_FIRST(&inp->sctp_asoc_list); 4599223132Stuexen if (stcb) { 4600223132Stuexen SCTP_TCB_LOCK(stcb); 4601223132Stuexen if (TAILQ_EMPTY(&stcb->asoc.send_queue) && 4602223132Stuexen TAILQ_EMPTY(&stcb->asoc.sent_queue) && 4603223132Stuexen (stcb->asoc.stream_queue_cnt == 0)) { 4604223132Stuexen sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED); 4605223132Stuexen } 4606223132Stuexen SCTP_TCB_UNLOCK(stcb); 4607223132Stuexen } 4608223132Stuexen } 4609223132Stuexen } 4610223132Stuexen SCTP_INP_RUNLOCK(inp); 4611223132Stuexen break; 4612163953Srrs } 4613163953Srrs case SCTP_ADAPTATION_LAYER: 4614163953Srrs { 4615163953Srrs struct sctp_setadaptation *adap_bits; 4616163953Srrs 4617166675Srrs SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize); 4618163953Srrs SCTP_INP_WLOCK(inp); 4619163953Srrs inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind; 4620163953Srrs SCTP_INP_WUNLOCK(inp); 4621223132Stuexen break; 4622163953Srrs } 4623166675Srrs#ifdef SCTP_DEBUG 4624163953Srrs case SCTP_SET_INITIAL_DBG_SEQ: 4625163953Srrs { 4626163953Srrs uint32_t *vvv; 4627163953Srrs 4628166675Srrs SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize); 4629163953Srrs SCTP_INP_WLOCK(inp); 4630163953Srrs inp->sctp_ep.initial_sequence_debug = *vvv; 4631163953Srrs SCTP_INP_WUNLOCK(inp); 4632223132Stuexen break; 4633163953Srrs } 4634166675Srrs#endif 4635163953Srrs case SCTP_DEFAULT_SEND_PARAM: 4636163953Srrs { 4637163953Srrs struct sctp_sndrcvinfo *s_info; 4638163953Srrs 4639166675Srrs SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize); 4640166675Srrs SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); 4641163953Srrs 4642166675Srrs if (stcb) { 4643223132Stuexen if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) { 4644170056Srrs memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send))); 4645163953Srrs } else { 4646171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4647166675Srrs error = EINVAL; 4648163953Srrs } 4649166675Srrs SCTP_TCB_UNLOCK(stcb); 4650166675Srrs } else { 4651224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4652224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4653224918Stuexen (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) || 4654223132Stuexen (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) { 4655223132Stuexen SCTP_INP_WLOCK(inp); 4656223132Stuexen memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send))); 4657223132Stuexen SCTP_INP_WUNLOCK(inp); 4658223132Stuexen } 4659223132Stuexen if ((s_info->sinfo_assoc_id == SCTP_CURRENT_ASSOC) || 4660223132Stuexen (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) { 4661223132Stuexen SCTP_INP_RLOCK(inp); 4662223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4663223132Stuexen SCTP_TCB_LOCK(stcb); 4664223132Stuexen if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) { 4665223132Stuexen memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send))); 4666223132Stuexen } 4667223132Stuexen SCTP_TCB_UNLOCK(stcb); 4668223132Stuexen } 4669223132Stuexen SCTP_INP_RUNLOCK(inp); 4670223132Stuexen } 4671163953Srrs } 4672223132Stuexen break; 4673163953Srrs } 4674163953Srrs case SCTP_PEER_ADDR_PARAMS: 4675163953Srrs { 4676163953Srrs struct sctp_paddrparams *paddrp; 4677163953Srrs struct sctp_nets *net; 4678163953Srrs 4679166675Srrs SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize); 4680166675Srrs SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); 4681163953Srrs net = NULL; 4682166675Srrs if (stcb) { 4683166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address); 4684166675Srrs } else { 4685166675Srrs /* 4686166675Srrs * We increment here since 4687166675Srrs * sctp_findassociation_ep_addr() wil do a 4688166675Srrs * decrement if it finds the stcb as long as 4689166675Srrs * the locked tcb (last argument) is NOT a 4690166675Srrs * TCB.. aka NULL. 4691166675Srrs */ 4692166675Srrs SCTP_INP_INCR_REF(inp); 4693166675Srrs stcb = sctp_findassociation_ep_addr(&inp, 4694166675Srrs (struct sockaddr *)&paddrp->spp_address, 4695166675Srrs &net, NULL, NULL); 4696163953Srrs if (stcb == NULL) { 4697166675Srrs SCTP_INP_DECR_REF(inp); 4698163953Srrs } 4699163953Srrs } 4700171943Srrs if (stcb && (net == NULL)) { 4701171943Srrs struct sockaddr *sa; 4702171943Srrs 4703171943Srrs sa = (struct sockaddr *)&paddrp->spp_address; 4704221249Stuexen#ifdef INET 4705171943Srrs if (sa->sa_family == AF_INET) { 4706221249Stuexen 4707171943Srrs struct sockaddr_in *sin; 4708171943Srrs 4709171943Srrs sin = (struct sockaddr_in *)sa; 4710171943Srrs if (sin->sin_addr.s_addr) { 4711171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4712171943Srrs SCTP_TCB_UNLOCK(stcb); 4713171943Srrs error = EINVAL; 4714171943Srrs break; 4715171943Srrs } 4716221249Stuexen } else 4717221249Stuexen#endif 4718221249Stuexen#ifdef INET6 4719221249Stuexen if (sa->sa_family == AF_INET6) { 4720171943Srrs struct sockaddr_in6 *sin6; 4721171943Srrs 4722171943Srrs sin6 = (struct sockaddr_in6 *)sa; 4723171943Srrs if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 4724171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4725171943Srrs SCTP_TCB_UNLOCK(stcb); 4726171943Srrs error = EINVAL; 4727171943Srrs break; 4728171943Srrs } 4729221249Stuexen } else 4730221249Stuexen#endif 4731221249Stuexen { 4732171943Srrs error = EAFNOSUPPORT; 4733171943Srrs SCTP_TCB_UNLOCK(stcb); 4734171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 4735171943Srrs break; 4736171943Srrs } 4737171943Srrs } 4738170056Srrs /* sanity checks */ 4739170056Srrs if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) { 4740170056Srrs if (stcb) 4741170056Srrs SCTP_TCB_UNLOCK(stcb); 4742171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4743170056Srrs return (EINVAL); 4744170056Srrs } 4745170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) { 4746170056Srrs if (stcb) 4747170056Srrs SCTP_TCB_UNLOCK(stcb); 4748171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4749170056Srrs return (EINVAL); 4750170056Srrs } 4751163953Srrs if (stcb) { 4752163953Srrs /************************TCB SPECIFIC SET ******************/ 4753163953Srrs /* 4754163953Srrs * do we change the timer for HB, we run 4755163953Srrs * only one? 4756163953Srrs */ 4757170056Srrs int ovh = 0; 4758170056Srrs 4759170056Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 4760170056Srrs ovh = SCTP_MED_OVERHEAD; 4761170056Srrs } else { 4762170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 4763170056Srrs } 4764170056Srrs 4765163953Srrs /* network sets ? */ 4766163953Srrs if (net) { 4767163953Srrs /************************NET SPECIFIC SET ******************/ 4768224641Stuexen if (paddrp->spp_flags & SPP_HB_DISABLE) { 4769224641Stuexen if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) && 4770224641Stuexen !(net->dest_state & SCTP_ADDR_NOHB)) { 4771224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 4772224641Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 4773171440Srrs } 4774163953Srrs net->dest_state |= SCTP_ADDR_NOHB; 4775163953Srrs } 4776163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 4777224641Stuexen if (paddrp->spp_hbinterval) { 4778224641Stuexen net->heart_beat_delay = paddrp->spp_hbinterval; 4779224641Stuexen } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 4780224641Stuexen net->heart_beat_delay = 0; 4781224641Stuexen } 4782224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 4783224641Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 4784224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 4785163953Srrs net->dest_state &= ~SCTP_ADDR_NOHB; 4786163953Srrs } 4787224641Stuexen if (paddrp->spp_flags & SPP_HB_DEMAND) { 4788224641Stuexen /* on demand HB */ 4789224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 4790228391Stuexen sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED); 4791224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 4792224641Stuexen } 4793170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { 4794165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 4795165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 4796165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 4797163953Srrs } 4798225635Stuexen net->dest_state |= SCTP_ADDR_NO_PMTUD; 4799163953Srrs if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) { 4800170056Srrs net->mtu = paddrp->spp_pathmtu + ovh; 4801169352Srrs if (net->mtu < stcb->asoc.smallest_mtu) { 4802228653Stuexen sctp_pathmtu_adjustment(stcb, net->mtu); 4803169352Srrs } 4804163953Srrs } 4805163953Srrs } 4806163953Srrs if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 4807225635Stuexen if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 4808163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 4809163953Srrs } 4810225635Stuexen net->dest_state &= ~SCTP_ADDR_NO_PMTUD; 4811163953Srrs } 4812224641Stuexen if (paddrp->spp_pathmaxrxt) { 4813224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 4814224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 4815224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 4816224641Stuexen } 4817224641Stuexen } else { 4818224641Stuexen if ((net->error_count <= paddrp->spp_pathmaxrxt) && 4819224641Stuexen (net->error_count > net->pf_threshold)) { 4820224641Stuexen net->dest_state |= SCTP_ADDR_PF; 4821224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 4822224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); 4823224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 4824224641Stuexen } 4825224641Stuexen } 4826224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 4827224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 4828224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 4829224641Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); 4830224641Stuexen } 4831224641Stuexen } else { 4832224641Stuexen if (net->error_count <= paddrp->spp_pathmaxrxt) { 4833224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 4834224641Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); 4835224641Stuexen } 4836224641Stuexen } 4837163953Srrs net->failure_threshold = paddrp->spp_pathmaxrxt; 4838224641Stuexen } 4839224870Stuexen if (paddrp->spp_flags & SPP_DSCP) { 4840226252Stuexen net->dscp = paddrp->spp_dscp & 0xfc; 4841225549Stuexen net->dscp |= 0x01; 4842163953Srrs } 4843167598Srrs#ifdef INET6 4844163953Srrs if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { 4845225549Stuexen if (net->ro._l_addr.sa.sa_family == AF_INET6) { 4846224870Stuexen net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 4847225549Stuexen net->flowlabel |= 0x80000000; 4848163953Srrs } 4849163953Srrs } 4850163953Srrs#endif 4851163953Srrs } else { 4852163953Srrs /************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/ 4853224641Stuexen if (paddrp->spp_pathmaxrxt) { 4854163953Srrs stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt; 4855224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4856224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 4857224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 4858224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 4859224641Stuexen } 4860224641Stuexen } else { 4861224641Stuexen if ((net->error_count <= paddrp->spp_pathmaxrxt) && 4862224641Stuexen (net->error_count > net->pf_threshold)) { 4863224641Stuexen net->dest_state |= SCTP_ADDR_PF; 4864224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 4865224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); 4866224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 4867224641Stuexen } 4868224641Stuexen } 4869224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 4870224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 4871224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 4872224641Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); 4873224641Stuexen } 4874224641Stuexen } else { 4875224641Stuexen if (net->error_count <= paddrp->spp_pathmaxrxt) { 4876224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 4877224641Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); 4878224641Stuexen } 4879224641Stuexen } 4880224641Stuexen net->failure_threshold = paddrp->spp_pathmaxrxt; 4881224641Stuexen } 4882224641Stuexen } 4883163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 4884224641Stuexen if (paddrp->spp_hbinterval) { 4885224641Stuexen stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval; 4886224641Stuexen } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 4887224641Stuexen stcb->asoc.heart_beat_delay = 0; 4888224641Stuexen } 4889163953Srrs /* Turn back on the timer */ 4890224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4891224641Stuexen if (paddrp->spp_hbinterval) { 4892224641Stuexen net->heart_beat_delay = paddrp->spp_hbinterval; 4893224641Stuexen } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 4894224641Stuexen net->heart_beat_delay = 0; 4895224641Stuexen } 4896224641Stuexen if (net->dest_state & SCTP_ADDR_NOHB) { 4897224641Stuexen net->dest_state &= ~SCTP_ADDR_NOHB; 4898224641Stuexen } 4899224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 4900224641Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 4901224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 4902224641Stuexen } 4903225635Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 4904163953Srrs } 4905224641Stuexen if (paddrp->spp_flags & SPP_HB_DISABLE) { 4906224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4907224641Stuexen if (!(net->dest_state & SCTP_ADDR_NOHB)) { 4908224641Stuexen net->dest_state |= SCTP_ADDR_NOHB; 4909224641Stuexen if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { 4910224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 4911224641Stuexen } 4912224641Stuexen } 4913224641Stuexen } 4914225635Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 4915224641Stuexen } 4916170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { 4917170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4918170056Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 4919170056Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 4920170056Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 4921170056Srrs } 4922225635Stuexen net->dest_state |= SCTP_ADDR_NO_PMTUD; 4923170056Srrs if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) { 4924170056Srrs net->mtu = paddrp->spp_pathmtu + ovh; 4925170056Srrs if (net->mtu < stcb->asoc.smallest_mtu) { 4926228653Stuexen sctp_pathmtu_adjustment(stcb, net->mtu); 4927170056Srrs } 4928170056Srrs } 4929170056Srrs } 4930225635Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 4931170056Srrs } 4932170056Srrs if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 4933170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4934225635Stuexen if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 4935170056Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 4936170056Srrs } 4937225635Stuexen net->dest_state &= ~SCTP_ADDR_NO_PMTUD; 4938170056Srrs } 4939225635Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 4940170056Srrs } 4941224870Stuexen if (paddrp->spp_flags & SPP_DSCP) { 4942224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4943226252Stuexen net->dscp = paddrp->spp_dscp & 0xfc; 4944225549Stuexen net->dscp |= 0x01; 4945163953Srrs } 4946226252Stuexen stcb->asoc.default_dscp = paddrp->spp_dscp & 0xfc; 4947225549Stuexen stcb->asoc.default_dscp |= 0x01; 4948163953Srrs } 4949225549Stuexen#ifdef INET6 4950224641Stuexen if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { 4951170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4952225549Stuexen if (net->ro._l_addr.sa.sa_family == AF_INET6) { 4953225549Stuexen net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 4954225549Stuexen net->flowlabel |= 0x80000000; 4955225549Stuexen } 4956170056Srrs } 4957225549Stuexen stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 4958225549Stuexen stcb->asoc.default_flowlabel |= 0x80000000; 4959163953Srrs } 4960225549Stuexen#endif 4961163953Srrs } 4962163953Srrs SCTP_TCB_UNLOCK(stcb); 4963163953Srrs } else { 4964163953Srrs /************************NO TCB, SET TO default stuff ******************/ 4965224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4966224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4967224918Stuexen (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) { 4968223132Stuexen SCTP_INP_WLOCK(inp); 4969223132Stuexen /* 4970223132Stuexen * For the TOS/FLOWLABEL stuff you 4971223132Stuexen * set it with the options on the 4972223132Stuexen * socket 4973223132Stuexen */ 4974223132Stuexen if (paddrp->spp_pathmaxrxt) { 4975223132Stuexen inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt; 4976223132Stuexen } 4977223132Stuexen if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) 4978223132Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0; 4979223132Stuexen else if (paddrp->spp_hbinterval) { 4980223132Stuexen if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL) 4981223132Stuexen paddrp->spp_hbinterval = SCTP_MAX_HB_INTERVAL; 4982223132Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval); 4983223132Stuexen } 4984223132Stuexen if (paddrp->spp_flags & SPP_HB_ENABLE) { 4985224641Stuexen if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 4986224641Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0; 4987224641Stuexen } else if (paddrp->spp_hbinterval) { 4988224641Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval); 4989224641Stuexen } 4990223132Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 4991223132Stuexen } else if (paddrp->spp_flags & SPP_HB_DISABLE) { 4992223132Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 4993223132Stuexen } 4994225635Stuexen if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 4995225635Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 4996225635Stuexen } else if (paddrp->spp_flags & SPP_PMTUD_DISABLE) { 4997225635Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 4998225635Stuexen } 4999225549Stuexen if (paddrp->spp_flags & SPP_DSCP) { 5000226252Stuexen inp->sctp_ep.default_dscp = paddrp->spp_dscp & 0xfc; 5001225549Stuexen inp->sctp_ep.default_dscp |= 0x01; 5002225549Stuexen } 5003225549Stuexen#ifdef INET6 5004225549Stuexen if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { 5005225549Stuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 5006225549Stuexen inp->sctp_ep.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 5007225549Stuexen inp->sctp_ep.default_flowlabel |= 0x80000000; 5008225549Stuexen } 5009225549Stuexen } 5010225549Stuexen#endif 5011223132Stuexen SCTP_INP_WUNLOCK(inp); 5012223132Stuexen } else { 5013223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5014223132Stuexen error = EINVAL; 5015163953Srrs } 5016163953Srrs } 5017223132Stuexen break; 5018163953Srrs } 5019163953Srrs case SCTP_RTOINFO: 5020163953Srrs { 5021163953Srrs struct sctp_rtoinfo *srto; 5022169655Srrs uint32_t new_init, new_min, new_max; 5023163953Srrs 5024166675Srrs SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize); 5025166675Srrs SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); 5026166675Srrs 5027166675Srrs if (stcb) { 5028167598Srrs if (srto->srto_initial) 5029169655Srrs new_init = srto->srto_initial; 5030169655Srrs else 5031169655Srrs new_init = stcb->asoc.initial_rto; 5032167598Srrs if (srto->srto_max) 5033169655Srrs new_max = srto->srto_max; 5034169655Srrs else 5035169655Srrs new_max = stcb->asoc.maxrto; 5036167598Srrs if (srto->srto_min) 5037169655Srrs new_min = srto->srto_min; 5038169655Srrs else 5039169655Srrs new_min = stcb->asoc.minrto; 5040169655Srrs if ((new_min <= new_init) && (new_init <= new_max)) { 5041169655Srrs stcb->asoc.initial_rto = new_init; 5042169655Srrs stcb->asoc.maxrto = new_max; 5043169655Srrs stcb->asoc.minrto = new_min; 5044169655Srrs } else { 5045179783Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5046179783Srrs error = EINVAL; 5047169655Srrs } 5048166675Srrs SCTP_TCB_UNLOCK(stcb); 5049166675Srrs } else { 5050224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5051224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5052224918Stuexen (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) { 5053223132Stuexen SCTP_INP_WLOCK(inp); 5054223132Stuexen if (srto->srto_initial) 5055223132Stuexen new_init = srto->srto_initial; 5056223132Stuexen else 5057223132Stuexen new_init = inp->sctp_ep.initial_rto; 5058223132Stuexen if (srto->srto_max) 5059223132Stuexen new_max = srto->srto_max; 5060223132Stuexen else 5061223132Stuexen new_max = inp->sctp_ep.sctp_maxrto; 5062223132Stuexen if (srto->srto_min) 5063223132Stuexen new_min = srto->srto_min; 5064223132Stuexen else 5065223132Stuexen new_min = inp->sctp_ep.sctp_minrto; 5066223132Stuexen if ((new_min <= new_init) && (new_init <= new_max)) { 5067223132Stuexen inp->sctp_ep.initial_rto = new_init; 5068223132Stuexen inp->sctp_ep.sctp_maxrto = new_max; 5069223132Stuexen inp->sctp_ep.sctp_minrto = new_min; 5070223132Stuexen } else { 5071223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5072223132Stuexen error = EINVAL; 5073223132Stuexen } 5074223132Stuexen SCTP_INP_WUNLOCK(inp); 5075169655Srrs } else { 5076179783Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5077179783Srrs error = EINVAL; 5078169655Srrs } 5079163953Srrs } 5080223132Stuexen break; 5081163953Srrs } 5082163953Srrs case SCTP_ASSOCINFO: 5083163953Srrs { 5084163953Srrs struct sctp_assocparams *sasoc; 5085163953Srrs 5086166675Srrs SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize); 5087166675Srrs SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); 5088171477Srrs if (sasoc->sasoc_cookie_life) { 5089171477Srrs /* boundary check the cookie life */ 5090171477Srrs if (sasoc->sasoc_cookie_life < 1000) 5091171477Srrs sasoc->sasoc_cookie_life = 1000; 5092171477Srrs if (sasoc->sasoc_cookie_life > SCTP_MAX_COOKIE_LIFE) { 5093171477Srrs sasoc->sasoc_cookie_life = SCTP_MAX_COOKIE_LIFE; 5094171477Srrs } 5095171477Srrs } 5096163953Srrs if (stcb) { 5097163953Srrs if (sasoc->sasoc_asocmaxrxt) 5098163953Srrs stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt; 5099170056Srrs if (sasoc->sasoc_cookie_life) { 5100171572Srrs stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); 5101167598Srrs } 5102163953Srrs SCTP_TCB_UNLOCK(stcb); 5103163953Srrs } else { 5104224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5105224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5106224918Stuexen (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) { 5107223132Stuexen SCTP_INP_WLOCK(inp); 5108223132Stuexen if (sasoc->sasoc_asocmaxrxt) 5109223132Stuexen inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt; 5110223132Stuexen if (sasoc->sasoc_cookie_life) { 5111223132Stuexen inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); 5112223132Stuexen } 5113223132Stuexen SCTP_INP_WUNLOCK(inp); 5114223132Stuexen } else { 5115223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5116223132Stuexen error = EINVAL; 5117167598Srrs } 5118163953Srrs } 5119223132Stuexen break; 5120163953Srrs } 5121163953Srrs case SCTP_INITMSG: 5122163953Srrs { 5123163953Srrs struct sctp_initmsg *sinit; 5124163953Srrs 5125166675Srrs SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize); 5126163953Srrs SCTP_INP_WLOCK(inp); 5127163953Srrs if (sinit->sinit_num_ostreams) 5128163953Srrs inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams; 5129163953Srrs 5130163953Srrs if (sinit->sinit_max_instreams) 5131163953Srrs inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams; 5132163953Srrs 5133163953Srrs if (sinit->sinit_max_attempts) 5134163953Srrs inp->sctp_ep.max_init_times = sinit->sinit_max_attempts; 5135163953Srrs 5136167598Srrs if (sinit->sinit_max_init_timeo) 5137163953Srrs inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo; 5138163953Srrs SCTP_INP_WUNLOCK(inp); 5139223132Stuexen break; 5140163953Srrs } 5141163953Srrs case SCTP_PRIMARY_ADDR: 5142163953Srrs { 5143163953Srrs struct sctp_setprim *spa; 5144223132Stuexen struct sctp_nets *net; 5145163953Srrs 5146166675Srrs SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize); 5147166675Srrs SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id); 5148163953Srrs 5149166675Srrs net = NULL; 5150166675Srrs if (stcb) { 5151166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&spa->ssp_addr); 5152166675Srrs } else { 5153166675Srrs /* 5154166675Srrs * We increment here since 5155166675Srrs * sctp_findassociation_ep_addr() wil do a 5156166675Srrs * decrement if it finds the stcb as long as 5157166675Srrs * the locked tcb (last argument) is NOT a 5158166675Srrs * TCB.. aka NULL. 5159166675Srrs */ 5160163953Srrs SCTP_INP_INCR_REF(inp); 5161163953Srrs stcb = sctp_findassociation_ep_addr(&inp, 5162163953Srrs (struct sockaddr *)&spa->ssp_addr, 5163163953Srrs &net, NULL, NULL); 5164163953Srrs if (stcb == NULL) { 5165163953Srrs SCTP_INP_DECR_REF(inp); 5166163953Srrs } 5167163953Srrs } 5168166675Srrs 5169166675Srrs if ((stcb) && (net)) { 5170166675Srrs if ((net != stcb->asoc.primary_destination) && 5171166675Srrs (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) { 5172166675Srrs /* Ok we need to set it */ 5173166675Srrs if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) { 5174224641Stuexen if ((stcb->asoc.alternate) && 5175224641Stuexen (!(net->dest_state & SCTP_ADDR_PF)) && 5176224641Stuexen (net->dest_state & SCTP_ADDR_REACHABLE)) { 5177224641Stuexen sctp_free_remote_addr(stcb->asoc.alternate); 5178224641Stuexen stcb->asoc.alternate = NULL; 5179166675Srrs } 5180163953Srrs } 5181163953Srrs } 5182166675Srrs } else { 5183171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5184166675Srrs error = EINVAL; 5185163953Srrs } 5186166675Srrs if (stcb) { 5187166675Srrs SCTP_TCB_UNLOCK(stcb); 5188166675Srrs } 5189223132Stuexen break; 5190163953Srrs } 5191167598Srrs case SCTP_SET_DYNAMIC_PRIMARY: 5192167598Srrs { 5193167598Srrs union sctp_sockstore *ss; 5194163953Srrs 5195170587Srwatson error = priv_check(curthread, 5196170587Srwatson PRIV_NETINET_RESERVEDPORT); 5197167598Srrs if (error) 5198167598Srrs break; 5199167598Srrs 5200167598Srrs SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize); 5201167598Srrs /* SUPER USER CHECK? */ 5202167598Srrs error = sctp_dynamic_set_primary(&ss->sa, vrf_id); 5203223132Stuexen break; 5204167598Srrs } 5205163953Srrs case SCTP_SET_PEER_PRIMARY_ADDR: 5206163953Srrs { 5207163953Srrs struct sctp_setpeerprim *sspp; 5208163953Srrs 5209166675Srrs SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize); 5210166675Srrs SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id); 5211169208Srrs if (stcb != NULL) { 5212170056Srrs struct sctp_ifa *ifa; 5213170056Srrs 5214170056Srrs ifa = sctp_find_ifa_by_addr((struct sockaddr *)&sspp->sspp_addr, 5215172091Srrs stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED); 5216170056Srrs if (ifa == NULL) { 5217171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5218166675Srrs error = EINVAL; 5219170056Srrs goto out_of_it; 5220166675Srrs } 5221170056Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { 5222170056Srrs /* 5223170056Srrs * Must validate the ifa found is in 5224170056Srrs * our ep 5225170056Srrs */ 5226170056Srrs struct sctp_laddr *laddr; 5227170056Srrs int found = 0; 5228170056Srrs 5229170056Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 5230170056Srrs if (laddr->ifa == NULL) { 5231170056Srrs SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n", 5232170056Srrs __FUNCTION__); 5233170056Srrs continue; 5234170056Srrs } 5235170056Srrs if (laddr->ifa == ifa) { 5236170056Srrs found = 1; 5237170056Srrs break; 5238170056Srrs } 5239170056Srrs } 5240170056Srrs if (!found) { 5241171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5242170056Srrs error = EINVAL; 5243170056Srrs goto out_of_it; 5244170056Srrs } 5245170056Srrs } 5246170056Srrs if (sctp_set_primary_ip_address_sa(stcb, 5247170056Srrs (struct sockaddr *)&sspp->sspp_addr) != 0) { 5248171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5249170056Srrs error = EINVAL; 5250170056Srrs } 5251170056Srrs out_of_it: 5252169208Srrs SCTP_TCB_UNLOCK(stcb); 5253166675Srrs } else { 5254171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5255163953Srrs error = EINVAL; 5256163953Srrs } 5257223132Stuexen break; 5258163953Srrs } 5259163953Srrs case SCTP_BINDX_ADD_ADDR: 5260163953Srrs { 5261163953Srrs struct sctp_getaddresses *addrs; 5262171531Srrs size_t sz; 5263171477Srrs struct thread *td; 5264163953Srrs 5265171477Srrs td = (struct thread *)p; 5266170606Srrs SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, 5267170606Srrs optsize); 5268221249Stuexen#ifdef INET 5269171477Srrs if (addrs->addr->sa_family == AF_INET) { 5270171477Srrs sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in); 5271171477Srrs if (optsize < sz) { 5272171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5273171477Srrs error = EINVAL; 5274171477Srrs break; 5275171477Srrs } 5276188590Srrs if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) { 5277188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5278185435Sbz break; 5279171477Srrs } 5280221249Stuexen } else 5281221249Stuexen#endif 5282185435Sbz#ifdef INET6 5283221249Stuexen if (addrs->addr->sa_family == AF_INET6) { 5284171477Srrs sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6); 5285171477Srrs if (optsize < sz) { 5286171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5287171477Srrs error = EINVAL; 5288171477Srrs break; 5289171477Srrs } 5290188590Srrs if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr), 5291188590Srrs (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) { 5292188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5293185435Sbz break; 5294185435Sbz } 5295221249Stuexen } else 5296185435Sbz#endif 5297221249Stuexen { 5298185435Sbz error = EAFNOSUPPORT; 5299185435Sbz break; 5300171477Srrs } 5301170606Srrs sctp_bindx_add_address(so, inp, addrs->addr, 5302170606Srrs addrs->sget_assoc_id, vrf_id, 5303170606Srrs &error, p); 5304223132Stuexen break; 5305163953Srrs } 5306163953Srrs case SCTP_BINDX_REM_ADDR: 5307163953Srrs { 5308163953Srrs struct sctp_getaddresses *addrs; 5309171531Srrs size_t sz; 5310171477Srrs struct thread *td; 5311163953Srrs 5312171477Srrs td = (struct thread *)p; 5313185435Sbz 5314166675Srrs SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize); 5315221249Stuexen#ifdef INET 5316171477Srrs if (addrs->addr->sa_family == AF_INET) { 5317171477Srrs sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in); 5318171477Srrs if (optsize < sz) { 5319171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5320171477Srrs error = EINVAL; 5321171477Srrs break; 5322171477Srrs } 5323188590Srrs if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) { 5324188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5325185435Sbz break; 5326171477Srrs } 5327221249Stuexen } else 5328221249Stuexen#endif 5329185435Sbz#ifdef INET6 5330221249Stuexen if (addrs->addr->sa_family == AF_INET6) { 5331171477Srrs sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6); 5332171477Srrs if (optsize < sz) { 5333171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5334171477Srrs error = EINVAL; 5335171477Srrs break; 5336171477Srrs } 5337224641Stuexen if (td != NULL && 5338224641Stuexen (error = prison_local_ip6(td->td_ucred, 5339224641Stuexen &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr), 5340188590Srrs (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) { 5341188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5342185435Sbz break; 5343185435Sbz } 5344221249Stuexen } else 5345185435Sbz#endif 5346221249Stuexen { 5347185435Sbz error = EAFNOSUPPORT; 5348185435Sbz break; 5349171477Srrs } 5350228653Stuexen sctp_bindx_delete_address(inp, addrs->addr, 5351170606Srrs addrs->sget_assoc_id, vrf_id, 5352170606Srrs &error); 5353223132Stuexen break; 5354163953Srrs } 5355223132Stuexen case SCTP_EVENT: 5356223132Stuexen { 5357223132Stuexen struct sctp_event *event; 5358223132Stuexen uint32_t event_type; 5359223132Stuexen 5360223132Stuexen SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, optsize); 5361223132Stuexen SCTP_FIND_STCB(inp, stcb, event->se_assoc_id); 5362223132Stuexen switch (event->se_type) { 5363223132Stuexen case SCTP_ASSOC_CHANGE: 5364223132Stuexen event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT; 5365223132Stuexen break; 5366223132Stuexen case SCTP_PEER_ADDR_CHANGE: 5367223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPADDREVNT; 5368223132Stuexen break; 5369223132Stuexen case SCTP_REMOTE_ERROR: 5370223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPEERERR; 5371223132Stuexen break; 5372223132Stuexen case SCTP_SEND_FAILED: 5373223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT; 5374223132Stuexen break; 5375223132Stuexen case SCTP_SHUTDOWN_EVENT: 5376223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT; 5377223132Stuexen break; 5378223132Stuexen case SCTP_ADAPTATION_INDICATION: 5379223132Stuexen event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT; 5380223132Stuexen break; 5381223132Stuexen case SCTP_PARTIAL_DELIVERY_EVENT: 5382223132Stuexen event_type = SCTP_PCB_FLAGS_PDAPIEVNT; 5383223132Stuexen break; 5384223132Stuexen case SCTP_AUTHENTICATION_EVENT: 5385223132Stuexen event_type = SCTP_PCB_FLAGS_AUTHEVNT; 5386223132Stuexen break; 5387223132Stuexen case SCTP_STREAM_RESET_EVENT: 5388223132Stuexen event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT; 5389223132Stuexen break; 5390223132Stuexen case SCTP_SENDER_DRY_EVENT: 5391223132Stuexen event_type = SCTP_PCB_FLAGS_DRYEVNT; 5392223132Stuexen break; 5393223132Stuexen case SCTP_NOTIFICATIONS_STOPPED_EVENT: 5394223132Stuexen event_type = 0; 5395223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); 5396223132Stuexen error = ENOTSUP; 5397223132Stuexen break; 5398235009Stuexen case SCTP_ASSOC_RESET_EVENT: 5399235009Stuexen event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT; 5400235009Stuexen break; 5401235009Stuexen case SCTP_STREAM_CHANGE_EVENT: 5402235009Stuexen event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT; 5403235009Stuexen break; 5404235075Stuexen case SCTP_SEND_FAILED_EVENT: 5405235075Stuexen event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT; 5406235075Stuexen break; 5407223132Stuexen default: 5408223132Stuexen event_type = 0; 5409223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5410223132Stuexen error = EINVAL; 5411223132Stuexen break; 5412223132Stuexen } 5413223132Stuexen if (event_type > 0) { 5414223132Stuexen if (stcb) { 5415223132Stuexen if (event->se_on) { 5416223132Stuexen sctp_stcb_feature_on(inp, stcb, event_type); 5417223132Stuexen if (event_type == SCTP_PCB_FLAGS_DRYEVNT) { 5418223132Stuexen if (TAILQ_EMPTY(&stcb->asoc.send_queue) && 5419223132Stuexen TAILQ_EMPTY(&stcb->asoc.sent_queue) && 5420223132Stuexen (stcb->asoc.stream_queue_cnt == 0)) { 5421223132Stuexen sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED); 5422223132Stuexen } 5423223132Stuexen } 5424223132Stuexen } else { 5425223132Stuexen sctp_stcb_feature_off(inp, stcb, event_type); 5426223132Stuexen } 5427223132Stuexen SCTP_TCB_UNLOCK(stcb); 5428223132Stuexen } else { 5429223132Stuexen /* 5430223132Stuexen * We don't want to send up a storm 5431223132Stuexen * of events, so return an error for 5432223132Stuexen * sender dry events 5433223132Stuexen */ 5434223132Stuexen if ((event_type == SCTP_PCB_FLAGS_DRYEVNT) && 5435224918Stuexen ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) && 5436224918Stuexen ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) && 5437223132Stuexen ((event->se_assoc_id == SCTP_ALL_ASSOC) || 5438223132Stuexen (event->se_assoc_id == SCTP_CURRENT_ASSOC))) { 5439223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); 5440223132Stuexen error = ENOTSUP; 5441223132Stuexen break; 5442223132Stuexen } 5443224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5444224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5445224918Stuexen (event->se_assoc_id == SCTP_FUTURE_ASSOC) || 5446223132Stuexen (event->se_assoc_id == SCTP_ALL_ASSOC)) { 5447223132Stuexen SCTP_INP_WLOCK(inp); 5448223132Stuexen if (event->se_on) { 5449223132Stuexen sctp_feature_on(inp, event_type); 5450223132Stuexen } else { 5451223132Stuexen sctp_feature_off(inp, event_type); 5452223132Stuexen } 5453223132Stuexen SCTP_INP_WUNLOCK(inp); 5454223132Stuexen } 5455223132Stuexen if ((event->se_assoc_id == SCTP_CURRENT_ASSOC) || 5456223132Stuexen (event->se_assoc_id == SCTP_ALL_ASSOC)) { 5457223132Stuexen SCTP_INP_RLOCK(inp); 5458223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 5459223132Stuexen SCTP_TCB_LOCK(stcb); 5460223132Stuexen if (event->se_on) { 5461223132Stuexen sctp_stcb_feature_on(inp, stcb, event_type); 5462223132Stuexen } else { 5463223132Stuexen sctp_stcb_feature_off(inp, stcb, event_type); 5464223132Stuexen } 5465223132Stuexen SCTP_TCB_UNLOCK(stcb); 5466223132Stuexen } 5467223132Stuexen SCTP_INP_RUNLOCK(inp); 5468223132Stuexen } 5469223132Stuexen } 5470223132Stuexen } 5471223132Stuexen break; 5472223132Stuexen } 5473223132Stuexen case SCTP_RECVRCVINFO: 5474223132Stuexen { 5475223132Stuexen int *onoff; 5476223132Stuexen 5477223132Stuexen SCTP_CHECK_AND_CAST(onoff, optval, int, optsize); 5478223132Stuexen SCTP_INP_WLOCK(inp); 5479223132Stuexen if (*onoff != 0) { 5480223132Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO); 5481223132Stuexen } else { 5482223132Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO); 5483223132Stuexen } 5484223132Stuexen SCTP_INP_WUNLOCK(inp); 5485223132Stuexen break; 5486223132Stuexen } 5487223132Stuexen case SCTP_RECVNXTINFO: 5488223132Stuexen { 5489223132Stuexen int *onoff; 5490223132Stuexen 5491223132Stuexen SCTP_CHECK_AND_CAST(onoff, optval, int, optsize); 5492223132Stuexen SCTP_INP_WLOCK(inp); 5493223132Stuexen if (*onoff != 0) { 5494223132Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO); 5495223132Stuexen } else { 5496223132Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO); 5497223132Stuexen } 5498223132Stuexen SCTP_INP_WUNLOCK(inp); 5499223132Stuexen break; 5500223132Stuexen } 5501223132Stuexen case SCTP_DEFAULT_SNDINFO: 5502223132Stuexen { 5503223132Stuexen struct sctp_sndinfo *info; 5504223162Stuexen uint16_t policy; 5505223132Stuexen 5506223132Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, optsize); 5507223132Stuexen SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id); 5508223132Stuexen 5509223132Stuexen if (stcb) { 5510223132Stuexen if (info->snd_sid < stcb->asoc.streamoutcnt) { 5511223132Stuexen stcb->asoc.def_send.sinfo_stream = info->snd_sid; 5512223162Stuexen policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); 5513223132Stuexen stcb->asoc.def_send.sinfo_flags = info->snd_flags; 5514223162Stuexen stcb->asoc.def_send.sinfo_flags |= policy; 5515223132Stuexen stcb->asoc.def_send.sinfo_ppid = info->snd_ppid; 5516223132Stuexen stcb->asoc.def_send.sinfo_context = info->snd_context; 5517223132Stuexen } else { 5518223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5519223132Stuexen error = EINVAL; 5520223132Stuexen } 5521223132Stuexen SCTP_TCB_UNLOCK(stcb); 5522223132Stuexen } else { 5523224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5524224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5525224918Stuexen (info->snd_assoc_id == SCTP_FUTURE_ASSOC) || 5526223132Stuexen (info->snd_assoc_id == SCTP_ALL_ASSOC)) { 5527223132Stuexen SCTP_INP_WLOCK(inp); 5528223132Stuexen inp->def_send.sinfo_stream = info->snd_sid; 5529223162Stuexen policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags); 5530223132Stuexen inp->def_send.sinfo_flags = info->snd_flags; 5531223162Stuexen inp->def_send.sinfo_flags |= policy; 5532223132Stuexen inp->def_send.sinfo_ppid = info->snd_ppid; 5533223132Stuexen inp->def_send.sinfo_context = info->snd_context; 5534223132Stuexen SCTP_INP_WUNLOCK(inp); 5535223132Stuexen } 5536223132Stuexen if ((info->snd_assoc_id == SCTP_CURRENT_ASSOC) || 5537223132Stuexen (info->snd_assoc_id == SCTP_ALL_ASSOC)) { 5538223132Stuexen SCTP_INP_RLOCK(inp); 5539223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 5540223132Stuexen SCTP_TCB_LOCK(stcb); 5541223132Stuexen if (info->snd_sid < stcb->asoc.streamoutcnt) { 5542223132Stuexen stcb->asoc.def_send.sinfo_stream = info->snd_sid; 5543223162Stuexen policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); 5544223132Stuexen stcb->asoc.def_send.sinfo_flags = info->snd_flags; 5545223162Stuexen stcb->asoc.def_send.sinfo_flags |= policy; 5546223132Stuexen stcb->asoc.def_send.sinfo_ppid = info->snd_ppid; 5547223132Stuexen stcb->asoc.def_send.sinfo_context = info->snd_context; 5548223132Stuexen } 5549223132Stuexen SCTP_TCB_UNLOCK(stcb); 5550223132Stuexen } 5551223132Stuexen SCTP_INP_RUNLOCK(inp); 5552223132Stuexen } 5553223132Stuexen } 5554223132Stuexen break; 5555223132Stuexen } 5556223162Stuexen case SCTP_DEFAULT_PRINFO: 5557223162Stuexen { 5558223162Stuexen struct sctp_default_prinfo *info; 5559223162Stuexen 5560223162Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, optsize); 5561223162Stuexen SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id); 5562223162Stuexen 5563223162Stuexen if (PR_SCTP_INVALID_POLICY(info->pr_policy)) { 5564223162Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5565223162Stuexen error = EINVAL; 5566223162Stuexen break; 5567223162Stuexen } 5568223162Stuexen if (stcb) { 5569223162Stuexen stcb->asoc.def_send.sinfo_flags &= 0xfff0; 5570223162Stuexen stcb->asoc.def_send.sinfo_flags |= info->pr_policy; 5571224918Stuexen stcb->asoc.def_send.sinfo_timetolive = info->pr_value; 5572223162Stuexen SCTP_TCB_UNLOCK(stcb); 5573223162Stuexen } else { 5574224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5575224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5576224918Stuexen (info->pr_assoc_id == SCTP_FUTURE_ASSOC) || 5577223162Stuexen (info->pr_assoc_id == SCTP_ALL_ASSOC)) { 5578223162Stuexen SCTP_INP_WLOCK(inp); 5579223162Stuexen inp->def_send.sinfo_flags &= 0xfff0; 5580223162Stuexen inp->def_send.sinfo_flags |= info->pr_policy; 5581224918Stuexen inp->def_send.sinfo_timetolive = info->pr_value; 5582223162Stuexen SCTP_INP_WUNLOCK(inp); 5583223162Stuexen } 5584223162Stuexen if ((info->pr_assoc_id == SCTP_CURRENT_ASSOC) || 5585223162Stuexen (info->pr_assoc_id == SCTP_ALL_ASSOC)) { 5586223162Stuexen SCTP_INP_RLOCK(inp); 5587223162Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 5588223162Stuexen SCTP_TCB_LOCK(stcb); 5589223162Stuexen stcb->asoc.def_send.sinfo_flags &= 0xfff0; 5590223162Stuexen stcb->asoc.def_send.sinfo_flags |= info->pr_policy; 5591224918Stuexen stcb->asoc.def_send.sinfo_timetolive = info->pr_value; 5592223162Stuexen SCTP_TCB_UNLOCK(stcb); 5593223162Stuexen } 5594223162Stuexen SCTP_INP_RUNLOCK(inp); 5595223162Stuexen } 5596223162Stuexen } 5597223162Stuexen break; 5598223162Stuexen } 5599224641Stuexen case SCTP_PEER_ADDR_THLDS: 5600224641Stuexen /* Applies to the specific association */ 5601224641Stuexen { 5602224641Stuexen struct sctp_paddrthlds *thlds; 5603224641Stuexen struct sctp_nets *net; 5604224641Stuexen 5605224641Stuexen SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, optsize); 5606224641Stuexen SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id); 5607224641Stuexen net = NULL; 5608224641Stuexen if (stcb) { 5609224641Stuexen net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_assoc_id); 5610224641Stuexen } else { 5611224641Stuexen /* 5612224641Stuexen * We increment here since 5613224641Stuexen * sctp_findassociation_ep_addr() wil do a 5614224641Stuexen * decrement if it finds the stcb as long as 5615224641Stuexen * the locked tcb (last argument) is NOT a 5616224641Stuexen * TCB.. aka NULL. 5617224641Stuexen */ 5618224641Stuexen SCTP_INP_INCR_REF(inp); 5619224641Stuexen stcb = sctp_findassociation_ep_addr(&inp, 5620224641Stuexen (struct sockaddr *)&thlds->spt_assoc_id, 5621224641Stuexen &net, NULL, NULL); 5622224641Stuexen if (stcb == NULL) { 5623224641Stuexen SCTP_INP_DECR_REF(inp); 5624224641Stuexen } 5625224641Stuexen } 5626224641Stuexen if (stcb && (net == NULL)) { 5627224641Stuexen struct sockaddr *sa; 5628224641Stuexen 5629224641Stuexen sa = (struct sockaddr *)&thlds->spt_assoc_id; 5630224641Stuexen#ifdef INET 5631224641Stuexen if (sa->sa_family == AF_INET) { 5632224641Stuexen 5633224641Stuexen struct sockaddr_in *sin; 5634224641Stuexen 5635224641Stuexen sin = (struct sockaddr_in *)sa; 5636224641Stuexen if (sin->sin_addr.s_addr) { 5637224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5638224641Stuexen SCTP_TCB_UNLOCK(stcb); 5639224641Stuexen error = EINVAL; 5640224641Stuexen break; 5641224641Stuexen } 5642224641Stuexen } else 5643224641Stuexen#endif 5644224641Stuexen#ifdef INET6 5645224641Stuexen if (sa->sa_family == AF_INET6) { 5646224641Stuexen struct sockaddr_in6 *sin6; 5647224641Stuexen 5648224641Stuexen sin6 = (struct sockaddr_in6 *)sa; 5649224641Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 5650224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5651224641Stuexen SCTP_TCB_UNLOCK(stcb); 5652224641Stuexen error = EINVAL; 5653224641Stuexen break; 5654224641Stuexen } 5655224641Stuexen } else 5656224641Stuexen#endif 5657224641Stuexen { 5658224641Stuexen error = EAFNOSUPPORT; 5659224641Stuexen SCTP_TCB_UNLOCK(stcb); 5660224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 5661224641Stuexen break; 5662224641Stuexen } 5663224641Stuexen } 5664224641Stuexen if (stcb) { 5665224641Stuexen if (net) { 5666224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 5667224641Stuexen if ((net->failure_threshold > thlds->spt_pathmaxrxt) || 5668224641Stuexen (net->failure_threshold <= thlds->spt_pathpfthld)) { 5669224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 5670224641Stuexen } 5671224641Stuexen } else { 5672224641Stuexen if ((net->failure_threshold > thlds->spt_pathpfthld) && 5673224641Stuexen (net->failure_threshold <= thlds->spt_pathmaxrxt)) { 5674224641Stuexen net->dest_state |= SCTP_ADDR_PF; 5675224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 5676224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); 5677224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 5678224641Stuexen } 5679224641Stuexen } 5680224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 5681224641Stuexen if (net->failure_threshold > thlds->spt_pathmaxrxt) { 5682224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 5683224641Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); 5684224641Stuexen } 5685224641Stuexen } else { 5686224641Stuexen if (net->failure_threshold <= thlds->spt_pathmaxrxt) { 5687224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 5688224641Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); 5689224641Stuexen } 5690224641Stuexen } 5691224641Stuexen net->failure_threshold = thlds->spt_pathmaxrxt; 5692224641Stuexen net->pf_threshold = thlds->spt_pathpfthld; 5693224641Stuexen } else { 5694224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 5695224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 5696224641Stuexen if ((net->failure_threshold > thlds->spt_pathmaxrxt) || 5697224641Stuexen (net->failure_threshold <= thlds->spt_pathpfthld)) { 5698224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 5699224641Stuexen } 5700224641Stuexen } else { 5701224641Stuexen if ((net->failure_threshold > thlds->spt_pathpfthld) && 5702224641Stuexen (net->failure_threshold <= thlds->spt_pathmaxrxt)) { 5703224641Stuexen net->dest_state |= SCTP_ADDR_PF; 5704224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 5705224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); 5706224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 5707224641Stuexen } 5708224641Stuexen } 5709224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 5710224641Stuexen if (net->failure_threshold > thlds->spt_pathmaxrxt) { 5711224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 5712224641Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); 5713224641Stuexen } 5714224641Stuexen } else { 5715224641Stuexen if (net->failure_threshold <= thlds->spt_pathmaxrxt) { 5716224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 5717224641Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); 5718224641Stuexen } 5719224641Stuexen } 5720224641Stuexen net->failure_threshold = thlds->spt_pathmaxrxt; 5721224641Stuexen net->pf_threshold = thlds->spt_pathpfthld; 5722224641Stuexen } 5723224641Stuexen stcb->asoc.def_net_failure = thlds->spt_pathmaxrxt; 5724224641Stuexen stcb->asoc.def_net_pf_threshold = thlds->spt_pathpfthld; 5725224641Stuexen } 5726224641Stuexen } else { 5727224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5728224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5729224918Stuexen (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) { 5730224641Stuexen SCTP_INP_WLOCK(inp); 5731224641Stuexen inp->sctp_ep.def_net_failure = thlds->spt_pathmaxrxt; 5732224641Stuexen inp->sctp_ep.def_net_pf_threshold = thlds->spt_pathpfthld; 5733224641Stuexen SCTP_INP_WUNLOCK(inp); 5734224641Stuexen } else { 5735224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5736224641Stuexen error = EINVAL; 5737224641Stuexen } 5738224641Stuexen } 5739224641Stuexen break; 5740224641Stuexen } 5741227755Stuexen case SCTP_REMOTE_UDP_ENCAPS_PORT: 5742227755Stuexen { 5743227755Stuexen struct sctp_udpencaps *encaps; 5744227755Stuexen struct sctp_nets *net; 5745227755Stuexen 5746227755Stuexen SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, optsize); 5747227755Stuexen SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id); 5748227755Stuexen if (stcb) { 5749227755Stuexen net = sctp_findnet(stcb, (struct sockaddr *)&encaps->sue_address); 5750227755Stuexen } else { 5751227755Stuexen /* 5752227755Stuexen * We increment here since 5753227755Stuexen * sctp_findassociation_ep_addr() wil do a 5754227755Stuexen * decrement if it finds the stcb as long as 5755227755Stuexen * the locked tcb (last argument) is NOT a 5756227755Stuexen * TCB.. aka NULL. 5757227755Stuexen */ 5758227755Stuexen net = NULL; 5759227755Stuexen SCTP_INP_INCR_REF(inp); 5760227755Stuexen stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&encaps->sue_address, &net, NULL, NULL); 5761227755Stuexen if (stcb == NULL) { 5762227755Stuexen SCTP_INP_DECR_REF(inp); 5763227755Stuexen } 5764227755Stuexen } 5765227755Stuexen if (stcb && (net == NULL)) { 5766227755Stuexen struct sockaddr *sa; 5767227755Stuexen 5768227755Stuexen sa = (struct sockaddr *)&encaps->sue_address; 5769227755Stuexen#ifdef INET 5770227755Stuexen if (sa->sa_family == AF_INET) { 5771227755Stuexen 5772227755Stuexen struct sockaddr_in *sin; 5773227755Stuexen 5774227755Stuexen sin = (struct sockaddr_in *)sa; 5775227755Stuexen if (sin->sin_addr.s_addr) { 5776227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5777227755Stuexen SCTP_TCB_UNLOCK(stcb); 5778227755Stuexen error = EINVAL; 5779227755Stuexen break; 5780227755Stuexen } 5781227755Stuexen } else 5782227755Stuexen#endif 5783227755Stuexen#ifdef INET6 5784227755Stuexen if (sa->sa_family == AF_INET6) { 5785227755Stuexen struct sockaddr_in6 *sin6; 5786227755Stuexen 5787227755Stuexen sin6 = (struct sockaddr_in6 *)sa; 5788227755Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 5789227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5790227755Stuexen SCTP_TCB_UNLOCK(stcb); 5791227755Stuexen error = EINVAL; 5792227755Stuexen break; 5793227755Stuexen } 5794227755Stuexen } else 5795227755Stuexen#endif 5796227755Stuexen { 5797227755Stuexen error = EAFNOSUPPORT; 5798227755Stuexen SCTP_TCB_UNLOCK(stcb); 5799227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 5800227755Stuexen break; 5801227755Stuexen } 5802227755Stuexen } 5803227755Stuexen if (stcb) { 5804227755Stuexen if (net) { 5805227755Stuexen net->port = encaps->sue_port; 5806227755Stuexen } else { 5807227755Stuexen stcb->asoc.port = encaps->sue_port; 5808227755Stuexen } 5809227755Stuexen SCTP_TCB_UNLOCK(stcb); 5810227755Stuexen } else { 5811227755Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5812227755Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5813227755Stuexen (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) { 5814227755Stuexen SCTP_INP_WLOCK(inp); 5815227755Stuexen inp->sctp_ep.port = encaps->sue_port; 5816227755Stuexen SCTP_INP_WUNLOCK(inp); 5817227755Stuexen } else { 5818227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5819227755Stuexen error = EINVAL; 5820227755Stuexen } 5821227755Stuexen } 5822227755Stuexen break; 5823227755Stuexen } 5824163953Srrs default: 5825171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 5826163953Srrs error = ENOPROTOOPT; 5827163953Srrs break; 5828163953Srrs } /* end switch (opt) */ 5829163953Srrs return (error); 5830163953Srrs} 5831163953Srrs 5832163953Srrsint 5833163953Srrssctp_ctloutput(struct socket *so, struct sockopt *sopt) 5834163953Srrs{ 5835166675Srrs void *optval = NULL; 5836166675Srrs size_t optsize = 0; 5837166675Srrs void *p; 5838166675Srrs int error = 0; 5839163953Srrs 5840163953Srrs if (sopt->sopt_level != IPPROTO_SCTP) { 5841163953Srrs /* wrong proto level... send back up to IP */ 5842163953Srrs#ifdef INET6 5843163953Srrs if (INP_CHECK_SOCKAF(so, AF_INET6)) 5844163953Srrs error = ip6_ctloutput(so, sopt); 5845221249Stuexen#endif /* INET6 */ 5846221249Stuexen#if defined(INET) && defined (INET6) 5847163953Srrs else 5848221249Stuexen#endif 5849221249Stuexen#ifdef INET 5850163953Srrs error = ip_ctloutput(so, sopt); 5851221249Stuexen#endif 5852163953Srrs return (error); 5853163953Srrs } 5854166675Srrs optsize = sopt->sopt_valsize; 5855166675Srrs if (optsize) { 5856170091Srrs SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT); 5857166675Srrs if (optval == NULL) { 5858235091Stuexen SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS); 5859163953Srrs return (ENOBUFS); 5860163953Srrs } 5861166675Srrs error = sooptcopyin(sopt, optval, optsize, optsize); 5862163953Srrs if (error) { 5863170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 5864163953Srrs goto out; 5865163953Srrs } 5866163953Srrs } 5867166675Srrs p = (void *)sopt->sopt_td; 5868163953Srrs if (sopt->sopt_dir == SOPT_SET) { 5869166675Srrs error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p); 5870163953Srrs } else if (sopt->sopt_dir == SOPT_GET) { 5871166675Srrs error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p); 5872163953Srrs } else { 5873235091Stuexen SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5874163953Srrs error = EINVAL; 5875163953Srrs } 5876166675Srrs if ((error == 0) && (optval != NULL)) { 5877166675Srrs error = sooptcopyout(sopt, optval, optsize); 5878170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 5879166675Srrs } else if (optval != NULL) { 5880170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 5881163953Srrs } 5882163953Srrsout: 5883163953Srrs return (error); 5884163953Srrs} 5885163953Srrs 5886221249Stuexen#ifdef INET 5887163953Srrsstatic int 5888163953Srrssctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p) 5889163953Srrs{ 5890163953Srrs int error = 0; 5891163953Srrs int create_lock_on = 0; 5892167598Srrs uint32_t vrf_id; 5893163953Srrs struct sctp_inpcb *inp; 5894163953Srrs struct sctp_tcb *stcb = NULL; 5895163953Srrs 5896163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 5897233005Stuexen if (inp == NULL) { 5898163953Srrs /* I made the same as TCP since we are not setup? */ 5899171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5900163953Srrs return (ECONNRESET); 5901163953Srrs } 5902171943Srrs if (addr == NULL) { 5903171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5904170056Srrs return EINVAL; 5905171943Srrs } 5906221249Stuexen switch (addr->sa_family) { 5907185435Sbz#ifdef INET6 5908221249Stuexen case AF_INET6: 5909221249Stuexen { 5910221249Stuexen struct sockaddr_in6 *sin6p; 5911185694Srrs 5912221249Stuexen if (addr->sa_len != sizeof(struct sockaddr_in6)) { 5913221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5914221249Stuexen return (EINVAL); 5915221249Stuexen } 5916221249Stuexen sin6p = (struct sockaddr_in6 *)addr; 5917221249Stuexen if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6p->sin6_addr)) != 0) { 5918221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 5919221249Stuexen return (error); 5920221249Stuexen } 5921221249Stuexen break; 5922185435Sbz } 5923185435Sbz#endif 5924221249Stuexen#ifdef INET 5925221249Stuexen case AF_INET: 5926221249Stuexen { 5927221249Stuexen struct sockaddr_in *sinp; 5928185694Srrs 5929221249Stuexen if (addr->sa_len != sizeof(struct sockaddr_in)) { 5930221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5931221249Stuexen return (EINVAL); 5932221249Stuexen } 5933221249Stuexen sinp = (struct sockaddr_in *)addr; 5934221249Stuexen if (p != NULL && (error = prison_remote_ip4(p->td_ucred, &sinp->sin_addr)) != 0) { 5935221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 5936221249Stuexen return (error); 5937221249Stuexen } 5938221249Stuexen break; 5939185435Sbz } 5940221249Stuexen#endif 5941221249Stuexen default: 5942185435Sbz SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT); 5943185435Sbz return (EAFNOSUPPORT); 5944170056Srrs } 5945178202Srrs SCTP_INP_INCR_REF(inp); 5946163953Srrs SCTP_ASOC_CREATE_LOCK(inp); 5947163953Srrs create_lock_on = 1; 5948163953Srrs 5949178202Srrs 5950163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 5951163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 5952163953Srrs /* Should I really unlock ? */ 5953171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); 5954163953Srrs error = EFAULT; 5955163953Srrs goto out_now; 5956163953Srrs } 5957163953Srrs#ifdef INET6 5958163953Srrs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 5959163953Srrs (addr->sa_family == AF_INET6)) { 5960171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5961163953Srrs error = EINVAL; 5962163953Srrs goto out_now; 5963163953Srrs } 5964163953Srrs#endif /* INET6 */ 5965163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 5966163953Srrs SCTP_PCB_FLAGS_UNBOUND) { 5967163953Srrs /* Bind a ephemeral port */ 5968171572Srrs error = sctp_inpcb_bind(so, NULL, NULL, p); 5969163953Srrs if (error) { 5970163953Srrs goto out_now; 5971163953Srrs } 5972163953Srrs } 5973163953Srrs /* Now do we connect? */ 5974181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && 5975181054Srrs (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) { 5976171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5977163953Srrs error = EINVAL; 5978163953Srrs goto out_now; 5979163953Srrs } 5980163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 5981163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 5982163953Srrs /* We are already connected AND the TCP model */ 5983171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 5984163953Srrs error = EADDRINUSE; 5985163953Srrs goto out_now; 5986163953Srrs } 5987163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 5988163953Srrs SCTP_INP_RLOCK(inp); 5989163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 5990163953Srrs SCTP_INP_RUNLOCK(inp); 5991163953Srrs } else { 5992163953Srrs /* 5993166675Srrs * We increment here since sctp_findassociation_ep_addr() 5994181054Srrs * will do a decrement if it finds the stcb as long as the 5995166675Srrs * locked tcb (last argument) is NOT a TCB.. aka NULL. 5996163953Srrs */ 5997163953Srrs SCTP_INP_INCR_REF(inp); 5998163953Srrs stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL); 5999163953Srrs if (stcb == NULL) { 6000163953Srrs SCTP_INP_DECR_REF(inp); 6001168299Srrs } else { 6002178202Srrs SCTP_TCB_UNLOCK(stcb); 6003163953Srrs } 6004163953Srrs } 6005163953Srrs if (stcb != NULL) { 6006163953Srrs /* Already have or am bring up an association */ 6007171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 6008163953Srrs error = EALREADY; 6009163953Srrs goto out_now; 6010163953Srrs } 6011168299Srrs vrf_id = inp->def_vrf_id; 6012163953Srrs /* We are GOOD to go */ 6013206137Stuexen stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p); 6014163953Srrs if (stcb == NULL) { 6015163953Srrs /* Gak! no memory */ 6016167598Srrs goto out_now; 6017163953Srrs } 6018163953Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 6019163953Srrs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 6020163953Srrs /* Set the connected flag so we can queue data */ 6021163953Srrs soisconnecting(so); 6022163953Srrs } 6023171943Srrs SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); 6024169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 6025163953Srrs 6026163953Srrs /* initialize authentication parameters for the assoc */ 6027163953Srrs sctp_initialize_auth_params(inp, stcb); 6028163953Srrs 6029172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 6030168299Srrs SCTP_TCB_UNLOCK(stcb); 6031163953Srrsout_now: 6032169420Srrs if (create_lock_on) { 6033163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 6034169420Srrs } 6035163953Srrs SCTP_INP_DECR_REF(inp); 6036228907Stuexen return (error); 6037163953Srrs} 6038163953Srrs 6039221249Stuexen#endif 6040221249Stuexen 6041163953Srrsint 6042163953Srrssctp_listen(struct socket *so, int backlog, struct thread *p) 6043163953Srrs{ 6044163953Srrs /* 6045163953Srrs * Note this module depends on the protocol processing being called 6046163953Srrs * AFTER any socket level flags and backlog are applied to the 6047163953Srrs * socket. The traditional way that the socket flags are applied is 6048163953Srrs * AFTER protocol processing. We have made a change to the 6049163953Srrs * sys/kern/uipc_socket.c module to reverse this but this MUST be in 6050163953Srrs * place if the socket API for SCTP is to work properly. 6051163953Srrs */ 6052163953Srrs 6053163953Srrs int error = 0; 6054163953Srrs struct sctp_inpcb *inp; 6055163953Srrs 6056163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 6057233005Stuexen if (inp == NULL) { 6058163953Srrs /* I made the same as TCP since we are not setup? */ 6059171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6060163953Srrs return (ECONNRESET); 6061163953Srrs } 6062181054Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) { 6063181054Srrs /* See if we have a listener */ 6064181054Srrs struct sctp_inpcb *tinp; 6065181054Srrs union sctp_sockstore store, *sp; 6066181054Srrs 6067181054Srrs sp = &store; 6068181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { 6069181054Srrs /* not bound all */ 6070181054Srrs struct sctp_laddr *laddr; 6071181054Srrs 6072181054Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 6073181054Srrs memcpy(&store, &laddr->ifa->address, sizeof(store)); 6074221249Stuexen switch (sp->sa.sa_family) { 6075221249Stuexen#ifdef INET 6076221249Stuexen case AF_INET: 6077221249Stuexen sp->sin.sin_port = inp->sctp_lport; 6078221249Stuexen break; 6079221249Stuexen#endif 6080221249Stuexen#ifdef INET6 6081221249Stuexen case AF_INET6: 6082221249Stuexen sp->sin6.sin6_port = inp->sctp_lport; 6083221249Stuexen break; 6084221249Stuexen#endif 6085221249Stuexen default: 6086221249Stuexen break; 6087221249Stuexen } 6088181054Srrs tinp = sctp_pcb_findep(&sp->sa, 0, 0, inp->def_vrf_id); 6089181054Srrs if (tinp && (tinp != inp) && 6090181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && 6091181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 6092181054Srrs (tinp->sctp_socket->so_qlimit)) { 6093181054Srrs /* 6094181054Srrs * we have a listener already and 6095181054Srrs * its not this inp. 6096181054Srrs */ 6097181054Srrs SCTP_INP_DECR_REF(tinp); 6098181054Srrs return (EADDRINUSE); 6099181054Srrs } else if (tinp) { 6100181054Srrs SCTP_INP_DECR_REF(tinp); 6101181054Srrs } 6102181054Srrs } 6103181054Srrs } else { 6104181054Srrs /* Setup a local addr bound all */ 6105181054Srrs memset(&store, 0, sizeof(store)); 6106221249Stuexen switch (sp->sa.sa_family) { 6107221249Stuexen#ifdef INET 6108221249Stuexen case AF_INET: 6109221249Stuexen store.sin.sin_port = inp->sctp_lport; 6110221249Stuexen break; 6111221249Stuexen#endif 6112181054Srrs#ifdef INET6 6113221249Stuexen case AF_INET6: 6114221249Stuexen sp->sin6.sin6_port = inp->sctp_lport; 6115221249Stuexen break; 6116221249Stuexen#endif 6117221249Stuexen default: 6118221249Stuexen break; 6119221249Stuexen } 6120221249Stuexen#ifdef INET6 6121181054Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 6122181054Srrs store.sa.sa_family = AF_INET6; 6123181054Srrs store.sa.sa_len = sizeof(struct sockaddr_in6); 6124181054Srrs } 6125181054Srrs#endif 6126221249Stuexen#ifdef INET 6127181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { 6128181054Srrs store.sa.sa_family = AF_INET; 6129181054Srrs store.sa.sa_len = sizeof(struct sockaddr_in); 6130181054Srrs } 6131221249Stuexen#endif 6132181054Srrs tinp = sctp_pcb_findep(&sp->sa, 0, 0, inp->def_vrf_id); 6133181054Srrs if (tinp && (tinp != inp) && 6134181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && 6135181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 6136181054Srrs (tinp->sctp_socket->so_qlimit)) { 6137181054Srrs /* 6138181054Srrs * we have a listener already and its not 6139181054Srrs * this inp. 6140181054Srrs */ 6141181054Srrs SCTP_INP_DECR_REF(tinp); 6142181054Srrs return (EADDRINUSE); 6143181054Srrs } else if (tinp) { 6144181054Srrs SCTP_INP_DECR_REF(inp); 6145181054Srrs } 6146181054Srrs } 6147181054Srrs } 6148163953Srrs SCTP_INP_RLOCK(inp); 6149163953Srrs#ifdef SCTP_LOCK_LOGGING 6150179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) { 6151170744Srrs sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK); 6152170744Srrs } 6153163953Srrs#endif 6154163953Srrs SOCK_LOCK(so); 6155163953Srrs error = solisten_proto_check(so); 6156163953Srrs if (error) { 6157163953Srrs SOCK_UNLOCK(so); 6158169208Srrs SCTP_INP_RUNLOCK(inp); 6159163953Srrs return (error); 6160163953Srrs } 6161181054Srrs if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) && 6162181054Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 6163181054Srrs /* 6164181054Srrs * The unlucky case - We are in the tcp pool with this guy. 6165181054Srrs * - Someone else is in the main inp slot. - We must move 6166181054Srrs * this guy (the listener) to the main slot - We must then 6167181054Srrs * move the guy that was listener to the TCP Pool. 6168181054Srrs */ 6169181054Srrs if (sctp_swap_inpcb_for_listen(inp)) { 6170181054Srrs goto in_use; 6171181054Srrs } 6172181054Srrs } 6173163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 6174163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 6175163953Srrs /* We are already connected AND the TCP model */ 6176181054Srrsin_use: 6177163953Srrs SCTP_INP_RUNLOCK(inp); 6178163953Srrs SOCK_UNLOCK(so); 6179171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 6180163953Srrs return (EADDRINUSE); 6181163953Srrs } 6182181054Srrs SCTP_INP_RUNLOCK(inp); 6183163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { 6184163953Srrs /* We must do a bind. */ 6185166675Srrs SOCK_UNLOCK(so); 6186171572Srrs if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) { 6187163953Srrs /* bind error, probably perm */ 6188163953Srrs return (error); 6189163953Srrs } 6190166675Srrs SOCK_LOCK(so); 6191163953Srrs } 6192163953Srrs /* It appears for 7.0 and on, we must always call this. */ 6193163953Srrs solisten_proto(so, backlog); 6194163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 6195163953Srrs /* remove the ACCEPTCONN flag for one-to-many sockets */ 6196163953Srrs so->so_options &= ~SO_ACCEPTCONN; 6197163953Srrs } 6198163953Srrs if (backlog == 0) { 6199163953Srrs /* turning off listen */ 6200163953Srrs so->so_options &= ~SO_ACCEPTCONN; 6201163953Srrs } 6202163953Srrs SOCK_UNLOCK(so); 6203163953Srrs return (error); 6204163953Srrs} 6205163953Srrs 6206163953Srrsstatic int sctp_defered_wakeup_cnt = 0; 6207163953Srrs 6208163953Srrsint 6209163953Srrssctp_accept(struct socket *so, struct sockaddr **addr) 6210163953Srrs{ 6211163953Srrs struct sctp_tcb *stcb; 6212163953Srrs struct sctp_inpcb *inp; 6213163953Srrs union sctp_sockstore store; 6214163953Srrs 6215178251Srrs#ifdef INET6 6216163953Srrs int error; 6217163953Srrs 6218178251Srrs#endif 6219163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 6220163953Srrs 6221233005Stuexen if (inp == NULL) { 6222171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6223163953Srrs return (ECONNRESET); 6224163953Srrs } 6225163953Srrs SCTP_INP_RLOCK(inp); 6226163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 6227168299Srrs SCTP_INP_RUNLOCK(inp); 6228171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 6229171943Srrs return (EOPNOTSUPP); 6230163953Srrs } 6231163953Srrs if (so->so_state & SS_ISDISCONNECTED) { 6232163953Srrs SCTP_INP_RUNLOCK(inp); 6233171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED); 6234163953Srrs return (ECONNABORTED); 6235163953Srrs } 6236163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 6237163953Srrs if (stcb == NULL) { 6238163953Srrs SCTP_INP_RUNLOCK(inp); 6239171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6240163953Srrs return (ECONNRESET); 6241163953Srrs } 6242163953Srrs SCTP_TCB_LOCK(stcb); 6243163953Srrs SCTP_INP_RUNLOCK(inp); 6244163953Srrs store = stcb->asoc.primary_destination->ro._l_addr; 6245207924Srrs stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE; 6246163953Srrs SCTP_TCB_UNLOCK(stcb); 6247178251Srrs switch (store.sa.sa_family) { 6248221249Stuexen#ifdef INET 6249178251Srrs case AF_INET: 6250178251Srrs { 6251178251Srrs struct sockaddr_in *sin; 6252163953Srrs 6253178251Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 6254208863Srrs if (sin == NULL) 6255208863Srrs return (ENOMEM); 6256178251Srrs sin->sin_family = AF_INET; 6257178251Srrs sin->sin_len = sizeof(*sin); 6258178251Srrs sin->sin_port = ((struct sockaddr_in *)&store)->sin_port; 6259178251Srrs sin->sin_addr = ((struct sockaddr_in *)&store)->sin_addr; 6260178251Srrs *addr = (struct sockaddr *)sin; 6261178251Srrs break; 6262178251Srrs } 6263221249Stuexen#endif 6264178251Srrs#ifdef INET6 6265178251Srrs case AF_INET6: 6266178251Srrs { 6267178251Srrs struct sockaddr_in6 *sin6; 6268163953Srrs 6269178251Srrs SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); 6270208863Srrs if (sin6 == NULL) 6271208863Srrs return (ENOMEM); 6272178251Srrs sin6->sin6_family = AF_INET6; 6273178251Srrs sin6->sin6_len = sizeof(*sin6); 6274178251Srrs sin6->sin6_port = ((struct sockaddr_in6 *)&store)->sin6_port; 6275163953Srrs 6276178251Srrs sin6->sin6_addr = ((struct sockaddr_in6 *)&store)->sin6_addr; 6277178251Srrs if ((error = sa6_recoverscope(sin6)) != 0) { 6278178251Srrs SCTP_FREE_SONAME(sin6); 6279178251Srrs return (error); 6280178251Srrs } 6281178251Srrs *addr = (struct sockaddr *)sin6; 6282178251Srrs break; 6283164085Srrs } 6284178251Srrs#endif 6285178251Srrs default: 6286178251Srrs /* TSNH */ 6287178251Srrs break; 6288163953Srrs } 6289163953Srrs /* Wake any delayed sleep action */ 6290163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { 6291166086Srrs SCTP_INP_WLOCK(inp); 6292163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE; 6293163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) { 6294163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT; 6295166086Srrs SCTP_INP_WUNLOCK(inp); 6296163953Srrs SOCKBUF_LOCK(&inp->sctp_socket->so_snd); 6297163953Srrs if (sowriteable(inp->sctp_socket)) { 6298163953Srrs sowwakeup_locked(inp->sctp_socket); 6299163953Srrs } else { 6300163953Srrs SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd); 6301163953Srrs } 6302166086Srrs SCTP_INP_WLOCK(inp); 6303163953Srrs } 6304163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) { 6305163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT; 6306166086Srrs SCTP_INP_WUNLOCK(inp); 6307163953Srrs SOCKBUF_LOCK(&inp->sctp_socket->so_rcv); 6308163953Srrs if (soreadable(inp->sctp_socket)) { 6309163953Srrs sctp_defered_wakeup_cnt++; 6310163953Srrs sorwakeup_locked(inp->sctp_socket); 6311163953Srrs } else { 6312163953Srrs SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv); 6313163953Srrs } 6314166086Srrs SCTP_INP_WLOCK(inp); 6315163953Srrs } 6316166086Srrs SCTP_INP_WUNLOCK(inp); 6317163953Srrs } 6318207924Srrs if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 6319207924Srrs SCTP_TCB_LOCK(stcb); 6320207924Srrs sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); 6321207924Srrs } 6322163953Srrs return (0); 6323163953Srrs} 6324163953Srrs 6325221249Stuexen#ifdef INET 6326163953Srrsint 6327163953Srrssctp_ingetaddr(struct socket *so, struct sockaddr **addr) 6328163953Srrs{ 6329163953Srrs struct sockaddr_in *sin; 6330167598Srrs uint32_t vrf_id; 6331163953Srrs struct sctp_inpcb *inp; 6332167695Srrs struct sctp_ifa *sctp_ifa; 6333163953Srrs 6334163953Srrs /* 6335163953Srrs * Do the malloc first in case it blocks. 6336163953Srrs */ 6337163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 6338208863Srrs if (sin == NULL) 6339208863Srrs return (ENOMEM); 6340163953Srrs sin->sin_family = AF_INET; 6341163953Srrs sin->sin_len = sizeof(*sin); 6342163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 6343163953Srrs if (!inp) { 6344163953Srrs SCTP_FREE_SONAME(sin); 6345171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6346228907Stuexen return (ECONNRESET); 6347163953Srrs } 6348163953Srrs SCTP_INP_RLOCK(inp); 6349163953Srrs sin->sin_port = inp->sctp_lport; 6350163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 6351163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 6352163953Srrs struct sctp_tcb *stcb; 6353163953Srrs struct sockaddr_in *sin_a; 6354163953Srrs struct sctp_nets *net; 6355163953Srrs int fnd; 6356163953Srrs 6357163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 6358163953Srrs if (stcb == NULL) { 6359163953Srrs goto notConn; 6360163953Srrs } 6361163953Srrs fnd = 0; 6362163953Srrs sin_a = NULL; 6363163953Srrs SCTP_TCB_LOCK(stcb); 6364163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 6365163953Srrs sin_a = (struct sockaddr_in *)&net->ro._l_addr; 6366164085Srrs if (sin_a == NULL) 6367164085Srrs /* this will make coverity happy */ 6368164085Srrs continue; 6369164085Srrs 6370163953Srrs if (sin_a->sin_family == AF_INET) { 6371163953Srrs fnd = 1; 6372163953Srrs break; 6373163953Srrs } 6374163953Srrs } 6375163953Srrs if ((!fnd) || (sin_a == NULL)) { 6376163953Srrs /* punt */ 6377163953Srrs SCTP_TCB_UNLOCK(stcb); 6378163953Srrs goto notConn; 6379163953Srrs } 6380168299Srrs vrf_id = inp->def_vrf_id; 6381167598Srrs sctp_ifa = sctp_source_address_selection(inp, 6382167598Srrs stcb, 6383168299Srrs (sctp_route_t *) & net->ro, 6384167598Srrs net, 0, vrf_id); 6385167598Srrs if (sctp_ifa) { 6386167598Srrs sin->sin_addr = sctp_ifa->address.sin.sin_addr; 6387167598Srrs sctp_free_ifa(sctp_ifa); 6388167598Srrs } 6389163953Srrs SCTP_TCB_UNLOCK(stcb); 6390163953Srrs } else { 6391163953Srrs /* For the bound all case you get back 0 */ 6392163953Srrs notConn: 6393163953Srrs sin->sin_addr.s_addr = 0; 6394163953Srrs } 6395163953Srrs 6396163953Srrs } else { 6397163953Srrs /* Take the first IPv4 address in the list */ 6398163953Srrs struct sctp_laddr *laddr; 6399163953Srrs int fnd = 0; 6400163953Srrs 6401163953Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 6402167598Srrs if (laddr->ifa->address.sa.sa_family == AF_INET) { 6403163953Srrs struct sockaddr_in *sin_a; 6404163953Srrs 6405167598Srrs sin_a = (struct sockaddr_in *)&laddr->ifa->address.sa; 6406163953Srrs sin->sin_addr = sin_a->sin_addr; 6407163953Srrs fnd = 1; 6408163953Srrs break; 6409163953Srrs } 6410163953Srrs } 6411163953Srrs if (!fnd) { 6412163953Srrs SCTP_FREE_SONAME(sin); 6413163953Srrs SCTP_INP_RUNLOCK(inp); 6414171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 6415228907Stuexen return (ENOENT); 6416163953Srrs } 6417163953Srrs } 6418163953Srrs SCTP_INP_RUNLOCK(inp); 6419163953Srrs (*addr) = (struct sockaddr *)sin; 6420163953Srrs return (0); 6421163953Srrs} 6422163953Srrs 6423163953Srrsint 6424163953Srrssctp_peeraddr(struct socket *so, struct sockaddr **addr) 6425163953Srrs{ 6426231895Stuexen struct sockaddr_in *sin; 6427166086Srrs int fnd; 6428163953Srrs struct sockaddr_in *sin_a; 6429163953Srrs struct sctp_inpcb *inp; 6430163953Srrs struct sctp_tcb *stcb; 6431163953Srrs struct sctp_nets *net; 6432163953Srrs 6433163953Srrs /* Do the malloc first in case it blocks. */ 6434163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 6435208863Srrs if (sin == NULL) 6436208863Srrs return (ENOMEM); 6437163953Srrs sin->sin_family = AF_INET; 6438163953Srrs sin->sin_len = sizeof(*sin); 6439163953Srrs 6440163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 6441228907Stuexen if ((inp == NULL) || 6442228907Stuexen ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { 6443228907Stuexen /* UDP type and listeners will drop out here */ 6444163953Srrs SCTP_FREE_SONAME(sin); 6445228907Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 6446228907Stuexen return (ENOTCONN); 6447163953Srrs } 6448163953Srrs SCTP_INP_RLOCK(inp); 6449163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 6450169420Srrs if (stcb) { 6451163953Srrs SCTP_TCB_LOCK(stcb); 6452169420Srrs } 6453163953Srrs SCTP_INP_RUNLOCK(inp); 6454163953Srrs if (stcb == NULL) { 6455163953Srrs SCTP_FREE_SONAME(sin); 6456171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6457228907Stuexen return (ECONNRESET); 6458163953Srrs } 6459163953Srrs fnd = 0; 6460163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 6461163953Srrs sin_a = (struct sockaddr_in *)&net->ro._l_addr; 6462163953Srrs if (sin_a->sin_family == AF_INET) { 6463163953Srrs fnd = 1; 6464163953Srrs sin->sin_port = stcb->rport; 6465163953Srrs sin->sin_addr = sin_a->sin_addr; 6466163953Srrs break; 6467163953Srrs } 6468163953Srrs } 6469163953Srrs SCTP_TCB_UNLOCK(stcb); 6470163953Srrs if (!fnd) { 6471163953Srrs /* No IPv4 address */ 6472163953Srrs SCTP_FREE_SONAME(sin); 6473171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 6474228907Stuexen return (ENOENT); 6475163953Srrs } 6476163953Srrs (*addr) = (struct sockaddr *)sin; 6477163953Srrs return (0); 6478163953Srrs} 6479163953Srrs 6480221249Stuexen#ifdef INET 6481163953Srrsstruct pr_usrreqs sctp_usrreqs = { 6482163953Srrs .pru_abort = sctp_abort, 6483163953Srrs .pru_accept = sctp_accept, 6484163953Srrs .pru_attach = sctp_attach, 6485163953Srrs .pru_bind = sctp_bind, 6486163953Srrs .pru_connect = sctp_connect, 6487163953Srrs .pru_control = in_control, 6488163953Srrs .pru_close = sctp_close, 6489163953Srrs .pru_detach = sctp_close, 6490163953Srrs .pru_sopoll = sopoll_generic, 6491178202Srrs .pru_flush = sctp_flush, 6492163953Srrs .pru_disconnect = sctp_disconnect, 6493163953Srrs .pru_listen = sctp_listen, 6494163953Srrs .pru_peeraddr = sctp_peeraddr, 6495163953Srrs .pru_send = sctp_sendm, 6496163953Srrs .pru_shutdown = sctp_shutdown, 6497163953Srrs .pru_sockaddr = sctp_ingetaddr, 6498163953Srrs .pru_sosend = sctp_sosend, 6499163953Srrs .pru_soreceive = sctp_soreceive 6500163953Srrs}; 6501221249Stuexen 6502221249Stuexen#endif 6503221249Stuexen#endif 6504