1163953Srrs/*- 2185694Srrs * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. 3235828Stuexen * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. 4235828Stuexen * Copyright (c) 2008-2012, 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#include <sys/cdefs.h> 34163953Srrs__FBSDID("$FreeBSD$"); 35235828Stuexen 36166086Srrs#include <netinet/sctp_os.h> 37163953Srrs#include <sys/proc.h> 38163953Srrs#include <netinet/sctp_pcb.h> 39163953Srrs#include <netinet/sctp_header.h> 40163953Srrs#include <netinet/sctp_var.h> 41238475Stuexen#ifdef INET6 42283699Stuexen#include <netinet6/sctp6_var.h> 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); 128283729Stuexen chk->sent = SCTP_DATAGRAM_RESEND; 129163953Srrs sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 130283729Stuexen chk->rec.data.doing_fast_retransmit = 0; 131283729Stuexen if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { 132283729Stuexen sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU, 133283729Stuexen chk->whoTo->flight_size, 134283729Stuexen chk->book_size, 135283729Stuexen (uintptr_t) chk->whoTo, 136283729Stuexen chk->rec.data.TSN_seq); 137283729Stuexen } 138283729Stuexen /* Clear any time so NO RTT is being done */ 139283729Stuexen chk->do_rtt = 0; 140163953Srrs } 141163953Srrs } 142163953Srrs } 143163953Srrs} 144163953Srrs 145221249Stuexen#ifdef INET 146163953Srrsstatic void 147163953Srrssctp_notify_mbuf(struct sctp_inpcb *inp, 148163953Srrs struct sctp_tcb *stcb, 149163953Srrs struct sctp_nets *net, 150163953Srrs struct ip *ip, 151163953Srrs struct sctphdr *sh) 152163953Srrs{ 153163953Srrs struct icmp *icmph; 154163953Srrs int totsz, tmr_stopped = 0; 155163953Srrs uint16_t nxtsz; 156163953Srrs 157163953Srrs /* protection */ 158163953Srrs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 159163953Srrs (ip == NULL) || (sh == NULL)) { 160169420Srrs if (stcb != NULL) { 161163953Srrs SCTP_TCB_UNLOCK(stcb); 162169420Srrs } 163163953Srrs return; 164163953Srrs } 165163953Srrs /* First job is to verify the vtag matches what I would send */ 166163953Srrs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 167163953Srrs SCTP_TCB_UNLOCK(stcb); 168163953Srrs return; 169163953Srrs } 170163953Srrs icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) - 171163953Srrs sizeof(struct ip))); 172163953Srrs if (icmph->icmp_type != ICMP_UNREACH) { 173163953Srrs /* We only care about unreachable */ 174163953Srrs SCTP_TCB_UNLOCK(stcb); 175163953Srrs return; 176163953Srrs } 177163953Srrs if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) { 178163953Srrs /* not a unreachable message due to frag. */ 179163953Srrs SCTP_TCB_UNLOCK(stcb); 180163953Srrs return; 181163953Srrs } 182241913Sglebius totsz = ntohs(ip->ip_len); 183163953Srrs 184171943Srrs nxtsz = ntohs(icmph->icmp_nextmtu); 185163953Srrs if (nxtsz == 0) { 186163953Srrs /* 187163953Srrs * old type router that does not tell us what the next size 188163953Srrs * mtu is. Rats we will have to guess (in a educated fashion 189163953Srrs * of course) 190163953Srrs */ 191214939Stuexen nxtsz = sctp_get_prev_mtu(totsz); 192163953Srrs } 193163953Srrs /* Stop any PMTU timer */ 194165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 195163953Srrs tmr_stopped = 1; 196165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 197165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1); 198163953Srrs } 199163953Srrs /* Adjust destination size limit */ 200163953Srrs if (net->mtu > nxtsz) { 201163953Srrs net->mtu = nxtsz; 202185694Srrs if (net->port) { 203185694Srrs net->mtu -= sizeof(struct udphdr); 204185694Srrs } 205163953Srrs } 206163953Srrs /* now what about the ep? */ 207163953Srrs if (stcb->asoc.smallest_mtu > nxtsz) { 208228653Stuexen sctp_pathmtu_adjustment(stcb, nxtsz); 209163953Srrs } 210163953Srrs if (tmr_stopped) 211163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 212163953Srrs 213163953Srrs SCTP_TCB_UNLOCK(stcb); 214163953Srrs} 215163953Srrs 216163953Srrsvoid 217163953Srrssctp_notify(struct sctp_inpcb *inp, 218172091Srrs struct ip *ip, 219163953Srrs struct sctphdr *sh, 220163953Srrs struct sockaddr *to, 221163953Srrs struct sctp_tcb *stcb, 222163953Srrs struct sctp_nets *net) 223163953Srrs{ 224237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 225172090Srrs struct socket *so; 226172090Srrs 227172090Srrs#endif 228172091Srrs struct icmp *icmph; 229172091Srrs 230235360Stuexen /* protection */ 231163953Srrs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 232163953Srrs (sh == NULL) || (to == NULL)) { 233172091Srrs if (stcb) 234172091Srrs SCTP_TCB_UNLOCK(stcb); 235163953Srrs return; 236163953Srrs } 237163953Srrs /* First job is to verify the vtag matches what I would send */ 238163953Srrs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 239172091Srrs SCTP_TCB_UNLOCK(stcb); 240163953Srrs return; 241163953Srrs } 242172091Srrs icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) - 243172091Srrs sizeof(struct ip))); 244172091Srrs if (icmph->icmp_type != ICMP_UNREACH) { 245172091Srrs /* We only care about unreachable */ 246172091Srrs SCTP_TCB_UNLOCK(stcb); 247172091Srrs return; 248172091Srrs } 249172091Srrs if ((icmph->icmp_code == ICMP_UNREACH_NET) || 250172091Srrs (icmph->icmp_code == ICMP_UNREACH_HOST) || 251172091Srrs (icmph->icmp_code == ICMP_UNREACH_NET_UNKNOWN) || 252172091Srrs (icmph->icmp_code == ICMP_UNREACH_HOST_UNKNOWN) || 253172091Srrs (icmph->icmp_code == ICMP_UNREACH_ISOLATED) || 254172091Srrs (icmph->icmp_code == ICMP_UNREACH_NET_PROHIB) || 255172091Srrs (icmph->icmp_code == ICMP_UNREACH_HOST_PROHIB) || 256172091Srrs (icmph->icmp_code == ICMP_UNREACH_FILTER_PROHIB)) { 257163953Srrs 258163953Srrs /* 259163953Srrs * Hmm reachablity problems we must examine closely. If its 260163953Srrs * not reachable, we may have lost a network. Or if there is 261163953Srrs * NO protocol at the other end named SCTP. well we consider 262163953Srrs * it a OOTB abort. 263163953Srrs */ 264172091Srrs if (net->dest_state & SCTP_ADDR_REACHABLE) { 265172091Srrs /* Ok that destination is NOT reachable */ 266172091Srrs net->dest_state &= ~SCTP_ADDR_REACHABLE; 267224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 268172091Srrs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, 269235414Stuexen stcb, 0, 270172091Srrs (void *)net, SCTP_SO_NOT_LOCKED); 271172091Srrs } 272172091Srrs SCTP_TCB_UNLOCK(stcb); 273172091Srrs } else if ((icmph->icmp_code == ICMP_UNREACH_PROTOCOL) || 274172091Srrs (icmph->icmp_code == ICMP_UNREACH_PORT)) { 275172091Srrs /* 276172091Srrs * Here the peer is either playing tricks on us, including 277172091Srrs * an address that belongs to someone who does not support 278172091Srrs * SCTP OR was a userland implementation that shutdown and 279172091Srrs * now is dead. In either case treat it like a OOTB abort 280172091Srrs * with no TCB 281172091Srrs */ 282235403Stuexen sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED); 283237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 284172091Srrs so = SCTP_INP_SO(inp); 285172091Srrs atomic_add_int(&stcb->asoc.refcnt, 1); 286172091Srrs SCTP_TCB_UNLOCK(stcb); 287172091Srrs SCTP_SOCKET_LOCK(so, 1); 288172091Srrs SCTP_TCB_LOCK(stcb); 289172091Srrs atomic_subtract_int(&stcb->asoc.refcnt, 1); 290172090Srrs#endif 291283822Stuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 292283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); 293237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 294172091Srrs SCTP_SOCKET_UNLOCK(so, 1); 295172091Srrs /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */ 296172090Srrs#endif 297172091Srrs /* no need to unlock here, since the TCB is gone */ 298163953Srrs } else { 299172091Srrs SCTP_TCB_UNLOCK(stcb); 300163953Srrs } 301163953Srrs} 302163953Srrs 303270350Stuexen#endif 304270350Stuexen 305221249Stuexen#ifdef INET 306163953Srrsvoid 307163953Srrssctp_ctlinput(cmd, sa, vip) 308163953Srrs int cmd; 309163953Srrs struct sockaddr *sa; 310163953Srrs void *vip; 311163953Srrs{ 312163953Srrs struct ip *ip = vip; 313163953Srrs struct sctphdr *sh; 314167598Srrs uint32_t vrf_id; 315163953Srrs 316168299Srrs /* FIX, for non-bsd is this right? */ 317167598Srrs vrf_id = SCTP_DEFAULT_VRFID; 318163953Srrs if (sa->sa_family != AF_INET || 319163953Srrs ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) { 320163953Srrs return; 321163953Srrs } 322163953Srrs if (PRC_IS_REDIRECT(cmd)) { 323163953Srrs ip = 0; 324163953Srrs } else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) { 325163953Srrs return; 326163953Srrs } 327163953Srrs if (ip) { 328163953Srrs struct sctp_inpcb *inp = NULL; 329163953Srrs struct sctp_tcb *stcb = NULL; 330163953Srrs struct sctp_nets *net = NULL; 331163953Srrs struct sockaddr_in to, from; 332163953Srrs 333163953Srrs sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 334163953Srrs bzero(&to, sizeof(to)); 335163953Srrs bzero(&from, sizeof(from)); 336163953Srrs from.sin_family = to.sin_family = AF_INET; 337163953Srrs from.sin_len = to.sin_len = sizeof(to); 338163953Srrs from.sin_port = sh->src_port; 339163953Srrs from.sin_addr = ip->ip_src; 340163953Srrs to.sin_port = sh->dest_port; 341163953Srrs to.sin_addr = ip->ip_dst; 342163953Srrs 343163953Srrs /* 344163953Srrs * 'to' holds the dest of the packet that failed to be sent. 345163953Srrs * 'from' holds our local endpoint address. Thus we reverse 346163953Srrs * the to and the from in the lookup. 347163953Srrs */ 348237715Stuexen stcb = sctp_findassociation_addr_sa((struct sockaddr *)&to, 349237715Stuexen (struct sockaddr *)&from, 350167598Srrs &inp, &net, 1, vrf_id); 351163953Srrs if (stcb != NULL && inp && (inp->sctp_socket != NULL)) { 352163953Srrs if (cmd != PRC_MSGSIZE) { 353172091Srrs sctp_notify(inp, ip, sh, 354163953Srrs (struct sockaddr *)&to, stcb, 355163953Srrs net); 356163953Srrs } else { 357163953Srrs /* handle possible ICMP size messages */ 358163953Srrs sctp_notify_mbuf(inp, stcb, net, ip, sh); 359163953Srrs } 360163953Srrs } else { 361163953Srrs if ((stcb == NULL) && (inp != NULL)) { 362163953Srrs /* reduce ref-count */ 363163953Srrs SCTP_INP_WLOCK(inp); 364163953Srrs SCTP_INP_DECR_REF(inp); 365163953Srrs SCTP_INP_WUNLOCK(inp); 366163953Srrs } 367209029Srrs if (stcb) { 368209029Srrs SCTP_TCB_UNLOCK(stcb); 369209029Srrs } 370163953Srrs } 371163953Srrs } 372163953Srrs return; 373163953Srrs} 374163953Srrs 375221249Stuexen#endif 376221249Stuexen 377163953Srrsstatic int 378163953Srrssctp_getcred(SYSCTL_HANDLER_ARGS) 379163953Srrs{ 380164085Srrs struct xucred xuc; 381163953Srrs struct sockaddr_in addrs[2]; 382163953Srrs struct sctp_inpcb *inp; 383163953Srrs struct sctp_nets *net; 384163953Srrs struct sctp_tcb *stcb; 385164085Srrs int error; 386167598Srrs uint32_t vrf_id; 387163953Srrs 388168299Srrs /* FIX, for non-bsd is this right? */ 389167598Srrs vrf_id = SCTP_DEFAULT_VRFID; 390168299Srrs 391170587Srwatson error = priv_check(req->td, PRIV_NETINET_GETCRED); 392170587Srwatson 393163953Srrs if (error) 394163953Srrs return (error); 395164039Srwatson 396163953Srrs error = SYSCTL_IN(req, addrs, sizeof(addrs)); 397163953Srrs if (error) 398163953Srrs return (error); 399163953Srrs 400237715Stuexen stcb = sctp_findassociation_addr_sa(sintosa(&addrs[1]), 401237715Stuexen sintosa(&addrs[0]), 402167598Srrs &inp, &net, 1, vrf_id); 403163953Srrs if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) { 404163953Srrs if ((inp != NULL) && (stcb == NULL)) { 405163953Srrs /* reduce ref-count */ 406163953Srrs SCTP_INP_WLOCK(inp); 407163953Srrs SCTP_INP_DECR_REF(inp); 408164085Srrs goto cred_can_cont; 409163953Srrs } 410171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 411163953Srrs error = ENOENT; 412163953Srrs goto out; 413163953Srrs } 414163953Srrs SCTP_TCB_UNLOCK(stcb); 415164085Srrs /* 416164085Srrs * We use the write lock here, only since in the error leg we need 417164085Srrs * it. If we used RLOCK, then we would have to 418164085Srrs * wlock/decr/unlock/rlock. Which in theory could create a hole. 419164085Srrs * Better to use higher wlock. 420164085Srrs */ 421164085Srrs SCTP_INP_WLOCK(inp); 422164085Srrscred_can_cont: 423164085Srrs error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket); 424164085Srrs if (error) { 425164085Srrs SCTP_INP_WUNLOCK(inp); 426164085Srrs goto out; 427164085Srrs } 428164085Srrs cru2x(inp->sctp_socket->so_cred, &xuc); 429164085Srrs SCTP_INP_WUNLOCK(inp); 430164085Srrs error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); 431163953Srrsout: 432163953Srrs return (error); 433163953Srrs} 434163953Srrs 435163953SrrsSYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW, 436163953Srrs 0, 0, sctp_getcred, "S,ucred", "Get the ucred of a SCTP connection"); 437163953Srrs 438163953Srrs 439221249Stuexen#ifdef INET 440163953Srrsstatic void 441163953Srrssctp_abort(struct socket *so) 442163953Srrs{ 443163953Srrs struct sctp_inpcb *inp; 444163953Srrs uint32_t flags; 445163953Srrs 446163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 447233005Stuexen if (inp == NULL) { 448163953Srrs return; 449171943Srrs } 450163953Srrssctp_must_try_again: 451163953Srrs flags = inp->sctp_flags; 452163953Srrs#ifdef SCTP_LOG_CLOSING 453163953Srrs sctp_log_closing(inp, NULL, 17); 454163953Srrs#endif 455163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 456163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 457163953Srrs#ifdef SCTP_LOG_CLOSING 458163953Srrs sctp_log_closing(inp, NULL, 16); 459163953Srrs#endif 460169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 461169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 462163953Srrs SOCK_LOCK(so); 463167695Srrs SCTP_SB_CLEAR(so->so_snd); 464163953Srrs /* 465163953Srrs * same for the rcv ones, they are only here for the 466163953Srrs * accounting/select. 467163953Srrs */ 468167695Srrs SCTP_SB_CLEAR(so->so_rcv); 469167695Srrs 470167695Srrs /* Now null out the reference, we are completely detached. */ 471163953Srrs so->so_pcb = NULL; 472163953Srrs SOCK_UNLOCK(so); 473163953Srrs } else { 474163953Srrs flags = inp->sctp_flags; 475163953Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 476163953Srrs goto sctp_must_try_again; 477163953Srrs } 478163953Srrs } 479163953Srrs return; 480163953Srrs} 481163953Srrs 482163953Srrsstatic int 483228653Stuexensctp_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED) 484163953Srrs{ 485163953Srrs struct sctp_inpcb *inp; 486163953Srrs struct inpcb *ip_inp; 487166086Srrs int error; 488170205Srrs uint32_t vrf_id = SCTP_DEFAULT_VRFID; 489185694Srrs 490163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 491163953Srrs if (inp != 0) { 492171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 493228907Stuexen return (EINVAL); 494163953Srrs } 495184030Srrs if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 496184030Srrs error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace)); 497184030Srrs if (error) { 498228907Stuexen return (error); 499184030Srrs } 500163953Srrs } 501170205Srrs error = sctp_inpcb_alloc(so, vrf_id); 502163953Srrs if (error) { 503228907Stuexen return (error); 504163953Srrs } 505163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 506163953Srrs SCTP_INP_WLOCK(inp); 507163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6; /* I'm not v6! */ 508163953Srrs ip_inp = &inp->ip_inp.inp; 509163953Srrs ip_inp->inp_vflag |= INP_IPV4; 510197288Srrs ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl); 511163953Srrs SCTP_INP_WUNLOCK(inp); 512228907Stuexen return (0); 513163953Srrs} 514163953Srrs 515163953Srrsstatic int 516163953Srrssctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p) 517163953Srrs{ 518244730Stuexen struct sctp_inpcb *inp; 519163953Srrs 520163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 521233005Stuexen if (inp == NULL) { 522171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 523228907Stuexen return (EINVAL); 524171943Srrs } 525244730Stuexen if (addr != NULL) { 526244730Stuexen if ((addr->sa_family != AF_INET) || 527244730Stuexen (addr->sa_len != sizeof(struct sockaddr_in))) { 528244730Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 529244730Stuexen return (EINVAL); 530244730Stuexen } 531244730Stuexen } 532244730Stuexen return (sctp_inpcb_bind(so, addr, NULL, p)); 533163953Srrs} 534163953Srrs 535221249Stuexen#endif 536171990Srrsvoid 537163953Srrssctp_close(struct socket *so) 538163953Srrs{ 539163953Srrs struct sctp_inpcb *inp; 540163953Srrs uint32_t flags; 541163953Srrs 542163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 543233005Stuexen if (inp == NULL) 544163953Srrs return; 545163953Srrs 546163953Srrs /* 547163953Srrs * Inform all the lower layer assoc that we are done. 548163953Srrs */ 549163953Srrssctp_must_try_again: 550163953Srrs flags = inp->sctp_flags; 551163953Srrs#ifdef SCTP_LOG_CLOSING 552163953Srrs sctp_log_closing(inp, NULL, 17); 553163953Srrs#endif 554163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 555163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 556163953Srrs if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || 557163953Srrs (so->so_rcv.sb_cc > 0)) { 558163953Srrs#ifdef SCTP_LOG_CLOSING 559163953Srrs sctp_log_closing(inp, NULL, 13); 560163953Srrs#endif 561169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 562169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 563163953Srrs } else { 564163953Srrs#ifdef SCTP_LOG_CLOSING 565163953Srrs sctp_log_closing(inp, NULL, 14); 566163953Srrs#endif 567169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE, 568169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 569163953Srrs } 570163953Srrs /* 571163953Srrs * The socket is now detached, no matter what the state of 572163953Srrs * the SCTP association. 573163953Srrs */ 574163953Srrs SOCK_LOCK(so); 575167695Srrs SCTP_SB_CLEAR(so->so_snd); 576163953Srrs /* 577163953Srrs * same for the rcv ones, they are only here for the 578163953Srrs * accounting/select. 579163953Srrs */ 580167695Srrs SCTP_SB_CLEAR(so->so_rcv); 581167695Srrs 582167695Srrs /* Now null out the reference, we are completely detached. */ 583163953Srrs so->so_pcb = NULL; 584163953Srrs SOCK_UNLOCK(so); 585163953Srrs } else { 586163953Srrs flags = inp->sctp_flags; 587163953Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 588163953Srrs goto sctp_must_try_again; 589163953Srrs } 590163953Srrs } 591163953Srrs return; 592163953Srrs} 593163953Srrs 594163953Srrs 595163953Srrsint 596163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 597163953Srrs struct mbuf *control, struct thread *p); 598163953Srrs 599163953Srrs 600163953Srrsint 601163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 602163953Srrs struct mbuf *control, struct thread *p) 603163953Srrs{ 604163953Srrs struct sctp_inpcb *inp; 605163953Srrs int error; 606163953Srrs 607163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 608233005Stuexen if (inp == NULL) { 609163953Srrs if (control) { 610163953Srrs sctp_m_freem(control); 611163953Srrs control = NULL; 612163953Srrs } 613171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 614163953Srrs sctp_m_freem(m); 615228907Stuexen return (EINVAL); 616163953Srrs } 617163953Srrs /* Got to have an to address if we are NOT a connected socket */ 618163953Srrs if ((addr == NULL) && 619163953Srrs ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) || 620228907Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE))) { 621163953Srrs goto connected_type; 622163953Srrs } else if (addr == NULL) { 623171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); 624163953Srrs error = EDESTADDRREQ; 625163953Srrs sctp_m_freem(m); 626163953Srrs if (control) { 627163953Srrs sctp_m_freem(control); 628163953Srrs control = NULL; 629163953Srrs } 630163953Srrs return (error); 631163953Srrs } 632163953Srrs#ifdef INET6 633163953Srrs if (addr->sa_family != AF_INET) { 634163953Srrs /* must be a v4 address! */ 635171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); 636163953Srrs sctp_m_freem(m); 637163953Srrs if (control) { 638163953Srrs sctp_m_freem(control); 639163953Srrs control = NULL; 640163953Srrs } 641163953Srrs error = EDESTADDRREQ; 642223132Stuexen return (error); 643163953Srrs } 644163953Srrs#endif /* INET6 */ 645163953Srrsconnected_type: 646163953Srrs /* now what about control */ 647163953Srrs if (control) { 648163953Srrs if (inp->control) { 649169420Srrs SCTP_PRINTF("huh? control set?\n"); 650163953Srrs sctp_m_freem(inp->control); 651163953Srrs inp->control = NULL; 652163953Srrs } 653163953Srrs inp->control = control; 654163953Srrs } 655163953Srrs /* Place the data */ 656163953Srrs if (inp->pkt) { 657165647Srrs SCTP_BUF_NEXT(inp->pkt_last) = m; 658163953Srrs inp->pkt_last = m; 659163953Srrs } else { 660163953Srrs inp->pkt_last = inp->pkt = m; 661163953Srrs } 662163953Srrs if ( 663163953Srrs /* FreeBSD uses a flag passed */ 664163953Srrs ((flags & PRUS_MORETOCOME) == 0) 665163953Srrs ) { 666163953Srrs /* 667163953Srrs * note with the current version this code will only be used 668163953Srrs * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for 669163953Srrs * re-defining sosend to use the sctp_sosend. One can 670163953Srrs * optionally switch back to this code (by changing back the 671163953Srrs * definitions) but this is not advisable. This code is used 672163953Srrs * by FreeBSD when sending a file with sendfile() though. 673163953Srrs */ 674163953Srrs int ret; 675163953Srrs 676163953Srrs ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags); 677163953Srrs inp->pkt = NULL; 678163953Srrs inp->control = NULL; 679163953Srrs return (ret); 680163953Srrs } else { 681163953Srrs return (0); 682163953Srrs } 683163953Srrs} 684163953Srrs 685171990Srrsint 686163953Srrssctp_disconnect(struct socket *so) 687163953Srrs{ 688163953Srrs struct sctp_inpcb *inp; 689163953Srrs 690163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 691163953Srrs if (inp == NULL) { 692171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 693163953Srrs return (ENOTCONN); 694163953Srrs } 695163953Srrs SCTP_INP_RLOCK(inp); 696171745Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 697171745Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 698199437Stuexen if (LIST_EMPTY(&inp->sctp_asoc_list)) { 699163953Srrs /* No connection */ 700163953Srrs SCTP_INP_RUNLOCK(inp); 701163953Srrs return (0); 702163953Srrs } else { 703163953Srrs struct sctp_association *asoc; 704163953Srrs struct sctp_tcb *stcb; 705163953Srrs 706163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 707163953Srrs if (stcb == NULL) { 708163953Srrs SCTP_INP_RUNLOCK(inp); 709171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 710163953Srrs return (EINVAL); 711163953Srrs } 712163953Srrs SCTP_TCB_LOCK(stcb); 713163953Srrs asoc = &stcb->asoc; 714163953Srrs if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 715163953Srrs /* We are about to be freed, out of here */ 716163953Srrs SCTP_TCB_UNLOCK(stcb); 717163953Srrs SCTP_INP_RUNLOCK(inp); 718163953Srrs return (0); 719163953Srrs } 720163953Srrs if (((so->so_options & SO_LINGER) && 721163953Srrs (so->so_linger == 0)) || 722163953Srrs (so->so_rcv.sb_cc > 0)) { 723163953Srrs if (SCTP_GET_STATE(asoc) != 724163953Srrs SCTP_STATE_COOKIE_WAIT) { 725163953Srrs /* Left with Data unread */ 726163953Srrs struct mbuf *err; 727163953Srrs 728243882Sglebius err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA); 729163953Srrs if (err) { 730163953Srrs /* 731163953Srrs * Fill in the user 732163953Srrs * initiated abort 733163953Srrs */ 734163953Srrs struct sctp_paramhdr *ph; 735163953Srrs 736163953Srrs ph = mtod(err, struct sctp_paramhdr *); 737165647Srrs SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr); 738163953Srrs ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); 739165647Srrs ph->param_length = htons(SCTP_BUF_LEN(err)); 740163953Srrs } 741172090Srrs sctp_send_abort_tcb(stcb, err, SCTP_SO_LOCKED); 742163953Srrs SCTP_STAT_INCR_COUNTER32(sctps_aborted); 743163953Srrs } 744163953Srrs SCTP_INP_RUNLOCK(inp); 745163953Srrs if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 746163953Srrs (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 747163953Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 748163953Srrs } 749283822Stuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 750283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3); 751163953Srrs /* No unlock tcb assoc is gone */ 752163953Srrs return (0); 753163953Srrs } 754163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 755163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 756163953Srrs (asoc->stream_queue_cnt == 0)) { 757163953Srrs /* there is nothing queued to send, so done */ 758163953Srrs if (asoc->locked_on_sending) { 759163953Srrs goto abort_anyway; 760163953Srrs } 761166675Srrs if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) && 762166675Srrs (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { 763163953Srrs /* only send SHUTDOWN 1st time thru */ 764224641Stuexen struct sctp_nets *netp; 765224641Stuexen 766246588Stuexen if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 767246588Stuexen (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 768246588Stuexen SCTP_STAT_DECR_GAUGE32(sctps_currestab); 769246588Stuexen } 770246588Stuexen SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); 771246588Stuexen SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 772246588Stuexen sctp_stop_timers_for_shutdown(stcb); 773224641Stuexen if (stcb->asoc.alternate) { 774224641Stuexen netp = stcb->asoc.alternate; 775224641Stuexen } else { 776224641Stuexen netp = stcb->asoc.primary_destination; 777224641Stuexen } 778224641Stuexen sctp_send_shutdown(stcb, netp); 779163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 780224641Stuexen stcb->sctp_ep, stcb, netp); 781163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 782224641Stuexen stcb->sctp_ep, stcb, netp); 783246588Stuexen sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); 784163953Srrs } 785163953Srrs } else { 786163953Srrs /* 787163953Srrs * we still got (or just got) data to send, 788163953Srrs * so set SHUTDOWN_PENDING 789163953Srrs */ 790163953Srrs /* 791163953Srrs * XXX sockets draft says that SCTP_EOF 792163953Srrs * should be sent with no data. currently, 793163953Srrs * we will allow user data to be sent first 794163953Srrs * and move to SHUTDOWN-PENDING 795163953Srrs */ 796224641Stuexen struct sctp_nets *netp; 797224641Stuexen 798224641Stuexen if (stcb->asoc.alternate) { 799224641Stuexen netp = stcb->asoc.alternate; 800224641Stuexen } else { 801224641Stuexen netp = stcb->asoc.primary_destination; 802224641Stuexen } 803224641Stuexen 804163953Srrs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 805163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, 806224641Stuexen netp); 807163953Srrs if (asoc->locked_on_sending) { 808163953Srrs /* Locked to send out the data */ 809163953Srrs struct sctp_stream_queue_pending *sp; 810163953Srrs 811163953Srrs sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); 812163953Srrs if (sp == NULL) { 813169420Srrs SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", 814163953Srrs asoc->locked_on_sending->stream_no); 815163953Srrs } else { 816163953Srrs if ((sp->length == 0) && (sp->msg_is_complete == 0)) 817163953Srrs asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; 818163953Srrs } 819163953Srrs } 820163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 821163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 822163953Srrs (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 823163953Srrs struct mbuf *op_err; 824163953Srrs 825163953Srrs abort_anyway: 826267723Stuexen op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); 827165220Srrs stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4; 828172090Srrs sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED); 829163953Srrs SCTP_STAT_INCR_COUNTER32(sctps_aborted); 830163953Srrs if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 831163953Srrs (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 832163953Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 833163953Srrs } 834163953Srrs SCTP_INP_RUNLOCK(inp); 835283822Stuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 836283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5); 837163953Srrs return (0); 838171990Srrs } else { 839172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); 840163953Srrs } 841163953Srrs } 842188067Srrs soisdisconnecting(so); 843163953Srrs SCTP_TCB_UNLOCK(stcb); 844163953Srrs SCTP_INP_RUNLOCK(inp); 845163953Srrs return (0); 846163953Srrs } 847163953Srrs /* not reached */ 848163953Srrs } else { 849163953Srrs /* UDP model does not support this */ 850163953Srrs SCTP_INP_RUNLOCK(inp); 851171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 852228907Stuexen return (EOPNOTSUPP); 853163953Srrs } 854163953Srrs} 855163953Srrs 856163953Srrsint 857178202Srrssctp_flush(struct socket *so, int how) 858178202Srrs{ 859178202Srrs /* 860178202Srrs * We will just clear out the values and let subsequent close clear 861178202Srrs * out the data, if any. Note if the user did a shutdown(SHUT_RD) 862178202Srrs * they will not be able to read the data, the socket will block 863178202Srrs * that from happening. 864178202Srrs */ 865209289Stuexen struct sctp_inpcb *inp; 866209289Stuexen 867209289Stuexen inp = (struct sctp_inpcb *)so->so_pcb; 868209289Stuexen if (inp == NULL) { 869209289Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 870228907Stuexen return (EINVAL); 871209289Stuexen } 872209289Stuexen SCTP_INP_RLOCK(inp); 873209289Stuexen /* For the 1 to many model this does nothing */ 874209289Stuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 875209289Stuexen SCTP_INP_RUNLOCK(inp); 876209289Stuexen return (0); 877209289Stuexen } 878209289Stuexen SCTP_INP_RUNLOCK(inp); 879178202Srrs if ((how == PRU_FLUSH_RD) || (how == PRU_FLUSH_RDWR)) { 880178202Srrs /* 881178202Srrs * First make sure the sb will be happy, we don't use these 882178202Srrs * except maybe the count 883178202Srrs */ 884209289Stuexen SCTP_INP_WLOCK(inp); 885209289Stuexen SCTP_INP_READ_LOCK(inp); 886209289Stuexen inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ; 887209289Stuexen SCTP_INP_READ_UNLOCK(inp); 888209289Stuexen SCTP_INP_WUNLOCK(inp); 889178202Srrs so->so_rcv.sb_cc = 0; 890178202Srrs so->so_rcv.sb_mbcnt = 0; 891178202Srrs so->so_rcv.sb_mb = NULL; 892178202Srrs } 893178202Srrs if ((how == PRU_FLUSH_WR) || (how == PRU_FLUSH_RDWR)) { 894178202Srrs /* 895178202Srrs * First make sure the sb will be happy, we don't use these 896178202Srrs * except maybe the count 897178202Srrs */ 898178202Srrs so->so_snd.sb_cc = 0; 899178202Srrs so->so_snd.sb_mbcnt = 0; 900178202Srrs so->so_snd.sb_mb = NULL; 901178202Srrs 902178202Srrs } 903178202Srrs return (0); 904178202Srrs} 905178202Srrs 906178202Srrsint 907163953Srrssctp_shutdown(struct socket *so) 908163953Srrs{ 909163953Srrs struct sctp_inpcb *inp; 910163953Srrs 911163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 912233005Stuexen if (inp == NULL) { 913171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 914228907Stuexen return (EINVAL); 915163953Srrs } 916163953Srrs SCTP_INP_RLOCK(inp); 917163953Srrs /* For UDP model this is a invalid call */ 918243558Stuexen if (!((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 919243558Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { 920163953Srrs /* Restore the flags that the soshutdown took away. */ 921204096Stuexen SOCKBUF_LOCK(&so->so_rcv); 922163953Srrs so->so_rcv.sb_state &= ~SBS_CANTRCVMORE; 923204096Stuexen SOCKBUF_UNLOCK(&so->so_rcv); 924163953Srrs /* This proc will wakeup for read and do nothing (I hope) */ 925163953Srrs SCTP_INP_RUNLOCK(inp); 926171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 927163953Srrs return (EOPNOTSUPP); 928294182Stuexen } else { 929294182Stuexen /* 930294182Stuexen * Ok, if we reach here its the TCP model and it is either a 931294182Stuexen * SHUT_WR or SHUT_RDWR. This means we put the shutdown flag 932294182Stuexen * against it. 933294182Stuexen */ 934163953Srrs struct sctp_tcb *stcb; 935163953Srrs struct sctp_association *asoc; 936294182Stuexen struct sctp_nets *netp; 937163953Srrs 938188067Srrs if ((so->so_state & 939188067Srrs (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) { 940188067Srrs SCTP_INP_RUNLOCK(inp); 941188067Srrs return (ENOTCONN); 942188067Srrs } 943163953Srrs socantsendmore(so); 944163953Srrs 945163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 946163953Srrs if (stcb == NULL) { 947163953Srrs /* 948294182Stuexen * Ok, we hit the case that the shutdown call was 949163953Srrs * made after an abort or something. Nothing to do 950163953Srrs * now. 951163953Srrs */ 952168299Srrs SCTP_INP_RUNLOCK(inp); 953163953Srrs return (0); 954163953Srrs } 955163953Srrs SCTP_TCB_LOCK(stcb); 956163953Srrs asoc = &stcb->asoc; 957294182Stuexen if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) { 958294182Stuexen SCTP_TCB_UNLOCK(stcb); 959294182Stuexen SCTP_INP_RUNLOCK(inp); 960294182Stuexen return (0); 961294182Stuexen } 962294182Stuexen if ((SCTP_GET_STATE(asoc) != SCTP_STATE_COOKIE_WAIT) && 963294182Stuexen (SCTP_GET_STATE(asoc) != SCTP_STATE_COOKIE_ECHOED) && 964294182Stuexen (SCTP_GET_STATE(asoc) != SCTP_STATE_OPEN)) { 965294182Stuexen /* 966294182Stuexen * If we are not in or before ESTABLISHED, there is 967294182Stuexen * no protocol action required. 968294182Stuexen */ 969294182Stuexen SCTP_TCB_UNLOCK(stcb); 970294182Stuexen SCTP_INP_RUNLOCK(inp); 971294182Stuexen return (0); 972294182Stuexen } 973294182Stuexen if (stcb->asoc.alternate) { 974294182Stuexen netp = stcb->asoc.alternate; 975294182Stuexen } else { 976294182Stuexen netp = stcb->asoc.primary_destination; 977294182Stuexen } 978294184Stuexen if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) && 979294184Stuexen TAILQ_EMPTY(&asoc->send_queue) && 980163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 981163953Srrs (asoc->stream_queue_cnt == 0)) { 982163953Srrs if (asoc->locked_on_sending) { 983163953Srrs goto abort_anyway; 984163953Srrs } 985163953Srrs /* there is nothing queued to send, so I'm done... */ 986294184Stuexen SCTP_STAT_DECR_GAUGE32(sctps_currestab); 987294182Stuexen SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); 988294182Stuexen SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 989294182Stuexen sctp_stop_timers_for_shutdown(stcb); 990294182Stuexen sctp_send_shutdown(stcb, netp); 991294182Stuexen sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 992294182Stuexen stcb->sctp_ep, stcb, netp); 993163953Srrs } else { 994163953Srrs /* 995294182Stuexen * We still got (or just got) data to send, so set 996294182Stuexen * SHUTDOWN_PENDING. 997163953Srrs */ 998294182Stuexen SCTP_ADD_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 999163953Srrs if (asoc->locked_on_sending) { 1000163953Srrs /* Locked to send out the data */ 1001163953Srrs struct sctp_stream_queue_pending *sp; 1002163953Srrs 1003163953Srrs sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); 1004163953Srrs if (sp == NULL) { 1005169420Srrs SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", 1006163953Srrs asoc->locked_on_sending->stream_no); 1007163953Srrs } else { 1008163953Srrs if ((sp->length == 0) && (sp->msg_is_complete == 0)) { 1009294182Stuexen SCTP_ADD_SUBSTATE(asoc, SCTP_STATE_PARTIAL_MSG_LEFT); 1010163953Srrs } 1011163953Srrs } 1012163953Srrs } 1013163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 1014163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 1015163953Srrs (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 1016163953Srrs struct mbuf *op_err; 1017163953Srrs 1018163953Srrs abort_anyway: 1019267723Stuexen op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); 1020165220Srrs stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6; 1021163953Srrs sctp_abort_an_association(stcb->sctp_ep, stcb, 1022172090Srrs op_err, SCTP_SO_LOCKED); 1023294182Stuexen SCTP_INP_RUNLOCK(inp); 1024294182Stuexen return (0); 1025163953Srrs } 1026163953Srrs } 1027294182Stuexen sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, netp); 1028294182Stuexen /* 1029294182Stuexen * XXX: Why do this in the case where we have still data 1030294182Stuexen * queued? 1031294182Stuexen */ 1032294182Stuexen sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); 1033163953Srrs SCTP_TCB_UNLOCK(stcb); 1034294182Stuexen SCTP_INP_RUNLOCK(inp); 1035294182Stuexen return (0); 1036163953Srrs } 1037163953Srrs} 1038163953Srrs 1039163953Srrs/* 1040163953Srrs * copies a "user" presentable address and removes embedded scope, etc. 1041163953Srrs * returns 0 on success, 1 on error 1042163953Srrs */ 1043163953Srrsstatic uint32_t 1044163953Srrssctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa) 1045163953Srrs{ 1046178251Srrs#ifdef INET6 1047163953Srrs struct sockaddr_in6 lsa6; 1048163953Srrs 1049163953Srrs sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa, 1050163953Srrs &lsa6); 1051178251Srrs#endif 1052163953Srrs memcpy(ss, sa, sa->sa_len); 1053163953Srrs return (0); 1054163953Srrs} 1055163953Srrs 1056163953Srrs 1057163953Srrs 1058172091Srrs/* 1059172091Srrs * NOTE: assumes addr lock is held 1060172091Srrs */ 1061166675Srrsstatic size_t 1062168124Srrssctp_fill_up_addresses_vrf(struct sctp_inpcb *inp, 1063163953Srrs struct sctp_tcb *stcb, 1064166675Srrs size_t limit, 1065167598Srrs struct sockaddr_storage *sas, 1066167598Srrs uint32_t vrf_id) 1067163953Srrs{ 1068167598Srrs struct sctp_ifn *sctp_ifn; 1069167598Srrs struct sctp_ifa *sctp_ifa; 1070166675Srrs size_t actual; 1071258454Stuexen int loopback_scope; 1072258454Stuexen 1073258454Stuexen#if defined(INET) 1074258454Stuexen int ipv4_local_scope, ipv4_addr_legal; 1075258454Stuexen 1076258454Stuexen#endif 1077258454Stuexen#if defined(INET6) 1078258454Stuexen int local_scope, site_scope, ipv6_addr_legal; 1079258454Stuexen 1080258454Stuexen#endif 1081167598Srrs struct sctp_vrf *vrf; 1082163953Srrs 1083163953Srrs actual = 0; 1084163953Srrs if (limit <= 0) 1085163953Srrs return (actual); 1086163953Srrs 1087163953Srrs if (stcb) { 1088163953Srrs /* Turn on all the appropriate scope */ 1089246595Stuexen loopback_scope = stcb->asoc.scope.loopback_scope; 1090258454Stuexen#if defined(INET) 1091246595Stuexen ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope; 1092258454Stuexen ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal; 1093258454Stuexen#endif 1094258454Stuexen#if defined(INET6) 1095246595Stuexen local_scope = stcb->asoc.scope.local_scope; 1096246595Stuexen site_scope = stcb->asoc.scope.site_scope; 1097246595Stuexen ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal; 1098258454Stuexen#endif 1099163953Srrs } else { 1100246595Stuexen /* Use generic values for endpoints. */ 1101246595Stuexen loopback_scope = 1; 1102258454Stuexen#if defined(INET) 1103246595Stuexen ipv4_local_scope = 1; 1104258454Stuexen#endif 1105258454Stuexen#if defined(INET6) 1106246595Stuexen local_scope = 1; 1107246595Stuexen site_scope = 1; 1108258454Stuexen#endif 1109246595Stuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 1110258454Stuexen#if defined(INET6) 1111246595Stuexen ipv6_addr_legal = 1; 1112258454Stuexen#endif 1113258454Stuexen#if defined(INET) 1114246595Stuexen if (SCTP_IPV6_V6ONLY(inp)) { 1115246595Stuexen ipv4_addr_legal = 0; 1116246595Stuexen } else { 1117246595Stuexen ipv4_addr_legal = 1; 1118246595Stuexen } 1119258454Stuexen#endif 1120246595Stuexen } else { 1121258454Stuexen#if defined(INET6) 1122246595Stuexen ipv6_addr_legal = 0; 1123258454Stuexen#endif 1124258454Stuexen#if defined(INET) 1125163953Srrs ipv4_addr_legal = 1; 1126258454Stuexen#endif 1127163953Srrs } 1128163953Srrs } 1129167598Srrs vrf = sctp_find_vrf(vrf_id); 1130167598Srrs if (vrf == NULL) { 1131167598Srrs return (0); 1132167598Srrs } 1133163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1134167598Srrs LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 1135163953Srrs if ((loopback_scope == 0) && 1136167598Srrs SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { 1137163953Srrs /* Skip loopback if loopback_scope not set */ 1138163953Srrs continue; 1139163953Srrs } 1140167598Srrs LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 1141163953Srrs if (stcb) { 1142163953Srrs /* 1143163953Srrs * For the BOUND-ALL case, the list 1144163953Srrs * associated with a TCB is Always 1145163953Srrs * considered a reverse list.. i.e. 1146163953Srrs * it lists addresses that are NOT 1147163953Srrs * part of the association. If this 1148163953Srrs * is one of those we must skip it. 1149163953Srrs */ 1150163953Srrs if (sctp_is_addr_restricted(stcb, 1151167598Srrs sctp_ifa)) { 1152163953Srrs continue; 1153163953Srrs } 1154163953Srrs } 1155178251Srrs switch (sctp_ifa->address.sa.sa_family) { 1156221249Stuexen#ifdef INET 1157178251Srrs case AF_INET: 1158178251Srrs if (ipv4_addr_legal) { 1159178251Srrs struct sockaddr_in *sin; 1160163953Srrs 1161271746Stuexen sin = &sctp_ifa->address.sin; 1162178251Srrs if (sin->sin_addr.s_addr == 0) { 1163178251Srrs /* 1164178251Srrs * we skip 1165178251Srrs * unspecifed 1166178251Srrs * addresses 1167178251Srrs */ 1168178251Srrs continue; 1169178251Srrs } 1170267769Stuexen if (prison_check_ip4(inp->ip_inp.inp.inp_cred, 1171267769Stuexen &sin->sin_addr) != 0) { 1172267769Stuexen continue; 1173267769Stuexen } 1174178251Srrs if ((ipv4_local_scope == 0) && 1175178251Srrs (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { 1176178251Srrs continue; 1177178251Srrs } 1178178251Srrs#ifdef INET6 1179178251Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 1180178251Srrs in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas); 1181178251Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1182178251Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6)); 1183178251Srrs actual += sizeof(struct sockaddr_in6); 1184178251Srrs } else { 1185178251Srrs#endif 1186178251Srrs memcpy(sas, sin, sizeof(*sin)); 1187178251Srrs ((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport; 1188178251Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin)); 1189178251Srrs actual += sizeof(*sin); 1190178251Srrs#ifdef INET6 1191178251Srrs } 1192178251Srrs#endif 1193178251Srrs if (actual >= limit) { 1194178251Srrs return (actual); 1195178251Srrs } 1196178251Srrs } else { 1197163953Srrs continue; 1198163953Srrs } 1199178251Srrs break; 1200221249Stuexen#endif 1201178251Srrs#ifdef INET6 1202178251Srrs case AF_INET6: 1203178251Srrs if (ipv6_addr_legal) { 1204178251Srrs struct sockaddr_in6 *sin6; 1205163953Srrs 1206271746Stuexen sin6 = &sctp_ifa->address.sin6; 1207178251Srrs if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 1208178251Srrs /* 1209178251Srrs * we skip 1210178251Srrs * unspecifed 1211178251Srrs * addresses 1212178251Srrs */ 1213163953Srrs continue; 1214178251Srrs } 1215267769Stuexen if (prison_check_ip6(inp->ip_inp.inp.inp_cred, 1216267769Stuexen &sin6->sin6_addr) != 0) { 1217267769Stuexen continue; 1218267769Stuexen } 1219178251Srrs if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 1220178251Srrs if (local_scope == 0) 1221163953Srrs continue; 1222178251Srrs if (sin6->sin6_scope_id == 0) { 1223178251Srrs if (sa6_recoverscope(sin6) != 0) 1224178251Srrs /* 1225178251Srrs * 1226178251Srrs * bad 1227178251Srrs * 1228178251Srrs * li 1229178251Srrs * nk 1230178251Srrs * 1231178251Srrs * loc 1232178251Srrs * al 1233178251Srrs * 1234178251Srrs * add 1235178251Srrs * re 1236178251Srrs * ss 1237178251Srrs * */ 1238178251Srrs continue; 1239178251Srrs } 1240163953Srrs } 1241178251Srrs if ((site_scope == 0) && 1242178251Srrs (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { 1243178251Srrs continue; 1244178251Srrs } 1245178251Srrs memcpy(sas, sin6, sizeof(*sin6)); 1246178251Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1247178251Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6)); 1248178251Srrs actual += sizeof(*sin6); 1249178251Srrs if (actual >= limit) { 1250178251Srrs return (actual); 1251178251Srrs } 1252178251Srrs } else { 1253163953Srrs continue; 1254163953Srrs } 1255178251Srrs break; 1256178251Srrs#endif 1257178251Srrs default: 1258178251Srrs /* TSNH */ 1259178251Srrs break; 1260163953Srrs } 1261163953Srrs } 1262163953Srrs } 1263163953Srrs } else { 1264163953Srrs struct sctp_laddr *laddr; 1265163953Srrs 1266167598Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1267167598Srrs if (stcb) { 1268167598Srrs if (sctp_is_addr_restricted(stcb, laddr->ifa)) { 1269163953Srrs continue; 1270163953Srrs } 1271163953Srrs } 1272167598Srrs if (sctp_fill_user_address(sas, &laddr->ifa->address.sa)) 1273167598Srrs continue; 1274246595Stuexen switch (laddr->ifa->address.sa.sa_family) { 1275246595Stuexen#ifdef INET 1276246595Stuexen case AF_INET: 1277246595Stuexen ((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport; 1278246595Stuexen break; 1279246595Stuexen#endif 1280246595Stuexen#ifdef INET6 1281246595Stuexen case AF_INET6: 1282246595Stuexen ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1283246595Stuexen break; 1284246595Stuexen#endif 1285246595Stuexen default: 1286246595Stuexen /* TSNH */ 1287246595Stuexen break; 1288246595Stuexen } 1289167598Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + 1290167598Srrs laddr->ifa->address.sa.sa_len); 1291167598Srrs actual += laddr->ifa->address.sa.sa_len; 1292167598Srrs if (actual >= limit) { 1293167598Srrs return (actual); 1294163953Srrs } 1295163953Srrs } 1296163953Srrs } 1297163953Srrs return (actual); 1298163953Srrs} 1299163953Srrs 1300168124Srrsstatic size_t 1301168124Srrssctp_fill_up_addresses(struct sctp_inpcb *inp, 1302168124Srrs struct sctp_tcb *stcb, 1303168124Srrs size_t limit, 1304168124Srrs struct sockaddr_storage *sas) 1305168124Srrs{ 1306168124Srrs size_t size = 0; 1307168124Srrs 1308172218Srrs SCTP_IPI_ADDR_RLOCK(); 1309168124Srrs /* fill up addresses for the endpoint's default vrf */ 1310168124Srrs size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas, 1311168124Srrs inp->def_vrf_id); 1312172218Srrs SCTP_IPI_ADDR_RUNLOCK(); 1313168124Srrs return (size); 1314168124Srrs} 1315168124Srrs 1316172091Srrs/* 1317172091Srrs * NOTE: assumes addr lock is held 1318172091Srrs */ 1319163953Srrsstatic int 1320168124Srrssctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) 1321163953Srrs{ 1322163953Srrs int cnt = 0; 1323167598Srrs struct sctp_vrf *vrf = NULL; 1324163953Srrs 1325163953Srrs /* 1326163953Srrs * In both sub-set bound an bound_all cases we return the MAXIMUM 1327163953Srrs * number of addresses that you COULD get. In reality the sub-set 1328163953Srrs * bound may have an exclusion list for a given TCB OR in the 1329163953Srrs * bound-all case a TCB may NOT include the loopback or other 1330163953Srrs * addresses as well. 1331163953Srrs */ 1332167598Srrs vrf = sctp_find_vrf(vrf_id); 1333167598Srrs if (vrf == NULL) { 1334167598Srrs return (0); 1335167598Srrs } 1336163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1337167598Srrs struct sctp_ifn *sctp_ifn; 1338167598Srrs struct sctp_ifa *sctp_ifa; 1339163953Srrs 1340167598Srrs LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 1341167598Srrs LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 1342163953Srrs /* Count them if they are the right type */ 1343221249Stuexen switch (sctp_ifa->address.sa.sa_family) { 1344221249Stuexen#ifdef INET 1345221249Stuexen case AF_INET: 1346283699Stuexen#ifdef INET6 1347178251Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) 1348163953Srrs cnt += sizeof(struct sockaddr_in6); 1349163953Srrs else 1350163953Srrs cnt += sizeof(struct sockaddr_in); 1351283699Stuexen#else 1352283699Stuexen cnt += sizeof(struct sockaddr_in); 1353283699Stuexen#endif 1354221249Stuexen break; 1355221249Stuexen#endif 1356221249Stuexen#ifdef INET6 1357221249Stuexen case AF_INET6: 1358163953Srrs cnt += sizeof(struct sockaddr_in6); 1359221249Stuexen break; 1360221249Stuexen#endif 1361221249Stuexen default: 1362221249Stuexen break; 1363221249Stuexen } 1364163953Srrs } 1365163953Srrs } 1366163953Srrs } else { 1367163953Srrs struct sctp_laddr *laddr; 1368163953Srrs 1369163953Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1370221249Stuexen switch (laddr->ifa->address.sa.sa_family) { 1371221249Stuexen#ifdef INET 1372221249Stuexen case AF_INET: 1373283699Stuexen#ifdef INET6 1374178251Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) 1375163953Srrs cnt += sizeof(struct sockaddr_in6); 1376163953Srrs else 1377163953Srrs cnt += sizeof(struct sockaddr_in); 1378283699Stuexen#else 1379283699Stuexen cnt += sizeof(struct sockaddr_in); 1380283699Stuexen#endif 1381221249Stuexen break; 1382221249Stuexen#endif 1383221249Stuexen#ifdef INET6 1384221249Stuexen case AF_INET6: 1385163953Srrs cnt += sizeof(struct sockaddr_in6); 1386221249Stuexen break; 1387221249Stuexen#endif 1388221249Stuexen default: 1389221249Stuexen break; 1390221249Stuexen } 1391163953Srrs } 1392163953Srrs } 1393163953Srrs return (cnt); 1394163953Srrs} 1395163953Srrs 1396168124Srrsstatic int 1397168124Srrssctp_count_max_addresses(struct sctp_inpcb *inp) 1398168124Srrs{ 1399168124Srrs int cnt = 0; 1400166675Srrs 1401172218Srrs SCTP_IPI_ADDR_RLOCK(); 1402168124Srrs /* count addresses for the endpoint's default VRF */ 1403168124Srrs cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id); 1404172218Srrs SCTP_IPI_ADDR_RUNLOCK(); 1405168124Srrs return (cnt); 1406168124Srrs} 1407168124Srrs 1408163953Srrsstatic int 1409166675Srrssctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, 1410166675Srrs size_t optsize, void *p, int delay) 1411163953Srrs{ 1412163953Srrs int error = 0; 1413163953Srrs int creat_lock_on = 0; 1414163953Srrs struct sctp_tcb *stcb = NULL; 1415163953Srrs struct sockaddr *sa; 1416169352Srrs int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr; 1417167598Srrs uint32_t vrf_id; 1418170056Srrs int bad_addresses = 0; 1419167598Srrs sctp_assoc_t *a_id; 1420163953Srrs 1421169420Srrs SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n"); 1422163953Srrs 1423163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 1424163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 1425163953Srrs /* We are already connected AND the TCP model */ 1426171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 1427163953Srrs return (EADDRINUSE); 1428163953Srrs } 1429181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && 1430181054Srrs (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) { 1431171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1432163953Srrs return (EINVAL); 1433163953Srrs } 1434163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 1435163953Srrs SCTP_INP_RLOCK(inp); 1436163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 1437163953Srrs SCTP_INP_RUNLOCK(inp); 1438163953Srrs } 1439163953Srrs if (stcb) { 1440171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 1441163953Srrs return (EALREADY); 1442163953Srrs } 1443163953Srrs SCTP_INP_INCR_REF(inp); 1444163953Srrs SCTP_ASOC_CREATE_LOCK(inp); 1445163953Srrs creat_lock_on = 1; 1446163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 1447163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 1448171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); 1449163953Srrs error = EFAULT; 1450163953Srrs goto out_now; 1451163953Srrs } 1452166675Srrs totaddrp = (int *)optval; 1453163953Srrs totaddr = *totaddrp; 1454163953Srrs sa = (struct sockaddr *)(totaddrp + 1); 1455170056Srrs stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses); 1456170056Srrs if ((stcb != NULL) || bad_addresses) { 1457169352Srrs /* Already have or am bring up an association */ 1458169352Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1459169352Srrs creat_lock_on = 0; 1460170931Srrs if (stcb) 1461170931Srrs SCTP_TCB_UNLOCK(stcb); 1462171943Srrs if (bad_addresses == 0) { 1463171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 1464170056Srrs error = EALREADY; 1465171943Srrs } 1466169352Srrs goto out_now; 1467163953Srrs } 1468163953Srrs#ifdef INET6 1469163953Srrs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 1470163953Srrs (num_v6 > 0)) { 1471163953Srrs error = EINVAL; 1472163953Srrs goto out_now; 1473163953Srrs } 1474163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 1475163953Srrs (num_v4 > 0)) { 1476163953Srrs struct in6pcb *inp6; 1477163953Srrs 1478163953Srrs inp6 = (struct in6pcb *)inp; 1479166023Srrs if (SCTP_IPV6_V6ONLY(inp6)) { 1480163953Srrs /* 1481163953Srrs * if IPV6_V6ONLY flag, ignore connections destined 1482163953Srrs * to a v4 addr or v4-mapped addr 1483163953Srrs */ 1484171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1485163953Srrs error = EINVAL; 1486163953Srrs goto out_now; 1487163953Srrs } 1488163953Srrs } 1489163953Srrs#endif /* INET6 */ 1490163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 1491163953Srrs SCTP_PCB_FLAGS_UNBOUND) { 1492163953Srrs /* Bind a ephemeral port */ 1493171572Srrs error = sctp_inpcb_bind(so, NULL, NULL, p); 1494163953Srrs if (error) { 1495163953Srrs goto out_now; 1496163953Srrs } 1497163953Srrs } 1498167695Srrs /* FIX ME: do we want to pass in a vrf on the connect call? */ 1499167695Srrs vrf_id = inp->def_vrf_id; 1500167695Srrs 1501181054Srrs 1502163953Srrs /* We are GOOD to go */ 1503206137Stuexen stcb = sctp_aloc_assoc(inp, sa, &error, 0, vrf_id, 1504294215Stuexen inp->sctp_ep.pre_open_stream_count, 1505171531Srrs (struct thread *)p 1506171531Srrs ); 1507163953Srrs if (stcb == NULL) { 1508163953Srrs /* Gak! no memory */ 1509163953Srrs goto out_now; 1510163953Srrs } 1511225559Stuexen if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 1512225559Stuexen stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 1513225559Stuexen /* Set the connected flag so we can queue data */ 1514225559Stuexen soisconnecting(so); 1515225559Stuexen } 1516171943Srrs SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); 1517163953Srrs /* move to second address */ 1518221249Stuexen switch (sa->sa_family) { 1519221249Stuexen#ifdef INET 1520221249Stuexen case AF_INET: 1521163953Srrs sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in)); 1522221249Stuexen break; 1523221249Stuexen#endif 1524221249Stuexen#ifdef INET6 1525221249Stuexen case AF_INET6: 1526163953Srrs sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6)); 1527221249Stuexen break; 1528221249Stuexen#endif 1529221249Stuexen default: 1530221249Stuexen break; 1531221249Stuexen } 1532163953Srrs 1533170056Srrs error = 0; 1534223132Stuexen sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error); 1535167598Srrs /* Fill in the return id */ 1536170056Srrs if (error) { 1537283822Stuexen (void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, 1538283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); 1539170056Srrs goto out_now; 1540170056Srrs } 1541167598Srrs a_id = (sctp_assoc_t *) optval; 1542167598Srrs *a_id = sctp_get_associd(stcb); 1543163953Srrs 1544163953Srrs /* initialize authentication parameters for the assoc */ 1545163953Srrs sctp_initialize_auth_params(inp, stcb); 1546163953Srrs 1547163953Srrs if (delay) { 1548163953Srrs /* doing delayed connection */ 1549163953Srrs stcb->asoc.delayed_connection = 1; 1550163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination); 1551163953Srrs } else { 1552169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 1553172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 1554163953Srrs } 1555163953Srrs SCTP_TCB_UNLOCK(stcb); 1556163953Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 1557163953Srrs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 1558163953Srrs /* Set the connected flag so we can queue data */ 1559163953Srrs soisconnecting(so); 1560163953Srrs } 1561163953Srrsout_now: 1562169655Srrs if (creat_lock_on) { 1563163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1564169655Srrs } 1565163953Srrs SCTP_INP_DECR_REF(inp); 1566228907Stuexen return (error); 1567163953Srrs} 1568163953Srrs 1569169420Srrs#define SCTP_FIND_STCB(inp, stcb, assoc_id) { \ 1570169655Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||\ 1571169655Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { \ 1572166675Srrs SCTP_INP_RLOCK(inp); \ 1573166675Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); \ 1574169655Srrs if (stcb) { \ 1575166675Srrs SCTP_TCB_LOCK(stcb); \ 1576169655Srrs } \ 1577166675Srrs SCTP_INP_RUNLOCK(inp); \ 1578223132Stuexen } else if (assoc_id > SCTP_ALL_ASSOC) { \ 1579166675Srrs stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \ 1580166675Srrs if (stcb == NULL) { \ 1581171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \ 1582166675Srrs error = ENOENT; \ 1583166675Srrs break; \ 1584166675Srrs } \ 1585166675Srrs } else { \ 1586166675Srrs stcb = NULL; \ 1587169420Srrs } \ 1588169420Srrs } 1589163953Srrs 1590169420Srrs 1591234464Stuexen#define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\ 1592166675Srrs if (size < sizeof(type)) { \ 1593171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); \ 1594166675Srrs error = EINVAL; \ 1595166675Srrs break; \ 1596166675Srrs } else { \ 1597166675Srrs destp = (type *)srcp; \ 1598169420Srrs } \ 1599169420Srrs } 1600163953Srrs 1601163953Srrsstatic int 1602166675Srrssctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, 1603166675Srrs void *p) 1604163953Srrs{ 1605171943Srrs struct sctp_inpcb *inp = NULL; 1606166675Srrs int error, val = 0; 1607163953Srrs struct sctp_tcb *stcb = NULL; 1608163953Srrs 1609166675Srrs if (optval == NULL) { 1610171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1611166675Srrs return (EINVAL); 1612166675Srrs } 1613163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 1614233005Stuexen if (inp == NULL) { 1615171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1616163953Srrs return EINVAL; 1617171943Srrs } 1618163953Srrs error = 0; 1619163953Srrs 1620166675Srrs switch (optname) { 1621163953Srrs case SCTP_NODELAY: 1622163953Srrs case SCTP_AUTOCLOSE: 1623163953Srrs case SCTP_EXPLICIT_EOR: 1624163953Srrs case SCTP_AUTO_ASCONF: 1625163953Srrs case SCTP_DISABLE_FRAGMENTS: 1626163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 1627163953Srrs case SCTP_USE_EXT_RCVINFO: 1628163953Srrs SCTP_INP_RLOCK(inp); 1629166675Srrs switch (optname) { 1630163953Srrs case SCTP_DISABLE_FRAGMENTS: 1631166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT); 1632163953Srrs break; 1633163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 1634166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4); 1635163953Srrs break; 1636163953Srrs case SCTP_AUTO_ASCONF: 1637171943Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1638171943Srrs /* only valid for bound all sockets */ 1639171943Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); 1640171943Srrs } else { 1641171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1642171943Srrs error = EINVAL; 1643171943Srrs goto flags_out; 1644171943Srrs } 1645163953Srrs break; 1646163953Srrs case SCTP_EXPLICIT_EOR: 1647166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); 1648163953Srrs break; 1649163953Srrs case SCTP_NODELAY: 1650166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY); 1651163953Srrs break; 1652163953Srrs case SCTP_USE_EXT_RCVINFO: 1653166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO); 1654163953Srrs break; 1655163953Srrs case SCTP_AUTOCLOSE: 1656163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) 1657166675Srrs val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time); 1658163953Srrs else 1659166675Srrs val = 0; 1660163953Srrs break; 1661163953Srrs 1662163953Srrs default: 1663171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 1664163953Srrs error = ENOPROTOOPT; 1665163953Srrs } /* end switch (sopt->sopt_name) */ 1666166675Srrs if (*optsize < sizeof(val)) { 1667171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1668163953Srrs error = EINVAL; 1669163953Srrs } 1670171943Srrsflags_out: 1671163953Srrs SCTP_INP_RUNLOCK(inp); 1672163953Srrs if (error == 0) { 1673163953Srrs /* return the option value */ 1674166675Srrs *(int *)optval = val; 1675166675Srrs *optsize = sizeof(val); 1676163953Srrs } 1677163953Srrs break; 1678170091Srrs case SCTP_GET_PACKET_LOG: 1679170091Srrs { 1680170091Srrs#ifdef SCTP_PACKET_LOGGING 1681170091Srrs uint8_t *target; 1682170091Srrs int ret; 1683167598Srrs 1684170091Srrs SCTP_CHECK_AND_CAST(target, optval, uint8_t, *optsize); 1685170091Srrs ret = sctp_copy_out_packet_log(target, (int)*optsize); 1686170091Srrs *optsize = ret; 1687170091Srrs#else 1688171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 1689170091Srrs error = EOPNOTSUPP; 1690170091Srrs#endif 1691170091Srrs break; 1692170091Srrs } 1693181054Srrs case SCTP_REUSE_PORT: 1694181054Srrs { 1695181054Srrs uint32_t *value; 1696181054Srrs 1697181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) { 1698181054Srrs /* Can't do this for a 1-m socket */ 1699181054Srrs error = EINVAL; 1700181054Srrs break; 1701181054Srrs } 1702181054Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1703181054Srrs *value = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE); 1704181054Srrs *optsize = sizeof(uint32_t); 1705223132Stuexen break; 1706181054Srrs } 1707163953Srrs case SCTP_PARTIAL_DELIVERY_POINT: 1708163953Srrs { 1709166675Srrs uint32_t *value; 1710166675Srrs 1711166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1712166675Srrs *value = inp->partial_delivery_point; 1713166675Srrs *optsize = sizeof(uint32_t); 1714223132Stuexen break; 1715163953Srrs } 1716163953Srrs case SCTP_FRAGMENT_INTERLEAVE: 1717163953Srrs { 1718166675Srrs uint32_t *value; 1719166675Srrs 1720166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1721168943Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) { 1722168943Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) { 1723168943Srrs *value = SCTP_FRAG_LEVEL_2; 1724168943Srrs } else { 1725168943Srrs *value = SCTP_FRAG_LEVEL_1; 1726168943Srrs } 1727168943Srrs } else { 1728168943Srrs *value = SCTP_FRAG_LEVEL_0; 1729168943Srrs } 1730166675Srrs *optsize = sizeof(uint32_t); 1731223132Stuexen break; 1732163953Srrs } 1733163953Srrs case SCTP_CMT_ON_OFF: 1734163953Srrs { 1735166675Srrs struct sctp_assoc_value *av; 1736166675Srrs 1737166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1738211944Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1739211944Stuexen if (stcb) { 1740211944Stuexen av->assoc_value = stcb->asoc.sctp_cmt_on_off; 1741211944Stuexen SCTP_TCB_UNLOCK(stcb); 1742166675Srrs } else { 1743224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1744224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1745224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1746223132Stuexen SCTP_INP_RLOCK(inp); 1747223132Stuexen av->assoc_value = inp->sctp_cmt_on_off; 1748223132Stuexen SCTP_INP_RUNLOCK(inp); 1749223132Stuexen } else { 1750223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1751223132Stuexen error = EINVAL; 1752223132Stuexen } 1753163953Srrs } 1754223132Stuexen if (error == 0) { 1755223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1756223132Stuexen } 1757223132Stuexen break; 1758163953Srrs } 1759171440Srrs case SCTP_PLUGGABLE_CC: 1760171440Srrs { 1761171440Srrs struct sctp_assoc_value *av; 1762171440Srrs 1763171440Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1764171440Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1765171440Srrs if (stcb) { 1766171440Srrs av->assoc_value = stcb->asoc.congestion_control_module; 1767171440Srrs SCTP_TCB_UNLOCK(stcb); 1768171440Srrs } else { 1769224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1770224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1771224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1772223132Stuexen SCTP_INP_RLOCK(inp); 1773223132Stuexen av->assoc_value = inp->sctp_ep.sctp_default_cc_module; 1774223132Stuexen SCTP_INP_RUNLOCK(inp); 1775223132Stuexen } else { 1776223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1777223132Stuexen error = EINVAL; 1778223132Stuexen } 1779171440Srrs } 1780223132Stuexen if (error == 0) { 1781223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1782223132Stuexen } 1783223132Stuexen break; 1784171440Srrs } 1785219057Srrs case SCTP_CC_OPTION: 1786219057Srrs { 1787219057Srrs struct sctp_cc_option *cc_opt; 1788219057Srrs 1789219057Srrs SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, *optsize); 1790219057Srrs SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id); 1791219057Srrs if (stcb == NULL) { 1792219057Srrs error = EINVAL; 1793219057Srrs } else { 1794219057Srrs if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) { 1795219057Srrs error = ENOTSUP; 1796219057Srrs } else { 1797223132Stuexen error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 0, cc_opt); 1798223132Stuexen *optsize = sizeof(struct sctp_cc_option); 1799219057Srrs } 1800219057Srrs SCTP_TCB_UNLOCK(stcb); 1801219057Srrs } 1802223132Stuexen break; 1803219057Srrs } 1804217760Stuexen case SCTP_PLUGGABLE_SS: 1805217760Stuexen { 1806217760Stuexen struct sctp_assoc_value *av; 1807217760Stuexen 1808217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1809217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1810217760Stuexen if (stcb) { 1811217760Stuexen av->assoc_value = stcb->asoc.stream_scheduling_module; 1812217760Stuexen SCTP_TCB_UNLOCK(stcb); 1813217760Stuexen } else { 1814224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1815224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1816224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1817223132Stuexen SCTP_INP_RLOCK(inp); 1818223132Stuexen av->assoc_value = inp->sctp_ep.sctp_default_ss_module; 1819223132Stuexen SCTP_INP_RUNLOCK(inp); 1820223132Stuexen } else { 1821223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1822223132Stuexen error = EINVAL; 1823223132Stuexen } 1824217760Stuexen } 1825223132Stuexen if (error == 0) { 1826223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1827223132Stuexen } 1828223132Stuexen break; 1829217760Stuexen } 1830217760Stuexen case SCTP_SS_VALUE: 1831217760Stuexen { 1832217760Stuexen struct sctp_stream_value *av; 1833217760Stuexen 1834217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize); 1835217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1836217760Stuexen if (stcb) { 1837277807Sdelphij if ((av->stream_id >= stcb->asoc.streamoutcnt) || 1838277807Sdelphij (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], 1839277807Sdelphij &av->stream_value) < 0)) { 1840217760Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1841217760Stuexen error = EINVAL; 1842217760Stuexen } else { 1843223132Stuexen *optsize = sizeof(struct sctp_stream_value); 1844217760Stuexen } 1845217760Stuexen SCTP_TCB_UNLOCK(stcb); 1846217760Stuexen } else { 1847217760Stuexen /* 1848217760Stuexen * Can't get stream value without 1849217760Stuexen * association 1850217760Stuexen */ 1851217760Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1852217760Stuexen error = EINVAL; 1853217760Stuexen } 1854223132Stuexen break; 1855217760Stuexen } 1856163953Srrs case SCTP_GET_ADDR_LEN: 1857163953Srrs { 1858163953Srrs struct sctp_assoc_value *av; 1859163953Srrs 1860166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1861163953Srrs error = EINVAL; 1862167598Srrs#ifdef INET 1863163953Srrs if (av->assoc_value == AF_INET) { 1864163953Srrs av->assoc_value = sizeof(struct sockaddr_in); 1865163953Srrs error = 0; 1866163953Srrs } 1867163953Srrs#endif 1868167598Srrs#ifdef INET6 1869163953Srrs if (av->assoc_value == AF_INET6) { 1870163953Srrs av->assoc_value = sizeof(struct sockaddr_in6); 1871163953Srrs error = 0; 1872163953Srrs } 1873163953Srrs#endif 1874172091Srrs if (error) { 1875171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1876223132Stuexen } else { 1877223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1878172091Srrs } 1879223132Stuexen break; 1880163953Srrs } 1881169655Srrs case SCTP_GET_ASSOC_NUMBER: 1882163953Srrs { 1883169655Srrs uint32_t *value, cnt; 1884163953Srrs 1885169655Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1886294222Stuexen SCTP_INP_RLOCK(inp); 1887294222Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1888294222Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 1889294222Stuexen /* Can't do this for a 1-1 socket */ 1890294222Stuexen error = EINVAL; 1891294222Stuexen SCTP_INP_RUNLOCK(inp); 1892294222Stuexen break; 1893294222Stuexen } 1894163953Srrs cnt = 0; 1895169655Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 1896169655Srrs cnt++; 1897163953Srrs } 1898169655Srrs SCTP_INP_RUNLOCK(inp); 1899169655Srrs *value = cnt; 1900169655Srrs *optsize = sizeof(uint32_t); 1901223132Stuexen break; 1902169655Srrs } 1903169655Srrs case SCTP_GET_ASSOC_ID_LIST: 1904169655Srrs { 1905169655Srrs struct sctp_assoc_ids *ids; 1906169655Srrs unsigned int at, limit; 1907169655Srrs 1908169655Srrs SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize); 1909294222Stuexen SCTP_INP_RLOCK(inp); 1910294222Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1911294222Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 1912294222Stuexen /* Can't do this for a 1-1 socket */ 1913294222Stuexen error = EINVAL; 1914294222Stuexen SCTP_INP_RUNLOCK(inp); 1915294222Stuexen break; 1916294222Stuexen } 1917163953Srrs at = 0; 1918185694Srrs limit = (*optsize - sizeof(uint32_t)) / sizeof(sctp_assoc_t); 1919169655Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 1920169655Srrs if (at < limit) { 1921169655Srrs ids->gaids_assoc_id[at++] = sctp_get_associd(stcb); 1922169655Srrs } else { 1923169655Srrs error = EINVAL; 1924171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1925163953Srrs break; 1926163953Srrs } 1927163953Srrs } 1928163953Srrs SCTP_INP_RUNLOCK(inp); 1929223132Stuexen if (error == 0) { 1930223132Stuexen ids->gaids_number_of_ids = at; 1931223132Stuexen *optsize = ((at * sizeof(sctp_assoc_t)) + sizeof(uint32_t)); 1932223132Stuexen } 1933223132Stuexen break; 1934163953Srrs } 1935163953Srrs case SCTP_CONTEXT: 1936163953Srrs { 1937163953Srrs struct sctp_assoc_value *av; 1938163953Srrs 1939166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1940166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1941166675Srrs 1942166675Srrs if (stcb) { 1943166675Srrs av->assoc_value = stcb->asoc.context; 1944166675Srrs SCTP_TCB_UNLOCK(stcb); 1945163953Srrs } else { 1946224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1947224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1948224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1949223132Stuexen SCTP_INP_RLOCK(inp); 1950223132Stuexen av->assoc_value = inp->sctp_context; 1951223132Stuexen SCTP_INP_RUNLOCK(inp); 1952223132Stuexen } else { 1953223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1954223132Stuexen error = EINVAL; 1955223132Stuexen } 1956163953Srrs } 1957223132Stuexen if (error == 0) { 1958223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1959223132Stuexen } 1960223132Stuexen break; 1961163953Srrs } 1962167598Srrs case SCTP_VRF_ID: 1963167598Srrs { 1964170056Srrs uint32_t *default_vrfid; 1965167598Srrs 1966170056Srrs SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize); 1967170056Srrs *default_vrfid = inp->def_vrf_id; 1968223132Stuexen *optsize = sizeof(uint32_t); 1969167598Srrs break; 1970167598Srrs } 1971167598Srrs case SCTP_GET_ASOC_VRF: 1972167598Srrs { 1973167598Srrs struct sctp_assoc_value *id; 1974167598Srrs 1975167598Srrs SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize); 1976167598Srrs SCTP_FIND_STCB(inp, stcb, id->assoc_id); 1977167598Srrs if (stcb == NULL) { 1978167598Srrs error = EINVAL; 1979171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1980223132Stuexen } else { 1981223132Stuexen id->assoc_value = stcb->asoc.vrf_id; 1982223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1983167598Srrs } 1984167598Srrs break; 1985167598Srrs } 1986167598Srrs case SCTP_GET_VRF_IDS: 1987167598Srrs { 1988171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 1989167598Srrs error = EOPNOTSUPP; 1990167598Srrs break; 1991167598Srrs } 1992163953Srrs case SCTP_GET_NONCE_VALUES: 1993163953Srrs { 1994163953Srrs struct sctp_get_nonce_values *gnv; 1995163953Srrs 1996166675Srrs SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize); 1997166675Srrs SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id); 1998166675Srrs 1999166675Srrs if (stcb) { 2000163953Srrs gnv->gn_peers_tag = stcb->asoc.peer_vtag; 2001163953Srrs gnv->gn_local_tag = stcb->asoc.my_vtag; 2002163953Srrs SCTP_TCB_UNLOCK(stcb); 2003223132Stuexen *optsize = sizeof(struct sctp_get_nonce_values); 2004166675Srrs } else { 2005171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 2006166675Srrs error = ENOTCONN; 2007163953Srrs } 2008223132Stuexen break; 2009163953Srrs } 2010170056Srrs case SCTP_DELAYED_SACK: 2011163953Srrs { 2012170056Srrs struct sctp_sack_info *sack; 2013163953Srrs 2014170056Srrs SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, *optsize); 2015170056Srrs SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); 2016166675Srrs if (stcb) { 2017170056Srrs sack->sack_delay = stcb->asoc.delayed_ack; 2018170056Srrs sack->sack_freq = stcb->asoc.sack_freq; 2019166675Srrs SCTP_TCB_UNLOCK(stcb); 2020166675Srrs } else { 2021224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2022224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2023224918Stuexen (sack->sack_assoc_id == SCTP_FUTURE_ASSOC)) { 2024223132Stuexen SCTP_INP_RLOCK(inp); 2025223132Stuexen sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); 2026223132Stuexen sack->sack_freq = inp->sctp_ep.sctp_sack_freq; 2027223132Stuexen SCTP_INP_RUNLOCK(inp); 2028223132Stuexen } else { 2029223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2030223132Stuexen error = EINVAL; 2031223132Stuexen } 2032163953Srrs } 2033223132Stuexen if (error == 0) { 2034223132Stuexen *optsize = sizeof(struct sctp_sack_info); 2035223132Stuexen } 2036223132Stuexen break; 2037163953Srrs } 2038163953Srrs case SCTP_GET_SNDBUF_USE: 2039166675Srrs { 2040163953Srrs struct sctp_sockstat *ss; 2041163953Srrs 2042166675Srrs SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize); 2043166675Srrs SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id); 2044166675Srrs 2045166675Srrs if (stcb) { 2046166675Srrs ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size; 2047166675Srrs ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue + 2048166675Srrs stcb->asoc.size_on_all_streams); 2049166675Srrs SCTP_TCB_UNLOCK(stcb); 2050223132Stuexen *optsize = sizeof(struct sctp_sockstat); 2051166675Srrs } else { 2052171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 2053163953Srrs error = ENOTCONN; 2054163953Srrs } 2055223132Stuexen break; 2056163953Srrs } 2057170056Srrs case SCTP_MAX_BURST: 2058163953Srrs { 2059217895Stuexen struct sctp_assoc_value *av; 2060163953Srrs 2061217895Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 2062217895Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2063166675Srrs 2064217895Stuexen if (stcb) { 2065217895Stuexen av->assoc_value = stcb->asoc.max_burst; 2066217895Stuexen SCTP_TCB_UNLOCK(stcb); 2067217894Stuexen } else { 2068224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2069224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2070224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 2071223132Stuexen SCTP_INP_RLOCK(inp); 2072223132Stuexen av->assoc_value = inp->sctp_ep.max_burst; 2073223132Stuexen SCTP_INP_RUNLOCK(inp); 2074223132Stuexen } else { 2075223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2076223132Stuexen error = EINVAL; 2077223132Stuexen } 2078217894Stuexen } 2079223132Stuexen if (error == 0) { 2080223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 2081223132Stuexen } 2082223132Stuexen break; 2083163953Srrs } 2084163953Srrs case SCTP_MAXSEG: 2085163953Srrs { 2086167598Srrs struct sctp_assoc_value *av; 2087163953Srrs int ovh; 2088163953Srrs 2089167598Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 2090170056Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2091163953Srrs 2092167598Srrs if (stcb) { 2093167598Srrs av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc); 2094167598Srrs SCTP_TCB_UNLOCK(stcb); 2095163953Srrs } else { 2096224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2097224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2098224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 2099223132Stuexen SCTP_INP_RLOCK(inp); 2100223132Stuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2101223132Stuexen ovh = SCTP_MED_OVERHEAD; 2102223132Stuexen } else { 2103223132Stuexen ovh = SCTP_MED_V4_OVERHEAD; 2104223132Stuexen } 2105223132Stuexen if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT) 2106223132Stuexen av->assoc_value = 0; 2107223132Stuexen else 2108223132Stuexen av->assoc_value = inp->sctp_frag_point - ovh; 2109223132Stuexen SCTP_INP_RUNLOCK(inp); 2110167598Srrs } else { 2111223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2112223132Stuexen error = EINVAL; 2113167598Srrs } 2114163953Srrs } 2115223132Stuexen if (error == 0) { 2116223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 2117223132Stuexen } 2118223132Stuexen break; 2119163953Srrs } 2120163953Srrs case SCTP_GET_STAT_LOG: 2121167598Srrs error = sctp_fill_stat_log(optval, optsize); 2122163953Srrs break; 2123163953Srrs case SCTP_EVENTS: 2124163953Srrs { 2125163953Srrs struct sctp_event_subscribe *events; 2126163953Srrs 2127166675Srrs SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize); 2128223132Stuexen memset(events, 0, sizeof(struct sctp_event_subscribe)); 2129163953Srrs SCTP_INP_RLOCK(inp); 2130163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) 2131163953Srrs events->sctp_data_io_event = 1; 2132163953Srrs 2133163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT)) 2134163953Srrs events->sctp_association_event = 1; 2135163953Srrs 2136163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT)) 2137163953Srrs events->sctp_address_event = 1; 2138163953Srrs 2139163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) 2140163953Srrs events->sctp_send_failure_event = 1; 2141163953Srrs 2142163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR)) 2143163953Srrs events->sctp_peer_error_event = 1; 2144163953Srrs 2145163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) 2146163953Srrs events->sctp_shutdown_event = 1; 2147163953Srrs 2148163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT)) 2149163953Srrs events->sctp_partial_delivery_event = 1; 2150163953Srrs 2151163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) 2152163953Srrs events->sctp_adaptation_layer_event = 1; 2153163953Srrs 2154163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT)) 2155163953Srrs events->sctp_authentication_event = 1; 2156163953Srrs 2157185694Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT)) 2158185694Srrs events->sctp_sender_dry_event = 1; 2159185694Srrs 2160163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) 2161202520Srrs events->sctp_stream_reset_event = 1; 2162163953Srrs SCTP_INP_RUNLOCK(inp); 2163166675Srrs *optsize = sizeof(struct sctp_event_subscribe); 2164223132Stuexen break; 2165163953Srrs } 2166163953Srrs case SCTP_ADAPTATION_LAYER: 2167166675Srrs { 2168166675Srrs uint32_t *value; 2169166675Srrs 2170166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2171166675Srrs 2172166675Srrs SCTP_INP_RLOCK(inp); 2173166675Srrs *value = inp->sctp_ep.adaptation_layer_indicator; 2174166675Srrs SCTP_INP_RUNLOCK(inp); 2175166675Srrs *optsize = sizeof(uint32_t); 2176223132Stuexen break; 2177163953Srrs } 2178163953Srrs case SCTP_SET_INITIAL_DBG_SEQ: 2179166675Srrs { 2180166675Srrs uint32_t *value; 2181166675Srrs 2182166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2183166675Srrs SCTP_INP_RLOCK(inp); 2184166675Srrs *value = inp->sctp_ep.initial_sequence_debug; 2185166675Srrs SCTP_INP_RUNLOCK(inp); 2186166675Srrs *optsize = sizeof(uint32_t); 2187223132Stuexen break; 2188163953Srrs } 2189163953Srrs case SCTP_GET_LOCAL_ADDR_SIZE: 2190166675Srrs { 2191166675Srrs uint32_t *value; 2192166675Srrs 2193166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2194166675Srrs SCTP_INP_RLOCK(inp); 2195168124Srrs *value = sctp_count_max_addresses(inp); 2196166675Srrs SCTP_INP_RUNLOCK(inp); 2197166675Srrs *optsize = sizeof(uint32_t); 2198223132Stuexen break; 2199163953Srrs } 2200163953Srrs case SCTP_GET_REMOTE_ADDR_SIZE: 2201163953Srrs { 2202166675Srrs uint32_t *value; 2203166675Srrs size_t size; 2204163953Srrs struct sctp_nets *net; 2205163953Srrs 2206166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2207166675Srrs /* FIXME MT: change to sctp_assoc_value? */ 2208166675Srrs SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value); 2209166675Srrs 2210166675Srrs if (stcb) { 2211166675Srrs size = 0; 2212166675Srrs /* Count the sizes */ 2213166675Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 2214283699Stuexen switch (net->ro._l_addr.sa.sa_family) { 2215221249Stuexen#ifdef INET 2216283699Stuexen case AF_INET: 2217283699Stuexen#ifdef INET6 2218283699Stuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 2219283699Stuexen size += sizeof(struct sockaddr_in6); 2220283699Stuexen } else { 2221221249Stuexen size += sizeof(struct sockaddr_in); 2222283699Stuexen } 2223283699Stuexen#else 2224283699Stuexen size += sizeof(struct sockaddr_in); 2225221249Stuexen#endif 2226283699Stuexen break; 2227283699Stuexen#endif 2228221249Stuexen#ifdef INET6 2229283699Stuexen case AF_INET6: 2230283699Stuexen size += sizeof(struct sockaddr_in6); 2231283699Stuexen break; 2232221249Stuexen#endif 2233283699Stuexen default: 2234283699Stuexen break; 2235166675Srrs } 2236163953Srrs } 2237166675Srrs SCTP_TCB_UNLOCK(stcb); 2238166675Srrs *value = (uint32_t) size; 2239223132Stuexen *optsize = sizeof(uint32_t); 2240166675Srrs } else { 2241171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 2242166675Srrs error = ENOTCONN; 2243163953Srrs } 2244223132Stuexen break; 2245163953Srrs } 2246163953Srrs case SCTP_GET_PEER_ADDRESSES: 2247163953Srrs /* 2248163953Srrs * Get the address information, an array is passed in to 2249163953Srrs * fill up we pack it. 2250163953Srrs */ 2251163953Srrs { 2252166675Srrs size_t cpsz, left; 2253163953Srrs struct sockaddr_storage *sas; 2254163953Srrs struct sctp_nets *net; 2255163953Srrs struct sctp_getaddresses *saddr; 2256163953Srrs 2257166675Srrs SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); 2258166675Srrs SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); 2259163953Srrs 2260166675Srrs if (stcb) { 2261166675Srrs left = (*optsize) - sizeof(struct sctp_getaddresses); 2262166675Srrs *optsize = sizeof(struct sctp_getaddresses); 2263166675Srrs sas = (struct sockaddr_storage *)&saddr->addr[0]; 2264166675Srrs 2265166675Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 2266283699Stuexen switch (net->ro._l_addr.sa.sa_family) { 2267221249Stuexen#ifdef INET 2268283699Stuexen case AF_INET: 2269283699Stuexen#ifdef INET6 2270283699Stuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 2271283699Stuexen cpsz = sizeof(struct sockaddr_in6); 2272283699Stuexen } else { 2273221249Stuexen cpsz = sizeof(struct sockaddr_in); 2274283699Stuexen } 2275283699Stuexen#else 2276283699Stuexen cpsz = sizeof(struct sockaddr_in); 2277221249Stuexen#endif 2278283699Stuexen break; 2279283699Stuexen#endif 2280221249Stuexen#ifdef INET6 2281283699Stuexen case AF_INET6: 2282283699Stuexen cpsz = sizeof(struct sockaddr_in6); 2283283699Stuexen break; 2284221249Stuexen#endif 2285283699Stuexen default: 2286283699Stuexen cpsz = 0; 2287283699Stuexen break; 2288221249Stuexen } 2289221249Stuexen if (cpsz == 0) { 2290166675Srrs break; 2291166675Srrs } 2292166675Srrs if (left < cpsz) { 2293166675Srrs /* not enough room. */ 2294166675Srrs break; 2295166675Srrs } 2296221249Stuexen#if defined(INET) && defined(INET6) 2297178251Srrs if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) && 2298283699Stuexen (net->ro._l_addr.sa.sa_family == AF_INET)) { 2299166675Srrs /* Must map the address */ 2300283699Stuexen in6_sin_2_v4mapsin6(&net->ro._l_addr.sin, 2301166675Srrs (struct sockaddr_in6 *)sas); 2302166675Srrs } else { 2303166675Srrs memcpy(sas, &net->ro._l_addr, cpsz); 2304166675Srrs } 2305283699Stuexen#else 2306283699Stuexen memcpy(sas, &net->ro._l_addr, cpsz); 2307178251Srrs#endif 2308166675Srrs ((struct sockaddr_in *)sas)->sin_port = stcb->rport; 2309166675Srrs 2310166675Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz); 2311166675Srrs left -= cpsz; 2312166675Srrs *optsize += cpsz; 2313163953Srrs } 2314166675Srrs SCTP_TCB_UNLOCK(stcb); 2315166675Srrs } else { 2316171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 2317166675Srrs error = ENOENT; 2318163953Srrs } 2319223132Stuexen break; 2320163953Srrs } 2321163953Srrs case SCTP_GET_LOCAL_ADDRESSES: 2322163953Srrs { 2323166675Srrs size_t limit, actual; 2324163953Srrs struct sockaddr_storage *sas; 2325163953Srrs struct sctp_getaddresses *saddr; 2326163953Srrs 2327166675Srrs SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); 2328166675Srrs SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); 2329163953Srrs 2330163953Srrs sas = (struct sockaddr_storage *)&saddr->addr[0]; 2331166675Srrs limit = *optsize - sizeof(sctp_assoc_t); 2332168124Srrs actual = sctp_fill_up_addresses(inp, stcb, limit, sas); 2333169655Srrs if (stcb) { 2334163953Srrs SCTP_TCB_UNLOCK(stcb); 2335169655Srrs } 2336166675Srrs *optsize = sizeof(struct sockaddr_storage) + actual; 2337223132Stuexen break; 2338163953Srrs } 2339163953Srrs case SCTP_PEER_ADDR_PARAMS: 2340163953Srrs { 2341163953Srrs struct sctp_paddrparams *paddrp; 2342163953Srrs struct sctp_nets *net; 2343283699Stuexen struct sockaddr *addr; 2344163953Srrs 2345283699Stuexen#if defined(INET) && defined(INET6) 2346283699Stuexen struct sockaddr_in sin_store; 2347283699Stuexen 2348283699Stuexen#endif 2349283699Stuexen 2350166675Srrs SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize); 2351166675Srrs SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); 2352163953Srrs 2353283699Stuexen#if defined(INET) && defined(INET6) 2354283699Stuexen if (paddrp->spp_address.ss_family == AF_INET6) { 2355283699Stuexen struct sockaddr_in6 *sin6; 2356283699Stuexen 2357283699Stuexen sin6 = (struct sockaddr_in6 *)&paddrp->spp_address; 2358283699Stuexen if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 2359283699Stuexen in6_sin6_2_sin(&sin_store, sin6); 2360283699Stuexen addr = (struct sockaddr *)&sin_store; 2361283699Stuexen } else { 2362283699Stuexen addr = (struct sockaddr *)&paddrp->spp_address; 2363283699Stuexen } 2364166675Srrs } else { 2365283699Stuexen addr = (struct sockaddr *)&paddrp->spp_address; 2366283699Stuexen } 2367283699Stuexen#else 2368283699Stuexen addr = (struct sockaddr *)&paddrp->spp_address; 2369283699Stuexen#endif 2370283699Stuexen if (stcb != NULL) { 2371283699Stuexen net = sctp_findnet(stcb, addr); 2372283699Stuexen } else { 2373166675Srrs /* 2374166675Srrs * We increment here since 2375166675Srrs * sctp_findassociation_ep_addr() wil do a 2376166675Srrs * decrement if it finds the stcb as long as 2377166675Srrs * the locked tcb (last argument) is NOT a 2378166675Srrs * TCB.. aka NULL. 2379166675Srrs */ 2380283699Stuexen net = NULL; 2381166675Srrs SCTP_INP_INCR_REF(inp); 2382283699Stuexen stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL); 2383163953Srrs if (stcb == NULL) { 2384166675Srrs SCTP_INP_DECR_REF(inp); 2385163953Srrs } 2386163953Srrs } 2387283699Stuexen if ((stcb != NULL) && (net == NULL)) { 2388221249Stuexen#ifdef INET 2389283699Stuexen if (addr->sa_family == AF_INET) { 2390171943Srrs struct sockaddr_in *sin; 2391171943Srrs 2392283699Stuexen sin = (struct sockaddr_in *)addr; 2393283699Stuexen if (sin->sin_addr.s_addr != INADDR_ANY) { 2394171943Srrs error = EINVAL; 2395171943Srrs SCTP_TCB_UNLOCK(stcb); 2396171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2397171943Srrs break; 2398171943Srrs } 2399221249Stuexen } else 2400221249Stuexen#endif 2401221249Stuexen#ifdef INET6 2402283699Stuexen if (addr->sa_family == AF_INET6) { 2403171943Srrs struct sockaddr_in6 *sin6; 2404171943Srrs 2405283699Stuexen sin6 = (struct sockaddr_in6 *)addr; 2406171943Srrs if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 2407171943Srrs error = EINVAL; 2408171943Srrs SCTP_TCB_UNLOCK(stcb); 2409171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2410171943Srrs break; 2411171943Srrs } 2412221249Stuexen } else 2413221249Stuexen#endif 2414221249Stuexen { 2415171943Srrs error = EAFNOSUPPORT; 2416171943Srrs SCTP_TCB_UNLOCK(stcb); 2417171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2418171943Srrs break; 2419171943Srrs } 2420171943Srrs } 2421283699Stuexen if (stcb != NULL) { 2422224641Stuexen /* Applies to the specific association */ 2423163953Srrs paddrp->spp_flags = 0; 2424283699Stuexen if (net != NULL) { 2425224641Stuexen paddrp->spp_hbinterval = net->heart_beat_delay; 2426163953Srrs paddrp->spp_pathmaxrxt = net->failure_threshold; 2427283829Stuexen paddrp->spp_pathmtu = net->mtu; 2428283829Stuexen switch (net->ro._l_addr.sa.sa_family) { 2429283829Stuexen#ifdef INET 2430283829Stuexen case AF_INET: 2431283829Stuexen paddrp->spp_pathmtu -= SCTP_MIN_V4_OVERHEAD; 2432283829Stuexen break; 2433283829Stuexen#endif 2434283829Stuexen#ifdef INET6 2435283829Stuexen case AF_INET6: 2436283829Stuexen paddrp->spp_pathmtu -= SCTP_MIN_V4_OVERHEAD; 2437283829Stuexen break; 2438283829Stuexen#endif 2439283829Stuexen default: 2440283829Stuexen break; 2441283829Stuexen } 2442163953Srrs /* get flags for HB */ 2443225635Stuexen if (net->dest_state & SCTP_ADDR_NOHB) { 2444163953Srrs paddrp->spp_flags |= SPP_HB_DISABLE; 2445225635Stuexen } else { 2446163953Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 2447225635Stuexen } 2448163953Srrs /* get flags for PMTU */ 2449225635Stuexen if (net->dest_state & SCTP_ADDR_NO_PMTUD) { 2450284440Stuexen paddrp->spp_flags |= SPP_PMTUD_DISABLE; 2451284440Stuexen } else { 2452163953Srrs paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2453163953Srrs } 2454225549Stuexen if (net->dscp & 0x01) { 2455226252Stuexen paddrp->spp_dscp = net->dscp & 0xfc; 2456224870Stuexen paddrp->spp_flags |= SPP_DSCP; 2457163953Srrs } 2458167598Srrs#ifdef INET6 2459225549Stuexen if ((net->ro._l_addr.sa.sa_family == AF_INET6) && 2460225549Stuexen (net->flowlabel & 0x80000000)) { 2461225549Stuexen paddrp->spp_ipv6_flowlabel = net->flowlabel & 0x000fffff; 2462163953Srrs paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2463163953Srrs } 2464163953Srrs#endif 2465163953Srrs } else { 2466163953Srrs /* 2467163953Srrs * No destination so return default 2468163953Srrs * value 2469163953Srrs */ 2470163953Srrs paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure; 2471283829Stuexen paddrp->spp_pathmtu = 0; 2472225549Stuexen if (stcb->asoc.default_dscp & 0x01) { 2473226252Stuexen paddrp->spp_dscp = stcb->asoc.default_dscp & 0xfc; 2474225549Stuexen paddrp->spp_flags |= SPP_DSCP; 2475225549Stuexen } 2476167598Srrs#ifdef INET6 2477225549Stuexen if (stcb->asoc.default_flowlabel & 0x80000000) { 2478225549Stuexen paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel & 0x000fffff; 2479225549Stuexen paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2480225549Stuexen } 2481163953Srrs#endif 2482163953Srrs /* default settings should be these */ 2483225635Stuexen if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { 2484224641Stuexen paddrp->spp_flags |= SPP_HB_DISABLE; 2485224641Stuexen } else { 2486163953Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 2487163953Srrs } 2488225635Stuexen if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) { 2489225635Stuexen paddrp->spp_flags |= SPP_PMTUD_DISABLE; 2490225635Stuexen } else { 2491170056Srrs paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2492170056Srrs } 2493225635Stuexen paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay; 2494163953Srrs } 2495163953Srrs paddrp->spp_assoc_id = sctp_get_associd(stcb); 2496163953Srrs SCTP_TCB_UNLOCK(stcb); 2497163953Srrs } else { 2498224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2499224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2500224918Stuexen (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) { 2501223132Stuexen /* Use endpoint defaults */ 2502223132Stuexen SCTP_INP_RLOCK(inp); 2503223132Stuexen paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure; 2504223132Stuexen paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); 2505223132Stuexen paddrp->spp_assoc_id = SCTP_FUTURE_ASSOC; 2506223132Stuexen /* get inp's default */ 2507225549Stuexen if (inp->sctp_ep.default_dscp & 0x01) { 2508226252Stuexen paddrp->spp_dscp = inp->sctp_ep.default_dscp & 0xfc; 2509225549Stuexen paddrp->spp_flags |= SPP_DSCP; 2510225549Stuexen } 2511167598Srrs#ifdef INET6 2512225549Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 2513225549Stuexen (inp->sctp_ep.default_flowlabel & 0x80000000)) { 2514225549Stuexen paddrp->spp_ipv6_flowlabel = inp->sctp_ep.default_flowlabel & 0x000fffff; 2515223132Stuexen paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2516223132Stuexen } 2517163953Srrs#endif 2518223132Stuexen /* can't return this */ 2519223132Stuexen paddrp->spp_pathmtu = 0; 2520170056Srrs 2521223132Stuexen if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { 2522223132Stuexen paddrp->spp_flags |= SPP_HB_ENABLE; 2523223132Stuexen } else { 2524223132Stuexen paddrp->spp_flags |= SPP_HB_DISABLE; 2525223132Stuexen } 2526225635Stuexen if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) { 2527225635Stuexen paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2528225635Stuexen } else { 2529225635Stuexen paddrp->spp_flags |= SPP_PMTUD_DISABLE; 2530225635Stuexen } 2531223132Stuexen SCTP_INP_RUNLOCK(inp); 2532170056Srrs } else { 2533223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2534223132Stuexen error = EINVAL; 2535170056Srrs } 2536163953Srrs } 2537223132Stuexen if (error == 0) { 2538223132Stuexen *optsize = sizeof(struct sctp_paddrparams); 2539223132Stuexen } 2540223132Stuexen break; 2541163953Srrs } 2542163953Srrs case SCTP_GET_PEER_ADDR_INFO: 2543163953Srrs { 2544163953Srrs struct sctp_paddrinfo *paddri; 2545163953Srrs struct sctp_nets *net; 2546283699Stuexen struct sockaddr *addr; 2547163953Srrs 2548283699Stuexen#if defined(INET) && defined(INET6) 2549283699Stuexen struct sockaddr_in sin_store; 2550283699Stuexen 2551283699Stuexen#endif 2552283699Stuexen 2553166675Srrs SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize); 2554166675Srrs SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id); 2555166675Srrs 2556283699Stuexen#if defined(INET) && defined(INET6) 2557283699Stuexen if (paddri->spinfo_address.ss_family == AF_INET6) { 2558283699Stuexen struct sockaddr_in6 *sin6; 2559283699Stuexen 2560283699Stuexen sin6 = (struct sockaddr_in6 *)&paddri->spinfo_address; 2561283699Stuexen if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 2562283699Stuexen in6_sin6_2_sin(&sin_store, sin6); 2563283699Stuexen addr = (struct sockaddr *)&sin_store; 2564283699Stuexen } else { 2565283699Stuexen addr = (struct sockaddr *)&paddri->spinfo_address; 2566283699Stuexen } 2567166675Srrs } else { 2568283699Stuexen addr = (struct sockaddr *)&paddri->spinfo_address; 2569283699Stuexen } 2570283699Stuexen#else 2571283699Stuexen addr = (struct sockaddr *)&paddri->spinfo_address; 2572283699Stuexen#endif 2573283699Stuexen if (stcb != NULL) { 2574283699Stuexen net = sctp_findnet(stcb, addr); 2575283699Stuexen } else { 2576166675Srrs /* 2577166675Srrs * We increment here since 2578166675Srrs * sctp_findassociation_ep_addr() wil do a 2579166675Srrs * decrement if it finds the stcb as long as 2580166675Srrs * the locked tcb (last argument) is NOT a 2581166675Srrs * TCB.. aka NULL. 2582166675Srrs */ 2583283699Stuexen net = NULL; 2584166675Srrs SCTP_INP_INCR_REF(inp); 2585283699Stuexen stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL); 2586166675Srrs if (stcb == NULL) { 2587166675Srrs SCTP_INP_DECR_REF(inp); 2588163953Srrs } 2589166675Srrs } 2590163953Srrs 2591283699Stuexen if ((stcb != NULL) && (net != NULL)) { 2592217635Srrs if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { 2593217638Stuexen /* It's unconfirmed */ 2594217635Srrs paddri->spinfo_state = SCTP_UNCONFIRMED; 2595217635Srrs } else if (net->dest_state & SCTP_ADDR_REACHABLE) { 2596217638Stuexen /* It's active */ 2597217635Srrs paddri->spinfo_state = SCTP_ACTIVE; 2598217635Srrs } else { 2599217638Stuexen /* It's inactive */ 2600217635Srrs paddri->spinfo_state = SCTP_INACTIVE; 2601217635Srrs } 2602166675Srrs paddri->spinfo_cwnd = net->cwnd; 2603219014Stuexen paddri->spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT; 2604166675Srrs paddri->spinfo_rto = net->RTO; 2605166675Srrs paddri->spinfo_assoc_id = sctp_get_associd(stcb); 2606222029Stuexen paddri->spinfo_mtu = net->mtu; 2607283829Stuexen switch (addr->sa_family) { 2608283829Stuexen#if defined(INET) 2609283829Stuexen case AF_INET: 2610283829Stuexen paddri->spinfo_mtu -= SCTP_MIN_V4_OVERHEAD; 2611283829Stuexen break; 2612283829Stuexen#endif 2613283829Stuexen#if defined(INET6) 2614283829Stuexen case AF_INET6: 2615283829Stuexen paddri->spinfo_mtu -= SCTP_MIN_OVERHEAD; 2616283829Stuexen break; 2617283829Stuexen#endif 2618283829Stuexen default: 2619283829Stuexen break; 2620283829Stuexen } 2621166675Srrs SCTP_TCB_UNLOCK(stcb); 2622223132Stuexen *optsize = sizeof(struct sctp_paddrinfo); 2623163953Srrs } else { 2624283699Stuexen if (stcb != NULL) { 2625163953Srrs SCTP_TCB_UNLOCK(stcb); 2626163953Srrs } 2627171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 2628163953Srrs error = ENOENT; 2629163953Srrs } 2630223132Stuexen break; 2631163953Srrs } 2632163953Srrs case SCTP_PCB_STATUS: 2633163953Srrs { 2634163953Srrs struct sctp_pcbinfo *spcb; 2635163953Srrs 2636166675Srrs SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize); 2637163953Srrs sctp_fill_pcbinfo(spcb); 2638166675Srrs *optsize = sizeof(struct sctp_pcbinfo); 2639223132Stuexen break; 2640163953Srrs } 2641163953Srrs case SCTP_STATUS: 2642163953Srrs { 2643163953Srrs struct sctp_nets *net; 2644163953Srrs struct sctp_status *sstat; 2645163953Srrs 2646166675Srrs SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize); 2647166675Srrs SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id); 2648163953Srrs 2649163953Srrs if (stcb == NULL) { 2650223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2651163953Srrs error = EINVAL; 2652163953Srrs break; 2653163953Srrs } 2654294149Stuexen sstat->sstat_state = sctp_map_assoc_state(stcb->asoc.state); 2655173179Srrs sstat->sstat_assoc_id = sctp_get_associd(stcb); 2656163953Srrs sstat->sstat_rwnd = stcb->asoc.peers_rwnd; 2657163953Srrs sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt; 2658163953Srrs /* 2659163953Srrs * We can't include chunks that have been passed to 2660163953Srrs * the socket layer. Only things in queue. 2661163953Srrs */ 2662163953Srrs sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue + 2663163953Srrs stcb->asoc.cnt_on_all_streams); 2664163953Srrs 2665163953Srrs 2666163953Srrs sstat->sstat_instrms = stcb->asoc.streamincnt; 2667163953Srrs sstat->sstat_outstrms = stcb->asoc.streamoutcnt; 2668163953Srrs sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc); 2669163953Srrs memcpy(&sstat->sstat_primary.spinfo_address, 2670163953Srrs &stcb->asoc.primary_destination->ro._l_addr, 2671163953Srrs ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len); 2672163953Srrs net = stcb->asoc.primary_destination; 2673163953Srrs ((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport; 2674163953Srrs /* 2675163953Srrs * Again the user can get info from sctp_constants.h 2676163953Srrs * for what the state of the network is. 2677163953Srrs */ 2678217635Srrs if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { 2679217635Srrs /* It's unconfirmed */ 2680217635Srrs sstat->sstat_primary.spinfo_state = SCTP_UNCONFIRMED; 2681217635Srrs } else if (net->dest_state & SCTP_ADDR_REACHABLE) { 2682217638Stuexen /* It's active */ 2683217635Srrs sstat->sstat_primary.spinfo_state = SCTP_ACTIVE; 2684217635Srrs } else { 2685217638Stuexen /* It's inactive */ 2686217635Srrs sstat->sstat_primary.spinfo_state = SCTP_INACTIVE; 2687217635Srrs } 2688163953Srrs sstat->sstat_primary.spinfo_cwnd = net->cwnd; 2689219014Stuexen sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT; 2690163953Srrs sstat->sstat_primary.spinfo_rto = net->RTO; 2691163953Srrs sstat->sstat_primary.spinfo_mtu = net->mtu; 2692283829Stuexen switch (stcb->asoc.primary_destination->ro._l_addr.sa.sa_family) { 2693283829Stuexen#if defined(INET) 2694283829Stuexen case AF_INET: 2695283829Stuexen sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_V4_OVERHEAD; 2696283829Stuexen break; 2697283829Stuexen#endif 2698283829Stuexen#if defined(INET6) 2699283829Stuexen case AF_INET6: 2700283829Stuexen sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_OVERHEAD; 2701283829Stuexen break; 2702283829Stuexen#endif 2703283829Stuexen default: 2704283829Stuexen break; 2705283829Stuexen } 2706163953Srrs sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb); 2707163953Srrs SCTP_TCB_UNLOCK(stcb); 2708223132Stuexen *optsize = sizeof(struct sctp_status); 2709223132Stuexen break; 2710163953Srrs } 2711163953Srrs case SCTP_RTOINFO: 2712163953Srrs { 2713163953Srrs struct sctp_rtoinfo *srto; 2714163953Srrs 2715166675Srrs SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize); 2716166675Srrs SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); 2717166675Srrs 2718166675Srrs if (stcb) { 2719166675Srrs srto->srto_initial = stcb->asoc.initial_rto; 2720166675Srrs srto->srto_max = stcb->asoc.maxrto; 2721166675Srrs srto->srto_min = stcb->asoc.minrto; 2722166675Srrs SCTP_TCB_UNLOCK(stcb); 2723166675Srrs } else { 2724224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2725224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2726224918Stuexen (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) { 2727223132Stuexen SCTP_INP_RLOCK(inp); 2728223132Stuexen srto->srto_initial = inp->sctp_ep.initial_rto; 2729223132Stuexen srto->srto_max = inp->sctp_ep.sctp_maxrto; 2730223132Stuexen srto->srto_min = inp->sctp_ep.sctp_minrto; 2731223132Stuexen SCTP_INP_RUNLOCK(inp); 2732223132Stuexen } else { 2733223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2734223132Stuexen error = EINVAL; 2735223132Stuexen } 2736163953Srrs } 2737223132Stuexen if (error == 0) { 2738223132Stuexen *optsize = sizeof(struct sctp_rtoinfo); 2739223132Stuexen } 2740223132Stuexen break; 2741163953Srrs } 2742215410Stuexen case SCTP_TIMEOUTS: 2743215410Stuexen { 2744215410Stuexen struct sctp_timeouts *stimo; 2745215410Stuexen 2746215410Stuexen SCTP_CHECK_AND_CAST(stimo, optval, struct sctp_timeouts, *optsize); 2747215410Stuexen SCTP_FIND_STCB(inp, stcb, stimo->stimo_assoc_id); 2748215410Stuexen 2749215410Stuexen if (stcb) { 2750215410Stuexen stimo->stimo_init = stcb->asoc.timoinit; 2751215410Stuexen stimo->stimo_data = stcb->asoc.timodata; 2752215410Stuexen stimo->stimo_sack = stcb->asoc.timosack; 2753215410Stuexen stimo->stimo_shutdown = stcb->asoc.timoshutdown; 2754215410Stuexen stimo->stimo_heartbeat = stcb->asoc.timoheartbeat; 2755215410Stuexen stimo->stimo_cookie = stcb->asoc.timocookie; 2756215410Stuexen stimo->stimo_shutdownack = stcb->asoc.timoshutdownack; 2757215410Stuexen SCTP_TCB_UNLOCK(stcb); 2758223132Stuexen *optsize = sizeof(struct sctp_timeouts); 2759215410Stuexen } else { 2760223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2761215410Stuexen error = EINVAL; 2762215410Stuexen } 2763223132Stuexen break; 2764215410Stuexen } 2765163953Srrs case SCTP_ASSOCINFO: 2766163953Srrs { 2767163953Srrs struct sctp_assocparams *sasoc; 2768163953Srrs 2769166675Srrs SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize); 2770166675Srrs SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); 2771163953Srrs 2772163953Srrs if (stcb) { 2773171477Srrs sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life); 2774163953Srrs sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times; 2775163953Srrs sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets; 2776163953Srrs sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd; 2777163953Srrs sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd; 2778163953Srrs SCTP_TCB_UNLOCK(stcb); 2779163953Srrs } else { 2780224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2781224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2782224918Stuexen (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) { 2783223132Stuexen SCTP_INP_RLOCK(inp); 2784223132Stuexen sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life); 2785223132Stuexen sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times; 2786223132Stuexen sasoc->sasoc_number_peer_destinations = 0; 2787223132Stuexen sasoc->sasoc_peer_rwnd = 0; 2788223132Stuexen sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv); 2789223132Stuexen SCTP_INP_RUNLOCK(inp); 2790223132Stuexen } else { 2791223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2792223132Stuexen error = EINVAL; 2793223132Stuexen } 2794163953Srrs } 2795223132Stuexen if (error == 0) { 2796223132Stuexen *optsize = sizeof(struct sctp_assocparams); 2797223132Stuexen } 2798223132Stuexen break; 2799163953Srrs } 2800163953Srrs case SCTP_DEFAULT_SEND_PARAM: 2801163953Srrs { 2802163953Srrs struct sctp_sndrcvinfo *s_info; 2803163953Srrs 2804166675Srrs SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize); 2805166675Srrs SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); 2806166675Srrs 2807166675Srrs if (stcb) { 2808170056Srrs memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send)); 2809166675Srrs SCTP_TCB_UNLOCK(stcb); 2810166675Srrs } else { 2811224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2812224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2813224918Stuexen (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC)) { 2814223132Stuexen SCTP_INP_RLOCK(inp); 2815223132Stuexen memcpy(s_info, &inp->def_send, sizeof(inp->def_send)); 2816223132Stuexen SCTP_INP_RUNLOCK(inp); 2817223132Stuexen } else { 2818223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2819223132Stuexen error = EINVAL; 2820223132Stuexen } 2821163953Srrs } 2822223132Stuexen if (error == 0) { 2823223132Stuexen *optsize = sizeof(struct sctp_sndrcvinfo); 2824223132Stuexen } 2825223132Stuexen break; 2826163953Srrs } 2827163953Srrs case SCTP_INITMSG: 2828163953Srrs { 2829163953Srrs struct sctp_initmsg *sinit; 2830163953Srrs 2831166675Srrs SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize); 2832163953Srrs SCTP_INP_RLOCK(inp); 2833163953Srrs sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count; 2834163953Srrs sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome; 2835163953Srrs sinit->sinit_max_attempts = inp->sctp_ep.max_init_times; 2836163953Srrs sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max; 2837163953Srrs SCTP_INP_RUNLOCK(inp); 2838223132Stuexen *optsize = sizeof(struct sctp_initmsg); 2839223132Stuexen break; 2840163953Srrs } 2841163953Srrs case SCTP_PRIMARY_ADDR: 2842163953Srrs /* we allow a "get" operation on this */ 2843163953Srrs { 2844163953Srrs struct sctp_setprim *ssp; 2845163953Srrs 2846166675Srrs SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize); 2847166675Srrs SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id); 2848166675Srrs 2849166675Srrs if (stcb) { 2850283699Stuexen union sctp_sockstore *addr; 2851170056Srrs 2852283699Stuexen addr = &stcb->asoc.primary_destination->ro._l_addr; 2853283699Stuexen switch (addr->sa.sa_family) { 2854283699Stuexen#ifdef INET 2855283699Stuexen case AF_INET: 2856283699Stuexen#ifdef INET6 2857283699Stuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 2858283699Stuexen in6_sin_2_v4mapsin6(&addr->sin, 2859283699Stuexen (struct sockaddr_in6 *)&ssp->ssp_addr); 2860283699Stuexen } else { 2861283699Stuexen memcpy(&ssp->ssp_addr, &addr->sin, sizeof(struct sockaddr_in)); 2862283699Stuexen } 2863283699Stuexen#else 2864283699Stuexen memcpy(&ssp->ssp_addr, &addr->sin, sizeof(struct sockaddr_in)); 2865283699Stuexen#endif 2866283699Stuexen break; 2867283699Stuexen#endif 2868283699Stuexen#ifdef INET6 2869283699Stuexen case AF_INET6: 2870283699Stuexen memcpy(&ssp->ssp_addr, &addr->sin6, sizeof(struct sockaddr_in6)); 2871283699Stuexen break; 2872283699Stuexen#endif 2873283699Stuexen default: 2874283699Stuexen break; 2875283699Stuexen } 2876166675Srrs SCTP_TCB_UNLOCK(stcb); 2877223132Stuexen *optsize = sizeof(struct sctp_setprim); 2878166675Srrs } else { 2879223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2880163953Srrs error = EINVAL; 2881163953Srrs } 2882223132Stuexen break; 2883163953Srrs } 2884163953Srrs case SCTP_HMAC_IDENT: 2885163953Srrs { 2886163953Srrs struct sctp_hmacalgo *shmac; 2887163953Srrs sctp_hmaclist_t *hmaclist; 2888163953Srrs uint32_t size; 2889163953Srrs int i; 2890163953Srrs 2891166675Srrs SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize); 2892166675Srrs 2893163953Srrs SCTP_INP_RLOCK(inp); 2894163953Srrs hmaclist = inp->sctp_ep.local_hmacs; 2895163953Srrs if (hmaclist == NULL) { 2896163953Srrs /* no HMACs to return */ 2897166675Srrs *optsize = sizeof(*shmac); 2898168299Srrs SCTP_INP_RUNLOCK(inp); 2899163953Srrs break; 2900163953Srrs } 2901163953Srrs /* is there room for all of the hmac ids? */ 2902163953Srrs size = sizeof(*shmac) + (hmaclist->num_algo * 2903163953Srrs sizeof(shmac->shmac_idents[0])); 2904166675Srrs if ((size_t)(*optsize) < size) { 2905223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2906163953Srrs error = EINVAL; 2907163953Srrs SCTP_INP_RUNLOCK(inp); 2908163953Srrs break; 2909163953Srrs } 2910163953Srrs /* copy in the list */ 2911181054Srrs shmac->shmac_number_of_idents = hmaclist->num_algo; 2912181054Srrs for (i = 0; i < hmaclist->num_algo; i++) { 2913163953Srrs shmac->shmac_idents[i] = hmaclist->hmac[i]; 2914181054Srrs } 2915163953Srrs SCTP_INP_RUNLOCK(inp); 2916166675Srrs *optsize = size; 2917163953Srrs break; 2918163953Srrs } 2919163953Srrs case SCTP_AUTH_ACTIVE_KEY: 2920163953Srrs { 2921163953Srrs struct sctp_authkeyid *scact; 2922163953Srrs 2923166675Srrs SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize); 2924166675Srrs SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); 2925166675Srrs 2926166675Srrs if (stcb) { 2927163953Srrs /* get the active key on the assoc */ 2928185694Srrs scact->scact_keynumber = stcb->asoc.authinfo.active_keyid; 2929163953Srrs SCTP_TCB_UNLOCK(stcb); 2930163953Srrs } else { 2931224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2932224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2933224918Stuexen (scact->scact_assoc_id == SCTP_FUTURE_ASSOC)) { 2934223132Stuexen /* get the endpoint active key */ 2935223132Stuexen SCTP_INP_RLOCK(inp); 2936223132Stuexen scact->scact_keynumber = inp->sctp_ep.default_keyid; 2937223132Stuexen SCTP_INP_RUNLOCK(inp); 2938223132Stuexen } else { 2939223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2940223132Stuexen error = EINVAL; 2941223132Stuexen } 2942163953Srrs } 2943223132Stuexen if (error == 0) { 2944223132Stuexen *optsize = sizeof(struct sctp_authkeyid); 2945223132Stuexen } 2946163953Srrs break; 2947163953Srrs } 2948163953Srrs case SCTP_LOCAL_AUTH_CHUNKS: 2949163953Srrs { 2950163953Srrs struct sctp_authchunks *sac; 2951163953Srrs sctp_auth_chklist_t *chklist = NULL; 2952166675Srrs size_t size = 0; 2953163953Srrs 2954166675Srrs SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); 2955166675Srrs SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); 2956166675Srrs 2957166675Srrs if (stcb) { 2958163953Srrs /* get off the assoc */ 2959163953Srrs chklist = stcb->asoc.local_auth_chunks; 2960163953Srrs /* is there enough space? */ 2961163953Srrs size = sctp_auth_get_chklist_size(chklist); 2962166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2963163953Srrs error = EINVAL; 2964171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2965166675Srrs } else { 2966166675Srrs /* copy in the chunks */ 2967169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2968234832Stuexen sac->gauth_number_of_chunks = (uint32_t) size; 2969223132Stuexen *optsize = sizeof(struct sctp_authchunks) + size; 2970163953Srrs } 2971163953Srrs SCTP_TCB_UNLOCK(stcb); 2972163953Srrs } else { 2973224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2974224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2975224918Stuexen (sac->gauth_assoc_id == SCTP_FUTURE_ASSOC)) { 2976223132Stuexen /* get off the endpoint */ 2977223132Stuexen SCTP_INP_RLOCK(inp); 2978223132Stuexen chklist = inp->sctp_ep.local_auth_chunks; 2979223132Stuexen /* is there enough space? */ 2980223132Stuexen size = sctp_auth_get_chklist_size(chklist); 2981223132Stuexen if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2982223132Stuexen error = EINVAL; 2983223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2984223132Stuexen } else { 2985223132Stuexen /* copy in the chunks */ 2986223132Stuexen (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2987234832Stuexen sac->gauth_number_of_chunks = (uint32_t) size; 2988223132Stuexen *optsize = sizeof(struct sctp_authchunks) + size; 2989223132Stuexen } 2990223132Stuexen SCTP_INP_RUNLOCK(inp); 2991223132Stuexen } else { 2992223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2993163953Srrs error = EINVAL; 2994163953Srrs } 2995163953Srrs } 2996163953Srrs break; 2997163953Srrs } 2998163953Srrs case SCTP_PEER_AUTH_CHUNKS: 2999163953Srrs { 3000163953Srrs struct sctp_authchunks *sac; 3001163953Srrs sctp_auth_chklist_t *chklist = NULL; 3002166675Srrs size_t size = 0; 3003163953Srrs 3004166675Srrs SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); 3005166675Srrs SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); 3006166675Srrs 3007166675Srrs if (stcb) { 3008166675Srrs /* get off the assoc */ 3009166675Srrs chklist = stcb->asoc.peer_auth_chunks; 3010166675Srrs /* is there enough space? */ 3011166675Srrs size = sctp_auth_get_chklist_size(chklist); 3012166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 3013166675Srrs error = EINVAL; 3014171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3015166675Srrs } else { 3016166675Srrs /* copy in the chunks */ 3017169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 3018234832Stuexen sac->gauth_number_of_chunks = (uint32_t) size; 3019223132Stuexen *optsize = sizeof(struct sctp_authchunks) + size; 3020166675Srrs } 3021166675Srrs SCTP_TCB_UNLOCK(stcb); 3022166675Srrs } else { 3023171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 3024163953Srrs error = ENOENT; 3025163953Srrs } 3026163953Srrs break; 3027163953Srrs } 3028223132Stuexen case SCTP_EVENT: 3029223132Stuexen { 3030223132Stuexen struct sctp_event *event; 3031223132Stuexen uint32_t event_type; 3032163953Srrs 3033223132Stuexen SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, *optsize); 3034223132Stuexen SCTP_FIND_STCB(inp, stcb, event->se_assoc_id); 3035163953Srrs 3036223132Stuexen switch (event->se_type) { 3037223132Stuexen case SCTP_ASSOC_CHANGE: 3038223132Stuexen event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT; 3039223132Stuexen break; 3040223132Stuexen case SCTP_PEER_ADDR_CHANGE: 3041223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPADDREVNT; 3042223132Stuexen break; 3043223132Stuexen case SCTP_REMOTE_ERROR: 3044223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPEERERR; 3045223132Stuexen break; 3046223132Stuexen case SCTP_SEND_FAILED: 3047223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT; 3048223132Stuexen break; 3049223132Stuexen case SCTP_SHUTDOWN_EVENT: 3050223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT; 3051223132Stuexen break; 3052223132Stuexen case SCTP_ADAPTATION_INDICATION: 3053223132Stuexen event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT; 3054223132Stuexen break; 3055223132Stuexen case SCTP_PARTIAL_DELIVERY_EVENT: 3056223132Stuexen event_type = SCTP_PCB_FLAGS_PDAPIEVNT; 3057223132Stuexen break; 3058223132Stuexen case SCTP_AUTHENTICATION_EVENT: 3059223132Stuexen event_type = SCTP_PCB_FLAGS_AUTHEVNT; 3060223132Stuexen break; 3061223132Stuexen case SCTP_STREAM_RESET_EVENT: 3062223132Stuexen event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT; 3063223132Stuexen break; 3064223132Stuexen case SCTP_SENDER_DRY_EVENT: 3065223132Stuexen event_type = SCTP_PCB_FLAGS_DRYEVNT; 3066223132Stuexen break; 3067223132Stuexen case SCTP_NOTIFICATIONS_STOPPED_EVENT: 3068223132Stuexen event_type = 0; 3069223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); 3070223132Stuexen error = ENOTSUP; 3071223132Stuexen break; 3072235009Stuexen case SCTP_ASSOC_RESET_EVENT: 3073235009Stuexen event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT; 3074235009Stuexen break; 3075235009Stuexen case SCTP_STREAM_CHANGE_EVENT: 3076235009Stuexen event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT; 3077235009Stuexen break; 3078235075Stuexen case SCTP_SEND_FAILED_EVENT: 3079235075Stuexen event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT; 3080235075Stuexen break; 3081223132Stuexen default: 3082223132Stuexen event_type = 0; 3083223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3084223132Stuexen error = EINVAL; 3085223132Stuexen break; 3086223132Stuexen } 3087223132Stuexen if (event_type > 0) { 3088223132Stuexen if (stcb) { 3089223132Stuexen event->se_on = sctp_stcb_is_feature_on(inp, stcb, event_type); 3090223132Stuexen SCTP_TCB_UNLOCK(stcb); 3091223132Stuexen } else { 3092224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3093224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3094224918Stuexen (event->se_assoc_id == SCTP_FUTURE_ASSOC)) { 3095223132Stuexen SCTP_INP_RLOCK(inp); 3096223132Stuexen event->se_on = sctp_is_feature_on(inp, event_type); 3097223132Stuexen SCTP_INP_RUNLOCK(inp); 3098223132Stuexen } else { 3099223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3100223132Stuexen error = EINVAL; 3101223132Stuexen } 3102223132Stuexen } 3103223132Stuexen } 3104223132Stuexen if (error == 0) { 3105223132Stuexen *optsize = sizeof(struct sctp_event); 3106223132Stuexen } 3107223132Stuexen break; 3108223132Stuexen } 3109223132Stuexen case SCTP_RECVRCVINFO: 3110223132Stuexen { 3111223132Stuexen int onoff; 3112223132Stuexen 3113223132Stuexen if (*optsize < sizeof(int)) { 3114223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3115223132Stuexen error = EINVAL; 3116223132Stuexen } else { 3117230104Stuexen SCTP_INP_RLOCK(inp); 3118223132Stuexen onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO); 3119223132Stuexen SCTP_INP_RUNLOCK(inp); 3120223132Stuexen } 3121223132Stuexen if (error == 0) { 3122223132Stuexen /* return the option value */ 3123223132Stuexen *(int *)optval = onoff; 3124223132Stuexen *optsize = sizeof(int); 3125223132Stuexen } 3126223132Stuexen break; 3127223132Stuexen } 3128223132Stuexen case SCTP_RECVNXTINFO: 3129223132Stuexen { 3130223132Stuexen int onoff; 3131223132Stuexen 3132223132Stuexen if (*optsize < sizeof(int)) { 3133223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3134223132Stuexen error = EINVAL; 3135223132Stuexen } else { 3136230104Stuexen SCTP_INP_RLOCK(inp); 3137223132Stuexen onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO); 3138223132Stuexen SCTP_INP_RUNLOCK(inp); 3139223132Stuexen } 3140223132Stuexen if (error == 0) { 3141223132Stuexen /* return the option value */ 3142223132Stuexen *(int *)optval = onoff; 3143223132Stuexen *optsize = sizeof(int); 3144223132Stuexen } 3145223132Stuexen break; 3146223132Stuexen } 3147223132Stuexen case SCTP_DEFAULT_SNDINFO: 3148223132Stuexen { 3149223132Stuexen struct sctp_sndinfo *info; 3150223132Stuexen 3151223132Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, *optsize); 3152223132Stuexen SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id); 3153223132Stuexen 3154223132Stuexen if (stcb) { 3155223132Stuexen info->snd_sid = stcb->asoc.def_send.sinfo_stream; 3156223132Stuexen info->snd_flags = stcb->asoc.def_send.sinfo_flags; 3157223162Stuexen info->snd_flags &= 0xfff0; 3158223132Stuexen info->snd_ppid = stcb->asoc.def_send.sinfo_ppid; 3159223132Stuexen info->snd_context = stcb->asoc.def_send.sinfo_context; 3160223132Stuexen SCTP_TCB_UNLOCK(stcb); 3161223132Stuexen } else { 3162224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3163224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3164224918Stuexen (info->snd_assoc_id == SCTP_FUTURE_ASSOC)) { 3165223132Stuexen SCTP_INP_RLOCK(inp); 3166223132Stuexen info->snd_sid = inp->def_send.sinfo_stream; 3167223132Stuexen info->snd_flags = inp->def_send.sinfo_flags; 3168223162Stuexen info->snd_flags &= 0xfff0; 3169223132Stuexen info->snd_ppid = inp->def_send.sinfo_ppid; 3170223132Stuexen info->snd_context = inp->def_send.sinfo_context; 3171223132Stuexen SCTP_INP_RUNLOCK(inp); 3172223132Stuexen } else { 3173223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3174223132Stuexen error = EINVAL; 3175223132Stuexen } 3176223132Stuexen } 3177223132Stuexen if (error == 0) { 3178223132Stuexen *optsize = sizeof(struct sctp_sndinfo); 3179223132Stuexen } 3180223132Stuexen break; 3181223132Stuexen } 3182223162Stuexen case SCTP_DEFAULT_PRINFO: 3183223162Stuexen { 3184223162Stuexen struct sctp_default_prinfo *info; 3185223162Stuexen 3186223162Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, *optsize); 3187223162Stuexen SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id); 3188223162Stuexen 3189223162Stuexen if (stcb) { 3190223162Stuexen info->pr_policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); 3191223162Stuexen info->pr_value = stcb->asoc.def_send.sinfo_timetolive; 3192223162Stuexen SCTP_TCB_UNLOCK(stcb); 3193223162Stuexen } else { 3194224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3195224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3196224918Stuexen (info->pr_assoc_id == SCTP_FUTURE_ASSOC)) { 3197223162Stuexen SCTP_INP_RLOCK(inp); 3198223162Stuexen info->pr_policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags); 3199223162Stuexen info->pr_value = inp->def_send.sinfo_timetolive; 3200223162Stuexen SCTP_INP_RUNLOCK(inp); 3201223162Stuexen } else { 3202223162Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3203223162Stuexen error = EINVAL; 3204223162Stuexen } 3205223162Stuexen } 3206223162Stuexen if (error == 0) { 3207223162Stuexen *optsize = sizeof(struct sctp_default_prinfo); 3208223162Stuexen } 3209223162Stuexen break; 3210223162Stuexen } 3211224641Stuexen case SCTP_PEER_ADDR_THLDS: 3212224641Stuexen { 3213224641Stuexen struct sctp_paddrthlds *thlds; 3214224641Stuexen struct sctp_nets *net; 3215283699Stuexen struct sockaddr *addr; 3216224641Stuexen 3217283699Stuexen#if defined(INET) && defined(INET6) 3218283699Stuexen struct sockaddr_in sin_store; 3219283699Stuexen 3220283699Stuexen#endif 3221283699Stuexen 3222224641Stuexen SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, *optsize); 3223224641Stuexen SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id); 3224224641Stuexen 3225283699Stuexen#if defined(INET) && defined(INET6) 3226283699Stuexen if (thlds->spt_address.ss_family == AF_INET6) { 3227283699Stuexen struct sockaddr_in6 *sin6; 3228283699Stuexen 3229283699Stuexen sin6 = (struct sockaddr_in6 *)&thlds->spt_address; 3230283699Stuexen if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 3231283699Stuexen in6_sin6_2_sin(&sin_store, sin6); 3232283699Stuexen addr = (struct sockaddr *)&sin_store; 3233283699Stuexen } else { 3234283699Stuexen addr = (struct sockaddr *)&thlds->spt_address; 3235283699Stuexen } 3236224641Stuexen } else { 3237283699Stuexen addr = (struct sockaddr *)&thlds->spt_address; 3238283699Stuexen } 3239283699Stuexen#else 3240283699Stuexen addr = (struct sockaddr *)&thlds->spt_address; 3241283699Stuexen#endif 3242283699Stuexen if (stcb != NULL) { 3243283699Stuexen net = sctp_findnet(stcb, addr); 3244283699Stuexen } else { 3245224641Stuexen /* 3246224641Stuexen * We increment here since 3247224641Stuexen * sctp_findassociation_ep_addr() wil do a 3248224641Stuexen * decrement if it finds the stcb as long as 3249224641Stuexen * the locked tcb (last argument) is NOT a 3250224641Stuexen * TCB.. aka NULL. 3251224641Stuexen */ 3252283699Stuexen net = NULL; 3253224641Stuexen SCTP_INP_INCR_REF(inp); 3254283699Stuexen stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL); 3255224641Stuexen if (stcb == NULL) { 3256224641Stuexen SCTP_INP_DECR_REF(inp); 3257224641Stuexen } 3258224641Stuexen } 3259283699Stuexen if ((stcb != NULL) && (net == NULL)) { 3260224641Stuexen#ifdef INET 3261283699Stuexen if (addr->sa_family == AF_INET) { 3262224641Stuexen struct sockaddr_in *sin; 3263224641Stuexen 3264283699Stuexen sin = (struct sockaddr_in *)addr; 3265283699Stuexen if (sin->sin_addr.s_addr != INADDR_ANY) { 3266224641Stuexen error = EINVAL; 3267224641Stuexen SCTP_TCB_UNLOCK(stcb); 3268224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3269224641Stuexen break; 3270224641Stuexen } 3271224641Stuexen } else 3272224641Stuexen#endif 3273224641Stuexen#ifdef INET6 3274283699Stuexen if (addr->sa_family == AF_INET6) { 3275224641Stuexen struct sockaddr_in6 *sin6; 3276224641Stuexen 3277283699Stuexen sin6 = (struct sockaddr_in6 *)addr; 3278224641Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 3279224641Stuexen error = EINVAL; 3280224641Stuexen SCTP_TCB_UNLOCK(stcb); 3281224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3282224641Stuexen break; 3283224641Stuexen } 3284224641Stuexen } else 3285224641Stuexen#endif 3286224641Stuexen { 3287224641Stuexen error = EAFNOSUPPORT; 3288224641Stuexen SCTP_TCB_UNLOCK(stcb); 3289224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3290224641Stuexen break; 3291224641Stuexen } 3292224641Stuexen } 3293283699Stuexen if (stcb != NULL) { 3294283699Stuexen if (net != NULL) { 3295224641Stuexen thlds->spt_pathmaxrxt = net->failure_threshold; 3296224641Stuexen thlds->spt_pathpfthld = net->pf_threshold; 3297224641Stuexen } else { 3298224641Stuexen thlds->spt_pathmaxrxt = stcb->asoc.def_net_failure; 3299224641Stuexen thlds->spt_pathpfthld = stcb->asoc.def_net_pf_threshold; 3300224641Stuexen } 3301224641Stuexen thlds->spt_assoc_id = sctp_get_associd(stcb); 3302224641Stuexen SCTP_TCB_UNLOCK(stcb); 3303224641Stuexen } else { 3304224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3305224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3306224918Stuexen (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) { 3307224641Stuexen /* Use endpoint defaults */ 3308224641Stuexen SCTP_INP_RLOCK(inp); 3309224641Stuexen thlds->spt_pathmaxrxt = inp->sctp_ep.def_net_failure; 3310224641Stuexen thlds->spt_pathpfthld = inp->sctp_ep.def_net_pf_threshold; 3311224641Stuexen SCTP_INP_RUNLOCK(inp); 3312224641Stuexen } else { 3313224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3314224641Stuexen error = EINVAL; 3315224641Stuexen } 3316224641Stuexen } 3317224641Stuexen if (error == 0) { 3318224641Stuexen *optsize = sizeof(struct sctp_paddrthlds); 3319224641Stuexen } 3320224641Stuexen break; 3321224641Stuexen } 3322227755Stuexen case SCTP_REMOTE_UDP_ENCAPS_PORT: 3323227755Stuexen { 3324227755Stuexen struct sctp_udpencaps *encaps; 3325227755Stuexen struct sctp_nets *net; 3326283699Stuexen struct sockaddr *addr; 3327227755Stuexen 3328283699Stuexen#if defined(INET) && defined(INET6) 3329283699Stuexen struct sockaddr_in sin_store; 3330283699Stuexen 3331283699Stuexen#endif 3332283699Stuexen 3333227755Stuexen SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, *optsize); 3334227755Stuexen SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id); 3335227755Stuexen 3336283699Stuexen#if defined(INET) && defined(INET6) 3337283699Stuexen if (encaps->sue_address.ss_family == AF_INET6) { 3338283699Stuexen struct sockaddr_in6 *sin6; 3339283699Stuexen 3340283699Stuexen sin6 = (struct sockaddr_in6 *)&encaps->sue_address; 3341283699Stuexen if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 3342283699Stuexen in6_sin6_2_sin(&sin_store, sin6); 3343283699Stuexen addr = (struct sockaddr *)&sin_store; 3344283699Stuexen } else { 3345283699Stuexen addr = (struct sockaddr *)&encaps->sue_address; 3346283699Stuexen } 3347283699Stuexen } else { 3348283699Stuexen addr = (struct sockaddr *)&encaps->sue_address; 3349283699Stuexen } 3350283699Stuexen#else 3351283699Stuexen addr = (struct sockaddr *)&encaps->sue_address; 3352283699Stuexen#endif 3353227755Stuexen if (stcb) { 3354283699Stuexen net = sctp_findnet(stcb, addr); 3355227755Stuexen } else { 3356227755Stuexen /* 3357227755Stuexen * We increment here since 3358227755Stuexen * sctp_findassociation_ep_addr() wil do a 3359227755Stuexen * decrement if it finds the stcb as long as 3360227755Stuexen * the locked tcb (last argument) is NOT a 3361227755Stuexen * TCB.. aka NULL. 3362227755Stuexen */ 3363227755Stuexen net = NULL; 3364227755Stuexen SCTP_INP_INCR_REF(inp); 3365283699Stuexen stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL); 3366227755Stuexen if (stcb == NULL) { 3367227755Stuexen SCTP_INP_DECR_REF(inp); 3368227755Stuexen } 3369227755Stuexen } 3370283699Stuexen if ((stcb != NULL) && (net == NULL)) { 3371227755Stuexen#ifdef INET 3372283699Stuexen if (addr->sa_family == AF_INET) { 3373227755Stuexen struct sockaddr_in *sin; 3374227755Stuexen 3375283699Stuexen sin = (struct sockaddr_in *)addr; 3376283699Stuexen if (sin->sin_addr.s_addr != INADDR_ANY) { 3377227755Stuexen error = EINVAL; 3378227755Stuexen SCTP_TCB_UNLOCK(stcb); 3379227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3380227755Stuexen break; 3381227755Stuexen } 3382227755Stuexen } else 3383227755Stuexen#endif 3384227755Stuexen#ifdef INET6 3385283699Stuexen if (addr->sa_family == AF_INET6) { 3386227755Stuexen struct sockaddr_in6 *sin6; 3387227755Stuexen 3388283699Stuexen sin6 = (struct sockaddr_in6 *)addr; 3389227755Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 3390227755Stuexen error = EINVAL; 3391227755Stuexen SCTP_TCB_UNLOCK(stcb); 3392227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3393227755Stuexen break; 3394227755Stuexen } 3395227755Stuexen } else 3396227755Stuexen#endif 3397227755Stuexen { 3398227755Stuexen error = EAFNOSUPPORT; 3399227755Stuexen SCTP_TCB_UNLOCK(stcb); 3400227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3401227755Stuexen break; 3402227755Stuexen } 3403227755Stuexen } 3404283699Stuexen if (stcb != NULL) { 3405227755Stuexen if (net) { 3406227755Stuexen encaps->sue_port = net->port; 3407227755Stuexen } else { 3408227755Stuexen encaps->sue_port = stcb->asoc.port; 3409227755Stuexen } 3410227755Stuexen SCTP_TCB_UNLOCK(stcb); 3411227755Stuexen } else { 3412227755Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3413227755Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3414227755Stuexen (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) { 3415227755Stuexen SCTP_INP_RLOCK(inp); 3416227755Stuexen encaps->sue_port = inp->sctp_ep.port; 3417227755Stuexen SCTP_INP_RUNLOCK(inp); 3418227755Stuexen } else { 3419227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3420227755Stuexen error = EINVAL; 3421227755Stuexen } 3422227755Stuexen } 3423227755Stuexen if (error == 0) { 3424258454Stuexen *optsize = sizeof(struct sctp_udpencaps); 3425227755Stuexen } 3426227755Stuexen break; 3427227755Stuexen } 3428270356Stuexen case SCTP_ECN_SUPPORTED: 3429270356Stuexen { 3430270356Stuexen struct sctp_assoc_value *av; 3431270356Stuexen 3432270356Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3433270356Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3434270356Stuexen 3435270356Stuexen if (stcb) { 3436270356Stuexen av->assoc_value = stcb->asoc.ecn_supported; 3437270356Stuexen SCTP_TCB_UNLOCK(stcb); 3438270356Stuexen } else { 3439270356Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3440270356Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3441270356Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3442270356Stuexen SCTP_INP_RLOCK(inp); 3443270356Stuexen av->assoc_value = inp->ecn_supported; 3444270356Stuexen SCTP_INP_RUNLOCK(inp); 3445270356Stuexen } else { 3446270356Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3447270356Stuexen error = EINVAL; 3448270356Stuexen } 3449270356Stuexen } 3450270356Stuexen if (error == 0) { 3451270356Stuexen *optsize = sizeof(struct sctp_assoc_value); 3452270356Stuexen } 3453270356Stuexen break; 3454270356Stuexen } 3455270357Stuexen case SCTP_PR_SUPPORTED: 3456270357Stuexen { 3457270357Stuexen struct sctp_assoc_value *av; 3458270357Stuexen 3459270357Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3460270357Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3461270357Stuexen 3462270357Stuexen if (stcb) { 3463270357Stuexen av->assoc_value = stcb->asoc.prsctp_supported; 3464270357Stuexen SCTP_TCB_UNLOCK(stcb); 3465270357Stuexen } else { 3466270357Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3467270357Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3468270357Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3469270357Stuexen SCTP_INP_RLOCK(inp); 3470270357Stuexen av->assoc_value = inp->prsctp_supported; 3471270357Stuexen SCTP_INP_RUNLOCK(inp); 3472270357Stuexen } else { 3473270357Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3474270357Stuexen error = EINVAL; 3475270357Stuexen } 3476270357Stuexen } 3477270357Stuexen if (error == 0) { 3478270357Stuexen *optsize = sizeof(struct sctp_assoc_value); 3479270357Stuexen } 3480270357Stuexen break; 3481270357Stuexen } 3482270362Stuexen case SCTP_AUTH_SUPPORTED: 3483270362Stuexen { 3484270362Stuexen struct sctp_assoc_value *av; 3485270362Stuexen 3486270362Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3487270362Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3488270362Stuexen 3489270362Stuexen if (stcb) { 3490270362Stuexen av->assoc_value = stcb->asoc.auth_supported; 3491270362Stuexen SCTP_TCB_UNLOCK(stcb); 3492270362Stuexen } else { 3493270362Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3494270362Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3495270362Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3496270362Stuexen SCTP_INP_RLOCK(inp); 3497270362Stuexen av->assoc_value = inp->auth_supported; 3498270362Stuexen SCTP_INP_RUNLOCK(inp); 3499270362Stuexen } else { 3500270362Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3501270362Stuexen error = EINVAL; 3502270362Stuexen } 3503270362Stuexen } 3504270362Stuexen if (error == 0) { 3505270362Stuexen *optsize = sizeof(struct sctp_assoc_value); 3506270362Stuexen } 3507270362Stuexen break; 3508270362Stuexen } 3509270362Stuexen case SCTP_ASCONF_SUPPORTED: 3510270362Stuexen { 3511270362Stuexen struct sctp_assoc_value *av; 3512270362Stuexen 3513270362Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3514270362Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3515270362Stuexen 3516270362Stuexen if (stcb) { 3517270362Stuexen av->assoc_value = stcb->asoc.asconf_supported; 3518270362Stuexen SCTP_TCB_UNLOCK(stcb); 3519270362Stuexen } else { 3520270362Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3521270362Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3522270362Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3523270362Stuexen SCTP_INP_RLOCK(inp); 3524270362Stuexen av->assoc_value = inp->asconf_supported; 3525270362Stuexen SCTP_INP_RUNLOCK(inp); 3526270362Stuexen } else { 3527270362Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3528270362Stuexen error = EINVAL; 3529270362Stuexen } 3530270362Stuexen } 3531270362Stuexen if (error == 0) { 3532270362Stuexen *optsize = sizeof(struct sctp_assoc_value); 3533270362Stuexen } 3534270362Stuexen break; 3535270362Stuexen } 3536270361Stuexen case SCTP_RECONFIG_SUPPORTED: 3537270361Stuexen { 3538270361Stuexen struct sctp_assoc_value *av; 3539270361Stuexen 3540270361Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3541270361Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3542270361Stuexen 3543270361Stuexen if (stcb) { 3544270361Stuexen av->assoc_value = stcb->asoc.reconfig_supported; 3545270361Stuexen SCTP_TCB_UNLOCK(stcb); 3546270361Stuexen } else { 3547270361Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3548270361Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3549270361Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3550270361Stuexen SCTP_INP_RLOCK(inp); 3551270361Stuexen av->assoc_value = inp->reconfig_supported; 3552270361Stuexen SCTP_INP_RUNLOCK(inp); 3553270361Stuexen } else { 3554270361Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3555270361Stuexen error = EINVAL; 3556270361Stuexen } 3557270361Stuexen } 3558270361Stuexen if (error == 0) { 3559270361Stuexen *optsize = sizeof(struct sctp_assoc_value); 3560270361Stuexen } 3561270361Stuexen break; 3562270361Stuexen } 3563270359Stuexen case SCTP_NRSACK_SUPPORTED: 3564270359Stuexen { 3565270359Stuexen struct sctp_assoc_value *av; 3566270359Stuexen 3567270359Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3568270359Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3569270359Stuexen 3570270359Stuexen if (stcb) { 3571270359Stuexen av->assoc_value = stcb->asoc.nrsack_supported; 3572270359Stuexen SCTP_TCB_UNLOCK(stcb); 3573270359Stuexen } else { 3574270359Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3575270359Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3576270359Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3577270359Stuexen SCTP_INP_RLOCK(inp); 3578270359Stuexen av->assoc_value = inp->nrsack_supported; 3579270359Stuexen SCTP_INP_RUNLOCK(inp); 3580270359Stuexen } else { 3581270359Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3582270359Stuexen error = EINVAL; 3583270359Stuexen } 3584270359Stuexen } 3585270359Stuexen if (error == 0) { 3586270359Stuexen *optsize = sizeof(struct sctp_assoc_value); 3587270359Stuexen } 3588270359Stuexen break; 3589270359Stuexen } 3590270360Stuexen case SCTP_PKTDROP_SUPPORTED: 3591270360Stuexen { 3592270360Stuexen struct sctp_assoc_value *av; 3593270360Stuexen 3594270360Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3595270360Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3596270360Stuexen 3597270360Stuexen if (stcb) { 3598270360Stuexen av->assoc_value = stcb->asoc.pktdrop_supported; 3599270360Stuexen SCTP_TCB_UNLOCK(stcb); 3600270360Stuexen } else { 3601270360Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3602270360Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3603270360Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3604270360Stuexen SCTP_INP_RLOCK(inp); 3605270360Stuexen av->assoc_value = inp->pktdrop_supported; 3606270360Stuexen SCTP_INP_RUNLOCK(inp); 3607270360Stuexen } else { 3608270360Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3609270360Stuexen error = EINVAL; 3610270360Stuexen } 3611270360Stuexen } 3612270360Stuexen if (error == 0) { 3613270360Stuexen *optsize = sizeof(struct sctp_assoc_value); 3614270360Stuexen } 3615270360Stuexen break; 3616270360Stuexen } 3617235021Stuexen case SCTP_ENABLE_STREAM_RESET: 3618235021Stuexen { 3619235021Stuexen struct sctp_assoc_value *av; 3620235021Stuexen 3621235021Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3622235021Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3623235021Stuexen 3624235021Stuexen if (stcb) { 3625235021Stuexen av->assoc_value = (uint32_t) stcb->asoc.local_strreset_support; 3626235021Stuexen SCTP_TCB_UNLOCK(stcb); 3627235021Stuexen } else { 3628235021Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3629235021Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3630235021Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3631235021Stuexen SCTP_INP_RLOCK(inp); 3632235021Stuexen av->assoc_value = (uint32_t) inp->local_strreset_support; 3633235021Stuexen SCTP_INP_RUNLOCK(inp); 3634235021Stuexen } else { 3635235021Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3636235021Stuexen error = EINVAL; 3637235021Stuexen } 3638235021Stuexen } 3639235021Stuexen if (error == 0) { 3640235021Stuexen *optsize = sizeof(struct sctp_assoc_value); 3641235021Stuexen } 3642235021Stuexen break; 3643235021Stuexen } 3644270363Stuexen case SCTP_PR_STREAM_STATUS: 3645270363Stuexen { 3646270363Stuexen struct sctp_prstatus *sprstat; 3647270363Stuexen uint16_t sid; 3648270363Stuexen uint16_t policy; 3649270363Stuexen 3650270363Stuexen SCTP_CHECK_AND_CAST(sprstat, optval, struct sctp_prstatus, *optsize); 3651270363Stuexen SCTP_FIND_STCB(inp, stcb, sprstat->sprstat_assoc_id); 3652270363Stuexen 3653270363Stuexen sid = sprstat->sprstat_sid; 3654270363Stuexen policy = sprstat->sprstat_policy; 3655270363Stuexen#if defined(SCTP_DETAILED_STR_STATS) 3656270363Stuexen if ((stcb != NULL) && 3657283706Stuexen (sid < stcb->asoc.streamoutcnt) && 3658270363Stuexen (policy != SCTP_PR_SCTP_NONE) && 3659283706Stuexen ((policy <= SCTP_PR_SCTP_MAX) || 3660283706Stuexen (policy == SCTP_PR_SCTP_ALL))) { 3661270363Stuexen if (policy == SCTP_PR_SCTP_ALL) { 3662270363Stuexen sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[0]; 3663270363Stuexen sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[0]; 3664270363Stuexen } else { 3665270363Stuexen sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[policy]; 3666270363Stuexen sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[policy]; 3667270363Stuexen } 3668283705Stuexen#else 3669283705Stuexen if ((stcb != NULL) && 3670283706Stuexen (sid < stcb->asoc.streamoutcnt) && 3671283706Stuexen (policy == SCTP_PR_SCTP_ALL)) { 3672283705Stuexen sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[0]; 3673283705Stuexen sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[0]; 3674283705Stuexen#endif 3675270363Stuexen SCTP_TCB_UNLOCK(stcb); 3676270363Stuexen *optsize = sizeof(struct sctp_prstatus); 3677270363Stuexen } else { 3678270363Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3679270363Stuexen error = EINVAL; 3680270363Stuexen } 3681270363Stuexen break; 3682270363Stuexen } 3683270363Stuexen case SCTP_PR_ASSOC_STATUS: 3684270363Stuexen { 3685270363Stuexen struct sctp_prstatus *sprstat; 3686270363Stuexen uint16_t policy; 3687270363Stuexen 3688270363Stuexen SCTP_CHECK_AND_CAST(sprstat, optval, struct sctp_prstatus, *optsize); 3689270363Stuexen SCTP_FIND_STCB(inp, stcb, sprstat->sprstat_assoc_id); 3690270363Stuexen 3691270363Stuexen policy = sprstat->sprstat_policy; 3692270363Stuexen if ((stcb != NULL) && 3693270363Stuexen (policy != SCTP_PR_SCTP_NONE) && 3694283706Stuexen ((policy <= SCTP_PR_SCTP_MAX) || 3695283706Stuexen (policy == SCTP_PR_SCTP_ALL))) { 3696270363Stuexen if (policy == SCTP_PR_SCTP_ALL) { 3697270363Stuexen sprstat->sprstat_abandoned_unsent = stcb->asoc.abandoned_unsent[0]; 3698270363Stuexen sprstat->sprstat_abandoned_sent = stcb->asoc.abandoned_sent[0]; 3699270363Stuexen } else { 3700270363Stuexen sprstat->sprstat_abandoned_unsent = stcb->asoc.abandoned_unsent[policy]; 3701270363Stuexen sprstat->sprstat_abandoned_sent = stcb->asoc.abandoned_sent[policy]; 3702270363Stuexen } 3703270363Stuexen SCTP_TCB_UNLOCK(stcb); 3704270363Stuexen *optsize = sizeof(struct sctp_prstatus); 3705270363Stuexen } else { 3706270363Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3707270363Stuexen error = EINVAL; 3708270363Stuexen } 3709270363Stuexen break; 3710270363Stuexen } 3711283724Stuexen case SCTP_MAX_CWND: 3712283724Stuexen { 3713283724Stuexen struct sctp_assoc_value *av; 3714283724Stuexen 3715283724Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3716283724Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3717283724Stuexen 3718283724Stuexen if (stcb) { 3719283724Stuexen av->assoc_value = stcb->asoc.max_cwnd; 3720283724Stuexen SCTP_TCB_UNLOCK(stcb); 3721283724Stuexen } else { 3722283724Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3723283724Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3724283724Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3725283724Stuexen SCTP_INP_RLOCK(inp); 3726283724Stuexen av->assoc_value = inp->max_cwnd; 3727283724Stuexen SCTP_INP_RUNLOCK(inp); 3728283724Stuexen } else { 3729283724Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3730283724Stuexen error = EINVAL; 3731283724Stuexen } 3732283724Stuexen } 3733283724Stuexen if (error == 0) { 3734283724Stuexen *optsize = sizeof(struct sctp_assoc_value); 3735283724Stuexen } 3736283724Stuexen break; 3737283724Stuexen } 3738163953Srrs default: 3739171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 3740163953Srrs error = ENOPROTOOPT; 3741163953Srrs break; 3742163953Srrs } /* end switch (sopt->sopt_name) */ 3743223132Stuexen if (error) { 3744223132Stuexen *optsize = 0; 3745223132Stuexen } 3746163953Srrs return (error); 3747163953Srrs} 3748163953Srrs 3749163953Srrsstatic int 3750166675Srrssctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, 3751166675Srrs void *p) 3752163953Srrs{ 3753166675Srrs int error, set_opt; 3754166675Srrs uint32_t *mopt; 3755163953Srrs struct sctp_tcb *stcb = NULL; 3756171943Srrs struct sctp_inpcb *inp = NULL; 3757167598Srrs uint32_t vrf_id; 3758163953Srrs 3759166675Srrs if (optval == NULL) { 3760169420Srrs SCTP_PRINTF("optval is NULL\n"); 3761171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3762163953Srrs return (EINVAL); 3763163953Srrs } 3764163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3765233005Stuexen if (inp == NULL) { 3766169420Srrs SCTP_PRINTF("inp is NULL?\n"); 3767171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3768228907Stuexen return (EINVAL); 3769167598Srrs } 3770168299Srrs vrf_id = inp->def_vrf_id; 3771163953Srrs 3772163953Srrs error = 0; 3773166675Srrs switch (optname) { 3774163953Srrs case SCTP_NODELAY: 3775163953Srrs case SCTP_AUTOCLOSE: 3776163953Srrs case SCTP_AUTO_ASCONF: 3777163953Srrs case SCTP_EXPLICIT_EOR: 3778163953Srrs case SCTP_DISABLE_FRAGMENTS: 3779163953Srrs case SCTP_USE_EXT_RCVINFO: 3780163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 3781163953Srrs /* copy in the option value */ 3782166675Srrs SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); 3783163953Srrs set_opt = 0; 3784163953Srrs if (error) 3785163953Srrs break; 3786166675Srrs switch (optname) { 3787163953Srrs case SCTP_DISABLE_FRAGMENTS: 3788163953Srrs set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT; 3789163953Srrs break; 3790163953Srrs case SCTP_AUTO_ASCONF: 3791171943Srrs /* 3792171943Srrs * NOTE: we don't really support this flag 3793171943Srrs */ 3794171943Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 3795171943Srrs /* only valid for bound all sockets */ 3796224641Stuexen if ((SCTP_BASE_SYSCTL(sctp_auto_asconf) == 0) && 3797224641Stuexen (*mopt != 0)) { 3798224641Stuexen /* forbidden by admin */ 3799224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM); 3800224641Stuexen return (EPERM); 3801224641Stuexen } 3802171943Srrs set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF; 3803171943Srrs } else { 3804171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3805171943Srrs return (EINVAL); 3806171943Srrs } 3807163953Srrs break; 3808163953Srrs case SCTP_EXPLICIT_EOR: 3809163953Srrs set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR; 3810163953Srrs break; 3811163953Srrs case SCTP_USE_EXT_RCVINFO: 3812163953Srrs set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO; 3813163953Srrs break; 3814163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 3815163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 3816163953Srrs set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4; 3817163953Srrs } else { 3818171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3819163953Srrs return (EINVAL); 3820163953Srrs } 3821163953Srrs break; 3822163953Srrs case SCTP_NODELAY: 3823163953Srrs set_opt = SCTP_PCB_FLAGS_NODELAY; 3824163953Srrs break; 3825163953Srrs case SCTP_AUTOCLOSE: 3826170056Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3827170056Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 3828171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3829170056Srrs return (EINVAL); 3830170056Srrs } 3831163953Srrs set_opt = SCTP_PCB_FLAGS_AUTOCLOSE; 3832163953Srrs /* 3833163953Srrs * The value is in ticks. Note this does not effect 3834163953Srrs * old associations, only new ones. 3835163953Srrs */ 3836163953Srrs inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt); 3837163953Srrs break; 3838163953Srrs } 3839163953Srrs SCTP_INP_WLOCK(inp); 3840163953Srrs if (*mopt != 0) { 3841163953Srrs sctp_feature_on(inp, set_opt); 3842163953Srrs } else { 3843163953Srrs sctp_feature_off(inp, set_opt); 3844163953Srrs } 3845163953Srrs SCTP_INP_WUNLOCK(inp); 3846163953Srrs break; 3847181054Srrs case SCTP_REUSE_PORT: 3848181054Srrs { 3849181054Srrs SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); 3850181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) { 3851181054Srrs /* Can't set it after we are bound */ 3852181054Srrs error = EINVAL; 3853181054Srrs break; 3854181054Srrs } 3855181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) { 3856181054Srrs /* Can't do this for a 1-m socket */ 3857181054Srrs error = EINVAL; 3858181054Srrs break; 3859181054Srrs } 3860181054Srrs if (optval) 3861181054Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE); 3862181054Srrs else 3863181054Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE); 3864223132Stuexen break; 3865181054Srrs } 3866163953Srrs case SCTP_PARTIAL_DELIVERY_POINT: 3867163953Srrs { 3868166675Srrs uint32_t *value; 3869166675Srrs 3870166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); 3871167736Srrs if (*value > SCTP_SB_LIMIT_RCV(so)) { 3872171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3873167736Srrs error = EINVAL; 3874167736Srrs break; 3875167736Srrs } 3876166675Srrs inp->partial_delivery_point = *value; 3877223132Stuexen break; 3878163953Srrs } 3879163953Srrs case SCTP_FRAGMENT_INTERLEAVE: 3880163953Srrs /* not yet until we re-write sctp_recvmsg() */ 3881163953Srrs { 3882168943Srrs uint32_t *level; 3883163953Srrs 3884168943Srrs SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize); 3885168943Srrs if (*level == SCTP_FRAG_LEVEL_2) { 3886163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 3887168943Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 3888168943Srrs } else if (*level == SCTP_FRAG_LEVEL_1) { 3889168943Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 3890168943Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 3891168943Srrs } else if (*level == SCTP_FRAG_LEVEL_0) { 3892170056Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 3893168943Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 3894168943Srrs 3895163953Srrs } else { 3896171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3897168943Srrs error = EINVAL; 3898163953Srrs } 3899223132Stuexen break; 3900163953Srrs } 3901163953Srrs case SCTP_CMT_ON_OFF: 3902211944Stuexen if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { 3903163953Srrs struct sctp_assoc_value *av; 3904163953Srrs 3905166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 3906223132Stuexen if (av->assoc_value > SCTP_CMT_MAX) { 3907223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3908223132Stuexen error = EINVAL; 3909223132Stuexen break; 3910223132Stuexen } 3911211944Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3912211944Stuexen if (stcb) { 3913223132Stuexen stcb->asoc.sctp_cmt_on_off = av->assoc_value; 3914211944Stuexen SCTP_TCB_UNLOCK(stcb); 3915166675Srrs } else { 3916224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3917224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3918224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 3919223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3920221460Stuexen SCTP_INP_WLOCK(inp); 3921221460Stuexen inp->sctp_cmt_on_off = av->assoc_value; 3922221460Stuexen SCTP_INP_WUNLOCK(inp); 3923216669Stuexen } 3924223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 3925223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3926223132Stuexen SCTP_INP_RLOCK(inp); 3927223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3928223132Stuexen SCTP_TCB_LOCK(stcb); 3929223132Stuexen stcb->asoc.sctp_cmt_on_off = av->assoc_value; 3930223132Stuexen SCTP_TCB_UNLOCK(stcb); 3931223132Stuexen } 3932224918Stuexen SCTP_INP_RUNLOCK(inp); 3933223132Stuexen } 3934163953Srrs } 3935211944Stuexen } else { 3936211944Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 3937211944Stuexen error = ENOPROTOOPT; 3938163953Srrs } 3939163953Srrs break; 3940171440Srrs case SCTP_PLUGGABLE_CC: 3941171440Srrs { 3942171440Srrs struct sctp_assoc_value *av; 3943219057Srrs struct sctp_nets *net; 3944171440Srrs 3945171440Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 3946223132Stuexen if ((av->assoc_value != SCTP_CC_RFC2581) && 3947223132Stuexen (av->assoc_value != SCTP_CC_HSTCP) && 3948223132Stuexen (av->assoc_value != SCTP_CC_HTCP) && 3949223132Stuexen (av->assoc_value != SCTP_CC_RTCC)) { 3950223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3951223132Stuexen error = EINVAL; 3952223132Stuexen break; 3953223132Stuexen } 3954171440Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3955171440Srrs if (stcb) { 3956223132Stuexen stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value]; 3957223132Stuexen stcb->asoc.congestion_control_module = av->assoc_value; 3958223132Stuexen if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) { 3959223132Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3960223132Stuexen stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); 3961219057Srrs } 3962171440Srrs } 3963217611Stuexen SCTP_TCB_UNLOCK(stcb); 3964171440Srrs } else { 3965224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3966224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3967224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 3968223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3969217611Stuexen SCTP_INP_WLOCK(inp); 3970171440Srrs inp->sctp_ep.sctp_default_cc_module = av->assoc_value; 3971217611Stuexen SCTP_INP_WUNLOCK(inp); 3972217760Stuexen } 3973223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 3974223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3975223132Stuexen SCTP_INP_RLOCK(inp); 3976223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3977223132Stuexen SCTP_TCB_LOCK(stcb); 3978223132Stuexen stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value]; 3979223132Stuexen stcb->asoc.congestion_control_module = av->assoc_value; 3980223132Stuexen if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) { 3981223132Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3982223132Stuexen stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); 3983223132Stuexen } 3984223132Stuexen } 3985223132Stuexen SCTP_TCB_UNLOCK(stcb); 3986223132Stuexen } 3987223132Stuexen SCTP_INP_RUNLOCK(inp); 3988223132Stuexen } 3989171440Srrs } 3990223132Stuexen break; 3991171440Srrs } 3992219057Srrs case SCTP_CC_OPTION: 3993219057Srrs { 3994219057Srrs struct sctp_cc_option *cc_opt; 3995219057Srrs 3996219057Srrs SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, optsize); 3997219057Srrs SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id); 3998219057Srrs if (stcb == NULL) { 3999223132Stuexen if (cc_opt->aid_value.assoc_id == SCTP_CURRENT_ASSOC) { 4000223132Stuexen SCTP_INP_RLOCK(inp); 4001223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4002223132Stuexen SCTP_TCB_LOCK(stcb); 4003223132Stuexen if (stcb->asoc.cc_functions.sctp_cwnd_socket_option) { 4004223132Stuexen (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1, cc_opt); 4005223132Stuexen } 4006223132Stuexen SCTP_TCB_UNLOCK(stcb); 4007223132Stuexen } 4008223132Stuexen SCTP_INP_RUNLOCK(inp); 4009223132Stuexen } else { 4010223132Stuexen error = EINVAL; 4011223132Stuexen } 4012219057Srrs } else { 4013219057Srrs if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) { 4014219057Srrs error = ENOTSUP; 4015219057Srrs } else { 4016219057Srrs error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1, 4017219057Srrs cc_opt); 4018219057Srrs } 4019219057Srrs SCTP_TCB_UNLOCK(stcb); 4020219057Srrs } 4021223132Stuexen break; 4022219057Srrs } 4023217760Stuexen case SCTP_PLUGGABLE_SS: 4024217760Stuexen { 4025217760Stuexen struct sctp_assoc_value *av; 4026217760Stuexen 4027217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 4028223132Stuexen if ((av->assoc_value != SCTP_SS_DEFAULT) && 4029223132Stuexen (av->assoc_value != SCTP_SS_ROUND_ROBIN) && 4030223132Stuexen (av->assoc_value != SCTP_SS_ROUND_ROBIN_PACKET) && 4031223132Stuexen (av->assoc_value != SCTP_SS_PRIORITY) && 4032223132Stuexen (av->assoc_value != SCTP_SS_FAIR_BANDWITH) && 4033223132Stuexen (av->assoc_value != SCTP_SS_FIRST_COME)) { 4034223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4035223132Stuexen error = EINVAL; 4036223132Stuexen break; 4037223132Stuexen } 4038217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4039217760Stuexen if (stcb) { 4040223132Stuexen stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1); 4041223132Stuexen stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value]; 4042223132Stuexen stcb->asoc.stream_scheduling_module = av->assoc_value; 4043223132Stuexen stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1); 4044217760Stuexen SCTP_TCB_UNLOCK(stcb); 4045217760Stuexen } else { 4046224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4047224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4048224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 4049223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 4050217760Stuexen SCTP_INP_WLOCK(inp); 4051217760Stuexen inp->sctp_ep.sctp_default_ss_module = av->assoc_value; 4052217760Stuexen SCTP_INP_WUNLOCK(inp); 4053217760Stuexen } 4054223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 4055223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 4056223132Stuexen SCTP_INP_RLOCK(inp); 4057223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4058223132Stuexen SCTP_TCB_LOCK(stcb); 4059223132Stuexen stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1); 4060223132Stuexen stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value]; 4061223132Stuexen stcb->asoc.stream_scheduling_module = av->assoc_value; 4062223132Stuexen stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1); 4063223132Stuexen SCTP_TCB_UNLOCK(stcb); 4064223132Stuexen } 4065223132Stuexen SCTP_INP_RUNLOCK(inp); 4066223132Stuexen } 4067217760Stuexen } 4068223132Stuexen break; 4069217760Stuexen } 4070217760Stuexen case SCTP_SS_VALUE: 4071217760Stuexen { 4072217760Stuexen struct sctp_stream_value *av; 4073217760Stuexen 4074217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize); 4075217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4076217760Stuexen if (stcb) { 4077277807Sdelphij if ((av->stream_id >= stcb->asoc.streamoutcnt) || 4078277807Sdelphij (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], 4079277807Sdelphij av->stream_value) < 0)) { 4080217760Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4081217760Stuexen error = EINVAL; 4082217760Stuexen } 4083217760Stuexen SCTP_TCB_UNLOCK(stcb); 4084217760Stuexen } else { 4085223132Stuexen if (av->assoc_id == SCTP_CURRENT_ASSOC) { 4086223132Stuexen SCTP_INP_RLOCK(inp); 4087223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4088223132Stuexen SCTP_TCB_LOCK(stcb); 4089277807Sdelphij if (av->stream_id < stcb->asoc.streamoutcnt) { 4090277807Sdelphij stcb->asoc.ss_functions.sctp_ss_set_value(stcb, 4091277807Sdelphij &stcb->asoc, 4092277807Sdelphij &stcb->asoc.strmout[av->stream_id], 4093277807Sdelphij av->stream_value); 4094277807Sdelphij } 4095223132Stuexen SCTP_TCB_UNLOCK(stcb); 4096223132Stuexen } 4097223132Stuexen SCTP_INP_RUNLOCK(inp); 4098223132Stuexen } else { 4099223132Stuexen /* 4100223132Stuexen * Can't set stream value without 4101223132Stuexen * association 4102223132Stuexen */ 4103223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4104223132Stuexen error = EINVAL; 4105223132Stuexen } 4106217760Stuexen } 4107223132Stuexen break; 4108217760Stuexen } 4109163953Srrs case SCTP_CLR_STAT_LOG: 4110171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4111163953Srrs error = EOPNOTSUPP; 4112163953Srrs break; 4113163953Srrs case SCTP_CONTEXT: 4114163953Srrs { 4115163953Srrs struct sctp_assoc_value *av; 4116163953Srrs 4117166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 4118166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4119166675Srrs 4120166675Srrs if (stcb) { 4121166675Srrs stcb->asoc.context = av->assoc_value; 4122166675Srrs SCTP_TCB_UNLOCK(stcb); 4123163953Srrs } else { 4124224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4125224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4126224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 4127223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 4128223132Stuexen SCTP_INP_WLOCK(inp); 4129223132Stuexen inp->sctp_context = av->assoc_value; 4130223132Stuexen SCTP_INP_WUNLOCK(inp); 4131223132Stuexen } 4132223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 4133223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 4134223132Stuexen SCTP_INP_RLOCK(inp); 4135223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4136223132Stuexen SCTP_TCB_LOCK(stcb); 4137223132Stuexen stcb->asoc.context = av->assoc_value; 4138223132Stuexen SCTP_TCB_UNLOCK(stcb); 4139223132Stuexen } 4140223132Stuexen SCTP_INP_RUNLOCK(inp); 4141223132Stuexen } 4142163953Srrs } 4143223132Stuexen break; 4144163953Srrs } 4145167598Srrs case SCTP_VRF_ID: 4146167598Srrs { 4147170056Srrs uint32_t *default_vrfid; 4148167598Srrs 4149170056Srrs SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize); 4150170056Srrs if (*default_vrfid > SCTP_MAX_VRF_ID) { 4151171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4152167598Srrs error = EINVAL; 4153167598Srrs break; 4154167598Srrs } 4155170056Srrs inp->def_vrf_id = *default_vrfid; 4156167598Srrs break; 4157167598Srrs } 4158167598Srrs case SCTP_DEL_VRF_ID: 4159167598Srrs { 4160171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4161167598Srrs error = EOPNOTSUPP; 4162167598Srrs break; 4163167598Srrs } 4164167598Srrs case SCTP_ADD_VRF_ID: 4165167598Srrs { 4166171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4167167598Srrs error = EOPNOTSUPP; 4168167598Srrs break; 4169167598Srrs } 4170170056Srrs case SCTP_DELAYED_SACK: 4171163953Srrs { 4172170056Srrs struct sctp_sack_info *sack; 4173163953Srrs 4174170056Srrs SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize); 4175170056Srrs SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); 4176171477Srrs if (sack->sack_delay) { 4177171477Srrs if (sack->sack_delay > SCTP_MAX_SACK_DELAY) 4178171477Srrs sack->sack_delay = SCTP_MAX_SACK_DELAY; 4179223132Stuexen if (MSEC_TO_TICKS(sack->sack_delay) < 1) { 4180223132Stuexen sack->sack_delay = TICKS_TO_MSEC(1); 4181223132Stuexen } 4182171477Srrs } 4183166675Srrs if (stcb) { 4184170056Srrs if (sack->sack_delay) { 4185170056Srrs stcb->asoc.delayed_ack = sack->sack_delay; 4186170056Srrs } 4187170056Srrs if (sack->sack_freq) { 4188170056Srrs stcb->asoc.sack_freq = sack->sack_freq; 4189170056Srrs } 4190166675Srrs SCTP_TCB_UNLOCK(stcb); 4191166675Srrs } else { 4192224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4193224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4194224918Stuexen (sack->sack_assoc_id == SCTP_FUTURE_ASSOC) || 4195223132Stuexen (sack->sack_assoc_id == SCTP_ALL_ASSOC)) { 4196223132Stuexen SCTP_INP_WLOCK(inp); 4197223132Stuexen if (sack->sack_delay) { 4198223132Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay); 4199170056Srrs } 4200223132Stuexen if (sack->sack_freq) { 4201223132Stuexen inp->sctp_ep.sctp_sack_freq = sack->sack_freq; 4202223132Stuexen } 4203223132Stuexen SCTP_INP_WUNLOCK(inp); 4204170056Srrs } 4205223132Stuexen if ((sack->sack_assoc_id == SCTP_CURRENT_ASSOC) || 4206223132Stuexen (sack->sack_assoc_id == SCTP_ALL_ASSOC)) { 4207223132Stuexen SCTP_INP_RLOCK(inp); 4208223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4209223132Stuexen SCTP_TCB_LOCK(stcb); 4210223132Stuexen if (sack->sack_delay) { 4211223132Stuexen stcb->asoc.delayed_ack = sack->sack_delay; 4212223132Stuexen } 4213223132Stuexen if (sack->sack_freq) { 4214223132Stuexen stcb->asoc.sack_freq = sack->sack_freq; 4215223132Stuexen } 4216223132Stuexen SCTP_TCB_UNLOCK(stcb); 4217223132Stuexen } 4218223132Stuexen SCTP_INP_RUNLOCK(inp); 4219170056Srrs } 4220163953Srrs } 4221166675Srrs break; 4222163953Srrs } 4223163953Srrs case SCTP_AUTH_CHUNK: 4224163953Srrs { 4225163953Srrs struct sctp_authchunk *sauth; 4226163953Srrs 4227166675Srrs SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize); 4228166675Srrs 4229166675Srrs SCTP_INP_WLOCK(inp); 4230171943Srrs if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) { 4231171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4232163953Srrs error = EINVAL; 4233171943Srrs } 4234166675Srrs SCTP_INP_WUNLOCK(inp); 4235163953Srrs break; 4236163953Srrs } 4237163953Srrs case SCTP_AUTH_KEY: 4238163953Srrs { 4239163953Srrs struct sctp_authkey *sca; 4240163953Srrs struct sctp_keyhead *shared_keys; 4241163953Srrs sctp_sharedkey_t *shared_key; 4242163953Srrs sctp_key_t *key = NULL; 4243166675Srrs size_t size; 4244163953Srrs 4245166675Srrs SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize); 4246223697Stuexen if (sca->sca_keylength == 0) { 4247223697Stuexen size = optsize - sizeof(struct sctp_authkey); 4248223697Stuexen } else { 4249223697Stuexen if (sca->sca_keylength + sizeof(struct sctp_authkey) <= optsize) { 4250223697Stuexen size = sca->sca_keylength; 4251223697Stuexen } else { 4252223697Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4253223697Stuexen error = EINVAL; 4254223697Stuexen break; 4255223697Stuexen } 4256223697Stuexen } 4257169420Srrs SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id); 4258166675Srrs 4259166675Srrs if (stcb) { 4260163953Srrs shared_keys = &stcb->asoc.shared_keys; 4261163953Srrs /* clear the cached keys for this key id */ 4262163953Srrs sctp_clear_cachedkeys(stcb, sca->sca_keynumber); 4263163953Srrs /* 4264163953Srrs * create the new shared key and 4265163953Srrs * insert/replace it 4266163953Srrs */ 4267163953Srrs if (size > 0) { 4268163953Srrs key = sctp_set_key(sca->sca_key, (uint32_t) size); 4269163953Srrs if (key == NULL) { 4270171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 4271163953Srrs error = ENOMEM; 4272163953Srrs SCTP_TCB_UNLOCK(stcb); 4273163953Srrs break; 4274163953Srrs } 4275163953Srrs } 4276163953Srrs shared_key = sctp_alloc_sharedkey(); 4277163953Srrs if (shared_key == NULL) { 4278163953Srrs sctp_free_key(key); 4279171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 4280163953Srrs error = ENOMEM; 4281163953Srrs SCTP_TCB_UNLOCK(stcb); 4282163953Srrs break; 4283163953Srrs } 4284163953Srrs shared_key->key = key; 4285163953Srrs shared_key->keyid = sca->sca_keynumber; 4286185694Srrs error = sctp_insert_sharedkey(shared_keys, shared_key); 4287163953Srrs SCTP_TCB_UNLOCK(stcb); 4288163953Srrs } else { 4289224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4290224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4291224918Stuexen (sca->sca_assoc_id == SCTP_FUTURE_ASSOC) || 4292223132Stuexen (sca->sca_assoc_id == SCTP_ALL_ASSOC)) { 4293223132Stuexen SCTP_INP_WLOCK(inp); 4294223132Stuexen shared_keys = &inp->sctp_ep.shared_keys; 4295223132Stuexen /* 4296223132Stuexen * clear the cached keys on all 4297223132Stuexen * assocs for this key id 4298223132Stuexen */ 4299223132Stuexen sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber); 4300223132Stuexen /* 4301223132Stuexen * create the new shared key and 4302223132Stuexen * insert/replace it 4303223132Stuexen */ 4304223132Stuexen if (size > 0) { 4305223132Stuexen key = sctp_set_key(sca->sca_key, (uint32_t) size); 4306223132Stuexen if (key == NULL) { 4307223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 4308223132Stuexen error = ENOMEM; 4309223132Stuexen SCTP_INP_WUNLOCK(inp); 4310223132Stuexen break; 4311223132Stuexen } 4312223132Stuexen } 4313223132Stuexen shared_key = sctp_alloc_sharedkey(); 4314223132Stuexen if (shared_key == NULL) { 4315223132Stuexen sctp_free_key(key); 4316171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 4317163953Srrs error = ENOMEM; 4318163953Srrs SCTP_INP_WUNLOCK(inp); 4319163953Srrs break; 4320163953Srrs } 4321223132Stuexen shared_key->key = key; 4322223132Stuexen shared_key->keyid = sca->sca_keynumber; 4323223132Stuexen error = sctp_insert_sharedkey(shared_keys, shared_key); 4324163953Srrs SCTP_INP_WUNLOCK(inp); 4325163953Srrs } 4326223132Stuexen if ((sca->sca_assoc_id == SCTP_CURRENT_ASSOC) || 4327223132Stuexen (sca->sca_assoc_id == SCTP_ALL_ASSOC)) { 4328223132Stuexen SCTP_INP_RLOCK(inp); 4329223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4330223132Stuexen SCTP_TCB_LOCK(stcb); 4331223132Stuexen shared_keys = &stcb->asoc.shared_keys; 4332223132Stuexen /* 4333223132Stuexen * clear the cached keys for 4334223132Stuexen * this key id 4335223132Stuexen */ 4336223132Stuexen sctp_clear_cachedkeys(stcb, sca->sca_keynumber); 4337223132Stuexen /* 4338223132Stuexen * create the new shared key 4339223132Stuexen * and insert/replace it 4340223132Stuexen */ 4341223132Stuexen if (size > 0) { 4342223132Stuexen key = sctp_set_key(sca->sca_key, (uint32_t) size); 4343223132Stuexen if (key == NULL) { 4344223132Stuexen SCTP_TCB_UNLOCK(stcb); 4345223132Stuexen continue; 4346223132Stuexen } 4347223132Stuexen } 4348223132Stuexen shared_key = sctp_alloc_sharedkey(); 4349223132Stuexen if (shared_key == NULL) { 4350223132Stuexen sctp_free_key(key); 4351223132Stuexen SCTP_TCB_UNLOCK(stcb); 4352223132Stuexen continue; 4353223132Stuexen } 4354223132Stuexen shared_key->key = key; 4355223132Stuexen shared_key->keyid = sca->sca_keynumber; 4356223132Stuexen error = sctp_insert_sharedkey(shared_keys, shared_key); 4357223132Stuexen SCTP_TCB_UNLOCK(stcb); 4358223132Stuexen } 4359223132Stuexen SCTP_INP_RUNLOCK(inp); 4360223132Stuexen } 4361163953Srrs } 4362163953Srrs break; 4363163953Srrs } 4364163953Srrs case SCTP_HMAC_IDENT: 4365163953Srrs { 4366163953Srrs struct sctp_hmacalgo *shmac; 4367163953Srrs sctp_hmaclist_t *hmaclist; 4368181054Srrs uint16_t hmacid; 4369181054Srrs uint32_t i; 4370181054Srrs 4371166675Srrs SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize); 4372271750Stuexen if ((optsize < sizeof(struct sctp_hmacalgo) + shmac->shmac_number_of_idents * sizeof(uint16_t)) || 4373271750Stuexen (shmac->shmac_number_of_idents > 0xffff)) { 4374181054Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4375181054Srrs error = EINVAL; 4376181054Srrs break; 4377181054Srrs } 4378271750Stuexen hmaclist = sctp_alloc_hmaclist((uint16_t) shmac->shmac_number_of_idents); 4379163953Srrs if (hmaclist == NULL) { 4380171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 4381163953Srrs error = ENOMEM; 4382163953Srrs break; 4383163953Srrs } 4384181054Srrs for (i = 0; i < shmac->shmac_number_of_idents; i++) { 4385163953Srrs hmacid = shmac->shmac_idents[i]; 4386181054Srrs if (sctp_auth_add_hmacid(hmaclist, hmacid)) { 4387163953Srrs /* invalid HMACs were found */ ; 4388171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4389163953Srrs error = EINVAL; 4390164085Srrs sctp_free_hmaclist(hmaclist); 4391163953Srrs goto sctp_set_hmac_done; 4392163953Srrs } 4393163953Srrs } 4394170056Srrs for (i = 0; i < hmaclist->num_algo; i++) { 4395170056Srrs if (hmaclist->hmac[i] == SCTP_AUTH_HMAC_ID_SHA1) { 4396170056Srrs /* already in list */ 4397253858Stuexen break; 4398170056Srrs } 4399170056Srrs } 4400253858Stuexen if (i == hmaclist->num_algo) { 4401253858Stuexen /* not found in list */ 4402170056Srrs sctp_free_hmaclist(hmaclist); 4403171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4404170056Srrs error = EINVAL; 4405170056Srrs break; 4406170056Srrs } 4407163953Srrs /* set it on the endpoint */ 4408163953Srrs SCTP_INP_WLOCK(inp); 4409163953Srrs if (inp->sctp_ep.local_hmacs) 4410163953Srrs sctp_free_hmaclist(inp->sctp_ep.local_hmacs); 4411163953Srrs inp->sctp_ep.local_hmacs = hmaclist; 4412163953Srrs SCTP_INP_WUNLOCK(inp); 4413163953Srrs sctp_set_hmac_done: 4414163953Srrs break; 4415163953Srrs } 4416163953Srrs case SCTP_AUTH_ACTIVE_KEY: 4417163953Srrs { 4418163953Srrs struct sctp_authkeyid *scact; 4419163953Srrs 4420223132Stuexen SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize); 4421166675Srrs SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); 4422166675Srrs 4423163953Srrs /* set the active key on the right place */ 4424166675Srrs if (stcb) { 4425163953Srrs /* set the active key on the assoc */ 4426185694Srrs if (sctp_auth_setactivekey(stcb, 4427185694Srrs scact->scact_keynumber)) { 4428185694Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, 4429185694Srrs SCTP_FROM_SCTP_USRREQ, 4430185694Srrs EINVAL); 4431163953Srrs error = EINVAL; 4432171943Srrs } 4433163953Srrs SCTP_TCB_UNLOCK(stcb); 4434163953Srrs } else { 4435224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4436224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4437224918Stuexen (scact->scact_assoc_id == SCTP_FUTURE_ASSOC) || 4438223132Stuexen (scact->scact_assoc_id == SCTP_ALL_ASSOC)) { 4439223132Stuexen SCTP_INP_WLOCK(inp); 4440223132Stuexen if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) { 4441223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4442223132Stuexen error = EINVAL; 4443223132Stuexen } 4444223132Stuexen SCTP_INP_WUNLOCK(inp); 4445171943Srrs } 4446223132Stuexen if ((scact->scact_assoc_id == SCTP_CURRENT_ASSOC) || 4447223132Stuexen (scact->scact_assoc_id == SCTP_ALL_ASSOC)) { 4448223132Stuexen SCTP_INP_RLOCK(inp); 4449223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4450223132Stuexen SCTP_TCB_LOCK(stcb); 4451223132Stuexen sctp_auth_setactivekey(stcb, scact->scact_keynumber); 4452223132Stuexen SCTP_TCB_UNLOCK(stcb); 4453223132Stuexen } 4454223132Stuexen SCTP_INP_RUNLOCK(inp); 4455223132Stuexen } 4456163953Srrs } 4457163953Srrs break; 4458163953Srrs } 4459163953Srrs case SCTP_AUTH_DELETE_KEY: 4460163953Srrs { 4461163953Srrs struct sctp_authkeyid *scdel; 4462163953Srrs 4463223132Stuexen SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize); 4464166675Srrs SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id); 4465166675Srrs 4466163953Srrs /* delete the key from the right place */ 4467166675Srrs if (stcb) { 4468223132Stuexen if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) { 4469223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4470163953Srrs error = EINVAL; 4471171943Srrs } 4472163953Srrs SCTP_TCB_UNLOCK(stcb); 4473163953Srrs } else { 4474224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4475224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4476224918Stuexen (scdel->scact_assoc_id == SCTP_FUTURE_ASSOC) || 4477223132Stuexen (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) { 4478223132Stuexen SCTP_INP_WLOCK(inp); 4479223132Stuexen if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) { 4480223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4481223132Stuexen error = EINVAL; 4482223132Stuexen } 4483223132Stuexen SCTP_INP_WUNLOCK(inp); 4484171943Srrs } 4485223132Stuexen if ((scdel->scact_assoc_id == SCTP_CURRENT_ASSOC) || 4486223132Stuexen (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) { 4487223132Stuexen SCTP_INP_RLOCK(inp); 4488223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4489223132Stuexen SCTP_TCB_LOCK(stcb); 4490223132Stuexen sctp_delete_sharedkey(stcb, scdel->scact_keynumber); 4491223132Stuexen SCTP_TCB_UNLOCK(stcb); 4492223132Stuexen } 4493223132Stuexen SCTP_INP_RUNLOCK(inp); 4494223132Stuexen } 4495163953Srrs } 4496163953Srrs break; 4497163953Srrs } 4498185694Srrs case SCTP_AUTH_DEACTIVATE_KEY: 4499185694Srrs { 4500185694Srrs struct sctp_authkeyid *keyid; 4501163953Srrs 4502223132Stuexen SCTP_CHECK_AND_CAST(keyid, optval, struct sctp_authkeyid, optsize); 4503185694Srrs SCTP_FIND_STCB(inp, stcb, keyid->scact_assoc_id); 4504185694Srrs 4505185694Srrs /* deactivate the key from the right place */ 4506185694Srrs if (stcb) { 4507223132Stuexen if (sctp_deact_sharedkey(stcb, keyid->scact_keynumber)) { 4508223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4509185694Srrs error = EINVAL; 4510185694Srrs } 4511185694Srrs SCTP_TCB_UNLOCK(stcb); 4512185694Srrs } else { 4513224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4514224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4515224918Stuexen (keyid->scact_assoc_id == SCTP_FUTURE_ASSOC) || 4516223132Stuexen (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) { 4517223132Stuexen SCTP_INP_WLOCK(inp); 4518223132Stuexen if (sctp_deact_sharedkey_ep(inp, keyid->scact_keynumber)) { 4519223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4520223132Stuexen error = EINVAL; 4521223132Stuexen } 4522223132Stuexen SCTP_INP_WUNLOCK(inp); 4523185694Srrs } 4524223132Stuexen if ((keyid->scact_assoc_id == SCTP_CURRENT_ASSOC) || 4525223132Stuexen (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) { 4526223132Stuexen SCTP_INP_RLOCK(inp); 4527223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4528223132Stuexen SCTP_TCB_LOCK(stcb); 4529223132Stuexen sctp_deact_sharedkey(stcb, keyid->scact_keynumber); 4530223132Stuexen SCTP_TCB_UNLOCK(stcb); 4531223132Stuexen } 4532223132Stuexen SCTP_INP_RUNLOCK(inp); 4533223132Stuexen } 4534185694Srrs } 4535185694Srrs break; 4536185694Srrs } 4537233660Srrs case SCTP_ENABLE_STREAM_RESET: 4538233660Srrs { 4539233660Srrs struct sctp_assoc_value *av; 4540185694Srrs 4541233660Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 4542233660Srrs if (av->assoc_value & (~SCTP_ENABLE_VALUE_MASK)) { 4543233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4544233660Srrs error = EINVAL; 4545233660Srrs break; 4546233660Srrs } 4547233660Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4548233660Srrs if (stcb) { 4549235021Stuexen stcb->asoc.local_strreset_support = (uint8_t) av->assoc_value; 4550233660Srrs SCTP_TCB_UNLOCK(stcb); 4551233660Srrs } else { 4552233660Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4553233660Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4554233660Srrs (av->assoc_id == SCTP_FUTURE_ASSOC) || 4555233660Srrs (av->assoc_id == SCTP_ALL_ASSOC)) { 4556233660Srrs SCTP_INP_WLOCK(inp); 4557235021Stuexen inp->local_strreset_support = (uint8_t) av->assoc_value; 4558233660Srrs SCTP_INP_WUNLOCK(inp); 4559233660Srrs } 4560233660Srrs if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 4561233660Srrs (av->assoc_id == SCTP_ALL_ASSOC)) { 4562233660Srrs SCTP_INP_RLOCK(inp); 4563233660Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4564233660Srrs SCTP_TCB_LOCK(stcb); 4565235021Stuexen stcb->asoc.local_strreset_support = (uint8_t) av->assoc_value; 4566233660Srrs SCTP_TCB_UNLOCK(stcb); 4567233660Srrs } 4568233660Srrs SCTP_INP_RUNLOCK(inp); 4569233660Srrs } 4570233660Srrs } 4571233660Srrs break; 4572233660Srrs } 4573163953Srrs case SCTP_RESET_STREAMS: 4574163953Srrs { 4575233660Srrs struct sctp_reset_streams *strrst; 4576233660Srrs int i, send_out = 0; 4577233660Srrs int send_in = 0; 4578163953Srrs 4579233660Srrs SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_reset_streams, optsize); 4580233660Srrs SCTP_FIND_STCB(inp, stcb, strrst->srs_assoc_id); 4581163953Srrs if (stcb == NULL) { 4582171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4583163953Srrs error = ENOENT; 4584163953Srrs break; 4585163953Srrs } 4586270361Stuexen if (stcb->asoc.reconfig_supported == 0) { 4587163953Srrs /* 4588233660Srrs * Peer does not support the chunk type. 4589163953Srrs */ 4590233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4591233660Srrs error = EOPNOTSUPP; 4592163953Srrs SCTP_TCB_UNLOCK(stcb); 4593163953Srrs break; 4594163953Srrs } 4595273000Stuexen if (sizeof(struct sctp_reset_streams) + 4596273000Stuexen strrst->srs_number_streams * sizeof(uint16_t) > optsize) { 4597273000Stuexen error = EINVAL; 4598273000Stuexen SCTP_TCB_UNLOCK(stcb); 4599273000Stuexen break; 4600273000Stuexen } 4601233660Srrs if (strrst->srs_flags & SCTP_STREAM_RESET_INCOMING) { 4602163953Srrs send_in = 1; 4603294140Stuexen if (stcb->asoc.stream_reset_outstanding) { 4604294140Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4605294140Stuexen error = EALREADY; 4606294140Stuexen SCTP_TCB_UNLOCK(stcb); 4607294140Stuexen break; 4608294140Stuexen } 4609233660Srrs } 4610233660Srrs if (strrst->srs_flags & SCTP_STREAM_RESET_OUTGOING) { 4611163953Srrs send_out = 1; 4612233660Srrs } 4613294140Stuexen if ((strrst->srs_number_streams > SCTP_MAX_STREAMS_AT_ONCE_RESET) && send_in) { 4614294140Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 4615294140Stuexen error = ENOMEM; 4616294140Stuexen SCTP_TCB_UNLOCK(stcb); 4617294140Stuexen break; 4618294140Stuexen } 4619233660Srrs if ((send_in == 0) && (send_out == 0)) { 4620233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4621233660Srrs error = EINVAL; 4622233660Srrs SCTP_TCB_UNLOCK(stcb); 4623233660Srrs break; 4624233660Srrs } 4625233660Srrs for (i = 0; i < strrst->srs_number_streams; i++) { 4626233660Srrs if ((send_in) && 4627233660Srrs (strrst->srs_stream_list[i] > stcb->asoc.streamincnt)) { 4628233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4629188854Srrs error = EINVAL; 4630233660Srrs break; 4631188854Srrs } 4632233660Srrs if ((send_out) && 4633233660Srrs (strrst->srs_stream_list[i] > stcb->asoc.streamoutcnt)) { 4634233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4635233660Srrs error = EINVAL; 4636233660Srrs break; 4637188854Srrs } 4638233660Srrs } 4639233660Srrs if (error) { 4640233660Srrs SCTP_TCB_UNLOCK(stcb); 4641233660Srrs break; 4642233660Srrs } 4643294140Stuexen if (send_out) { 4644294140Stuexen int cnt; 4645294140Stuexen uint16_t strm; 4646233660Srrs 4647294140Stuexen if (strrst->srs_number_streams) { 4648294140Stuexen for (i = 0, cnt = 0; i < strrst->srs_number_streams; i++) { 4649294140Stuexen strm = strrst->srs_stream_list[i]; 4650294140Stuexen if (stcb->asoc.strmout[strm].state == SCTP_STREAM_OPEN) { 4651294140Stuexen stcb->asoc.strmout[strm].state = SCTP_STREAM_RESET_PENDING; 4652294140Stuexen cnt++; 4653294140Stuexen } 4654294140Stuexen } 4655294140Stuexen } else { 4656294140Stuexen /* Its all */ 4657294140Stuexen for (i = 0, cnt = 0; i < stcb->asoc.streamoutcnt; i++) { 4658294140Stuexen if (stcb->asoc.strmout[i].state == SCTP_STREAM_OPEN) { 4659294140Stuexen stcb->asoc.strmout[i].state = SCTP_STREAM_RESET_PENDING; 4660294140Stuexen cnt++; 4661294140Stuexen } 4662294140Stuexen } 4663294140Stuexen } 4664294140Stuexen } 4665294140Stuexen if (send_in) { 4666294140Stuexen error = sctp_send_str_reset_req(stcb, strrst->srs_number_streams, 4667294140Stuexen strrst->srs_stream_list, 4668294140Stuexen send_in, 0, 0, 0, 0, 0); 4669294206Stuexen } else { 4670294141Stuexen error = sctp_send_stream_reset_out_if_possible(stcb, SCTP_SO_LOCKED); 4671294206Stuexen } 4672294206Stuexen if (error == 0) { 4673294140Stuexen sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); 4674294206Stuexen } else { 4675294206Stuexen /* 4676294206Stuexen * For outgoing streams don't report any 4677294206Stuexen * problems in sending the request to the 4678294206Stuexen * application. XXX: Double check resetting 4679294206Stuexen * incoming streams. 4680294206Stuexen */ 4681294206Stuexen error = 0; 4682294206Stuexen } 4683233660Srrs SCTP_TCB_UNLOCK(stcb); 4684233660Srrs break; 4685233660Srrs } 4686233660Srrs case SCTP_ADD_STREAMS: 4687233660Srrs { 4688233660Srrs struct sctp_add_streams *stradd; 4689233660Srrs uint8_t addstream = 0; 4690233660Srrs uint16_t add_o_strmcnt = 0; 4691233660Srrs uint16_t add_i_strmcnt = 0; 4692233660Srrs 4693233660Srrs SCTP_CHECK_AND_CAST(stradd, optval, struct sctp_add_streams, optsize); 4694233660Srrs SCTP_FIND_STCB(inp, stcb, stradd->sas_assoc_id); 4695233660Srrs if (stcb == NULL) { 4696233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4697233660Srrs error = ENOENT; 4698233660Srrs break; 4699233660Srrs } 4700270361Stuexen if (stcb->asoc.reconfig_supported == 0) { 4701235057Stuexen /* 4702235057Stuexen * Peer does not support the chunk type. 4703235057Stuexen */ 4704235057Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4705235057Stuexen error = EOPNOTSUPP; 4706235057Stuexen SCTP_TCB_UNLOCK(stcb); 4707235057Stuexen break; 4708235057Stuexen } 4709235057Stuexen if (stcb->asoc.stream_reset_outstanding) { 4710235057Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4711235057Stuexen error = EALREADY; 4712235057Stuexen SCTP_TCB_UNLOCK(stcb); 4713235057Stuexen break; 4714235057Stuexen } 4715233660Srrs if ((stradd->sas_outstrms == 0) && 4716233660Srrs (stradd->sas_instrms == 0)) { 4717233660Srrs error = EINVAL; 4718233660Srrs goto skip_stuff; 4719233660Srrs } 4720233660Srrs if (stradd->sas_outstrms) { 4721188854Srrs addstream = 1; 4722188854Srrs /* We allocate here */ 4723233660Srrs add_o_strmcnt = stradd->sas_outstrms; 4724233660Srrs if ((((int)add_o_strmcnt) + ((int)stcb->asoc.streamoutcnt)) > 0x0000ffff) { 4725188854Srrs /* You can't have more than 64k */ 4726188854Srrs error = EINVAL; 4727188854Srrs goto skip_stuff; 4728188854Srrs } 4729163953Srrs } 4730233660Srrs if (stradd->sas_instrms) { 4731233660Srrs int cnt; 4732163953Srrs 4733233660Srrs addstream |= 2; 4734233660Srrs /* 4735233660Srrs * We allocate inside 4736233660Srrs * sctp_send_str_reset_req() 4737233660Srrs */ 4738233660Srrs add_i_strmcnt = stradd->sas_instrms; 4739233660Srrs cnt = add_i_strmcnt; 4740233660Srrs cnt += stcb->asoc.streamincnt; 4741233660Srrs if (cnt > 0x0000ffff) { 4742233660Srrs /* You can't have more than 64k */ 4743163953Srrs error = EINVAL; 4744233660Srrs goto skip_stuff; 4745163953Srrs } 4746233660Srrs if (cnt > (int)stcb->asoc.max_inbound_streams) { 4747233660Srrs /* More than you are allowed */ 4748163953Srrs error = EINVAL; 4749233660Srrs goto skip_stuff; 4750163953Srrs } 4751163953Srrs } 4752294140Stuexen error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, addstream, add_o_strmcnt, add_i_strmcnt, 0); 4753233660Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); 4754188854Srrs skip_stuff: 4755233660Srrs SCTP_TCB_UNLOCK(stcb); 4756233660Srrs break; 4757233660Srrs } 4758233660Srrs case SCTP_RESET_ASSOC: 4759233660Srrs { 4760294140Stuexen int i; 4761233660Srrs uint32_t *value; 4762233660Srrs 4763233660Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); 4764233660Srrs SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value); 4765233660Srrs if (stcb == NULL) { 4766233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4767233660Srrs error = ENOENT; 4768233660Srrs break; 4769233660Srrs } 4770270361Stuexen if (stcb->asoc.reconfig_supported == 0) { 4771233660Srrs /* 4772233660Srrs * Peer does not support the chunk type. 4773233660Srrs */ 4774233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4775233660Srrs error = EOPNOTSUPP; 4776163953Srrs SCTP_TCB_UNLOCK(stcb); 4777163953Srrs break; 4778163953Srrs } 4779233660Srrs if (stcb->asoc.stream_reset_outstanding) { 4780233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4781233660Srrs error = EALREADY; 4782233660Srrs SCTP_TCB_UNLOCK(stcb); 4783233660Srrs break; 4784233660Srrs } 4785294140Stuexen /* 4786294140Stuexen * Is there any data pending in the send or sent 4787294140Stuexen * queues? 4788294140Stuexen */ 4789294140Stuexen if (!TAILQ_EMPTY(&stcb->asoc.send_queue) || 4790294140Stuexen !TAILQ_EMPTY(&stcb->asoc.sent_queue)) { 4791294140Stuexen busy_out: 4792294140Stuexen error = EBUSY; 4793294140Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 4794294140Stuexen SCTP_TCB_UNLOCK(stcb); 4795294140Stuexen break; 4796294140Stuexen } 4797294140Stuexen /* Do any streams have data queued? */ 4798294140Stuexen for (i = 0; i < stcb->asoc.streamoutcnt; i++) { 4799294140Stuexen if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { 4800294140Stuexen goto busy_out; 4801294140Stuexen } 4802294140Stuexen } 4803294140Stuexen error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 1, 0, 0, 0, 0); 4804172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); 4805163953Srrs SCTP_TCB_UNLOCK(stcb); 4806223132Stuexen break; 4807163953Srrs } 4808163953Srrs case SCTP_CONNECT_X: 4809166675Srrs if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { 4810171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4811163953Srrs error = EINVAL; 4812163953Srrs break; 4813163953Srrs } 4814166675Srrs error = sctp_do_connect_x(so, inp, optval, optsize, p, 0); 4815163953Srrs break; 4816163953Srrs case SCTP_CONNECT_X_DELAYED: 4817166675Srrs if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { 4818171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4819163953Srrs error = EINVAL; 4820163953Srrs break; 4821163953Srrs } 4822166675Srrs error = sctp_do_connect_x(so, inp, optval, optsize, p, 1); 4823163953Srrs break; 4824163953Srrs case SCTP_CONNECT_X_COMPLETE: 4825163953Srrs { 4826163953Srrs struct sockaddr *sa; 4827163953Srrs 4828166675Srrs /* FIXME MT: check correct? */ 4829166675Srrs SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize); 4830166675Srrs 4831163953Srrs /* find tcb */ 4832163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 4833163953Srrs SCTP_INP_RLOCK(inp); 4834163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 4835163953Srrs if (stcb) { 4836163953Srrs SCTP_TCB_LOCK(stcb); 4837163953Srrs } 4838163953Srrs SCTP_INP_RUNLOCK(inp); 4839163953Srrs } else { 4840166675Srrs /* 4841166675Srrs * We increment here since 4842166675Srrs * sctp_findassociation_ep_addr() wil do a 4843166675Srrs * decrement if it finds the stcb as long as 4844166675Srrs * the locked tcb (last argument) is NOT a 4845166675Srrs * TCB.. aka NULL. 4846166675Srrs */ 4847163953Srrs SCTP_INP_INCR_REF(inp); 4848283716Stuexen stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL); 4849163953Srrs if (stcb == NULL) { 4850163953Srrs SCTP_INP_DECR_REF(inp); 4851163953Srrs } 4852163953Srrs } 4853163953Srrs 4854163953Srrs if (stcb == NULL) { 4855171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4856163953Srrs error = ENOENT; 4857163953Srrs break; 4858163953Srrs } 4859163953Srrs if (stcb->asoc.delayed_connection == 1) { 4860163953Srrs stcb->asoc.delayed_connection = 0; 4861169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 4862165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, 4863165220Srrs stcb->asoc.primary_destination, 4864283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8); 4865172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 4866163953Srrs } else { 4867163953Srrs /* 4868163953Srrs * already expired or did not use delayed 4869163953Srrs * connectx 4870163953Srrs */ 4871171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4872163953Srrs error = EALREADY; 4873163953Srrs } 4874163953Srrs SCTP_TCB_UNLOCK(stcb); 4875223132Stuexen break; 4876163953Srrs } 4877170056Srrs case SCTP_MAX_BURST: 4878163953Srrs { 4879217895Stuexen struct sctp_assoc_value *av; 4880163953Srrs 4881217895Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 4882217895Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4883166675Srrs 4884217895Stuexen if (stcb) { 4885217895Stuexen stcb->asoc.max_burst = av->assoc_value; 4886217895Stuexen SCTP_TCB_UNLOCK(stcb); 4887217895Stuexen } else { 4888224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4889224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4890224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 4891223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 4892223132Stuexen SCTP_INP_WLOCK(inp); 4893223132Stuexen inp->sctp_ep.max_burst = av->assoc_value; 4894223132Stuexen SCTP_INP_WUNLOCK(inp); 4895223132Stuexen } 4896223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 4897223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 4898223132Stuexen SCTP_INP_RLOCK(inp); 4899223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4900223132Stuexen SCTP_TCB_LOCK(stcb); 4901223132Stuexen stcb->asoc.max_burst = av->assoc_value; 4902223132Stuexen SCTP_TCB_UNLOCK(stcb); 4903223132Stuexen } 4904223132Stuexen SCTP_INP_RUNLOCK(inp); 4905223132Stuexen } 4906217895Stuexen } 4907223132Stuexen break; 4908163953Srrs } 4909163953Srrs case SCTP_MAXSEG: 4910163953Srrs { 4911167598Srrs struct sctp_assoc_value *av; 4912163953Srrs int ovh; 4913163953Srrs 4914167598Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 4915167598Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4916166675Srrs 4917170056Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 4918170056Srrs ovh = SCTP_MED_OVERHEAD; 4919170056Srrs } else { 4920170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 4921170056Srrs } 4922167598Srrs if (stcb) { 4923170056Srrs if (av->assoc_value) { 4924170056Srrs stcb->asoc.sctp_frag_point = (av->assoc_value + ovh); 4925170056Srrs } else { 4926170056Srrs stcb->asoc.sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; 4927170056Srrs } 4928167598Srrs SCTP_TCB_UNLOCK(stcb); 4929163953Srrs } else { 4930224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4931224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4932224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 4933223132Stuexen SCTP_INP_WLOCK(inp); 4934223132Stuexen /* 4935223132Stuexen * FIXME MT: I think this is not in 4936223132Stuexen * tune with the API ID 4937223132Stuexen */ 4938223132Stuexen if (av->assoc_value) { 4939223132Stuexen inp->sctp_frag_point = (av->assoc_value + ovh); 4940223132Stuexen } else { 4941223132Stuexen inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; 4942223132Stuexen } 4943223132Stuexen SCTP_INP_WUNLOCK(inp); 4944167598Srrs } else { 4945223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4946223132Stuexen error = EINVAL; 4947167598Srrs } 4948163953Srrs } 4949223132Stuexen break; 4950163953Srrs } 4951163953Srrs case SCTP_EVENTS: 4952163953Srrs { 4953163953Srrs struct sctp_event_subscribe *events; 4954163953Srrs 4955166675Srrs SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize); 4956166675Srrs 4957163953Srrs SCTP_INP_WLOCK(inp); 4958163953Srrs if (events->sctp_data_io_event) { 4959163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); 4960163953Srrs } else { 4961163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); 4962163953Srrs } 4963163953Srrs 4964163953Srrs if (events->sctp_association_event) { 4965163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); 4966163953Srrs } else { 4967163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); 4968163953Srrs } 4969163953Srrs 4970163953Srrs if (events->sctp_address_event) { 4971163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); 4972163953Srrs } else { 4973163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); 4974163953Srrs } 4975163953Srrs 4976163953Srrs if (events->sctp_send_failure_event) { 4977163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 4978163953Srrs } else { 4979163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 4980163953Srrs } 4981163953Srrs 4982163953Srrs if (events->sctp_peer_error_event) { 4983163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR); 4984163953Srrs } else { 4985163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR); 4986163953Srrs } 4987163953Srrs 4988163953Srrs if (events->sctp_shutdown_event) { 4989163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 4990163953Srrs } else { 4991163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 4992163953Srrs } 4993163953Srrs 4994163953Srrs if (events->sctp_partial_delivery_event) { 4995163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT); 4996163953Srrs } else { 4997163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT); 4998163953Srrs } 4999163953Srrs 5000163953Srrs if (events->sctp_adaptation_layer_event) { 5001163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 5002163953Srrs } else { 5003163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 5004163953Srrs } 5005163953Srrs 5006163953Srrs if (events->sctp_authentication_event) { 5007163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT); 5008163953Srrs } else { 5009163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT); 5010163953Srrs } 5011163953Srrs 5012185694Srrs if (events->sctp_sender_dry_event) { 5013185694Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT); 5014185694Srrs } else { 5015185694Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT); 5016185694Srrs } 5017185694Srrs 5018202520Srrs if (events->sctp_stream_reset_event) { 5019163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 5020163953Srrs } else { 5021163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 5022163953Srrs } 5023163953Srrs SCTP_INP_WUNLOCK(inp); 5024223132Stuexen 5025223132Stuexen SCTP_INP_RLOCK(inp); 5026223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 5027223132Stuexen SCTP_TCB_LOCK(stcb); 5028223132Stuexen if (events->sctp_association_event) { 5029223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT); 5030223132Stuexen } else { 5031223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT); 5032223132Stuexen } 5033223132Stuexen if (events->sctp_address_event) { 5034223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT); 5035223132Stuexen } else { 5036223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT); 5037223132Stuexen } 5038223132Stuexen if (events->sctp_send_failure_event) { 5039223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 5040223132Stuexen } else { 5041223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 5042223132Stuexen } 5043223132Stuexen if (events->sctp_peer_error_event) { 5044223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR); 5045223132Stuexen } else { 5046223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR); 5047223132Stuexen } 5048223132Stuexen if (events->sctp_shutdown_event) { 5049223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 5050223132Stuexen } else { 5051223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 5052223132Stuexen } 5053223132Stuexen if (events->sctp_partial_delivery_event) { 5054223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT); 5055223132Stuexen } else { 5056223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT); 5057223132Stuexen } 5058223132Stuexen if (events->sctp_adaptation_layer_event) { 5059223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 5060223132Stuexen } else { 5061223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 5062223132Stuexen } 5063223132Stuexen if (events->sctp_authentication_event) { 5064223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT); 5065223132Stuexen } else { 5066223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT); 5067223132Stuexen } 5068223132Stuexen if (events->sctp_sender_dry_event) { 5069223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT); 5070223132Stuexen } else { 5071223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT); 5072223132Stuexen } 5073223132Stuexen if (events->sctp_stream_reset_event) { 5074223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 5075223132Stuexen } else { 5076223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 5077223132Stuexen } 5078223132Stuexen SCTP_TCB_UNLOCK(stcb); 5079223132Stuexen } 5080223132Stuexen /* 5081223132Stuexen * Send up the sender dry event only for 1-to-1 5082223132Stuexen * style sockets. 5083223132Stuexen */ 5084223132Stuexen if (events->sctp_sender_dry_event) { 5085223132Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5086223132Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 5087223132Stuexen stcb = LIST_FIRST(&inp->sctp_asoc_list); 5088223132Stuexen if (stcb) { 5089223132Stuexen SCTP_TCB_LOCK(stcb); 5090223132Stuexen if (TAILQ_EMPTY(&stcb->asoc.send_queue) && 5091223132Stuexen TAILQ_EMPTY(&stcb->asoc.sent_queue) && 5092223132Stuexen (stcb->asoc.stream_queue_cnt == 0)) { 5093223132Stuexen sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED); 5094223132Stuexen } 5095223132Stuexen SCTP_TCB_UNLOCK(stcb); 5096223132Stuexen } 5097223132Stuexen } 5098223132Stuexen } 5099223132Stuexen SCTP_INP_RUNLOCK(inp); 5100223132Stuexen break; 5101163953Srrs } 5102163953Srrs case SCTP_ADAPTATION_LAYER: 5103163953Srrs { 5104163953Srrs struct sctp_setadaptation *adap_bits; 5105163953Srrs 5106166675Srrs SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize); 5107163953Srrs SCTP_INP_WLOCK(inp); 5108163953Srrs inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind; 5109246687Stuexen inp->sctp_ep.adaptation_layer_indicator_provided = 1; 5110163953Srrs SCTP_INP_WUNLOCK(inp); 5111223132Stuexen break; 5112163953Srrs } 5113166675Srrs#ifdef SCTP_DEBUG 5114163953Srrs case SCTP_SET_INITIAL_DBG_SEQ: 5115163953Srrs { 5116163953Srrs uint32_t *vvv; 5117163953Srrs 5118166675Srrs SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize); 5119163953Srrs SCTP_INP_WLOCK(inp); 5120163953Srrs inp->sctp_ep.initial_sequence_debug = *vvv; 5121163953Srrs SCTP_INP_WUNLOCK(inp); 5122223132Stuexen break; 5123163953Srrs } 5124166675Srrs#endif 5125163953Srrs case SCTP_DEFAULT_SEND_PARAM: 5126163953Srrs { 5127163953Srrs struct sctp_sndrcvinfo *s_info; 5128163953Srrs 5129166675Srrs SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize); 5130166675Srrs SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); 5131163953Srrs 5132166675Srrs if (stcb) { 5133223132Stuexen if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) { 5134170056Srrs memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send))); 5135163953Srrs } else { 5136171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5137166675Srrs error = EINVAL; 5138163953Srrs } 5139166675Srrs SCTP_TCB_UNLOCK(stcb); 5140166675Srrs } else { 5141224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5142224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5143224918Stuexen (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) || 5144223132Stuexen (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) { 5145223132Stuexen SCTP_INP_WLOCK(inp); 5146223132Stuexen memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send))); 5147223132Stuexen SCTP_INP_WUNLOCK(inp); 5148223132Stuexen } 5149223132Stuexen if ((s_info->sinfo_assoc_id == SCTP_CURRENT_ASSOC) || 5150223132Stuexen (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) { 5151223132Stuexen SCTP_INP_RLOCK(inp); 5152223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 5153223132Stuexen SCTP_TCB_LOCK(stcb); 5154223132Stuexen if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) { 5155223132Stuexen memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send))); 5156223132Stuexen } 5157223132Stuexen SCTP_TCB_UNLOCK(stcb); 5158223132Stuexen } 5159223132Stuexen SCTP_INP_RUNLOCK(inp); 5160223132Stuexen } 5161163953Srrs } 5162223132Stuexen break; 5163163953Srrs } 5164163953Srrs case SCTP_PEER_ADDR_PARAMS: 5165163953Srrs { 5166163953Srrs struct sctp_paddrparams *paddrp; 5167163953Srrs struct sctp_nets *net; 5168283699Stuexen struct sockaddr *addr; 5169163953Srrs 5170283699Stuexen#if defined(INET) && defined(INET6) 5171283699Stuexen struct sockaddr_in sin_store; 5172283699Stuexen 5173283699Stuexen#endif 5174283699Stuexen 5175166675Srrs SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize); 5176166675Srrs SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); 5177283699Stuexen 5178283699Stuexen#if defined(INET) && defined(INET6) 5179283699Stuexen if (paddrp->spp_address.ss_family == AF_INET6) { 5180283699Stuexen struct sockaddr_in6 *sin6; 5181283699Stuexen 5182283699Stuexen sin6 = (struct sockaddr_in6 *)&paddrp->spp_address; 5183283699Stuexen if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 5184283699Stuexen in6_sin6_2_sin(&sin_store, sin6); 5185283699Stuexen addr = (struct sockaddr *)&sin_store; 5186283699Stuexen } else { 5187283699Stuexen addr = (struct sockaddr *)&paddrp->spp_address; 5188283699Stuexen } 5189166675Srrs } else { 5190283699Stuexen addr = (struct sockaddr *)&paddrp->spp_address; 5191283699Stuexen } 5192283699Stuexen#else 5193283699Stuexen addr = (struct sockaddr *)&paddrp->spp_address; 5194283699Stuexen#endif 5195283699Stuexen if (stcb != NULL) { 5196283699Stuexen net = sctp_findnet(stcb, addr); 5197283699Stuexen } else { 5198166675Srrs /* 5199166675Srrs * We increment here since 5200166675Srrs * sctp_findassociation_ep_addr() wil do a 5201166675Srrs * decrement if it finds the stcb as long as 5202166675Srrs * the locked tcb (last argument) is NOT a 5203166675Srrs * TCB.. aka NULL. 5204166675Srrs */ 5205283699Stuexen net = NULL; 5206166675Srrs SCTP_INP_INCR_REF(inp); 5207283699Stuexen stcb = sctp_findassociation_ep_addr(&inp, addr, 5208166675Srrs &net, NULL, NULL); 5209163953Srrs if (stcb == NULL) { 5210166675Srrs SCTP_INP_DECR_REF(inp); 5211163953Srrs } 5212163953Srrs } 5213283699Stuexen if ((stcb != NULL) && (net == NULL)) { 5214221249Stuexen#ifdef INET 5215283699Stuexen if (addr->sa_family == AF_INET) { 5216221249Stuexen 5217171943Srrs struct sockaddr_in *sin; 5218171943Srrs 5219283699Stuexen sin = (struct sockaddr_in *)addr; 5220283699Stuexen if (sin->sin_addr.s_addr != INADDR_ANY) { 5221171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5222171943Srrs SCTP_TCB_UNLOCK(stcb); 5223171943Srrs error = EINVAL; 5224171943Srrs break; 5225171943Srrs } 5226221249Stuexen } else 5227221249Stuexen#endif 5228221249Stuexen#ifdef INET6 5229283699Stuexen if (addr->sa_family == AF_INET6) { 5230171943Srrs struct sockaddr_in6 *sin6; 5231171943Srrs 5232283699Stuexen sin6 = (struct sockaddr_in6 *)addr; 5233171943Srrs if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 5234171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5235171943Srrs SCTP_TCB_UNLOCK(stcb); 5236171943Srrs error = EINVAL; 5237171943Srrs break; 5238171943Srrs } 5239221249Stuexen } else 5240221249Stuexen#endif 5241221249Stuexen { 5242171943Srrs error = EAFNOSUPPORT; 5243171943Srrs SCTP_TCB_UNLOCK(stcb); 5244171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 5245171943Srrs break; 5246171943Srrs } 5247171943Srrs } 5248170056Srrs /* sanity checks */ 5249170056Srrs if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) { 5250170056Srrs if (stcb) 5251170056Srrs SCTP_TCB_UNLOCK(stcb); 5252171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5253170056Srrs return (EINVAL); 5254170056Srrs } 5255170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) { 5256170056Srrs if (stcb) 5257170056Srrs SCTP_TCB_UNLOCK(stcb); 5258171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5259170056Srrs return (EINVAL); 5260170056Srrs } 5261283699Stuexen if (stcb != NULL) { 5262163953Srrs /************************TCB SPECIFIC SET ******************/ 5263283699Stuexen if (net != NULL) { 5264163953Srrs /************************NET SPECIFIC SET ******************/ 5265224641Stuexen if (paddrp->spp_flags & SPP_HB_DISABLE) { 5266224641Stuexen if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) && 5267224641Stuexen !(net->dest_state & SCTP_ADDR_NOHB)) { 5268224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 5269283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9); 5270171440Srrs } 5271163953Srrs net->dest_state |= SCTP_ADDR_NOHB; 5272163953Srrs } 5273163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 5274224641Stuexen if (paddrp->spp_hbinterval) { 5275224641Stuexen net->heart_beat_delay = paddrp->spp_hbinterval; 5276224641Stuexen } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 5277224641Stuexen net->heart_beat_delay = 0; 5278224641Stuexen } 5279224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 5280224641Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 5281224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 5282163953Srrs net->dest_state &= ~SCTP_ADDR_NOHB; 5283163953Srrs } 5284224641Stuexen if (paddrp->spp_flags & SPP_HB_DEMAND) { 5285224641Stuexen /* on demand HB */ 5286224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 5287228391Stuexen sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED); 5288224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 5289224641Stuexen } 5290170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { 5291165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 5292165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 5293283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11); 5294163953Srrs } 5295225635Stuexen net->dest_state |= SCTP_ADDR_NO_PMTUD; 5296283829Stuexen net->mtu = paddrp->spp_pathmtu; 5297283829Stuexen switch (net->ro._l_addr.sa.sa_family) { 5298283829Stuexen#ifdef INET 5299283829Stuexen case AF_INET: 5300283829Stuexen net->mtu += SCTP_MIN_V4_OVERHEAD; 5301283829Stuexen break; 5302283829Stuexen#endif 5303283829Stuexen#ifdef INET6 5304283829Stuexen case AF_INET6: 5305283829Stuexen net->mtu += SCTP_MIN_OVERHEAD; 5306283829Stuexen break; 5307283829Stuexen#endif 5308283829Stuexen default: 5309283829Stuexen break; 5310283829Stuexen } 5311258454Stuexen if (net->mtu < stcb->asoc.smallest_mtu) { 5312258454Stuexen sctp_pathmtu_adjustment(stcb, net->mtu); 5313163953Srrs } 5314163953Srrs } 5315163953Srrs if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 5316225635Stuexen if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 5317163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 5318163953Srrs } 5319225635Stuexen net->dest_state &= ~SCTP_ADDR_NO_PMTUD; 5320163953Srrs } 5321224641Stuexen if (paddrp->spp_pathmaxrxt) { 5322224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 5323224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 5324224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 5325224641Stuexen } 5326224641Stuexen } else { 5327224641Stuexen if ((net->error_count <= paddrp->spp_pathmaxrxt) && 5328224641Stuexen (net->error_count > net->pf_threshold)) { 5329224641Stuexen net->dest_state |= SCTP_ADDR_PF; 5330224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 5331283822Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, 5332283822Stuexen stcb->sctp_ep, stcb, net, 5333283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_12); 5334224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 5335224641Stuexen } 5336224641Stuexen } 5337224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 5338224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 5339224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 5340235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); 5341224641Stuexen } 5342224641Stuexen } else { 5343224641Stuexen if (net->error_count <= paddrp->spp_pathmaxrxt) { 5344224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 5345235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); 5346224641Stuexen } 5347224641Stuexen } 5348163953Srrs net->failure_threshold = paddrp->spp_pathmaxrxt; 5349224641Stuexen } 5350224870Stuexen if (paddrp->spp_flags & SPP_DSCP) { 5351226252Stuexen net->dscp = paddrp->spp_dscp & 0xfc; 5352225549Stuexen net->dscp |= 0x01; 5353163953Srrs } 5354167598Srrs#ifdef INET6 5355163953Srrs if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { 5356225549Stuexen if (net->ro._l_addr.sa.sa_family == AF_INET6) { 5357224870Stuexen net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 5358225549Stuexen net->flowlabel |= 0x80000000; 5359163953Srrs } 5360163953Srrs } 5361163953Srrs#endif 5362163953Srrs } else { 5363163953Srrs /************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/ 5364283699Stuexen if (paddrp->spp_pathmaxrxt != 0) { 5365163953Srrs stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt; 5366224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 5367224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 5368224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 5369224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 5370224641Stuexen } 5371224641Stuexen } else { 5372224641Stuexen if ((net->error_count <= paddrp->spp_pathmaxrxt) && 5373224641Stuexen (net->error_count > net->pf_threshold)) { 5374224641Stuexen net->dest_state |= SCTP_ADDR_PF; 5375224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 5376283822Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, 5377283822Stuexen stcb->sctp_ep, stcb, net, 5378283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_13); 5379224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 5380224641Stuexen } 5381224641Stuexen } 5382224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 5383224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 5384224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 5385235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); 5386224641Stuexen } 5387224641Stuexen } else { 5388224641Stuexen if (net->error_count <= paddrp->spp_pathmaxrxt) { 5389224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 5390235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); 5391224641Stuexen } 5392224641Stuexen } 5393224641Stuexen net->failure_threshold = paddrp->spp_pathmaxrxt; 5394224641Stuexen } 5395224641Stuexen } 5396163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 5397283699Stuexen if (paddrp->spp_hbinterval != 0) { 5398224641Stuexen stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval; 5399224641Stuexen } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 5400224641Stuexen stcb->asoc.heart_beat_delay = 0; 5401224641Stuexen } 5402163953Srrs /* Turn back on the timer */ 5403224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 5404283699Stuexen if (paddrp->spp_hbinterval != 0) { 5405224641Stuexen net->heart_beat_delay = paddrp->spp_hbinterval; 5406224641Stuexen } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 5407224641Stuexen net->heart_beat_delay = 0; 5408224641Stuexen } 5409224641Stuexen if (net->dest_state & SCTP_ADDR_NOHB) { 5410224641Stuexen net->dest_state &= ~SCTP_ADDR_NOHB; 5411224641Stuexen } 5412224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 5413283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_14); 5414224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 5415224641Stuexen } 5416225635Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 5417163953Srrs } 5418224641Stuexen if (paddrp->spp_flags & SPP_HB_DISABLE) { 5419224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 5420224641Stuexen if (!(net->dest_state & SCTP_ADDR_NOHB)) { 5421224641Stuexen net->dest_state |= SCTP_ADDR_NOHB; 5422224641Stuexen if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { 5423283822Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, 5424283822Stuexen inp, stcb, net, 5425283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_15); 5426224641Stuexen } 5427224641Stuexen } 5428224641Stuexen } 5429225635Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 5430224641Stuexen } 5431170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { 5432170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 5433170056Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 5434170056Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 5435283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_16); 5436170056Srrs } 5437225635Stuexen net->dest_state |= SCTP_ADDR_NO_PMTUD; 5438283829Stuexen net->mtu = paddrp->spp_pathmtu; 5439283829Stuexen switch (net->ro._l_addr.sa.sa_family) { 5440283829Stuexen#ifdef INET 5441283829Stuexen case AF_INET: 5442283829Stuexen net->mtu += SCTP_MIN_V4_OVERHEAD; 5443283829Stuexen break; 5444283829Stuexen#endif 5445283829Stuexen#ifdef INET6 5446283829Stuexen case AF_INET6: 5447283829Stuexen net->mtu += SCTP_MIN_OVERHEAD; 5448283829Stuexen break; 5449283829Stuexen#endif 5450283829Stuexen default: 5451283829Stuexen break; 5452283829Stuexen } 5453258454Stuexen if (net->mtu < stcb->asoc.smallest_mtu) { 5454258454Stuexen sctp_pathmtu_adjustment(stcb, net->mtu); 5455170056Srrs } 5456170056Srrs } 5457225635Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 5458170056Srrs } 5459170056Srrs if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 5460170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 5461225635Stuexen if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 5462170056Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 5463170056Srrs } 5464225635Stuexen net->dest_state &= ~SCTP_ADDR_NO_PMTUD; 5465170056Srrs } 5466225635Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 5467170056Srrs } 5468224870Stuexen if (paddrp->spp_flags & SPP_DSCP) { 5469224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 5470226252Stuexen net->dscp = paddrp->spp_dscp & 0xfc; 5471225549Stuexen net->dscp |= 0x01; 5472163953Srrs } 5473226252Stuexen stcb->asoc.default_dscp = paddrp->spp_dscp & 0xfc; 5474225549Stuexen stcb->asoc.default_dscp |= 0x01; 5475163953Srrs } 5476225549Stuexen#ifdef INET6 5477224641Stuexen if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { 5478170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 5479225549Stuexen if (net->ro._l_addr.sa.sa_family == AF_INET6) { 5480225549Stuexen net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 5481225549Stuexen net->flowlabel |= 0x80000000; 5482225549Stuexen } 5483170056Srrs } 5484225549Stuexen stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 5485225549Stuexen stcb->asoc.default_flowlabel |= 0x80000000; 5486163953Srrs } 5487225549Stuexen#endif 5488163953Srrs } 5489163953Srrs SCTP_TCB_UNLOCK(stcb); 5490163953Srrs } else { 5491163953Srrs /************************NO TCB, SET TO default stuff ******************/ 5492224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5493224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5494224918Stuexen (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) { 5495223132Stuexen SCTP_INP_WLOCK(inp); 5496223132Stuexen /* 5497223132Stuexen * For the TOS/FLOWLABEL stuff you 5498223132Stuexen * set it with the options on the 5499223132Stuexen * socket 5500223132Stuexen */ 5501283699Stuexen if (paddrp->spp_pathmaxrxt != 0) { 5502223132Stuexen inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt; 5503223132Stuexen } 5504223132Stuexen if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) 5505223132Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0; 5506283699Stuexen else if (paddrp->spp_hbinterval != 0) { 5507223132Stuexen if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL) 5508223132Stuexen paddrp->spp_hbinterval = SCTP_MAX_HB_INTERVAL; 5509223132Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval); 5510223132Stuexen } 5511223132Stuexen if (paddrp->spp_flags & SPP_HB_ENABLE) { 5512224641Stuexen if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 5513224641Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0; 5514224641Stuexen } else if (paddrp->spp_hbinterval) { 5515224641Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval); 5516224641Stuexen } 5517223132Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 5518223132Stuexen } else if (paddrp->spp_flags & SPP_HB_DISABLE) { 5519223132Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 5520223132Stuexen } 5521225635Stuexen if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 5522225635Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 5523225635Stuexen } else if (paddrp->spp_flags & SPP_PMTUD_DISABLE) { 5524225635Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 5525225635Stuexen } 5526225549Stuexen if (paddrp->spp_flags & SPP_DSCP) { 5527226252Stuexen inp->sctp_ep.default_dscp = paddrp->spp_dscp & 0xfc; 5528225549Stuexen inp->sctp_ep.default_dscp |= 0x01; 5529225549Stuexen } 5530225549Stuexen#ifdef INET6 5531225549Stuexen if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { 5532225549Stuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 5533225549Stuexen inp->sctp_ep.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 5534225549Stuexen inp->sctp_ep.default_flowlabel |= 0x80000000; 5535225549Stuexen } 5536225549Stuexen } 5537225549Stuexen#endif 5538223132Stuexen SCTP_INP_WUNLOCK(inp); 5539223132Stuexen } else { 5540223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5541223132Stuexen error = EINVAL; 5542163953Srrs } 5543163953Srrs } 5544223132Stuexen break; 5545163953Srrs } 5546163953Srrs case SCTP_RTOINFO: 5547163953Srrs { 5548163953Srrs struct sctp_rtoinfo *srto; 5549169655Srrs uint32_t new_init, new_min, new_max; 5550163953Srrs 5551166675Srrs SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize); 5552166675Srrs SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); 5553166675Srrs 5554166675Srrs if (stcb) { 5555167598Srrs if (srto->srto_initial) 5556169655Srrs new_init = srto->srto_initial; 5557169655Srrs else 5558169655Srrs new_init = stcb->asoc.initial_rto; 5559167598Srrs if (srto->srto_max) 5560169655Srrs new_max = srto->srto_max; 5561169655Srrs else 5562169655Srrs new_max = stcb->asoc.maxrto; 5563167598Srrs if (srto->srto_min) 5564169655Srrs new_min = srto->srto_min; 5565169655Srrs else 5566169655Srrs new_min = stcb->asoc.minrto; 5567169655Srrs if ((new_min <= new_init) && (new_init <= new_max)) { 5568169655Srrs stcb->asoc.initial_rto = new_init; 5569169655Srrs stcb->asoc.maxrto = new_max; 5570169655Srrs stcb->asoc.minrto = new_min; 5571169655Srrs } else { 5572179783Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5573179783Srrs error = EINVAL; 5574169655Srrs } 5575166675Srrs SCTP_TCB_UNLOCK(stcb); 5576166675Srrs } else { 5577224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5578224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5579224918Stuexen (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) { 5580223132Stuexen SCTP_INP_WLOCK(inp); 5581223132Stuexen if (srto->srto_initial) 5582223132Stuexen new_init = srto->srto_initial; 5583223132Stuexen else 5584223132Stuexen new_init = inp->sctp_ep.initial_rto; 5585223132Stuexen if (srto->srto_max) 5586223132Stuexen new_max = srto->srto_max; 5587223132Stuexen else 5588223132Stuexen new_max = inp->sctp_ep.sctp_maxrto; 5589223132Stuexen if (srto->srto_min) 5590223132Stuexen new_min = srto->srto_min; 5591223132Stuexen else 5592223132Stuexen new_min = inp->sctp_ep.sctp_minrto; 5593223132Stuexen if ((new_min <= new_init) && (new_init <= new_max)) { 5594223132Stuexen inp->sctp_ep.initial_rto = new_init; 5595223132Stuexen inp->sctp_ep.sctp_maxrto = new_max; 5596223132Stuexen inp->sctp_ep.sctp_minrto = new_min; 5597223132Stuexen } else { 5598223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5599223132Stuexen error = EINVAL; 5600223132Stuexen } 5601223132Stuexen SCTP_INP_WUNLOCK(inp); 5602169655Srrs } else { 5603179783Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5604179783Srrs error = EINVAL; 5605169655Srrs } 5606163953Srrs } 5607223132Stuexen break; 5608163953Srrs } 5609163953Srrs case SCTP_ASSOCINFO: 5610163953Srrs { 5611163953Srrs struct sctp_assocparams *sasoc; 5612163953Srrs 5613166675Srrs SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize); 5614166675Srrs SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); 5615171477Srrs if (sasoc->sasoc_cookie_life) { 5616171477Srrs /* boundary check the cookie life */ 5617171477Srrs if (sasoc->sasoc_cookie_life < 1000) 5618171477Srrs sasoc->sasoc_cookie_life = 1000; 5619171477Srrs if (sasoc->sasoc_cookie_life > SCTP_MAX_COOKIE_LIFE) { 5620171477Srrs sasoc->sasoc_cookie_life = SCTP_MAX_COOKIE_LIFE; 5621171477Srrs } 5622171477Srrs } 5623163953Srrs if (stcb) { 5624163953Srrs if (sasoc->sasoc_asocmaxrxt) 5625163953Srrs stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt; 5626170056Srrs if (sasoc->sasoc_cookie_life) { 5627171572Srrs stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); 5628167598Srrs } 5629163953Srrs SCTP_TCB_UNLOCK(stcb); 5630163953Srrs } else { 5631224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5632224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5633224918Stuexen (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) { 5634223132Stuexen SCTP_INP_WLOCK(inp); 5635223132Stuexen if (sasoc->sasoc_asocmaxrxt) 5636223132Stuexen inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt; 5637223132Stuexen if (sasoc->sasoc_cookie_life) { 5638223132Stuexen inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); 5639223132Stuexen } 5640223132Stuexen SCTP_INP_WUNLOCK(inp); 5641223132Stuexen } else { 5642223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5643223132Stuexen error = EINVAL; 5644167598Srrs } 5645163953Srrs } 5646223132Stuexen break; 5647163953Srrs } 5648163953Srrs case SCTP_INITMSG: 5649163953Srrs { 5650163953Srrs struct sctp_initmsg *sinit; 5651163953Srrs 5652166675Srrs SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize); 5653163953Srrs SCTP_INP_WLOCK(inp); 5654163953Srrs if (sinit->sinit_num_ostreams) 5655163953Srrs inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams; 5656163953Srrs 5657163953Srrs if (sinit->sinit_max_instreams) 5658163953Srrs inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams; 5659163953Srrs 5660163953Srrs if (sinit->sinit_max_attempts) 5661163953Srrs inp->sctp_ep.max_init_times = sinit->sinit_max_attempts; 5662163953Srrs 5663167598Srrs if (sinit->sinit_max_init_timeo) 5664163953Srrs inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo; 5665163953Srrs SCTP_INP_WUNLOCK(inp); 5666223132Stuexen break; 5667163953Srrs } 5668163953Srrs case SCTP_PRIMARY_ADDR: 5669163953Srrs { 5670163953Srrs struct sctp_setprim *spa; 5671223132Stuexen struct sctp_nets *net; 5672283699Stuexen struct sockaddr *addr; 5673163953Srrs 5674283699Stuexen#if defined(INET) && defined(INET6) 5675283699Stuexen struct sockaddr_in sin_store; 5676283699Stuexen 5677283699Stuexen#endif 5678283699Stuexen 5679166675Srrs SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize); 5680166675Srrs SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id); 5681163953Srrs 5682283699Stuexen#if defined(INET) && defined(INET6) 5683283699Stuexen if (spa->ssp_addr.ss_family == AF_INET6) { 5684283699Stuexen struct sockaddr_in6 *sin6; 5685283699Stuexen 5686283699Stuexen sin6 = (struct sockaddr_in6 *)&spa->ssp_addr; 5687283699Stuexen if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 5688283699Stuexen in6_sin6_2_sin(&sin_store, sin6); 5689283699Stuexen addr = (struct sockaddr *)&sin_store; 5690283699Stuexen } else { 5691283699Stuexen addr = (struct sockaddr *)&spa->ssp_addr; 5692283699Stuexen } 5693166675Srrs } else { 5694283699Stuexen addr = (struct sockaddr *)&spa->ssp_addr; 5695283699Stuexen } 5696283699Stuexen#else 5697283699Stuexen addr = (struct sockaddr *)&spa->ssp_addr; 5698283699Stuexen#endif 5699283699Stuexen if (stcb != NULL) { 5700283699Stuexen net = sctp_findnet(stcb, addr); 5701283699Stuexen } else { 5702166675Srrs /* 5703166675Srrs * We increment here since 5704166675Srrs * sctp_findassociation_ep_addr() wil do a 5705166675Srrs * decrement if it finds the stcb as long as 5706166675Srrs * the locked tcb (last argument) is NOT a 5707166675Srrs * TCB.. aka NULL. 5708166675Srrs */ 5709283699Stuexen net = NULL; 5710163953Srrs SCTP_INP_INCR_REF(inp); 5711283699Stuexen stcb = sctp_findassociation_ep_addr(&inp, addr, 5712163953Srrs &net, NULL, NULL); 5713163953Srrs if (stcb == NULL) { 5714163953Srrs SCTP_INP_DECR_REF(inp); 5715163953Srrs } 5716163953Srrs } 5717166675Srrs 5718283699Stuexen if ((stcb != NULL) && (net != NULL)) { 5719284693Stuexen if (net != stcb->asoc.primary_destination) { 5720284693Stuexen if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { 5721284693Stuexen /* Ok we need to set it */ 5722284693Stuexen if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) { 5723284693Stuexen if ((stcb->asoc.alternate) && 5724284693Stuexen (!(net->dest_state & SCTP_ADDR_PF)) && 5725284693Stuexen (net->dest_state & SCTP_ADDR_REACHABLE)) { 5726284693Stuexen sctp_free_remote_addr(stcb->asoc.alternate); 5727284693Stuexen stcb->asoc.alternate = NULL; 5728284693Stuexen } 5729284693Stuexen } else { 5730284693Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5731284693Stuexen error = EINVAL; 5732166675Srrs } 5733284693Stuexen } else { 5734284693Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5735284693Stuexen error = EINVAL; 5736163953Srrs } 5737163953Srrs } 5738166675Srrs } else { 5739171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5740166675Srrs error = EINVAL; 5741163953Srrs } 5742283699Stuexen if (stcb != NULL) { 5743166675Srrs SCTP_TCB_UNLOCK(stcb); 5744166675Srrs } 5745223132Stuexen break; 5746163953Srrs } 5747167598Srrs case SCTP_SET_DYNAMIC_PRIMARY: 5748167598Srrs { 5749167598Srrs union sctp_sockstore *ss; 5750163953Srrs 5751170587Srwatson error = priv_check(curthread, 5752170587Srwatson PRIV_NETINET_RESERVEDPORT); 5753167598Srrs if (error) 5754167598Srrs break; 5755167598Srrs 5756167598Srrs SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize); 5757167598Srrs /* SUPER USER CHECK? */ 5758167598Srrs error = sctp_dynamic_set_primary(&ss->sa, vrf_id); 5759223132Stuexen break; 5760167598Srrs } 5761163953Srrs case SCTP_SET_PEER_PRIMARY_ADDR: 5762163953Srrs { 5763163953Srrs struct sctp_setpeerprim *sspp; 5764283699Stuexen struct sockaddr *addr; 5765163953Srrs 5766283699Stuexen#if defined(INET) && defined(INET6) 5767283699Stuexen struct sockaddr_in sin_store; 5768283699Stuexen 5769283699Stuexen#endif 5770283699Stuexen 5771166675Srrs SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize); 5772166675Srrs SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id); 5773169208Srrs if (stcb != NULL) { 5774170056Srrs struct sctp_ifa *ifa; 5775170056Srrs 5776283699Stuexen#if defined(INET) && defined(INET6) 5777283699Stuexen if (sspp->sspp_addr.ss_family == AF_INET6) { 5778283699Stuexen struct sockaddr_in6 *sin6; 5779283699Stuexen 5780283699Stuexen sin6 = (struct sockaddr_in6 *)&sspp->sspp_addr; 5781283699Stuexen if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 5782283699Stuexen in6_sin6_2_sin(&sin_store, sin6); 5783283699Stuexen addr = (struct sockaddr *)&sin_store; 5784283699Stuexen } else { 5785283699Stuexen addr = (struct sockaddr *)&sspp->sspp_addr; 5786283699Stuexen } 5787283699Stuexen } else { 5788283699Stuexen addr = (struct sockaddr *)&sspp->sspp_addr; 5789283699Stuexen } 5790283699Stuexen#else 5791283699Stuexen addr = (struct sockaddr *)&sspp->sspp_addr; 5792283699Stuexen#endif 5793283699Stuexen ifa = sctp_find_ifa_by_addr(addr, stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED); 5794170056Srrs if (ifa == NULL) { 5795171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5796166675Srrs error = EINVAL; 5797170056Srrs goto out_of_it; 5798166675Srrs } 5799170056Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { 5800170056Srrs /* 5801170056Srrs * Must validate the ifa found is in 5802170056Srrs * our ep 5803170056Srrs */ 5804170056Srrs struct sctp_laddr *laddr; 5805170056Srrs int found = 0; 5806170056Srrs 5807170056Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 5808170056Srrs if (laddr->ifa == NULL) { 5809170056Srrs SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n", 5810294174Stuexen __func__); 5811170056Srrs continue; 5812170056Srrs } 5813170056Srrs if (laddr->ifa == ifa) { 5814170056Srrs found = 1; 5815170056Srrs break; 5816170056Srrs } 5817170056Srrs } 5818170056Srrs if (!found) { 5819171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5820170056Srrs error = EINVAL; 5821170056Srrs goto out_of_it; 5822170056Srrs } 5823267769Stuexen } else { 5824283699Stuexen switch (addr->sa_family) { 5825267769Stuexen#ifdef INET 5826267769Stuexen case AF_INET: 5827267769Stuexen { 5828267769Stuexen struct sockaddr_in *sin; 5829267769Stuexen 5830283699Stuexen sin = (struct sockaddr_in *)addr; 5831267769Stuexen if (prison_check_ip4(inp->ip_inp.inp.inp_cred, 5832267769Stuexen &sin->sin_addr) != 0) { 5833267769Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5834267769Stuexen error = EINVAL; 5835267769Stuexen goto out_of_it; 5836267769Stuexen } 5837267769Stuexen break; 5838267769Stuexen } 5839267769Stuexen#endif 5840267769Stuexen#ifdef INET6 5841267769Stuexen case AF_INET6: 5842267769Stuexen { 5843267769Stuexen struct sockaddr_in6 *sin6; 5844267769Stuexen 5845283699Stuexen sin6 = (struct sockaddr_in6 *)addr; 5846267769Stuexen if (prison_check_ip6(inp->ip_inp.inp.inp_cred, 5847267769Stuexen &sin6->sin6_addr) != 0) { 5848267769Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5849267769Stuexen error = EINVAL; 5850267769Stuexen goto out_of_it; 5851267769Stuexen } 5852267769Stuexen break; 5853267769Stuexen } 5854267769Stuexen#endif 5855267769Stuexen default: 5856267769Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5857267769Stuexen error = EINVAL; 5858267769Stuexen goto out_of_it; 5859267769Stuexen } 5860170056Srrs } 5861283699Stuexen if (sctp_set_primary_ip_address_sa(stcb, addr) != 0) { 5862171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5863170056Srrs error = EINVAL; 5864170056Srrs } 5865170056Srrs out_of_it: 5866169208Srrs SCTP_TCB_UNLOCK(stcb); 5867166675Srrs } else { 5868171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5869163953Srrs error = EINVAL; 5870163953Srrs } 5871223132Stuexen break; 5872163953Srrs } 5873163953Srrs case SCTP_BINDX_ADD_ADDR: 5874163953Srrs { 5875163953Srrs struct sctp_getaddresses *addrs; 5876171477Srrs struct thread *td; 5877163953Srrs 5878171477Srrs td = (struct thread *)p; 5879170606Srrs SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, 5880170606Srrs optsize); 5881221249Stuexen#ifdef INET 5882171477Srrs if (addrs->addr->sa_family == AF_INET) { 5883238501Stuexen if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) { 5884171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5885171477Srrs error = EINVAL; 5886171477Srrs break; 5887171477Srrs } 5888188590Srrs if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) { 5889188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5890185435Sbz break; 5891171477Srrs } 5892221249Stuexen } else 5893221249Stuexen#endif 5894185435Sbz#ifdef INET6 5895221249Stuexen if (addrs->addr->sa_family == AF_INET6) { 5896238501Stuexen if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) { 5897171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5898171477Srrs error = EINVAL; 5899171477Srrs break; 5900171477Srrs } 5901188590Srrs if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr), 5902188590Srrs (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) { 5903188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5904185435Sbz break; 5905185435Sbz } 5906221249Stuexen } else 5907185435Sbz#endif 5908221249Stuexen { 5909185435Sbz error = EAFNOSUPPORT; 5910185435Sbz break; 5911171477Srrs } 5912170606Srrs sctp_bindx_add_address(so, inp, addrs->addr, 5913170606Srrs addrs->sget_assoc_id, vrf_id, 5914170606Srrs &error, p); 5915223132Stuexen break; 5916163953Srrs } 5917163953Srrs case SCTP_BINDX_REM_ADDR: 5918163953Srrs { 5919163953Srrs struct sctp_getaddresses *addrs; 5920171477Srrs struct thread *td; 5921163953Srrs 5922171477Srrs td = (struct thread *)p; 5923185435Sbz 5924166675Srrs SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize); 5925221249Stuexen#ifdef INET 5926171477Srrs if (addrs->addr->sa_family == AF_INET) { 5927238501Stuexen if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) { 5928171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5929171477Srrs error = EINVAL; 5930171477Srrs break; 5931171477Srrs } 5932188590Srrs if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) { 5933188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5934185435Sbz break; 5935171477Srrs } 5936221249Stuexen } else 5937221249Stuexen#endif 5938185435Sbz#ifdef INET6 5939221249Stuexen if (addrs->addr->sa_family == AF_INET6) { 5940238501Stuexen if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) { 5941171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5942171477Srrs error = EINVAL; 5943171477Srrs break; 5944171477Srrs } 5945224641Stuexen if (td != NULL && 5946224641Stuexen (error = prison_local_ip6(td->td_ucred, 5947224641Stuexen &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr), 5948188590Srrs (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) { 5949188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5950185435Sbz break; 5951185435Sbz } 5952221249Stuexen } else 5953185435Sbz#endif 5954221249Stuexen { 5955185435Sbz error = EAFNOSUPPORT; 5956185435Sbz break; 5957171477Srrs } 5958228653Stuexen sctp_bindx_delete_address(inp, addrs->addr, 5959170606Srrs addrs->sget_assoc_id, vrf_id, 5960170606Srrs &error); 5961223132Stuexen break; 5962163953Srrs } 5963223132Stuexen case SCTP_EVENT: 5964223132Stuexen { 5965223132Stuexen struct sctp_event *event; 5966223132Stuexen uint32_t event_type; 5967223132Stuexen 5968223132Stuexen SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, optsize); 5969223132Stuexen SCTP_FIND_STCB(inp, stcb, event->se_assoc_id); 5970223132Stuexen switch (event->se_type) { 5971223132Stuexen case SCTP_ASSOC_CHANGE: 5972223132Stuexen event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT; 5973223132Stuexen break; 5974223132Stuexen case SCTP_PEER_ADDR_CHANGE: 5975223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPADDREVNT; 5976223132Stuexen break; 5977223132Stuexen case SCTP_REMOTE_ERROR: 5978223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPEERERR; 5979223132Stuexen break; 5980223132Stuexen case SCTP_SEND_FAILED: 5981223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT; 5982223132Stuexen break; 5983223132Stuexen case SCTP_SHUTDOWN_EVENT: 5984223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT; 5985223132Stuexen break; 5986223132Stuexen case SCTP_ADAPTATION_INDICATION: 5987223132Stuexen event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT; 5988223132Stuexen break; 5989223132Stuexen case SCTP_PARTIAL_DELIVERY_EVENT: 5990223132Stuexen event_type = SCTP_PCB_FLAGS_PDAPIEVNT; 5991223132Stuexen break; 5992223132Stuexen case SCTP_AUTHENTICATION_EVENT: 5993223132Stuexen event_type = SCTP_PCB_FLAGS_AUTHEVNT; 5994223132Stuexen break; 5995223132Stuexen case SCTP_STREAM_RESET_EVENT: 5996223132Stuexen event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT; 5997223132Stuexen break; 5998223132Stuexen case SCTP_SENDER_DRY_EVENT: 5999223132Stuexen event_type = SCTP_PCB_FLAGS_DRYEVNT; 6000223132Stuexen break; 6001223132Stuexen case SCTP_NOTIFICATIONS_STOPPED_EVENT: 6002223132Stuexen event_type = 0; 6003223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); 6004223132Stuexen error = ENOTSUP; 6005223132Stuexen break; 6006235009Stuexen case SCTP_ASSOC_RESET_EVENT: 6007235009Stuexen event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT; 6008235009Stuexen break; 6009235009Stuexen case SCTP_STREAM_CHANGE_EVENT: 6010235009Stuexen event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT; 6011235009Stuexen break; 6012235075Stuexen case SCTP_SEND_FAILED_EVENT: 6013235075Stuexen event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT; 6014235075Stuexen break; 6015223132Stuexen default: 6016223132Stuexen event_type = 0; 6017223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6018223132Stuexen error = EINVAL; 6019223132Stuexen break; 6020223132Stuexen } 6021223132Stuexen if (event_type > 0) { 6022223132Stuexen if (stcb) { 6023223132Stuexen if (event->se_on) { 6024223132Stuexen sctp_stcb_feature_on(inp, stcb, event_type); 6025223132Stuexen if (event_type == SCTP_PCB_FLAGS_DRYEVNT) { 6026223132Stuexen if (TAILQ_EMPTY(&stcb->asoc.send_queue) && 6027223132Stuexen TAILQ_EMPTY(&stcb->asoc.sent_queue) && 6028223132Stuexen (stcb->asoc.stream_queue_cnt == 0)) { 6029223132Stuexen sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED); 6030223132Stuexen } 6031223132Stuexen } 6032223132Stuexen } else { 6033223132Stuexen sctp_stcb_feature_off(inp, stcb, event_type); 6034223132Stuexen } 6035223132Stuexen SCTP_TCB_UNLOCK(stcb); 6036223132Stuexen } else { 6037223132Stuexen /* 6038223132Stuexen * We don't want to send up a storm 6039223132Stuexen * of events, so return an error for 6040223132Stuexen * sender dry events 6041223132Stuexen */ 6042223132Stuexen if ((event_type == SCTP_PCB_FLAGS_DRYEVNT) && 6043224918Stuexen ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) && 6044224918Stuexen ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) && 6045223132Stuexen ((event->se_assoc_id == SCTP_ALL_ASSOC) || 6046223132Stuexen (event->se_assoc_id == SCTP_CURRENT_ASSOC))) { 6047223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); 6048223132Stuexen error = ENOTSUP; 6049223132Stuexen break; 6050223132Stuexen } 6051224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6052224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6053224918Stuexen (event->se_assoc_id == SCTP_FUTURE_ASSOC) || 6054223132Stuexen (event->se_assoc_id == SCTP_ALL_ASSOC)) { 6055223132Stuexen SCTP_INP_WLOCK(inp); 6056223132Stuexen if (event->se_on) { 6057223132Stuexen sctp_feature_on(inp, event_type); 6058223132Stuexen } else { 6059223132Stuexen sctp_feature_off(inp, event_type); 6060223132Stuexen } 6061223132Stuexen SCTP_INP_WUNLOCK(inp); 6062223132Stuexen } 6063223132Stuexen if ((event->se_assoc_id == SCTP_CURRENT_ASSOC) || 6064223132Stuexen (event->se_assoc_id == SCTP_ALL_ASSOC)) { 6065223132Stuexen SCTP_INP_RLOCK(inp); 6066223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 6067223132Stuexen SCTP_TCB_LOCK(stcb); 6068223132Stuexen if (event->se_on) { 6069223132Stuexen sctp_stcb_feature_on(inp, stcb, event_type); 6070223132Stuexen } else { 6071223132Stuexen sctp_stcb_feature_off(inp, stcb, event_type); 6072223132Stuexen } 6073223132Stuexen SCTP_TCB_UNLOCK(stcb); 6074223132Stuexen } 6075223132Stuexen SCTP_INP_RUNLOCK(inp); 6076223132Stuexen } 6077223132Stuexen } 6078223132Stuexen } 6079223132Stuexen break; 6080223132Stuexen } 6081223132Stuexen case SCTP_RECVRCVINFO: 6082223132Stuexen { 6083223132Stuexen int *onoff; 6084223132Stuexen 6085223132Stuexen SCTP_CHECK_AND_CAST(onoff, optval, int, optsize); 6086223132Stuexen SCTP_INP_WLOCK(inp); 6087223132Stuexen if (*onoff != 0) { 6088223132Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO); 6089223132Stuexen } else { 6090223132Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO); 6091223132Stuexen } 6092223132Stuexen SCTP_INP_WUNLOCK(inp); 6093223132Stuexen break; 6094223132Stuexen } 6095223132Stuexen case SCTP_RECVNXTINFO: 6096223132Stuexen { 6097223132Stuexen int *onoff; 6098223132Stuexen 6099223132Stuexen SCTP_CHECK_AND_CAST(onoff, optval, int, optsize); 6100223132Stuexen SCTP_INP_WLOCK(inp); 6101223132Stuexen if (*onoff != 0) { 6102223132Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO); 6103223132Stuexen } else { 6104223132Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO); 6105223132Stuexen } 6106223132Stuexen SCTP_INP_WUNLOCK(inp); 6107223132Stuexen break; 6108223132Stuexen } 6109223132Stuexen case SCTP_DEFAULT_SNDINFO: 6110223132Stuexen { 6111223132Stuexen struct sctp_sndinfo *info; 6112223162Stuexen uint16_t policy; 6113223132Stuexen 6114223132Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, optsize); 6115223132Stuexen SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id); 6116223132Stuexen 6117223132Stuexen if (stcb) { 6118223132Stuexen if (info->snd_sid < stcb->asoc.streamoutcnt) { 6119223132Stuexen stcb->asoc.def_send.sinfo_stream = info->snd_sid; 6120223162Stuexen policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); 6121223132Stuexen stcb->asoc.def_send.sinfo_flags = info->snd_flags; 6122223162Stuexen stcb->asoc.def_send.sinfo_flags |= policy; 6123223132Stuexen stcb->asoc.def_send.sinfo_ppid = info->snd_ppid; 6124223132Stuexen stcb->asoc.def_send.sinfo_context = info->snd_context; 6125223132Stuexen } else { 6126223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6127223132Stuexen error = EINVAL; 6128223132Stuexen } 6129223132Stuexen SCTP_TCB_UNLOCK(stcb); 6130223132Stuexen } else { 6131224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6132224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6133224918Stuexen (info->snd_assoc_id == SCTP_FUTURE_ASSOC) || 6134223132Stuexen (info->snd_assoc_id == SCTP_ALL_ASSOC)) { 6135223132Stuexen SCTP_INP_WLOCK(inp); 6136223132Stuexen inp->def_send.sinfo_stream = info->snd_sid; 6137223162Stuexen policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags); 6138223132Stuexen inp->def_send.sinfo_flags = info->snd_flags; 6139223162Stuexen inp->def_send.sinfo_flags |= policy; 6140223132Stuexen inp->def_send.sinfo_ppid = info->snd_ppid; 6141223132Stuexen inp->def_send.sinfo_context = info->snd_context; 6142223132Stuexen SCTP_INP_WUNLOCK(inp); 6143223132Stuexen } 6144223132Stuexen if ((info->snd_assoc_id == SCTP_CURRENT_ASSOC) || 6145223132Stuexen (info->snd_assoc_id == SCTP_ALL_ASSOC)) { 6146223132Stuexen SCTP_INP_RLOCK(inp); 6147223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 6148223132Stuexen SCTP_TCB_LOCK(stcb); 6149223132Stuexen if (info->snd_sid < stcb->asoc.streamoutcnt) { 6150223132Stuexen stcb->asoc.def_send.sinfo_stream = info->snd_sid; 6151223162Stuexen policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); 6152223132Stuexen stcb->asoc.def_send.sinfo_flags = info->snd_flags; 6153223162Stuexen stcb->asoc.def_send.sinfo_flags |= policy; 6154223132Stuexen stcb->asoc.def_send.sinfo_ppid = info->snd_ppid; 6155223132Stuexen stcb->asoc.def_send.sinfo_context = info->snd_context; 6156223132Stuexen } 6157223132Stuexen SCTP_TCB_UNLOCK(stcb); 6158223132Stuexen } 6159223132Stuexen SCTP_INP_RUNLOCK(inp); 6160223132Stuexen } 6161223132Stuexen } 6162223132Stuexen break; 6163223132Stuexen } 6164223162Stuexen case SCTP_DEFAULT_PRINFO: 6165223162Stuexen { 6166223162Stuexen struct sctp_default_prinfo *info; 6167223162Stuexen 6168223162Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, optsize); 6169223162Stuexen SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id); 6170223162Stuexen 6171283706Stuexen if (info->pr_policy > SCTP_PR_SCTP_MAX) { 6172223162Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6173223162Stuexen error = EINVAL; 6174223162Stuexen break; 6175223162Stuexen } 6176223162Stuexen if (stcb) { 6177223162Stuexen stcb->asoc.def_send.sinfo_flags &= 0xfff0; 6178223162Stuexen stcb->asoc.def_send.sinfo_flags |= info->pr_policy; 6179224918Stuexen stcb->asoc.def_send.sinfo_timetolive = info->pr_value; 6180223162Stuexen SCTP_TCB_UNLOCK(stcb); 6181223162Stuexen } else { 6182224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6183224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6184224918Stuexen (info->pr_assoc_id == SCTP_FUTURE_ASSOC) || 6185223162Stuexen (info->pr_assoc_id == SCTP_ALL_ASSOC)) { 6186223162Stuexen SCTP_INP_WLOCK(inp); 6187223162Stuexen inp->def_send.sinfo_flags &= 0xfff0; 6188223162Stuexen inp->def_send.sinfo_flags |= info->pr_policy; 6189224918Stuexen inp->def_send.sinfo_timetolive = info->pr_value; 6190223162Stuexen SCTP_INP_WUNLOCK(inp); 6191223162Stuexen } 6192223162Stuexen if ((info->pr_assoc_id == SCTP_CURRENT_ASSOC) || 6193223162Stuexen (info->pr_assoc_id == SCTP_ALL_ASSOC)) { 6194223162Stuexen SCTP_INP_RLOCK(inp); 6195223162Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 6196223162Stuexen SCTP_TCB_LOCK(stcb); 6197223162Stuexen stcb->asoc.def_send.sinfo_flags &= 0xfff0; 6198223162Stuexen stcb->asoc.def_send.sinfo_flags |= info->pr_policy; 6199224918Stuexen stcb->asoc.def_send.sinfo_timetolive = info->pr_value; 6200223162Stuexen SCTP_TCB_UNLOCK(stcb); 6201223162Stuexen } 6202223162Stuexen SCTP_INP_RUNLOCK(inp); 6203223162Stuexen } 6204223162Stuexen } 6205223162Stuexen break; 6206223162Stuexen } 6207224641Stuexen case SCTP_PEER_ADDR_THLDS: 6208224641Stuexen /* Applies to the specific association */ 6209224641Stuexen { 6210224641Stuexen struct sctp_paddrthlds *thlds; 6211224641Stuexen struct sctp_nets *net; 6212283699Stuexen struct sockaddr *addr; 6213224641Stuexen 6214283699Stuexen#if defined(INET) && defined(INET6) 6215283699Stuexen struct sockaddr_in sin_store; 6216283699Stuexen 6217283699Stuexen#endif 6218283699Stuexen 6219224641Stuexen SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, optsize); 6220224641Stuexen SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id); 6221283699Stuexen 6222283699Stuexen#if defined(INET) && defined(INET6) 6223283699Stuexen if (thlds->spt_address.ss_family == AF_INET6) { 6224283699Stuexen struct sockaddr_in6 *sin6; 6225283699Stuexen 6226283699Stuexen sin6 = (struct sockaddr_in6 *)&thlds->spt_address; 6227283699Stuexen if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 6228283699Stuexen in6_sin6_2_sin(&sin_store, sin6); 6229283699Stuexen addr = (struct sockaddr *)&sin_store; 6230283699Stuexen } else { 6231283699Stuexen addr = (struct sockaddr *)&thlds->spt_address; 6232283699Stuexen } 6233224641Stuexen } else { 6234283699Stuexen addr = (struct sockaddr *)&thlds->spt_address; 6235283699Stuexen } 6236283699Stuexen#else 6237283699Stuexen addr = (struct sockaddr *)&thlds->spt_address; 6238283699Stuexen#endif 6239283699Stuexen if (stcb != NULL) { 6240283699Stuexen net = sctp_findnet(stcb, addr); 6241283699Stuexen } else { 6242224641Stuexen /* 6243224641Stuexen * We increment here since 6244224641Stuexen * sctp_findassociation_ep_addr() wil do a 6245224641Stuexen * decrement if it finds the stcb as long as 6246224641Stuexen * the locked tcb (last argument) is NOT a 6247224641Stuexen * TCB.. aka NULL. 6248224641Stuexen */ 6249283699Stuexen net = NULL; 6250224641Stuexen SCTP_INP_INCR_REF(inp); 6251283699Stuexen stcb = sctp_findassociation_ep_addr(&inp, addr, 6252224641Stuexen &net, NULL, NULL); 6253224641Stuexen if (stcb == NULL) { 6254224641Stuexen SCTP_INP_DECR_REF(inp); 6255224641Stuexen } 6256224641Stuexen } 6257283699Stuexen if ((stcb != NULL) && (net == NULL)) { 6258224641Stuexen#ifdef INET 6259283699Stuexen if (addr->sa_family == AF_INET) { 6260224641Stuexen 6261224641Stuexen struct sockaddr_in *sin; 6262224641Stuexen 6263283699Stuexen sin = (struct sockaddr_in *)addr; 6264283699Stuexen if (sin->sin_addr.s_addr != INADDR_ANY) { 6265224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6266224641Stuexen SCTP_TCB_UNLOCK(stcb); 6267224641Stuexen error = EINVAL; 6268224641Stuexen break; 6269224641Stuexen } 6270224641Stuexen } else 6271224641Stuexen#endif 6272224641Stuexen#ifdef INET6 6273283699Stuexen if (addr->sa_family == AF_INET6) { 6274224641Stuexen struct sockaddr_in6 *sin6; 6275224641Stuexen 6276283699Stuexen sin6 = (struct sockaddr_in6 *)addr; 6277224641Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 6278224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6279224641Stuexen SCTP_TCB_UNLOCK(stcb); 6280224641Stuexen error = EINVAL; 6281224641Stuexen break; 6282224641Stuexen } 6283224641Stuexen } else 6284224641Stuexen#endif 6285224641Stuexen { 6286224641Stuexen error = EAFNOSUPPORT; 6287224641Stuexen SCTP_TCB_UNLOCK(stcb); 6288224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 6289224641Stuexen break; 6290224641Stuexen } 6291224641Stuexen } 6292283699Stuexen if (stcb != NULL) { 6293283699Stuexen if (net != NULL) { 6294283727Stuexen net->failure_threshold = thlds->spt_pathmaxrxt; 6295283727Stuexen net->pf_threshold = thlds->spt_pathpfthld; 6296224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 6297283727Stuexen if ((net->error_count > net->failure_threshold) || 6298283727Stuexen (net->error_count <= net->pf_threshold)) { 6299224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 6300224641Stuexen } 6301224641Stuexen } else { 6302283727Stuexen if ((net->error_count > net->pf_threshold) && 6303283727Stuexen (net->error_count <= net->failure_threshold)) { 6304224641Stuexen net->dest_state |= SCTP_ADDR_PF; 6305224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 6306283822Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, 6307283822Stuexen stcb->sctp_ep, stcb, net, 6308283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_17); 6309224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 6310224641Stuexen } 6311224641Stuexen } 6312224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 6313283727Stuexen if (net->error_count > net->failure_threshold) { 6314224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 6315235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); 6316224641Stuexen } 6317224641Stuexen } else { 6318283727Stuexen if (net->error_count <= net->failure_threshold) { 6319224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 6320235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); 6321224641Stuexen } 6322224641Stuexen } 6323224641Stuexen } else { 6324224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 6325283727Stuexen net->failure_threshold = thlds->spt_pathmaxrxt; 6326283727Stuexen net->pf_threshold = thlds->spt_pathpfthld; 6327224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 6328283727Stuexen if ((net->error_count > net->failure_threshold) || 6329283727Stuexen (net->error_count <= net->pf_threshold)) { 6330224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 6331224641Stuexen } 6332224641Stuexen } else { 6333283727Stuexen if ((net->error_count > net->pf_threshold) && 6334283727Stuexen (net->error_count <= net->failure_threshold)) { 6335224641Stuexen net->dest_state |= SCTP_ADDR_PF; 6336224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 6337283822Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, 6338283822Stuexen stcb->sctp_ep, stcb, net, 6339283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_18); 6340224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 6341224641Stuexen } 6342224641Stuexen } 6343224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 6344283727Stuexen if (net->error_count > net->failure_threshold) { 6345224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 6346235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); 6347224641Stuexen } 6348224641Stuexen } else { 6349283727Stuexen if (net->error_count <= net->failure_threshold) { 6350224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 6351235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); 6352224641Stuexen } 6353224641Stuexen } 6354224641Stuexen } 6355224641Stuexen stcb->asoc.def_net_failure = thlds->spt_pathmaxrxt; 6356224641Stuexen stcb->asoc.def_net_pf_threshold = thlds->spt_pathpfthld; 6357224641Stuexen } 6358283725Stuexen SCTP_TCB_UNLOCK(stcb); 6359224641Stuexen } else { 6360224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6361224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6362224918Stuexen (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) { 6363224641Stuexen SCTP_INP_WLOCK(inp); 6364224641Stuexen inp->sctp_ep.def_net_failure = thlds->spt_pathmaxrxt; 6365224641Stuexen inp->sctp_ep.def_net_pf_threshold = thlds->spt_pathpfthld; 6366224641Stuexen SCTP_INP_WUNLOCK(inp); 6367224641Stuexen } else { 6368224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6369224641Stuexen error = EINVAL; 6370224641Stuexen } 6371224641Stuexen } 6372224641Stuexen break; 6373224641Stuexen } 6374227755Stuexen case SCTP_REMOTE_UDP_ENCAPS_PORT: 6375227755Stuexen { 6376227755Stuexen struct sctp_udpencaps *encaps; 6377227755Stuexen struct sctp_nets *net; 6378283699Stuexen struct sockaddr *addr; 6379227755Stuexen 6380283699Stuexen#if defined(INET) && defined(INET6) 6381283699Stuexen struct sockaddr_in sin_store; 6382283699Stuexen 6383283699Stuexen#endif 6384283699Stuexen 6385227755Stuexen SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, optsize); 6386227755Stuexen SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id); 6387283699Stuexen 6388283699Stuexen#if defined(INET) && defined(INET6) 6389283699Stuexen if (encaps->sue_address.ss_family == AF_INET6) { 6390283699Stuexen struct sockaddr_in6 *sin6; 6391283699Stuexen 6392283699Stuexen sin6 = (struct sockaddr_in6 *)&encaps->sue_address; 6393283699Stuexen if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 6394283699Stuexen in6_sin6_2_sin(&sin_store, sin6); 6395283699Stuexen addr = (struct sockaddr *)&sin_store; 6396283699Stuexen } else { 6397283699Stuexen addr = (struct sockaddr *)&encaps->sue_address; 6398283699Stuexen } 6399227755Stuexen } else { 6400283699Stuexen addr = (struct sockaddr *)&encaps->sue_address; 6401283699Stuexen } 6402283699Stuexen#else 6403283699Stuexen addr = (struct sockaddr *)&encaps->sue_address; 6404283699Stuexen#endif 6405283699Stuexen if (stcb != NULL) { 6406283699Stuexen net = sctp_findnet(stcb, addr); 6407283699Stuexen } else { 6408227755Stuexen /* 6409227755Stuexen * We increment here since 6410227755Stuexen * sctp_findassociation_ep_addr() wil do a 6411227755Stuexen * decrement if it finds the stcb as long as 6412227755Stuexen * the locked tcb (last argument) is NOT a 6413227755Stuexen * TCB.. aka NULL. 6414227755Stuexen */ 6415227755Stuexen net = NULL; 6416227755Stuexen SCTP_INP_INCR_REF(inp); 6417283699Stuexen stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL); 6418227755Stuexen if (stcb == NULL) { 6419227755Stuexen SCTP_INP_DECR_REF(inp); 6420227755Stuexen } 6421227755Stuexen } 6422283699Stuexen if ((stcb != NULL) && (net == NULL)) { 6423227755Stuexen#ifdef INET 6424283699Stuexen if (addr->sa_family == AF_INET) { 6425227755Stuexen 6426227755Stuexen struct sockaddr_in *sin; 6427227755Stuexen 6428283699Stuexen sin = (struct sockaddr_in *)addr; 6429283699Stuexen if (sin->sin_addr.s_addr != INADDR_ANY) { 6430227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6431227755Stuexen SCTP_TCB_UNLOCK(stcb); 6432227755Stuexen error = EINVAL; 6433227755Stuexen break; 6434227755Stuexen } 6435227755Stuexen } else 6436227755Stuexen#endif 6437227755Stuexen#ifdef INET6 6438283699Stuexen if (addr->sa_family == AF_INET6) { 6439227755Stuexen struct sockaddr_in6 *sin6; 6440227755Stuexen 6441283699Stuexen sin6 = (struct sockaddr_in6 *)addr; 6442227755Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 6443227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6444227755Stuexen SCTP_TCB_UNLOCK(stcb); 6445227755Stuexen error = EINVAL; 6446227755Stuexen break; 6447227755Stuexen } 6448227755Stuexen } else 6449227755Stuexen#endif 6450227755Stuexen { 6451227755Stuexen error = EAFNOSUPPORT; 6452227755Stuexen SCTP_TCB_UNLOCK(stcb); 6453227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 6454227755Stuexen break; 6455227755Stuexen } 6456227755Stuexen } 6457283699Stuexen if (stcb != NULL) { 6458283699Stuexen if (net != NULL) { 6459227755Stuexen net->port = encaps->sue_port; 6460227755Stuexen } else { 6461227755Stuexen stcb->asoc.port = encaps->sue_port; 6462227755Stuexen } 6463227755Stuexen SCTP_TCB_UNLOCK(stcb); 6464227755Stuexen } else { 6465227755Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6466227755Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6467227755Stuexen (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) { 6468227755Stuexen SCTP_INP_WLOCK(inp); 6469227755Stuexen inp->sctp_ep.port = encaps->sue_port; 6470227755Stuexen SCTP_INP_WUNLOCK(inp); 6471227755Stuexen } else { 6472227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6473227755Stuexen error = EINVAL; 6474227755Stuexen } 6475227755Stuexen } 6476227755Stuexen break; 6477227755Stuexen } 6478270356Stuexen case SCTP_ECN_SUPPORTED: 6479270356Stuexen { 6480270356Stuexen struct sctp_assoc_value *av; 6481270356Stuexen 6482270356Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 6483270356Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 6484270356Stuexen 6485270356Stuexen if (stcb) { 6486270356Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6487270356Stuexen error = EINVAL; 6488270356Stuexen SCTP_TCB_UNLOCK(stcb); 6489270356Stuexen } else { 6490270356Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6491270356Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6492270356Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 6493270356Stuexen SCTP_INP_WLOCK(inp); 6494270356Stuexen if (av->assoc_value == 0) { 6495270356Stuexen inp->ecn_supported = 0; 6496270356Stuexen } else { 6497270356Stuexen inp->ecn_supported = 1; 6498270356Stuexen } 6499270356Stuexen SCTP_INP_WUNLOCK(inp); 6500270356Stuexen } else { 6501270356Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6502270356Stuexen error = EINVAL; 6503270356Stuexen } 6504270356Stuexen } 6505270356Stuexen break; 6506270356Stuexen } 6507270357Stuexen case SCTP_PR_SUPPORTED: 6508270357Stuexen { 6509270357Stuexen struct sctp_assoc_value *av; 6510270357Stuexen 6511270357Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 6512270357Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 6513270357Stuexen 6514270357Stuexen if (stcb) { 6515270357Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6516270357Stuexen error = EINVAL; 6517270357Stuexen SCTP_TCB_UNLOCK(stcb); 6518270357Stuexen } else { 6519270357Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6520270357Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6521270357Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 6522270357Stuexen SCTP_INP_WLOCK(inp); 6523270357Stuexen if (av->assoc_value == 0) { 6524270357Stuexen inp->prsctp_supported = 0; 6525270357Stuexen } else { 6526270357Stuexen inp->prsctp_supported = 1; 6527270357Stuexen } 6528270357Stuexen SCTP_INP_WUNLOCK(inp); 6529270357Stuexen } else { 6530270357Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6531270357Stuexen error = EINVAL; 6532270357Stuexen } 6533270357Stuexen } 6534270357Stuexen break; 6535270357Stuexen } 6536270362Stuexen case SCTP_AUTH_SUPPORTED: 6537270362Stuexen { 6538270362Stuexen struct sctp_assoc_value *av; 6539270362Stuexen 6540270362Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 6541270362Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 6542270362Stuexen 6543270362Stuexen if (stcb) { 6544270362Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6545270362Stuexen error = EINVAL; 6546270362Stuexen SCTP_TCB_UNLOCK(stcb); 6547270362Stuexen } else { 6548270362Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6549270362Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6550270362Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 6551270362Stuexen if ((av->assoc_value == 0) && 6552270362Stuexen (inp->asconf_supported == 1)) { 6553270362Stuexen /* 6554270362Stuexen * AUTH is required for 6555270362Stuexen * ASCONF 6556270362Stuexen */ 6557270362Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6558270362Stuexen error = EINVAL; 6559270362Stuexen } else { 6560270362Stuexen SCTP_INP_WLOCK(inp); 6561270362Stuexen if (av->assoc_value == 0) { 6562270362Stuexen inp->auth_supported = 0; 6563270362Stuexen } else { 6564270362Stuexen inp->auth_supported = 1; 6565270362Stuexen } 6566270362Stuexen SCTP_INP_WUNLOCK(inp); 6567270362Stuexen } 6568270362Stuexen } else { 6569270362Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6570270362Stuexen error = EINVAL; 6571270362Stuexen } 6572270362Stuexen } 6573270362Stuexen break; 6574270362Stuexen } 6575270362Stuexen case SCTP_ASCONF_SUPPORTED: 6576270362Stuexen { 6577270362Stuexen struct sctp_assoc_value *av; 6578270362Stuexen 6579270362Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 6580270362Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 6581270362Stuexen 6582270362Stuexen if (stcb) { 6583270362Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6584270362Stuexen error = EINVAL; 6585270362Stuexen SCTP_TCB_UNLOCK(stcb); 6586270362Stuexen } else { 6587270362Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6588270362Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6589270362Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 6590270362Stuexen if ((av->assoc_value != 0) && 6591270362Stuexen (inp->auth_supported == 0)) { 6592270362Stuexen /* 6593270362Stuexen * AUTH is required for 6594270362Stuexen * ASCONF 6595270362Stuexen */ 6596270362Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6597270362Stuexen error = EINVAL; 6598270362Stuexen } else { 6599270362Stuexen SCTP_INP_WLOCK(inp); 6600270362Stuexen if (av->assoc_value == 0) { 6601270362Stuexen inp->asconf_supported = 0; 6602270362Stuexen sctp_auth_delete_chunk(SCTP_ASCONF, 6603270362Stuexen inp->sctp_ep.local_auth_chunks); 6604270362Stuexen sctp_auth_delete_chunk(SCTP_ASCONF_ACK, 6605270362Stuexen inp->sctp_ep.local_auth_chunks); 6606270362Stuexen } else { 6607270362Stuexen inp->asconf_supported = 1; 6608270362Stuexen sctp_auth_add_chunk(SCTP_ASCONF, 6609270362Stuexen inp->sctp_ep.local_auth_chunks); 6610270362Stuexen sctp_auth_add_chunk(SCTP_ASCONF_ACK, 6611270362Stuexen inp->sctp_ep.local_auth_chunks); 6612270362Stuexen } 6613270362Stuexen SCTP_INP_WUNLOCK(inp); 6614270362Stuexen } 6615270362Stuexen } else { 6616270362Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6617270362Stuexen error = EINVAL; 6618270362Stuexen } 6619270362Stuexen } 6620270362Stuexen break; 6621270362Stuexen } 6622270361Stuexen case SCTP_RECONFIG_SUPPORTED: 6623270361Stuexen { 6624270361Stuexen struct sctp_assoc_value *av; 6625270361Stuexen 6626270361Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 6627270361Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 6628270361Stuexen 6629270361Stuexen if (stcb) { 6630270361Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6631270361Stuexen error = EINVAL; 6632270361Stuexen SCTP_TCB_UNLOCK(stcb); 6633270361Stuexen } else { 6634270361Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6635270361Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6636270361Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 6637270361Stuexen SCTP_INP_WLOCK(inp); 6638270361Stuexen if (av->assoc_value == 0) { 6639270361Stuexen inp->reconfig_supported = 0; 6640270361Stuexen } else { 6641270361Stuexen inp->reconfig_supported = 1; 6642270361Stuexen } 6643270361Stuexen SCTP_INP_WUNLOCK(inp); 6644270361Stuexen } else { 6645270361Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6646270361Stuexen error = EINVAL; 6647270361Stuexen } 6648270361Stuexen } 6649270361Stuexen break; 6650270361Stuexen } 6651270359Stuexen case SCTP_NRSACK_SUPPORTED: 6652270359Stuexen { 6653270359Stuexen struct sctp_assoc_value *av; 6654270359Stuexen 6655270359Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 6656270359Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 6657270359Stuexen 6658270359Stuexen if (stcb) { 6659270359Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6660270359Stuexen error = EINVAL; 6661270359Stuexen SCTP_TCB_UNLOCK(stcb); 6662270359Stuexen } else { 6663270359Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6664270359Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6665270359Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 6666270359Stuexen SCTP_INP_WLOCK(inp); 6667270359Stuexen if (av->assoc_value == 0) { 6668270359Stuexen inp->nrsack_supported = 0; 6669270359Stuexen } else { 6670270359Stuexen inp->nrsack_supported = 1; 6671270359Stuexen } 6672270359Stuexen SCTP_INP_WUNLOCK(inp); 6673270359Stuexen } else { 6674270359Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6675270359Stuexen error = EINVAL; 6676270359Stuexen } 6677270359Stuexen } 6678270359Stuexen break; 6679270359Stuexen } 6680270360Stuexen case SCTP_PKTDROP_SUPPORTED: 6681270360Stuexen { 6682270360Stuexen struct sctp_assoc_value *av; 6683270360Stuexen 6684270360Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 6685270360Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 6686270360Stuexen 6687270360Stuexen if (stcb) { 6688270360Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6689270360Stuexen error = EINVAL; 6690270360Stuexen SCTP_TCB_UNLOCK(stcb); 6691270360Stuexen } else { 6692270360Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6693270360Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6694270360Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 6695270360Stuexen SCTP_INP_WLOCK(inp); 6696270360Stuexen if (av->assoc_value == 0) { 6697270360Stuexen inp->pktdrop_supported = 0; 6698270360Stuexen } else { 6699270360Stuexen inp->pktdrop_supported = 1; 6700270360Stuexen } 6701270360Stuexen SCTP_INP_WUNLOCK(inp); 6702270360Stuexen } else { 6703270360Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6704270360Stuexen error = EINVAL; 6705270360Stuexen } 6706270360Stuexen } 6707270360Stuexen break; 6708270360Stuexen } 6709283724Stuexen case SCTP_MAX_CWND: 6710283724Stuexen { 6711283724Stuexen struct sctp_assoc_value *av; 6712283724Stuexen struct sctp_nets *net; 6713283724Stuexen 6714283724Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 6715283724Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 6716283724Stuexen 6717283724Stuexen if (stcb) { 6718283724Stuexen stcb->asoc.max_cwnd = av->assoc_value; 6719283724Stuexen if (stcb->asoc.max_cwnd > 0) { 6720283724Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 6721283724Stuexen if ((net->cwnd > stcb->asoc.max_cwnd) && 6722283724Stuexen (net->cwnd > (net->mtu - sizeof(struct sctphdr)))) { 6723283724Stuexen net->cwnd = stcb->asoc.max_cwnd; 6724283724Stuexen if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) { 6725283724Stuexen net->cwnd = net->mtu - sizeof(struct sctphdr); 6726283724Stuexen } 6727283724Stuexen } 6728283724Stuexen } 6729283724Stuexen } 6730283724Stuexen SCTP_TCB_UNLOCK(stcb); 6731283724Stuexen } else { 6732283724Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6733283724Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6734283724Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 6735283724Stuexen SCTP_INP_WLOCK(inp); 6736283724Stuexen inp->max_cwnd = av->assoc_value; 6737283724Stuexen SCTP_INP_WUNLOCK(inp); 6738283724Stuexen } else { 6739283724Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6740283724Stuexen error = EINVAL; 6741283724Stuexen } 6742283724Stuexen } 6743283724Stuexen break; 6744283724Stuexen } 6745163953Srrs default: 6746171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 6747163953Srrs error = ENOPROTOOPT; 6748163953Srrs break; 6749163953Srrs } /* end switch (opt) */ 6750163953Srrs return (error); 6751163953Srrs} 6752163953Srrs 6753163953Srrsint 6754163953Srrssctp_ctloutput(struct socket *so, struct sockopt *sopt) 6755163953Srrs{ 6756166675Srrs void *optval = NULL; 6757166675Srrs size_t optsize = 0; 6758166675Srrs void *p; 6759166675Srrs int error = 0; 6760284633Stuexen struct sctp_inpcb *inp; 6761163953Srrs 6762284633Stuexen if ((sopt->sopt_level == SOL_SOCKET) && 6763284633Stuexen (sopt->sopt_name == SO_SETFIB)) { 6764284633Stuexen inp = (struct sctp_inpcb *)so->so_pcb; 6765284633Stuexen if (inp == NULL) { 6766284633Stuexen SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS); 6767284633Stuexen return (EINVAL); 6768284633Stuexen } 6769284633Stuexen SCTP_INP_WLOCK(inp); 6770284633Stuexen inp->fibnum = so->so_fibnum; 6771284633Stuexen SCTP_INP_WUNLOCK(inp); 6772284633Stuexen return (0); 6773284633Stuexen } 6774163953Srrs if (sopt->sopt_level != IPPROTO_SCTP) { 6775163953Srrs /* wrong proto level... send back up to IP */ 6776163953Srrs#ifdef INET6 6777163953Srrs if (INP_CHECK_SOCKAF(so, AF_INET6)) 6778163953Srrs error = ip6_ctloutput(so, sopt); 6779221249Stuexen#endif /* INET6 */ 6780237565Stuexen#if defined(INET) && defined(INET6) 6781163953Srrs else 6782221249Stuexen#endif 6783221249Stuexen#ifdef INET 6784163953Srrs error = ip_ctloutput(so, sopt); 6785221249Stuexen#endif 6786163953Srrs return (error); 6787163953Srrs } 6788166675Srrs optsize = sopt->sopt_valsize; 6789166675Srrs if (optsize) { 6790170091Srrs SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT); 6791166675Srrs if (optval == NULL) { 6792235091Stuexen SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS); 6793163953Srrs return (ENOBUFS); 6794163953Srrs } 6795166675Srrs error = sooptcopyin(sopt, optval, optsize, optsize); 6796163953Srrs if (error) { 6797170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 6798163953Srrs goto out; 6799163953Srrs } 6800163953Srrs } 6801166675Srrs p = (void *)sopt->sopt_td; 6802163953Srrs if (sopt->sopt_dir == SOPT_SET) { 6803166675Srrs error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p); 6804163953Srrs } else if (sopt->sopt_dir == SOPT_GET) { 6805166675Srrs error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p); 6806163953Srrs } else { 6807235091Stuexen SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6808163953Srrs error = EINVAL; 6809163953Srrs } 6810166675Srrs if ((error == 0) && (optval != NULL)) { 6811166675Srrs error = sooptcopyout(sopt, optval, optsize); 6812170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 6813166675Srrs } else if (optval != NULL) { 6814170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 6815163953Srrs } 6816163953Srrsout: 6817163953Srrs return (error); 6818163953Srrs} 6819163953Srrs 6820221249Stuexen#ifdef INET 6821163953Srrsstatic int 6822163953Srrssctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p) 6823163953Srrs{ 6824163953Srrs int error = 0; 6825163953Srrs int create_lock_on = 0; 6826167598Srrs uint32_t vrf_id; 6827163953Srrs struct sctp_inpcb *inp; 6828163953Srrs struct sctp_tcb *stcb = NULL; 6829163953Srrs 6830163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 6831233005Stuexen if (inp == NULL) { 6832163953Srrs /* I made the same as TCP since we are not setup? */ 6833171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6834163953Srrs return (ECONNRESET); 6835163953Srrs } 6836171943Srrs if (addr == NULL) { 6837171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6838170056Srrs return EINVAL; 6839171943Srrs } 6840221249Stuexen switch (addr->sa_family) { 6841185435Sbz#ifdef INET6 6842221249Stuexen case AF_INET6: 6843221249Stuexen { 6844221249Stuexen struct sockaddr_in6 *sin6p; 6845185694Srrs 6846221249Stuexen if (addr->sa_len != sizeof(struct sockaddr_in6)) { 6847221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6848221249Stuexen return (EINVAL); 6849221249Stuexen } 6850221249Stuexen sin6p = (struct sockaddr_in6 *)addr; 6851221249Stuexen if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6p->sin6_addr)) != 0) { 6852221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 6853221249Stuexen return (error); 6854221249Stuexen } 6855221249Stuexen break; 6856185435Sbz } 6857185435Sbz#endif 6858221249Stuexen#ifdef INET 6859221249Stuexen case AF_INET: 6860221249Stuexen { 6861221249Stuexen struct sockaddr_in *sinp; 6862185694Srrs 6863221249Stuexen if (addr->sa_len != sizeof(struct sockaddr_in)) { 6864221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6865221249Stuexen return (EINVAL); 6866221249Stuexen } 6867221249Stuexen sinp = (struct sockaddr_in *)addr; 6868221249Stuexen if (p != NULL && (error = prison_remote_ip4(p->td_ucred, &sinp->sin_addr)) != 0) { 6869221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 6870221249Stuexen return (error); 6871221249Stuexen } 6872221249Stuexen break; 6873185435Sbz } 6874221249Stuexen#endif 6875221249Stuexen default: 6876185435Sbz SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT); 6877185435Sbz return (EAFNOSUPPORT); 6878170056Srrs } 6879178202Srrs SCTP_INP_INCR_REF(inp); 6880163953Srrs SCTP_ASOC_CREATE_LOCK(inp); 6881163953Srrs create_lock_on = 1; 6882163953Srrs 6883178202Srrs 6884163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 6885163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 6886163953Srrs /* Should I really unlock ? */ 6887171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); 6888163953Srrs error = EFAULT; 6889163953Srrs goto out_now; 6890163953Srrs } 6891163953Srrs#ifdef INET6 6892163953Srrs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 6893163953Srrs (addr->sa_family == AF_INET6)) { 6894171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6895163953Srrs error = EINVAL; 6896163953Srrs goto out_now; 6897163953Srrs } 6898246595Stuexen#endif 6899163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 6900163953Srrs SCTP_PCB_FLAGS_UNBOUND) { 6901163953Srrs /* Bind a ephemeral port */ 6902171572Srrs error = sctp_inpcb_bind(so, NULL, NULL, p); 6903163953Srrs if (error) { 6904163953Srrs goto out_now; 6905163953Srrs } 6906163953Srrs } 6907163953Srrs /* Now do we connect? */ 6908181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && 6909181054Srrs (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) { 6910171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6911163953Srrs error = EINVAL; 6912163953Srrs goto out_now; 6913163953Srrs } 6914163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 6915163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 6916163953Srrs /* We are already connected AND the TCP model */ 6917171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 6918163953Srrs error = EADDRINUSE; 6919163953Srrs goto out_now; 6920163953Srrs } 6921163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 6922163953Srrs SCTP_INP_RLOCK(inp); 6923163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 6924163953Srrs SCTP_INP_RUNLOCK(inp); 6925163953Srrs } else { 6926163953Srrs /* 6927166675Srrs * We increment here since sctp_findassociation_ep_addr() 6928181054Srrs * will do a decrement if it finds the stcb as long as the 6929166675Srrs * locked tcb (last argument) is NOT a TCB.. aka NULL. 6930163953Srrs */ 6931163953Srrs SCTP_INP_INCR_REF(inp); 6932163953Srrs stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL); 6933163953Srrs if (stcb == NULL) { 6934163953Srrs SCTP_INP_DECR_REF(inp); 6935168299Srrs } else { 6936178202Srrs SCTP_TCB_UNLOCK(stcb); 6937163953Srrs } 6938163953Srrs } 6939163953Srrs if (stcb != NULL) { 6940163953Srrs /* Already have or am bring up an association */ 6941171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 6942163953Srrs error = EALREADY; 6943163953Srrs goto out_now; 6944163953Srrs } 6945168299Srrs vrf_id = inp->def_vrf_id; 6946163953Srrs /* We are GOOD to go */ 6947294215Stuexen stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, inp->sctp_ep.pre_open_stream_count, p); 6948163953Srrs if (stcb == NULL) { 6949163953Srrs /* Gak! no memory */ 6950167598Srrs goto out_now; 6951163953Srrs } 6952163953Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 6953163953Srrs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 6954163953Srrs /* Set the connected flag so we can queue data */ 6955163953Srrs soisconnecting(so); 6956163953Srrs } 6957171943Srrs SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); 6958169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 6959163953Srrs 6960163953Srrs /* initialize authentication parameters for the assoc */ 6961163953Srrs sctp_initialize_auth_params(inp, stcb); 6962163953Srrs 6963172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 6964168299Srrs SCTP_TCB_UNLOCK(stcb); 6965163953Srrsout_now: 6966169420Srrs if (create_lock_on) { 6967163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 6968169420Srrs } 6969163953Srrs SCTP_INP_DECR_REF(inp); 6970228907Stuexen return (error); 6971163953Srrs} 6972163953Srrs 6973221249Stuexen#endif 6974221249Stuexen 6975163953Srrsint 6976163953Srrssctp_listen(struct socket *so, int backlog, struct thread *p) 6977163953Srrs{ 6978163953Srrs /* 6979163953Srrs * Note this module depends on the protocol processing being called 6980163953Srrs * AFTER any socket level flags and backlog are applied to the 6981163953Srrs * socket. The traditional way that the socket flags are applied is 6982163953Srrs * AFTER protocol processing. We have made a change to the 6983163953Srrs * sys/kern/uipc_socket.c module to reverse this but this MUST be in 6984163953Srrs * place if the socket API for SCTP is to work properly. 6985163953Srrs */ 6986163953Srrs 6987163953Srrs int error = 0; 6988163953Srrs struct sctp_inpcb *inp; 6989163953Srrs 6990163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 6991233005Stuexen if (inp == NULL) { 6992163953Srrs /* I made the same as TCP since we are not setup? */ 6993171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6994163953Srrs return (ECONNRESET); 6995163953Srrs } 6996181054Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) { 6997181054Srrs /* See if we have a listener */ 6998181054Srrs struct sctp_inpcb *tinp; 6999267771Stuexen union sctp_sockstore store; 7000181054Srrs 7001181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { 7002181054Srrs /* not bound all */ 7003181054Srrs struct sctp_laddr *laddr; 7004181054Srrs 7005181054Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 7006181054Srrs memcpy(&store, &laddr->ifa->address, sizeof(store)); 7007267771Stuexen switch (store.sa.sa_family) { 7008221249Stuexen#ifdef INET 7009221249Stuexen case AF_INET: 7010267771Stuexen store.sin.sin_port = inp->sctp_lport; 7011221249Stuexen break; 7012221249Stuexen#endif 7013221249Stuexen#ifdef INET6 7014221249Stuexen case AF_INET6: 7015267771Stuexen store.sin6.sin6_port = inp->sctp_lport; 7016221249Stuexen break; 7017221249Stuexen#endif 7018221249Stuexen default: 7019221249Stuexen break; 7020221249Stuexen } 7021267771Stuexen tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id); 7022181054Srrs if (tinp && (tinp != inp) && 7023181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && 7024181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 7025181054Srrs (tinp->sctp_socket->so_qlimit)) { 7026181054Srrs /* 7027181054Srrs * we have a listener already and 7028181054Srrs * its not this inp. 7029181054Srrs */ 7030181054Srrs SCTP_INP_DECR_REF(tinp); 7031181054Srrs return (EADDRINUSE); 7032181054Srrs } else if (tinp) { 7033181054Srrs SCTP_INP_DECR_REF(tinp); 7034181054Srrs } 7035181054Srrs } 7036181054Srrs } else { 7037181054Srrs /* Setup a local addr bound all */ 7038181054Srrs memset(&store, 0, sizeof(store)); 7039267771Stuexen#ifdef INET6 7040267771Stuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 7041267771Stuexen store.sa.sa_family = AF_INET6; 7042267771Stuexen store.sa.sa_len = sizeof(struct sockaddr_in6); 7043267771Stuexen } 7044267771Stuexen#endif 7045221249Stuexen#ifdef INET 7046267771Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { 7047267771Stuexen store.sa.sa_family = AF_INET; 7048267771Stuexen store.sa.sa_len = sizeof(struct sockaddr_in); 7049267771Stuexen } 7050267771Stuexen#endif 7051267771Stuexen switch (store.sa.sa_family) { 7052267771Stuexen#ifdef INET 7053221249Stuexen case AF_INET: 7054221249Stuexen store.sin.sin_port = inp->sctp_lport; 7055221249Stuexen break; 7056221249Stuexen#endif 7057181054Srrs#ifdef INET6 7058221249Stuexen case AF_INET6: 7059267771Stuexen store.sin6.sin6_port = inp->sctp_lport; 7060221249Stuexen break; 7061221249Stuexen#endif 7062221249Stuexen default: 7063221249Stuexen break; 7064221249Stuexen } 7065267771Stuexen tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id); 7066181054Srrs if (tinp && (tinp != inp) && 7067181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && 7068181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 7069181054Srrs (tinp->sctp_socket->so_qlimit)) { 7070181054Srrs /* 7071181054Srrs * we have a listener already and its not 7072181054Srrs * this inp. 7073181054Srrs */ 7074181054Srrs SCTP_INP_DECR_REF(tinp); 7075181054Srrs return (EADDRINUSE); 7076181054Srrs } else if (tinp) { 7077283733Stuexen SCTP_INP_DECR_REF(tinp); 7078181054Srrs } 7079181054Srrs } 7080181054Srrs } 7081163953Srrs SCTP_INP_RLOCK(inp); 7082163953Srrs#ifdef SCTP_LOCK_LOGGING 7083179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) { 7084170744Srrs sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK); 7085170744Srrs } 7086163953Srrs#endif 7087163953Srrs SOCK_LOCK(so); 7088163953Srrs error = solisten_proto_check(so); 7089283732Stuexen SOCK_UNLOCK(so); 7090163953Srrs if (error) { 7091169208Srrs SCTP_INP_RUNLOCK(inp); 7092163953Srrs return (error); 7093163953Srrs } 7094181054Srrs if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) && 7095181054Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 7096181054Srrs /* 7097181054Srrs * The unlucky case - We are in the tcp pool with this guy. 7098181054Srrs * - Someone else is in the main inp slot. - We must move 7099181054Srrs * this guy (the listener) to the main slot - We must then 7100181054Srrs * move the guy that was listener to the TCP Pool. 7101181054Srrs */ 7102181054Srrs if (sctp_swap_inpcb_for_listen(inp)) { 7103283732Stuexen SCTP_INP_RUNLOCK(inp); 7104283732Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 7105283732Stuexen return (EADDRINUSE); 7106181054Srrs } 7107181054Srrs } 7108163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 7109163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 7110163953Srrs /* We are already connected AND the TCP model */ 7111163953Srrs SCTP_INP_RUNLOCK(inp); 7112171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 7113163953Srrs return (EADDRINUSE); 7114163953Srrs } 7115181054Srrs SCTP_INP_RUNLOCK(inp); 7116163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { 7117163953Srrs /* We must do a bind. */ 7118171572Srrs if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) { 7119163953Srrs /* bind error, probably perm */ 7120163953Srrs return (error); 7121163953Srrs } 7122163953Srrs } 7123283732Stuexen SOCK_LOCK(so); 7124163953Srrs /* It appears for 7.0 and on, we must always call this. */ 7125163953Srrs solisten_proto(so, backlog); 7126163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 7127163953Srrs /* remove the ACCEPTCONN flag for one-to-many sockets */ 7128163953Srrs so->so_options &= ~SO_ACCEPTCONN; 7129163953Srrs } 7130163953Srrs if (backlog == 0) { 7131163953Srrs /* turning off listen */ 7132163953Srrs so->so_options &= ~SO_ACCEPTCONN; 7133163953Srrs } 7134163953Srrs SOCK_UNLOCK(so); 7135163953Srrs return (error); 7136163953Srrs} 7137163953Srrs 7138163953Srrsstatic int sctp_defered_wakeup_cnt = 0; 7139163953Srrs 7140163953Srrsint 7141163953Srrssctp_accept(struct socket *so, struct sockaddr **addr) 7142163953Srrs{ 7143163953Srrs struct sctp_tcb *stcb; 7144163953Srrs struct sctp_inpcb *inp; 7145163953Srrs union sctp_sockstore store; 7146163953Srrs 7147178251Srrs#ifdef INET6 7148163953Srrs int error; 7149163953Srrs 7150178251Srrs#endif 7151163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 7152163953Srrs 7153233005Stuexen if (inp == NULL) { 7154171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 7155163953Srrs return (ECONNRESET); 7156163953Srrs } 7157163953Srrs SCTP_INP_RLOCK(inp); 7158163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 7159168299Srrs SCTP_INP_RUNLOCK(inp); 7160171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 7161171943Srrs return (EOPNOTSUPP); 7162163953Srrs } 7163163953Srrs if (so->so_state & SS_ISDISCONNECTED) { 7164163953Srrs SCTP_INP_RUNLOCK(inp); 7165171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED); 7166163953Srrs return (ECONNABORTED); 7167163953Srrs } 7168163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 7169163953Srrs if (stcb == NULL) { 7170163953Srrs SCTP_INP_RUNLOCK(inp); 7171171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 7172163953Srrs return (ECONNRESET); 7173163953Srrs } 7174163953Srrs SCTP_TCB_LOCK(stcb); 7175163953Srrs SCTP_INP_RUNLOCK(inp); 7176163953Srrs store = stcb->asoc.primary_destination->ro._l_addr; 7177207924Srrs stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE; 7178163953Srrs SCTP_TCB_UNLOCK(stcb); 7179178251Srrs switch (store.sa.sa_family) { 7180221249Stuexen#ifdef INET 7181178251Srrs case AF_INET: 7182178251Srrs { 7183178251Srrs struct sockaddr_in *sin; 7184163953Srrs 7185178251Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 7186208863Srrs if (sin == NULL) 7187208863Srrs return (ENOMEM); 7188178251Srrs sin->sin_family = AF_INET; 7189178251Srrs sin->sin_len = sizeof(*sin); 7190246595Stuexen sin->sin_port = store.sin.sin_port; 7191246595Stuexen sin->sin_addr = store.sin.sin_addr; 7192178251Srrs *addr = (struct sockaddr *)sin; 7193178251Srrs break; 7194178251Srrs } 7195221249Stuexen#endif 7196178251Srrs#ifdef INET6 7197178251Srrs case AF_INET6: 7198178251Srrs { 7199178251Srrs struct sockaddr_in6 *sin6; 7200163953Srrs 7201178251Srrs SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); 7202208863Srrs if (sin6 == NULL) 7203208863Srrs return (ENOMEM); 7204178251Srrs sin6->sin6_family = AF_INET6; 7205178251Srrs sin6->sin6_len = sizeof(*sin6); 7206246595Stuexen sin6->sin6_port = store.sin6.sin6_port; 7207246595Stuexen sin6->sin6_addr = store.sin6.sin6_addr; 7208178251Srrs if ((error = sa6_recoverscope(sin6)) != 0) { 7209178251Srrs SCTP_FREE_SONAME(sin6); 7210178251Srrs return (error); 7211178251Srrs } 7212178251Srrs *addr = (struct sockaddr *)sin6; 7213178251Srrs break; 7214164085Srrs } 7215178251Srrs#endif 7216178251Srrs default: 7217178251Srrs /* TSNH */ 7218178251Srrs break; 7219163953Srrs } 7220163953Srrs /* Wake any delayed sleep action */ 7221163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { 7222166086Srrs SCTP_INP_WLOCK(inp); 7223163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE; 7224163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) { 7225163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT; 7226166086Srrs SCTP_INP_WUNLOCK(inp); 7227163953Srrs SOCKBUF_LOCK(&inp->sctp_socket->so_snd); 7228163953Srrs if (sowriteable(inp->sctp_socket)) { 7229163953Srrs sowwakeup_locked(inp->sctp_socket); 7230163953Srrs } else { 7231163953Srrs SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd); 7232163953Srrs } 7233166086Srrs SCTP_INP_WLOCK(inp); 7234163953Srrs } 7235163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) { 7236163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT; 7237166086Srrs SCTP_INP_WUNLOCK(inp); 7238163953Srrs SOCKBUF_LOCK(&inp->sctp_socket->so_rcv); 7239163953Srrs if (soreadable(inp->sctp_socket)) { 7240163953Srrs sctp_defered_wakeup_cnt++; 7241163953Srrs sorwakeup_locked(inp->sctp_socket); 7242163953Srrs } else { 7243163953Srrs SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv); 7244163953Srrs } 7245166086Srrs SCTP_INP_WLOCK(inp); 7246163953Srrs } 7247166086Srrs SCTP_INP_WUNLOCK(inp); 7248163953Srrs } 7249207924Srrs if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 7250207924Srrs SCTP_TCB_LOCK(stcb); 7251283822Stuexen sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 7252283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_19); 7253207924Srrs } 7254163953Srrs return (0); 7255163953Srrs} 7256163953Srrs 7257221249Stuexen#ifdef INET 7258163953Srrsint 7259163953Srrssctp_ingetaddr(struct socket *so, struct sockaddr **addr) 7260163953Srrs{ 7261163953Srrs struct sockaddr_in *sin; 7262167598Srrs uint32_t vrf_id; 7263163953Srrs struct sctp_inpcb *inp; 7264167695Srrs struct sctp_ifa *sctp_ifa; 7265163953Srrs 7266163953Srrs /* 7267163953Srrs * Do the malloc first in case it blocks. 7268163953Srrs */ 7269163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 7270208863Srrs if (sin == NULL) 7271208863Srrs return (ENOMEM); 7272163953Srrs sin->sin_family = AF_INET; 7273163953Srrs sin->sin_len = sizeof(*sin); 7274163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 7275163953Srrs if (!inp) { 7276163953Srrs SCTP_FREE_SONAME(sin); 7277171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 7278228907Stuexen return (ECONNRESET); 7279163953Srrs } 7280163953Srrs SCTP_INP_RLOCK(inp); 7281163953Srrs sin->sin_port = inp->sctp_lport; 7282163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 7283163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 7284163953Srrs struct sctp_tcb *stcb; 7285163953Srrs struct sockaddr_in *sin_a; 7286163953Srrs struct sctp_nets *net; 7287163953Srrs int fnd; 7288163953Srrs 7289163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 7290163953Srrs if (stcb == NULL) { 7291163953Srrs goto notConn; 7292163953Srrs } 7293163953Srrs fnd = 0; 7294163953Srrs sin_a = NULL; 7295163953Srrs SCTP_TCB_LOCK(stcb); 7296163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 7297163953Srrs sin_a = (struct sockaddr_in *)&net->ro._l_addr; 7298164085Srrs if (sin_a == NULL) 7299164085Srrs /* this will make coverity happy */ 7300164085Srrs continue; 7301164085Srrs 7302163953Srrs if (sin_a->sin_family == AF_INET) { 7303163953Srrs fnd = 1; 7304163953Srrs break; 7305163953Srrs } 7306163953Srrs } 7307163953Srrs if ((!fnd) || (sin_a == NULL)) { 7308163953Srrs /* punt */ 7309163953Srrs SCTP_TCB_UNLOCK(stcb); 7310163953Srrs goto notConn; 7311163953Srrs } 7312168299Srrs vrf_id = inp->def_vrf_id; 7313167598Srrs sctp_ifa = sctp_source_address_selection(inp, 7314167598Srrs stcb, 7315168299Srrs (sctp_route_t *) & net->ro, 7316167598Srrs net, 0, vrf_id); 7317167598Srrs if (sctp_ifa) { 7318167598Srrs sin->sin_addr = sctp_ifa->address.sin.sin_addr; 7319167598Srrs sctp_free_ifa(sctp_ifa); 7320167598Srrs } 7321163953Srrs SCTP_TCB_UNLOCK(stcb); 7322163953Srrs } else { 7323163953Srrs /* For the bound all case you get back 0 */ 7324163953Srrs notConn: 7325163953Srrs sin->sin_addr.s_addr = 0; 7326163953Srrs } 7327163953Srrs 7328163953Srrs } else { 7329163953Srrs /* Take the first IPv4 address in the list */ 7330163953Srrs struct sctp_laddr *laddr; 7331163953Srrs int fnd = 0; 7332163953Srrs 7333163953Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 7334167598Srrs if (laddr->ifa->address.sa.sa_family == AF_INET) { 7335163953Srrs struct sockaddr_in *sin_a; 7336163953Srrs 7337271746Stuexen sin_a = &laddr->ifa->address.sin; 7338163953Srrs sin->sin_addr = sin_a->sin_addr; 7339163953Srrs fnd = 1; 7340163953Srrs break; 7341163953Srrs } 7342163953Srrs } 7343163953Srrs if (!fnd) { 7344163953Srrs SCTP_FREE_SONAME(sin); 7345163953Srrs SCTP_INP_RUNLOCK(inp); 7346171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 7347228907Stuexen return (ENOENT); 7348163953Srrs } 7349163953Srrs } 7350163953Srrs SCTP_INP_RUNLOCK(inp); 7351163953Srrs (*addr) = (struct sockaddr *)sin; 7352163953Srrs return (0); 7353163953Srrs} 7354163953Srrs 7355163953Srrsint 7356163953Srrssctp_peeraddr(struct socket *so, struct sockaddr **addr) 7357163953Srrs{ 7358231895Stuexen struct sockaddr_in *sin; 7359166086Srrs int fnd; 7360163953Srrs struct sockaddr_in *sin_a; 7361163953Srrs struct sctp_inpcb *inp; 7362163953Srrs struct sctp_tcb *stcb; 7363163953Srrs struct sctp_nets *net; 7364163953Srrs 7365163953Srrs /* Do the malloc first in case it blocks. */ 7366163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 7367208863Srrs if (sin == NULL) 7368208863Srrs return (ENOMEM); 7369163953Srrs sin->sin_family = AF_INET; 7370163953Srrs sin->sin_len = sizeof(*sin); 7371163953Srrs 7372163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 7373228907Stuexen if ((inp == NULL) || 7374228907Stuexen ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { 7375228907Stuexen /* UDP type and listeners will drop out here */ 7376163953Srrs SCTP_FREE_SONAME(sin); 7377228907Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 7378228907Stuexen return (ENOTCONN); 7379163953Srrs } 7380163953Srrs SCTP_INP_RLOCK(inp); 7381163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 7382169420Srrs if (stcb) { 7383163953Srrs SCTP_TCB_LOCK(stcb); 7384169420Srrs } 7385163953Srrs SCTP_INP_RUNLOCK(inp); 7386163953Srrs if (stcb == NULL) { 7387163953Srrs SCTP_FREE_SONAME(sin); 7388171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 7389228907Stuexen return (ECONNRESET); 7390163953Srrs } 7391163953Srrs fnd = 0; 7392163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 7393163953Srrs sin_a = (struct sockaddr_in *)&net->ro._l_addr; 7394163953Srrs if (sin_a->sin_family == AF_INET) { 7395163953Srrs fnd = 1; 7396163953Srrs sin->sin_port = stcb->rport; 7397163953Srrs sin->sin_addr = sin_a->sin_addr; 7398163953Srrs break; 7399163953Srrs } 7400163953Srrs } 7401163953Srrs SCTP_TCB_UNLOCK(stcb); 7402163953Srrs if (!fnd) { 7403163953Srrs /* No IPv4 address */ 7404163953Srrs SCTP_FREE_SONAME(sin); 7405171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 7406228907Stuexen return (ENOENT); 7407163953Srrs } 7408163953Srrs (*addr) = (struct sockaddr *)sin; 7409163953Srrs return (0); 7410163953Srrs} 7411163953Srrs 7412163953Srrsstruct pr_usrreqs sctp_usrreqs = { 7413163953Srrs .pru_abort = sctp_abort, 7414163953Srrs .pru_accept = sctp_accept, 7415163953Srrs .pru_attach = sctp_attach, 7416163953Srrs .pru_bind = sctp_bind, 7417163953Srrs .pru_connect = sctp_connect, 7418163953Srrs .pru_control = in_control, 7419163953Srrs .pru_close = sctp_close, 7420163953Srrs .pru_detach = sctp_close, 7421163953Srrs .pru_sopoll = sopoll_generic, 7422178202Srrs .pru_flush = sctp_flush, 7423163953Srrs .pru_disconnect = sctp_disconnect, 7424163953Srrs .pru_listen = sctp_listen, 7425163953Srrs .pru_peeraddr = sctp_peeraddr, 7426163953Srrs .pru_send = sctp_sendm, 7427163953Srrs .pru_shutdown = sctp_shutdown, 7428163953Srrs .pru_sockaddr = sctp_ingetaddr, 7429163953Srrs .pru_sosend = sctp_sosend, 7430163953Srrs .pru_soreceive = sctp_soreceive 7431163953Srrs}; 7432221249Stuexen 7433221249Stuexen#endif 7434