sctp_usrreq.c revision 294174
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: stable/10/sys/netinet/sctp_usrreq.c 294174 2016-01-16 17:56:06Z tuexen $"); 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 490171167Sgnn#ifdef IPSEC 491163953Srrs uint32_t flags; 492185694Srrs 493185435Sbz#endif 494171440Srrs 495163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 496163953Srrs if (inp != 0) { 497171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 498228907Stuexen return (EINVAL); 499163953Srrs } 500184030Srrs if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 501184030Srrs error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace)); 502184030Srrs if (error) { 503228907Stuexen return (error); 504184030Srrs } 505163953Srrs } 506170205Srrs error = sctp_inpcb_alloc(so, vrf_id); 507163953Srrs if (error) { 508228907Stuexen return (error); 509163953Srrs } 510163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 511163953Srrs SCTP_INP_WLOCK(inp); 512163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6; /* I'm not v6! */ 513163953Srrs ip_inp = &inp->ip_inp.inp; 514163953Srrs ip_inp->inp_vflag |= INP_IPV4; 515197288Srrs ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl); 516171167Sgnn#ifdef IPSEC 517171133Sgnn error = ipsec_init_policy(so, &ip_inp->inp_sp); 518163953Srrs#ifdef SCTP_LOG_CLOSING 519163953Srrs sctp_log_closing(inp, NULL, 17); 520163953Srrs#endif 521163953Srrs if (error != 0) { 522202523Srrstry_again: 523163953Srrs flags = inp->sctp_flags; 524163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 525163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 526163953Srrs#ifdef SCTP_LOG_CLOSING 527163953Srrs sctp_log_closing(inp, NULL, 15); 528163953Srrs#endif 529169352Srrs SCTP_INP_WUNLOCK(inp); 530169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 531169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 532169254Srrs } else { 533202523Srrs flags = inp->sctp_flags; 534202523Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 535202523Srrs goto try_again; 536202523Srrs } else { 537202523Srrs SCTP_INP_WUNLOCK(inp); 538202523Srrs } 539163953Srrs } 540228907Stuexen return (error); 541163953Srrs } 542171167Sgnn#endif /* IPSEC */ 543163953Srrs SCTP_INP_WUNLOCK(inp); 544228907Stuexen return (0); 545163953Srrs} 546163953Srrs 547163953Srrsstatic int 548163953Srrssctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p) 549163953Srrs{ 550244730Stuexen struct sctp_inpcb *inp; 551163953Srrs 552163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 553233005Stuexen if (inp == NULL) { 554171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 555228907Stuexen return (EINVAL); 556171943Srrs } 557244730Stuexen if (addr != NULL) { 558244730Stuexen if ((addr->sa_family != AF_INET) || 559244730Stuexen (addr->sa_len != sizeof(struct sockaddr_in))) { 560244730Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 561244730Stuexen return (EINVAL); 562244730Stuexen } 563244730Stuexen } 564244730Stuexen return (sctp_inpcb_bind(so, addr, NULL, p)); 565163953Srrs} 566163953Srrs 567221249Stuexen#endif 568171990Srrsvoid 569163953Srrssctp_close(struct socket *so) 570163953Srrs{ 571163953Srrs struct sctp_inpcb *inp; 572163953Srrs uint32_t flags; 573163953Srrs 574163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 575233005Stuexen if (inp == NULL) 576163953Srrs return; 577163953Srrs 578163953Srrs /* 579163953Srrs * Inform all the lower layer assoc that we are done. 580163953Srrs */ 581163953Srrssctp_must_try_again: 582163953Srrs flags = inp->sctp_flags; 583163953Srrs#ifdef SCTP_LOG_CLOSING 584163953Srrs sctp_log_closing(inp, NULL, 17); 585163953Srrs#endif 586163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 587163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 588163953Srrs if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || 589163953Srrs (so->so_rcv.sb_cc > 0)) { 590163953Srrs#ifdef SCTP_LOG_CLOSING 591163953Srrs sctp_log_closing(inp, NULL, 13); 592163953Srrs#endif 593169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 594169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 595163953Srrs } else { 596163953Srrs#ifdef SCTP_LOG_CLOSING 597163953Srrs sctp_log_closing(inp, NULL, 14); 598163953Srrs#endif 599169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE, 600169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 601163953Srrs } 602163953Srrs /* 603163953Srrs * The socket is now detached, no matter what the state of 604163953Srrs * the SCTP association. 605163953Srrs */ 606163953Srrs SOCK_LOCK(so); 607167695Srrs SCTP_SB_CLEAR(so->so_snd); 608163953Srrs /* 609163953Srrs * same for the rcv ones, they are only here for the 610163953Srrs * accounting/select. 611163953Srrs */ 612167695Srrs SCTP_SB_CLEAR(so->so_rcv); 613167695Srrs 614167695Srrs /* Now null out the reference, we are completely detached. */ 615163953Srrs so->so_pcb = NULL; 616163953Srrs SOCK_UNLOCK(so); 617163953Srrs } else { 618163953Srrs flags = inp->sctp_flags; 619163953Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 620163953Srrs goto sctp_must_try_again; 621163953Srrs } 622163953Srrs } 623163953Srrs return; 624163953Srrs} 625163953Srrs 626163953Srrs 627163953Srrsint 628163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 629163953Srrs struct mbuf *control, struct thread *p); 630163953Srrs 631163953Srrs 632163953Srrsint 633163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 634163953Srrs struct mbuf *control, struct thread *p) 635163953Srrs{ 636163953Srrs struct sctp_inpcb *inp; 637163953Srrs int error; 638163953Srrs 639163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 640233005Stuexen if (inp == NULL) { 641163953Srrs if (control) { 642163953Srrs sctp_m_freem(control); 643163953Srrs control = NULL; 644163953Srrs } 645171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 646163953Srrs sctp_m_freem(m); 647228907Stuexen return (EINVAL); 648163953Srrs } 649163953Srrs /* Got to have an to address if we are NOT a connected socket */ 650163953Srrs if ((addr == NULL) && 651163953Srrs ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) || 652228907Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE))) { 653163953Srrs goto connected_type; 654163953Srrs } else if (addr == NULL) { 655171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); 656163953Srrs error = EDESTADDRREQ; 657163953Srrs sctp_m_freem(m); 658163953Srrs if (control) { 659163953Srrs sctp_m_freem(control); 660163953Srrs control = NULL; 661163953Srrs } 662163953Srrs return (error); 663163953Srrs } 664163953Srrs#ifdef INET6 665163953Srrs if (addr->sa_family != AF_INET) { 666163953Srrs /* must be a v4 address! */ 667171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); 668163953Srrs sctp_m_freem(m); 669163953Srrs if (control) { 670163953Srrs sctp_m_freem(control); 671163953Srrs control = NULL; 672163953Srrs } 673163953Srrs error = EDESTADDRREQ; 674223132Stuexen return (error); 675163953Srrs } 676163953Srrs#endif /* INET6 */ 677163953Srrsconnected_type: 678163953Srrs /* now what about control */ 679163953Srrs if (control) { 680163953Srrs if (inp->control) { 681169420Srrs SCTP_PRINTF("huh? control set?\n"); 682163953Srrs sctp_m_freem(inp->control); 683163953Srrs inp->control = NULL; 684163953Srrs } 685163953Srrs inp->control = control; 686163953Srrs } 687163953Srrs /* Place the data */ 688163953Srrs if (inp->pkt) { 689165647Srrs SCTP_BUF_NEXT(inp->pkt_last) = m; 690163953Srrs inp->pkt_last = m; 691163953Srrs } else { 692163953Srrs inp->pkt_last = inp->pkt = m; 693163953Srrs } 694163953Srrs if ( 695163953Srrs /* FreeBSD uses a flag passed */ 696163953Srrs ((flags & PRUS_MORETOCOME) == 0) 697163953Srrs ) { 698163953Srrs /* 699163953Srrs * note with the current version this code will only be used 700163953Srrs * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for 701163953Srrs * re-defining sosend to use the sctp_sosend. One can 702163953Srrs * optionally switch back to this code (by changing back the 703163953Srrs * definitions) but this is not advisable. This code is used 704163953Srrs * by FreeBSD when sending a file with sendfile() though. 705163953Srrs */ 706163953Srrs int ret; 707163953Srrs 708163953Srrs ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags); 709163953Srrs inp->pkt = NULL; 710163953Srrs inp->control = NULL; 711163953Srrs return (ret); 712163953Srrs } else { 713163953Srrs return (0); 714163953Srrs } 715163953Srrs} 716163953Srrs 717171990Srrsint 718163953Srrssctp_disconnect(struct socket *so) 719163953Srrs{ 720163953Srrs struct sctp_inpcb *inp; 721163953Srrs 722163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 723163953Srrs if (inp == NULL) { 724171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 725163953Srrs return (ENOTCONN); 726163953Srrs } 727163953Srrs SCTP_INP_RLOCK(inp); 728171745Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 729171745Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 730199437Stuexen if (LIST_EMPTY(&inp->sctp_asoc_list)) { 731163953Srrs /* No connection */ 732163953Srrs SCTP_INP_RUNLOCK(inp); 733163953Srrs return (0); 734163953Srrs } else { 735163953Srrs struct sctp_association *asoc; 736163953Srrs struct sctp_tcb *stcb; 737163953Srrs 738163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 739163953Srrs if (stcb == NULL) { 740163953Srrs SCTP_INP_RUNLOCK(inp); 741171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 742163953Srrs return (EINVAL); 743163953Srrs } 744163953Srrs SCTP_TCB_LOCK(stcb); 745163953Srrs asoc = &stcb->asoc; 746163953Srrs if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 747163953Srrs /* We are about to be freed, out of here */ 748163953Srrs SCTP_TCB_UNLOCK(stcb); 749163953Srrs SCTP_INP_RUNLOCK(inp); 750163953Srrs return (0); 751163953Srrs } 752163953Srrs if (((so->so_options & SO_LINGER) && 753163953Srrs (so->so_linger == 0)) || 754163953Srrs (so->so_rcv.sb_cc > 0)) { 755163953Srrs if (SCTP_GET_STATE(asoc) != 756163953Srrs SCTP_STATE_COOKIE_WAIT) { 757163953Srrs /* Left with Data unread */ 758163953Srrs struct mbuf *err; 759163953Srrs 760243882Sglebius err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA); 761163953Srrs if (err) { 762163953Srrs /* 763163953Srrs * Fill in the user 764163953Srrs * initiated abort 765163953Srrs */ 766163953Srrs struct sctp_paramhdr *ph; 767163953Srrs 768163953Srrs ph = mtod(err, struct sctp_paramhdr *); 769165647Srrs SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr); 770163953Srrs ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); 771165647Srrs ph->param_length = htons(SCTP_BUF_LEN(err)); 772163953Srrs } 773172090Srrs sctp_send_abort_tcb(stcb, err, SCTP_SO_LOCKED); 774163953Srrs SCTP_STAT_INCR_COUNTER32(sctps_aborted); 775163953Srrs } 776163953Srrs SCTP_INP_RUNLOCK(inp); 777163953Srrs if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 778163953Srrs (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 779163953Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 780163953Srrs } 781283822Stuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 782283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3); 783163953Srrs /* No unlock tcb assoc is gone */ 784163953Srrs return (0); 785163953Srrs } 786163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 787163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 788163953Srrs (asoc->stream_queue_cnt == 0)) { 789163953Srrs /* there is nothing queued to send, so done */ 790163953Srrs if (asoc->locked_on_sending) { 791163953Srrs goto abort_anyway; 792163953Srrs } 793166675Srrs if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) && 794166675Srrs (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { 795163953Srrs /* only send SHUTDOWN 1st time thru */ 796224641Stuexen struct sctp_nets *netp; 797224641Stuexen 798246588Stuexen if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 799246588Stuexen (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 800246588Stuexen SCTP_STAT_DECR_GAUGE32(sctps_currestab); 801246588Stuexen } 802246588Stuexen SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); 803246588Stuexen SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 804246588Stuexen sctp_stop_timers_for_shutdown(stcb); 805224641Stuexen if (stcb->asoc.alternate) { 806224641Stuexen netp = stcb->asoc.alternate; 807224641Stuexen } else { 808224641Stuexen netp = stcb->asoc.primary_destination; 809224641Stuexen } 810224641Stuexen sctp_send_shutdown(stcb, netp); 811163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 812224641Stuexen stcb->sctp_ep, stcb, netp); 813163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 814224641Stuexen stcb->sctp_ep, stcb, netp); 815246588Stuexen sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); 816163953Srrs } 817163953Srrs } else { 818163953Srrs /* 819163953Srrs * we still got (or just got) data to send, 820163953Srrs * so set SHUTDOWN_PENDING 821163953Srrs */ 822163953Srrs /* 823163953Srrs * XXX sockets draft says that SCTP_EOF 824163953Srrs * should be sent with no data. currently, 825163953Srrs * we will allow user data to be sent first 826163953Srrs * and move to SHUTDOWN-PENDING 827163953Srrs */ 828224641Stuexen struct sctp_nets *netp; 829224641Stuexen 830224641Stuexen if (stcb->asoc.alternate) { 831224641Stuexen netp = stcb->asoc.alternate; 832224641Stuexen } else { 833224641Stuexen netp = stcb->asoc.primary_destination; 834224641Stuexen } 835224641Stuexen 836163953Srrs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 837163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, 838224641Stuexen netp); 839163953Srrs if (asoc->locked_on_sending) { 840163953Srrs /* Locked to send out the data */ 841163953Srrs struct sctp_stream_queue_pending *sp; 842163953Srrs 843163953Srrs sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); 844163953Srrs if (sp == NULL) { 845169420Srrs SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", 846163953Srrs asoc->locked_on_sending->stream_no); 847163953Srrs } else { 848163953Srrs if ((sp->length == 0) && (sp->msg_is_complete == 0)) 849163953Srrs asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; 850163953Srrs } 851163953Srrs } 852163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 853163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 854163953Srrs (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 855163953Srrs struct mbuf *op_err; 856163953Srrs 857163953Srrs abort_anyway: 858267723Stuexen op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); 859165220Srrs stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4; 860172090Srrs sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED); 861163953Srrs SCTP_STAT_INCR_COUNTER32(sctps_aborted); 862163953Srrs if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 863163953Srrs (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 864163953Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 865163953Srrs } 866163953Srrs SCTP_INP_RUNLOCK(inp); 867283822Stuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 868283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5); 869163953Srrs return (0); 870171990Srrs } else { 871172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); 872163953Srrs } 873163953Srrs } 874188067Srrs soisdisconnecting(so); 875163953Srrs SCTP_TCB_UNLOCK(stcb); 876163953Srrs SCTP_INP_RUNLOCK(inp); 877163953Srrs return (0); 878163953Srrs } 879163953Srrs /* not reached */ 880163953Srrs } else { 881163953Srrs /* UDP model does not support this */ 882163953Srrs SCTP_INP_RUNLOCK(inp); 883171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 884228907Stuexen return (EOPNOTSUPP); 885163953Srrs } 886163953Srrs} 887163953Srrs 888163953Srrsint 889178202Srrssctp_flush(struct socket *so, int how) 890178202Srrs{ 891178202Srrs /* 892178202Srrs * We will just clear out the values and let subsequent close clear 893178202Srrs * out the data, if any. Note if the user did a shutdown(SHUT_RD) 894178202Srrs * they will not be able to read the data, the socket will block 895178202Srrs * that from happening. 896178202Srrs */ 897209289Stuexen struct sctp_inpcb *inp; 898209289Stuexen 899209289Stuexen inp = (struct sctp_inpcb *)so->so_pcb; 900209289Stuexen if (inp == NULL) { 901209289Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 902228907Stuexen return (EINVAL); 903209289Stuexen } 904209289Stuexen SCTP_INP_RLOCK(inp); 905209289Stuexen /* For the 1 to many model this does nothing */ 906209289Stuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 907209289Stuexen SCTP_INP_RUNLOCK(inp); 908209289Stuexen return (0); 909209289Stuexen } 910209289Stuexen SCTP_INP_RUNLOCK(inp); 911178202Srrs if ((how == PRU_FLUSH_RD) || (how == PRU_FLUSH_RDWR)) { 912178202Srrs /* 913178202Srrs * First make sure the sb will be happy, we don't use these 914178202Srrs * except maybe the count 915178202Srrs */ 916209289Stuexen SCTP_INP_WLOCK(inp); 917209289Stuexen SCTP_INP_READ_LOCK(inp); 918209289Stuexen inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ; 919209289Stuexen SCTP_INP_READ_UNLOCK(inp); 920209289Stuexen SCTP_INP_WUNLOCK(inp); 921178202Srrs so->so_rcv.sb_cc = 0; 922178202Srrs so->so_rcv.sb_mbcnt = 0; 923178202Srrs so->so_rcv.sb_mb = NULL; 924178202Srrs } 925178202Srrs if ((how == PRU_FLUSH_WR) || (how == PRU_FLUSH_RDWR)) { 926178202Srrs /* 927178202Srrs * First make sure the sb will be happy, we don't use these 928178202Srrs * except maybe the count 929178202Srrs */ 930178202Srrs so->so_snd.sb_cc = 0; 931178202Srrs so->so_snd.sb_mbcnt = 0; 932178202Srrs so->so_snd.sb_mb = NULL; 933178202Srrs 934178202Srrs } 935178202Srrs return (0); 936178202Srrs} 937178202Srrs 938178202Srrsint 939163953Srrssctp_shutdown(struct socket *so) 940163953Srrs{ 941163953Srrs struct sctp_inpcb *inp; 942163953Srrs 943163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 944233005Stuexen if (inp == NULL) { 945171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 946228907Stuexen return (EINVAL); 947163953Srrs } 948163953Srrs SCTP_INP_RLOCK(inp); 949163953Srrs /* For UDP model this is a invalid call */ 950243558Stuexen if (!((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 951243558Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { 952163953Srrs /* Restore the flags that the soshutdown took away. */ 953204096Stuexen SOCKBUF_LOCK(&so->so_rcv); 954163953Srrs so->so_rcv.sb_state &= ~SBS_CANTRCVMORE; 955204096Stuexen SOCKBUF_UNLOCK(&so->so_rcv); 956163953Srrs /* This proc will wakeup for read and do nothing (I hope) */ 957163953Srrs SCTP_INP_RUNLOCK(inp); 958171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 959163953Srrs return (EOPNOTSUPP); 960163953Srrs } 961163953Srrs /* 962163953Srrs * Ok if we reach here its the TCP model and it is either a SHUT_WR 963163953Srrs * or SHUT_RDWR. This means we put the shutdown flag against it. 964163953Srrs */ 965163953Srrs { 966163953Srrs struct sctp_tcb *stcb; 967163953Srrs struct sctp_association *asoc; 968163953Srrs 969188067Srrs if ((so->so_state & 970188067Srrs (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) { 971188067Srrs SCTP_INP_RUNLOCK(inp); 972188067Srrs return (ENOTCONN); 973188067Srrs } 974163953Srrs socantsendmore(so); 975163953Srrs 976163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 977163953Srrs if (stcb == NULL) { 978163953Srrs /* 979163953Srrs * Ok we hit the case that the shutdown call was 980163953Srrs * made after an abort or something. Nothing to do 981163953Srrs * now. 982163953Srrs */ 983168299Srrs SCTP_INP_RUNLOCK(inp); 984163953Srrs return (0); 985163953Srrs } 986163953Srrs SCTP_TCB_LOCK(stcb); 987163953Srrs asoc = &stcb->asoc; 988163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 989163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 990163953Srrs (asoc->stream_queue_cnt == 0)) { 991163953Srrs if (asoc->locked_on_sending) { 992163953Srrs goto abort_anyway; 993163953Srrs } 994163953Srrs /* there is nothing queued to send, so I'm done... */ 995163953Srrs if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { 996163953Srrs /* only send SHUTDOWN the first time through */ 997224641Stuexen struct sctp_nets *netp; 998224641Stuexen 999246588Stuexen if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 1000246588Stuexen (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 1001246588Stuexen SCTP_STAT_DECR_GAUGE32(sctps_currestab); 1002246588Stuexen } 1003246588Stuexen SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); 1004246588Stuexen SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 1005246588Stuexen sctp_stop_timers_for_shutdown(stcb); 1006224641Stuexen if (stcb->asoc.alternate) { 1007224641Stuexen netp = stcb->asoc.alternate; 1008224641Stuexen } else { 1009224641Stuexen netp = stcb->asoc.primary_destination; 1010224641Stuexen } 1011224641Stuexen sctp_send_shutdown(stcb, netp); 1012163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 1013224641Stuexen stcb->sctp_ep, stcb, netp); 1014163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 1015224641Stuexen stcb->sctp_ep, stcb, netp); 1016246588Stuexen sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); 1017163953Srrs } 1018163953Srrs } else { 1019163953Srrs /* 1020163953Srrs * we still got (or just got) data to send, so set 1021163953Srrs * SHUTDOWN_PENDING 1022163953Srrs */ 1023224641Stuexen struct sctp_nets *netp; 1024224641Stuexen 1025224641Stuexen if (stcb->asoc.alternate) { 1026224641Stuexen netp = stcb->asoc.alternate; 1027224641Stuexen } else { 1028224641Stuexen netp = stcb->asoc.primary_destination; 1029224641Stuexen } 1030224641Stuexen 1031163953Srrs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 1032163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, 1033224641Stuexen netp); 1034163953Srrs 1035163953Srrs if (asoc->locked_on_sending) { 1036163953Srrs /* Locked to send out the data */ 1037163953Srrs struct sctp_stream_queue_pending *sp; 1038163953Srrs 1039163953Srrs sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); 1040163953Srrs if (sp == NULL) { 1041169420Srrs SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", 1042163953Srrs asoc->locked_on_sending->stream_no); 1043163953Srrs } else { 1044163953Srrs if ((sp->length == 0) && (sp->msg_is_complete == 0)) { 1045163953Srrs asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; 1046163953Srrs } 1047163953Srrs } 1048163953Srrs } 1049163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 1050163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 1051163953Srrs (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 1052163953Srrs struct mbuf *op_err; 1053163953Srrs 1054163953Srrs abort_anyway: 1055267723Stuexen op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); 1056165220Srrs stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6; 1057163953Srrs sctp_abort_an_association(stcb->sctp_ep, stcb, 1058172090Srrs op_err, SCTP_SO_LOCKED); 1059163953Srrs goto skip_unlock; 1060171990Srrs } else { 1061172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); 1062163953Srrs } 1063163953Srrs } 1064163953Srrs SCTP_TCB_UNLOCK(stcb); 1065163953Srrs } 1066163953Srrsskip_unlock: 1067163953Srrs SCTP_INP_RUNLOCK(inp); 1068228907Stuexen return (0); 1069163953Srrs} 1070163953Srrs 1071163953Srrs/* 1072163953Srrs * copies a "user" presentable address and removes embedded scope, etc. 1073163953Srrs * returns 0 on success, 1 on error 1074163953Srrs */ 1075163953Srrsstatic uint32_t 1076163953Srrssctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa) 1077163953Srrs{ 1078178251Srrs#ifdef INET6 1079163953Srrs struct sockaddr_in6 lsa6; 1080163953Srrs 1081163953Srrs sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa, 1082163953Srrs &lsa6); 1083178251Srrs#endif 1084163953Srrs memcpy(ss, sa, sa->sa_len); 1085163953Srrs return (0); 1086163953Srrs} 1087163953Srrs 1088163953Srrs 1089163953Srrs 1090172091Srrs/* 1091172091Srrs * NOTE: assumes addr lock is held 1092172091Srrs */ 1093166675Srrsstatic size_t 1094168124Srrssctp_fill_up_addresses_vrf(struct sctp_inpcb *inp, 1095163953Srrs struct sctp_tcb *stcb, 1096166675Srrs size_t limit, 1097167598Srrs struct sockaddr_storage *sas, 1098167598Srrs uint32_t vrf_id) 1099163953Srrs{ 1100167598Srrs struct sctp_ifn *sctp_ifn; 1101167598Srrs struct sctp_ifa *sctp_ifa; 1102166675Srrs size_t actual; 1103258454Stuexen int loopback_scope; 1104258454Stuexen 1105258454Stuexen#if defined(INET) 1106258454Stuexen int ipv4_local_scope, ipv4_addr_legal; 1107258454Stuexen 1108258454Stuexen#endif 1109258454Stuexen#if defined(INET6) 1110258454Stuexen int local_scope, site_scope, ipv6_addr_legal; 1111258454Stuexen 1112258454Stuexen#endif 1113167598Srrs struct sctp_vrf *vrf; 1114163953Srrs 1115163953Srrs actual = 0; 1116163953Srrs if (limit <= 0) 1117163953Srrs return (actual); 1118163953Srrs 1119163953Srrs if (stcb) { 1120163953Srrs /* Turn on all the appropriate scope */ 1121246595Stuexen loopback_scope = stcb->asoc.scope.loopback_scope; 1122258454Stuexen#if defined(INET) 1123246595Stuexen ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope; 1124258454Stuexen ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal; 1125258454Stuexen#endif 1126258454Stuexen#if defined(INET6) 1127246595Stuexen local_scope = stcb->asoc.scope.local_scope; 1128246595Stuexen site_scope = stcb->asoc.scope.site_scope; 1129246595Stuexen ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal; 1130258454Stuexen#endif 1131163953Srrs } else { 1132246595Stuexen /* Use generic values for endpoints. */ 1133246595Stuexen loopback_scope = 1; 1134258454Stuexen#if defined(INET) 1135246595Stuexen ipv4_local_scope = 1; 1136258454Stuexen#endif 1137258454Stuexen#if defined(INET6) 1138246595Stuexen local_scope = 1; 1139246595Stuexen site_scope = 1; 1140258454Stuexen#endif 1141246595Stuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 1142258454Stuexen#if defined(INET6) 1143246595Stuexen ipv6_addr_legal = 1; 1144258454Stuexen#endif 1145258454Stuexen#if defined(INET) 1146246595Stuexen if (SCTP_IPV6_V6ONLY(inp)) { 1147246595Stuexen ipv4_addr_legal = 0; 1148246595Stuexen } else { 1149246595Stuexen ipv4_addr_legal = 1; 1150246595Stuexen } 1151258454Stuexen#endif 1152246595Stuexen } else { 1153258454Stuexen#if defined(INET6) 1154246595Stuexen ipv6_addr_legal = 0; 1155258454Stuexen#endif 1156258454Stuexen#if defined(INET) 1157163953Srrs ipv4_addr_legal = 1; 1158258454Stuexen#endif 1159163953Srrs } 1160163953Srrs } 1161167598Srrs vrf = sctp_find_vrf(vrf_id); 1162167598Srrs if (vrf == NULL) { 1163167598Srrs return (0); 1164167598Srrs } 1165163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1166167598Srrs LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 1167163953Srrs if ((loopback_scope == 0) && 1168167598Srrs SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { 1169163953Srrs /* Skip loopback if loopback_scope not set */ 1170163953Srrs continue; 1171163953Srrs } 1172167598Srrs LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 1173163953Srrs if (stcb) { 1174163953Srrs /* 1175163953Srrs * For the BOUND-ALL case, the list 1176163953Srrs * associated with a TCB is Always 1177163953Srrs * considered a reverse list.. i.e. 1178163953Srrs * it lists addresses that are NOT 1179163953Srrs * part of the association. If this 1180163953Srrs * is one of those we must skip it. 1181163953Srrs */ 1182163953Srrs if (sctp_is_addr_restricted(stcb, 1183167598Srrs sctp_ifa)) { 1184163953Srrs continue; 1185163953Srrs } 1186163953Srrs } 1187178251Srrs switch (sctp_ifa->address.sa.sa_family) { 1188221249Stuexen#ifdef INET 1189178251Srrs case AF_INET: 1190178251Srrs if (ipv4_addr_legal) { 1191178251Srrs struct sockaddr_in *sin; 1192163953Srrs 1193271746Stuexen sin = &sctp_ifa->address.sin; 1194178251Srrs if (sin->sin_addr.s_addr == 0) { 1195178251Srrs /* 1196178251Srrs * we skip 1197178251Srrs * unspecifed 1198178251Srrs * addresses 1199178251Srrs */ 1200178251Srrs continue; 1201178251Srrs } 1202267769Stuexen if (prison_check_ip4(inp->ip_inp.inp.inp_cred, 1203267769Stuexen &sin->sin_addr) != 0) { 1204267769Stuexen continue; 1205267769Stuexen } 1206178251Srrs if ((ipv4_local_scope == 0) && 1207178251Srrs (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { 1208178251Srrs continue; 1209178251Srrs } 1210178251Srrs#ifdef INET6 1211178251Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 1212178251Srrs in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas); 1213178251Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1214178251Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6)); 1215178251Srrs actual += sizeof(struct sockaddr_in6); 1216178251Srrs } else { 1217178251Srrs#endif 1218178251Srrs memcpy(sas, sin, sizeof(*sin)); 1219178251Srrs ((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport; 1220178251Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin)); 1221178251Srrs actual += sizeof(*sin); 1222178251Srrs#ifdef INET6 1223178251Srrs } 1224178251Srrs#endif 1225178251Srrs if (actual >= limit) { 1226178251Srrs return (actual); 1227178251Srrs } 1228178251Srrs } else { 1229163953Srrs continue; 1230163953Srrs } 1231178251Srrs break; 1232221249Stuexen#endif 1233178251Srrs#ifdef INET6 1234178251Srrs case AF_INET6: 1235178251Srrs if (ipv6_addr_legal) { 1236178251Srrs struct sockaddr_in6 *sin6; 1237163953Srrs 1238271746Stuexen sin6 = &sctp_ifa->address.sin6; 1239178251Srrs if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 1240178251Srrs /* 1241178251Srrs * we skip 1242178251Srrs * unspecifed 1243178251Srrs * addresses 1244178251Srrs */ 1245163953Srrs continue; 1246178251Srrs } 1247267769Stuexen if (prison_check_ip6(inp->ip_inp.inp.inp_cred, 1248267769Stuexen &sin6->sin6_addr) != 0) { 1249267769Stuexen continue; 1250267769Stuexen } 1251178251Srrs if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 1252178251Srrs if (local_scope == 0) 1253163953Srrs continue; 1254178251Srrs if (sin6->sin6_scope_id == 0) { 1255178251Srrs if (sa6_recoverscope(sin6) != 0) 1256178251Srrs /* 1257178251Srrs * 1258178251Srrs * bad 1259178251Srrs * 1260178251Srrs * li 1261178251Srrs * nk 1262178251Srrs * 1263178251Srrs * loc 1264178251Srrs * al 1265178251Srrs * 1266178251Srrs * add 1267178251Srrs * re 1268178251Srrs * ss 1269178251Srrs * */ 1270178251Srrs continue; 1271178251Srrs } 1272163953Srrs } 1273178251Srrs if ((site_scope == 0) && 1274178251Srrs (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { 1275178251Srrs continue; 1276178251Srrs } 1277178251Srrs memcpy(sas, sin6, sizeof(*sin6)); 1278178251Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1279178251Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6)); 1280178251Srrs actual += sizeof(*sin6); 1281178251Srrs if (actual >= limit) { 1282178251Srrs return (actual); 1283178251Srrs } 1284178251Srrs } else { 1285163953Srrs continue; 1286163953Srrs } 1287178251Srrs break; 1288178251Srrs#endif 1289178251Srrs default: 1290178251Srrs /* TSNH */ 1291178251Srrs break; 1292163953Srrs } 1293163953Srrs } 1294163953Srrs } 1295163953Srrs } else { 1296163953Srrs struct sctp_laddr *laddr; 1297163953Srrs 1298167598Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1299167598Srrs if (stcb) { 1300167598Srrs if (sctp_is_addr_restricted(stcb, laddr->ifa)) { 1301163953Srrs continue; 1302163953Srrs } 1303163953Srrs } 1304167598Srrs if (sctp_fill_user_address(sas, &laddr->ifa->address.sa)) 1305167598Srrs continue; 1306246595Stuexen switch (laddr->ifa->address.sa.sa_family) { 1307246595Stuexen#ifdef INET 1308246595Stuexen case AF_INET: 1309246595Stuexen ((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport; 1310246595Stuexen break; 1311246595Stuexen#endif 1312246595Stuexen#ifdef INET6 1313246595Stuexen case AF_INET6: 1314246595Stuexen ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1315246595Stuexen break; 1316246595Stuexen#endif 1317246595Stuexen default: 1318246595Stuexen /* TSNH */ 1319246595Stuexen break; 1320246595Stuexen } 1321167598Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + 1322167598Srrs laddr->ifa->address.sa.sa_len); 1323167598Srrs actual += laddr->ifa->address.sa.sa_len; 1324167598Srrs if (actual >= limit) { 1325167598Srrs return (actual); 1326163953Srrs } 1327163953Srrs } 1328163953Srrs } 1329163953Srrs return (actual); 1330163953Srrs} 1331163953Srrs 1332168124Srrsstatic size_t 1333168124Srrssctp_fill_up_addresses(struct sctp_inpcb *inp, 1334168124Srrs struct sctp_tcb *stcb, 1335168124Srrs size_t limit, 1336168124Srrs struct sockaddr_storage *sas) 1337168124Srrs{ 1338168124Srrs size_t size = 0; 1339168124Srrs 1340172218Srrs SCTP_IPI_ADDR_RLOCK(); 1341168124Srrs /* fill up addresses for the endpoint's default vrf */ 1342168124Srrs size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas, 1343168124Srrs inp->def_vrf_id); 1344172218Srrs SCTP_IPI_ADDR_RUNLOCK(); 1345168124Srrs return (size); 1346168124Srrs} 1347168124Srrs 1348172091Srrs/* 1349172091Srrs * NOTE: assumes addr lock is held 1350172091Srrs */ 1351163953Srrsstatic int 1352168124Srrssctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) 1353163953Srrs{ 1354163953Srrs int cnt = 0; 1355167598Srrs struct sctp_vrf *vrf = NULL; 1356163953Srrs 1357163953Srrs /* 1358163953Srrs * In both sub-set bound an bound_all cases we return the MAXIMUM 1359163953Srrs * number of addresses that you COULD get. In reality the sub-set 1360163953Srrs * bound may have an exclusion list for a given TCB OR in the 1361163953Srrs * bound-all case a TCB may NOT include the loopback or other 1362163953Srrs * addresses as well. 1363163953Srrs */ 1364167598Srrs vrf = sctp_find_vrf(vrf_id); 1365167598Srrs if (vrf == NULL) { 1366167598Srrs return (0); 1367167598Srrs } 1368163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1369167598Srrs struct sctp_ifn *sctp_ifn; 1370167598Srrs struct sctp_ifa *sctp_ifa; 1371163953Srrs 1372167598Srrs LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 1373167598Srrs LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 1374163953Srrs /* Count them if they are the right type */ 1375221249Stuexen switch (sctp_ifa->address.sa.sa_family) { 1376221249Stuexen#ifdef INET 1377221249Stuexen case AF_INET: 1378283699Stuexen#ifdef INET6 1379178251Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) 1380163953Srrs cnt += sizeof(struct sockaddr_in6); 1381163953Srrs else 1382163953Srrs cnt += sizeof(struct sockaddr_in); 1383283699Stuexen#else 1384283699Stuexen cnt += sizeof(struct sockaddr_in); 1385283699Stuexen#endif 1386221249Stuexen break; 1387221249Stuexen#endif 1388221249Stuexen#ifdef INET6 1389221249Stuexen case AF_INET6: 1390163953Srrs cnt += sizeof(struct sockaddr_in6); 1391221249Stuexen break; 1392221249Stuexen#endif 1393221249Stuexen default: 1394221249Stuexen break; 1395221249Stuexen } 1396163953Srrs } 1397163953Srrs } 1398163953Srrs } else { 1399163953Srrs struct sctp_laddr *laddr; 1400163953Srrs 1401163953Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1402221249Stuexen switch (laddr->ifa->address.sa.sa_family) { 1403221249Stuexen#ifdef INET 1404221249Stuexen case AF_INET: 1405283699Stuexen#ifdef INET6 1406178251Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) 1407163953Srrs cnt += sizeof(struct sockaddr_in6); 1408163953Srrs else 1409163953Srrs cnt += sizeof(struct sockaddr_in); 1410283699Stuexen#else 1411283699Stuexen cnt += sizeof(struct sockaddr_in); 1412283699Stuexen#endif 1413221249Stuexen break; 1414221249Stuexen#endif 1415221249Stuexen#ifdef INET6 1416221249Stuexen case AF_INET6: 1417163953Srrs cnt += sizeof(struct sockaddr_in6); 1418221249Stuexen break; 1419221249Stuexen#endif 1420221249Stuexen default: 1421221249Stuexen break; 1422221249Stuexen } 1423163953Srrs } 1424163953Srrs } 1425163953Srrs return (cnt); 1426163953Srrs} 1427163953Srrs 1428168124Srrsstatic int 1429168124Srrssctp_count_max_addresses(struct sctp_inpcb *inp) 1430168124Srrs{ 1431168124Srrs int cnt = 0; 1432166675Srrs 1433172218Srrs SCTP_IPI_ADDR_RLOCK(); 1434168124Srrs /* count addresses for the endpoint's default VRF */ 1435168124Srrs cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id); 1436172218Srrs SCTP_IPI_ADDR_RUNLOCK(); 1437168124Srrs return (cnt); 1438168124Srrs} 1439168124Srrs 1440163953Srrsstatic int 1441166675Srrssctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, 1442166675Srrs size_t optsize, void *p, int delay) 1443163953Srrs{ 1444163953Srrs int error = 0; 1445163953Srrs int creat_lock_on = 0; 1446163953Srrs struct sctp_tcb *stcb = NULL; 1447163953Srrs struct sockaddr *sa; 1448169352Srrs int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr; 1449167598Srrs uint32_t vrf_id; 1450170056Srrs int bad_addresses = 0; 1451167598Srrs sctp_assoc_t *a_id; 1452163953Srrs 1453169420Srrs SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n"); 1454163953Srrs 1455163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 1456163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 1457163953Srrs /* We are already connected AND the TCP model */ 1458171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 1459163953Srrs return (EADDRINUSE); 1460163953Srrs } 1461181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && 1462181054Srrs (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) { 1463171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1464163953Srrs return (EINVAL); 1465163953Srrs } 1466163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 1467163953Srrs SCTP_INP_RLOCK(inp); 1468163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 1469163953Srrs SCTP_INP_RUNLOCK(inp); 1470163953Srrs } 1471163953Srrs if (stcb) { 1472171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 1473163953Srrs return (EALREADY); 1474163953Srrs } 1475163953Srrs SCTP_INP_INCR_REF(inp); 1476163953Srrs SCTP_ASOC_CREATE_LOCK(inp); 1477163953Srrs creat_lock_on = 1; 1478163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 1479163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 1480171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); 1481163953Srrs error = EFAULT; 1482163953Srrs goto out_now; 1483163953Srrs } 1484166675Srrs totaddrp = (int *)optval; 1485163953Srrs totaddr = *totaddrp; 1486163953Srrs sa = (struct sockaddr *)(totaddrp + 1); 1487170056Srrs stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses); 1488170056Srrs if ((stcb != NULL) || bad_addresses) { 1489169352Srrs /* Already have or am bring up an association */ 1490169352Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1491169352Srrs creat_lock_on = 0; 1492170931Srrs if (stcb) 1493170931Srrs SCTP_TCB_UNLOCK(stcb); 1494171943Srrs if (bad_addresses == 0) { 1495171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 1496170056Srrs error = EALREADY; 1497171943Srrs } 1498169352Srrs goto out_now; 1499163953Srrs } 1500163953Srrs#ifdef INET6 1501163953Srrs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 1502163953Srrs (num_v6 > 0)) { 1503163953Srrs error = EINVAL; 1504163953Srrs goto out_now; 1505163953Srrs } 1506163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 1507163953Srrs (num_v4 > 0)) { 1508163953Srrs struct in6pcb *inp6; 1509163953Srrs 1510163953Srrs inp6 = (struct in6pcb *)inp; 1511166023Srrs if (SCTP_IPV6_V6ONLY(inp6)) { 1512163953Srrs /* 1513163953Srrs * if IPV6_V6ONLY flag, ignore connections destined 1514163953Srrs * to a v4 addr or v4-mapped addr 1515163953Srrs */ 1516171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1517163953Srrs error = EINVAL; 1518163953Srrs goto out_now; 1519163953Srrs } 1520163953Srrs } 1521163953Srrs#endif /* INET6 */ 1522163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 1523163953Srrs SCTP_PCB_FLAGS_UNBOUND) { 1524163953Srrs /* Bind a ephemeral port */ 1525171572Srrs error = sctp_inpcb_bind(so, NULL, NULL, p); 1526163953Srrs if (error) { 1527163953Srrs goto out_now; 1528163953Srrs } 1529163953Srrs } 1530167695Srrs /* FIX ME: do we want to pass in a vrf on the connect call? */ 1531167695Srrs vrf_id = inp->def_vrf_id; 1532167695Srrs 1533181054Srrs 1534163953Srrs /* We are GOOD to go */ 1535206137Stuexen stcb = sctp_aloc_assoc(inp, sa, &error, 0, vrf_id, 1536171531Srrs (struct thread *)p 1537171531Srrs ); 1538163953Srrs if (stcb == NULL) { 1539163953Srrs /* Gak! no memory */ 1540163953Srrs goto out_now; 1541163953Srrs } 1542225559Stuexen if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 1543225559Stuexen stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 1544225559Stuexen /* Set the connected flag so we can queue data */ 1545225559Stuexen soisconnecting(so); 1546225559Stuexen } 1547171943Srrs SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); 1548163953Srrs /* move to second address */ 1549221249Stuexen switch (sa->sa_family) { 1550221249Stuexen#ifdef INET 1551221249Stuexen case AF_INET: 1552163953Srrs sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in)); 1553221249Stuexen break; 1554221249Stuexen#endif 1555221249Stuexen#ifdef INET6 1556221249Stuexen case AF_INET6: 1557163953Srrs sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6)); 1558221249Stuexen break; 1559221249Stuexen#endif 1560221249Stuexen default: 1561221249Stuexen break; 1562221249Stuexen } 1563163953Srrs 1564170056Srrs error = 0; 1565223132Stuexen sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error); 1566167598Srrs /* Fill in the return id */ 1567170056Srrs if (error) { 1568283822Stuexen (void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, 1569283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); 1570170056Srrs goto out_now; 1571170056Srrs } 1572167598Srrs a_id = (sctp_assoc_t *) optval; 1573167598Srrs *a_id = sctp_get_associd(stcb); 1574163953Srrs 1575163953Srrs /* initialize authentication parameters for the assoc */ 1576163953Srrs sctp_initialize_auth_params(inp, stcb); 1577163953Srrs 1578163953Srrs if (delay) { 1579163953Srrs /* doing delayed connection */ 1580163953Srrs stcb->asoc.delayed_connection = 1; 1581163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination); 1582163953Srrs } else { 1583169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 1584172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 1585163953Srrs } 1586163953Srrs SCTP_TCB_UNLOCK(stcb); 1587163953Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 1588163953Srrs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 1589163953Srrs /* Set the connected flag so we can queue data */ 1590163953Srrs soisconnecting(so); 1591163953Srrs } 1592163953Srrsout_now: 1593169655Srrs if (creat_lock_on) { 1594163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1595169655Srrs } 1596163953Srrs SCTP_INP_DECR_REF(inp); 1597228907Stuexen return (error); 1598163953Srrs} 1599163953Srrs 1600169420Srrs#define SCTP_FIND_STCB(inp, stcb, assoc_id) { \ 1601169655Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||\ 1602169655Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { \ 1603166675Srrs SCTP_INP_RLOCK(inp); \ 1604166675Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); \ 1605169655Srrs if (stcb) { \ 1606166675Srrs SCTP_TCB_LOCK(stcb); \ 1607169655Srrs } \ 1608166675Srrs SCTP_INP_RUNLOCK(inp); \ 1609223132Stuexen } else if (assoc_id > SCTP_ALL_ASSOC) { \ 1610166675Srrs stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \ 1611166675Srrs if (stcb == NULL) { \ 1612171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \ 1613166675Srrs error = ENOENT; \ 1614166675Srrs break; \ 1615166675Srrs } \ 1616166675Srrs } else { \ 1617166675Srrs stcb = NULL; \ 1618169420Srrs } \ 1619169420Srrs } 1620163953Srrs 1621169420Srrs 1622234464Stuexen#define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\ 1623166675Srrs if (size < sizeof(type)) { \ 1624171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); \ 1625166675Srrs error = EINVAL; \ 1626166675Srrs break; \ 1627166675Srrs } else { \ 1628166675Srrs destp = (type *)srcp; \ 1629169420Srrs } \ 1630169420Srrs } 1631163953Srrs 1632163953Srrsstatic int 1633166675Srrssctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, 1634166675Srrs void *p) 1635163953Srrs{ 1636171943Srrs struct sctp_inpcb *inp = NULL; 1637166675Srrs int error, val = 0; 1638163953Srrs struct sctp_tcb *stcb = NULL; 1639163953Srrs 1640166675Srrs if (optval == NULL) { 1641171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1642166675Srrs return (EINVAL); 1643166675Srrs } 1644163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 1645233005Stuexen if (inp == NULL) { 1646171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1647163953Srrs return EINVAL; 1648171943Srrs } 1649163953Srrs error = 0; 1650163953Srrs 1651166675Srrs switch (optname) { 1652163953Srrs case SCTP_NODELAY: 1653163953Srrs case SCTP_AUTOCLOSE: 1654163953Srrs case SCTP_EXPLICIT_EOR: 1655163953Srrs case SCTP_AUTO_ASCONF: 1656163953Srrs case SCTP_DISABLE_FRAGMENTS: 1657163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 1658163953Srrs case SCTP_USE_EXT_RCVINFO: 1659163953Srrs SCTP_INP_RLOCK(inp); 1660166675Srrs switch (optname) { 1661163953Srrs case SCTP_DISABLE_FRAGMENTS: 1662166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT); 1663163953Srrs break; 1664163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 1665166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4); 1666163953Srrs break; 1667163953Srrs case SCTP_AUTO_ASCONF: 1668171943Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1669171943Srrs /* only valid for bound all sockets */ 1670171943Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); 1671171943Srrs } else { 1672171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1673171943Srrs error = EINVAL; 1674171943Srrs goto flags_out; 1675171943Srrs } 1676163953Srrs break; 1677163953Srrs case SCTP_EXPLICIT_EOR: 1678166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); 1679163953Srrs break; 1680163953Srrs case SCTP_NODELAY: 1681166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY); 1682163953Srrs break; 1683163953Srrs case SCTP_USE_EXT_RCVINFO: 1684166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO); 1685163953Srrs break; 1686163953Srrs case SCTP_AUTOCLOSE: 1687163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) 1688166675Srrs val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time); 1689163953Srrs else 1690166675Srrs val = 0; 1691163953Srrs break; 1692163953Srrs 1693163953Srrs default: 1694171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 1695163953Srrs error = ENOPROTOOPT; 1696163953Srrs } /* end switch (sopt->sopt_name) */ 1697166675Srrs if (*optsize < sizeof(val)) { 1698171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1699163953Srrs error = EINVAL; 1700163953Srrs } 1701171943Srrsflags_out: 1702163953Srrs SCTP_INP_RUNLOCK(inp); 1703163953Srrs if (error == 0) { 1704163953Srrs /* return the option value */ 1705166675Srrs *(int *)optval = val; 1706166675Srrs *optsize = sizeof(val); 1707163953Srrs } 1708163953Srrs break; 1709170091Srrs case SCTP_GET_PACKET_LOG: 1710170091Srrs { 1711170091Srrs#ifdef SCTP_PACKET_LOGGING 1712170091Srrs uint8_t *target; 1713170091Srrs int ret; 1714167598Srrs 1715170091Srrs SCTP_CHECK_AND_CAST(target, optval, uint8_t, *optsize); 1716170091Srrs ret = sctp_copy_out_packet_log(target, (int)*optsize); 1717170091Srrs *optsize = ret; 1718170091Srrs#else 1719171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 1720170091Srrs error = EOPNOTSUPP; 1721170091Srrs#endif 1722170091Srrs break; 1723170091Srrs } 1724181054Srrs case SCTP_REUSE_PORT: 1725181054Srrs { 1726181054Srrs uint32_t *value; 1727181054Srrs 1728181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) { 1729181054Srrs /* Can't do this for a 1-m socket */ 1730181054Srrs error = EINVAL; 1731181054Srrs break; 1732181054Srrs } 1733181054Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1734181054Srrs *value = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE); 1735181054Srrs *optsize = sizeof(uint32_t); 1736223132Stuexen break; 1737181054Srrs } 1738163953Srrs case SCTP_PARTIAL_DELIVERY_POINT: 1739163953Srrs { 1740166675Srrs uint32_t *value; 1741166675Srrs 1742166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1743166675Srrs *value = inp->partial_delivery_point; 1744166675Srrs *optsize = sizeof(uint32_t); 1745223132Stuexen break; 1746163953Srrs } 1747163953Srrs case SCTP_FRAGMENT_INTERLEAVE: 1748163953Srrs { 1749166675Srrs uint32_t *value; 1750166675Srrs 1751166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1752168943Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) { 1753168943Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) { 1754168943Srrs *value = SCTP_FRAG_LEVEL_2; 1755168943Srrs } else { 1756168943Srrs *value = SCTP_FRAG_LEVEL_1; 1757168943Srrs } 1758168943Srrs } else { 1759168943Srrs *value = SCTP_FRAG_LEVEL_0; 1760168943Srrs } 1761166675Srrs *optsize = sizeof(uint32_t); 1762223132Stuexen break; 1763163953Srrs } 1764163953Srrs case SCTP_CMT_ON_OFF: 1765163953Srrs { 1766166675Srrs struct sctp_assoc_value *av; 1767166675Srrs 1768166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1769211944Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1770211944Stuexen if (stcb) { 1771211944Stuexen av->assoc_value = stcb->asoc.sctp_cmt_on_off; 1772211944Stuexen SCTP_TCB_UNLOCK(stcb); 1773166675Srrs } else { 1774224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1775224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1776224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1777223132Stuexen SCTP_INP_RLOCK(inp); 1778223132Stuexen av->assoc_value = inp->sctp_cmt_on_off; 1779223132Stuexen SCTP_INP_RUNLOCK(inp); 1780223132Stuexen } else { 1781223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1782223132Stuexen error = EINVAL; 1783223132Stuexen } 1784163953Srrs } 1785223132Stuexen if (error == 0) { 1786223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1787223132Stuexen } 1788223132Stuexen break; 1789163953Srrs } 1790171440Srrs case SCTP_PLUGGABLE_CC: 1791171440Srrs { 1792171440Srrs struct sctp_assoc_value *av; 1793171440Srrs 1794171440Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1795171440Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1796171440Srrs if (stcb) { 1797171440Srrs av->assoc_value = stcb->asoc.congestion_control_module; 1798171440Srrs SCTP_TCB_UNLOCK(stcb); 1799171440Srrs } else { 1800224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1801224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1802224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1803223132Stuexen SCTP_INP_RLOCK(inp); 1804223132Stuexen av->assoc_value = inp->sctp_ep.sctp_default_cc_module; 1805223132Stuexen SCTP_INP_RUNLOCK(inp); 1806223132Stuexen } else { 1807223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1808223132Stuexen error = EINVAL; 1809223132Stuexen } 1810171440Srrs } 1811223132Stuexen if (error == 0) { 1812223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1813223132Stuexen } 1814223132Stuexen break; 1815171440Srrs } 1816219057Srrs case SCTP_CC_OPTION: 1817219057Srrs { 1818219057Srrs struct sctp_cc_option *cc_opt; 1819219057Srrs 1820219057Srrs SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, *optsize); 1821219057Srrs SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id); 1822219057Srrs if (stcb == NULL) { 1823219057Srrs error = EINVAL; 1824219057Srrs } else { 1825219057Srrs if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) { 1826219057Srrs error = ENOTSUP; 1827219057Srrs } else { 1828223132Stuexen error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 0, cc_opt); 1829223132Stuexen *optsize = sizeof(struct sctp_cc_option); 1830219057Srrs } 1831219057Srrs SCTP_TCB_UNLOCK(stcb); 1832219057Srrs } 1833223132Stuexen break; 1834219057Srrs } 1835217760Stuexen case SCTP_PLUGGABLE_SS: 1836217760Stuexen { 1837217760Stuexen struct sctp_assoc_value *av; 1838217760Stuexen 1839217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1840217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1841217760Stuexen if (stcb) { 1842217760Stuexen av->assoc_value = stcb->asoc.stream_scheduling_module; 1843217760Stuexen SCTP_TCB_UNLOCK(stcb); 1844217760Stuexen } else { 1845224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1846224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1847224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1848223132Stuexen SCTP_INP_RLOCK(inp); 1849223132Stuexen av->assoc_value = inp->sctp_ep.sctp_default_ss_module; 1850223132Stuexen SCTP_INP_RUNLOCK(inp); 1851223132Stuexen } else { 1852223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1853223132Stuexen error = EINVAL; 1854223132Stuexen } 1855217760Stuexen } 1856223132Stuexen if (error == 0) { 1857223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1858223132Stuexen } 1859223132Stuexen break; 1860217760Stuexen } 1861217760Stuexen case SCTP_SS_VALUE: 1862217760Stuexen { 1863217760Stuexen struct sctp_stream_value *av; 1864217760Stuexen 1865217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize); 1866217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1867217760Stuexen if (stcb) { 1868277807Sdelphij if ((av->stream_id >= stcb->asoc.streamoutcnt) || 1869277807Sdelphij (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], 1870277807Sdelphij &av->stream_value) < 0)) { 1871217760Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1872217760Stuexen error = EINVAL; 1873217760Stuexen } else { 1874223132Stuexen *optsize = sizeof(struct sctp_stream_value); 1875217760Stuexen } 1876217760Stuexen SCTP_TCB_UNLOCK(stcb); 1877217760Stuexen } else { 1878217760Stuexen /* 1879217760Stuexen * Can't get stream value without 1880217760Stuexen * association 1881217760Stuexen */ 1882217760Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1883217760Stuexen error = EINVAL; 1884217760Stuexen } 1885223132Stuexen break; 1886217760Stuexen } 1887163953Srrs case SCTP_GET_ADDR_LEN: 1888163953Srrs { 1889163953Srrs struct sctp_assoc_value *av; 1890163953Srrs 1891166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1892163953Srrs error = EINVAL; 1893167598Srrs#ifdef INET 1894163953Srrs if (av->assoc_value == AF_INET) { 1895163953Srrs av->assoc_value = sizeof(struct sockaddr_in); 1896163953Srrs error = 0; 1897163953Srrs } 1898163953Srrs#endif 1899167598Srrs#ifdef INET6 1900163953Srrs if (av->assoc_value == AF_INET6) { 1901163953Srrs av->assoc_value = sizeof(struct sockaddr_in6); 1902163953Srrs error = 0; 1903163953Srrs } 1904163953Srrs#endif 1905172091Srrs if (error) { 1906171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1907223132Stuexen } else { 1908223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1909172091Srrs } 1910223132Stuexen break; 1911163953Srrs } 1912169655Srrs case SCTP_GET_ASSOC_NUMBER: 1913163953Srrs { 1914169655Srrs uint32_t *value, cnt; 1915163953Srrs 1916169655Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1917163953Srrs cnt = 0; 1918163953Srrs SCTP_INP_RLOCK(inp); 1919169655Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 1920169655Srrs cnt++; 1921163953Srrs } 1922169655Srrs SCTP_INP_RUNLOCK(inp); 1923169655Srrs *value = cnt; 1924169655Srrs *optsize = sizeof(uint32_t); 1925223132Stuexen break; 1926169655Srrs } 1927169655Srrs case SCTP_GET_ASSOC_ID_LIST: 1928169655Srrs { 1929169655Srrs struct sctp_assoc_ids *ids; 1930169655Srrs unsigned int at, limit; 1931169655Srrs 1932169655Srrs SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize); 1933163953Srrs at = 0; 1934185694Srrs limit = (*optsize - sizeof(uint32_t)) / sizeof(sctp_assoc_t); 1935169655Srrs SCTP_INP_RLOCK(inp); 1936169655Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 1937169655Srrs if (at < limit) { 1938169655Srrs ids->gaids_assoc_id[at++] = sctp_get_associd(stcb); 1939169655Srrs } else { 1940169655Srrs error = EINVAL; 1941171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1942163953Srrs break; 1943163953Srrs } 1944163953Srrs } 1945163953Srrs SCTP_INP_RUNLOCK(inp); 1946223132Stuexen if (error == 0) { 1947223132Stuexen ids->gaids_number_of_ids = at; 1948223132Stuexen *optsize = ((at * sizeof(sctp_assoc_t)) + sizeof(uint32_t)); 1949223132Stuexen } 1950223132Stuexen break; 1951163953Srrs } 1952163953Srrs case SCTP_CONTEXT: 1953163953Srrs { 1954163953Srrs struct sctp_assoc_value *av; 1955163953Srrs 1956166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1957166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1958166675Srrs 1959166675Srrs if (stcb) { 1960166675Srrs av->assoc_value = stcb->asoc.context; 1961166675Srrs SCTP_TCB_UNLOCK(stcb); 1962163953Srrs } else { 1963224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1964224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1965224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1966223132Stuexen SCTP_INP_RLOCK(inp); 1967223132Stuexen av->assoc_value = inp->sctp_context; 1968223132Stuexen SCTP_INP_RUNLOCK(inp); 1969223132Stuexen } else { 1970223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1971223132Stuexen error = EINVAL; 1972223132Stuexen } 1973163953Srrs } 1974223132Stuexen if (error == 0) { 1975223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1976223132Stuexen } 1977223132Stuexen break; 1978163953Srrs } 1979167598Srrs case SCTP_VRF_ID: 1980167598Srrs { 1981170056Srrs uint32_t *default_vrfid; 1982167598Srrs 1983170056Srrs SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize); 1984170056Srrs *default_vrfid = inp->def_vrf_id; 1985223132Stuexen *optsize = sizeof(uint32_t); 1986167598Srrs break; 1987167598Srrs } 1988167598Srrs case SCTP_GET_ASOC_VRF: 1989167598Srrs { 1990167598Srrs struct sctp_assoc_value *id; 1991167598Srrs 1992167598Srrs SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize); 1993167598Srrs SCTP_FIND_STCB(inp, stcb, id->assoc_id); 1994167598Srrs if (stcb == NULL) { 1995167598Srrs error = EINVAL; 1996171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1997223132Stuexen } else { 1998223132Stuexen id->assoc_value = stcb->asoc.vrf_id; 1999223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 2000167598Srrs } 2001167598Srrs break; 2002167598Srrs } 2003167598Srrs case SCTP_GET_VRF_IDS: 2004167598Srrs { 2005171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 2006167598Srrs error = EOPNOTSUPP; 2007167598Srrs break; 2008167598Srrs } 2009163953Srrs case SCTP_GET_NONCE_VALUES: 2010163953Srrs { 2011163953Srrs struct sctp_get_nonce_values *gnv; 2012163953Srrs 2013166675Srrs SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize); 2014166675Srrs SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id); 2015166675Srrs 2016166675Srrs if (stcb) { 2017163953Srrs gnv->gn_peers_tag = stcb->asoc.peer_vtag; 2018163953Srrs gnv->gn_local_tag = stcb->asoc.my_vtag; 2019163953Srrs SCTP_TCB_UNLOCK(stcb); 2020223132Stuexen *optsize = sizeof(struct sctp_get_nonce_values); 2021166675Srrs } else { 2022171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 2023166675Srrs error = ENOTCONN; 2024163953Srrs } 2025223132Stuexen break; 2026163953Srrs } 2027170056Srrs case SCTP_DELAYED_SACK: 2028163953Srrs { 2029170056Srrs struct sctp_sack_info *sack; 2030163953Srrs 2031170056Srrs SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, *optsize); 2032170056Srrs SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); 2033166675Srrs if (stcb) { 2034170056Srrs sack->sack_delay = stcb->asoc.delayed_ack; 2035170056Srrs sack->sack_freq = stcb->asoc.sack_freq; 2036166675Srrs SCTP_TCB_UNLOCK(stcb); 2037166675Srrs } else { 2038224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2039224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2040224918Stuexen (sack->sack_assoc_id == SCTP_FUTURE_ASSOC)) { 2041223132Stuexen SCTP_INP_RLOCK(inp); 2042223132Stuexen sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); 2043223132Stuexen sack->sack_freq = inp->sctp_ep.sctp_sack_freq; 2044223132Stuexen SCTP_INP_RUNLOCK(inp); 2045223132Stuexen } else { 2046223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2047223132Stuexen error = EINVAL; 2048223132Stuexen } 2049163953Srrs } 2050223132Stuexen if (error == 0) { 2051223132Stuexen *optsize = sizeof(struct sctp_sack_info); 2052223132Stuexen } 2053223132Stuexen break; 2054163953Srrs } 2055163953Srrs case SCTP_GET_SNDBUF_USE: 2056166675Srrs { 2057163953Srrs struct sctp_sockstat *ss; 2058163953Srrs 2059166675Srrs SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize); 2060166675Srrs SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id); 2061166675Srrs 2062166675Srrs if (stcb) { 2063166675Srrs ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size; 2064166675Srrs ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue + 2065166675Srrs stcb->asoc.size_on_all_streams); 2066166675Srrs SCTP_TCB_UNLOCK(stcb); 2067223132Stuexen *optsize = sizeof(struct sctp_sockstat); 2068166675Srrs } else { 2069171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 2070163953Srrs error = ENOTCONN; 2071163953Srrs } 2072223132Stuexen break; 2073163953Srrs } 2074170056Srrs case SCTP_MAX_BURST: 2075163953Srrs { 2076217895Stuexen struct sctp_assoc_value *av; 2077163953Srrs 2078217895Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 2079217895Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2080166675Srrs 2081217895Stuexen if (stcb) { 2082217895Stuexen av->assoc_value = stcb->asoc.max_burst; 2083217895Stuexen SCTP_TCB_UNLOCK(stcb); 2084217894Stuexen } else { 2085224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2086224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2087224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 2088223132Stuexen SCTP_INP_RLOCK(inp); 2089223132Stuexen av->assoc_value = inp->sctp_ep.max_burst; 2090223132Stuexen SCTP_INP_RUNLOCK(inp); 2091223132Stuexen } else { 2092223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2093223132Stuexen error = EINVAL; 2094223132Stuexen } 2095217894Stuexen } 2096223132Stuexen if (error == 0) { 2097223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 2098223132Stuexen } 2099223132Stuexen break; 2100163953Srrs } 2101163953Srrs case SCTP_MAXSEG: 2102163953Srrs { 2103167598Srrs struct sctp_assoc_value *av; 2104163953Srrs int ovh; 2105163953Srrs 2106167598Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 2107170056Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2108163953Srrs 2109167598Srrs if (stcb) { 2110167598Srrs av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc); 2111167598Srrs SCTP_TCB_UNLOCK(stcb); 2112163953Srrs } else { 2113224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2114224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2115224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 2116223132Stuexen SCTP_INP_RLOCK(inp); 2117223132Stuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2118223132Stuexen ovh = SCTP_MED_OVERHEAD; 2119223132Stuexen } else { 2120223132Stuexen ovh = SCTP_MED_V4_OVERHEAD; 2121223132Stuexen } 2122223132Stuexen if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT) 2123223132Stuexen av->assoc_value = 0; 2124223132Stuexen else 2125223132Stuexen av->assoc_value = inp->sctp_frag_point - ovh; 2126223132Stuexen SCTP_INP_RUNLOCK(inp); 2127167598Srrs } else { 2128223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2129223132Stuexen error = EINVAL; 2130167598Srrs } 2131163953Srrs } 2132223132Stuexen if (error == 0) { 2133223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 2134223132Stuexen } 2135223132Stuexen break; 2136163953Srrs } 2137163953Srrs case SCTP_GET_STAT_LOG: 2138167598Srrs error = sctp_fill_stat_log(optval, optsize); 2139163953Srrs break; 2140163953Srrs case SCTP_EVENTS: 2141163953Srrs { 2142163953Srrs struct sctp_event_subscribe *events; 2143163953Srrs 2144166675Srrs SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize); 2145223132Stuexen memset(events, 0, sizeof(struct sctp_event_subscribe)); 2146163953Srrs SCTP_INP_RLOCK(inp); 2147163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) 2148163953Srrs events->sctp_data_io_event = 1; 2149163953Srrs 2150163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT)) 2151163953Srrs events->sctp_association_event = 1; 2152163953Srrs 2153163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT)) 2154163953Srrs events->sctp_address_event = 1; 2155163953Srrs 2156163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) 2157163953Srrs events->sctp_send_failure_event = 1; 2158163953Srrs 2159163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR)) 2160163953Srrs events->sctp_peer_error_event = 1; 2161163953Srrs 2162163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) 2163163953Srrs events->sctp_shutdown_event = 1; 2164163953Srrs 2165163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT)) 2166163953Srrs events->sctp_partial_delivery_event = 1; 2167163953Srrs 2168163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) 2169163953Srrs events->sctp_adaptation_layer_event = 1; 2170163953Srrs 2171163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT)) 2172163953Srrs events->sctp_authentication_event = 1; 2173163953Srrs 2174185694Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT)) 2175185694Srrs events->sctp_sender_dry_event = 1; 2176185694Srrs 2177163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) 2178202520Srrs events->sctp_stream_reset_event = 1; 2179163953Srrs SCTP_INP_RUNLOCK(inp); 2180166675Srrs *optsize = sizeof(struct sctp_event_subscribe); 2181223132Stuexen break; 2182163953Srrs } 2183163953Srrs case SCTP_ADAPTATION_LAYER: 2184166675Srrs { 2185166675Srrs uint32_t *value; 2186166675Srrs 2187166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2188166675Srrs 2189166675Srrs SCTP_INP_RLOCK(inp); 2190166675Srrs *value = inp->sctp_ep.adaptation_layer_indicator; 2191166675Srrs SCTP_INP_RUNLOCK(inp); 2192166675Srrs *optsize = sizeof(uint32_t); 2193223132Stuexen break; 2194163953Srrs } 2195163953Srrs case SCTP_SET_INITIAL_DBG_SEQ: 2196166675Srrs { 2197166675Srrs uint32_t *value; 2198166675Srrs 2199166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2200166675Srrs SCTP_INP_RLOCK(inp); 2201166675Srrs *value = inp->sctp_ep.initial_sequence_debug; 2202166675Srrs SCTP_INP_RUNLOCK(inp); 2203166675Srrs *optsize = sizeof(uint32_t); 2204223132Stuexen break; 2205163953Srrs } 2206163953Srrs case SCTP_GET_LOCAL_ADDR_SIZE: 2207166675Srrs { 2208166675Srrs uint32_t *value; 2209166675Srrs 2210166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2211166675Srrs SCTP_INP_RLOCK(inp); 2212168124Srrs *value = sctp_count_max_addresses(inp); 2213166675Srrs SCTP_INP_RUNLOCK(inp); 2214166675Srrs *optsize = sizeof(uint32_t); 2215223132Stuexen break; 2216163953Srrs } 2217163953Srrs case SCTP_GET_REMOTE_ADDR_SIZE: 2218163953Srrs { 2219166675Srrs uint32_t *value; 2220166675Srrs size_t size; 2221163953Srrs struct sctp_nets *net; 2222163953Srrs 2223166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2224166675Srrs /* FIXME MT: change to sctp_assoc_value? */ 2225166675Srrs SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value); 2226166675Srrs 2227166675Srrs if (stcb) { 2228166675Srrs size = 0; 2229166675Srrs /* Count the sizes */ 2230166675Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 2231283699Stuexen switch (net->ro._l_addr.sa.sa_family) { 2232221249Stuexen#ifdef INET 2233283699Stuexen case AF_INET: 2234283699Stuexen#ifdef INET6 2235283699Stuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 2236283699Stuexen size += sizeof(struct sockaddr_in6); 2237283699Stuexen } else { 2238221249Stuexen size += sizeof(struct sockaddr_in); 2239283699Stuexen } 2240283699Stuexen#else 2241283699Stuexen size += sizeof(struct sockaddr_in); 2242221249Stuexen#endif 2243283699Stuexen break; 2244283699Stuexen#endif 2245221249Stuexen#ifdef INET6 2246283699Stuexen case AF_INET6: 2247283699Stuexen size += sizeof(struct sockaddr_in6); 2248283699Stuexen break; 2249221249Stuexen#endif 2250283699Stuexen default: 2251283699Stuexen break; 2252166675Srrs } 2253163953Srrs } 2254166675Srrs SCTP_TCB_UNLOCK(stcb); 2255166675Srrs *value = (uint32_t) size; 2256223132Stuexen *optsize = sizeof(uint32_t); 2257166675Srrs } else { 2258171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 2259166675Srrs error = ENOTCONN; 2260163953Srrs } 2261223132Stuexen break; 2262163953Srrs } 2263163953Srrs case SCTP_GET_PEER_ADDRESSES: 2264163953Srrs /* 2265163953Srrs * Get the address information, an array is passed in to 2266163953Srrs * fill up we pack it. 2267163953Srrs */ 2268163953Srrs { 2269166675Srrs size_t cpsz, left; 2270163953Srrs struct sockaddr_storage *sas; 2271163953Srrs struct sctp_nets *net; 2272163953Srrs struct sctp_getaddresses *saddr; 2273163953Srrs 2274166675Srrs SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); 2275166675Srrs SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); 2276163953Srrs 2277166675Srrs if (stcb) { 2278166675Srrs left = (*optsize) - sizeof(struct sctp_getaddresses); 2279166675Srrs *optsize = sizeof(struct sctp_getaddresses); 2280166675Srrs sas = (struct sockaddr_storage *)&saddr->addr[0]; 2281166675Srrs 2282166675Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 2283283699Stuexen switch (net->ro._l_addr.sa.sa_family) { 2284221249Stuexen#ifdef INET 2285283699Stuexen case AF_INET: 2286283699Stuexen#ifdef INET6 2287283699Stuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 2288283699Stuexen cpsz = sizeof(struct sockaddr_in6); 2289283699Stuexen } else { 2290221249Stuexen cpsz = sizeof(struct sockaddr_in); 2291283699Stuexen } 2292283699Stuexen#else 2293283699Stuexen cpsz = sizeof(struct sockaddr_in); 2294221249Stuexen#endif 2295283699Stuexen break; 2296283699Stuexen#endif 2297221249Stuexen#ifdef INET6 2298283699Stuexen case AF_INET6: 2299283699Stuexen cpsz = sizeof(struct sockaddr_in6); 2300283699Stuexen break; 2301221249Stuexen#endif 2302283699Stuexen default: 2303283699Stuexen cpsz = 0; 2304283699Stuexen break; 2305221249Stuexen } 2306221249Stuexen if (cpsz == 0) { 2307166675Srrs break; 2308166675Srrs } 2309166675Srrs if (left < cpsz) { 2310166675Srrs /* not enough room. */ 2311166675Srrs break; 2312166675Srrs } 2313221249Stuexen#if defined(INET) && defined(INET6) 2314178251Srrs if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) && 2315283699Stuexen (net->ro._l_addr.sa.sa_family == AF_INET)) { 2316166675Srrs /* Must map the address */ 2317283699Stuexen in6_sin_2_v4mapsin6(&net->ro._l_addr.sin, 2318166675Srrs (struct sockaddr_in6 *)sas); 2319166675Srrs } else { 2320166675Srrs memcpy(sas, &net->ro._l_addr, cpsz); 2321166675Srrs } 2322283699Stuexen#else 2323283699Stuexen memcpy(sas, &net->ro._l_addr, cpsz); 2324178251Srrs#endif 2325166675Srrs ((struct sockaddr_in *)sas)->sin_port = stcb->rport; 2326166675Srrs 2327166675Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz); 2328166675Srrs left -= cpsz; 2329166675Srrs *optsize += cpsz; 2330163953Srrs } 2331166675Srrs SCTP_TCB_UNLOCK(stcb); 2332166675Srrs } else { 2333171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 2334166675Srrs error = ENOENT; 2335163953Srrs } 2336223132Stuexen break; 2337163953Srrs } 2338163953Srrs case SCTP_GET_LOCAL_ADDRESSES: 2339163953Srrs { 2340166675Srrs size_t limit, actual; 2341163953Srrs struct sockaddr_storage *sas; 2342163953Srrs struct sctp_getaddresses *saddr; 2343163953Srrs 2344166675Srrs SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); 2345166675Srrs SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); 2346163953Srrs 2347163953Srrs sas = (struct sockaddr_storage *)&saddr->addr[0]; 2348166675Srrs limit = *optsize - sizeof(sctp_assoc_t); 2349168124Srrs actual = sctp_fill_up_addresses(inp, stcb, limit, sas); 2350169655Srrs if (stcb) { 2351163953Srrs SCTP_TCB_UNLOCK(stcb); 2352169655Srrs } 2353166675Srrs *optsize = sizeof(struct sockaddr_storage) + actual; 2354223132Stuexen break; 2355163953Srrs } 2356163953Srrs case SCTP_PEER_ADDR_PARAMS: 2357163953Srrs { 2358163953Srrs struct sctp_paddrparams *paddrp; 2359163953Srrs struct sctp_nets *net; 2360283699Stuexen struct sockaddr *addr; 2361163953Srrs 2362283699Stuexen#if defined(INET) && defined(INET6) 2363283699Stuexen struct sockaddr_in sin_store; 2364283699Stuexen 2365283699Stuexen#endif 2366283699Stuexen 2367166675Srrs SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize); 2368166675Srrs SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); 2369163953Srrs 2370283699Stuexen#if defined(INET) && defined(INET6) 2371283699Stuexen if (paddrp->spp_address.ss_family == AF_INET6) { 2372283699Stuexen struct sockaddr_in6 *sin6; 2373283699Stuexen 2374283699Stuexen sin6 = (struct sockaddr_in6 *)&paddrp->spp_address; 2375283699Stuexen if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 2376283699Stuexen in6_sin6_2_sin(&sin_store, sin6); 2377283699Stuexen addr = (struct sockaddr *)&sin_store; 2378283699Stuexen } else { 2379283699Stuexen addr = (struct sockaddr *)&paddrp->spp_address; 2380283699Stuexen } 2381166675Srrs } else { 2382283699Stuexen addr = (struct sockaddr *)&paddrp->spp_address; 2383283699Stuexen } 2384283699Stuexen#else 2385283699Stuexen addr = (struct sockaddr *)&paddrp->spp_address; 2386283699Stuexen#endif 2387283699Stuexen if (stcb != NULL) { 2388283699Stuexen net = sctp_findnet(stcb, addr); 2389283699Stuexen } else { 2390166675Srrs /* 2391166675Srrs * We increment here since 2392166675Srrs * sctp_findassociation_ep_addr() wil do a 2393166675Srrs * decrement if it finds the stcb as long as 2394166675Srrs * the locked tcb (last argument) is NOT a 2395166675Srrs * TCB.. aka NULL. 2396166675Srrs */ 2397283699Stuexen net = NULL; 2398166675Srrs SCTP_INP_INCR_REF(inp); 2399283699Stuexen stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL); 2400163953Srrs if (stcb == NULL) { 2401166675Srrs SCTP_INP_DECR_REF(inp); 2402163953Srrs } 2403163953Srrs } 2404283699Stuexen if ((stcb != NULL) && (net == NULL)) { 2405221249Stuexen#ifdef INET 2406283699Stuexen if (addr->sa_family == AF_INET) { 2407171943Srrs struct sockaddr_in *sin; 2408171943Srrs 2409283699Stuexen sin = (struct sockaddr_in *)addr; 2410283699Stuexen if (sin->sin_addr.s_addr != INADDR_ANY) { 2411171943Srrs error = EINVAL; 2412171943Srrs SCTP_TCB_UNLOCK(stcb); 2413171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2414171943Srrs break; 2415171943Srrs } 2416221249Stuexen } else 2417221249Stuexen#endif 2418221249Stuexen#ifdef INET6 2419283699Stuexen if (addr->sa_family == AF_INET6) { 2420171943Srrs struct sockaddr_in6 *sin6; 2421171943Srrs 2422283699Stuexen sin6 = (struct sockaddr_in6 *)addr; 2423171943Srrs if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 2424171943Srrs error = EINVAL; 2425171943Srrs SCTP_TCB_UNLOCK(stcb); 2426171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2427171943Srrs break; 2428171943Srrs } 2429221249Stuexen } else 2430221249Stuexen#endif 2431221249Stuexen { 2432171943Srrs error = EAFNOSUPPORT; 2433171943Srrs SCTP_TCB_UNLOCK(stcb); 2434171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2435171943Srrs break; 2436171943Srrs } 2437171943Srrs } 2438283699Stuexen if (stcb != NULL) { 2439224641Stuexen /* Applies to the specific association */ 2440163953Srrs paddrp->spp_flags = 0; 2441283699Stuexen if (net != NULL) { 2442224641Stuexen paddrp->spp_hbinterval = net->heart_beat_delay; 2443163953Srrs paddrp->spp_pathmaxrxt = net->failure_threshold; 2444283829Stuexen paddrp->spp_pathmtu = net->mtu; 2445283829Stuexen switch (net->ro._l_addr.sa.sa_family) { 2446283829Stuexen#ifdef INET 2447283829Stuexen case AF_INET: 2448283829Stuexen paddrp->spp_pathmtu -= SCTP_MIN_V4_OVERHEAD; 2449283829Stuexen break; 2450283829Stuexen#endif 2451283829Stuexen#ifdef INET6 2452283829Stuexen case AF_INET6: 2453283829Stuexen paddrp->spp_pathmtu -= SCTP_MIN_V4_OVERHEAD; 2454283829Stuexen break; 2455283829Stuexen#endif 2456283829Stuexen default: 2457283829Stuexen break; 2458283829Stuexen } 2459163953Srrs /* get flags for HB */ 2460225635Stuexen if (net->dest_state & SCTP_ADDR_NOHB) { 2461163953Srrs paddrp->spp_flags |= SPP_HB_DISABLE; 2462225635Stuexen } else { 2463163953Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 2464225635Stuexen } 2465163953Srrs /* get flags for PMTU */ 2466225635Stuexen if (net->dest_state & SCTP_ADDR_NO_PMTUD) { 2467284440Stuexen paddrp->spp_flags |= SPP_PMTUD_DISABLE; 2468284440Stuexen } else { 2469163953Srrs paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2470163953Srrs } 2471225549Stuexen if (net->dscp & 0x01) { 2472226252Stuexen paddrp->spp_dscp = net->dscp & 0xfc; 2473224870Stuexen paddrp->spp_flags |= SPP_DSCP; 2474163953Srrs } 2475167598Srrs#ifdef INET6 2476225549Stuexen if ((net->ro._l_addr.sa.sa_family == AF_INET6) && 2477225549Stuexen (net->flowlabel & 0x80000000)) { 2478225549Stuexen paddrp->spp_ipv6_flowlabel = net->flowlabel & 0x000fffff; 2479163953Srrs paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2480163953Srrs } 2481163953Srrs#endif 2482163953Srrs } else { 2483163953Srrs /* 2484163953Srrs * No destination so return default 2485163953Srrs * value 2486163953Srrs */ 2487163953Srrs paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure; 2488283829Stuexen paddrp->spp_pathmtu = 0; 2489225549Stuexen if (stcb->asoc.default_dscp & 0x01) { 2490226252Stuexen paddrp->spp_dscp = stcb->asoc.default_dscp & 0xfc; 2491225549Stuexen paddrp->spp_flags |= SPP_DSCP; 2492225549Stuexen } 2493167598Srrs#ifdef INET6 2494225549Stuexen if (stcb->asoc.default_flowlabel & 0x80000000) { 2495225549Stuexen paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel & 0x000fffff; 2496225549Stuexen paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2497225549Stuexen } 2498163953Srrs#endif 2499163953Srrs /* default settings should be these */ 2500225635Stuexen if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { 2501224641Stuexen paddrp->spp_flags |= SPP_HB_DISABLE; 2502224641Stuexen } else { 2503163953Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 2504163953Srrs } 2505225635Stuexen if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) { 2506225635Stuexen paddrp->spp_flags |= SPP_PMTUD_DISABLE; 2507225635Stuexen } else { 2508170056Srrs paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2509170056Srrs } 2510225635Stuexen paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay; 2511163953Srrs } 2512163953Srrs paddrp->spp_assoc_id = sctp_get_associd(stcb); 2513163953Srrs SCTP_TCB_UNLOCK(stcb); 2514163953Srrs } else { 2515224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2516224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2517224918Stuexen (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) { 2518223132Stuexen /* Use endpoint defaults */ 2519223132Stuexen SCTP_INP_RLOCK(inp); 2520223132Stuexen paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure; 2521223132Stuexen paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); 2522223132Stuexen paddrp->spp_assoc_id = SCTP_FUTURE_ASSOC; 2523223132Stuexen /* get inp's default */ 2524225549Stuexen if (inp->sctp_ep.default_dscp & 0x01) { 2525226252Stuexen paddrp->spp_dscp = inp->sctp_ep.default_dscp & 0xfc; 2526225549Stuexen paddrp->spp_flags |= SPP_DSCP; 2527225549Stuexen } 2528167598Srrs#ifdef INET6 2529225549Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 2530225549Stuexen (inp->sctp_ep.default_flowlabel & 0x80000000)) { 2531225549Stuexen paddrp->spp_ipv6_flowlabel = inp->sctp_ep.default_flowlabel & 0x000fffff; 2532223132Stuexen paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2533223132Stuexen } 2534163953Srrs#endif 2535223132Stuexen /* can't return this */ 2536223132Stuexen paddrp->spp_pathmtu = 0; 2537170056Srrs 2538223132Stuexen if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { 2539223132Stuexen paddrp->spp_flags |= SPP_HB_ENABLE; 2540223132Stuexen } else { 2541223132Stuexen paddrp->spp_flags |= SPP_HB_DISABLE; 2542223132Stuexen } 2543225635Stuexen if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) { 2544225635Stuexen paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2545225635Stuexen } else { 2546225635Stuexen paddrp->spp_flags |= SPP_PMTUD_DISABLE; 2547225635Stuexen } 2548223132Stuexen SCTP_INP_RUNLOCK(inp); 2549170056Srrs } else { 2550223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2551223132Stuexen error = EINVAL; 2552170056Srrs } 2553163953Srrs } 2554223132Stuexen if (error == 0) { 2555223132Stuexen *optsize = sizeof(struct sctp_paddrparams); 2556223132Stuexen } 2557223132Stuexen break; 2558163953Srrs } 2559163953Srrs case SCTP_GET_PEER_ADDR_INFO: 2560163953Srrs { 2561163953Srrs struct sctp_paddrinfo *paddri; 2562163953Srrs struct sctp_nets *net; 2563283699Stuexen struct sockaddr *addr; 2564163953Srrs 2565283699Stuexen#if defined(INET) && defined(INET6) 2566283699Stuexen struct sockaddr_in sin_store; 2567283699Stuexen 2568283699Stuexen#endif 2569283699Stuexen 2570166675Srrs SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize); 2571166675Srrs SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id); 2572166675Srrs 2573283699Stuexen#if defined(INET) && defined(INET6) 2574283699Stuexen if (paddri->spinfo_address.ss_family == AF_INET6) { 2575283699Stuexen struct sockaddr_in6 *sin6; 2576283699Stuexen 2577283699Stuexen sin6 = (struct sockaddr_in6 *)&paddri->spinfo_address; 2578283699Stuexen if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 2579283699Stuexen in6_sin6_2_sin(&sin_store, sin6); 2580283699Stuexen addr = (struct sockaddr *)&sin_store; 2581283699Stuexen } else { 2582283699Stuexen addr = (struct sockaddr *)&paddri->spinfo_address; 2583283699Stuexen } 2584166675Srrs } else { 2585283699Stuexen addr = (struct sockaddr *)&paddri->spinfo_address; 2586283699Stuexen } 2587283699Stuexen#else 2588283699Stuexen addr = (struct sockaddr *)&paddri->spinfo_address; 2589283699Stuexen#endif 2590283699Stuexen if (stcb != NULL) { 2591283699Stuexen net = sctp_findnet(stcb, addr); 2592283699Stuexen } else { 2593166675Srrs /* 2594166675Srrs * We increment here since 2595166675Srrs * sctp_findassociation_ep_addr() wil do a 2596166675Srrs * decrement if it finds the stcb as long as 2597166675Srrs * the locked tcb (last argument) is NOT a 2598166675Srrs * TCB.. aka NULL. 2599166675Srrs */ 2600283699Stuexen net = NULL; 2601166675Srrs SCTP_INP_INCR_REF(inp); 2602283699Stuexen stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL); 2603166675Srrs if (stcb == NULL) { 2604166675Srrs SCTP_INP_DECR_REF(inp); 2605163953Srrs } 2606166675Srrs } 2607163953Srrs 2608283699Stuexen if ((stcb != NULL) && (net != NULL)) { 2609217635Srrs if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { 2610217638Stuexen /* It's unconfirmed */ 2611217635Srrs paddri->spinfo_state = SCTP_UNCONFIRMED; 2612217635Srrs } else if (net->dest_state & SCTP_ADDR_REACHABLE) { 2613217638Stuexen /* It's active */ 2614217635Srrs paddri->spinfo_state = SCTP_ACTIVE; 2615217635Srrs } else { 2616217638Stuexen /* It's inactive */ 2617217635Srrs paddri->spinfo_state = SCTP_INACTIVE; 2618217635Srrs } 2619166675Srrs paddri->spinfo_cwnd = net->cwnd; 2620219014Stuexen paddri->spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT; 2621166675Srrs paddri->spinfo_rto = net->RTO; 2622166675Srrs paddri->spinfo_assoc_id = sctp_get_associd(stcb); 2623222029Stuexen paddri->spinfo_mtu = net->mtu; 2624283829Stuexen switch (addr->sa_family) { 2625283829Stuexen#if defined(INET) 2626283829Stuexen case AF_INET: 2627283829Stuexen paddri->spinfo_mtu -= SCTP_MIN_V4_OVERHEAD; 2628283829Stuexen break; 2629283829Stuexen#endif 2630283829Stuexen#if defined(INET6) 2631283829Stuexen case AF_INET6: 2632283829Stuexen paddri->spinfo_mtu -= SCTP_MIN_OVERHEAD; 2633283829Stuexen break; 2634283829Stuexen#endif 2635283829Stuexen default: 2636283829Stuexen break; 2637283829Stuexen } 2638166675Srrs SCTP_TCB_UNLOCK(stcb); 2639223132Stuexen *optsize = sizeof(struct sctp_paddrinfo); 2640163953Srrs } else { 2641283699Stuexen if (stcb != NULL) { 2642163953Srrs SCTP_TCB_UNLOCK(stcb); 2643163953Srrs } 2644171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 2645163953Srrs error = ENOENT; 2646163953Srrs } 2647223132Stuexen break; 2648163953Srrs } 2649163953Srrs case SCTP_PCB_STATUS: 2650163953Srrs { 2651163953Srrs struct sctp_pcbinfo *spcb; 2652163953Srrs 2653166675Srrs SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize); 2654163953Srrs sctp_fill_pcbinfo(spcb); 2655166675Srrs *optsize = sizeof(struct sctp_pcbinfo); 2656223132Stuexen break; 2657163953Srrs } 2658163953Srrs case SCTP_STATUS: 2659163953Srrs { 2660163953Srrs struct sctp_nets *net; 2661163953Srrs struct sctp_status *sstat; 2662163953Srrs 2663166675Srrs SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize); 2664166675Srrs SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id); 2665163953Srrs 2666163953Srrs if (stcb == NULL) { 2667223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2668163953Srrs error = EINVAL; 2669163953Srrs break; 2670163953Srrs } 2671294149Stuexen sstat->sstat_state = sctp_map_assoc_state(stcb->asoc.state); 2672173179Srrs sstat->sstat_assoc_id = sctp_get_associd(stcb); 2673163953Srrs sstat->sstat_rwnd = stcb->asoc.peers_rwnd; 2674163953Srrs sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt; 2675163953Srrs /* 2676163953Srrs * We can't include chunks that have been passed to 2677163953Srrs * the socket layer. Only things in queue. 2678163953Srrs */ 2679163953Srrs sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue + 2680163953Srrs stcb->asoc.cnt_on_all_streams); 2681163953Srrs 2682163953Srrs 2683163953Srrs sstat->sstat_instrms = stcb->asoc.streamincnt; 2684163953Srrs sstat->sstat_outstrms = stcb->asoc.streamoutcnt; 2685163953Srrs sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc); 2686163953Srrs memcpy(&sstat->sstat_primary.spinfo_address, 2687163953Srrs &stcb->asoc.primary_destination->ro._l_addr, 2688163953Srrs ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len); 2689163953Srrs net = stcb->asoc.primary_destination; 2690163953Srrs ((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport; 2691163953Srrs /* 2692163953Srrs * Again the user can get info from sctp_constants.h 2693163953Srrs * for what the state of the network is. 2694163953Srrs */ 2695217635Srrs if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { 2696217635Srrs /* It's unconfirmed */ 2697217635Srrs sstat->sstat_primary.spinfo_state = SCTP_UNCONFIRMED; 2698217635Srrs } else if (net->dest_state & SCTP_ADDR_REACHABLE) { 2699217638Stuexen /* It's active */ 2700217635Srrs sstat->sstat_primary.spinfo_state = SCTP_ACTIVE; 2701217635Srrs } else { 2702217638Stuexen /* It's inactive */ 2703217635Srrs sstat->sstat_primary.spinfo_state = SCTP_INACTIVE; 2704217635Srrs } 2705163953Srrs sstat->sstat_primary.spinfo_cwnd = net->cwnd; 2706219014Stuexen sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT; 2707163953Srrs sstat->sstat_primary.spinfo_rto = net->RTO; 2708163953Srrs sstat->sstat_primary.spinfo_mtu = net->mtu; 2709283829Stuexen switch (stcb->asoc.primary_destination->ro._l_addr.sa.sa_family) { 2710283829Stuexen#if defined(INET) 2711283829Stuexen case AF_INET: 2712283829Stuexen sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_V4_OVERHEAD; 2713283829Stuexen break; 2714283829Stuexen#endif 2715283829Stuexen#if defined(INET6) 2716283829Stuexen case AF_INET6: 2717283829Stuexen sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_OVERHEAD; 2718283829Stuexen break; 2719283829Stuexen#endif 2720283829Stuexen default: 2721283829Stuexen break; 2722283829Stuexen } 2723163953Srrs sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb); 2724163953Srrs SCTP_TCB_UNLOCK(stcb); 2725223132Stuexen *optsize = sizeof(struct sctp_status); 2726223132Stuexen break; 2727163953Srrs } 2728163953Srrs case SCTP_RTOINFO: 2729163953Srrs { 2730163953Srrs struct sctp_rtoinfo *srto; 2731163953Srrs 2732166675Srrs SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize); 2733166675Srrs SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); 2734166675Srrs 2735166675Srrs if (stcb) { 2736166675Srrs srto->srto_initial = stcb->asoc.initial_rto; 2737166675Srrs srto->srto_max = stcb->asoc.maxrto; 2738166675Srrs srto->srto_min = stcb->asoc.minrto; 2739166675Srrs SCTP_TCB_UNLOCK(stcb); 2740166675Srrs } else { 2741224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2742224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2743224918Stuexen (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) { 2744223132Stuexen SCTP_INP_RLOCK(inp); 2745223132Stuexen srto->srto_initial = inp->sctp_ep.initial_rto; 2746223132Stuexen srto->srto_max = inp->sctp_ep.sctp_maxrto; 2747223132Stuexen srto->srto_min = inp->sctp_ep.sctp_minrto; 2748223132Stuexen SCTP_INP_RUNLOCK(inp); 2749223132Stuexen } else { 2750223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2751223132Stuexen error = EINVAL; 2752223132Stuexen } 2753163953Srrs } 2754223132Stuexen if (error == 0) { 2755223132Stuexen *optsize = sizeof(struct sctp_rtoinfo); 2756223132Stuexen } 2757223132Stuexen break; 2758163953Srrs } 2759215410Stuexen case SCTP_TIMEOUTS: 2760215410Stuexen { 2761215410Stuexen struct sctp_timeouts *stimo; 2762215410Stuexen 2763215410Stuexen SCTP_CHECK_AND_CAST(stimo, optval, struct sctp_timeouts, *optsize); 2764215410Stuexen SCTP_FIND_STCB(inp, stcb, stimo->stimo_assoc_id); 2765215410Stuexen 2766215410Stuexen if (stcb) { 2767215410Stuexen stimo->stimo_init = stcb->asoc.timoinit; 2768215410Stuexen stimo->stimo_data = stcb->asoc.timodata; 2769215410Stuexen stimo->stimo_sack = stcb->asoc.timosack; 2770215410Stuexen stimo->stimo_shutdown = stcb->asoc.timoshutdown; 2771215410Stuexen stimo->stimo_heartbeat = stcb->asoc.timoheartbeat; 2772215410Stuexen stimo->stimo_cookie = stcb->asoc.timocookie; 2773215410Stuexen stimo->stimo_shutdownack = stcb->asoc.timoshutdownack; 2774215410Stuexen SCTP_TCB_UNLOCK(stcb); 2775223132Stuexen *optsize = sizeof(struct sctp_timeouts); 2776215410Stuexen } else { 2777223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2778215410Stuexen error = EINVAL; 2779215410Stuexen } 2780223132Stuexen break; 2781215410Stuexen } 2782163953Srrs case SCTP_ASSOCINFO: 2783163953Srrs { 2784163953Srrs struct sctp_assocparams *sasoc; 2785163953Srrs 2786166675Srrs SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize); 2787166675Srrs SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); 2788163953Srrs 2789163953Srrs if (stcb) { 2790171477Srrs sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life); 2791163953Srrs sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times; 2792163953Srrs sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets; 2793163953Srrs sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd; 2794163953Srrs sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd; 2795163953Srrs SCTP_TCB_UNLOCK(stcb); 2796163953Srrs } else { 2797224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2798224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2799224918Stuexen (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) { 2800223132Stuexen SCTP_INP_RLOCK(inp); 2801223132Stuexen sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life); 2802223132Stuexen sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times; 2803223132Stuexen sasoc->sasoc_number_peer_destinations = 0; 2804223132Stuexen sasoc->sasoc_peer_rwnd = 0; 2805223132Stuexen sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv); 2806223132Stuexen SCTP_INP_RUNLOCK(inp); 2807223132Stuexen } else { 2808223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2809223132Stuexen error = EINVAL; 2810223132Stuexen } 2811163953Srrs } 2812223132Stuexen if (error == 0) { 2813223132Stuexen *optsize = sizeof(struct sctp_assocparams); 2814223132Stuexen } 2815223132Stuexen break; 2816163953Srrs } 2817163953Srrs case SCTP_DEFAULT_SEND_PARAM: 2818163953Srrs { 2819163953Srrs struct sctp_sndrcvinfo *s_info; 2820163953Srrs 2821166675Srrs SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize); 2822166675Srrs SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); 2823166675Srrs 2824166675Srrs if (stcb) { 2825170056Srrs memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send)); 2826166675Srrs SCTP_TCB_UNLOCK(stcb); 2827166675Srrs } else { 2828224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2829224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2830224918Stuexen (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC)) { 2831223132Stuexen SCTP_INP_RLOCK(inp); 2832223132Stuexen memcpy(s_info, &inp->def_send, sizeof(inp->def_send)); 2833223132Stuexen SCTP_INP_RUNLOCK(inp); 2834223132Stuexen } else { 2835223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2836223132Stuexen error = EINVAL; 2837223132Stuexen } 2838163953Srrs } 2839223132Stuexen if (error == 0) { 2840223132Stuexen *optsize = sizeof(struct sctp_sndrcvinfo); 2841223132Stuexen } 2842223132Stuexen break; 2843163953Srrs } 2844163953Srrs case SCTP_INITMSG: 2845163953Srrs { 2846163953Srrs struct sctp_initmsg *sinit; 2847163953Srrs 2848166675Srrs SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize); 2849163953Srrs SCTP_INP_RLOCK(inp); 2850163953Srrs sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count; 2851163953Srrs sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome; 2852163953Srrs sinit->sinit_max_attempts = inp->sctp_ep.max_init_times; 2853163953Srrs sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max; 2854163953Srrs SCTP_INP_RUNLOCK(inp); 2855223132Stuexen *optsize = sizeof(struct sctp_initmsg); 2856223132Stuexen break; 2857163953Srrs } 2858163953Srrs case SCTP_PRIMARY_ADDR: 2859163953Srrs /* we allow a "get" operation on this */ 2860163953Srrs { 2861163953Srrs struct sctp_setprim *ssp; 2862163953Srrs 2863166675Srrs SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize); 2864166675Srrs SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id); 2865166675Srrs 2866166675Srrs if (stcb) { 2867283699Stuexen union sctp_sockstore *addr; 2868170056Srrs 2869283699Stuexen addr = &stcb->asoc.primary_destination->ro._l_addr; 2870283699Stuexen switch (addr->sa.sa_family) { 2871283699Stuexen#ifdef INET 2872283699Stuexen case AF_INET: 2873283699Stuexen#ifdef INET6 2874283699Stuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 2875283699Stuexen in6_sin_2_v4mapsin6(&addr->sin, 2876283699Stuexen (struct sockaddr_in6 *)&ssp->ssp_addr); 2877283699Stuexen } else { 2878283699Stuexen memcpy(&ssp->ssp_addr, &addr->sin, sizeof(struct sockaddr_in)); 2879283699Stuexen } 2880283699Stuexen#else 2881283699Stuexen memcpy(&ssp->ssp_addr, &addr->sin, sizeof(struct sockaddr_in)); 2882283699Stuexen#endif 2883283699Stuexen break; 2884283699Stuexen#endif 2885283699Stuexen#ifdef INET6 2886283699Stuexen case AF_INET6: 2887283699Stuexen memcpy(&ssp->ssp_addr, &addr->sin6, sizeof(struct sockaddr_in6)); 2888283699Stuexen break; 2889283699Stuexen#endif 2890283699Stuexen default: 2891283699Stuexen break; 2892283699Stuexen } 2893166675Srrs SCTP_TCB_UNLOCK(stcb); 2894223132Stuexen *optsize = sizeof(struct sctp_setprim); 2895166675Srrs } else { 2896223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2897163953Srrs error = EINVAL; 2898163953Srrs } 2899223132Stuexen break; 2900163953Srrs } 2901163953Srrs case SCTP_HMAC_IDENT: 2902163953Srrs { 2903163953Srrs struct sctp_hmacalgo *shmac; 2904163953Srrs sctp_hmaclist_t *hmaclist; 2905163953Srrs uint32_t size; 2906163953Srrs int i; 2907163953Srrs 2908166675Srrs SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize); 2909166675Srrs 2910163953Srrs SCTP_INP_RLOCK(inp); 2911163953Srrs hmaclist = inp->sctp_ep.local_hmacs; 2912163953Srrs if (hmaclist == NULL) { 2913163953Srrs /* no HMACs to return */ 2914166675Srrs *optsize = sizeof(*shmac); 2915168299Srrs SCTP_INP_RUNLOCK(inp); 2916163953Srrs break; 2917163953Srrs } 2918163953Srrs /* is there room for all of the hmac ids? */ 2919163953Srrs size = sizeof(*shmac) + (hmaclist->num_algo * 2920163953Srrs sizeof(shmac->shmac_idents[0])); 2921166675Srrs if ((size_t)(*optsize) < size) { 2922223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2923163953Srrs error = EINVAL; 2924163953Srrs SCTP_INP_RUNLOCK(inp); 2925163953Srrs break; 2926163953Srrs } 2927163953Srrs /* copy in the list */ 2928181054Srrs shmac->shmac_number_of_idents = hmaclist->num_algo; 2929181054Srrs for (i = 0; i < hmaclist->num_algo; i++) { 2930163953Srrs shmac->shmac_idents[i] = hmaclist->hmac[i]; 2931181054Srrs } 2932163953Srrs SCTP_INP_RUNLOCK(inp); 2933166675Srrs *optsize = size; 2934163953Srrs break; 2935163953Srrs } 2936163953Srrs case SCTP_AUTH_ACTIVE_KEY: 2937163953Srrs { 2938163953Srrs struct sctp_authkeyid *scact; 2939163953Srrs 2940166675Srrs SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize); 2941166675Srrs SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); 2942166675Srrs 2943166675Srrs if (stcb) { 2944163953Srrs /* get the active key on the assoc */ 2945185694Srrs scact->scact_keynumber = stcb->asoc.authinfo.active_keyid; 2946163953Srrs SCTP_TCB_UNLOCK(stcb); 2947163953Srrs } else { 2948224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2949224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2950224918Stuexen (scact->scact_assoc_id == SCTP_FUTURE_ASSOC)) { 2951223132Stuexen /* get the endpoint active key */ 2952223132Stuexen SCTP_INP_RLOCK(inp); 2953223132Stuexen scact->scact_keynumber = inp->sctp_ep.default_keyid; 2954223132Stuexen SCTP_INP_RUNLOCK(inp); 2955223132Stuexen } else { 2956223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2957223132Stuexen error = EINVAL; 2958223132Stuexen } 2959163953Srrs } 2960223132Stuexen if (error == 0) { 2961223132Stuexen *optsize = sizeof(struct sctp_authkeyid); 2962223132Stuexen } 2963163953Srrs break; 2964163953Srrs } 2965163953Srrs case SCTP_LOCAL_AUTH_CHUNKS: 2966163953Srrs { 2967163953Srrs struct sctp_authchunks *sac; 2968163953Srrs sctp_auth_chklist_t *chklist = NULL; 2969166675Srrs size_t size = 0; 2970163953Srrs 2971166675Srrs SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); 2972166675Srrs SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); 2973166675Srrs 2974166675Srrs if (stcb) { 2975163953Srrs /* get off the assoc */ 2976163953Srrs chklist = stcb->asoc.local_auth_chunks; 2977163953Srrs /* is there enough space? */ 2978163953Srrs size = sctp_auth_get_chklist_size(chklist); 2979166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2980163953Srrs error = EINVAL; 2981171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2982166675Srrs } else { 2983166675Srrs /* copy in the chunks */ 2984169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2985234832Stuexen sac->gauth_number_of_chunks = (uint32_t) size; 2986223132Stuexen *optsize = sizeof(struct sctp_authchunks) + size; 2987163953Srrs } 2988163953Srrs SCTP_TCB_UNLOCK(stcb); 2989163953Srrs } else { 2990224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2991224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2992224918Stuexen (sac->gauth_assoc_id == SCTP_FUTURE_ASSOC)) { 2993223132Stuexen /* get off the endpoint */ 2994223132Stuexen SCTP_INP_RLOCK(inp); 2995223132Stuexen chklist = inp->sctp_ep.local_auth_chunks; 2996223132Stuexen /* is there enough space? */ 2997223132Stuexen size = sctp_auth_get_chklist_size(chklist); 2998223132Stuexen if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2999223132Stuexen error = EINVAL; 3000223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3001223132Stuexen } else { 3002223132Stuexen /* copy in the chunks */ 3003223132Stuexen (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 3004234832Stuexen sac->gauth_number_of_chunks = (uint32_t) size; 3005223132Stuexen *optsize = sizeof(struct sctp_authchunks) + size; 3006223132Stuexen } 3007223132Stuexen SCTP_INP_RUNLOCK(inp); 3008223132Stuexen } else { 3009223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3010163953Srrs error = EINVAL; 3011163953Srrs } 3012163953Srrs } 3013163953Srrs break; 3014163953Srrs } 3015163953Srrs case SCTP_PEER_AUTH_CHUNKS: 3016163953Srrs { 3017163953Srrs struct sctp_authchunks *sac; 3018163953Srrs sctp_auth_chklist_t *chklist = NULL; 3019166675Srrs size_t size = 0; 3020163953Srrs 3021166675Srrs SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); 3022166675Srrs SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); 3023166675Srrs 3024166675Srrs if (stcb) { 3025166675Srrs /* get off the assoc */ 3026166675Srrs chklist = stcb->asoc.peer_auth_chunks; 3027166675Srrs /* is there enough space? */ 3028166675Srrs size = sctp_auth_get_chklist_size(chklist); 3029166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 3030166675Srrs error = EINVAL; 3031171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3032166675Srrs } else { 3033166675Srrs /* copy in the chunks */ 3034169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 3035234832Stuexen sac->gauth_number_of_chunks = (uint32_t) size; 3036223132Stuexen *optsize = sizeof(struct sctp_authchunks) + size; 3037166675Srrs } 3038166675Srrs SCTP_TCB_UNLOCK(stcb); 3039166675Srrs } else { 3040171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 3041163953Srrs error = ENOENT; 3042163953Srrs } 3043163953Srrs break; 3044163953Srrs } 3045223132Stuexen case SCTP_EVENT: 3046223132Stuexen { 3047223132Stuexen struct sctp_event *event; 3048223132Stuexen uint32_t event_type; 3049163953Srrs 3050223132Stuexen SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, *optsize); 3051223132Stuexen SCTP_FIND_STCB(inp, stcb, event->se_assoc_id); 3052163953Srrs 3053223132Stuexen switch (event->se_type) { 3054223132Stuexen case SCTP_ASSOC_CHANGE: 3055223132Stuexen event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT; 3056223132Stuexen break; 3057223132Stuexen case SCTP_PEER_ADDR_CHANGE: 3058223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPADDREVNT; 3059223132Stuexen break; 3060223132Stuexen case SCTP_REMOTE_ERROR: 3061223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPEERERR; 3062223132Stuexen break; 3063223132Stuexen case SCTP_SEND_FAILED: 3064223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT; 3065223132Stuexen break; 3066223132Stuexen case SCTP_SHUTDOWN_EVENT: 3067223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT; 3068223132Stuexen break; 3069223132Stuexen case SCTP_ADAPTATION_INDICATION: 3070223132Stuexen event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT; 3071223132Stuexen break; 3072223132Stuexen case SCTP_PARTIAL_DELIVERY_EVENT: 3073223132Stuexen event_type = SCTP_PCB_FLAGS_PDAPIEVNT; 3074223132Stuexen break; 3075223132Stuexen case SCTP_AUTHENTICATION_EVENT: 3076223132Stuexen event_type = SCTP_PCB_FLAGS_AUTHEVNT; 3077223132Stuexen break; 3078223132Stuexen case SCTP_STREAM_RESET_EVENT: 3079223132Stuexen event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT; 3080223132Stuexen break; 3081223132Stuexen case SCTP_SENDER_DRY_EVENT: 3082223132Stuexen event_type = SCTP_PCB_FLAGS_DRYEVNT; 3083223132Stuexen break; 3084223132Stuexen case SCTP_NOTIFICATIONS_STOPPED_EVENT: 3085223132Stuexen event_type = 0; 3086223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); 3087223132Stuexen error = ENOTSUP; 3088223132Stuexen break; 3089235009Stuexen case SCTP_ASSOC_RESET_EVENT: 3090235009Stuexen event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT; 3091235009Stuexen break; 3092235009Stuexen case SCTP_STREAM_CHANGE_EVENT: 3093235009Stuexen event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT; 3094235009Stuexen break; 3095235075Stuexen case SCTP_SEND_FAILED_EVENT: 3096235075Stuexen event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT; 3097235075Stuexen break; 3098223132Stuexen default: 3099223132Stuexen event_type = 0; 3100223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3101223132Stuexen error = EINVAL; 3102223132Stuexen break; 3103223132Stuexen } 3104223132Stuexen if (event_type > 0) { 3105223132Stuexen if (stcb) { 3106223132Stuexen event->se_on = sctp_stcb_is_feature_on(inp, stcb, event_type); 3107223132Stuexen SCTP_TCB_UNLOCK(stcb); 3108223132Stuexen } else { 3109224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3110224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3111224918Stuexen (event->se_assoc_id == SCTP_FUTURE_ASSOC)) { 3112223132Stuexen SCTP_INP_RLOCK(inp); 3113223132Stuexen event->se_on = sctp_is_feature_on(inp, event_type); 3114223132Stuexen SCTP_INP_RUNLOCK(inp); 3115223132Stuexen } else { 3116223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3117223132Stuexen error = EINVAL; 3118223132Stuexen } 3119223132Stuexen } 3120223132Stuexen } 3121223132Stuexen if (error == 0) { 3122223132Stuexen *optsize = sizeof(struct sctp_event); 3123223132Stuexen } 3124223132Stuexen break; 3125223132Stuexen } 3126223132Stuexen case SCTP_RECVRCVINFO: 3127223132Stuexen { 3128223132Stuexen int onoff; 3129223132Stuexen 3130223132Stuexen if (*optsize < sizeof(int)) { 3131223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3132223132Stuexen error = EINVAL; 3133223132Stuexen } else { 3134230104Stuexen SCTP_INP_RLOCK(inp); 3135223132Stuexen onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO); 3136223132Stuexen SCTP_INP_RUNLOCK(inp); 3137223132Stuexen } 3138223132Stuexen if (error == 0) { 3139223132Stuexen /* return the option value */ 3140223132Stuexen *(int *)optval = onoff; 3141223132Stuexen *optsize = sizeof(int); 3142223132Stuexen } 3143223132Stuexen break; 3144223132Stuexen } 3145223132Stuexen case SCTP_RECVNXTINFO: 3146223132Stuexen { 3147223132Stuexen int onoff; 3148223132Stuexen 3149223132Stuexen if (*optsize < sizeof(int)) { 3150223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3151223132Stuexen error = EINVAL; 3152223132Stuexen } else { 3153230104Stuexen SCTP_INP_RLOCK(inp); 3154223132Stuexen onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO); 3155223132Stuexen SCTP_INP_RUNLOCK(inp); 3156223132Stuexen } 3157223132Stuexen if (error == 0) { 3158223132Stuexen /* return the option value */ 3159223132Stuexen *(int *)optval = onoff; 3160223132Stuexen *optsize = sizeof(int); 3161223132Stuexen } 3162223132Stuexen break; 3163223132Stuexen } 3164223132Stuexen case SCTP_DEFAULT_SNDINFO: 3165223132Stuexen { 3166223132Stuexen struct sctp_sndinfo *info; 3167223132Stuexen 3168223132Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, *optsize); 3169223132Stuexen SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id); 3170223132Stuexen 3171223132Stuexen if (stcb) { 3172223132Stuexen info->snd_sid = stcb->asoc.def_send.sinfo_stream; 3173223132Stuexen info->snd_flags = stcb->asoc.def_send.sinfo_flags; 3174223162Stuexen info->snd_flags &= 0xfff0; 3175223132Stuexen info->snd_ppid = stcb->asoc.def_send.sinfo_ppid; 3176223132Stuexen info->snd_context = stcb->asoc.def_send.sinfo_context; 3177223132Stuexen SCTP_TCB_UNLOCK(stcb); 3178223132Stuexen } else { 3179224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3180224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3181224918Stuexen (info->snd_assoc_id == SCTP_FUTURE_ASSOC)) { 3182223132Stuexen SCTP_INP_RLOCK(inp); 3183223132Stuexen info->snd_sid = inp->def_send.sinfo_stream; 3184223132Stuexen info->snd_flags = inp->def_send.sinfo_flags; 3185223162Stuexen info->snd_flags &= 0xfff0; 3186223132Stuexen info->snd_ppid = inp->def_send.sinfo_ppid; 3187223132Stuexen info->snd_context = inp->def_send.sinfo_context; 3188223132Stuexen SCTP_INP_RUNLOCK(inp); 3189223132Stuexen } else { 3190223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3191223132Stuexen error = EINVAL; 3192223132Stuexen } 3193223132Stuexen } 3194223132Stuexen if (error == 0) { 3195223132Stuexen *optsize = sizeof(struct sctp_sndinfo); 3196223132Stuexen } 3197223132Stuexen break; 3198223132Stuexen } 3199223162Stuexen case SCTP_DEFAULT_PRINFO: 3200223162Stuexen { 3201223162Stuexen struct sctp_default_prinfo *info; 3202223162Stuexen 3203223162Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, *optsize); 3204223162Stuexen SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id); 3205223162Stuexen 3206223162Stuexen if (stcb) { 3207223162Stuexen info->pr_policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); 3208223162Stuexen info->pr_value = stcb->asoc.def_send.sinfo_timetolive; 3209223162Stuexen SCTP_TCB_UNLOCK(stcb); 3210223162Stuexen } else { 3211224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3212224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3213224918Stuexen (info->pr_assoc_id == SCTP_FUTURE_ASSOC)) { 3214223162Stuexen SCTP_INP_RLOCK(inp); 3215223162Stuexen info->pr_policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags); 3216223162Stuexen info->pr_value = inp->def_send.sinfo_timetolive; 3217223162Stuexen SCTP_INP_RUNLOCK(inp); 3218223162Stuexen } else { 3219223162Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3220223162Stuexen error = EINVAL; 3221223162Stuexen } 3222223162Stuexen } 3223223162Stuexen if (error == 0) { 3224223162Stuexen *optsize = sizeof(struct sctp_default_prinfo); 3225223162Stuexen } 3226223162Stuexen break; 3227223162Stuexen } 3228224641Stuexen case SCTP_PEER_ADDR_THLDS: 3229224641Stuexen { 3230224641Stuexen struct sctp_paddrthlds *thlds; 3231224641Stuexen struct sctp_nets *net; 3232283699Stuexen struct sockaddr *addr; 3233224641Stuexen 3234283699Stuexen#if defined(INET) && defined(INET6) 3235283699Stuexen struct sockaddr_in sin_store; 3236283699Stuexen 3237283699Stuexen#endif 3238283699Stuexen 3239224641Stuexen SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, *optsize); 3240224641Stuexen SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id); 3241224641Stuexen 3242283699Stuexen#if defined(INET) && defined(INET6) 3243283699Stuexen if (thlds->spt_address.ss_family == AF_INET6) { 3244283699Stuexen struct sockaddr_in6 *sin6; 3245283699Stuexen 3246283699Stuexen sin6 = (struct sockaddr_in6 *)&thlds->spt_address; 3247283699Stuexen if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 3248283699Stuexen in6_sin6_2_sin(&sin_store, sin6); 3249283699Stuexen addr = (struct sockaddr *)&sin_store; 3250283699Stuexen } else { 3251283699Stuexen addr = (struct sockaddr *)&thlds->spt_address; 3252283699Stuexen } 3253224641Stuexen } else { 3254283699Stuexen addr = (struct sockaddr *)&thlds->spt_address; 3255283699Stuexen } 3256283699Stuexen#else 3257283699Stuexen addr = (struct sockaddr *)&thlds->spt_address; 3258283699Stuexen#endif 3259283699Stuexen if (stcb != NULL) { 3260283699Stuexen net = sctp_findnet(stcb, addr); 3261283699Stuexen } else { 3262224641Stuexen /* 3263224641Stuexen * We increment here since 3264224641Stuexen * sctp_findassociation_ep_addr() wil do a 3265224641Stuexen * decrement if it finds the stcb as long as 3266224641Stuexen * the locked tcb (last argument) is NOT a 3267224641Stuexen * TCB.. aka NULL. 3268224641Stuexen */ 3269283699Stuexen net = NULL; 3270224641Stuexen SCTP_INP_INCR_REF(inp); 3271283699Stuexen stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL); 3272224641Stuexen if (stcb == NULL) { 3273224641Stuexen SCTP_INP_DECR_REF(inp); 3274224641Stuexen } 3275224641Stuexen } 3276283699Stuexen if ((stcb != NULL) && (net == NULL)) { 3277224641Stuexen#ifdef INET 3278283699Stuexen if (addr->sa_family == AF_INET) { 3279224641Stuexen struct sockaddr_in *sin; 3280224641Stuexen 3281283699Stuexen sin = (struct sockaddr_in *)addr; 3282283699Stuexen if (sin->sin_addr.s_addr != INADDR_ANY) { 3283224641Stuexen error = EINVAL; 3284224641Stuexen SCTP_TCB_UNLOCK(stcb); 3285224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3286224641Stuexen break; 3287224641Stuexen } 3288224641Stuexen } else 3289224641Stuexen#endif 3290224641Stuexen#ifdef INET6 3291283699Stuexen if (addr->sa_family == AF_INET6) { 3292224641Stuexen struct sockaddr_in6 *sin6; 3293224641Stuexen 3294283699Stuexen sin6 = (struct sockaddr_in6 *)addr; 3295224641Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 3296224641Stuexen error = EINVAL; 3297224641Stuexen SCTP_TCB_UNLOCK(stcb); 3298224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3299224641Stuexen break; 3300224641Stuexen } 3301224641Stuexen } else 3302224641Stuexen#endif 3303224641Stuexen { 3304224641Stuexen error = EAFNOSUPPORT; 3305224641Stuexen SCTP_TCB_UNLOCK(stcb); 3306224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3307224641Stuexen break; 3308224641Stuexen } 3309224641Stuexen } 3310283699Stuexen if (stcb != NULL) { 3311283699Stuexen if (net != NULL) { 3312224641Stuexen thlds->spt_pathmaxrxt = net->failure_threshold; 3313224641Stuexen thlds->spt_pathpfthld = net->pf_threshold; 3314224641Stuexen } else { 3315224641Stuexen thlds->spt_pathmaxrxt = stcb->asoc.def_net_failure; 3316224641Stuexen thlds->spt_pathpfthld = stcb->asoc.def_net_pf_threshold; 3317224641Stuexen } 3318224641Stuexen thlds->spt_assoc_id = sctp_get_associd(stcb); 3319224641Stuexen SCTP_TCB_UNLOCK(stcb); 3320224641Stuexen } else { 3321224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3322224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3323224918Stuexen (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) { 3324224641Stuexen /* Use endpoint defaults */ 3325224641Stuexen SCTP_INP_RLOCK(inp); 3326224641Stuexen thlds->spt_pathmaxrxt = inp->sctp_ep.def_net_failure; 3327224641Stuexen thlds->spt_pathpfthld = inp->sctp_ep.def_net_pf_threshold; 3328224641Stuexen SCTP_INP_RUNLOCK(inp); 3329224641Stuexen } else { 3330224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3331224641Stuexen error = EINVAL; 3332224641Stuexen } 3333224641Stuexen } 3334224641Stuexen if (error == 0) { 3335224641Stuexen *optsize = sizeof(struct sctp_paddrthlds); 3336224641Stuexen } 3337224641Stuexen break; 3338224641Stuexen } 3339227755Stuexen case SCTP_REMOTE_UDP_ENCAPS_PORT: 3340227755Stuexen { 3341227755Stuexen struct sctp_udpencaps *encaps; 3342227755Stuexen struct sctp_nets *net; 3343283699Stuexen struct sockaddr *addr; 3344227755Stuexen 3345283699Stuexen#if defined(INET) && defined(INET6) 3346283699Stuexen struct sockaddr_in sin_store; 3347283699Stuexen 3348283699Stuexen#endif 3349283699Stuexen 3350227755Stuexen SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, *optsize); 3351227755Stuexen SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id); 3352227755Stuexen 3353283699Stuexen#if defined(INET) && defined(INET6) 3354283699Stuexen if (encaps->sue_address.ss_family == AF_INET6) { 3355283699Stuexen struct sockaddr_in6 *sin6; 3356283699Stuexen 3357283699Stuexen sin6 = (struct sockaddr_in6 *)&encaps->sue_address; 3358283699Stuexen if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 3359283699Stuexen in6_sin6_2_sin(&sin_store, sin6); 3360283699Stuexen addr = (struct sockaddr *)&sin_store; 3361283699Stuexen } else { 3362283699Stuexen addr = (struct sockaddr *)&encaps->sue_address; 3363283699Stuexen } 3364283699Stuexen } else { 3365283699Stuexen addr = (struct sockaddr *)&encaps->sue_address; 3366283699Stuexen } 3367283699Stuexen#else 3368283699Stuexen addr = (struct sockaddr *)&encaps->sue_address; 3369283699Stuexen#endif 3370227755Stuexen if (stcb) { 3371283699Stuexen net = sctp_findnet(stcb, addr); 3372227755Stuexen } else { 3373227755Stuexen /* 3374227755Stuexen * We increment here since 3375227755Stuexen * sctp_findassociation_ep_addr() wil do a 3376227755Stuexen * decrement if it finds the stcb as long as 3377227755Stuexen * the locked tcb (last argument) is NOT a 3378227755Stuexen * TCB.. aka NULL. 3379227755Stuexen */ 3380227755Stuexen net = NULL; 3381227755Stuexen SCTP_INP_INCR_REF(inp); 3382283699Stuexen stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL); 3383227755Stuexen if (stcb == NULL) { 3384227755Stuexen SCTP_INP_DECR_REF(inp); 3385227755Stuexen } 3386227755Stuexen } 3387283699Stuexen if ((stcb != NULL) && (net == NULL)) { 3388227755Stuexen#ifdef INET 3389283699Stuexen if (addr->sa_family == AF_INET) { 3390227755Stuexen struct sockaddr_in *sin; 3391227755Stuexen 3392283699Stuexen sin = (struct sockaddr_in *)addr; 3393283699Stuexen if (sin->sin_addr.s_addr != INADDR_ANY) { 3394227755Stuexen error = EINVAL; 3395227755Stuexen SCTP_TCB_UNLOCK(stcb); 3396227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3397227755Stuexen break; 3398227755Stuexen } 3399227755Stuexen } else 3400227755Stuexen#endif 3401227755Stuexen#ifdef INET6 3402283699Stuexen if (addr->sa_family == AF_INET6) { 3403227755Stuexen struct sockaddr_in6 *sin6; 3404227755Stuexen 3405283699Stuexen sin6 = (struct sockaddr_in6 *)addr; 3406227755Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 3407227755Stuexen error = EINVAL; 3408227755Stuexen SCTP_TCB_UNLOCK(stcb); 3409227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3410227755Stuexen break; 3411227755Stuexen } 3412227755Stuexen } else 3413227755Stuexen#endif 3414227755Stuexen { 3415227755Stuexen error = EAFNOSUPPORT; 3416227755Stuexen SCTP_TCB_UNLOCK(stcb); 3417227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3418227755Stuexen break; 3419227755Stuexen } 3420227755Stuexen } 3421283699Stuexen if (stcb != NULL) { 3422227755Stuexen if (net) { 3423227755Stuexen encaps->sue_port = net->port; 3424227755Stuexen } else { 3425227755Stuexen encaps->sue_port = stcb->asoc.port; 3426227755Stuexen } 3427227755Stuexen SCTP_TCB_UNLOCK(stcb); 3428227755Stuexen } else { 3429227755Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3430227755Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3431227755Stuexen (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) { 3432227755Stuexen SCTP_INP_RLOCK(inp); 3433227755Stuexen encaps->sue_port = inp->sctp_ep.port; 3434227755Stuexen SCTP_INP_RUNLOCK(inp); 3435227755Stuexen } else { 3436227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3437227755Stuexen error = EINVAL; 3438227755Stuexen } 3439227755Stuexen } 3440227755Stuexen if (error == 0) { 3441258454Stuexen *optsize = sizeof(struct sctp_udpencaps); 3442227755Stuexen } 3443227755Stuexen break; 3444227755Stuexen } 3445270356Stuexen case SCTP_ECN_SUPPORTED: 3446270356Stuexen { 3447270356Stuexen struct sctp_assoc_value *av; 3448270356Stuexen 3449270356Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3450270356Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3451270356Stuexen 3452270356Stuexen if (stcb) { 3453270356Stuexen av->assoc_value = stcb->asoc.ecn_supported; 3454270356Stuexen SCTP_TCB_UNLOCK(stcb); 3455270356Stuexen } else { 3456270356Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3457270356Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3458270356Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3459270356Stuexen SCTP_INP_RLOCK(inp); 3460270356Stuexen av->assoc_value = inp->ecn_supported; 3461270356Stuexen SCTP_INP_RUNLOCK(inp); 3462270356Stuexen } else { 3463270356Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3464270356Stuexen error = EINVAL; 3465270356Stuexen } 3466270356Stuexen } 3467270356Stuexen if (error == 0) { 3468270356Stuexen *optsize = sizeof(struct sctp_assoc_value); 3469270356Stuexen } 3470270356Stuexen break; 3471270356Stuexen } 3472270357Stuexen case SCTP_PR_SUPPORTED: 3473270357Stuexen { 3474270357Stuexen struct sctp_assoc_value *av; 3475270357Stuexen 3476270357Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3477270357Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3478270357Stuexen 3479270357Stuexen if (stcb) { 3480270357Stuexen av->assoc_value = stcb->asoc.prsctp_supported; 3481270357Stuexen SCTP_TCB_UNLOCK(stcb); 3482270357Stuexen } else { 3483270357Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3484270357Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3485270357Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3486270357Stuexen SCTP_INP_RLOCK(inp); 3487270357Stuexen av->assoc_value = inp->prsctp_supported; 3488270357Stuexen SCTP_INP_RUNLOCK(inp); 3489270357Stuexen } else { 3490270357Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3491270357Stuexen error = EINVAL; 3492270357Stuexen } 3493270357Stuexen } 3494270357Stuexen if (error == 0) { 3495270357Stuexen *optsize = sizeof(struct sctp_assoc_value); 3496270357Stuexen } 3497270357Stuexen break; 3498270357Stuexen } 3499270362Stuexen case SCTP_AUTH_SUPPORTED: 3500270362Stuexen { 3501270362Stuexen struct sctp_assoc_value *av; 3502270362Stuexen 3503270362Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3504270362Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3505270362Stuexen 3506270362Stuexen if (stcb) { 3507270362Stuexen av->assoc_value = stcb->asoc.auth_supported; 3508270362Stuexen SCTP_TCB_UNLOCK(stcb); 3509270362Stuexen } else { 3510270362Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3511270362Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3512270362Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3513270362Stuexen SCTP_INP_RLOCK(inp); 3514270362Stuexen av->assoc_value = inp->auth_supported; 3515270362Stuexen SCTP_INP_RUNLOCK(inp); 3516270362Stuexen } else { 3517270362Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3518270362Stuexen error = EINVAL; 3519270362Stuexen } 3520270362Stuexen } 3521270362Stuexen if (error == 0) { 3522270362Stuexen *optsize = sizeof(struct sctp_assoc_value); 3523270362Stuexen } 3524270362Stuexen break; 3525270362Stuexen } 3526270362Stuexen case SCTP_ASCONF_SUPPORTED: 3527270362Stuexen { 3528270362Stuexen struct sctp_assoc_value *av; 3529270362Stuexen 3530270362Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3531270362Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3532270362Stuexen 3533270362Stuexen if (stcb) { 3534270362Stuexen av->assoc_value = stcb->asoc.asconf_supported; 3535270362Stuexen SCTP_TCB_UNLOCK(stcb); 3536270362Stuexen } else { 3537270362Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3538270362Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3539270362Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3540270362Stuexen SCTP_INP_RLOCK(inp); 3541270362Stuexen av->assoc_value = inp->asconf_supported; 3542270362Stuexen SCTP_INP_RUNLOCK(inp); 3543270362Stuexen } else { 3544270362Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3545270362Stuexen error = EINVAL; 3546270362Stuexen } 3547270362Stuexen } 3548270362Stuexen if (error == 0) { 3549270362Stuexen *optsize = sizeof(struct sctp_assoc_value); 3550270362Stuexen } 3551270362Stuexen break; 3552270362Stuexen } 3553270361Stuexen case SCTP_RECONFIG_SUPPORTED: 3554270361Stuexen { 3555270361Stuexen struct sctp_assoc_value *av; 3556270361Stuexen 3557270361Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3558270361Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3559270361Stuexen 3560270361Stuexen if (stcb) { 3561270361Stuexen av->assoc_value = stcb->asoc.reconfig_supported; 3562270361Stuexen SCTP_TCB_UNLOCK(stcb); 3563270361Stuexen } else { 3564270361Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3565270361Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3566270361Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3567270361Stuexen SCTP_INP_RLOCK(inp); 3568270361Stuexen av->assoc_value = inp->reconfig_supported; 3569270361Stuexen SCTP_INP_RUNLOCK(inp); 3570270361Stuexen } else { 3571270361Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3572270361Stuexen error = EINVAL; 3573270361Stuexen } 3574270361Stuexen } 3575270361Stuexen if (error == 0) { 3576270361Stuexen *optsize = sizeof(struct sctp_assoc_value); 3577270361Stuexen } 3578270361Stuexen break; 3579270361Stuexen } 3580270359Stuexen case SCTP_NRSACK_SUPPORTED: 3581270359Stuexen { 3582270359Stuexen struct sctp_assoc_value *av; 3583270359Stuexen 3584270359Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3585270359Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3586270359Stuexen 3587270359Stuexen if (stcb) { 3588270359Stuexen av->assoc_value = stcb->asoc.nrsack_supported; 3589270359Stuexen SCTP_TCB_UNLOCK(stcb); 3590270359Stuexen } else { 3591270359Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3592270359Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3593270359Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3594270359Stuexen SCTP_INP_RLOCK(inp); 3595270359Stuexen av->assoc_value = inp->nrsack_supported; 3596270359Stuexen SCTP_INP_RUNLOCK(inp); 3597270359Stuexen } else { 3598270359Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3599270359Stuexen error = EINVAL; 3600270359Stuexen } 3601270359Stuexen } 3602270359Stuexen if (error == 0) { 3603270359Stuexen *optsize = sizeof(struct sctp_assoc_value); 3604270359Stuexen } 3605270359Stuexen break; 3606270359Stuexen } 3607270360Stuexen case SCTP_PKTDROP_SUPPORTED: 3608270360Stuexen { 3609270360Stuexen struct sctp_assoc_value *av; 3610270360Stuexen 3611270360Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3612270360Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3613270360Stuexen 3614270360Stuexen if (stcb) { 3615270360Stuexen av->assoc_value = stcb->asoc.pktdrop_supported; 3616270360Stuexen SCTP_TCB_UNLOCK(stcb); 3617270360Stuexen } else { 3618270360Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3619270360Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3620270360Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3621270360Stuexen SCTP_INP_RLOCK(inp); 3622270360Stuexen av->assoc_value = inp->pktdrop_supported; 3623270360Stuexen SCTP_INP_RUNLOCK(inp); 3624270360Stuexen } else { 3625270360Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3626270360Stuexen error = EINVAL; 3627270360Stuexen } 3628270360Stuexen } 3629270360Stuexen if (error == 0) { 3630270360Stuexen *optsize = sizeof(struct sctp_assoc_value); 3631270360Stuexen } 3632270360Stuexen break; 3633270360Stuexen } 3634235021Stuexen case SCTP_ENABLE_STREAM_RESET: 3635235021Stuexen { 3636235021Stuexen struct sctp_assoc_value *av; 3637235021Stuexen 3638235021Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3639235021Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3640235021Stuexen 3641235021Stuexen if (stcb) { 3642235021Stuexen av->assoc_value = (uint32_t) stcb->asoc.local_strreset_support; 3643235021Stuexen SCTP_TCB_UNLOCK(stcb); 3644235021Stuexen } else { 3645235021Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3646235021Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3647235021Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3648235021Stuexen SCTP_INP_RLOCK(inp); 3649235021Stuexen av->assoc_value = (uint32_t) inp->local_strreset_support; 3650235021Stuexen SCTP_INP_RUNLOCK(inp); 3651235021Stuexen } else { 3652235021Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3653235021Stuexen error = EINVAL; 3654235021Stuexen } 3655235021Stuexen } 3656235021Stuexen if (error == 0) { 3657235021Stuexen *optsize = sizeof(struct sctp_assoc_value); 3658235021Stuexen } 3659235021Stuexen break; 3660235021Stuexen } 3661270363Stuexen case SCTP_PR_STREAM_STATUS: 3662270363Stuexen { 3663270363Stuexen struct sctp_prstatus *sprstat; 3664270363Stuexen uint16_t sid; 3665270363Stuexen uint16_t policy; 3666270363Stuexen 3667270363Stuexen SCTP_CHECK_AND_CAST(sprstat, optval, struct sctp_prstatus, *optsize); 3668270363Stuexen SCTP_FIND_STCB(inp, stcb, sprstat->sprstat_assoc_id); 3669270363Stuexen 3670270363Stuexen sid = sprstat->sprstat_sid; 3671270363Stuexen policy = sprstat->sprstat_policy; 3672270363Stuexen#if defined(SCTP_DETAILED_STR_STATS) 3673270363Stuexen if ((stcb != NULL) && 3674283706Stuexen (sid < stcb->asoc.streamoutcnt) && 3675270363Stuexen (policy != SCTP_PR_SCTP_NONE) && 3676283706Stuexen ((policy <= SCTP_PR_SCTP_MAX) || 3677283706Stuexen (policy == SCTP_PR_SCTP_ALL))) { 3678270363Stuexen if (policy == SCTP_PR_SCTP_ALL) { 3679270363Stuexen sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[0]; 3680270363Stuexen sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[0]; 3681270363Stuexen } else { 3682270363Stuexen sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[policy]; 3683270363Stuexen sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[policy]; 3684270363Stuexen } 3685283705Stuexen#else 3686283705Stuexen if ((stcb != NULL) && 3687283706Stuexen (sid < stcb->asoc.streamoutcnt) && 3688283706Stuexen (policy == SCTP_PR_SCTP_ALL)) { 3689283705Stuexen sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[0]; 3690283705Stuexen sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[0]; 3691283705Stuexen#endif 3692270363Stuexen SCTP_TCB_UNLOCK(stcb); 3693270363Stuexen *optsize = sizeof(struct sctp_prstatus); 3694270363Stuexen } else { 3695270363Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3696270363Stuexen error = EINVAL; 3697270363Stuexen } 3698270363Stuexen break; 3699270363Stuexen } 3700270363Stuexen case SCTP_PR_ASSOC_STATUS: 3701270363Stuexen { 3702270363Stuexen struct sctp_prstatus *sprstat; 3703270363Stuexen uint16_t policy; 3704270363Stuexen 3705270363Stuexen SCTP_CHECK_AND_CAST(sprstat, optval, struct sctp_prstatus, *optsize); 3706270363Stuexen SCTP_FIND_STCB(inp, stcb, sprstat->sprstat_assoc_id); 3707270363Stuexen 3708270363Stuexen policy = sprstat->sprstat_policy; 3709270363Stuexen if ((stcb != NULL) && 3710270363Stuexen (policy != SCTP_PR_SCTP_NONE) && 3711283706Stuexen ((policy <= SCTP_PR_SCTP_MAX) || 3712283706Stuexen (policy == SCTP_PR_SCTP_ALL))) { 3713270363Stuexen if (policy == SCTP_PR_SCTP_ALL) { 3714270363Stuexen sprstat->sprstat_abandoned_unsent = stcb->asoc.abandoned_unsent[0]; 3715270363Stuexen sprstat->sprstat_abandoned_sent = stcb->asoc.abandoned_sent[0]; 3716270363Stuexen } else { 3717270363Stuexen sprstat->sprstat_abandoned_unsent = stcb->asoc.abandoned_unsent[policy]; 3718270363Stuexen sprstat->sprstat_abandoned_sent = stcb->asoc.abandoned_sent[policy]; 3719270363Stuexen } 3720270363Stuexen SCTP_TCB_UNLOCK(stcb); 3721270363Stuexen *optsize = sizeof(struct sctp_prstatus); 3722270363Stuexen } else { 3723270363Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3724270363Stuexen error = EINVAL; 3725270363Stuexen } 3726270363Stuexen break; 3727270363Stuexen } 3728283724Stuexen case SCTP_MAX_CWND: 3729283724Stuexen { 3730283724Stuexen struct sctp_assoc_value *av; 3731283724Stuexen 3732283724Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3733283724Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3734283724Stuexen 3735283724Stuexen if (stcb) { 3736283724Stuexen av->assoc_value = stcb->asoc.max_cwnd; 3737283724Stuexen SCTP_TCB_UNLOCK(stcb); 3738283724Stuexen } else { 3739283724Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3740283724Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3741283724Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3742283724Stuexen SCTP_INP_RLOCK(inp); 3743283724Stuexen av->assoc_value = inp->max_cwnd; 3744283724Stuexen SCTP_INP_RUNLOCK(inp); 3745283724Stuexen } else { 3746283724Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3747283724Stuexen error = EINVAL; 3748283724Stuexen } 3749283724Stuexen } 3750283724Stuexen if (error == 0) { 3751283724Stuexen *optsize = sizeof(struct sctp_assoc_value); 3752283724Stuexen } 3753283724Stuexen break; 3754283724Stuexen } 3755163953Srrs default: 3756171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 3757163953Srrs error = ENOPROTOOPT; 3758163953Srrs break; 3759163953Srrs } /* end switch (sopt->sopt_name) */ 3760223132Stuexen if (error) { 3761223132Stuexen *optsize = 0; 3762223132Stuexen } 3763163953Srrs return (error); 3764163953Srrs} 3765163953Srrs 3766163953Srrsstatic int 3767166675Srrssctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, 3768166675Srrs void *p) 3769163953Srrs{ 3770166675Srrs int error, set_opt; 3771166675Srrs uint32_t *mopt; 3772163953Srrs struct sctp_tcb *stcb = NULL; 3773171943Srrs struct sctp_inpcb *inp = NULL; 3774167598Srrs uint32_t vrf_id; 3775163953Srrs 3776166675Srrs if (optval == NULL) { 3777169420Srrs SCTP_PRINTF("optval is NULL\n"); 3778171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3779163953Srrs return (EINVAL); 3780163953Srrs } 3781163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3782233005Stuexen if (inp == NULL) { 3783169420Srrs SCTP_PRINTF("inp is NULL?\n"); 3784171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3785228907Stuexen return (EINVAL); 3786167598Srrs } 3787168299Srrs vrf_id = inp->def_vrf_id; 3788163953Srrs 3789163953Srrs error = 0; 3790166675Srrs switch (optname) { 3791163953Srrs case SCTP_NODELAY: 3792163953Srrs case SCTP_AUTOCLOSE: 3793163953Srrs case SCTP_AUTO_ASCONF: 3794163953Srrs case SCTP_EXPLICIT_EOR: 3795163953Srrs case SCTP_DISABLE_FRAGMENTS: 3796163953Srrs case SCTP_USE_EXT_RCVINFO: 3797163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 3798163953Srrs /* copy in the option value */ 3799166675Srrs SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); 3800163953Srrs set_opt = 0; 3801163953Srrs if (error) 3802163953Srrs break; 3803166675Srrs switch (optname) { 3804163953Srrs case SCTP_DISABLE_FRAGMENTS: 3805163953Srrs set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT; 3806163953Srrs break; 3807163953Srrs case SCTP_AUTO_ASCONF: 3808171943Srrs /* 3809171943Srrs * NOTE: we don't really support this flag 3810171943Srrs */ 3811171943Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 3812171943Srrs /* only valid for bound all sockets */ 3813224641Stuexen if ((SCTP_BASE_SYSCTL(sctp_auto_asconf) == 0) && 3814224641Stuexen (*mopt != 0)) { 3815224641Stuexen /* forbidden by admin */ 3816224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM); 3817224641Stuexen return (EPERM); 3818224641Stuexen } 3819171943Srrs set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF; 3820171943Srrs } else { 3821171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3822171943Srrs return (EINVAL); 3823171943Srrs } 3824163953Srrs break; 3825163953Srrs case SCTP_EXPLICIT_EOR: 3826163953Srrs set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR; 3827163953Srrs break; 3828163953Srrs case SCTP_USE_EXT_RCVINFO: 3829163953Srrs set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO; 3830163953Srrs break; 3831163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 3832163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 3833163953Srrs set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4; 3834163953Srrs } else { 3835171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3836163953Srrs return (EINVAL); 3837163953Srrs } 3838163953Srrs break; 3839163953Srrs case SCTP_NODELAY: 3840163953Srrs set_opt = SCTP_PCB_FLAGS_NODELAY; 3841163953Srrs break; 3842163953Srrs case SCTP_AUTOCLOSE: 3843170056Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3844170056Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 3845171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3846170056Srrs return (EINVAL); 3847170056Srrs } 3848163953Srrs set_opt = SCTP_PCB_FLAGS_AUTOCLOSE; 3849163953Srrs /* 3850163953Srrs * The value is in ticks. Note this does not effect 3851163953Srrs * old associations, only new ones. 3852163953Srrs */ 3853163953Srrs inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt); 3854163953Srrs break; 3855163953Srrs } 3856163953Srrs SCTP_INP_WLOCK(inp); 3857163953Srrs if (*mopt != 0) { 3858163953Srrs sctp_feature_on(inp, set_opt); 3859163953Srrs } else { 3860163953Srrs sctp_feature_off(inp, set_opt); 3861163953Srrs } 3862163953Srrs SCTP_INP_WUNLOCK(inp); 3863163953Srrs break; 3864181054Srrs case SCTP_REUSE_PORT: 3865181054Srrs { 3866181054Srrs SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); 3867181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) { 3868181054Srrs /* Can't set it after we are bound */ 3869181054Srrs error = EINVAL; 3870181054Srrs break; 3871181054Srrs } 3872181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) { 3873181054Srrs /* Can't do this for a 1-m socket */ 3874181054Srrs error = EINVAL; 3875181054Srrs break; 3876181054Srrs } 3877181054Srrs if (optval) 3878181054Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE); 3879181054Srrs else 3880181054Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE); 3881223132Stuexen break; 3882181054Srrs } 3883163953Srrs case SCTP_PARTIAL_DELIVERY_POINT: 3884163953Srrs { 3885166675Srrs uint32_t *value; 3886166675Srrs 3887166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); 3888167736Srrs if (*value > SCTP_SB_LIMIT_RCV(so)) { 3889171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3890167736Srrs error = EINVAL; 3891167736Srrs break; 3892167736Srrs } 3893166675Srrs inp->partial_delivery_point = *value; 3894223132Stuexen break; 3895163953Srrs } 3896163953Srrs case SCTP_FRAGMENT_INTERLEAVE: 3897163953Srrs /* not yet until we re-write sctp_recvmsg() */ 3898163953Srrs { 3899168943Srrs uint32_t *level; 3900163953Srrs 3901168943Srrs SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize); 3902168943Srrs if (*level == SCTP_FRAG_LEVEL_2) { 3903163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 3904168943Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 3905168943Srrs } else if (*level == SCTP_FRAG_LEVEL_1) { 3906168943Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 3907168943Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 3908168943Srrs } else if (*level == SCTP_FRAG_LEVEL_0) { 3909170056Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 3910168943Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 3911168943Srrs 3912163953Srrs } else { 3913171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3914168943Srrs error = EINVAL; 3915163953Srrs } 3916223132Stuexen break; 3917163953Srrs } 3918163953Srrs case SCTP_CMT_ON_OFF: 3919211944Stuexen if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { 3920163953Srrs struct sctp_assoc_value *av; 3921163953Srrs 3922166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 3923223132Stuexen if (av->assoc_value > SCTP_CMT_MAX) { 3924223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3925223132Stuexen error = EINVAL; 3926223132Stuexen break; 3927223132Stuexen } 3928211944Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3929211944Stuexen if (stcb) { 3930223132Stuexen stcb->asoc.sctp_cmt_on_off = av->assoc_value; 3931211944Stuexen SCTP_TCB_UNLOCK(stcb); 3932166675Srrs } else { 3933224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3934224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3935224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 3936223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3937221460Stuexen SCTP_INP_WLOCK(inp); 3938221460Stuexen inp->sctp_cmt_on_off = av->assoc_value; 3939221460Stuexen SCTP_INP_WUNLOCK(inp); 3940216669Stuexen } 3941223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 3942223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3943223132Stuexen SCTP_INP_RLOCK(inp); 3944223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3945223132Stuexen SCTP_TCB_LOCK(stcb); 3946223132Stuexen stcb->asoc.sctp_cmt_on_off = av->assoc_value; 3947223132Stuexen SCTP_TCB_UNLOCK(stcb); 3948223132Stuexen } 3949224918Stuexen SCTP_INP_RUNLOCK(inp); 3950223132Stuexen } 3951163953Srrs } 3952211944Stuexen } else { 3953211944Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 3954211944Stuexen error = ENOPROTOOPT; 3955163953Srrs } 3956163953Srrs break; 3957171440Srrs case SCTP_PLUGGABLE_CC: 3958171440Srrs { 3959171440Srrs struct sctp_assoc_value *av; 3960219057Srrs struct sctp_nets *net; 3961171440Srrs 3962171440Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 3963223132Stuexen if ((av->assoc_value != SCTP_CC_RFC2581) && 3964223132Stuexen (av->assoc_value != SCTP_CC_HSTCP) && 3965223132Stuexen (av->assoc_value != SCTP_CC_HTCP) && 3966223132Stuexen (av->assoc_value != SCTP_CC_RTCC)) { 3967223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3968223132Stuexen error = EINVAL; 3969223132Stuexen break; 3970223132Stuexen } 3971171440Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3972171440Srrs if (stcb) { 3973223132Stuexen stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value]; 3974223132Stuexen stcb->asoc.congestion_control_module = av->assoc_value; 3975223132Stuexen if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) { 3976223132Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3977223132Stuexen stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); 3978219057Srrs } 3979171440Srrs } 3980217611Stuexen SCTP_TCB_UNLOCK(stcb); 3981171440Srrs } else { 3982224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3983224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3984224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 3985223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3986217611Stuexen SCTP_INP_WLOCK(inp); 3987171440Srrs inp->sctp_ep.sctp_default_cc_module = av->assoc_value; 3988217611Stuexen SCTP_INP_WUNLOCK(inp); 3989217760Stuexen } 3990223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 3991223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3992223132Stuexen SCTP_INP_RLOCK(inp); 3993223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3994223132Stuexen SCTP_TCB_LOCK(stcb); 3995223132Stuexen stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value]; 3996223132Stuexen stcb->asoc.congestion_control_module = av->assoc_value; 3997223132Stuexen if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) { 3998223132Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3999223132Stuexen stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); 4000223132Stuexen } 4001223132Stuexen } 4002223132Stuexen SCTP_TCB_UNLOCK(stcb); 4003223132Stuexen } 4004223132Stuexen SCTP_INP_RUNLOCK(inp); 4005223132Stuexen } 4006171440Srrs } 4007223132Stuexen break; 4008171440Srrs } 4009219057Srrs case SCTP_CC_OPTION: 4010219057Srrs { 4011219057Srrs struct sctp_cc_option *cc_opt; 4012219057Srrs 4013219057Srrs SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, optsize); 4014219057Srrs SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id); 4015219057Srrs if (stcb == NULL) { 4016223132Stuexen if (cc_opt->aid_value.assoc_id == SCTP_CURRENT_ASSOC) { 4017223132Stuexen SCTP_INP_RLOCK(inp); 4018223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4019223132Stuexen SCTP_TCB_LOCK(stcb); 4020223132Stuexen if (stcb->asoc.cc_functions.sctp_cwnd_socket_option) { 4021223132Stuexen (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1, cc_opt); 4022223132Stuexen } 4023223132Stuexen SCTP_TCB_UNLOCK(stcb); 4024223132Stuexen } 4025223132Stuexen SCTP_INP_RUNLOCK(inp); 4026223132Stuexen } else { 4027223132Stuexen error = EINVAL; 4028223132Stuexen } 4029219057Srrs } else { 4030219057Srrs if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) { 4031219057Srrs error = ENOTSUP; 4032219057Srrs } else { 4033219057Srrs error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1, 4034219057Srrs cc_opt); 4035219057Srrs } 4036219057Srrs SCTP_TCB_UNLOCK(stcb); 4037219057Srrs } 4038223132Stuexen break; 4039219057Srrs } 4040217760Stuexen case SCTP_PLUGGABLE_SS: 4041217760Stuexen { 4042217760Stuexen struct sctp_assoc_value *av; 4043217760Stuexen 4044217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 4045223132Stuexen if ((av->assoc_value != SCTP_SS_DEFAULT) && 4046223132Stuexen (av->assoc_value != SCTP_SS_ROUND_ROBIN) && 4047223132Stuexen (av->assoc_value != SCTP_SS_ROUND_ROBIN_PACKET) && 4048223132Stuexen (av->assoc_value != SCTP_SS_PRIORITY) && 4049223132Stuexen (av->assoc_value != SCTP_SS_FAIR_BANDWITH) && 4050223132Stuexen (av->assoc_value != SCTP_SS_FIRST_COME)) { 4051223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4052223132Stuexen error = EINVAL; 4053223132Stuexen break; 4054223132Stuexen } 4055217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4056217760Stuexen if (stcb) { 4057223132Stuexen stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1); 4058223132Stuexen stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value]; 4059223132Stuexen stcb->asoc.stream_scheduling_module = av->assoc_value; 4060223132Stuexen stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1); 4061217760Stuexen SCTP_TCB_UNLOCK(stcb); 4062217760Stuexen } else { 4063224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4064224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4065224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 4066223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 4067217760Stuexen SCTP_INP_WLOCK(inp); 4068217760Stuexen inp->sctp_ep.sctp_default_ss_module = av->assoc_value; 4069217760Stuexen SCTP_INP_WUNLOCK(inp); 4070217760Stuexen } 4071223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 4072223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 4073223132Stuexen SCTP_INP_RLOCK(inp); 4074223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4075223132Stuexen SCTP_TCB_LOCK(stcb); 4076223132Stuexen stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1); 4077223132Stuexen stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value]; 4078223132Stuexen stcb->asoc.stream_scheduling_module = av->assoc_value; 4079223132Stuexen stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1); 4080223132Stuexen SCTP_TCB_UNLOCK(stcb); 4081223132Stuexen } 4082223132Stuexen SCTP_INP_RUNLOCK(inp); 4083223132Stuexen } 4084217760Stuexen } 4085223132Stuexen break; 4086217760Stuexen } 4087217760Stuexen case SCTP_SS_VALUE: 4088217760Stuexen { 4089217760Stuexen struct sctp_stream_value *av; 4090217760Stuexen 4091217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize); 4092217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4093217760Stuexen if (stcb) { 4094277807Sdelphij if ((av->stream_id >= stcb->asoc.streamoutcnt) || 4095277807Sdelphij (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], 4096277807Sdelphij av->stream_value) < 0)) { 4097217760Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4098217760Stuexen error = EINVAL; 4099217760Stuexen } 4100217760Stuexen SCTP_TCB_UNLOCK(stcb); 4101217760Stuexen } else { 4102223132Stuexen if (av->assoc_id == SCTP_CURRENT_ASSOC) { 4103223132Stuexen SCTP_INP_RLOCK(inp); 4104223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4105223132Stuexen SCTP_TCB_LOCK(stcb); 4106277807Sdelphij if (av->stream_id < stcb->asoc.streamoutcnt) { 4107277807Sdelphij stcb->asoc.ss_functions.sctp_ss_set_value(stcb, 4108277807Sdelphij &stcb->asoc, 4109277807Sdelphij &stcb->asoc.strmout[av->stream_id], 4110277807Sdelphij av->stream_value); 4111277807Sdelphij } 4112223132Stuexen SCTP_TCB_UNLOCK(stcb); 4113223132Stuexen } 4114223132Stuexen SCTP_INP_RUNLOCK(inp); 4115223132Stuexen } else { 4116223132Stuexen /* 4117223132Stuexen * Can't set stream value without 4118223132Stuexen * association 4119223132Stuexen */ 4120223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4121223132Stuexen error = EINVAL; 4122223132Stuexen } 4123217760Stuexen } 4124223132Stuexen break; 4125217760Stuexen } 4126163953Srrs case SCTP_CLR_STAT_LOG: 4127171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4128163953Srrs error = EOPNOTSUPP; 4129163953Srrs break; 4130163953Srrs case SCTP_CONTEXT: 4131163953Srrs { 4132163953Srrs struct sctp_assoc_value *av; 4133163953Srrs 4134166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 4135166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4136166675Srrs 4137166675Srrs if (stcb) { 4138166675Srrs stcb->asoc.context = av->assoc_value; 4139166675Srrs SCTP_TCB_UNLOCK(stcb); 4140163953Srrs } else { 4141224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4142224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4143224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 4144223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 4145223132Stuexen SCTP_INP_WLOCK(inp); 4146223132Stuexen inp->sctp_context = av->assoc_value; 4147223132Stuexen SCTP_INP_WUNLOCK(inp); 4148223132Stuexen } 4149223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 4150223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 4151223132Stuexen SCTP_INP_RLOCK(inp); 4152223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4153223132Stuexen SCTP_TCB_LOCK(stcb); 4154223132Stuexen stcb->asoc.context = av->assoc_value; 4155223132Stuexen SCTP_TCB_UNLOCK(stcb); 4156223132Stuexen } 4157223132Stuexen SCTP_INP_RUNLOCK(inp); 4158223132Stuexen } 4159163953Srrs } 4160223132Stuexen break; 4161163953Srrs } 4162167598Srrs case SCTP_VRF_ID: 4163167598Srrs { 4164170056Srrs uint32_t *default_vrfid; 4165167598Srrs 4166170056Srrs SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize); 4167170056Srrs if (*default_vrfid > SCTP_MAX_VRF_ID) { 4168171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4169167598Srrs error = EINVAL; 4170167598Srrs break; 4171167598Srrs } 4172170056Srrs inp->def_vrf_id = *default_vrfid; 4173167598Srrs break; 4174167598Srrs } 4175167598Srrs case SCTP_DEL_VRF_ID: 4176167598Srrs { 4177171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4178167598Srrs error = EOPNOTSUPP; 4179167598Srrs break; 4180167598Srrs } 4181167598Srrs case SCTP_ADD_VRF_ID: 4182167598Srrs { 4183171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4184167598Srrs error = EOPNOTSUPP; 4185167598Srrs break; 4186167598Srrs } 4187170056Srrs case SCTP_DELAYED_SACK: 4188163953Srrs { 4189170056Srrs struct sctp_sack_info *sack; 4190163953Srrs 4191170056Srrs SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize); 4192170056Srrs SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); 4193171477Srrs if (sack->sack_delay) { 4194171477Srrs if (sack->sack_delay > SCTP_MAX_SACK_DELAY) 4195171477Srrs sack->sack_delay = SCTP_MAX_SACK_DELAY; 4196223132Stuexen if (MSEC_TO_TICKS(sack->sack_delay) < 1) { 4197223132Stuexen sack->sack_delay = TICKS_TO_MSEC(1); 4198223132Stuexen } 4199171477Srrs } 4200166675Srrs if (stcb) { 4201170056Srrs if (sack->sack_delay) { 4202170056Srrs stcb->asoc.delayed_ack = sack->sack_delay; 4203170056Srrs } 4204170056Srrs if (sack->sack_freq) { 4205170056Srrs stcb->asoc.sack_freq = sack->sack_freq; 4206170056Srrs } 4207166675Srrs SCTP_TCB_UNLOCK(stcb); 4208166675Srrs } else { 4209224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4210224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4211224918Stuexen (sack->sack_assoc_id == SCTP_FUTURE_ASSOC) || 4212223132Stuexen (sack->sack_assoc_id == SCTP_ALL_ASSOC)) { 4213223132Stuexen SCTP_INP_WLOCK(inp); 4214223132Stuexen if (sack->sack_delay) { 4215223132Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay); 4216170056Srrs } 4217223132Stuexen if (sack->sack_freq) { 4218223132Stuexen inp->sctp_ep.sctp_sack_freq = sack->sack_freq; 4219223132Stuexen } 4220223132Stuexen SCTP_INP_WUNLOCK(inp); 4221170056Srrs } 4222223132Stuexen if ((sack->sack_assoc_id == SCTP_CURRENT_ASSOC) || 4223223132Stuexen (sack->sack_assoc_id == SCTP_ALL_ASSOC)) { 4224223132Stuexen SCTP_INP_RLOCK(inp); 4225223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4226223132Stuexen SCTP_TCB_LOCK(stcb); 4227223132Stuexen if (sack->sack_delay) { 4228223132Stuexen stcb->asoc.delayed_ack = sack->sack_delay; 4229223132Stuexen } 4230223132Stuexen if (sack->sack_freq) { 4231223132Stuexen stcb->asoc.sack_freq = sack->sack_freq; 4232223132Stuexen } 4233223132Stuexen SCTP_TCB_UNLOCK(stcb); 4234223132Stuexen } 4235223132Stuexen SCTP_INP_RUNLOCK(inp); 4236170056Srrs } 4237163953Srrs } 4238166675Srrs break; 4239163953Srrs } 4240163953Srrs case SCTP_AUTH_CHUNK: 4241163953Srrs { 4242163953Srrs struct sctp_authchunk *sauth; 4243163953Srrs 4244166675Srrs SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize); 4245166675Srrs 4246166675Srrs SCTP_INP_WLOCK(inp); 4247171943Srrs if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) { 4248171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4249163953Srrs error = EINVAL; 4250171943Srrs } 4251166675Srrs SCTP_INP_WUNLOCK(inp); 4252163953Srrs break; 4253163953Srrs } 4254163953Srrs case SCTP_AUTH_KEY: 4255163953Srrs { 4256163953Srrs struct sctp_authkey *sca; 4257163953Srrs struct sctp_keyhead *shared_keys; 4258163953Srrs sctp_sharedkey_t *shared_key; 4259163953Srrs sctp_key_t *key = NULL; 4260166675Srrs size_t size; 4261163953Srrs 4262166675Srrs SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize); 4263223697Stuexen if (sca->sca_keylength == 0) { 4264223697Stuexen size = optsize - sizeof(struct sctp_authkey); 4265223697Stuexen } else { 4266223697Stuexen if (sca->sca_keylength + sizeof(struct sctp_authkey) <= optsize) { 4267223697Stuexen size = sca->sca_keylength; 4268223697Stuexen } else { 4269223697Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4270223697Stuexen error = EINVAL; 4271223697Stuexen break; 4272223697Stuexen } 4273223697Stuexen } 4274169420Srrs SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id); 4275166675Srrs 4276166675Srrs if (stcb) { 4277163953Srrs shared_keys = &stcb->asoc.shared_keys; 4278163953Srrs /* clear the cached keys for this key id */ 4279163953Srrs sctp_clear_cachedkeys(stcb, sca->sca_keynumber); 4280163953Srrs /* 4281163953Srrs * create the new shared key and 4282163953Srrs * insert/replace it 4283163953Srrs */ 4284163953Srrs if (size > 0) { 4285163953Srrs key = sctp_set_key(sca->sca_key, (uint32_t) size); 4286163953Srrs if (key == NULL) { 4287171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 4288163953Srrs error = ENOMEM; 4289163953Srrs SCTP_TCB_UNLOCK(stcb); 4290163953Srrs break; 4291163953Srrs } 4292163953Srrs } 4293163953Srrs shared_key = sctp_alloc_sharedkey(); 4294163953Srrs if (shared_key == NULL) { 4295163953Srrs sctp_free_key(key); 4296171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 4297163953Srrs error = ENOMEM; 4298163953Srrs SCTP_TCB_UNLOCK(stcb); 4299163953Srrs break; 4300163953Srrs } 4301163953Srrs shared_key->key = key; 4302163953Srrs shared_key->keyid = sca->sca_keynumber; 4303185694Srrs error = sctp_insert_sharedkey(shared_keys, shared_key); 4304163953Srrs SCTP_TCB_UNLOCK(stcb); 4305163953Srrs } else { 4306224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4307224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4308224918Stuexen (sca->sca_assoc_id == SCTP_FUTURE_ASSOC) || 4309223132Stuexen (sca->sca_assoc_id == SCTP_ALL_ASSOC)) { 4310223132Stuexen SCTP_INP_WLOCK(inp); 4311223132Stuexen shared_keys = &inp->sctp_ep.shared_keys; 4312223132Stuexen /* 4313223132Stuexen * clear the cached keys on all 4314223132Stuexen * assocs for this key id 4315223132Stuexen */ 4316223132Stuexen sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber); 4317223132Stuexen /* 4318223132Stuexen * create the new shared key and 4319223132Stuexen * insert/replace it 4320223132Stuexen */ 4321223132Stuexen if (size > 0) { 4322223132Stuexen key = sctp_set_key(sca->sca_key, (uint32_t) size); 4323223132Stuexen if (key == NULL) { 4324223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 4325223132Stuexen error = ENOMEM; 4326223132Stuexen SCTP_INP_WUNLOCK(inp); 4327223132Stuexen break; 4328223132Stuexen } 4329223132Stuexen } 4330223132Stuexen shared_key = sctp_alloc_sharedkey(); 4331223132Stuexen if (shared_key == NULL) { 4332223132Stuexen sctp_free_key(key); 4333171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 4334163953Srrs error = ENOMEM; 4335163953Srrs SCTP_INP_WUNLOCK(inp); 4336163953Srrs break; 4337163953Srrs } 4338223132Stuexen shared_key->key = key; 4339223132Stuexen shared_key->keyid = sca->sca_keynumber; 4340223132Stuexen error = sctp_insert_sharedkey(shared_keys, shared_key); 4341163953Srrs SCTP_INP_WUNLOCK(inp); 4342163953Srrs } 4343223132Stuexen if ((sca->sca_assoc_id == SCTP_CURRENT_ASSOC) || 4344223132Stuexen (sca->sca_assoc_id == SCTP_ALL_ASSOC)) { 4345223132Stuexen SCTP_INP_RLOCK(inp); 4346223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4347223132Stuexen SCTP_TCB_LOCK(stcb); 4348223132Stuexen shared_keys = &stcb->asoc.shared_keys; 4349223132Stuexen /* 4350223132Stuexen * clear the cached keys for 4351223132Stuexen * this key id 4352223132Stuexen */ 4353223132Stuexen sctp_clear_cachedkeys(stcb, sca->sca_keynumber); 4354223132Stuexen /* 4355223132Stuexen * create the new shared key 4356223132Stuexen * and insert/replace it 4357223132Stuexen */ 4358223132Stuexen if (size > 0) { 4359223132Stuexen key = sctp_set_key(sca->sca_key, (uint32_t) size); 4360223132Stuexen if (key == NULL) { 4361223132Stuexen SCTP_TCB_UNLOCK(stcb); 4362223132Stuexen continue; 4363223132Stuexen } 4364223132Stuexen } 4365223132Stuexen shared_key = sctp_alloc_sharedkey(); 4366223132Stuexen if (shared_key == NULL) { 4367223132Stuexen sctp_free_key(key); 4368223132Stuexen SCTP_TCB_UNLOCK(stcb); 4369223132Stuexen continue; 4370223132Stuexen } 4371223132Stuexen shared_key->key = key; 4372223132Stuexen shared_key->keyid = sca->sca_keynumber; 4373223132Stuexen error = sctp_insert_sharedkey(shared_keys, shared_key); 4374223132Stuexen SCTP_TCB_UNLOCK(stcb); 4375223132Stuexen } 4376223132Stuexen SCTP_INP_RUNLOCK(inp); 4377223132Stuexen } 4378163953Srrs } 4379163953Srrs break; 4380163953Srrs } 4381163953Srrs case SCTP_HMAC_IDENT: 4382163953Srrs { 4383163953Srrs struct sctp_hmacalgo *shmac; 4384163953Srrs sctp_hmaclist_t *hmaclist; 4385181054Srrs uint16_t hmacid; 4386181054Srrs uint32_t i; 4387181054Srrs 4388166675Srrs SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize); 4389271750Stuexen if ((optsize < sizeof(struct sctp_hmacalgo) + shmac->shmac_number_of_idents * sizeof(uint16_t)) || 4390271750Stuexen (shmac->shmac_number_of_idents > 0xffff)) { 4391181054Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4392181054Srrs error = EINVAL; 4393181054Srrs break; 4394181054Srrs } 4395271750Stuexen hmaclist = sctp_alloc_hmaclist((uint16_t) shmac->shmac_number_of_idents); 4396163953Srrs if (hmaclist == NULL) { 4397171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 4398163953Srrs error = ENOMEM; 4399163953Srrs break; 4400163953Srrs } 4401181054Srrs for (i = 0; i < shmac->shmac_number_of_idents; i++) { 4402163953Srrs hmacid = shmac->shmac_idents[i]; 4403181054Srrs if (sctp_auth_add_hmacid(hmaclist, hmacid)) { 4404163953Srrs /* invalid HMACs were found */ ; 4405171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4406163953Srrs error = EINVAL; 4407164085Srrs sctp_free_hmaclist(hmaclist); 4408163953Srrs goto sctp_set_hmac_done; 4409163953Srrs } 4410163953Srrs } 4411170056Srrs for (i = 0; i < hmaclist->num_algo; i++) { 4412170056Srrs if (hmaclist->hmac[i] == SCTP_AUTH_HMAC_ID_SHA1) { 4413170056Srrs /* already in list */ 4414253858Stuexen break; 4415170056Srrs } 4416170056Srrs } 4417253858Stuexen if (i == hmaclist->num_algo) { 4418253858Stuexen /* not found in list */ 4419170056Srrs sctp_free_hmaclist(hmaclist); 4420171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4421170056Srrs error = EINVAL; 4422170056Srrs break; 4423170056Srrs } 4424163953Srrs /* set it on the endpoint */ 4425163953Srrs SCTP_INP_WLOCK(inp); 4426163953Srrs if (inp->sctp_ep.local_hmacs) 4427163953Srrs sctp_free_hmaclist(inp->sctp_ep.local_hmacs); 4428163953Srrs inp->sctp_ep.local_hmacs = hmaclist; 4429163953Srrs SCTP_INP_WUNLOCK(inp); 4430163953Srrs sctp_set_hmac_done: 4431163953Srrs break; 4432163953Srrs } 4433163953Srrs case SCTP_AUTH_ACTIVE_KEY: 4434163953Srrs { 4435163953Srrs struct sctp_authkeyid *scact; 4436163953Srrs 4437223132Stuexen SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize); 4438166675Srrs SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); 4439166675Srrs 4440163953Srrs /* set the active key on the right place */ 4441166675Srrs if (stcb) { 4442163953Srrs /* set the active key on the assoc */ 4443185694Srrs if (sctp_auth_setactivekey(stcb, 4444185694Srrs scact->scact_keynumber)) { 4445185694Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, 4446185694Srrs SCTP_FROM_SCTP_USRREQ, 4447185694Srrs EINVAL); 4448163953Srrs error = EINVAL; 4449171943Srrs } 4450163953Srrs SCTP_TCB_UNLOCK(stcb); 4451163953Srrs } else { 4452224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4453224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4454224918Stuexen (scact->scact_assoc_id == SCTP_FUTURE_ASSOC) || 4455223132Stuexen (scact->scact_assoc_id == SCTP_ALL_ASSOC)) { 4456223132Stuexen SCTP_INP_WLOCK(inp); 4457223132Stuexen if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) { 4458223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4459223132Stuexen error = EINVAL; 4460223132Stuexen } 4461223132Stuexen SCTP_INP_WUNLOCK(inp); 4462171943Srrs } 4463223132Stuexen if ((scact->scact_assoc_id == SCTP_CURRENT_ASSOC) || 4464223132Stuexen (scact->scact_assoc_id == SCTP_ALL_ASSOC)) { 4465223132Stuexen SCTP_INP_RLOCK(inp); 4466223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4467223132Stuexen SCTP_TCB_LOCK(stcb); 4468223132Stuexen sctp_auth_setactivekey(stcb, scact->scact_keynumber); 4469223132Stuexen SCTP_TCB_UNLOCK(stcb); 4470223132Stuexen } 4471223132Stuexen SCTP_INP_RUNLOCK(inp); 4472223132Stuexen } 4473163953Srrs } 4474163953Srrs break; 4475163953Srrs } 4476163953Srrs case SCTP_AUTH_DELETE_KEY: 4477163953Srrs { 4478163953Srrs struct sctp_authkeyid *scdel; 4479163953Srrs 4480223132Stuexen SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize); 4481166675Srrs SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id); 4482166675Srrs 4483163953Srrs /* delete the key from the right place */ 4484166675Srrs if (stcb) { 4485223132Stuexen if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) { 4486223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4487163953Srrs error = EINVAL; 4488171943Srrs } 4489163953Srrs SCTP_TCB_UNLOCK(stcb); 4490163953Srrs } else { 4491224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4492224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4493224918Stuexen (scdel->scact_assoc_id == SCTP_FUTURE_ASSOC) || 4494223132Stuexen (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) { 4495223132Stuexen SCTP_INP_WLOCK(inp); 4496223132Stuexen if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) { 4497223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4498223132Stuexen error = EINVAL; 4499223132Stuexen } 4500223132Stuexen SCTP_INP_WUNLOCK(inp); 4501171943Srrs } 4502223132Stuexen if ((scdel->scact_assoc_id == SCTP_CURRENT_ASSOC) || 4503223132Stuexen (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) { 4504223132Stuexen SCTP_INP_RLOCK(inp); 4505223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4506223132Stuexen SCTP_TCB_LOCK(stcb); 4507223132Stuexen sctp_delete_sharedkey(stcb, scdel->scact_keynumber); 4508223132Stuexen SCTP_TCB_UNLOCK(stcb); 4509223132Stuexen } 4510223132Stuexen SCTP_INP_RUNLOCK(inp); 4511223132Stuexen } 4512163953Srrs } 4513163953Srrs break; 4514163953Srrs } 4515185694Srrs case SCTP_AUTH_DEACTIVATE_KEY: 4516185694Srrs { 4517185694Srrs struct sctp_authkeyid *keyid; 4518163953Srrs 4519223132Stuexen SCTP_CHECK_AND_CAST(keyid, optval, struct sctp_authkeyid, optsize); 4520185694Srrs SCTP_FIND_STCB(inp, stcb, keyid->scact_assoc_id); 4521185694Srrs 4522185694Srrs /* deactivate the key from the right place */ 4523185694Srrs if (stcb) { 4524223132Stuexen if (sctp_deact_sharedkey(stcb, keyid->scact_keynumber)) { 4525223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4526185694Srrs error = EINVAL; 4527185694Srrs } 4528185694Srrs SCTP_TCB_UNLOCK(stcb); 4529185694Srrs } else { 4530224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4531224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4532224918Stuexen (keyid->scact_assoc_id == SCTP_FUTURE_ASSOC) || 4533223132Stuexen (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) { 4534223132Stuexen SCTP_INP_WLOCK(inp); 4535223132Stuexen if (sctp_deact_sharedkey_ep(inp, keyid->scact_keynumber)) { 4536223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4537223132Stuexen error = EINVAL; 4538223132Stuexen } 4539223132Stuexen SCTP_INP_WUNLOCK(inp); 4540185694Srrs } 4541223132Stuexen if ((keyid->scact_assoc_id == SCTP_CURRENT_ASSOC) || 4542223132Stuexen (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) { 4543223132Stuexen SCTP_INP_RLOCK(inp); 4544223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4545223132Stuexen SCTP_TCB_LOCK(stcb); 4546223132Stuexen sctp_deact_sharedkey(stcb, keyid->scact_keynumber); 4547223132Stuexen SCTP_TCB_UNLOCK(stcb); 4548223132Stuexen } 4549223132Stuexen SCTP_INP_RUNLOCK(inp); 4550223132Stuexen } 4551185694Srrs } 4552185694Srrs break; 4553185694Srrs } 4554233660Srrs case SCTP_ENABLE_STREAM_RESET: 4555233660Srrs { 4556233660Srrs struct sctp_assoc_value *av; 4557185694Srrs 4558233660Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 4559233660Srrs if (av->assoc_value & (~SCTP_ENABLE_VALUE_MASK)) { 4560233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4561233660Srrs error = EINVAL; 4562233660Srrs break; 4563233660Srrs } 4564233660Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4565233660Srrs if (stcb) { 4566235021Stuexen stcb->asoc.local_strreset_support = (uint8_t) av->assoc_value; 4567233660Srrs SCTP_TCB_UNLOCK(stcb); 4568233660Srrs } else { 4569233660Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4570233660Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4571233660Srrs (av->assoc_id == SCTP_FUTURE_ASSOC) || 4572233660Srrs (av->assoc_id == SCTP_ALL_ASSOC)) { 4573233660Srrs SCTP_INP_WLOCK(inp); 4574235021Stuexen inp->local_strreset_support = (uint8_t) av->assoc_value; 4575233660Srrs SCTP_INP_WUNLOCK(inp); 4576233660Srrs } 4577233660Srrs if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 4578233660Srrs (av->assoc_id == SCTP_ALL_ASSOC)) { 4579233660Srrs SCTP_INP_RLOCK(inp); 4580233660Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4581233660Srrs SCTP_TCB_LOCK(stcb); 4582235021Stuexen stcb->asoc.local_strreset_support = (uint8_t) av->assoc_value; 4583233660Srrs SCTP_TCB_UNLOCK(stcb); 4584233660Srrs } 4585233660Srrs SCTP_INP_RUNLOCK(inp); 4586233660Srrs } 4587233660Srrs } 4588233660Srrs break; 4589233660Srrs } 4590163953Srrs case SCTP_RESET_STREAMS: 4591163953Srrs { 4592233660Srrs struct sctp_reset_streams *strrst; 4593233660Srrs int i, send_out = 0; 4594233660Srrs int send_in = 0; 4595163953Srrs 4596233660Srrs SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_reset_streams, optsize); 4597233660Srrs SCTP_FIND_STCB(inp, stcb, strrst->srs_assoc_id); 4598163953Srrs if (stcb == NULL) { 4599171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4600163953Srrs error = ENOENT; 4601163953Srrs break; 4602163953Srrs } 4603270361Stuexen if (stcb->asoc.reconfig_supported == 0) { 4604163953Srrs /* 4605233660Srrs * Peer does not support the chunk type. 4606163953Srrs */ 4607233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4608233660Srrs error = EOPNOTSUPP; 4609163953Srrs SCTP_TCB_UNLOCK(stcb); 4610163953Srrs break; 4611163953Srrs } 4612273000Stuexen if (sizeof(struct sctp_reset_streams) + 4613273000Stuexen strrst->srs_number_streams * sizeof(uint16_t) > optsize) { 4614273000Stuexen error = EINVAL; 4615273000Stuexen SCTP_TCB_UNLOCK(stcb); 4616273000Stuexen break; 4617273000Stuexen } 4618233660Srrs if (strrst->srs_flags & SCTP_STREAM_RESET_INCOMING) { 4619163953Srrs send_in = 1; 4620294140Stuexen if (stcb->asoc.stream_reset_outstanding) { 4621294140Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4622294140Stuexen error = EALREADY; 4623294140Stuexen SCTP_TCB_UNLOCK(stcb); 4624294140Stuexen break; 4625294140Stuexen } 4626233660Srrs } 4627233660Srrs if (strrst->srs_flags & SCTP_STREAM_RESET_OUTGOING) { 4628163953Srrs send_out = 1; 4629233660Srrs } 4630294140Stuexen if ((strrst->srs_number_streams > SCTP_MAX_STREAMS_AT_ONCE_RESET) && send_in) { 4631294140Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 4632294140Stuexen error = ENOMEM; 4633294140Stuexen SCTP_TCB_UNLOCK(stcb); 4634294140Stuexen break; 4635294140Stuexen } 4636233660Srrs if ((send_in == 0) && (send_out == 0)) { 4637233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4638233660Srrs error = EINVAL; 4639233660Srrs SCTP_TCB_UNLOCK(stcb); 4640233660Srrs break; 4641233660Srrs } 4642233660Srrs for (i = 0; i < strrst->srs_number_streams; i++) { 4643233660Srrs if ((send_in) && 4644233660Srrs (strrst->srs_stream_list[i] > stcb->asoc.streamincnt)) { 4645233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4646188854Srrs error = EINVAL; 4647233660Srrs break; 4648188854Srrs } 4649233660Srrs if ((send_out) && 4650233660Srrs (strrst->srs_stream_list[i] > stcb->asoc.streamoutcnt)) { 4651233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4652233660Srrs error = EINVAL; 4653233660Srrs break; 4654188854Srrs } 4655233660Srrs } 4656233660Srrs if (error) { 4657233660Srrs SCTP_TCB_UNLOCK(stcb); 4658233660Srrs break; 4659233660Srrs } 4660294140Stuexen if (send_out) { 4661294140Stuexen int cnt; 4662294140Stuexen uint16_t strm; 4663233660Srrs 4664294140Stuexen if (strrst->srs_number_streams) { 4665294140Stuexen for (i = 0, cnt = 0; i < strrst->srs_number_streams; i++) { 4666294140Stuexen strm = strrst->srs_stream_list[i]; 4667294140Stuexen if (stcb->asoc.strmout[strm].state == SCTP_STREAM_OPEN) { 4668294140Stuexen stcb->asoc.strmout[strm].state = SCTP_STREAM_RESET_PENDING; 4669294140Stuexen cnt++; 4670294140Stuexen } 4671294140Stuexen } 4672294140Stuexen } else { 4673294140Stuexen /* Its all */ 4674294140Stuexen for (i = 0, cnt = 0; i < stcb->asoc.streamoutcnt; i++) { 4675294140Stuexen if (stcb->asoc.strmout[i].state == SCTP_STREAM_OPEN) { 4676294140Stuexen stcb->asoc.strmout[i].state = SCTP_STREAM_RESET_PENDING; 4677294140Stuexen cnt++; 4678294140Stuexen } 4679294140Stuexen } 4680294140Stuexen } 4681294140Stuexen } 4682294140Stuexen if (send_in) { 4683294140Stuexen error = sctp_send_str_reset_req(stcb, strrst->srs_number_streams, 4684294140Stuexen strrst->srs_stream_list, 4685294140Stuexen send_in, 0, 0, 0, 0, 0); 4686294140Stuexen } else 4687294141Stuexen error = sctp_send_stream_reset_out_if_possible(stcb, SCTP_SO_LOCKED); 4688294140Stuexen if (!error) 4689294140Stuexen sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); 4690294140Stuexen 4691233660Srrs SCTP_TCB_UNLOCK(stcb); 4692233660Srrs break; 4693233660Srrs } 4694233660Srrs case SCTP_ADD_STREAMS: 4695233660Srrs { 4696233660Srrs struct sctp_add_streams *stradd; 4697233660Srrs uint8_t addstream = 0; 4698233660Srrs uint16_t add_o_strmcnt = 0; 4699233660Srrs uint16_t add_i_strmcnt = 0; 4700233660Srrs 4701233660Srrs SCTP_CHECK_AND_CAST(stradd, optval, struct sctp_add_streams, optsize); 4702233660Srrs SCTP_FIND_STCB(inp, stcb, stradd->sas_assoc_id); 4703233660Srrs if (stcb == NULL) { 4704233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4705233660Srrs error = ENOENT; 4706233660Srrs break; 4707233660Srrs } 4708270361Stuexen if (stcb->asoc.reconfig_supported == 0) { 4709235057Stuexen /* 4710235057Stuexen * Peer does not support the chunk type. 4711235057Stuexen */ 4712235057Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4713235057Stuexen error = EOPNOTSUPP; 4714235057Stuexen SCTP_TCB_UNLOCK(stcb); 4715235057Stuexen break; 4716235057Stuexen } 4717235057Stuexen if (stcb->asoc.stream_reset_outstanding) { 4718235057Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4719235057Stuexen error = EALREADY; 4720235057Stuexen SCTP_TCB_UNLOCK(stcb); 4721235057Stuexen break; 4722235057Stuexen } 4723233660Srrs if ((stradd->sas_outstrms == 0) && 4724233660Srrs (stradd->sas_instrms == 0)) { 4725233660Srrs error = EINVAL; 4726233660Srrs goto skip_stuff; 4727233660Srrs } 4728233660Srrs if (stradd->sas_outstrms) { 4729188854Srrs addstream = 1; 4730188854Srrs /* We allocate here */ 4731233660Srrs add_o_strmcnt = stradd->sas_outstrms; 4732233660Srrs if ((((int)add_o_strmcnt) + ((int)stcb->asoc.streamoutcnt)) > 0x0000ffff) { 4733188854Srrs /* You can't have more than 64k */ 4734188854Srrs error = EINVAL; 4735188854Srrs goto skip_stuff; 4736188854Srrs } 4737163953Srrs } 4738233660Srrs if (stradd->sas_instrms) { 4739233660Srrs int cnt; 4740163953Srrs 4741233660Srrs addstream |= 2; 4742233660Srrs /* 4743233660Srrs * We allocate inside 4744233660Srrs * sctp_send_str_reset_req() 4745233660Srrs */ 4746233660Srrs add_i_strmcnt = stradd->sas_instrms; 4747233660Srrs cnt = add_i_strmcnt; 4748233660Srrs cnt += stcb->asoc.streamincnt; 4749233660Srrs if (cnt > 0x0000ffff) { 4750233660Srrs /* You can't have more than 64k */ 4751163953Srrs error = EINVAL; 4752233660Srrs goto skip_stuff; 4753163953Srrs } 4754233660Srrs if (cnt > (int)stcb->asoc.max_inbound_streams) { 4755233660Srrs /* More than you are allowed */ 4756163953Srrs error = EINVAL; 4757233660Srrs goto skip_stuff; 4758163953Srrs } 4759163953Srrs } 4760294140Stuexen error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, addstream, add_o_strmcnt, add_i_strmcnt, 0); 4761233660Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); 4762188854Srrs skip_stuff: 4763233660Srrs SCTP_TCB_UNLOCK(stcb); 4764233660Srrs break; 4765233660Srrs } 4766233660Srrs case SCTP_RESET_ASSOC: 4767233660Srrs { 4768294140Stuexen int i; 4769233660Srrs uint32_t *value; 4770233660Srrs 4771233660Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); 4772233660Srrs SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value); 4773233660Srrs if (stcb == NULL) { 4774233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4775233660Srrs error = ENOENT; 4776233660Srrs break; 4777233660Srrs } 4778270361Stuexen if (stcb->asoc.reconfig_supported == 0) { 4779233660Srrs /* 4780233660Srrs * Peer does not support the chunk type. 4781233660Srrs */ 4782233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4783233660Srrs error = EOPNOTSUPP; 4784163953Srrs SCTP_TCB_UNLOCK(stcb); 4785163953Srrs break; 4786163953Srrs } 4787233660Srrs if (stcb->asoc.stream_reset_outstanding) { 4788233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4789233660Srrs error = EALREADY; 4790233660Srrs SCTP_TCB_UNLOCK(stcb); 4791233660Srrs break; 4792233660Srrs } 4793294140Stuexen /* 4794294140Stuexen * Is there any data pending in the send or sent 4795294140Stuexen * queues? 4796294140Stuexen */ 4797294140Stuexen if (!TAILQ_EMPTY(&stcb->asoc.send_queue) || 4798294140Stuexen !TAILQ_EMPTY(&stcb->asoc.sent_queue)) { 4799294140Stuexen busy_out: 4800294140Stuexen error = EBUSY; 4801294140Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 4802294140Stuexen SCTP_TCB_UNLOCK(stcb); 4803294140Stuexen break; 4804294140Stuexen } 4805294140Stuexen /* Do any streams have data queued? */ 4806294140Stuexen for (i = 0; i < stcb->asoc.streamoutcnt; i++) { 4807294140Stuexen if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { 4808294140Stuexen goto busy_out; 4809294140Stuexen } 4810294140Stuexen } 4811294140Stuexen error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 1, 0, 0, 0, 0); 4812172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); 4813163953Srrs SCTP_TCB_UNLOCK(stcb); 4814223132Stuexen break; 4815163953Srrs } 4816163953Srrs case SCTP_CONNECT_X: 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, 0); 4823163953Srrs break; 4824163953Srrs case SCTP_CONNECT_X_DELAYED: 4825166675Srrs if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { 4826171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4827163953Srrs error = EINVAL; 4828163953Srrs break; 4829163953Srrs } 4830166675Srrs error = sctp_do_connect_x(so, inp, optval, optsize, p, 1); 4831163953Srrs break; 4832163953Srrs case SCTP_CONNECT_X_COMPLETE: 4833163953Srrs { 4834163953Srrs struct sockaddr *sa; 4835163953Srrs 4836166675Srrs /* FIXME MT: check correct? */ 4837166675Srrs SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize); 4838166675Srrs 4839163953Srrs /* find tcb */ 4840163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 4841163953Srrs SCTP_INP_RLOCK(inp); 4842163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 4843163953Srrs if (stcb) { 4844163953Srrs SCTP_TCB_LOCK(stcb); 4845163953Srrs } 4846163953Srrs SCTP_INP_RUNLOCK(inp); 4847163953Srrs } else { 4848166675Srrs /* 4849166675Srrs * We increment here since 4850166675Srrs * sctp_findassociation_ep_addr() wil do a 4851166675Srrs * decrement if it finds the stcb as long as 4852166675Srrs * the locked tcb (last argument) is NOT a 4853166675Srrs * TCB.. aka NULL. 4854166675Srrs */ 4855163953Srrs SCTP_INP_INCR_REF(inp); 4856283716Stuexen stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL); 4857163953Srrs if (stcb == NULL) { 4858163953Srrs SCTP_INP_DECR_REF(inp); 4859163953Srrs } 4860163953Srrs } 4861163953Srrs 4862163953Srrs if (stcb == NULL) { 4863171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4864163953Srrs error = ENOENT; 4865163953Srrs break; 4866163953Srrs } 4867163953Srrs if (stcb->asoc.delayed_connection == 1) { 4868163953Srrs stcb->asoc.delayed_connection = 0; 4869169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 4870165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, 4871165220Srrs stcb->asoc.primary_destination, 4872283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8); 4873172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 4874163953Srrs } else { 4875163953Srrs /* 4876163953Srrs * already expired or did not use delayed 4877163953Srrs * connectx 4878163953Srrs */ 4879171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4880163953Srrs error = EALREADY; 4881163953Srrs } 4882163953Srrs SCTP_TCB_UNLOCK(stcb); 4883223132Stuexen break; 4884163953Srrs } 4885170056Srrs case SCTP_MAX_BURST: 4886163953Srrs { 4887217895Stuexen struct sctp_assoc_value *av; 4888163953Srrs 4889217895Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 4890217895Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4891166675Srrs 4892217895Stuexen if (stcb) { 4893217895Stuexen stcb->asoc.max_burst = av->assoc_value; 4894217895Stuexen SCTP_TCB_UNLOCK(stcb); 4895217895Stuexen } else { 4896224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4897224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4898224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 4899223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 4900223132Stuexen SCTP_INP_WLOCK(inp); 4901223132Stuexen inp->sctp_ep.max_burst = av->assoc_value; 4902223132Stuexen SCTP_INP_WUNLOCK(inp); 4903223132Stuexen } 4904223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 4905223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 4906223132Stuexen SCTP_INP_RLOCK(inp); 4907223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4908223132Stuexen SCTP_TCB_LOCK(stcb); 4909223132Stuexen stcb->asoc.max_burst = av->assoc_value; 4910223132Stuexen SCTP_TCB_UNLOCK(stcb); 4911223132Stuexen } 4912223132Stuexen SCTP_INP_RUNLOCK(inp); 4913223132Stuexen } 4914217895Stuexen } 4915223132Stuexen break; 4916163953Srrs } 4917163953Srrs case SCTP_MAXSEG: 4918163953Srrs { 4919167598Srrs struct sctp_assoc_value *av; 4920163953Srrs int ovh; 4921163953Srrs 4922167598Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 4923167598Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4924166675Srrs 4925170056Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 4926170056Srrs ovh = SCTP_MED_OVERHEAD; 4927170056Srrs } else { 4928170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 4929170056Srrs } 4930167598Srrs if (stcb) { 4931170056Srrs if (av->assoc_value) { 4932170056Srrs stcb->asoc.sctp_frag_point = (av->assoc_value + ovh); 4933170056Srrs } else { 4934170056Srrs stcb->asoc.sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; 4935170056Srrs } 4936167598Srrs SCTP_TCB_UNLOCK(stcb); 4937163953Srrs } else { 4938224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4939224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4940224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 4941223132Stuexen SCTP_INP_WLOCK(inp); 4942223132Stuexen /* 4943223132Stuexen * FIXME MT: I think this is not in 4944223132Stuexen * tune with the API ID 4945223132Stuexen */ 4946223132Stuexen if (av->assoc_value) { 4947223132Stuexen inp->sctp_frag_point = (av->assoc_value + ovh); 4948223132Stuexen } else { 4949223132Stuexen inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; 4950223132Stuexen } 4951223132Stuexen SCTP_INP_WUNLOCK(inp); 4952167598Srrs } else { 4953223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4954223132Stuexen error = EINVAL; 4955167598Srrs } 4956163953Srrs } 4957223132Stuexen break; 4958163953Srrs } 4959163953Srrs case SCTP_EVENTS: 4960163953Srrs { 4961163953Srrs struct sctp_event_subscribe *events; 4962163953Srrs 4963166675Srrs SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize); 4964166675Srrs 4965163953Srrs SCTP_INP_WLOCK(inp); 4966163953Srrs if (events->sctp_data_io_event) { 4967163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); 4968163953Srrs } else { 4969163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); 4970163953Srrs } 4971163953Srrs 4972163953Srrs if (events->sctp_association_event) { 4973163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); 4974163953Srrs } else { 4975163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); 4976163953Srrs } 4977163953Srrs 4978163953Srrs if (events->sctp_address_event) { 4979163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); 4980163953Srrs } else { 4981163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); 4982163953Srrs } 4983163953Srrs 4984163953Srrs if (events->sctp_send_failure_event) { 4985163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 4986163953Srrs } else { 4987163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 4988163953Srrs } 4989163953Srrs 4990163953Srrs if (events->sctp_peer_error_event) { 4991163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR); 4992163953Srrs } else { 4993163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR); 4994163953Srrs } 4995163953Srrs 4996163953Srrs if (events->sctp_shutdown_event) { 4997163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 4998163953Srrs } else { 4999163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 5000163953Srrs } 5001163953Srrs 5002163953Srrs if (events->sctp_partial_delivery_event) { 5003163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT); 5004163953Srrs } else { 5005163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT); 5006163953Srrs } 5007163953Srrs 5008163953Srrs if (events->sctp_adaptation_layer_event) { 5009163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 5010163953Srrs } else { 5011163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 5012163953Srrs } 5013163953Srrs 5014163953Srrs if (events->sctp_authentication_event) { 5015163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT); 5016163953Srrs } else { 5017163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT); 5018163953Srrs } 5019163953Srrs 5020185694Srrs if (events->sctp_sender_dry_event) { 5021185694Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT); 5022185694Srrs } else { 5023185694Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT); 5024185694Srrs } 5025185694Srrs 5026202520Srrs if (events->sctp_stream_reset_event) { 5027163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 5028163953Srrs } else { 5029163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 5030163953Srrs } 5031163953Srrs SCTP_INP_WUNLOCK(inp); 5032223132Stuexen 5033223132Stuexen SCTP_INP_RLOCK(inp); 5034223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 5035223132Stuexen SCTP_TCB_LOCK(stcb); 5036223132Stuexen if (events->sctp_association_event) { 5037223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT); 5038223132Stuexen } else { 5039223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT); 5040223132Stuexen } 5041223132Stuexen if (events->sctp_address_event) { 5042223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT); 5043223132Stuexen } else { 5044223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT); 5045223132Stuexen } 5046223132Stuexen if (events->sctp_send_failure_event) { 5047223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 5048223132Stuexen } else { 5049223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 5050223132Stuexen } 5051223132Stuexen if (events->sctp_peer_error_event) { 5052223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR); 5053223132Stuexen } else { 5054223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR); 5055223132Stuexen } 5056223132Stuexen if (events->sctp_shutdown_event) { 5057223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 5058223132Stuexen } else { 5059223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 5060223132Stuexen } 5061223132Stuexen if (events->sctp_partial_delivery_event) { 5062223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT); 5063223132Stuexen } else { 5064223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT); 5065223132Stuexen } 5066223132Stuexen if (events->sctp_adaptation_layer_event) { 5067223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 5068223132Stuexen } else { 5069223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 5070223132Stuexen } 5071223132Stuexen if (events->sctp_authentication_event) { 5072223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT); 5073223132Stuexen } else { 5074223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT); 5075223132Stuexen } 5076223132Stuexen if (events->sctp_sender_dry_event) { 5077223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT); 5078223132Stuexen } else { 5079223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT); 5080223132Stuexen } 5081223132Stuexen if (events->sctp_stream_reset_event) { 5082223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 5083223132Stuexen } else { 5084223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 5085223132Stuexen } 5086223132Stuexen SCTP_TCB_UNLOCK(stcb); 5087223132Stuexen } 5088223132Stuexen /* 5089223132Stuexen * Send up the sender dry event only for 1-to-1 5090223132Stuexen * style sockets. 5091223132Stuexen */ 5092223132Stuexen if (events->sctp_sender_dry_event) { 5093223132Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5094223132Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 5095223132Stuexen stcb = LIST_FIRST(&inp->sctp_asoc_list); 5096223132Stuexen if (stcb) { 5097223132Stuexen SCTP_TCB_LOCK(stcb); 5098223132Stuexen if (TAILQ_EMPTY(&stcb->asoc.send_queue) && 5099223132Stuexen TAILQ_EMPTY(&stcb->asoc.sent_queue) && 5100223132Stuexen (stcb->asoc.stream_queue_cnt == 0)) { 5101223132Stuexen sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED); 5102223132Stuexen } 5103223132Stuexen SCTP_TCB_UNLOCK(stcb); 5104223132Stuexen } 5105223132Stuexen } 5106223132Stuexen } 5107223132Stuexen SCTP_INP_RUNLOCK(inp); 5108223132Stuexen break; 5109163953Srrs } 5110163953Srrs case SCTP_ADAPTATION_LAYER: 5111163953Srrs { 5112163953Srrs struct sctp_setadaptation *adap_bits; 5113163953Srrs 5114166675Srrs SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize); 5115163953Srrs SCTP_INP_WLOCK(inp); 5116163953Srrs inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind; 5117246687Stuexen inp->sctp_ep.adaptation_layer_indicator_provided = 1; 5118163953Srrs SCTP_INP_WUNLOCK(inp); 5119223132Stuexen break; 5120163953Srrs } 5121166675Srrs#ifdef SCTP_DEBUG 5122163953Srrs case SCTP_SET_INITIAL_DBG_SEQ: 5123163953Srrs { 5124163953Srrs uint32_t *vvv; 5125163953Srrs 5126166675Srrs SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize); 5127163953Srrs SCTP_INP_WLOCK(inp); 5128163953Srrs inp->sctp_ep.initial_sequence_debug = *vvv; 5129163953Srrs SCTP_INP_WUNLOCK(inp); 5130223132Stuexen break; 5131163953Srrs } 5132166675Srrs#endif 5133163953Srrs case SCTP_DEFAULT_SEND_PARAM: 5134163953Srrs { 5135163953Srrs struct sctp_sndrcvinfo *s_info; 5136163953Srrs 5137166675Srrs SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize); 5138166675Srrs SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); 5139163953Srrs 5140166675Srrs if (stcb) { 5141223132Stuexen if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) { 5142170056Srrs memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send))); 5143163953Srrs } else { 5144171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5145166675Srrs error = EINVAL; 5146163953Srrs } 5147166675Srrs SCTP_TCB_UNLOCK(stcb); 5148166675Srrs } else { 5149224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5150224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5151224918Stuexen (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) || 5152223132Stuexen (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) { 5153223132Stuexen SCTP_INP_WLOCK(inp); 5154223132Stuexen memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send))); 5155223132Stuexen SCTP_INP_WUNLOCK(inp); 5156223132Stuexen } 5157223132Stuexen if ((s_info->sinfo_assoc_id == SCTP_CURRENT_ASSOC) || 5158223132Stuexen (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) { 5159223132Stuexen SCTP_INP_RLOCK(inp); 5160223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 5161223132Stuexen SCTP_TCB_LOCK(stcb); 5162223132Stuexen if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) { 5163223132Stuexen memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send))); 5164223132Stuexen } 5165223132Stuexen SCTP_TCB_UNLOCK(stcb); 5166223132Stuexen } 5167223132Stuexen SCTP_INP_RUNLOCK(inp); 5168223132Stuexen } 5169163953Srrs } 5170223132Stuexen break; 5171163953Srrs } 5172163953Srrs case SCTP_PEER_ADDR_PARAMS: 5173163953Srrs { 5174163953Srrs struct sctp_paddrparams *paddrp; 5175163953Srrs struct sctp_nets *net; 5176283699Stuexen struct sockaddr *addr; 5177163953Srrs 5178283699Stuexen#if defined(INET) && defined(INET6) 5179283699Stuexen struct sockaddr_in sin_store; 5180283699Stuexen 5181283699Stuexen#endif 5182283699Stuexen 5183166675Srrs SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize); 5184166675Srrs SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); 5185283699Stuexen 5186283699Stuexen#if defined(INET) && defined(INET6) 5187283699Stuexen if (paddrp->spp_address.ss_family == AF_INET6) { 5188283699Stuexen struct sockaddr_in6 *sin6; 5189283699Stuexen 5190283699Stuexen sin6 = (struct sockaddr_in6 *)&paddrp->spp_address; 5191283699Stuexen if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 5192283699Stuexen in6_sin6_2_sin(&sin_store, sin6); 5193283699Stuexen addr = (struct sockaddr *)&sin_store; 5194283699Stuexen } else { 5195283699Stuexen addr = (struct sockaddr *)&paddrp->spp_address; 5196283699Stuexen } 5197166675Srrs } else { 5198283699Stuexen addr = (struct sockaddr *)&paddrp->spp_address; 5199283699Stuexen } 5200283699Stuexen#else 5201283699Stuexen addr = (struct sockaddr *)&paddrp->spp_address; 5202283699Stuexen#endif 5203283699Stuexen if (stcb != NULL) { 5204283699Stuexen net = sctp_findnet(stcb, addr); 5205283699Stuexen } else { 5206166675Srrs /* 5207166675Srrs * We increment here since 5208166675Srrs * sctp_findassociation_ep_addr() wil do a 5209166675Srrs * decrement if it finds the stcb as long as 5210166675Srrs * the locked tcb (last argument) is NOT a 5211166675Srrs * TCB.. aka NULL. 5212166675Srrs */ 5213283699Stuexen net = NULL; 5214166675Srrs SCTP_INP_INCR_REF(inp); 5215283699Stuexen stcb = sctp_findassociation_ep_addr(&inp, addr, 5216166675Srrs &net, NULL, NULL); 5217163953Srrs if (stcb == NULL) { 5218166675Srrs SCTP_INP_DECR_REF(inp); 5219163953Srrs } 5220163953Srrs } 5221283699Stuexen if ((stcb != NULL) && (net == NULL)) { 5222221249Stuexen#ifdef INET 5223283699Stuexen if (addr->sa_family == AF_INET) { 5224221249Stuexen 5225171943Srrs struct sockaddr_in *sin; 5226171943Srrs 5227283699Stuexen sin = (struct sockaddr_in *)addr; 5228283699Stuexen if (sin->sin_addr.s_addr != INADDR_ANY) { 5229171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5230171943Srrs SCTP_TCB_UNLOCK(stcb); 5231171943Srrs error = EINVAL; 5232171943Srrs break; 5233171943Srrs } 5234221249Stuexen } else 5235221249Stuexen#endif 5236221249Stuexen#ifdef INET6 5237283699Stuexen if (addr->sa_family == AF_INET6) { 5238171943Srrs struct sockaddr_in6 *sin6; 5239171943Srrs 5240283699Stuexen sin6 = (struct sockaddr_in6 *)addr; 5241171943Srrs if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 5242171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5243171943Srrs SCTP_TCB_UNLOCK(stcb); 5244171943Srrs error = EINVAL; 5245171943Srrs break; 5246171943Srrs } 5247221249Stuexen } else 5248221249Stuexen#endif 5249221249Stuexen { 5250171943Srrs error = EAFNOSUPPORT; 5251171943Srrs SCTP_TCB_UNLOCK(stcb); 5252171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 5253171943Srrs break; 5254171943Srrs } 5255171943Srrs } 5256170056Srrs /* sanity checks */ 5257170056Srrs if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) { 5258170056Srrs if (stcb) 5259170056Srrs SCTP_TCB_UNLOCK(stcb); 5260171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5261170056Srrs return (EINVAL); 5262170056Srrs } 5263170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) { 5264170056Srrs if (stcb) 5265170056Srrs SCTP_TCB_UNLOCK(stcb); 5266171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5267170056Srrs return (EINVAL); 5268170056Srrs } 5269283699Stuexen if (stcb != NULL) { 5270163953Srrs /************************TCB SPECIFIC SET ******************/ 5271283699Stuexen if (net != NULL) { 5272163953Srrs /************************NET SPECIFIC SET ******************/ 5273224641Stuexen if (paddrp->spp_flags & SPP_HB_DISABLE) { 5274224641Stuexen if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) && 5275224641Stuexen !(net->dest_state & SCTP_ADDR_NOHB)) { 5276224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 5277283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9); 5278171440Srrs } 5279163953Srrs net->dest_state |= SCTP_ADDR_NOHB; 5280163953Srrs } 5281163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 5282224641Stuexen if (paddrp->spp_hbinterval) { 5283224641Stuexen net->heart_beat_delay = paddrp->spp_hbinterval; 5284224641Stuexen } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 5285224641Stuexen net->heart_beat_delay = 0; 5286224641Stuexen } 5287224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 5288224641Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 5289224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 5290163953Srrs net->dest_state &= ~SCTP_ADDR_NOHB; 5291163953Srrs } 5292224641Stuexen if (paddrp->spp_flags & SPP_HB_DEMAND) { 5293224641Stuexen /* on demand HB */ 5294224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 5295228391Stuexen sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED); 5296224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 5297224641Stuexen } 5298170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { 5299165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 5300165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 5301283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11); 5302163953Srrs } 5303225635Stuexen net->dest_state |= SCTP_ADDR_NO_PMTUD; 5304283829Stuexen net->mtu = paddrp->spp_pathmtu; 5305283829Stuexen switch (net->ro._l_addr.sa.sa_family) { 5306283829Stuexen#ifdef INET 5307283829Stuexen case AF_INET: 5308283829Stuexen net->mtu += SCTP_MIN_V4_OVERHEAD; 5309283829Stuexen break; 5310283829Stuexen#endif 5311283829Stuexen#ifdef INET6 5312283829Stuexen case AF_INET6: 5313283829Stuexen net->mtu += SCTP_MIN_OVERHEAD; 5314283829Stuexen break; 5315283829Stuexen#endif 5316283829Stuexen default: 5317283829Stuexen break; 5318283829Stuexen } 5319258454Stuexen if (net->mtu < stcb->asoc.smallest_mtu) { 5320258454Stuexen sctp_pathmtu_adjustment(stcb, net->mtu); 5321163953Srrs } 5322163953Srrs } 5323163953Srrs if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 5324225635Stuexen if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 5325163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 5326163953Srrs } 5327225635Stuexen net->dest_state &= ~SCTP_ADDR_NO_PMTUD; 5328163953Srrs } 5329224641Stuexen if (paddrp->spp_pathmaxrxt) { 5330224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 5331224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 5332224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 5333224641Stuexen } 5334224641Stuexen } else { 5335224641Stuexen if ((net->error_count <= paddrp->spp_pathmaxrxt) && 5336224641Stuexen (net->error_count > net->pf_threshold)) { 5337224641Stuexen net->dest_state |= SCTP_ADDR_PF; 5338224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 5339283822Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, 5340283822Stuexen stcb->sctp_ep, stcb, net, 5341283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_12); 5342224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 5343224641Stuexen } 5344224641Stuexen } 5345224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 5346224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 5347224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 5348235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); 5349224641Stuexen } 5350224641Stuexen } else { 5351224641Stuexen if (net->error_count <= paddrp->spp_pathmaxrxt) { 5352224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 5353235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); 5354224641Stuexen } 5355224641Stuexen } 5356163953Srrs net->failure_threshold = paddrp->spp_pathmaxrxt; 5357224641Stuexen } 5358224870Stuexen if (paddrp->spp_flags & SPP_DSCP) { 5359226252Stuexen net->dscp = paddrp->spp_dscp & 0xfc; 5360225549Stuexen net->dscp |= 0x01; 5361163953Srrs } 5362167598Srrs#ifdef INET6 5363163953Srrs if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { 5364225549Stuexen if (net->ro._l_addr.sa.sa_family == AF_INET6) { 5365224870Stuexen net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 5366225549Stuexen net->flowlabel |= 0x80000000; 5367163953Srrs } 5368163953Srrs } 5369163953Srrs#endif 5370163953Srrs } else { 5371163953Srrs /************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/ 5372283699Stuexen if (paddrp->spp_pathmaxrxt != 0) { 5373163953Srrs stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt; 5374224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 5375224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 5376224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 5377224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 5378224641Stuexen } 5379224641Stuexen } else { 5380224641Stuexen if ((net->error_count <= paddrp->spp_pathmaxrxt) && 5381224641Stuexen (net->error_count > net->pf_threshold)) { 5382224641Stuexen net->dest_state |= SCTP_ADDR_PF; 5383224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 5384283822Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, 5385283822Stuexen stcb->sctp_ep, stcb, net, 5386283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_13); 5387224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 5388224641Stuexen } 5389224641Stuexen } 5390224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 5391224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 5392224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 5393235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); 5394224641Stuexen } 5395224641Stuexen } else { 5396224641Stuexen if (net->error_count <= paddrp->spp_pathmaxrxt) { 5397224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 5398235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); 5399224641Stuexen } 5400224641Stuexen } 5401224641Stuexen net->failure_threshold = paddrp->spp_pathmaxrxt; 5402224641Stuexen } 5403224641Stuexen } 5404163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 5405283699Stuexen if (paddrp->spp_hbinterval != 0) { 5406224641Stuexen stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval; 5407224641Stuexen } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 5408224641Stuexen stcb->asoc.heart_beat_delay = 0; 5409224641Stuexen } 5410163953Srrs /* Turn back on the timer */ 5411224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 5412283699Stuexen if (paddrp->spp_hbinterval != 0) { 5413224641Stuexen net->heart_beat_delay = paddrp->spp_hbinterval; 5414224641Stuexen } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 5415224641Stuexen net->heart_beat_delay = 0; 5416224641Stuexen } 5417224641Stuexen if (net->dest_state & SCTP_ADDR_NOHB) { 5418224641Stuexen net->dest_state &= ~SCTP_ADDR_NOHB; 5419224641Stuexen } 5420224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 5421283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_14); 5422224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 5423224641Stuexen } 5424225635Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 5425163953Srrs } 5426224641Stuexen if (paddrp->spp_flags & SPP_HB_DISABLE) { 5427224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 5428224641Stuexen if (!(net->dest_state & SCTP_ADDR_NOHB)) { 5429224641Stuexen net->dest_state |= SCTP_ADDR_NOHB; 5430224641Stuexen if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { 5431283822Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, 5432283822Stuexen inp, stcb, net, 5433283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_15); 5434224641Stuexen } 5435224641Stuexen } 5436224641Stuexen } 5437225635Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 5438224641Stuexen } 5439170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { 5440170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 5441170056Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 5442170056Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 5443283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_16); 5444170056Srrs } 5445225635Stuexen net->dest_state |= SCTP_ADDR_NO_PMTUD; 5446283829Stuexen net->mtu = paddrp->spp_pathmtu; 5447283829Stuexen switch (net->ro._l_addr.sa.sa_family) { 5448283829Stuexen#ifdef INET 5449283829Stuexen case AF_INET: 5450283829Stuexen net->mtu += SCTP_MIN_V4_OVERHEAD; 5451283829Stuexen break; 5452283829Stuexen#endif 5453283829Stuexen#ifdef INET6 5454283829Stuexen case AF_INET6: 5455283829Stuexen net->mtu += SCTP_MIN_OVERHEAD; 5456283829Stuexen break; 5457283829Stuexen#endif 5458283829Stuexen default: 5459283829Stuexen break; 5460283829Stuexen } 5461258454Stuexen if (net->mtu < stcb->asoc.smallest_mtu) { 5462258454Stuexen sctp_pathmtu_adjustment(stcb, net->mtu); 5463170056Srrs } 5464170056Srrs } 5465225635Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 5466170056Srrs } 5467170056Srrs if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 5468170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 5469225635Stuexen if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 5470170056Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 5471170056Srrs } 5472225635Stuexen net->dest_state &= ~SCTP_ADDR_NO_PMTUD; 5473170056Srrs } 5474225635Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 5475170056Srrs } 5476224870Stuexen if (paddrp->spp_flags & SPP_DSCP) { 5477224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 5478226252Stuexen net->dscp = paddrp->spp_dscp & 0xfc; 5479225549Stuexen net->dscp |= 0x01; 5480163953Srrs } 5481226252Stuexen stcb->asoc.default_dscp = paddrp->spp_dscp & 0xfc; 5482225549Stuexen stcb->asoc.default_dscp |= 0x01; 5483163953Srrs } 5484225549Stuexen#ifdef INET6 5485224641Stuexen if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { 5486170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 5487225549Stuexen if (net->ro._l_addr.sa.sa_family == AF_INET6) { 5488225549Stuexen net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 5489225549Stuexen net->flowlabel |= 0x80000000; 5490225549Stuexen } 5491170056Srrs } 5492225549Stuexen stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 5493225549Stuexen stcb->asoc.default_flowlabel |= 0x80000000; 5494163953Srrs } 5495225549Stuexen#endif 5496163953Srrs } 5497163953Srrs SCTP_TCB_UNLOCK(stcb); 5498163953Srrs } else { 5499163953Srrs /************************NO TCB, SET TO default stuff ******************/ 5500224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5501224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5502224918Stuexen (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) { 5503223132Stuexen SCTP_INP_WLOCK(inp); 5504223132Stuexen /* 5505223132Stuexen * For the TOS/FLOWLABEL stuff you 5506223132Stuexen * set it with the options on the 5507223132Stuexen * socket 5508223132Stuexen */ 5509283699Stuexen if (paddrp->spp_pathmaxrxt != 0) { 5510223132Stuexen inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt; 5511223132Stuexen } 5512223132Stuexen if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) 5513223132Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0; 5514283699Stuexen else if (paddrp->spp_hbinterval != 0) { 5515223132Stuexen if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL) 5516223132Stuexen paddrp->spp_hbinterval = SCTP_MAX_HB_INTERVAL; 5517223132Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval); 5518223132Stuexen } 5519223132Stuexen if (paddrp->spp_flags & SPP_HB_ENABLE) { 5520224641Stuexen if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 5521224641Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0; 5522224641Stuexen } else if (paddrp->spp_hbinterval) { 5523224641Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval); 5524224641Stuexen } 5525223132Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 5526223132Stuexen } else if (paddrp->spp_flags & SPP_HB_DISABLE) { 5527223132Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 5528223132Stuexen } 5529225635Stuexen if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 5530225635Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 5531225635Stuexen } else if (paddrp->spp_flags & SPP_PMTUD_DISABLE) { 5532225635Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 5533225635Stuexen } 5534225549Stuexen if (paddrp->spp_flags & SPP_DSCP) { 5535226252Stuexen inp->sctp_ep.default_dscp = paddrp->spp_dscp & 0xfc; 5536225549Stuexen inp->sctp_ep.default_dscp |= 0x01; 5537225549Stuexen } 5538225549Stuexen#ifdef INET6 5539225549Stuexen if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { 5540225549Stuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 5541225549Stuexen inp->sctp_ep.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 5542225549Stuexen inp->sctp_ep.default_flowlabel |= 0x80000000; 5543225549Stuexen } 5544225549Stuexen } 5545225549Stuexen#endif 5546223132Stuexen SCTP_INP_WUNLOCK(inp); 5547223132Stuexen } else { 5548223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5549223132Stuexen error = EINVAL; 5550163953Srrs } 5551163953Srrs } 5552223132Stuexen break; 5553163953Srrs } 5554163953Srrs case SCTP_RTOINFO: 5555163953Srrs { 5556163953Srrs struct sctp_rtoinfo *srto; 5557169655Srrs uint32_t new_init, new_min, new_max; 5558163953Srrs 5559166675Srrs SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize); 5560166675Srrs SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); 5561166675Srrs 5562166675Srrs if (stcb) { 5563167598Srrs if (srto->srto_initial) 5564169655Srrs new_init = srto->srto_initial; 5565169655Srrs else 5566169655Srrs new_init = stcb->asoc.initial_rto; 5567167598Srrs if (srto->srto_max) 5568169655Srrs new_max = srto->srto_max; 5569169655Srrs else 5570169655Srrs new_max = stcb->asoc.maxrto; 5571167598Srrs if (srto->srto_min) 5572169655Srrs new_min = srto->srto_min; 5573169655Srrs else 5574169655Srrs new_min = stcb->asoc.minrto; 5575169655Srrs if ((new_min <= new_init) && (new_init <= new_max)) { 5576169655Srrs stcb->asoc.initial_rto = new_init; 5577169655Srrs stcb->asoc.maxrto = new_max; 5578169655Srrs stcb->asoc.minrto = new_min; 5579169655Srrs } else { 5580179783Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5581179783Srrs error = EINVAL; 5582169655Srrs } 5583166675Srrs SCTP_TCB_UNLOCK(stcb); 5584166675Srrs } else { 5585224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5586224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5587224918Stuexen (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) { 5588223132Stuexen SCTP_INP_WLOCK(inp); 5589223132Stuexen if (srto->srto_initial) 5590223132Stuexen new_init = srto->srto_initial; 5591223132Stuexen else 5592223132Stuexen new_init = inp->sctp_ep.initial_rto; 5593223132Stuexen if (srto->srto_max) 5594223132Stuexen new_max = srto->srto_max; 5595223132Stuexen else 5596223132Stuexen new_max = inp->sctp_ep.sctp_maxrto; 5597223132Stuexen if (srto->srto_min) 5598223132Stuexen new_min = srto->srto_min; 5599223132Stuexen else 5600223132Stuexen new_min = inp->sctp_ep.sctp_minrto; 5601223132Stuexen if ((new_min <= new_init) && (new_init <= new_max)) { 5602223132Stuexen inp->sctp_ep.initial_rto = new_init; 5603223132Stuexen inp->sctp_ep.sctp_maxrto = new_max; 5604223132Stuexen inp->sctp_ep.sctp_minrto = new_min; 5605223132Stuexen } else { 5606223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5607223132Stuexen error = EINVAL; 5608223132Stuexen } 5609223132Stuexen SCTP_INP_WUNLOCK(inp); 5610169655Srrs } else { 5611179783Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5612179783Srrs error = EINVAL; 5613169655Srrs } 5614163953Srrs } 5615223132Stuexen break; 5616163953Srrs } 5617163953Srrs case SCTP_ASSOCINFO: 5618163953Srrs { 5619163953Srrs struct sctp_assocparams *sasoc; 5620163953Srrs 5621166675Srrs SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize); 5622166675Srrs SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); 5623171477Srrs if (sasoc->sasoc_cookie_life) { 5624171477Srrs /* boundary check the cookie life */ 5625171477Srrs if (sasoc->sasoc_cookie_life < 1000) 5626171477Srrs sasoc->sasoc_cookie_life = 1000; 5627171477Srrs if (sasoc->sasoc_cookie_life > SCTP_MAX_COOKIE_LIFE) { 5628171477Srrs sasoc->sasoc_cookie_life = SCTP_MAX_COOKIE_LIFE; 5629171477Srrs } 5630171477Srrs } 5631163953Srrs if (stcb) { 5632163953Srrs if (sasoc->sasoc_asocmaxrxt) 5633163953Srrs stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt; 5634170056Srrs if (sasoc->sasoc_cookie_life) { 5635171572Srrs stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); 5636167598Srrs } 5637163953Srrs SCTP_TCB_UNLOCK(stcb); 5638163953Srrs } else { 5639224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5640224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5641224918Stuexen (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) { 5642223132Stuexen SCTP_INP_WLOCK(inp); 5643223132Stuexen if (sasoc->sasoc_asocmaxrxt) 5644223132Stuexen inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt; 5645223132Stuexen if (sasoc->sasoc_cookie_life) { 5646223132Stuexen inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); 5647223132Stuexen } 5648223132Stuexen SCTP_INP_WUNLOCK(inp); 5649223132Stuexen } else { 5650223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5651223132Stuexen error = EINVAL; 5652167598Srrs } 5653163953Srrs } 5654223132Stuexen break; 5655163953Srrs } 5656163953Srrs case SCTP_INITMSG: 5657163953Srrs { 5658163953Srrs struct sctp_initmsg *sinit; 5659163953Srrs 5660166675Srrs SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize); 5661163953Srrs SCTP_INP_WLOCK(inp); 5662163953Srrs if (sinit->sinit_num_ostreams) 5663163953Srrs inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams; 5664163953Srrs 5665163953Srrs if (sinit->sinit_max_instreams) 5666163953Srrs inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams; 5667163953Srrs 5668163953Srrs if (sinit->sinit_max_attempts) 5669163953Srrs inp->sctp_ep.max_init_times = sinit->sinit_max_attempts; 5670163953Srrs 5671167598Srrs if (sinit->sinit_max_init_timeo) 5672163953Srrs inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo; 5673163953Srrs SCTP_INP_WUNLOCK(inp); 5674223132Stuexen break; 5675163953Srrs } 5676163953Srrs case SCTP_PRIMARY_ADDR: 5677163953Srrs { 5678163953Srrs struct sctp_setprim *spa; 5679223132Stuexen struct sctp_nets *net; 5680283699Stuexen struct sockaddr *addr; 5681163953Srrs 5682283699Stuexen#if defined(INET) && defined(INET6) 5683283699Stuexen struct sockaddr_in sin_store; 5684283699Stuexen 5685283699Stuexen#endif 5686283699Stuexen 5687166675Srrs SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize); 5688166675Srrs SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id); 5689163953Srrs 5690283699Stuexen#if defined(INET) && defined(INET6) 5691283699Stuexen if (spa->ssp_addr.ss_family == AF_INET6) { 5692283699Stuexen struct sockaddr_in6 *sin6; 5693283699Stuexen 5694283699Stuexen sin6 = (struct sockaddr_in6 *)&spa->ssp_addr; 5695283699Stuexen if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 5696283699Stuexen in6_sin6_2_sin(&sin_store, sin6); 5697283699Stuexen addr = (struct sockaddr *)&sin_store; 5698283699Stuexen } else { 5699283699Stuexen addr = (struct sockaddr *)&spa->ssp_addr; 5700283699Stuexen } 5701166675Srrs } else { 5702283699Stuexen addr = (struct sockaddr *)&spa->ssp_addr; 5703283699Stuexen } 5704283699Stuexen#else 5705283699Stuexen addr = (struct sockaddr *)&spa->ssp_addr; 5706283699Stuexen#endif 5707283699Stuexen if (stcb != NULL) { 5708283699Stuexen net = sctp_findnet(stcb, addr); 5709283699Stuexen } else { 5710166675Srrs /* 5711166675Srrs * We increment here since 5712166675Srrs * sctp_findassociation_ep_addr() wil do a 5713166675Srrs * decrement if it finds the stcb as long as 5714166675Srrs * the locked tcb (last argument) is NOT a 5715166675Srrs * TCB.. aka NULL. 5716166675Srrs */ 5717283699Stuexen net = NULL; 5718163953Srrs SCTP_INP_INCR_REF(inp); 5719283699Stuexen stcb = sctp_findassociation_ep_addr(&inp, addr, 5720163953Srrs &net, NULL, NULL); 5721163953Srrs if (stcb == NULL) { 5722163953Srrs SCTP_INP_DECR_REF(inp); 5723163953Srrs } 5724163953Srrs } 5725166675Srrs 5726283699Stuexen if ((stcb != NULL) && (net != NULL)) { 5727284693Stuexen if (net != stcb->asoc.primary_destination) { 5728284693Stuexen if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { 5729284693Stuexen /* Ok we need to set it */ 5730284693Stuexen if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) { 5731284693Stuexen if ((stcb->asoc.alternate) && 5732284693Stuexen (!(net->dest_state & SCTP_ADDR_PF)) && 5733284693Stuexen (net->dest_state & SCTP_ADDR_REACHABLE)) { 5734284693Stuexen sctp_free_remote_addr(stcb->asoc.alternate); 5735284693Stuexen stcb->asoc.alternate = NULL; 5736284693Stuexen } 5737284693Stuexen } else { 5738284693Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5739284693Stuexen error = EINVAL; 5740166675Srrs } 5741284693Stuexen } else { 5742284693Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5743284693Stuexen error = EINVAL; 5744163953Srrs } 5745163953Srrs } 5746166675Srrs } else { 5747171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5748166675Srrs error = EINVAL; 5749163953Srrs } 5750283699Stuexen if (stcb != NULL) { 5751166675Srrs SCTP_TCB_UNLOCK(stcb); 5752166675Srrs } 5753223132Stuexen break; 5754163953Srrs } 5755167598Srrs case SCTP_SET_DYNAMIC_PRIMARY: 5756167598Srrs { 5757167598Srrs union sctp_sockstore *ss; 5758163953Srrs 5759170587Srwatson error = priv_check(curthread, 5760170587Srwatson PRIV_NETINET_RESERVEDPORT); 5761167598Srrs if (error) 5762167598Srrs break; 5763167598Srrs 5764167598Srrs SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize); 5765167598Srrs /* SUPER USER CHECK? */ 5766167598Srrs error = sctp_dynamic_set_primary(&ss->sa, vrf_id); 5767223132Stuexen break; 5768167598Srrs } 5769163953Srrs case SCTP_SET_PEER_PRIMARY_ADDR: 5770163953Srrs { 5771163953Srrs struct sctp_setpeerprim *sspp; 5772283699Stuexen struct sockaddr *addr; 5773163953Srrs 5774283699Stuexen#if defined(INET) && defined(INET6) 5775283699Stuexen struct sockaddr_in sin_store; 5776283699Stuexen 5777283699Stuexen#endif 5778283699Stuexen 5779166675Srrs SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize); 5780166675Srrs SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id); 5781169208Srrs if (stcb != NULL) { 5782170056Srrs struct sctp_ifa *ifa; 5783170056Srrs 5784283699Stuexen#if defined(INET) && defined(INET6) 5785283699Stuexen if (sspp->sspp_addr.ss_family == AF_INET6) { 5786283699Stuexen struct sockaddr_in6 *sin6; 5787283699Stuexen 5788283699Stuexen sin6 = (struct sockaddr_in6 *)&sspp->sspp_addr; 5789283699Stuexen if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 5790283699Stuexen in6_sin6_2_sin(&sin_store, sin6); 5791283699Stuexen addr = (struct sockaddr *)&sin_store; 5792283699Stuexen } else { 5793283699Stuexen addr = (struct sockaddr *)&sspp->sspp_addr; 5794283699Stuexen } 5795283699Stuexen } else { 5796283699Stuexen addr = (struct sockaddr *)&sspp->sspp_addr; 5797283699Stuexen } 5798283699Stuexen#else 5799283699Stuexen addr = (struct sockaddr *)&sspp->sspp_addr; 5800283699Stuexen#endif 5801283699Stuexen ifa = sctp_find_ifa_by_addr(addr, stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED); 5802170056Srrs if (ifa == NULL) { 5803171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5804166675Srrs error = EINVAL; 5805170056Srrs goto out_of_it; 5806166675Srrs } 5807170056Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { 5808170056Srrs /* 5809170056Srrs * Must validate the ifa found is in 5810170056Srrs * our ep 5811170056Srrs */ 5812170056Srrs struct sctp_laddr *laddr; 5813170056Srrs int found = 0; 5814170056Srrs 5815170056Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 5816170056Srrs if (laddr->ifa == NULL) { 5817170056Srrs SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n", 5818294174Stuexen __func__); 5819170056Srrs continue; 5820170056Srrs } 5821170056Srrs if (laddr->ifa == ifa) { 5822170056Srrs found = 1; 5823170056Srrs break; 5824170056Srrs } 5825170056Srrs } 5826170056Srrs if (!found) { 5827171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5828170056Srrs error = EINVAL; 5829170056Srrs goto out_of_it; 5830170056Srrs } 5831267769Stuexen } else { 5832283699Stuexen switch (addr->sa_family) { 5833267769Stuexen#ifdef INET 5834267769Stuexen case AF_INET: 5835267769Stuexen { 5836267769Stuexen struct sockaddr_in *sin; 5837267769Stuexen 5838283699Stuexen sin = (struct sockaddr_in *)addr; 5839267769Stuexen if (prison_check_ip4(inp->ip_inp.inp.inp_cred, 5840267769Stuexen &sin->sin_addr) != 0) { 5841267769Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5842267769Stuexen error = EINVAL; 5843267769Stuexen goto out_of_it; 5844267769Stuexen } 5845267769Stuexen break; 5846267769Stuexen } 5847267769Stuexen#endif 5848267769Stuexen#ifdef INET6 5849267769Stuexen case AF_INET6: 5850267769Stuexen { 5851267769Stuexen struct sockaddr_in6 *sin6; 5852267769Stuexen 5853283699Stuexen sin6 = (struct sockaddr_in6 *)addr; 5854267769Stuexen if (prison_check_ip6(inp->ip_inp.inp.inp_cred, 5855267769Stuexen &sin6->sin6_addr) != 0) { 5856267769Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5857267769Stuexen error = EINVAL; 5858267769Stuexen goto out_of_it; 5859267769Stuexen } 5860267769Stuexen break; 5861267769Stuexen } 5862267769Stuexen#endif 5863267769Stuexen default: 5864267769Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5865267769Stuexen error = EINVAL; 5866267769Stuexen goto out_of_it; 5867267769Stuexen } 5868170056Srrs } 5869283699Stuexen if (sctp_set_primary_ip_address_sa(stcb, addr) != 0) { 5870171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5871170056Srrs error = EINVAL; 5872170056Srrs } 5873170056Srrs out_of_it: 5874169208Srrs SCTP_TCB_UNLOCK(stcb); 5875166675Srrs } else { 5876171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5877163953Srrs error = EINVAL; 5878163953Srrs } 5879223132Stuexen break; 5880163953Srrs } 5881163953Srrs case SCTP_BINDX_ADD_ADDR: 5882163953Srrs { 5883163953Srrs struct sctp_getaddresses *addrs; 5884171477Srrs struct thread *td; 5885163953Srrs 5886171477Srrs td = (struct thread *)p; 5887170606Srrs SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, 5888170606Srrs optsize); 5889221249Stuexen#ifdef INET 5890171477Srrs if (addrs->addr->sa_family == AF_INET) { 5891238501Stuexen if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) { 5892171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5893171477Srrs error = EINVAL; 5894171477Srrs break; 5895171477Srrs } 5896188590Srrs if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) { 5897188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5898185435Sbz break; 5899171477Srrs } 5900221249Stuexen } else 5901221249Stuexen#endif 5902185435Sbz#ifdef INET6 5903221249Stuexen if (addrs->addr->sa_family == AF_INET6) { 5904238501Stuexen if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) { 5905171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5906171477Srrs error = EINVAL; 5907171477Srrs break; 5908171477Srrs } 5909188590Srrs if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr), 5910188590Srrs (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) { 5911188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5912185435Sbz break; 5913185435Sbz } 5914221249Stuexen } else 5915185435Sbz#endif 5916221249Stuexen { 5917185435Sbz error = EAFNOSUPPORT; 5918185435Sbz break; 5919171477Srrs } 5920170606Srrs sctp_bindx_add_address(so, inp, addrs->addr, 5921170606Srrs addrs->sget_assoc_id, vrf_id, 5922170606Srrs &error, p); 5923223132Stuexen break; 5924163953Srrs } 5925163953Srrs case SCTP_BINDX_REM_ADDR: 5926163953Srrs { 5927163953Srrs struct sctp_getaddresses *addrs; 5928171477Srrs struct thread *td; 5929163953Srrs 5930171477Srrs td = (struct thread *)p; 5931185435Sbz 5932166675Srrs SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize); 5933221249Stuexen#ifdef INET 5934171477Srrs if (addrs->addr->sa_family == AF_INET) { 5935238501Stuexen if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) { 5936171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5937171477Srrs error = EINVAL; 5938171477Srrs break; 5939171477Srrs } 5940188590Srrs if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) { 5941188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5942185435Sbz break; 5943171477Srrs } 5944221249Stuexen } else 5945221249Stuexen#endif 5946185435Sbz#ifdef INET6 5947221249Stuexen if (addrs->addr->sa_family == AF_INET6) { 5948238501Stuexen if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) { 5949171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5950171477Srrs error = EINVAL; 5951171477Srrs break; 5952171477Srrs } 5953224641Stuexen if (td != NULL && 5954224641Stuexen (error = prison_local_ip6(td->td_ucred, 5955224641Stuexen &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr), 5956188590Srrs (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) { 5957188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5958185435Sbz break; 5959185435Sbz } 5960221249Stuexen } else 5961185435Sbz#endif 5962221249Stuexen { 5963185435Sbz error = EAFNOSUPPORT; 5964185435Sbz break; 5965171477Srrs } 5966228653Stuexen sctp_bindx_delete_address(inp, addrs->addr, 5967170606Srrs addrs->sget_assoc_id, vrf_id, 5968170606Srrs &error); 5969223132Stuexen break; 5970163953Srrs } 5971223132Stuexen case SCTP_EVENT: 5972223132Stuexen { 5973223132Stuexen struct sctp_event *event; 5974223132Stuexen uint32_t event_type; 5975223132Stuexen 5976223132Stuexen SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, optsize); 5977223132Stuexen SCTP_FIND_STCB(inp, stcb, event->se_assoc_id); 5978223132Stuexen switch (event->se_type) { 5979223132Stuexen case SCTP_ASSOC_CHANGE: 5980223132Stuexen event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT; 5981223132Stuexen break; 5982223132Stuexen case SCTP_PEER_ADDR_CHANGE: 5983223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPADDREVNT; 5984223132Stuexen break; 5985223132Stuexen case SCTP_REMOTE_ERROR: 5986223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPEERERR; 5987223132Stuexen break; 5988223132Stuexen case SCTP_SEND_FAILED: 5989223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT; 5990223132Stuexen break; 5991223132Stuexen case SCTP_SHUTDOWN_EVENT: 5992223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT; 5993223132Stuexen break; 5994223132Stuexen case SCTP_ADAPTATION_INDICATION: 5995223132Stuexen event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT; 5996223132Stuexen break; 5997223132Stuexen case SCTP_PARTIAL_DELIVERY_EVENT: 5998223132Stuexen event_type = SCTP_PCB_FLAGS_PDAPIEVNT; 5999223132Stuexen break; 6000223132Stuexen case SCTP_AUTHENTICATION_EVENT: 6001223132Stuexen event_type = SCTP_PCB_FLAGS_AUTHEVNT; 6002223132Stuexen break; 6003223132Stuexen case SCTP_STREAM_RESET_EVENT: 6004223132Stuexen event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT; 6005223132Stuexen break; 6006223132Stuexen case SCTP_SENDER_DRY_EVENT: 6007223132Stuexen event_type = SCTP_PCB_FLAGS_DRYEVNT; 6008223132Stuexen break; 6009223132Stuexen case SCTP_NOTIFICATIONS_STOPPED_EVENT: 6010223132Stuexen event_type = 0; 6011223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); 6012223132Stuexen error = ENOTSUP; 6013223132Stuexen break; 6014235009Stuexen case SCTP_ASSOC_RESET_EVENT: 6015235009Stuexen event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT; 6016235009Stuexen break; 6017235009Stuexen case SCTP_STREAM_CHANGE_EVENT: 6018235009Stuexen event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT; 6019235009Stuexen break; 6020235075Stuexen case SCTP_SEND_FAILED_EVENT: 6021235075Stuexen event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT; 6022235075Stuexen break; 6023223132Stuexen default: 6024223132Stuexen event_type = 0; 6025223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6026223132Stuexen error = EINVAL; 6027223132Stuexen break; 6028223132Stuexen } 6029223132Stuexen if (event_type > 0) { 6030223132Stuexen if (stcb) { 6031223132Stuexen if (event->se_on) { 6032223132Stuexen sctp_stcb_feature_on(inp, stcb, event_type); 6033223132Stuexen if (event_type == SCTP_PCB_FLAGS_DRYEVNT) { 6034223132Stuexen if (TAILQ_EMPTY(&stcb->asoc.send_queue) && 6035223132Stuexen TAILQ_EMPTY(&stcb->asoc.sent_queue) && 6036223132Stuexen (stcb->asoc.stream_queue_cnt == 0)) { 6037223132Stuexen sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED); 6038223132Stuexen } 6039223132Stuexen } 6040223132Stuexen } else { 6041223132Stuexen sctp_stcb_feature_off(inp, stcb, event_type); 6042223132Stuexen } 6043223132Stuexen SCTP_TCB_UNLOCK(stcb); 6044223132Stuexen } else { 6045223132Stuexen /* 6046223132Stuexen * We don't want to send up a storm 6047223132Stuexen * of events, so return an error for 6048223132Stuexen * sender dry events 6049223132Stuexen */ 6050223132Stuexen if ((event_type == SCTP_PCB_FLAGS_DRYEVNT) && 6051224918Stuexen ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) && 6052224918Stuexen ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) && 6053223132Stuexen ((event->se_assoc_id == SCTP_ALL_ASSOC) || 6054223132Stuexen (event->se_assoc_id == SCTP_CURRENT_ASSOC))) { 6055223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); 6056223132Stuexen error = ENOTSUP; 6057223132Stuexen break; 6058223132Stuexen } 6059224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6060224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6061224918Stuexen (event->se_assoc_id == SCTP_FUTURE_ASSOC) || 6062223132Stuexen (event->se_assoc_id == SCTP_ALL_ASSOC)) { 6063223132Stuexen SCTP_INP_WLOCK(inp); 6064223132Stuexen if (event->se_on) { 6065223132Stuexen sctp_feature_on(inp, event_type); 6066223132Stuexen } else { 6067223132Stuexen sctp_feature_off(inp, event_type); 6068223132Stuexen } 6069223132Stuexen SCTP_INP_WUNLOCK(inp); 6070223132Stuexen } 6071223132Stuexen if ((event->se_assoc_id == SCTP_CURRENT_ASSOC) || 6072223132Stuexen (event->se_assoc_id == SCTP_ALL_ASSOC)) { 6073223132Stuexen SCTP_INP_RLOCK(inp); 6074223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 6075223132Stuexen SCTP_TCB_LOCK(stcb); 6076223132Stuexen if (event->se_on) { 6077223132Stuexen sctp_stcb_feature_on(inp, stcb, event_type); 6078223132Stuexen } else { 6079223132Stuexen sctp_stcb_feature_off(inp, stcb, event_type); 6080223132Stuexen } 6081223132Stuexen SCTP_TCB_UNLOCK(stcb); 6082223132Stuexen } 6083223132Stuexen SCTP_INP_RUNLOCK(inp); 6084223132Stuexen } 6085223132Stuexen } 6086223132Stuexen } 6087223132Stuexen break; 6088223132Stuexen } 6089223132Stuexen case SCTP_RECVRCVINFO: 6090223132Stuexen { 6091223132Stuexen int *onoff; 6092223132Stuexen 6093223132Stuexen SCTP_CHECK_AND_CAST(onoff, optval, int, optsize); 6094223132Stuexen SCTP_INP_WLOCK(inp); 6095223132Stuexen if (*onoff != 0) { 6096223132Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO); 6097223132Stuexen } else { 6098223132Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO); 6099223132Stuexen } 6100223132Stuexen SCTP_INP_WUNLOCK(inp); 6101223132Stuexen break; 6102223132Stuexen } 6103223132Stuexen case SCTP_RECVNXTINFO: 6104223132Stuexen { 6105223132Stuexen int *onoff; 6106223132Stuexen 6107223132Stuexen SCTP_CHECK_AND_CAST(onoff, optval, int, optsize); 6108223132Stuexen SCTP_INP_WLOCK(inp); 6109223132Stuexen if (*onoff != 0) { 6110223132Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO); 6111223132Stuexen } else { 6112223132Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO); 6113223132Stuexen } 6114223132Stuexen SCTP_INP_WUNLOCK(inp); 6115223132Stuexen break; 6116223132Stuexen } 6117223132Stuexen case SCTP_DEFAULT_SNDINFO: 6118223132Stuexen { 6119223132Stuexen struct sctp_sndinfo *info; 6120223162Stuexen uint16_t policy; 6121223132Stuexen 6122223132Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, optsize); 6123223132Stuexen SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id); 6124223132Stuexen 6125223132Stuexen if (stcb) { 6126223132Stuexen if (info->snd_sid < stcb->asoc.streamoutcnt) { 6127223132Stuexen stcb->asoc.def_send.sinfo_stream = info->snd_sid; 6128223162Stuexen policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); 6129223132Stuexen stcb->asoc.def_send.sinfo_flags = info->snd_flags; 6130223162Stuexen stcb->asoc.def_send.sinfo_flags |= policy; 6131223132Stuexen stcb->asoc.def_send.sinfo_ppid = info->snd_ppid; 6132223132Stuexen stcb->asoc.def_send.sinfo_context = info->snd_context; 6133223132Stuexen } else { 6134223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6135223132Stuexen error = EINVAL; 6136223132Stuexen } 6137223132Stuexen SCTP_TCB_UNLOCK(stcb); 6138223132Stuexen } else { 6139224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6140224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6141224918Stuexen (info->snd_assoc_id == SCTP_FUTURE_ASSOC) || 6142223132Stuexen (info->snd_assoc_id == SCTP_ALL_ASSOC)) { 6143223132Stuexen SCTP_INP_WLOCK(inp); 6144223132Stuexen inp->def_send.sinfo_stream = info->snd_sid; 6145223162Stuexen policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags); 6146223132Stuexen inp->def_send.sinfo_flags = info->snd_flags; 6147223162Stuexen inp->def_send.sinfo_flags |= policy; 6148223132Stuexen inp->def_send.sinfo_ppid = info->snd_ppid; 6149223132Stuexen inp->def_send.sinfo_context = info->snd_context; 6150223132Stuexen SCTP_INP_WUNLOCK(inp); 6151223132Stuexen } 6152223132Stuexen if ((info->snd_assoc_id == SCTP_CURRENT_ASSOC) || 6153223132Stuexen (info->snd_assoc_id == SCTP_ALL_ASSOC)) { 6154223132Stuexen SCTP_INP_RLOCK(inp); 6155223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 6156223132Stuexen SCTP_TCB_LOCK(stcb); 6157223132Stuexen if (info->snd_sid < stcb->asoc.streamoutcnt) { 6158223132Stuexen stcb->asoc.def_send.sinfo_stream = info->snd_sid; 6159223162Stuexen policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); 6160223132Stuexen stcb->asoc.def_send.sinfo_flags = info->snd_flags; 6161223162Stuexen stcb->asoc.def_send.sinfo_flags |= policy; 6162223132Stuexen stcb->asoc.def_send.sinfo_ppid = info->snd_ppid; 6163223132Stuexen stcb->asoc.def_send.sinfo_context = info->snd_context; 6164223132Stuexen } 6165223132Stuexen SCTP_TCB_UNLOCK(stcb); 6166223132Stuexen } 6167223132Stuexen SCTP_INP_RUNLOCK(inp); 6168223132Stuexen } 6169223132Stuexen } 6170223132Stuexen break; 6171223132Stuexen } 6172223162Stuexen case SCTP_DEFAULT_PRINFO: 6173223162Stuexen { 6174223162Stuexen struct sctp_default_prinfo *info; 6175223162Stuexen 6176223162Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, optsize); 6177223162Stuexen SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id); 6178223162Stuexen 6179283706Stuexen if (info->pr_policy > SCTP_PR_SCTP_MAX) { 6180223162Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6181223162Stuexen error = EINVAL; 6182223162Stuexen break; 6183223162Stuexen } 6184223162Stuexen if (stcb) { 6185223162Stuexen stcb->asoc.def_send.sinfo_flags &= 0xfff0; 6186223162Stuexen stcb->asoc.def_send.sinfo_flags |= info->pr_policy; 6187224918Stuexen stcb->asoc.def_send.sinfo_timetolive = info->pr_value; 6188223162Stuexen SCTP_TCB_UNLOCK(stcb); 6189223162Stuexen } else { 6190224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6191224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6192224918Stuexen (info->pr_assoc_id == SCTP_FUTURE_ASSOC) || 6193223162Stuexen (info->pr_assoc_id == SCTP_ALL_ASSOC)) { 6194223162Stuexen SCTP_INP_WLOCK(inp); 6195223162Stuexen inp->def_send.sinfo_flags &= 0xfff0; 6196223162Stuexen inp->def_send.sinfo_flags |= info->pr_policy; 6197224918Stuexen inp->def_send.sinfo_timetolive = info->pr_value; 6198223162Stuexen SCTP_INP_WUNLOCK(inp); 6199223162Stuexen } 6200223162Stuexen if ((info->pr_assoc_id == SCTP_CURRENT_ASSOC) || 6201223162Stuexen (info->pr_assoc_id == SCTP_ALL_ASSOC)) { 6202223162Stuexen SCTP_INP_RLOCK(inp); 6203223162Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 6204223162Stuexen SCTP_TCB_LOCK(stcb); 6205223162Stuexen stcb->asoc.def_send.sinfo_flags &= 0xfff0; 6206223162Stuexen stcb->asoc.def_send.sinfo_flags |= info->pr_policy; 6207224918Stuexen stcb->asoc.def_send.sinfo_timetolive = info->pr_value; 6208223162Stuexen SCTP_TCB_UNLOCK(stcb); 6209223162Stuexen } 6210223162Stuexen SCTP_INP_RUNLOCK(inp); 6211223162Stuexen } 6212223162Stuexen } 6213223162Stuexen break; 6214223162Stuexen } 6215224641Stuexen case SCTP_PEER_ADDR_THLDS: 6216224641Stuexen /* Applies to the specific association */ 6217224641Stuexen { 6218224641Stuexen struct sctp_paddrthlds *thlds; 6219224641Stuexen struct sctp_nets *net; 6220283699Stuexen struct sockaddr *addr; 6221224641Stuexen 6222283699Stuexen#if defined(INET) && defined(INET6) 6223283699Stuexen struct sockaddr_in sin_store; 6224283699Stuexen 6225283699Stuexen#endif 6226283699Stuexen 6227224641Stuexen SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, optsize); 6228224641Stuexen SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id); 6229283699Stuexen 6230283699Stuexen#if defined(INET) && defined(INET6) 6231283699Stuexen if (thlds->spt_address.ss_family == AF_INET6) { 6232283699Stuexen struct sockaddr_in6 *sin6; 6233283699Stuexen 6234283699Stuexen sin6 = (struct sockaddr_in6 *)&thlds->spt_address; 6235283699Stuexen if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 6236283699Stuexen in6_sin6_2_sin(&sin_store, sin6); 6237283699Stuexen addr = (struct sockaddr *)&sin_store; 6238283699Stuexen } else { 6239283699Stuexen addr = (struct sockaddr *)&thlds->spt_address; 6240283699Stuexen } 6241224641Stuexen } else { 6242283699Stuexen addr = (struct sockaddr *)&thlds->spt_address; 6243283699Stuexen } 6244283699Stuexen#else 6245283699Stuexen addr = (struct sockaddr *)&thlds->spt_address; 6246283699Stuexen#endif 6247283699Stuexen if (stcb != NULL) { 6248283699Stuexen net = sctp_findnet(stcb, addr); 6249283699Stuexen } else { 6250224641Stuexen /* 6251224641Stuexen * We increment here since 6252224641Stuexen * sctp_findassociation_ep_addr() wil do a 6253224641Stuexen * decrement if it finds the stcb as long as 6254224641Stuexen * the locked tcb (last argument) is NOT a 6255224641Stuexen * TCB.. aka NULL. 6256224641Stuexen */ 6257283699Stuexen net = NULL; 6258224641Stuexen SCTP_INP_INCR_REF(inp); 6259283699Stuexen stcb = sctp_findassociation_ep_addr(&inp, addr, 6260224641Stuexen &net, NULL, NULL); 6261224641Stuexen if (stcb == NULL) { 6262224641Stuexen SCTP_INP_DECR_REF(inp); 6263224641Stuexen } 6264224641Stuexen } 6265283699Stuexen if ((stcb != NULL) && (net == NULL)) { 6266224641Stuexen#ifdef INET 6267283699Stuexen if (addr->sa_family == AF_INET) { 6268224641Stuexen 6269224641Stuexen struct sockaddr_in *sin; 6270224641Stuexen 6271283699Stuexen sin = (struct sockaddr_in *)addr; 6272283699Stuexen if (sin->sin_addr.s_addr != INADDR_ANY) { 6273224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6274224641Stuexen SCTP_TCB_UNLOCK(stcb); 6275224641Stuexen error = EINVAL; 6276224641Stuexen break; 6277224641Stuexen } 6278224641Stuexen } else 6279224641Stuexen#endif 6280224641Stuexen#ifdef INET6 6281283699Stuexen if (addr->sa_family == AF_INET6) { 6282224641Stuexen struct sockaddr_in6 *sin6; 6283224641Stuexen 6284283699Stuexen sin6 = (struct sockaddr_in6 *)addr; 6285224641Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 6286224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6287224641Stuexen SCTP_TCB_UNLOCK(stcb); 6288224641Stuexen error = EINVAL; 6289224641Stuexen break; 6290224641Stuexen } 6291224641Stuexen } else 6292224641Stuexen#endif 6293224641Stuexen { 6294224641Stuexen error = EAFNOSUPPORT; 6295224641Stuexen SCTP_TCB_UNLOCK(stcb); 6296224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 6297224641Stuexen break; 6298224641Stuexen } 6299224641Stuexen } 6300283699Stuexen if (stcb != NULL) { 6301283699Stuexen if (net != NULL) { 6302283727Stuexen net->failure_threshold = thlds->spt_pathmaxrxt; 6303283727Stuexen net->pf_threshold = thlds->spt_pathpfthld; 6304224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 6305283727Stuexen if ((net->error_count > net->failure_threshold) || 6306283727Stuexen (net->error_count <= net->pf_threshold)) { 6307224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 6308224641Stuexen } 6309224641Stuexen } else { 6310283727Stuexen if ((net->error_count > net->pf_threshold) && 6311283727Stuexen (net->error_count <= net->failure_threshold)) { 6312224641Stuexen net->dest_state |= SCTP_ADDR_PF; 6313224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 6314283822Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, 6315283822Stuexen stcb->sctp_ep, stcb, net, 6316283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_17); 6317224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 6318224641Stuexen } 6319224641Stuexen } 6320224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 6321283727Stuexen if (net->error_count > net->failure_threshold) { 6322224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 6323235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); 6324224641Stuexen } 6325224641Stuexen } else { 6326283727Stuexen if (net->error_count <= net->failure_threshold) { 6327224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 6328235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); 6329224641Stuexen } 6330224641Stuexen } 6331224641Stuexen } else { 6332224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 6333283727Stuexen net->failure_threshold = thlds->spt_pathmaxrxt; 6334283727Stuexen net->pf_threshold = thlds->spt_pathpfthld; 6335224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 6336283727Stuexen if ((net->error_count > net->failure_threshold) || 6337283727Stuexen (net->error_count <= net->pf_threshold)) { 6338224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 6339224641Stuexen } 6340224641Stuexen } else { 6341283727Stuexen if ((net->error_count > net->pf_threshold) && 6342283727Stuexen (net->error_count <= net->failure_threshold)) { 6343224641Stuexen net->dest_state |= SCTP_ADDR_PF; 6344224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 6345283822Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, 6346283822Stuexen stcb->sctp_ep, stcb, net, 6347283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_18); 6348224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 6349224641Stuexen } 6350224641Stuexen } 6351224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 6352283727Stuexen if (net->error_count > net->failure_threshold) { 6353224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 6354235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); 6355224641Stuexen } 6356224641Stuexen } else { 6357283727Stuexen if (net->error_count <= net->failure_threshold) { 6358224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 6359235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); 6360224641Stuexen } 6361224641Stuexen } 6362224641Stuexen } 6363224641Stuexen stcb->asoc.def_net_failure = thlds->spt_pathmaxrxt; 6364224641Stuexen stcb->asoc.def_net_pf_threshold = thlds->spt_pathpfthld; 6365224641Stuexen } 6366283725Stuexen SCTP_TCB_UNLOCK(stcb); 6367224641Stuexen } else { 6368224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6369224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6370224918Stuexen (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) { 6371224641Stuexen SCTP_INP_WLOCK(inp); 6372224641Stuexen inp->sctp_ep.def_net_failure = thlds->spt_pathmaxrxt; 6373224641Stuexen inp->sctp_ep.def_net_pf_threshold = thlds->spt_pathpfthld; 6374224641Stuexen SCTP_INP_WUNLOCK(inp); 6375224641Stuexen } else { 6376224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6377224641Stuexen error = EINVAL; 6378224641Stuexen } 6379224641Stuexen } 6380224641Stuexen break; 6381224641Stuexen } 6382227755Stuexen case SCTP_REMOTE_UDP_ENCAPS_PORT: 6383227755Stuexen { 6384227755Stuexen struct sctp_udpencaps *encaps; 6385227755Stuexen struct sctp_nets *net; 6386283699Stuexen struct sockaddr *addr; 6387227755Stuexen 6388283699Stuexen#if defined(INET) && defined(INET6) 6389283699Stuexen struct sockaddr_in sin_store; 6390283699Stuexen 6391283699Stuexen#endif 6392283699Stuexen 6393227755Stuexen SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, optsize); 6394227755Stuexen SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id); 6395283699Stuexen 6396283699Stuexen#if defined(INET) && defined(INET6) 6397283699Stuexen if (encaps->sue_address.ss_family == AF_INET6) { 6398283699Stuexen struct sockaddr_in6 *sin6; 6399283699Stuexen 6400283699Stuexen sin6 = (struct sockaddr_in6 *)&encaps->sue_address; 6401283699Stuexen if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 6402283699Stuexen in6_sin6_2_sin(&sin_store, sin6); 6403283699Stuexen addr = (struct sockaddr *)&sin_store; 6404283699Stuexen } else { 6405283699Stuexen addr = (struct sockaddr *)&encaps->sue_address; 6406283699Stuexen } 6407227755Stuexen } else { 6408283699Stuexen addr = (struct sockaddr *)&encaps->sue_address; 6409283699Stuexen } 6410283699Stuexen#else 6411283699Stuexen addr = (struct sockaddr *)&encaps->sue_address; 6412283699Stuexen#endif 6413283699Stuexen if (stcb != NULL) { 6414283699Stuexen net = sctp_findnet(stcb, addr); 6415283699Stuexen } else { 6416227755Stuexen /* 6417227755Stuexen * We increment here since 6418227755Stuexen * sctp_findassociation_ep_addr() wil do a 6419227755Stuexen * decrement if it finds the stcb as long as 6420227755Stuexen * the locked tcb (last argument) is NOT a 6421227755Stuexen * TCB.. aka NULL. 6422227755Stuexen */ 6423227755Stuexen net = NULL; 6424227755Stuexen SCTP_INP_INCR_REF(inp); 6425283699Stuexen stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL); 6426227755Stuexen if (stcb == NULL) { 6427227755Stuexen SCTP_INP_DECR_REF(inp); 6428227755Stuexen } 6429227755Stuexen } 6430283699Stuexen if ((stcb != NULL) && (net == NULL)) { 6431227755Stuexen#ifdef INET 6432283699Stuexen if (addr->sa_family == AF_INET) { 6433227755Stuexen 6434227755Stuexen struct sockaddr_in *sin; 6435227755Stuexen 6436283699Stuexen sin = (struct sockaddr_in *)addr; 6437283699Stuexen if (sin->sin_addr.s_addr != INADDR_ANY) { 6438227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6439227755Stuexen SCTP_TCB_UNLOCK(stcb); 6440227755Stuexen error = EINVAL; 6441227755Stuexen break; 6442227755Stuexen } 6443227755Stuexen } else 6444227755Stuexen#endif 6445227755Stuexen#ifdef INET6 6446283699Stuexen if (addr->sa_family == AF_INET6) { 6447227755Stuexen struct sockaddr_in6 *sin6; 6448227755Stuexen 6449283699Stuexen sin6 = (struct sockaddr_in6 *)addr; 6450227755Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 6451227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6452227755Stuexen SCTP_TCB_UNLOCK(stcb); 6453227755Stuexen error = EINVAL; 6454227755Stuexen break; 6455227755Stuexen } 6456227755Stuexen } else 6457227755Stuexen#endif 6458227755Stuexen { 6459227755Stuexen error = EAFNOSUPPORT; 6460227755Stuexen SCTP_TCB_UNLOCK(stcb); 6461227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 6462227755Stuexen break; 6463227755Stuexen } 6464227755Stuexen } 6465283699Stuexen if (stcb != NULL) { 6466283699Stuexen if (net != NULL) { 6467227755Stuexen net->port = encaps->sue_port; 6468227755Stuexen } else { 6469227755Stuexen stcb->asoc.port = encaps->sue_port; 6470227755Stuexen } 6471227755Stuexen SCTP_TCB_UNLOCK(stcb); 6472227755Stuexen } else { 6473227755Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6474227755Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6475227755Stuexen (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) { 6476227755Stuexen SCTP_INP_WLOCK(inp); 6477227755Stuexen inp->sctp_ep.port = encaps->sue_port; 6478227755Stuexen SCTP_INP_WUNLOCK(inp); 6479227755Stuexen } else { 6480227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6481227755Stuexen error = EINVAL; 6482227755Stuexen } 6483227755Stuexen } 6484227755Stuexen break; 6485227755Stuexen } 6486270356Stuexen case SCTP_ECN_SUPPORTED: 6487270356Stuexen { 6488270356Stuexen struct sctp_assoc_value *av; 6489270356Stuexen 6490270356Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 6491270356Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 6492270356Stuexen 6493270356Stuexen if (stcb) { 6494270356Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6495270356Stuexen error = EINVAL; 6496270356Stuexen SCTP_TCB_UNLOCK(stcb); 6497270356Stuexen } else { 6498270356Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6499270356Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6500270356Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 6501270356Stuexen SCTP_INP_WLOCK(inp); 6502270356Stuexen if (av->assoc_value == 0) { 6503270356Stuexen inp->ecn_supported = 0; 6504270356Stuexen } else { 6505270356Stuexen inp->ecn_supported = 1; 6506270356Stuexen } 6507270356Stuexen SCTP_INP_WUNLOCK(inp); 6508270356Stuexen } else { 6509270356Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6510270356Stuexen error = EINVAL; 6511270356Stuexen } 6512270356Stuexen } 6513270356Stuexen break; 6514270356Stuexen } 6515270357Stuexen case SCTP_PR_SUPPORTED: 6516270357Stuexen { 6517270357Stuexen struct sctp_assoc_value *av; 6518270357Stuexen 6519270357Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 6520270357Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 6521270357Stuexen 6522270357Stuexen if (stcb) { 6523270357Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6524270357Stuexen error = EINVAL; 6525270357Stuexen SCTP_TCB_UNLOCK(stcb); 6526270357Stuexen } else { 6527270357Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6528270357Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6529270357Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 6530270357Stuexen SCTP_INP_WLOCK(inp); 6531270357Stuexen if (av->assoc_value == 0) { 6532270357Stuexen inp->prsctp_supported = 0; 6533270357Stuexen } else { 6534270357Stuexen inp->prsctp_supported = 1; 6535270357Stuexen } 6536270357Stuexen SCTP_INP_WUNLOCK(inp); 6537270357Stuexen } else { 6538270357Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6539270357Stuexen error = EINVAL; 6540270357Stuexen } 6541270357Stuexen } 6542270357Stuexen break; 6543270357Stuexen } 6544270362Stuexen case SCTP_AUTH_SUPPORTED: 6545270362Stuexen { 6546270362Stuexen struct sctp_assoc_value *av; 6547270362Stuexen 6548270362Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 6549270362Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 6550270362Stuexen 6551270362Stuexen if (stcb) { 6552270362Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6553270362Stuexen error = EINVAL; 6554270362Stuexen SCTP_TCB_UNLOCK(stcb); 6555270362Stuexen } else { 6556270362Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6557270362Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6558270362Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 6559270362Stuexen if ((av->assoc_value == 0) && 6560270362Stuexen (inp->asconf_supported == 1)) { 6561270362Stuexen /* 6562270362Stuexen * AUTH is required for 6563270362Stuexen * ASCONF 6564270362Stuexen */ 6565270362Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6566270362Stuexen error = EINVAL; 6567270362Stuexen } else { 6568270362Stuexen SCTP_INP_WLOCK(inp); 6569270362Stuexen if (av->assoc_value == 0) { 6570270362Stuexen inp->auth_supported = 0; 6571270362Stuexen } else { 6572270362Stuexen inp->auth_supported = 1; 6573270362Stuexen } 6574270362Stuexen SCTP_INP_WUNLOCK(inp); 6575270362Stuexen } 6576270362Stuexen } else { 6577270362Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6578270362Stuexen error = EINVAL; 6579270362Stuexen } 6580270362Stuexen } 6581270362Stuexen break; 6582270362Stuexen } 6583270362Stuexen case SCTP_ASCONF_SUPPORTED: 6584270362Stuexen { 6585270362Stuexen struct sctp_assoc_value *av; 6586270362Stuexen 6587270362Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 6588270362Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 6589270362Stuexen 6590270362Stuexen if (stcb) { 6591270362Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6592270362Stuexen error = EINVAL; 6593270362Stuexen SCTP_TCB_UNLOCK(stcb); 6594270362Stuexen } else { 6595270362Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6596270362Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6597270362Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 6598270362Stuexen if ((av->assoc_value != 0) && 6599270362Stuexen (inp->auth_supported == 0)) { 6600270362Stuexen /* 6601270362Stuexen * AUTH is required for 6602270362Stuexen * ASCONF 6603270362Stuexen */ 6604270362Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6605270362Stuexen error = EINVAL; 6606270362Stuexen } else { 6607270362Stuexen SCTP_INP_WLOCK(inp); 6608270362Stuexen if (av->assoc_value == 0) { 6609270362Stuexen inp->asconf_supported = 0; 6610270362Stuexen sctp_auth_delete_chunk(SCTP_ASCONF, 6611270362Stuexen inp->sctp_ep.local_auth_chunks); 6612270362Stuexen sctp_auth_delete_chunk(SCTP_ASCONF_ACK, 6613270362Stuexen inp->sctp_ep.local_auth_chunks); 6614270362Stuexen } else { 6615270362Stuexen inp->asconf_supported = 1; 6616270362Stuexen sctp_auth_add_chunk(SCTP_ASCONF, 6617270362Stuexen inp->sctp_ep.local_auth_chunks); 6618270362Stuexen sctp_auth_add_chunk(SCTP_ASCONF_ACK, 6619270362Stuexen inp->sctp_ep.local_auth_chunks); 6620270362Stuexen } 6621270362Stuexen SCTP_INP_WUNLOCK(inp); 6622270362Stuexen } 6623270362Stuexen } else { 6624270362Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6625270362Stuexen error = EINVAL; 6626270362Stuexen } 6627270362Stuexen } 6628270362Stuexen break; 6629270362Stuexen } 6630270361Stuexen case SCTP_RECONFIG_SUPPORTED: 6631270361Stuexen { 6632270361Stuexen struct sctp_assoc_value *av; 6633270361Stuexen 6634270361Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 6635270361Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 6636270361Stuexen 6637270361Stuexen if (stcb) { 6638270361Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6639270361Stuexen error = EINVAL; 6640270361Stuexen SCTP_TCB_UNLOCK(stcb); 6641270361Stuexen } else { 6642270361Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6643270361Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6644270361Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 6645270361Stuexen SCTP_INP_WLOCK(inp); 6646270361Stuexen if (av->assoc_value == 0) { 6647270361Stuexen inp->reconfig_supported = 0; 6648270361Stuexen } else { 6649270361Stuexen inp->reconfig_supported = 1; 6650270361Stuexen } 6651270361Stuexen SCTP_INP_WUNLOCK(inp); 6652270361Stuexen } else { 6653270361Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6654270361Stuexen error = EINVAL; 6655270361Stuexen } 6656270361Stuexen } 6657270361Stuexen break; 6658270361Stuexen } 6659270359Stuexen case SCTP_NRSACK_SUPPORTED: 6660270359Stuexen { 6661270359Stuexen struct sctp_assoc_value *av; 6662270359Stuexen 6663270359Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 6664270359Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 6665270359Stuexen 6666270359Stuexen if (stcb) { 6667270359Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6668270359Stuexen error = EINVAL; 6669270359Stuexen SCTP_TCB_UNLOCK(stcb); 6670270359Stuexen } else { 6671270359Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6672270359Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6673270359Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 6674270359Stuexen SCTP_INP_WLOCK(inp); 6675270359Stuexen if (av->assoc_value == 0) { 6676270359Stuexen inp->nrsack_supported = 0; 6677270359Stuexen } else { 6678270359Stuexen inp->nrsack_supported = 1; 6679270359Stuexen } 6680270359Stuexen SCTP_INP_WUNLOCK(inp); 6681270359Stuexen } else { 6682270359Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6683270359Stuexen error = EINVAL; 6684270359Stuexen } 6685270359Stuexen } 6686270359Stuexen break; 6687270359Stuexen } 6688270360Stuexen case SCTP_PKTDROP_SUPPORTED: 6689270360Stuexen { 6690270360Stuexen struct sctp_assoc_value *av; 6691270360Stuexen 6692270360Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 6693270360Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 6694270360Stuexen 6695270360Stuexen if (stcb) { 6696270360Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6697270360Stuexen error = EINVAL; 6698270360Stuexen SCTP_TCB_UNLOCK(stcb); 6699270360Stuexen } else { 6700270360Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6701270360Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6702270360Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 6703270360Stuexen SCTP_INP_WLOCK(inp); 6704270360Stuexen if (av->assoc_value == 0) { 6705270360Stuexen inp->pktdrop_supported = 0; 6706270360Stuexen } else { 6707270360Stuexen inp->pktdrop_supported = 1; 6708270360Stuexen } 6709270360Stuexen SCTP_INP_WUNLOCK(inp); 6710270360Stuexen } else { 6711270360Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6712270360Stuexen error = EINVAL; 6713270360Stuexen } 6714270360Stuexen } 6715270360Stuexen break; 6716270360Stuexen } 6717283724Stuexen case SCTP_MAX_CWND: 6718283724Stuexen { 6719283724Stuexen struct sctp_assoc_value *av; 6720283724Stuexen struct sctp_nets *net; 6721283724Stuexen 6722283724Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 6723283724Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 6724283724Stuexen 6725283724Stuexen if (stcb) { 6726283724Stuexen stcb->asoc.max_cwnd = av->assoc_value; 6727283724Stuexen if (stcb->asoc.max_cwnd > 0) { 6728283724Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 6729283724Stuexen if ((net->cwnd > stcb->asoc.max_cwnd) && 6730283724Stuexen (net->cwnd > (net->mtu - sizeof(struct sctphdr)))) { 6731283724Stuexen net->cwnd = stcb->asoc.max_cwnd; 6732283724Stuexen if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) { 6733283724Stuexen net->cwnd = net->mtu - sizeof(struct sctphdr); 6734283724Stuexen } 6735283724Stuexen } 6736283724Stuexen } 6737283724Stuexen } 6738283724Stuexen SCTP_TCB_UNLOCK(stcb); 6739283724Stuexen } else { 6740283724Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 6741283724Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 6742283724Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 6743283724Stuexen SCTP_INP_WLOCK(inp); 6744283724Stuexen inp->max_cwnd = av->assoc_value; 6745283724Stuexen SCTP_INP_WUNLOCK(inp); 6746283724Stuexen } else { 6747283724Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6748283724Stuexen error = EINVAL; 6749283724Stuexen } 6750283724Stuexen } 6751283724Stuexen break; 6752283724Stuexen } 6753163953Srrs default: 6754171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 6755163953Srrs error = ENOPROTOOPT; 6756163953Srrs break; 6757163953Srrs } /* end switch (opt) */ 6758163953Srrs return (error); 6759163953Srrs} 6760163953Srrs 6761163953Srrsint 6762163953Srrssctp_ctloutput(struct socket *so, struct sockopt *sopt) 6763163953Srrs{ 6764166675Srrs void *optval = NULL; 6765166675Srrs size_t optsize = 0; 6766166675Srrs void *p; 6767166675Srrs int error = 0; 6768284633Stuexen struct sctp_inpcb *inp; 6769163953Srrs 6770284633Stuexen if ((sopt->sopt_level == SOL_SOCKET) && 6771284633Stuexen (sopt->sopt_name == SO_SETFIB)) { 6772284633Stuexen inp = (struct sctp_inpcb *)so->so_pcb; 6773284633Stuexen if (inp == NULL) { 6774284633Stuexen SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS); 6775284633Stuexen return (EINVAL); 6776284633Stuexen } 6777284633Stuexen SCTP_INP_WLOCK(inp); 6778284633Stuexen inp->fibnum = so->so_fibnum; 6779284633Stuexen SCTP_INP_WUNLOCK(inp); 6780284633Stuexen return (0); 6781284633Stuexen } 6782163953Srrs if (sopt->sopt_level != IPPROTO_SCTP) { 6783163953Srrs /* wrong proto level... send back up to IP */ 6784163953Srrs#ifdef INET6 6785163953Srrs if (INP_CHECK_SOCKAF(so, AF_INET6)) 6786163953Srrs error = ip6_ctloutput(so, sopt); 6787221249Stuexen#endif /* INET6 */ 6788237565Stuexen#if defined(INET) && defined(INET6) 6789163953Srrs else 6790221249Stuexen#endif 6791221249Stuexen#ifdef INET 6792163953Srrs error = ip_ctloutput(so, sopt); 6793221249Stuexen#endif 6794163953Srrs return (error); 6795163953Srrs } 6796166675Srrs optsize = sopt->sopt_valsize; 6797166675Srrs if (optsize) { 6798170091Srrs SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT); 6799166675Srrs if (optval == NULL) { 6800235091Stuexen SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS); 6801163953Srrs return (ENOBUFS); 6802163953Srrs } 6803166675Srrs error = sooptcopyin(sopt, optval, optsize, optsize); 6804163953Srrs if (error) { 6805170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 6806163953Srrs goto out; 6807163953Srrs } 6808163953Srrs } 6809166675Srrs p = (void *)sopt->sopt_td; 6810163953Srrs if (sopt->sopt_dir == SOPT_SET) { 6811166675Srrs error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p); 6812163953Srrs } else if (sopt->sopt_dir == SOPT_GET) { 6813166675Srrs error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p); 6814163953Srrs } else { 6815235091Stuexen SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6816163953Srrs error = EINVAL; 6817163953Srrs } 6818166675Srrs if ((error == 0) && (optval != NULL)) { 6819166675Srrs error = sooptcopyout(sopt, optval, optsize); 6820170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 6821166675Srrs } else if (optval != NULL) { 6822170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 6823163953Srrs } 6824163953Srrsout: 6825163953Srrs return (error); 6826163953Srrs} 6827163953Srrs 6828221249Stuexen#ifdef INET 6829163953Srrsstatic int 6830163953Srrssctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p) 6831163953Srrs{ 6832163953Srrs int error = 0; 6833163953Srrs int create_lock_on = 0; 6834167598Srrs uint32_t vrf_id; 6835163953Srrs struct sctp_inpcb *inp; 6836163953Srrs struct sctp_tcb *stcb = NULL; 6837163953Srrs 6838163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 6839233005Stuexen if (inp == NULL) { 6840163953Srrs /* I made the same as TCP since we are not setup? */ 6841171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6842163953Srrs return (ECONNRESET); 6843163953Srrs } 6844171943Srrs if (addr == NULL) { 6845171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6846170056Srrs return EINVAL; 6847171943Srrs } 6848221249Stuexen switch (addr->sa_family) { 6849185435Sbz#ifdef INET6 6850221249Stuexen case AF_INET6: 6851221249Stuexen { 6852221249Stuexen struct sockaddr_in6 *sin6p; 6853185694Srrs 6854221249Stuexen if (addr->sa_len != sizeof(struct sockaddr_in6)) { 6855221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6856221249Stuexen return (EINVAL); 6857221249Stuexen } 6858221249Stuexen sin6p = (struct sockaddr_in6 *)addr; 6859221249Stuexen if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6p->sin6_addr)) != 0) { 6860221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 6861221249Stuexen return (error); 6862221249Stuexen } 6863221249Stuexen break; 6864185435Sbz } 6865185435Sbz#endif 6866221249Stuexen#ifdef INET 6867221249Stuexen case AF_INET: 6868221249Stuexen { 6869221249Stuexen struct sockaddr_in *sinp; 6870185694Srrs 6871221249Stuexen if (addr->sa_len != sizeof(struct sockaddr_in)) { 6872221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6873221249Stuexen return (EINVAL); 6874221249Stuexen } 6875221249Stuexen sinp = (struct sockaddr_in *)addr; 6876221249Stuexen if (p != NULL && (error = prison_remote_ip4(p->td_ucred, &sinp->sin_addr)) != 0) { 6877221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 6878221249Stuexen return (error); 6879221249Stuexen } 6880221249Stuexen break; 6881185435Sbz } 6882221249Stuexen#endif 6883221249Stuexen default: 6884185435Sbz SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT); 6885185435Sbz return (EAFNOSUPPORT); 6886170056Srrs } 6887178202Srrs SCTP_INP_INCR_REF(inp); 6888163953Srrs SCTP_ASOC_CREATE_LOCK(inp); 6889163953Srrs create_lock_on = 1; 6890163953Srrs 6891178202Srrs 6892163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 6893163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 6894163953Srrs /* Should I really unlock ? */ 6895171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); 6896163953Srrs error = EFAULT; 6897163953Srrs goto out_now; 6898163953Srrs } 6899163953Srrs#ifdef INET6 6900163953Srrs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 6901163953Srrs (addr->sa_family == AF_INET6)) { 6902171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6903163953Srrs error = EINVAL; 6904163953Srrs goto out_now; 6905163953Srrs } 6906246595Stuexen#endif 6907163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 6908163953Srrs SCTP_PCB_FLAGS_UNBOUND) { 6909163953Srrs /* Bind a ephemeral port */ 6910171572Srrs error = sctp_inpcb_bind(so, NULL, NULL, p); 6911163953Srrs if (error) { 6912163953Srrs goto out_now; 6913163953Srrs } 6914163953Srrs } 6915163953Srrs /* Now do we connect? */ 6916181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && 6917181054Srrs (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) { 6918171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6919163953Srrs error = EINVAL; 6920163953Srrs goto out_now; 6921163953Srrs } 6922163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 6923163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 6924163953Srrs /* We are already connected AND the TCP model */ 6925171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 6926163953Srrs error = EADDRINUSE; 6927163953Srrs goto out_now; 6928163953Srrs } 6929163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 6930163953Srrs SCTP_INP_RLOCK(inp); 6931163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 6932163953Srrs SCTP_INP_RUNLOCK(inp); 6933163953Srrs } else { 6934163953Srrs /* 6935166675Srrs * We increment here since sctp_findassociation_ep_addr() 6936181054Srrs * will do a decrement if it finds the stcb as long as the 6937166675Srrs * locked tcb (last argument) is NOT a TCB.. aka NULL. 6938163953Srrs */ 6939163953Srrs SCTP_INP_INCR_REF(inp); 6940163953Srrs stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL); 6941163953Srrs if (stcb == NULL) { 6942163953Srrs SCTP_INP_DECR_REF(inp); 6943168299Srrs } else { 6944178202Srrs SCTP_TCB_UNLOCK(stcb); 6945163953Srrs } 6946163953Srrs } 6947163953Srrs if (stcb != NULL) { 6948163953Srrs /* Already have or am bring up an association */ 6949171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 6950163953Srrs error = EALREADY; 6951163953Srrs goto out_now; 6952163953Srrs } 6953168299Srrs vrf_id = inp->def_vrf_id; 6954163953Srrs /* We are GOOD to go */ 6955206137Stuexen stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p); 6956163953Srrs if (stcb == NULL) { 6957163953Srrs /* Gak! no memory */ 6958167598Srrs goto out_now; 6959163953Srrs } 6960163953Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 6961163953Srrs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 6962163953Srrs /* Set the connected flag so we can queue data */ 6963163953Srrs soisconnecting(so); 6964163953Srrs } 6965171943Srrs SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); 6966169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 6967163953Srrs 6968163953Srrs /* initialize authentication parameters for the assoc */ 6969163953Srrs sctp_initialize_auth_params(inp, stcb); 6970163953Srrs 6971172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 6972168299Srrs SCTP_TCB_UNLOCK(stcb); 6973163953Srrsout_now: 6974169420Srrs if (create_lock_on) { 6975163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 6976169420Srrs } 6977163953Srrs SCTP_INP_DECR_REF(inp); 6978228907Stuexen return (error); 6979163953Srrs} 6980163953Srrs 6981221249Stuexen#endif 6982221249Stuexen 6983163953Srrsint 6984163953Srrssctp_listen(struct socket *so, int backlog, struct thread *p) 6985163953Srrs{ 6986163953Srrs /* 6987163953Srrs * Note this module depends on the protocol processing being called 6988163953Srrs * AFTER any socket level flags and backlog are applied to the 6989163953Srrs * socket. The traditional way that the socket flags are applied is 6990163953Srrs * AFTER protocol processing. We have made a change to the 6991163953Srrs * sys/kern/uipc_socket.c module to reverse this but this MUST be in 6992163953Srrs * place if the socket API for SCTP is to work properly. 6993163953Srrs */ 6994163953Srrs 6995163953Srrs int error = 0; 6996163953Srrs struct sctp_inpcb *inp; 6997163953Srrs 6998163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 6999233005Stuexen if (inp == NULL) { 7000163953Srrs /* I made the same as TCP since we are not setup? */ 7001171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 7002163953Srrs return (ECONNRESET); 7003163953Srrs } 7004181054Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) { 7005181054Srrs /* See if we have a listener */ 7006181054Srrs struct sctp_inpcb *tinp; 7007267771Stuexen union sctp_sockstore store; 7008181054Srrs 7009181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { 7010181054Srrs /* not bound all */ 7011181054Srrs struct sctp_laddr *laddr; 7012181054Srrs 7013181054Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 7014181054Srrs memcpy(&store, &laddr->ifa->address, sizeof(store)); 7015267771Stuexen switch (store.sa.sa_family) { 7016221249Stuexen#ifdef INET 7017221249Stuexen case AF_INET: 7018267771Stuexen store.sin.sin_port = inp->sctp_lport; 7019221249Stuexen break; 7020221249Stuexen#endif 7021221249Stuexen#ifdef INET6 7022221249Stuexen case AF_INET6: 7023267771Stuexen store.sin6.sin6_port = inp->sctp_lport; 7024221249Stuexen break; 7025221249Stuexen#endif 7026221249Stuexen default: 7027221249Stuexen break; 7028221249Stuexen } 7029267771Stuexen tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id); 7030181054Srrs if (tinp && (tinp != inp) && 7031181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && 7032181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 7033181054Srrs (tinp->sctp_socket->so_qlimit)) { 7034181054Srrs /* 7035181054Srrs * we have a listener already and 7036181054Srrs * its not this inp. 7037181054Srrs */ 7038181054Srrs SCTP_INP_DECR_REF(tinp); 7039181054Srrs return (EADDRINUSE); 7040181054Srrs } else if (tinp) { 7041181054Srrs SCTP_INP_DECR_REF(tinp); 7042181054Srrs } 7043181054Srrs } 7044181054Srrs } else { 7045181054Srrs /* Setup a local addr bound all */ 7046181054Srrs memset(&store, 0, sizeof(store)); 7047267771Stuexen#ifdef INET6 7048267771Stuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 7049267771Stuexen store.sa.sa_family = AF_INET6; 7050267771Stuexen store.sa.sa_len = sizeof(struct sockaddr_in6); 7051267771Stuexen } 7052267771Stuexen#endif 7053221249Stuexen#ifdef INET 7054267771Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { 7055267771Stuexen store.sa.sa_family = AF_INET; 7056267771Stuexen store.sa.sa_len = sizeof(struct sockaddr_in); 7057267771Stuexen } 7058267771Stuexen#endif 7059267771Stuexen switch (store.sa.sa_family) { 7060267771Stuexen#ifdef INET 7061221249Stuexen case AF_INET: 7062221249Stuexen store.sin.sin_port = inp->sctp_lport; 7063221249Stuexen break; 7064221249Stuexen#endif 7065181054Srrs#ifdef INET6 7066221249Stuexen case AF_INET6: 7067267771Stuexen store.sin6.sin6_port = inp->sctp_lport; 7068221249Stuexen break; 7069221249Stuexen#endif 7070221249Stuexen default: 7071221249Stuexen break; 7072221249Stuexen } 7073267771Stuexen tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id); 7074181054Srrs if (tinp && (tinp != inp) && 7075181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && 7076181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 7077181054Srrs (tinp->sctp_socket->so_qlimit)) { 7078181054Srrs /* 7079181054Srrs * we have a listener already and its not 7080181054Srrs * this inp. 7081181054Srrs */ 7082181054Srrs SCTP_INP_DECR_REF(tinp); 7083181054Srrs return (EADDRINUSE); 7084181054Srrs } else if (tinp) { 7085283733Stuexen SCTP_INP_DECR_REF(tinp); 7086181054Srrs } 7087181054Srrs } 7088181054Srrs } 7089163953Srrs SCTP_INP_RLOCK(inp); 7090163953Srrs#ifdef SCTP_LOCK_LOGGING 7091179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) { 7092170744Srrs sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK); 7093170744Srrs } 7094163953Srrs#endif 7095163953Srrs SOCK_LOCK(so); 7096163953Srrs error = solisten_proto_check(so); 7097283732Stuexen SOCK_UNLOCK(so); 7098163953Srrs if (error) { 7099169208Srrs SCTP_INP_RUNLOCK(inp); 7100163953Srrs return (error); 7101163953Srrs } 7102181054Srrs if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) && 7103181054Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 7104181054Srrs /* 7105181054Srrs * The unlucky case - We are in the tcp pool with this guy. 7106181054Srrs * - Someone else is in the main inp slot. - We must move 7107181054Srrs * this guy (the listener) to the main slot - We must then 7108181054Srrs * move the guy that was listener to the TCP Pool. 7109181054Srrs */ 7110181054Srrs if (sctp_swap_inpcb_for_listen(inp)) { 7111283732Stuexen SCTP_INP_RUNLOCK(inp); 7112283732Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 7113283732Stuexen return (EADDRINUSE); 7114181054Srrs } 7115181054Srrs } 7116163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 7117163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 7118163953Srrs /* We are already connected AND the TCP model */ 7119163953Srrs SCTP_INP_RUNLOCK(inp); 7120171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 7121163953Srrs return (EADDRINUSE); 7122163953Srrs } 7123181054Srrs SCTP_INP_RUNLOCK(inp); 7124163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { 7125163953Srrs /* We must do a bind. */ 7126171572Srrs if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) { 7127163953Srrs /* bind error, probably perm */ 7128163953Srrs return (error); 7129163953Srrs } 7130163953Srrs } 7131283732Stuexen SOCK_LOCK(so); 7132163953Srrs /* It appears for 7.0 and on, we must always call this. */ 7133163953Srrs solisten_proto(so, backlog); 7134163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 7135163953Srrs /* remove the ACCEPTCONN flag for one-to-many sockets */ 7136163953Srrs so->so_options &= ~SO_ACCEPTCONN; 7137163953Srrs } 7138163953Srrs if (backlog == 0) { 7139163953Srrs /* turning off listen */ 7140163953Srrs so->so_options &= ~SO_ACCEPTCONN; 7141163953Srrs } 7142163953Srrs SOCK_UNLOCK(so); 7143163953Srrs return (error); 7144163953Srrs} 7145163953Srrs 7146163953Srrsstatic int sctp_defered_wakeup_cnt = 0; 7147163953Srrs 7148163953Srrsint 7149163953Srrssctp_accept(struct socket *so, struct sockaddr **addr) 7150163953Srrs{ 7151163953Srrs struct sctp_tcb *stcb; 7152163953Srrs struct sctp_inpcb *inp; 7153163953Srrs union sctp_sockstore store; 7154163953Srrs 7155178251Srrs#ifdef INET6 7156163953Srrs int error; 7157163953Srrs 7158178251Srrs#endif 7159163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 7160163953Srrs 7161233005Stuexen if (inp == NULL) { 7162171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 7163163953Srrs return (ECONNRESET); 7164163953Srrs } 7165163953Srrs SCTP_INP_RLOCK(inp); 7166163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 7167168299Srrs SCTP_INP_RUNLOCK(inp); 7168171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 7169171943Srrs return (EOPNOTSUPP); 7170163953Srrs } 7171163953Srrs if (so->so_state & SS_ISDISCONNECTED) { 7172163953Srrs SCTP_INP_RUNLOCK(inp); 7173171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED); 7174163953Srrs return (ECONNABORTED); 7175163953Srrs } 7176163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 7177163953Srrs if (stcb == NULL) { 7178163953Srrs SCTP_INP_RUNLOCK(inp); 7179171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 7180163953Srrs return (ECONNRESET); 7181163953Srrs } 7182163953Srrs SCTP_TCB_LOCK(stcb); 7183163953Srrs SCTP_INP_RUNLOCK(inp); 7184163953Srrs store = stcb->asoc.primary_destination->ro._l_addr; 7185207924Srrs stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE; 7186163953Srrs SCTP_TCB_UNLOCK(stcb); 7187178251Srrs switch (store.sa.sa_family) { 7188221249Stuexen#ifdef INET 7189178251Srrs case AF_INET: 7190178251Srrs { 7191178251Srrs struct sockaddr_in *sin; 7192163953Srrs 7193178251Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 7194208863Srrs if (sin == NULL) 7195208863Srrs return (ENOMEM); 7196178251Srrs sin->sin_family = AF_INET; 7197178251Srrs sin->sin_len = sizeof(*sin); 7198246595Stuexen sin->sin_port = store.sin.sin_port; 7199246595Stuexen sin->sin_addr = store.sin.sin_addr; 7200178251Srrs *addr = (struct sockaddr *)sin; 7201178251Srrs break; 7202178251Srrs } 7203221249Stuexen#endif 7204178251Srrs#ifdef INET6 7205178251Srrs case AF_INET6: 7206178251Srrs { 7207178251Srrs struct sockaddr_in6 *sin6; 7208163953Srrs 7209178251Srrs SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); 7210208863Srrs if (sin6 == NULL) 7211208863Srrs return (ENOMEM); 7212178251Srrs sin6->sin6_family = AF_INET6; 7213178251Srrs sin6->sin6_len = sizeof(*sin6); 7214246595Stuexen sin6->sin6_port = store.sin6.sin6_port; 7215246595Stuexen sin6->sin6_addr = store.sin6.sin6_addr; 7216178251Srrs if ((error = sa6_recoverscope(sin6)) != 0) { 7217178251Srrs SCTP_FREE_SONAME(sin6); 7218178251Srrs return (error); 7219178251Srrs } 7220178251Srrs *addr = (struct sockaddr *)sin6; 7221178251Srrs break; 7222164085Srrs } 7223178251Srrs#endif 7224178251Srrs default: 7225178251Srrs /* TSNH */ 7226178251Srrs break; 7227163953Srrs } 7228163953Srrs /* Wake any delayed sleep action */ 7229163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { 7230166086Srrs SCTP_INP_WLOCK(inp); 7231163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE; 7232163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) { 7233163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT; 7234166086Srrs SCTP_INP_WUNLOCK(inp); 7235163953Srrs SOCKBUF_LOCK(&inp->sctp_socket->so_snd); 7236163953Srrs if (sowriteable(inp->sctp_socket)) { 7237163953Srrs sowwakeup_locked(inp->sctp_socket); 7238163953Srrs } else { 7239163953Srrs SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd); 7240163953Srrs } 7241166086Srrs SCTP_INP_WLOCK(inp); 7242163953Srrs } 7243163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) { 7244163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT; 7245166086Srrs SCTP_INP_WUNLOCK(inp); 7246163953Srrs SOCKBUF_LOCK(&inp->sctp_socket->so_rcv); 7247163953Srrs if (soreadable(inp->sctp_socket)) { 7248163953Srrs sctp_defered_wakeup_cnt++; 7249163953Srrs sorwakeup_locked(inp->sctp_socket); 7250163953Srrs } else { 7251163953Srrs SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv); 7252163953Srrs } 7253166086Srrs SCTP_INP_WLOCK(inp); 7254163953Srrs } 7255166086Srrs SCTP_INP_WUNLOCK(inp); 7256163953Srrs } 7257207924Srrs if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 7258207924Srrs SCTP_TCB_LOCK(stcb); 7259283822Stuexen sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 7260283822Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_19); 7261207924Srrs } 7262163953Srrs return (0); 7263163953Srrs} 7264163953Srrs 7265221249Stuexen#ifdef INET 7266163953Srrsint 7267163953Srrssctp_ingetaddr(struct socket *so, struct sockaddr **addr) 7268163953Srrs{ 7269163953Srrs struct sockaddr_in *sin; 7270167598Srrs uint32_t vrf_id; 7271163953Srrs struct sctp_inpcb *inp; 7272167695Srrs struct sctp_ifa *sctp_ifa; 7273163953Srrs 7274163953Srrs /* 7275163953Srrs * Do the malloc first in case it blocks. 7276163953Srrs */ 7277163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 7278208863Srrs if (sin == NULL) 7279208863Srrs return (ENOMEM); 7280163953Srrs sin->sin_family = AF_INET; 7281163953Srrs sin->sin_len = sizeof(*sin); 7282163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 7283163953Srrs if (!inp) { 7284163953Srrs SCTP_FREE_SONAME(sin); 7285171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 7286228907Stuexen return (ECONNRESET); 7287163953Srrs } 7288163953Srrs SCTP_INP_RLOCK(inp); 7289163953Srrs sin->sin_port = inp->sctp_lport; 7290163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 7291163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 7292163953Srrs struct sctp_tcb *stcb; 7293163953Srrs struct sockaddr_in *sin_a; 7294163953Srrs struct sctp_nets *net; 7295163953Srrs int fnd; 7296163953Srrs 7297163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 7298163953Srrs if (stcb == NULL) { 7299163953Srrs goto notConn; 7300163953Srrs } 7301163953Srrs fnd = 0; 7302163953Srrs sin_a = NULL; 7303163953Srrs SCTP_TCB_LOCK(stcb); 7304163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 7305163953Srrs sin_a = (struct sockaddr_in *)&net->ro._l_addr; 7306164085Srrs if (sin_a == NULL) 7307164085Srrs /* this will make coverity happy */ 7308164085Srrs continue; 7309164085Srrs 7310163953Srrs if (sin_a->sin_family == AF_INET) { 7311163953Srrs fnd = 1; 7312163953Srrs break; 7313163953Srrs } 7314163953Srrs } 7315163953Srrs if ((!fnd) || (sin_a == NULL)) { 7316163953Srrs /* punt */ 7317163953Srrs SCTP_TCB_UNLOCK(stcb); 7318163953Srrs goto notConn; 7319163953Srrs } 7320168299Srrs vrf_id = inp->def_vrf_id; 7321167598Srrs sctp_ifa = sctp_source_address_selection(inp, 7322167598Srrs stcb, 7323168299Srrs (sctp_route_t *) & net->ro, 7324167598Srrs net, 0, vrf_id); 7325167598Srrs if (sctp_ifa) { 7326167598Srrs sin->sin_addr = sctp_ifa->address.sin.sin_addr; 7327167598Srrs sctp_free_ifa(sctp_ifa); 7328167598Srrs } 7329163953Srrs SCTP_TCB_UNLOCK(stcb); 7330163953Srrs } else { 7331163953Srrs /* For the bound all case you get back 0 */ 7332163953Srrs notConn: 7333163953Srrs sin->sin_addr.s_addr = 0; 7334163953Srrs } 7335163953Srrs 7336163953Srrs } else { 7337163953Srrs /* Take the first IPv4 address in the list */ 7338163953Srrs struct sctp_laddr *laddr; 7339163953Srrs int fnd = 0; 7340163953Srrs 7341163953Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 7342167598Srrs if (laddr->ifa->address.sa.sa_family == AF_INET) { 7343163953Srrs struct sockaddr_in *sin_a; 7344163953Srrs 7345271746Stuexen sin_a = &laddr->ifa->address.sin; 7346163953Srrs sin->sin_addr = sin_a->sin_addr; 7347163953Srrs fnd = 1; 7348163953Srrs break; 7349163953Srrs } 7350163953Srrs } 7351163953Srrs if (!fnd) { 7352163953Srrs SCTP_FREE_SONAME(sin); 7353163953Srrs SCTP_INP_RUNLOCK(inp); 7354171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 7355228907Stuexen return (ENOENT); 7356163953Srrs } 7357163953Srrs } 7358163953Srrs SCTP_INP_RUNLOCK(inp); 7359163953Srrs (*addr) = (struct sockaddr *)sin; 7360163953Srrs return (0); 7361163953Srrs} 7362163953Srrs 7363163953Srrsint 7364163953Srrssctp_peeraddr(struct socket *so, struct sockaddr **addr) 7365163953Srrs{ 7366231895Stuexen struct sockaddr_in *sin; 7367166086Srrs int fnd; 7368163953Srrs struct sockaddr_in *sin_a; 7369163953Srrs struct sctp_inpcb *inp; 7370163953Srrs struct sctp_tcb *stcb; 7371163953Srrs struct sctp_nets *net; 7372163953Srrs 7373163953Srrs /* Do the malloc first in case it blocks. */ 7374163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 7375208863Srrs if (sin == NULL) 7376208863Srrs return (ENOMEM); 7377163953Srrs sin->sin_family = AF_INET; 7378163953Srrs sin->sin_len = sizeof(*sin); 7379163953Srrs 7380163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 7381228907Stuexen if ((inp == NULL) || 7382228907Stuexen ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { 7383228907Stuexen /* UDP type and listeners will drop out here */ 7384163953Srrs SCTP_FREE_SONAME(sin); 7385228907Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 7386228907Stuexen return (ENOTCONN); 7387163953Srrs } 7388163953Srrs SCTP_INP_RLOCK(inp); 7389163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 7390169420Srrs if (stcb) { 7391163953Srrs SCTP_TCB_LOCK(stcb); 7392169420Srrs } 7393163953Srrs SCTP_INP_RUNLOCK(inp); 7394163953Srrs if (stcb == NULL) { 7395163953Srrs SCTP_FREE_SONAME(sin); 7396171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 7397228907Stuexen return (ECONNRESET); 7398163953Srrs } 7399163953Srrs fnd = 0; 7400163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 7401163953Srrs sin_a = (struct sockaddr_in *)&net->ro._l_addr; 7402163953Srrs if (sin_a->sin_family == AF_INET) { 7403163953Srrs fnd = 1; 7404163953Srrs sin->sin_port = stcb->rport; 7405163953Srrs sin->sin_addr = sin_a->sin_addr; 7406163953Srrs break; 7407163953Srrs } 7408163953Srrs } 7409163953Srrs SCTP_TCB_UNLOCK(stcb); 7410163953Srrs if (!fnd) { 7411163953Srrs /* No IPv4 address */ 7412163953Srrs SCTP_FREE_SONAME(sin); 7413171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 7414228907Stuexen return (ENOENT); 7415163953Srrs } 7416163953Srrs (*addr) = (struct sockaddr *)sin; 7417163953Srrs return (0); 7418163953Srrs} 7419163953Srrs 7420163953Srrsstruct pr_usrreqs sctp_usrreqs = { 7421163953Srrs .pru_abort = sctp_abort, 7422163953Srrs .pru_accept = sctp_accept, 7423163953Srrs .pru_attach = sctp_attach, 7424163953Srrs .pru_bind = sctp_bind, 7425163953Srrs .pru_connect = sctp_connect, 7426163953Srrs .pru_control = in_control, 7427163953Srrs .pru_close = sctp_close, 7428163953Srrs .pru_detach = sctp_close, 7429163953Srrs .pru_sopoll = sopoll_generic, 7430178202Srrs .pru_flush = sctp_flush, 7431163953Srrs .pru_disconnect = sctp_disconnect, 7432163953Srrs .pru_listen = sctp_listen, 7433163953Srrs .pru_peeraddr = sctp_peeraddr, 7434163953Srrs .pru_send = sctp_sendm, 7435163953Srrs .pru_shutdown = sctp_shutdown, 7436163953Srrs .pru_sockaddr = sctp_ingetaddr, 7437163953Srrs .pru_sosend = sctp_sosend, 7438163953Srrs .pru_soreceive = sctp_soreceive 7439163953Srrs}; 7440221249Stuexen 7441221249Stuexen#endif 7442