sctp_usrreq.c revision 243882
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: head/sys/netinet/sctp_usrreq.c 243882 2012-12-05 08:04:20Z glebius $"); 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 42167695Srrs#endif 43167598Srrs#include <netinet/sctp_sysctl.h> 44163953Srrs#include <netinet/sctp_output.h> 45163953Srrs#include <netinet/sctp_uio.h> 46163953Srrs#include <netinet/sctp_asconf.h> 47163953Srrs#include <netinet/sctputil.h> 48163953Srrs#include <netinet/sctp_indata.h> 49163953Srrs#include <netinet/sctp_timer.h> 50163953Srrs#include <netinet/sctp_auth.h> 51170091Srrs#include <netinet/sctp_bsd_addr.h> 52185694Srrs#include <netinet/udp.h> 53164085Srrs 54163953Srrs 55163953Srrs 56217611Stuexenextern struct sctp_cc_functions sctp_cc_functions[]; 57217760Stuexenextern struct sctp_ss_functions sctp_ss_functions[]; 58170091Srrs 59163953Srrsvoid 60163953Srrssctp_init(void) 61163953Srrs{ 62163953Srrs u_long sb_max_adj; 63163953Srrs 64179783Srrs /* Initialize and modify the sysctled variables */ 65179783Srrs sctp_init_sysctls(); 66163953Srrs if ((nmbclusters / 8) > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE) 67179783Srrs SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue) = (nmbclusters / 8); 68163953Srrs /* 69163953Srrs * Allow a user to take no more than 1/2 the number of clusters or 70163953Srrs * the SB_MAX whichever is smaller for the send window. 71163953Srrs */ 72163953Srrs sb_max_adj = (u_long)((u_quad_t) (SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES)); 73179783Srrs SCTP_BASE_SYSCTL(sctp_sendspace) = min(sb_max_adj, 74170056Srrs (((uint32_t) nmbclusters / 2) * SCTP_DEFAULT_MAXSEGMENT)); 75163953Srrs /* 76163953Srrs * Now for the recv window, should we take the same amount? or 77163953Srrs * should I do 1/2 the SB_MAX instead in the SB_MAX min above. For 78163953Srrs * now I will just copy. 79163953Srrs */ 80179783Srrs SCTP_BASE_SYSCTL(sctp_recvspace) = SCTP_BASE_SYSCTL(sctp_sendspace); 81179783Srrs SCTP_BASE_VAR(first_time) = 0; 82179783Srrs SCTP_BASE_VAR(sctp_pcb_initialized) = 0; 83179783Srrs sctp_pcb_init(); 84179783Srrs#if defined(SCTP_PACKET_LOGGING) 85179783Srrs SCTP_BASE_VAR(packet_log_writers) = 0; 86179783Srrs SCTP_BASE_VAR(packet_log_end) = 0; 87179783Srrs bzero(&SCTP_BASE_VAR(packet_log_buffer), SCTP_PACKET_LOG_SIZE); 88179783Srrs#endif 89163953Srrs} 90163953Srrs 91179783Srrsvoid 92179783Srrssctp_finish(void) 93179783Srrs{ 94179783Srrs sctp_pcb_finish(); 95179783Srrs} 96163953Srrs 97166023Srrs 98163953Srrs 99179157Srrsvoid 100228653Stuexensctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint16_t nxtsz) 101163953Srrs{ 102163953Srrs struct sctp_tmit_chunk *chk; 103197257Stuexen uint16_t overhead; 104163953Srrs 105163953Srrs /* Adjust that too */ 106163953Srrs stcb->asoc.smallest_mtu = nxtsz; 107163953Srrs /* now off to subtract IP_DF flag if needed */ 108197257Stuexen overhead = IP_HDR_SIZE; 109197257Stuexen if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) { 110197257Stuexen overhead += sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); 111197257Stuexen } 112163953Srrs TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) { 113197257Stuexen if ((chk->send_size + overhead) > nxtsz) { 114163953Srrs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 115163953Srrs } 116163953Srrs } 117163953Srrs TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 118197257Stuexen if ((chk->send_size + overhead) > nxtsz) { 119163953Srrs /* 120163953Srrs * For this guy we also mark for immediate resend 121163953Srrs * since we sent to big of chunk 122163953Srrs */ 123163953Srrs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 124190689Srrs if (chk->sent < SCTP_DATAGRAM_RESEND) { 125190689Srrs sctp_flight_size_decrease(chk); 126190689Srrs sctp_total_flight_decrease(stcb, chk); 127190689Srrs } 128163953Srrs if (chk->sent != SCTP_DATAGRAM_RESEND) { 129163953Srrs sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 130163953Srrs } 131163953Srrs chk->sent = SCTP_DATAGRAM_RESEND; 132163953Srrs chk->rec.data.doing_fast_retransmit = 0; 133179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { 134170744Srrs sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU, 135170744Srrs chk->whoTo->flight_size, 136170744Srrs chk->book_size, 137170744Srrs (uintptr_t) chk->whoTo, 138170744Srrs chk->rec.data.TSN_seq); 139170744Srrs } 140163953Srrs /* Clear any time so NO RTT is being done */ 141163953Srrs chk->do_rtt = 0; 142163953Srrs } 143163953Srrs } 144163953Srrs} 145163953Srrs 146221249Stuexen#ifdef INET 147163953Srrsstatic void 148163953Srrssctp_notify_mbuf(struct sctp_inpcb *inp, 149163953Srrs struct sctp_tcb *stcb, 150163953Srrs struct sctp_nets *net, 151163953Srrs struct ip *ip, 152163953Srrs struct sctphdr *sh) 153163953Srrs{ 154163953Srrs struct icmp *icmph; 155163953Srrs int totsz, tmr_stopped = 0; 156163953Srrs uint16_t nxtsz; 157163953Srrs 158163953Srrs /* protection */ 159163953Srrs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 160163953Srrs (ip == NULL) || (sh == NULL)) { 161169420Srrs if (stcb != NULL) { 162163953Srrs SCTP_TCB_UNLOCK(stcb); 163169420Srrs } 164163953Srrs return; 165163953Srrs } 166163953Srrs /* First job is to verify the vtag matches what I would send */ 167163953Srrs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 168163953Srrs SCTP_TCB_UNLOCK(stcb); 169163953Srrs return; 170163953Srrs } 171163953Srrs icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) - 172163953Srrs sizeof(struct ip))); 173163953Srrs if (icmph->icmp_type != ICMP_UNREACH) { 174163953Srrs /* We only care about unreachable */ 175163953Srrs SCTP_TCB_UNLOCK(stcb); 176163953Srrs return; 177163953Srrs } 178163953Srrs if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) { 179163953Srrs /* not a unreachable message due to frag. */ 180163953Srrs SCTP_TCB_UNLOCK(stcb); 181163953Srrs return; 182163953Srrs } 183241913Sglebius totsz = ntohs(ip->ip_len); 184163953Srrs 185171943Srrs nxtsz = ntohs(icmph->icmp_nextmtu); 186163953Srrs if (nxtsz == 0) { 187163953Srrs /* 188163953Srrs * old type router that does not tell us what the next size 189163953Srrs * mtu is. Rats we will have to guess (in a educated fashion 190163953Srrs * of course) 191163953Srrs */ 192214939Stuexen nxtsz = sctp_get_prev_mtu(totsz); 193163953Srrs } 194163953Srrs /* Stop any PMTU timer */ 195165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 196163953Srrs tmr_stopped = 1; 197165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 198165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1); 199163953Srrs } 200163953Srrs /* Adjust destination size limit */ 201163953Srrs if (net->mtu > nxtsz) { 202163953Srrs net->mtu = nxtsz; 203185694Srrs if (net->port) { 204185694Srrs net->mtu -= sizeof(struct udphdr); 205185694Srrs } 206163953Srrs } 207163953Srrs /* now what about the ep? */ 208163953Srrs if (stcb->asoc.smallest_mtu > nxtsz) { 209228653Stuexen sctp_pathmtu_adjustment(stcb, nxtsz); 210163953Srrs } 211163953Srrs if (tmr_stopped) 212163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 213163953Srrs 214163953Srrs SCTP_TCB_UNLOCK(stcb); 215163953Srrs} 216163953Srrs 217221249Stuexen#endif 218163953Srrs 219163953Srrsvoid 220163953Srrssctp_notify(struct sctp_inpcb *inp, 221172091Srrs struct ip *ip, 222163953Srrs struct sctphdr *sh, 223163953Srrs struct sockaddr *to, 224163953Srrs struct sctp_tcb *stcb, 225163953Srrs struct sctp_nets *net) 226163953Srrs{ 227237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 228172090Srrs struct socket *so; 229172090Srrs 230172090Srrs#endif 231172091Srrs struct icmp *icmph; 232172091Srrs 233235360Stuexen /* protection */ 234163953Srrs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 235163953Srrs (sh == NULL) || (to == NULL)) { 236172091Srrs if (stcb) 237172091Srrs SCTP_TCB_UNLOCK(stcb); 238163953Srrs return; 239163953Srrs } 240163953Srrs /* First job is to verify the vtag matches what I would send */ 241163953Srrs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 242172091Srrs SCTP_TCB_UNLOCK(stcb); 243163953Srrs return; 244163953Srrs } 245172091Srrs icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) - 246172091Srrs sizeof(struct ip))); 247172091Srrs if (icmph->icmp_type != ICMP_UNREACH) { 248172091Srrs /* We only care about unreachable */ 249172091Srrs SCTP_TCB_UNLOCK(stcb); 250172091Srrs return; 251172091Srrs } 252172091Srrs if ((icmph->icmp_code == ICMP_UNREACH_NET) || 253172091Srrs (icmph->icmp_code == ICMP_UNREACH_HOST) || 254172091Srrs (icmph->icmp_code == ICMP_UNREACH_NET_UNKNOWN) || 255172091Srrs (icmph->icmp_code == ICMP_UNREACH_HOST_UNKNOWN) || 256172091Srrs (icmph->icmp_code == ICMP_UNREACH_ISOLATED) || 257172091Srrs (icmph->icmp_code == ICMP_UNREACH_NET_PROHIB) || 258172091Srrs (icmph->icmp_code == ICMP_UNREACH_HOST_PROHIB) || 259172091Srrs (icmph->icmp_code == ICMP_UNREACH_FILTER_PROHIB)) { 260163953Srrs 261163953Srrs /* 262163953Srrs * Hmm reachablity problems we must examine closely. If its 263163953Srrs * not reachable, we may have lost a network. Or if there is 264163953Srrs * NO protocol at the other end named SCTP. well we consider 265163953Srrs * it a OOTB abort. 266163953Srrs */ 267172091Srrs if (net->dest_state & SCTP_ADDR_REACHABLE) { 268172091Srrs /* Ok that destination is NOT reachable */ 269172091Srrs net->dest_state &= ~SCTP_ADDR_REACHABLE; 270224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 271172091Srrs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, 272235414Stuexen stcb, 0, 273172091Srrs (void *)net, SCTP_SO_NOT_LOCKED); 274172091Srrs } 275172091Srrs SCTP_TCB_UNLOCK(stcb); 276172091Srrs } else if ((icmph->icmp_code == ICMP_UNREACH_PROTOCOL) || 277172091Srrs (icmph->icmp_code == ICMP_UNREACH_PORT)) { 278172091Srrs /* 279172091Srrs * Here the peer is either playing tricks on us, including 280172091Srrs * an address that belongs to someone who does not support 281172091Srrs * SCTP OR was a userland implementation that shutdown and 282172091Srrs * now is dead. In either case treat it like a OOTB abort 283172091Srrs * with no TCB 284172091Srrs */ 285235403Stuexen sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED); 286237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 287172091Srrs so = SCTP_INP_SO(inp); 288172091Srrs atomic_add_int(&stcb->asoc.refcnt, 1); 289172091Srrs SCTP_TCB_UNLOCK(stcb); 290172091Srrs SCTP_SOCKET_LOCK(so, 1); 291172091Srrs SCTP_TCB_LOCK(stcb); 292172091Srrs atomic_subtract_int(&stcb->asoc.refcnt, 1); 293172090Srrs#endif 294172091Srrs (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); 295237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 296172091Srrs SCTP_SOCKET_UNLOCK(so, 1); 297172091Srrs /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */ 298172090Srrs#endif 299172091Srrs /* no need to unlock here, since the TCB is gone */ 300163953Srrs } else { 301172091Srrs SCTP_TCB_UNLOCK(stcb); 302163953Srrs } 303163953Srrs} 304163953Srrs 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{ 550171943Srrs struct sctp_inpcb *inp = NULL; 551166086Srrs int error; 552163953Srrs 553225571Stuexen#ifdef INET 554171943Srrs if (addr && addr->sa_family != AF_INET) { 555163953Srrs /* must be a v4 address! */ 556171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 557228907Stuexen return (EINVAL); 558171943Srrs } 559163953Srrs#endif /* INET6 */ 560170056Srrs if (addr && (addr->sa_len != sizeof(struct sockaddr_in))) { 561171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 562228907Stuexen return (EINVAL); 563170056Srrs } 564163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 565233005Stuexen if (inp == NULL) { 566171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 567228907Stuexen return (EINVAL); 568171943Srrs } 569171572Srrs error = sctp_inpcb_bind(so, addr, NULL, p); 570228907Stuexen return (error); 571163953Srrs} 572163953Srrs 573221249Stuexen#endif 574171990Srrsvoid 575163953Srrssctp_close(struct socket *so) 576163953Srrs{ 577163953Srrs struct sctp_inpcb *inp; 578163953Srrs uint32_t flags; 579163953Srrs 580163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 581233005Stuexen if (inp == NULL) 582163953Srrs return; 583163953Srrs 584163953Srrs /* 585163953Srrs * Inform all the lower layer assoc that we are done. 586163953Srrs */ 587163953Srrssctp_must_try_again: 588163953Srrs flags = inp->sctp_flags; 589163953Srrs#ifdef SCTP_LOG_CLOSING 590163953Srrs sctp_log_closing(inp, NULL, 17); 591163953Srrs#endif 592163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 593163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 594163953Srrs if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || 595163953Srrs (so->so_rcv.sb_cc > 0)) { 596163953Srrs#ifdef SCTP_LOG_CLOSING 597163953Srrs sctp_log_closing(inp, NULL, 13); 598163953Srrs#endif 599169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 600169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 601163953Srrs } else { 602163953Srrs#ifdef SCTP_LOG_CLOSING 603163953Srrs sctp_log_closing(inp, NULL, 14); 604163953Srrs#endif 605169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE, 606169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 607163953Srrs } 608163953Srrs /* 609163953Srrs * The socket is now detached, no matter what the state of 610163953Srrs * the SCTP association. 611163953Srrs */ 612163953Srrs SOCK_LOCK(so); 613167695Srrs SCTP_SB_CLEAR(so->so_snd); 614163953Srrs /* 615163953Srrs * same for the rcv ones, they are only here for the 616163953Srrs * accounting/select. 617163953Srrs */ 618167695Srrs SCTP_SB_CLEAR(so->so_rcv); 619167695Srrs 620167695Srrs /* Now null out the reference, we are completely detached. */ 621163953Srrs so->so_pcb = NULL; 622163953Srrs SOCK_UNLOCK(so); 623163953Srrs } else { 624163953Srrs flags = inp->sctp_flags; 625163953Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 626163953Srrs goto sctp_must_try_again; 627163953Srrs } 628163953Srrs } 629163953Srrs return; 630163953Srrs} 631163953Srrs 632163953Srrs 633163953Srrsint 634163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 635163953Srrs struct mbuf *control, struct thread *p); 636163953Srrs 637163953Srrs 638163953Srrsint 639163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 640163953Srrs struct mbuf *control, struct thread *p) 641163953Srrs{ 642163953Srrs struct sctp_inpcb *inp; 643163953Srrs int error; 644163953Srrs 645163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 646233005Stuexen if (inp == NULL) { 647163953Srrs if (control) { 648163953Srrs sctp_m_freem(control); 649163953Srrs control = NULL; 650163953Srrs } 651171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 652163953Srrs sctp_m_freem(m); 653228907Stuexen return (EINVAL); 654163953Srrs } 655163953Srrs /* Got to have an to address if we are NOT a connected socket */ 656163953Srrs if ((addr == NULL) && 657163953Srrs ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) || 658228907Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE))) { 659163953Srrs goto connected_type; 660163953Srrs } else if (addr == NULL) { 661171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); 662163953Srrs error = EDESTADDRREQ; 663163953Srrs sctp_m_freem(m); 664163953Srrs if (control) { 665163953Srrs sctp_m_freem(control); 666163953Srrs control = NULL; 667163953Srrs } 668163953Srrs return (error); 669163953Srrs } 670163953Srrs#ifdef INET6 671163953Srrs if (addr->sa_family != AF_INET) { 672163953Srrs /* must be a v4 address! */ 673171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); 674163953Srrs sctp_m_freem(m); 675163953Srrs if (control) { 676163953Srrs sctp_m_freem(control); 677163953Srrs control = NULL; 678163953Srrs } 679163953Srrs error = EDESTADDRREQ; 680223132Stuexen return (error); 681163953Srrs } 682163953Srrs#endif /* INET6 */ 683163953Srrsconnected_type: 684163953Srrs /* now what about control */ 685163953Srrs if (control) { 686163953Srrs if (inp->control) { 687169420Srrs SCTP_PRINTF("huh? control set?\n"); 688163953Srrs sctp_m_freem(inp->control); 689163953Srrs inp->control = NULL; 690163953Srrs } 691163953Srrs inp->control = control; 692163953Srrs } 693163953Srrs /* Place the data */ 694163953Srrs if (inp->pkt) { 695165647Srrs SCTP_BUF_NEXT(inp->pkt_last) = m; 696163953Srrs inp->pkt_last = m; 697163953Srrs } else { 698163953Srrs inp->pkt_last = inp->pkt = m; 699163953Srrs } 700163953Srrs if ( 701163953Srrs /* FreeBSD uses a flag passed */ 702163953Srrs ((flags & PRUS_MORETOCOME) == 0) 703163953Srrs ) { 704163953Srrs /* 705163953Srrs * note with the current version this code will only be used 706163953Srrs * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for 707163953Srrs * re-defining sosend to use the sctp_sosend. One can 708163953Srrs * optionally switch back to this code (by changing back the 709163953Srrs * definitions) but this is not advisable. This code is used 710163953Srrs * by FreeBSD when sending a file with sendfile() though. 711163953Srrs */ 712163953Srrs int ret; 713163953Srrs 714163953Srrs ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags); 715163953Srrs inp->pkt = NULL; 716163953Srrs inp->control = NULL; 717163953Srrs return (ret); 718163953Srrs } else { 719163953Srrs return (0); 720163953Srrs } 721163953Srrs} 722163953Srrs 723171990Srrsint 724163953Srrssctp_disconnect(struct socket *so) 725163953Srrs{ 726163953Srrs struct sctp_inpcb *inp; 727163953Srrs 728163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 729163953Srrs if (inp == NULL) { 730171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 731163953Srrs return (ENOTCONN); 732163953Srrs } 733163953Srrs SCTP_INP_RLOCK(inp); 734171745Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 735171745Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 736199437Stuexen if (LIST_EMPTY(&inp->sctp_asoc_list)) { 737163953Srrs /* No connection */ 738163953Srrs SCTP_INP_RUNLOCK(inp); 739163953Srrs return (0); 740163953Srrs } else { 741163953Srrs struct sctp_association *asoc; 742163953Srrs struct sctp_tcb *stcb; 743163953Srrs 744163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 745163953Srrs if (stcb == NULL) { 746163953Srrs SCTP_INP_RUNLOCK(inp); 747171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 748163953Srrs return (EINVAL); 749163953Srrs } 750163953Srrs SCTP_TCB_LOCK(stcb); 751163953Srrs asoc = &stcb->asoc; 752163953Srrs if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 753163953Srrs /* We are about to be freed, out of here */ 754163953Srrs SCTP_TCB_UNLOCK(stcb); 755163953Srrs SCTP_INP_RUNLOCK(inp); 756163953Srrs return (0); 757163953Srrs } 758163953Srrs if (((so->so_options & SO_LINGER) && 759163953Srrs (so->so_linger == 0)) || 760163953Srrs (so->so_rcv.sb_cc > 0)) { 761163953Srrs if (SCTP_GET_STATE(asoc) != 762163953Srrs SCTP_STATE_COOKIE_WAIT) { 763163953Srrs /* Left with Data unread */ 764163953Srrs struct mbuf *err; 765163953Srrs 766243882Sglebius err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA); 767163953Srrs if (err) { 768163953Srrs /* 769163953Srrs * Fill in the user 770163953Srrs * initiated abort 771163953Srrs */ 772163953Srrs struct sctp_paramhdr *ph; 773163953Srrs 774163953Srrs ph = mtod(err, struct sctp_paramhdr *); 775165647Srrs SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr); 776163953Srrs ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); 777165647Srrs ph->param_length = htons(SCTP_BUF_LEN(err)); 778163953Srrs } 779172090Srrs sctp_send_abort_tcb(stcb, err, SCTP_SO_LOCKED); 780163953Srrs SCTP_STAT_INCR_COUNTER32(sctps_aborted); 781163953Srrs } 782163953Srrs SCTP_INP_RUNLOCK(inp); 783163953Srrs if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 784163953Srrs (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 785163953Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 786163953Srrs } 787171943Srrs (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3); 788163953Srrs /* No unlock tcb assoc is gone */ 789163953Srrs return (0); 790163953Srrs } 791163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 792163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 793163953Srrs (asoc->stream_queue_cnt == 0)) { 794163953Srrs /* there is nothing queued to send, so done */ 795163953Srrs if (asoc->locked_on_sending) { 796163953Srrs goto abort_anyway; 797163953Srrs } 798166675Srrs if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) && 799166675Srrs (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { 800163953Srrs /* only send SHUTDOWN 1st time thru */ 801224641Stuexen struct sctp_nets *netp; 802224641Stuexen 803224641Stuexen if (stcb->asoc.alternate) { 804224641Stuexen netp = stcb->asoc.alternate; 805224641Stuexen } else { 806224641Stuexen netp = stcb->asoc.primary_destination; 807224641Stuexen } 808163953Srrs sctp_stop_timers_for_shutdown(stcb); 809224641Stuexen sctp_send_shutdown(stcb, netp); 810172090Srrs sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); 811166675Srrs if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 812166675Srrs (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 813166675Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 814166675Srrs } 815171943Srrs SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); 816172703Srrs SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 817163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 818224641Stuexen stcb->sctp_ep, stcb, netp); 819163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 820224641Stuexen stcb->sctp_ep, stcb, netp); 821224641Stuexen 822163953Srrs } 823163953Srrs } else { 824163953Srrs /* 825163953Srrs * we still got (or just got) data to send, 826163953Srrs * so set SHUTDOWN_PENDING 827163953Srrs */ 828163953Srrs /* 829163953Srrs * XXX sockets draft says that SCTP_EOF 830163953Srrs * should be sent with no data. currently, 831163953Srrs * we will allow user data to be sent first 832163953Srrs * and move to SHUTDOWN-PENDING 833163953Srrs */ 834224641Stuexen struct sctp_nets *netp; 835224641Stuexen 836224641Stuexen if (stcb->asoc.alternate) { 837224641Stuexen netp = stcb->asoc.alternate; 838224641Stuexen } else { 839224641Stuexen netp = stcb->asoc.primary_destination; 840224641Stuexen } 841224641Stuexen 842163953Srrs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 843163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, 844224641Stuexen netp); 845163953Srrs if (asoc->locked_on_sending) { 846163953Srrs /* Locked to send out the data */ 847163953Srrs struct sctp_stream_queue_pending *sp; 848163953Srrs 849163953Srrs sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); 850163953Srrs if (sp == NULL) { 851169420Srrs SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", 852163953Srrs asoc->locked_on_sending->stream_no); 853163953Srrs } else { 854163953Srrs if ((sp->length == 0) && (sp->msg_is_complete == 0)) 855163953Srrs asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; 856163953Srrs } 857163953Srrs } 858163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 859163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 860163953Srrs (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 861163953Srrs struct mbuf *op_err; 862163953Srrs 863163953Srrs abort_anyway: 864163953Srrs op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 865243882Sglebius 0, M_NOWAIT, 1, MT_DATA); 866163953Srrs if (op_err) { 867163953Srrs /* 868163953Srrs * Fill in the user 869163953Srrs * initiated abort 870163953Srrs */ 871163953Srrs struct sctp_paramhdr *ph; 872163953Srrs uint32_t *ippp; 873163953Srrs 874165647Srrs SCTP_BUF_LEN(op_err) = 875163953Srrs (sizeof(struct sctp_paramhdr) + sizeof(uint32_t)); 876163953Srrs ph = mtod(op_err, 877163953Srrs struct sctp_paramhdr *); 878163953Srrs ph->param_type = htons( 879163953Srrs SCTP_CAUSE_USER_INITIATED_ABT); 880165647Srrs ph->param_length = htons(SCTP_BUF_LEN(op_err)); 881163953Srrs ippp = (uint32_t *) (ph + 1); 882165220Srrs *ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4); 883163953Srrs } 884165220Srrs stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4; 885172090Srrs sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED); 886163953Srrs SCTP_STAT_INCR_COUNTER32(sctps_aborted); 887163953Srrs if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 888163953Srrs (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 889163953Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 890163953Srrs } 891163953Srrs SCTP_INP_RUNLOCK(inp); 892171943Srrs (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5); 893163953Srrs return (0); 894171990Srrs } else { 895172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); 896163953Srrs } 897163953Srrs } 898188067Srrs soisdisconnecting(so); 899163953Srrs SCTP_TCB_UNLOCK(stcb); 900163953Srrs SCTP_INP_RUNLOCK(inp); 901163953Srrs return (0); 902163953Srrs } 903163953Srrs /* not reached */ 904163953Srrs } else { 905163953Srrs /* UDP model does not support this */ 906163953Srrs SCTP_INP_RUNLOCK(inp); 907171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 908228907Stuexen return (EOPNOTSUPP); 909163953Srrs } 910163953Srrs} 911163953Srrs 912163953Srrsint 913178202Srrssctp_flush(struct socket *so, int how) 914178202Srrs{ 915178202Srrs /* 916178202Srrs * We will just clear out the values and let subsequent close clear 917178202Srrs * out the data, if any. Note if the user did a shutdown(SHUT_RD) 918178202Srrs * they will not be able to read the data, the socket will block 919178202Srrs * that from happening. 920178202Srrs */ 921209289Stuexen struct sctp_inpcb *inp; 922209289Stuexen 923209289Stuexen inp = (struct sctp_inpcb *)so->so_pcb; 924209289Stuexen if (inp == NULL) { 925209289Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 926228907Stuexen return (EINVAL); 927209289Stuexen } 928209289Stuexen SCTP_INP_RLOCK(inp); 929209289Stuexen /* For the 1 to many model this does nothing */ 930209289Stuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 931209289Stuexen SCTP_INP_RUNLOCK(inp); 932209289Stuexen return (0); 933209289Stuexen } 934209289Stuexen SCTP_INP_RUNLOCK(inp); 935178202Srrs if ((how == PRU_FLUSH_RD) || (how == PRU_FLUSH_RDWR)) { 936178202Srrs /* 937178202Srrs * First make sure the sb will be happy, we don't use these 938178202Srrs * except maybe the count 939178202Srrs */ 940209289Stuexen SCTP_INP_WLOCK(inp); 941209289Stuexen SCTP_INP_READ_LOCK(inp); 942209289Stuexen inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ; 943209289Stuexen SCTP_INP_READ_UNLOCK(inp); 944209289Stuexen SCTP_INP_WUNLOCK(inp); 945178202Srrs so->so_rcv.sb_cc = 0; 946178202Srrs so->so_rcv.sb_mbcnt = 0; 947178202Srrs so->so_rcv.sb_mb = NULL; 948178202Srrs } 949178202Srrs if ((how == PRU_FLUSH_WR) || (how == PRU_FLUSH_RDWR)) { 950178202Srrs /* 951178202Srrs * First make sure the sb will be happy, we don't use these 952178202Srrs * except maybe the count 953178202Srrs */ 954178202Srrs so->so_snd.sb_cc = 0; 955178202Srrs so->so_snd.sb_mbcnt = 0; 956178202Srrs so->so_snd.sb_mb = NULL; 957178202Srrs 958178202Srrs } 959178202Srrs return (0); 960178202Srrs} 961178202Srrs 962178202Srrsint 963163953Srrssctp_shutdown(struct socket *so) 964163953Srrs{ 965163953Srrs struct sctp_inpcb *inp; 966163953Srrs 967163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 968233005Stuexen if (inp == NULL) { 969171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 970228907Stuexen return (EINVAL); 971163953Srrs } 972163953Srrs SCTP_INP_RLOCK(inp); 973163953Srrs /* For UDP model this is a invalid call */ 974243558Stuexen if (!((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 975243558Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { 976163953Srrs /* Restore the flags that the soshutdown took away. */ 977204096Stuexen SOCKBUF_LOCK(&so->so_rcv); 978163953Srrs so->so_rcv.sb_state &= ~SBS_CANTRCVMORE; 979204096Stuexen SOCKBUF_UNLOCK(&so->so_rcv); 980163953Srrs /* This proc will wakeup for read and do nothing (I hope) */ 981163953Srrs SCTP_INP_RUNLOCK(inp); 982171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 983163953Srrs return (EOPNOTSUPP); 984163953Srrs } 985163953Srrs /* 986163953Srrs * Ok if we reach here its the TCP model and it is either a SHUT_WR 987163953Srrs * or SHUT_RDWR. This means we put the shutdown flag against it. 988163953Srrs */ 989163953Srrs { 990163953Srrs struct sctp_tcb *stcb; 991163953Srrs struct sctp_association *asoc; 992163953Srrs 993188067Srrs if ((so->so_state & 994188067Srrs (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) { 995188067Srrs SCTP_INP_RUNLOCK(inp); 996188067Srrs return (ENOTCONN); 997188067Srrs } 998163953Srrs socantsendmore(so); 999163953Srrs 1000163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 1001163953Srrs if (stcb == NULL) { 1002163953Srrs /* 1003163953Srrs * Ok we hit the case that the shutdown call was 1004163953Srrs * made after an abort or something. Nothing to do 1005163953Srrs * now. 1006163953Srrs */ 1007168299Srrs SCTP_INP_RUNLOCK(inp); 1008163953Srrs return (0); 1009163953Srrs } 1010163953Srrs SCTP_TCB_LOCK(stcb); 1011163953Srrs asoc = &stcb->asoc; 1012163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 1013163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 1014163953Srrs (asoc->stream_queue_cnt == 0)) { 1015163953Srrs if (asoc->locked_on_sending) { 1016163953Srrs goto abort_anyway; 1017163953Srrs } 1018163953Srrs /* there is nothing queued to send, so I'm done... */ 1019163953Srrs if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { 1020163953Srrs /* only send SHUTDOWN the first time through */ 1021224641Stuexen struct sctp_nets *netp; 1022224641Stuexen 1023224641Stuexen if (stcb->asoc.alternate) { 1024224641Stuexen netp = stcb->asoc.alternate; 1025224641Stuexen } else { 1026224641Stuexen netp = stcb->asoc.primary_destination; 1027224641Stuexen } 1028163953Srrs sctp_stop_timers_for_shutdown(stcb); 1029224641Stuexen sctp_send_shutdown(stcb, netp); 1030172218Srrs sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); 1031166675Srrs if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 1032166675Srrs (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 1033166675Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 1034166675Srrs } 1035171943Srrs SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); 1036172703Srrs SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 1037163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 1038224641Stuexen stcb->sctp_ep, stcb, netp); 1039163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 1040224641Stuexen stcb->sctp_ep, stcb, netp); 1041163953Srrs } 1042163953Srrs } else { 1043163953Srrs /* 1044163953Srrs * we still got (or just got) data to send, so set 1045163953Srrs * SHUTDOWN_PENDING 1046163953Srrs */ 1047224641Stuexen struct sctp_nets *netp; 1048224641Stuexen 1049224641Stuexen if (stcb->asoc.alternate) { 1050224641Stuexen netp = stcb->asoc.alternate; 1051224641Stuexen } else { 1052224641Stuexen netp = stcb->asoc.primary_destination; 1053224641Stuexen } 1054224641Stuexen 1055163953Srrs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 1056163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, 1057224641Stuexen netp); 1058163953Srrs 1059163953Srrs if (asoc->locked_on_sending) { 1060163953Srrs /* Locked to send out the data */ 1061163953Srrs struct sctp_stream_queue_pending *sp; 1062163953Srrs 1063163953Srrs sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); 1064163953Srrs if (sp == NULL) { 1065169420Srrs SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", 1066163953Srrs asoc->locked_on_sending->stream_no); 1067163953Srrs } else { 1068163953Srrs if ((sp->length == 0) && (sp->msg_is_complete == 0)) { 1069163953Srrs asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; 1070163953Srrs } 1071163953Srrs } 1072163953Srrs } 1073163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 1074163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 1075163953Srrs (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 1076163953Srrs struct mbuf *op_err; 1077163953Srrs 1078163953Srrs abort_anyway: 1079163953Srrs op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 1080243882Sglebius 0, M_NOWAIT, 1, MT_DATA); 1081163953Srrs if (op_err) { 1082163953Srrs /* Fill in the user initiated abort */ 1083163953Srrs struct sctp_paramhdr *ph; 1084163953Srrs uint32_t *ippp; 1085163953Srrs 1086165647Srrs SCTP_BUF_LEN(op_err) = 1087163953Srrs sizeof(struct sctp_paramhdr) + sizeof(uint32_t); 1088163953Srrs ph = mtod(op_err, 1089163953Srrs struct sctp_paramhdr *); 1090163953Srrs ph->param_type = htons( 1091163953Srrs SCTP_CAUSE_USER_INITIATED_ABT); 1092165647Srrs ph->param_length = htons(SCTP_BUF_LEN(op_err)); 1093163953Srrs ippp = (uint32_t *) (ph + 1); 1094165220Srrs *ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6); 1095163953Srrs } 1096165220Srrs stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6; 1097163953Srrs sctp_abort_an_association(stcb->sctp_ep, stcb, 1098172090Srrs op_err, SCTP_SO_LOCKED); 1099163953Srrs goto skip_unlock; 1100171990Srrs } else { 1101172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); 1102163953Srrs } 1103163953Srrs } 1104163953Srrs SCTP_TCB_UNLOCK(stcb); 1105163953Srrs } 1106163953Srrsskip_unlock: 1107163953Srrs SCTP_INP_RUNLOCK(inp); 1108228907Stuexen return (0); 1109163953Srrs} 1110163953Srrs 1111163953Srrs/* 1112163953Srrs * copies a "user" presentable address and removes embedded scope, etc. 1113163953Srrs * returns 0 on success, 1 on error 1114163953Srrs */ 1115163953Srrsstatic uint32_t 1116163953Srrssctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa) 1117163953Srrs{ 1118178251Srrs#ifdef INET6 1119163953Srrs struct sockaddr_in6 lsa6; 1120163953Srrs 1121163953Srrs sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa, 1122163953Srrs &lsa6); 1123178251Srrs#endif 1124163953Srrs memcpy(ss, sa, sa->sa_len); 1125163953Srrs return (0); 1126163953Srrs} 1127163953Srrs 1128163953Srrs 1129163953Srrs 1130172091Srrs/* 1131172091Srrs * NOTE: assumes addr lock is held 1132172091Srrs */ 1133166675Srrsstatic size_t 1134168124Srrssctp_fill_up_addresses_vrf(struct sctp_inpcb *inp, 1135163953Srrs struct sctp_tcb *stcb, 1136166675Srrs size_t limit, 1137167598Srrs struct sockaddr_storage *sas, 1138167598Srrs uint32_t vrf_id) 1139163953Srrs{ 1140167598Srrs struct sctp_ifn *sctp_ifn; 1141167598Srrs struct sctp_ifa *sctp_ifa; 1142166675Srrs int loopback_scope, ipv4_local_scope, local_scope, site_scope; 1143166675Srrs size_t actual; 1144163953Srrs int ipv4_addr_legal, ipv6_addr_legal; 1145167598Srrs struct sctp_vrf *vrf; 1146163953Srrs 1147163953Srrs actual = 0; 1148163953Srrs if (limit <= 0) 1149163953Srrs return (actual); 1150163953Srrs 1151163953Srrs if (stcb) { 1152163953Srrs /* Turn on all the appropriate scope */ 1153163953Srrs loopback_scope = stcb->asoc.loopback_scope; 1154163953Srrs ipv4_local_scope = stcb->asoc.ipv4_local_scope; 1155163953Srrs local_scope = stcb->asoc.local_scope; 1156163953Srrs site_scope = stcb->asoc.site_scope; 1157163953Srrs } else { 1158163953Srrs /* Turn on ALL scope, since we look at the EP */ 1159163953Srrs loopback_scope = ipv4_local_scope = local_scope = 1160163953Srrs site_scope = 1; 1161163953Srrs } 1162163953Srrs ipv4_addr_legal = ipv6_addr_legal = 0; 1163163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 1164163953Srrs ipv6_addr_legal = 1; 1165166023Srrs if (SCTP_IPV6_V6ONLY(inp) == 0) { 1166163953Srrs ipv4_addr_legal = 1; 1167163953Srrs } 1168163953Srrs } else { 1169163953Srrs ipv4_addr_legal = 1; 1170163953Srrs } 1171167598Srrs vrf = sctp_find_vrf(vrf_id); 1172167598Srrs if (vrf == NULL) { 1173167598Srrs return (0); 1174167598Srrs } 1175163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1176167598Srrs LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 1177163953Srrs if ((loopback_scope == 0) && 1178167598Srrs SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { 1179163953Srrs /* Skip loopback if loopback_scope not set */ 1180163953Srrs continue; 1181163953Srrs } 1182167598Srrs LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 1183163953Srrs if (stcb) { 1184163953Srrs /* 1185163953Srrs * For the BOUND-ALL case, the list 1186163953Srrs * associated with a TCB is Always 1187163953Srrs * considered a reverse list.. i.e. 1188163953Srrs * it lists addresses that are NOT 1189163953Srrs * part of the association. If this 1190163953Srrs * is one of those we must skip it. 1191163953Srrs */ 1192163953Srrs if (sctp_is_addr_restricted(stcb, 1193167598Srrs sctp_ifa)) { 1194163953Srrs continue; 1195163953Srrs } 1196163953Srrs } 1197178251Srrs switch (sctp_ifa->address.sa.sa_family) { 1198221249Stuexen#ifdef INET 1199178251Srrs case AF_INET: 1200178251Srrs if (ipv4_addr_legal) { 1201178251Srrs struct sockaddr_in *sin; 1202163953Srrs 1203178251Srrs sin = (struct sockaddr_in *)&sctp_ifa->address.sa; 1204178251Srrs if (sin->sin_addr.s_addr == 0) { 1205178251Srrs /* 1206178251Srrs * we skip 1207178251Srrs * unspecifed 1208178251Srrs * addresses 1209178251Srrs */ 1210178251Srrs continue; 1211178251Srrs } 1212178251Srrs if ((ipv4_local_scope == 0) && 1213178251Srrs (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { 1214178251Srrs continue; 1215178251Srrs } 1216178251Srrs#ifdef INET6 1217178251Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 1218178251Srrs in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas); 1219178251Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1220178251Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6)); 1221178251Srrs actual += sizeof(struct sockaddr_in6); 1222178251Srrs } else { 1223178251Srrs#endif 1224178251Srrs memcpy(sas, sin, sizeof(*sin)); 1225178251Srrs ((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport; 1226178251Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin)); 1227178251Srrs actual += sizeof(*sin); 1228178251Srrs#ifdef INET6 1229178251Srrs } 1230178251Srrs#endif 1231178251Srrs if (actual >= limit) { 1232178251Srrs return (actual); 1233178251Srrs } 1234178251Srrs } else { 1235163953Srrs continue; 1236163953Srrs } 1237178251Srrs break; 1238221249Stuexen#endif 1239178251Srrs#ifdef INET6 1240178251Srrs case AF_INET6: 1241178251Srrs if (ipv6_addr_legal) { 1242178251Srrs struct sockaddr_in6 *sin6; 1243163953Srrs 1244178251Srrs sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa; 1245178251Srrs if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 1246178251Srrs /* 1247178251Srrs * we skip 1248178251Srrs * unspecifed 1249178251Srrs * addresses 1250178251Srrs */ 1251163953Srrs continue; 1252178251Srrs } 1253178251Srrs if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 1254178251Srrs if (local_scope == 0) 1255163953Srrs continue; 1256178251Srrs if (sin6->sin6_scope_id == 0) { 1257178251Srrs if (sa6_recoverscope(sin6) != 0) 1258178251Srrs /* 1259178251Srrs * 1260178251Srrs * bad 1261178251Srrs * 1262178251Srrs * li 1263178251Srrs * nk 1264178251Srrs * 1265178251Srrs * loc 1266178251Srrs * al 1267178251Srrs * 1268178251Srrs * add 1269178251Srrs * re 1270178251Srrs * ss 1271178251Srrs * */ 1272178251Srrs continue; 1273178251Srrs } 1274163953Srrs } 1275178251Srrs if ((site_scope == 0) && 1276178251Srrs (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { 1277178251Srrs continue; 1278178251Srrs } 1279178251Srrs memcpy(sas, sin6, sizeof(*sin6)); 1280178251Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1281178251Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6)); 1282178251Srrs actual += sizeof(*sin6); 1283178251Srrs if (actual >= limit) { 1284178251Srrs return (actual); 1285178251Srrs } 1286178251Srrs } else { 1287163953Srrs continue; 1288163953Srrs } 1289178251Srrs break; 1290178251Srrs#endif 1291178251Srrs default: 1292178251Srrs /* TSNH */ 1293178251Srrs break; 1294163953Srrs } 1295163953Srrs } 1296163953Srrs } 1297163953Srrs } else { 1298163953Srrs struct sctp_laddr *laddr; 1299163953Srrs 1300167598Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1301167598Srrs if (stcb) { 1302167598Srrs if (sctp_is_addr_restricted(stcb, laddr->ifa)) { 1303163953Srrs continue; 1304163953Srrs } 1305163953Srrs } 1306167598Srrs if (sctp_fill_user_address(sas, &laddr->ifa->address.sa)) 1307167598Srrs continue; 1308167598Srrs 1309167598Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1310167598Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + 1311167598Srrs laddr->ifa->address.sa.sa_len); 1312167598Srrs actual += laddr->ifa->address.sa.sa_len; 1313167598Srrs if (actual >= limit) { 1314167598Srrs return (actual); 1315163953Srrs } 1316163953Srrs } 1317163953Srrs } 1318163953Srrs return (actual); 1319163953Srrs} 1320163953Srrs 1321168124Srrsstatic size_t 1322168124Srrssctp_fill_up_addresses(struct sctp_inpcb *inp, 1323168124Srrs struct sctp_tcb *stcb, 1324168124Srrs size_t limit, 1325168124Srrs struct sockaddr_storage *sas) 1326168124Srrs{ 1327168124Srrs size_t size = 0; 1328168124Srrs 1329172218Srrs SCTP_IPI_ADDR_RLOCK(); 1330168124Srrs /* fill up addresses for the endpoint's default vrf */ 1331168124Srrs size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas, 1332168124Srrs inp->def_vrf_id); 1333172218Srrs SCTP_IPI_ADDR_RUNLOCK(); 1334168124Srrs return (size); 1335168124Srrs} 1336168124Srrs 1337172091Srrs/* 1338172091Srrs * NOTE: assumes addr lock is held 1339172091Srrs */ 1340163953Srrsstatic int 1341168124Srrssctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) 1342163953Srrs{ 1343163953Srrs int cnt = 0; 1344167598Srrs struct sctp_vrf *vrf = NULL; 1345163953Srrs 1346163953Srrs /* 1347163953Srrs * In both sub-set bound an bound_all cases we return the MAXIMUM 1348163953Srrs * number of addresses that you COULD get. In reality the sub-set 1349163953Srrs * bound may have an exclusion list for a given TCB OR in the 1350163953Srrs * bound-all case a TCB may NOT include the loopback or other 1351163953Srrs * addresses as well. 1352163953Srrs */ 1353167598Srrs vrf = sctp_find_vrf(vrf_id); 1354167598Srrs if (vrf == NULL) { 1355167598Srrs return (0); 1356167598Srrs } 1357163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1358167598Srrs struct sctp_ifn *sctp_ifn; 1359167598Srrs struct sctp_ifa *sctp_ifa; 1360163953Srrs 1361167598Srrs LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 1362167598Srrs LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 1363163953Srrs /* Count them if they are the right type */ 1364221249Stuexen switch (sctp_ifa->address.sa.sa_family) { 1365221249Stuexen#ifdef INET 1366221249Stuexen case AF_INET: 1367178251Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) 1368163953Srrs cnt += sizeof(struct sockaddr_in6); 1369163953Srrs else 1370163953Srrs cnt += sizeof(struct sockaddr_in); 1371221249Stuexen break; 1372221249Stuexen#endif 1373221249Stuexen#ifdef INET6 1374221249Stuexen case AF_INET6: 1375163953Srrs cnt += sizeof(struct sockaddr_in6); 1376221249Stuexen break; 1377221249Stuexen#endif 1378221249Stuexen default: 1379221249Stuexen break; 1380221249Stuexen } 1381163953Srrs } 1382163953Srrs } 1383163953Srrs } else { 1384163953Srrs struct sctp_laddr *laddr; 1385163953Srrs 1386163953Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1387221249Stuexen switch (laddr->ifa->address.sa.sa_family) { 1388221249Stuexen#ifdef INET 1389221249Stuexen case AF_INET: 1390178251Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) 1391163953Srrs cnt += sizeof(struct sockaddr_in6); 1392163953Srrs else 1393163953Srrs cnt += sizeof(struct sockaddr_in); 1394221249Stuexen break; 1395221249Stuexen#endif 1396221249Stuexen#ifdef INET6 1397221249Stuexen case AF_INET6: 1398163953Srrs cnt += sizeof(struct sockaddr_in6); 1399221249Stuexen break; 1400221249Stuexen#endif 1401221249Stuexen default: 1402221249Stuexen break; 1403221249Stuexen } 1404163953Srrs } 1405163953Srrs } 1406163953Srrs return (cnt); 1407163953Srrs} 1408163953Srrs 1409168124Srrsstatic int 1410168124Srrssctp_count_max_addresses(struct sctp_inpcb *inp) 1411168124Srrs{ 1412168124Srrs int cnt = 0; 1413166675Srrs 1414172218Srrs SCTP_IPI_ADDR_RLOCK(); 1415168124Srrs /* count addresses for the endpoint's default VRF */ 1416168124Srrs cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id); 1417172218Srrs SCTP_IPI_ADDR_RUNLOCK(); 1418168124Srrs return (cnt); 1419168124Srrs} 1420168124Srrs 1421163953Srrsstatic int 1422166675Srrssctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, 1423166675Srrs size_t optsize, void *p, int delay) 1424163953Srrs{ 1425163953Srrs int error = 0; 1426163953Srrs int creat_lock_on = 0; 1427163953Srrs struct sctp_tcb *stcb = NULL; 1428163953Srrs struct sockaddr *sa; 1429169352Srrs int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr; 1430167598Srrs uint32_t vrf_id; 1431170056Srrs int bad_addresses = 0; 1432167598Srrs sctp_assoc_t *a_id; 1433163953Srrs 1434169420Srrs SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n"); 1435163953Srrs 1436163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 1437163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 1438163953Srrs /* We are already connected AND the TCP model */ 1439171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 1440163953Srrs return (EADDRINUSE); 1441163953Srrs } 1442181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && 1443181054Srrs (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) { 1444171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1445163953Srrs return (EINVAL); 1446163953Srrs } 1447163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 1448163953Srrs SCTP_INP_RLOCK(inp); 1449163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 1450163953Srrs SCTP_INP_RUNLOCK(inp); 1451163953Srrs } 1452163953Srrs if (stcb) { 1453171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 1454163953Srrs return (EALREADY); 1455163953Srrs } 1456163953Srrs SCTP_INP_INCR_REF(inp); 1457163953Srrs SCTP_ASOC_CREATE_LOCK(inp); 1458163953Srrs creat_lock_on = 1; 1459163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 1460163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 1461171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); 1462163953Srrs error = EFAULT; 1463163953Srrs goto out_now; 1464163953Srrs } 1465166675Srrs totaddrp = (int *)optval; 1466163953Srrs totaddr = *totaddrp; 1467163953Srrs sa = (struct sockaddr *)(totaddrp + 1); 1468170056Srrs stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses); 1469170056Srrs if ((stcb != NULL) || bad_addresses) { 1470169352Srrs /* Already have or am bring up an association */ 1471169352Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1472169352Srrs creat_lock_on = 0; 1473170931Srrs if (stcb) 1474170931Srrs SCTP_TCB_UNLOCK(stcb); 1475171943Srrs if (bad_addresses == 0) { 1476171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 1477170056Srrs error = EALREADY; 1478171943Srrs } 1479169352Srrs goto out_now; 1480163953Srrs } 1481163953Srrs#ifdef INET6 1482163953Srrs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 1483163953Srrs (num_v6 > 0)) { 1484163953Srrs error = EINVAL; 1485163953Srrs goto out_now; 1486163953Srrs } 1487163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 1488163953Srrs (num_v4 > 0)) { 1489163953Srrs struct in6pcb *inp6; 1490163953Srrs 1491163953Srrs inp6 = (struct in6pcb *)inp; 1492166023Srrs if (SCTP_IPV6_V6ONLY(inp6)) { 1493163953Srrs /* 1494163953Srrs * if IPV6_V6ONLY flag, ignore connections destined 1495163953Srrs * to a v4 addr or v4-mapped addr 1496163953Srrs */ 1497171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1498163953Srrs error = EINVAL; 1499163953Srrs goto out_now; 1500163953Srrs } 1501163953Srrs } 1502163953Srrs#endif /* INET6 */ 1503163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 1504163953Srrs SCTP_PCB_FLAGS_UNBOUND) { 1505163953Srrs /* Bind a ephemeral port */ 1506171572Srrs error = sctp_inpcb_bind(so, NULL, NULL, p); 1507163953Srrs if (error) { 1508163953Srrs goto out_now; 1509163953Srrs } 1510163953Srrs } 1511167695Srrs /* FIX ME: do we want to pass in a vrf on the connect call? */ 1512167695Srrs vrf_id = inp->def_vrf_id; 1513167695Srrs 1514181054Srrs 1515163953Srrs /* We are GOOD to go */ 1516206137Stuexen stcb = sctp_aloc_assoc(inp, sa, &error, 0, vrf_id, 1517171531Srrs (struct thread *)p 1518171531Srrs ); 1519163953Srrs if (stcb == NULL) { 1520163953Srrs /* Gak! no memory */ 1521163953Srrs goto out_now; 1522163953Srrs } 1523225559Stuexen if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 1524225559Stuexen stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 1525225559Stuexen /* Set the connected flag so we can queue data */ 1526225559Stuexen soisconnecting(so); 1527225559Stuexen } 1528171943Srrs SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); 1529163953Srrs /* move to second address */ 1530221249Stuexen switch (sa->sa_family) { 1531221249Stuexen#ifdef INET 1532221249Stuexen case AF_INET: 1533163953Srrs sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in)); 1534221249Stuexen break; 1535221249Stuexen#endif 1536221249Stuexen#ifdef INET6 1537221249Stuexen case AF_INET6: 1538163953Srrs sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6)); 1539221249Stuexen break; 1540221249Stuexen#endif 1541221249Stuexen default: 1542221249Stuexen break; 1543221249Stuexen } 1544163953Srrs 1545170056Srrs error = 0; 1546223132Stuexen sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error); 1547167598Srrs /* Fill in the return id */ 1548170056Srrs if (error) { 1549207924Srrs (void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6); 1550170056Srrs goto out_now; 1551170056Srrs } 1552167598Srrs a_id = (sctp_assoc_t *) optval; 1553167598Srrs *a_id = sctp_get_associd(stcb); 1554163953Srrs 1555163953Srrs /* initialize authentication parameters for the assoc */ 1556163953Srrs sctp_initialize_auth_params(inp, stcb); 1557163953Srrs 1558163953Srrs if (delay) { 1559163953Srrs /* doing delayed connection */ 1560163953Srrs stcb->asoc.delayed_connection = 1; 1561163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination); 1562163953Srrs } else { 1563169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 1564172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 1565163953Srrs } 1566163953Srrs SCTP_TCB_UNLOCK(stcb); 1567163953Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 1568163953Srrs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 1569163953Srrs /* Set the connected flag so we can queue data */ 1570163953Srrs soisconnecting(so); 1571163953Srrs } 1572163953Srrsout_now: 1573169655Srrs if (creat_lock_on) { 1574163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1575169655Srrs } 1576163953Srrs SCTP_INP_DECR_REF(inp); 1577228907Stuexen return (error); 1578163953Srrs} 1579163953Srrs 1580169420Srrs#define SCTP_FIND_STCB(inp, stcb, assoc_id) { \ 1581169655Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||\ 1582169655Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { \ 1583166675Srrs SCTP_INP_RLOCK(inp); \ 1584166675Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); \ 1585169655Srrs if (stcb) { \ 1586166675Srrs SCTP_TCB_LOCK(stcb); \ 1587169655Srrs } \ 1588166675Srrs SCTP_INP_RUNLOCK(inp); \ 1589223132Stuexen } else if (assoc_id > SCTP_ALL_ASSOC) { \ 1590166675Srrs stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \ 1591166675Srrs if (stcb == NULL) { \ 1592171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \ 1593166675Srrs error = ENOENT; \ 1594166675Srrs break; \ 1595166675Srrs } \ 1596166675Srrs } else { \ 1597166675Srrs stcb = NULL; \ 1598169420Srrs } \ 1599169420Srrs } 1600163953Srrs 1601169420Srrs 1602234464Stuexen#define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\ 1603166675Srrs if (size < sizeof(type)) { \ 1604171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); \ 1605166675Srrs error = EINVAL; \ 1606166675Srrs break; \ 1607166675Srrs } else { \ 1608166675Srrs destp = (type *)srcp; \ 1609169420Srrs } \ 1610169420Srrs } 1611163953Srrs 1612163953Srrsstatic int 1613166675Srrssctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, 1614166675Srrs void *p) 1615163953Srrs{ 1616171943Srrs struct sctp_inpcb *inp = NULL; 1617166675Srrs int error, val = 0; 1618163953Srrs struct sctp_tcb *stcb = NULL; 1619163953Srrs 1620166675Srrs if (optval == NULL) { 1621171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1622166675Srrs return (EINVAL); 1623166675Srrs } 1624163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 1625233005Stuexen if (inp == NULL) { 1626171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1627163953Srrs return EINVAL; 1628171943Srrs } 1629163953Srrs error = 0; 1630163953Srrs 1631166675Srrs switch (optname) { 1632163953Srrs case SCTP_NODELAY: 1633163953Srrs case SCTP_AUTOCLOSE: 1634163953Srrs case SCTP_EXPLICIT_EOR: 1635163953Srrs case SCTP_AUTO_ASCONF: 1636163953Srrs case SCTP_DISABLE_FRAGMENTS: 1637163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 1638163953Srrs case SCTP_USE_EXT_RCVINFO: 1639163953Srrs SCTP_INP_RLOCK(inp); 1640166675Srrs switch (optname) { 1641163953Srrs case SCTP_DISABLE_FRAGMENTS: 1642166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT); 1643163953Srrs break; 1644163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 1645166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4); 1646163953Srrs break; 1647163953Srrs case SCTP_AUTO_ASCONF: 1648171943Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1649171943Srrs /* only valid for bound all sockets */ 1650171943Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); 1651171943Srrs } else { 1652171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1653171943Srrs error = EINVAL; 1654171943Srrs goto flags_out; 1655171943Srrs } 1656163953Srrs break; 1657163953Srrs case SCTP_EXPLICIT_EOR: 1658166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); 1659163953Srrs break; 1660163953Srrs case SCTP_NODELAY: 1661166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY); 1662163953Srrs break; 1663163953Srrs case SCTP_USE_EXT_RCVINFO: 1664166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO); 1665163953Srrs break; 1666163953Srrs case SCTP_AUTOCLOSE: 1667163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) 1668166675Srrs val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time); 1669163953Srrs else 1670166675Srrs val = 0; 1671163953Srrs break; 1672163953Srrs 1673163953Srrs default: 1674171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 1675163953Srrs error = ENOPROTOOPT; 1676163953Srrs } /* end switch (sopt->sopt_name) */ 1677166675Srrs if (*optsize < sizeof(val)) { 1678171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1679163953Srrs error = EINVAL; 1680163953Srrs } 1681171943Srrsflags_out: 1682163953Srrs SCTP_INP_RUNLOCK(inp); 1683163953Srrs if (error == 0) { 1684163953Srrs /* return the option value */ 1685166675Srrs *(int *)optval = val; 1686166675Srrs *optsize = sizeof(val); 1687163953Srrs } 1688163953Srrs break; 1689170091Srrs case SCTP_GET_PACKET_LOG: 1690170091Srrs { 1691170091Srrs#ifdef SCTP_PACKET_LOGGING 1692170091Srrs uint8_t *target; 1693170091Srrs int ret; 1694167598Srrs 1695170091Srrs SCTP_CHECK_AND_CAST(target, optval, uint8_t, *optsize); 1696170091Srrs ret = sctp_copy_out_packet_log(target, (int)*optsize); 1697170091Srrs *optsize = ret; 1698170091Srrs#else 1699171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 1700170091Srrs error = EOPNOTSUPP; 1701170091Srrs#endif 1702170091Srrs break; 1703170091Srrs } 1704181054Srrs case SCTP_REUSE_PORT: 1705181054Srrs { 1706181054Srrs uint32_t *value; 1707181054Srrs 1708181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) { 1709181054Srrs /* Can't do this for a 1-m socket */ 1710181054Srrs error = EINVAL; 1711181054Srrs break; 1712181054Srrs } 1713181054Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1714181054Srrs *value = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE); 1715181054Srrs *optsize = sizeof(uint32_t); 1716223132Stuexen break; 1717181054Srrs } 1718163953Srrs case SCTP_PARTIAL_DELIVERY_POINT: 1719163953Srrs { 1720166675Srrs uint32_t *value; 1721166675Srrs 1722166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1723166675Srrs *value = inp->partial_delivery_point; 1724166675Srrs *optsize = sizeof(uint32_t); 1725223132Stuexen break; 1726163953Srrs } 1727163953Srrs case SCTP_FRAGMENT_INTERLEAVE: 1728163953Srrs { 1729166675Srrs uint32_t *value; 1730166675Srrs 1731166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1732168943Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) { 1733168943Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) { 1734168943Srrs *value = SCTP_FRAG_LEVEL_2; 1735168943Srrs } else { 1736168943Srrs *value = SCTP_FRAG_LEVEL_1; 1737168943Srrs } 1738168943Srrs } else { 1739168943Srrs *value = SCTP_FRAG_LEVEL_0; 1740168943Srrs } 1741166675Srrs *optsize = sizeof(uint32_t); 1742223132Stuexen break; 1743163953Srrs } 1744163953Srrs case SCTP_CMT_ON_OFF: 1745163953Srrs { 1746166675Srrs struct sctp_assoc_value *av; 1747166675Srrs 1748166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1749211944Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1750211944Stuexen if (stcb) { 1751211944Stuexen av->assoc_value = stcb->asoc.sctp_cmt_on_off; 1752211944Stuexen SCTP_TCB_UNLOCK(stcb); 1753166675Srrs } else { 1754224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1755224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1756224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1757223132Stuexen SCTP_INP_RLOCK(inp); 1758223132Stuexen av->assoc_value = inp->sctp_cmt_on_off; 1759223132Stuexen SCTP_INP_RUNLOCK(inp); 1760223132Stuexen } else { 1761223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1762223132Stuexen error = EINVAL; 1763223132Stuexen } 1764163953Srrs } 1765223132Stuexen if (error == 0) { 1766223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1767223132Stuexen } 1768223132Stuexen break; 1769163953Srrs } 1770171440Srrs case SCTP_PLUGGABLE_CC: 1771171440Srrs { 1772171440Srrs struct sctp_assoc_value *av; 1773171440Srrs 1774171440Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1775171440Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1776171440Srrs if (stcb) { 1777171440Srrs av->assoc_value = stcb->asoc.congestion_control_module; 1778171440Srrs SCTP_TCB_UNLOCK(stcb); 1779171440Srrs } else { 1780224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1781224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1782224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1783223132Stuexen SCTP_INP_RLOCK(inp); 1784223132Stuexen av->assoc_value = inp->sctp_ep.sctp_default_cc_module; 1785223132Stuexen SCTP_INP_RUNLOCK(inp); 1786223132Stuexen } else { 1787223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1788223132Stuexen error = EINVAL; 1789223132Stuexen } 1790171440Srrs } 1791223132Stuexen if (error == 0) { 1792223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1793223132Stuexen } 1794223132Stuexen break; 1795171440Srrs } 1796219057Srrs case SCTP_CC_OPTION: 1797219057Srrs { 1798219057Srrs struct sctp_cc_option *cc_opt; 1799219057Srrs 1800219057Srrs SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, *optsize); 1801219057Srrs SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id); 1802219057Srrs if (stcb == NULL) { 1803219057Srrs error = EINVAL; 1804219057Srrs } else { 1805219057Srrs if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) { 1806219057Srrs error = ENOTSUP; 1807219057Srrs } else { 1808223132Stuexen error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 0, cc_opt); 1809223132Stuexen *optsize = sizeof(struct sctp_cc_option); 1810219057Srrs } 1811219057Srrs SCTP_TCB_UNLOCK(stcb); 1812219057Srrs } 1813223132Stuexen break; 1814219057Srrs } 1815217760Stuexen case SCTP_PLUGGABLE_SS: 1816217760Stuexen { 1817217760Stuexen struct sctp_assoc_value *av; 1818217760Stuexen 1819217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1820217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1821217760Stuexen if (stcb) { 1822217760Stuexen av->assoc_value = stcb->asoc.stream_scheduling_module; 1823217760Stuexen SCTP_TCB_UNLOCK(stcb); 1824217760Stuexen } else { 1825224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1826224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1827224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1828223132Stuexen SCTP_INP_RLOCK(inp); 1829223132Stuexen av->assoc_value = inp->sctp_ep.sctp_default_ss_module; 1830223132Stuexen SCTP_INP_RUNLOCK(inp); 1831223132Stuexen } else { 1832223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1833223132Stuexen error = EINVAL; 1834223132Stuexen } 1835217760Stuexen } 1836223132Stuexen if (error == 0) { 1837223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1838223132Stuexen } 1839223132Stuexen break; 1840217760Stuexen } 1841217760Stuexen case SCTP_SS_VALUE: 1842217760Stuexen { 1843217760Stuexen struct sctp_stream_value *av; 1844217760Stuexen 1845217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize); 1846217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1847217760Stuexen if (stcb) { 1848217760Stuexen if (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], 1849217760Stuexen &av->stream_value) < 0) { 1850217760Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1851217760Stuexen error = EINVAL; 1852217760Stuexen } else { 1853223132Stuexen *optsize = sizeof(struct sctp_stream_value); 1854217760Stuexen } 1855217760Stuexen SCTP_TCB_UNLOCK(stcb); 1856217760Stuexen } else { 1857217760Stuexen /* 1858217760Stuexen * Can't get stream value without 1859217760Stuexen * association 1860217760Stuexen */ 1861217760Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1862217760Stuexen error = EINVAL; 1863217760Stuexen } 1864223132Stuexen break; 1865217760Stuexen } 1866163953Srrs case SCTP_GET_ADDR_LEN: 1867163953Srrs { 1868163953Srrs struct sctp_assoc_value *av; 1869163953Srrs 1870166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1871163953Srrs error = EINVAL; 1872167598Srrs#ifdef INET 1873163953Srrs if (av->assoc_value == AF_INET) { 1874163953Srrs av->assoc_value = sizeof(struct sockaddr_in); 1875163953Srrs error = 0; 1876163953Srrs } 1877163953Srrs#endif 1878167598Srrs#ifdef INET6 1879163953Srrs if (av->assoc_value == AF_INET6) { 1880163953Srrs av->assoc_value = sizeof(struct sockaddr_in6); 1881163953Srrs error = 0; 1882163953Srrs } 1883163953Srrs#endif 1884172091Srrs if (error) { 1885171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1886223132Stuexen } else { 1887223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1888172091Srrs } 1889223132Stuexen break; 1890163953Srrs } 1891169655Srrs case SCTP_GET_ASSOC_NUMBER: 1892163953Srrs { 1893169655Srrs uint32_t *value, cnt; 1894163953Srrs 1895169655Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1896163953Srrs cnt = 0; 1897163953Srrs SCTP_INP_RLOCK(inp); 1898169655Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 1899169655Srrs cnt++; 1900163953Srrs } 1901169655Srrs SCTP_INP_RUNLOCK(inp); 1902169655Srrs *value = cnt; 1903169655Srrs *optsize = sizeof(uint32_t); 1904223132Stuexen break; 1905169655Srrs } 1906169655Srrs case SCTP_GET_ASSOC_ID_LIST: 1907169655Srrs { 1908169655Srrs struct sctp_assoc_ids *ids; 1909169655Srrs unsigned int at, limit; 1910169655Srrs 1911169655Srrs SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize); 1912163953Srrs at = 0; 1913185694Srrs limit = (*optsize - sizeof(uint32_t)) / sizeof(sctp_assoc_t); 1914169655Srrs SCTP_INP_RLOCK(inp); 1915169655Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 1916169655Srrs if (at < limit) { 1917169655Srrs ids->gaids_assoc_id[at++] = sctp_get_associd(stcb); 1918169655Srrs } else { 1919169655Srrs error = EINVAL; 1920171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1921163953Srrs break; 1922163953Srrs } 1923163953Srrs } 1924163953Srrs SCTP_INP_RUNLOCK(inp); 1925223132Stuexen if (error == 0) { 1926223132Stuexen ids->gaids_number_of_ids = at; 1927223132Stuexen *optsize = ((at * sizeof(sctp_assoc_t)) + sizeof(uint32_t)); 1928223132Stuexen } 1929223132Stuexen break; 1930163953Srrs } 1931163953Srrs case SCTP_CONTEXT: 1932163953Srrs { 1933163953Srrs struct sctp_assoc_value *av; 1934163953Srrs 1935166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1936166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1937166675Srrs 1938166675Srrs if (stcb) { 1939166675Srrs av->assoc_value = stcb->asoc.context; 1940166675Srrs SCTP_TCB_UNLOCK(stcb); 1941163953Srrs } else { 1942224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1943224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1944224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1945223132Stuexen SCTP_INP_RLOCK(inp); 1946223132Stuexen av->assoc_value = inp->sctp_context; 1947223132Stuexen SCTP_INP_RUNLOCK(inp); 1948223132Stuexen } else { 1949223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1950223132Stuexen error = EINVAL; 1951223132Stuexen } 1952163953Srrs } 1953223132Stuexen if (error == 0) { 1954223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1955223132Stuexen } 1956223132Stuexen break; 1957163953Srrs } 1958167598Srrs case SCTP_VRF_ID: 1959167598Srrs { 1960170056Srrs uint32_t *default_vrfid; 1961167598Srrs 1962170056Srrs SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize); 1963170056Srrs *default_vrfid = inp->def_vrf_id; 1964223132Stuexen *optsize = sizeof(uint32_t); 1965167598Srrs break; 1966167598Srrs } 1967167598Srrs case SCTP_GET_ASOC_VRF: 1968167598Srrs { 1969167598Srrs struct sctp_assoc_value *id; 1970167598Srrs 1971167598Srrs SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize); 1972167598Srrs SCTP_FIND_STCB(inp, stcb, id->assoc_id); 1973167598Srrs if (stcb == NULL) { 1974167598Srrs error = EINVAL; 1975171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1976223132Stuexen } else { 1977223132Stuexen id->assoc_value = stcb->asoc.vrf_id; 1978223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1979167598Srrs } 1980167598Srrs break; 1981167598Srrs } 1982167598Srrs case SCTP_GET_VRF_IDS: 1983167598Srrs { 1984171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 1985167598Srrs error = EOPNOTSUPP; 1986167598Srrs break; 1987167598Srrs } 1988163953Srrs case SCTP_GET_NONCE_VALUES: 1989163953Srrs { 1990163953Srrs struct sctp_get_nonce_values *gnv; 1991163953Srrs 1992166675Srrs SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize); 1993166675Srrs SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id); 1994166675Srrs 1995166675Srrs if (stcb) { 1996163953Srrs gnv->gn_peers_tag = stcb->asoc.peer_vtag; 1997163953Srrs gnv->gn_local_tag = stcb->asoc.my_vtag; 1998163953Srrs SCTP_TCB_UNLOCK(stcb); 1999223132Stuexen *optsize = sizeof(struct sctp_get_nonce_values); 2000166675Srrs } else { 2001171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 2002166675Srrs error = ENOTCONN; 2003163953Srrs } 2004223132Stuexen break; 2005163953Srrs } 2006170056Srrs case SCTP_DELAYED_SACK: 2007163953Srrs { 2008170056Srrs struct sctp_sack_info *sack; 2009163953Srrs 2010170056Srrs SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, *optsize); 2011170056Srrs SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); 2012166675Srrs if (stcb) { 2013170056Srrs sack->sack_delay = stcb->asoc.delayed_ack; 2014170056Srrs sack->sack_freq = stcb->asoc.sack_freq; 2015166675Srrs SCTP_TCB_UNLOCK(stcb); 2016166675Srrs } else { 2017224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2018224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2019224918Stuexen (sack->sack_assoc_id == SCTP_FUTURE_ASSOC)) { 2020223132Stuexen SCTP_INP_RLOCK(inp); 2021223132Stuexen sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); 2022223132Stuexen sack->sack_freq = inp->sctp_ep.sctp_sack_freq; 2023223132Stuexen SCTP_INP_RUNLOCK(inp); 2024223132Stuexen } else { 2025223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2026223132Stuexen error = EINVAL; 2027223132Stuexen } 2028163953Srrs } 2029223132Stuexen if (error == 0) { 2030223132Stuexen *optsize = sizeof(struct sctp_sack_info); 2031223132Stuexen } 2032223132Stuexen break; 2033163953Srrs } 2034163953Srrs case SCTP_GET_SNDBUF_USE: 2035166675Srrs { 2036163953Srrs struct sctp_sockstat *ss; 2037163953Srrs 2038166675Srrs SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize); 2039166675Srrs SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id); 2040166675Srrs 2041166675Srrs if (stcb) { 2042166675Srrs ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size; 2043166675Srrs ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue + 2044166675Srrs stcb->asoc.size_on_all_streams); 2045166675Srrs SCTP_TCB_UNLOCK(stcb); 2046223132Stuexen *optsize = sizeof(struct sctp_sockstat); 2047166675Srrs } else { 2048171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 2049163953Srrs error = ENOTCONN; 2050163953Srrs } 2051223132Stuexen break; 2052163953Srrs } 2053170056Srrs case SCTP_MAX_BURST: 2054163953Srrs { 2055217895Stuexen struct sctp_assoc_value *av; 2056163953Srrs 2057217895Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 2058217895Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2059166675Srrs 2060217895Stuexen if (stcb) { 2061217895Stuexen av->assoc_value = stcb->asoc.max_burst; 2062217895Stuexen SCTP_TCB_UNLOCK(stcb); 2063217894Stuexen } else { 2064224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2065224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2066224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 2067223132Stuexen SCTP_INP_RLOCK(inp); 2068223132Stuexen av->assoc_value = inp->sctp_ep.max_burst; 2069223132Stuexen SCTP_INP_RUNLOCK(inp); 2070223132Stuexen } else { 2071223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2072223132Stuexen error = EINVAL; 2073223132Stuexen } 2074217894Stuexen } 2075223132Stuexen if (error == 0) { 2076223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 2077223132Stuexen } 2078223132Stuexen break; 2079163953Srrs } 2080163953Srrs case SCTP_MAXSEG: 2081163953Srrs { 2082167598Srrs struct sctp_assoc_value *av; 2083163953Srrs int ovh; 2084163953Srrs 2085167598Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 2086170056Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2087163953Srrs 2088167598Srrs if (stcb) { 2089167598Srrs av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc); 2090167598Srrs SCTP_TCB_UNLOCK(stcb); 2091163953Srrs } else { 2092224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2093224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2094224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 2095223132Stuexen SCTP_INP_RLOCK(inp); 2096223132Stuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2097223132Stuexen ovh = SCTP_MED_OVERHEAD; 2098223132Stuexen } else { 2099223132Stuexen ovh = SCTP_MED_V4_OVERHEAD; 2100223132Stuexen } 2101223132Stuexen if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT) 2102223132Stuexen av->assoc_value = 0; 2103223132Stuexen else 2104223132Stuexen av->assoc_value = inp->sctp_frag_point - ovh; 2105223132Stuexen SCTP_INP_RUNLOCK(inp); 2106167598Srrs } else { 2107223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2108223132Stuexen error = EINVAL; 2109167598Srrs } 2110163953Srrs } 2111223132Stuexen if (error == 0) { 2112223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 2113223132Stuexen } 2114223132Stuexen break; 2115163953Srrs } 2116163953Srrs case SCTP_GET_STAT_LOG: 2117167598Srrs error = sctp_fill_stat_log(optval, optsize); 2118163953Srrs break; 2119163953Srrs case SCTP_EVENTS: 2120163953Srrs { 2121163953Srrs struct sctp_event_subscribe *events; 2122163953Srrs 2123166675Srrs SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize); 2124223132Stuexen memset(events, 0, sizeof(struct sctp_event_subscribe)); 2125163953Srrs SCTP_INP_RLOCK(inp); 2126163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) 2127163953Srrs events->sctp_data_io_event = 1; 2128163953Srrs 2129163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT)) 2130163953Srrs events->sctp_association_event = 1; 2131163953Srrs 2132163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT)) 2133163953Srrs events->sctp_address_event = 1; 2134163953Srrs 2135163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) 2136163953Srrs events->sctp_send_failure_event = 1; 2137163953Srrs 2138163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR)) 2139163953Srrs events->sctp_peer_error_event = 1; 2140163953Srrs 2141163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) 2142163953Srrs events->sctp_shutdown_event = 1; 2143163953Srrs 2144163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT)) 2145163953Srrs events->sctp_partial_delivery_event = 1; 2146163953Srrs 2147163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) 2148163953Srrs events->sctp_adaptation_layer_event = 1; 2149163953Srrs 2150163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT)) 2151163953Srrs events->sctp_authentication_event = 1; 2152163953Srrs 2153185694Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT)) 2154185694Srrs events->sctp_sender_dry_event = 1; 2155185694Srrs 2156163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) 2157202520Srrs events->sctp_stream_reset_event = 1; 2158163953Srrs SCTP_INP_RUNLOCK(inp); 2159166675Srrs *optsize = sizeof(struct sctp_event_subscribe); 2160223132Stuexen break; 2161163953Srrs } 2162163953Srrs case SCTP_ADAPTATION_LAYER: 2163166675Srrs { 2164166675Srrs uint32_t *value; 2165166675Srrs 2166166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2167166675Srrs 2168166675Srrs SCTP_INP_RLOCK(inp); 2169166675Srrs *value = inp->sctp_ep.adaptation_layer_indicator; 2170166675Srrs SCTP_INP_RUNLOCK(inp); 2171166675Srrs *optsize = sizeof(uint32_t); 2172223132Stuexen break; 2173163953Srrs } 2174163953Srrs case SCTP_SET_INITIAL_DBG_SEQ: 2175166675Srrs { 2176166675Srrs uint32_t *value; 2177166675Srrs 2178166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2179166675Srrs SCTP_INP_RLOCK(inp); 2180166675Srrs *value = inp->sctp_ep.initial_sequence_debug; 2181166675Srrs SCTP_INP_RUNLOCK(inp); 2182166675Srrs *optsize = sizeof(uint32_t); 2183223132Stuexen break; 2184163953Srrs } 2185163953Srrs case SCTP_GET_LOCAL_ADDR_SIZE: 2186166675Srrs { 2187166675Srrs uint32_t *value; 2188166675Srrs 2189166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2190166675Srrs SCTP_INP_RLOCK(inp); 2191168124Srrs *value = sctp_count_max_addresses(inp); 2192166675Srrs SCTP_INP_RUNLOCK(inp); 2193166675Srrs *optsize = sizeof(uint32_t); 2194223132Stuexen break; 2195163953Srrs } 2196163953Srrs case SCTP_GET_REMOTE_ADDR_SIZE: 2197163953Srrs { 2198166675Srrs uint32_t *value; 2199166675Srrs size_t size; 2200163953Srrs struct sctp_nets *net; 2201163953Srrs 2202166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2203166675Srrs /* FIXME MT: change to sctp_assoc_value? */ 2204166675Srrs SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value); 2205166675Srrs 2206166675Srrs if (stcb) { 2207166675Srrs size = 0; 2208166675Srrs /* Count the sizes */ 2209166675Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 2210221249Stuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 2211166675Srrs size += sizeof(struct sockaddr_in6); 2212166675Srrs } else { 2213221249Stuexen switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) { 2214221249Stuexen#ifdef INET 2215221249Stuexen case AF_INET: 2216221249Stuexen size += sizeof(struct sockaddr_in); 2217221249Stuexen break; 2218221249Stuexen#endif 2219221249Stuexen#ifdef INET6 2220221249Stuexen case AF_INET6: 2221221249Stuexen size += sizeof(struct sockaddr_in6); 2222221249Stuexen break; 2223221249Stuexen#endif 2224221249Stuexen default: 2225221249Stuexen break; 2226221249Stuexen } 2227166675Srrs } 2228163953Srrs } 2229166675Srrs SCTP_TCB_UNLOCK(stcb); 2230166675Srrs *value = (uint32_t) size; 2231223132Stuexen *optsize = sizeof(uint32_t); 2232166675Srrs } else { 2233171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 2234166675Srrs error = ENOTCONN; 2235163953Srrs } 2236223132Stuexen break; 2237163953Srrs } 2238163953Srrs case SCTP_GET_PEER_ADDRESSES: 2239163953Srrs /* 2240163953Srrs * Get the address information, an array is passed in to 2241163953Srrs * fill up we pack it. 2242163953Srrs */ 2243163953Srrs { 2244166675Srrs size_t cpsz, left; 2245163953Srrs struct sockaddr_storage *sas; 2246163953Srrs struct sctp_nets *net; 2247163953Srrs struct sctp_getaddresses *saddr; 2248163953Srrs 2249166675Srrs SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); 2250166675Srrs SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); 2251163953Srrs 2252166675Srrs if (stcb) { 2253166675Srrs left = (*optsize) - sizeof(struct sctp_getaddresses); 2254166675Srrs *optsize = sizeof(struct sctp_getaddresses); 2255166675Srrs sas = (struct sockaddr_storage *)&saddr->addr[0]; 2256166675Srrs 2257166675Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 2258221249Stuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 2259166675Srrs cpsz = sizeof(struct sockaddr_in6); 2260166675Srrs } else { 2261221249Stuexen switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) { 2262221249Stuexen#ifdef INET 2263221249Stuexen case AF_INET: 2264221249Stuexen cpsz = sizeof(struct sockaddr_in); 2265221249Stuexen break; 2266221249Stuexen#endif 2267221249Stuexen#ifdef INET6 2268221249Stuexen case AF_INET6: 2269221249Stuexen cpsz = sizeof(struct sockaddr_in6); 2270221249Stuexen break; 2271221249Stuexen#endif 2272221249Stuexen default: 2273221249Stuexen cpsz = 0; 2274221249Stuexen break; 2275221249Stuexen } 2276221249Stuexen } 2277221249Stuexen if (cpsz == 0) { 2278166675Srrs break; 2279166675Srrs } 2280166675Srrs if (left < cpsz) { 2281166675Srrs /* not enough room. */ 2282166675Srrs break; 2283166675Srrs } 2284221249Stuexen#if defined(INET) && defined(INET6) 2285178251Srrs if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) && 2286166675Srrs (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET)) { 2287166675Srrs /* Must map the address */ 2288166675Srrs in6_sin_2_v4mapsin6((struct sockaddr_in *)&net->ro._l_addr, 2289166675Srrs (struct sockaddr_in6 *)sas); 2290166675Srrs } else { 2291178251Srrs#endif 2292166675Srrs memcpy(sas, &net->ro._l_addr, cpsz); 2293221249Stuexen#if defined(INET) && defined(INET6) 2294166675Srrs } 2295178251Srrs#endif 2296166675Srrs ((struct sockaddr_in *)sas)->sin_port = stcb->rport; 2297166675Srrs 2298166675Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz); 2299166675Srrs left -= cpsz; 2300166675Srrs *optsize += cpsz; 2301163953Srrs } 2302166675Srrs SCTP_TCB_UNLOCK(stcb); 2303166675Srrs } else { 2304171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 2305166675Srrs error = ENOENT; 2306163953Srrs } 2307223132Stuexen break; 2308163953Srrs } 2309163953Srrs case SCTP_GET_LOCAL_ADDRESSES: 2310163953Srrs { 2311166675Srrs size_t limit, actual; 2312163953Srrs struct sockaddr_storage *sas; 2313163953Srrs struct sctp_getaddresses *saddr; 2314163953Srrs 2315166675Srrs SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); 2316166675Srrs SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); 2317163953Srrs 2318163953Srrs sas = (struct sockaddr_storage *)&saddr->addr[0]; 2319166675Srrs limit = *optsize - sizeof(sctp_assoc_t); 2320168124Srrs actual = sctp_fill_up_addresses(inp, stcb, limit, sas); 2321169655Srrs if (stcb) { 2322163953Srrs SCTP_TCB_UNLOCK(stcb); 2323169655Srrs } 2324166675Srrs *optsize = sizeof(struct sockaddr_storage) + actual; 2325223132Stuexen break; 2326163953Srrs } 2327163953Srrs case SCTP_PEER_ADDR_PARAMS: 2328163953Srrs { 2329163953Srrs struct sctp_paddrparams *paddrp; 2330163953Srrs struct sctp_nets *net; 2331163953Srrs 2332166675Srrs SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize); 2333166675Srrs SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); 2334163953Srrs 2335163953Srrs net = NULL; 2336166675Srrs if (stcb) { 2337166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address); 2338166675Srrs } else { 2339166675Srrs /* 2340166675Srrs * We increment here since 2341166675Srrs * sctp_findassociation_ep_addr() wil do a 2342166675Srrs * decrement if it finds the stcb as long as 2343166675Srrs * the locked tcb (last argument) is NOT a 2344166675Srrs * TCB.. aka NULL. 2345166675Srrs */ 2346166675Srrs SCTP_INP_INCR_REF(inp); 2347166675Srrs stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddrp->spp_address, &net, NULL, NULL); 2348163953Srrs if (stcb == NULL) { 2349166675Srrs SCTP_INP_DECR_REF(inp); 2350163953Srrs } 2351163953Srrs } 2352171943Srrs if (stcb && (net == NULL)) { 2353171943Srrs struct sockaddr *sa; 2354163953Srrs 2355171943Srrs sa = (struct sockaddr *)&paddrp->spp_address; 2356221249Stuexen#ifdef INET 2357171943Srrs if (sa->sa_family == AF_INET) { 2358171943Srrs struct sockaddr_in *sin; 2359171943Srrs 2360171943Srrs sin = (struct sockaddr_in *)sa; 2361171943Srrs if (sin->sin_addr.s_addr) { 2362171943Srrs error = EINVAL; 2363171943Srrs SCTP_TCB_UNLOCK(stcb); 2364171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2365171943Srrs break; 2366171943Srrs } 2367221249Stuexen } else 2368221249Stuexen#endif 2369221249Stuexen#ifdef INET6 2370221249Stuexen if (sa->sa_family == AF_INET6) { 2371171943Srrs struct sockaddr_in6 *sin6; 2372171943Srrs 2373171943Srrs sin6 = (struct sockaddr_in6 *)sa; 2374171943Srrs if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 2375171943Srrs error = EINVAL; 2376171943Srrs SCTP_TCB_UNLOCK(stcb); 2377171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2378171943Srrs break; 2379171943Srrs } 2380221249Stuexen } else 2381221249Stuexen#endif 2382221249Stuexen { 2383171943Srrs error = EAFNOSUPPORT; 2384171943Srrs SCTP_TCB_UNLOCK(stcb); 2385171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2386171943Srrs break; 2387171943Srrs } 2388171943Srrs } 2389163953Srrs if (stcb) { 2390224641Stuexen /* Applies to the specific association */ 2391163953Srrs paddrp->spp_flags = 0; 2392163953Srrs if (net) { 2393170056Srrs int ovh; 2394170056Srrs 2395170056Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2396170056Srrs ovh = SCTP_MED_OVERHEAD; 2397170056Srrs } else { 2398170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 2399170056Srrs } 2400170056Srrs 2401224641Stuexen paddrp->spp_hbinterval = net->heart_beat_delay; 2402163953Srrs paddrp->spp_pathmaxrxt = net->failure_threshold; 2403170056Srrs paddrp->spp_pathmtu = net->mtu - ovh; 2404163953Srrs /* get flags for HB */ 2405225635Stuexen if (net->dest_state & SCTP_ADDR_NOHB) { 2406163953Srrs paddrp->spp_flags |= SPP_HB_DISABLE; 2407225635Stuexen } else { 2408163953Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 2409225635Stuexen } 2410163953Srrs /* get flags for PMTU */ 2411225635Stuexen if (net->dest_state & SCTP_ADDR_NO_PMTUD) { 2412163953Srrs paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2413163953Srrs } else { 2414163953Srrs paddrp->spp_flags |= SPP_PMTUD_DISABLE; 2415163953Srrs } 2416225549Stuexen if (net->dscp & 0x01) { 2417226252Stuexen paddrp->spp_dscp = net->dscp & 0xfc; 2418224870Stuexen paddrp->spp_flags |= SPP_DSCP; 2419163953Srrs } 2420167598Srrs#ifdef INET6 2421225549Stuexen if ((net->ro._l_addr.sa.sa_family == AF_INET6) && 2422225549Stuexen (net->flowlabel & 0x80000000)) { 2423225549Stuexen paddrp->spp_ipv6_flowlabel = net->flowlabel & 0x000fffff; 2424163953Srrs paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2425163953Srrs } 2426163953Srrs#endif 2427163953Srrs } else { 2428163953Srrs /* 2429163953Srrs * No destination so return default 2430163953Srrs * value 2431163953Srrs */ 2432163953Srrs paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure; 2433163953Srrs paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc); 2434225549Stuexen if (stcb->asoc.default_dscp & 0x01) { 2435226252Stuexen paddrp->spp_dscp = stcb->asoc.default_dscp & 0xfc; 2436225549Stuexen paddrp->spp_flags |= SPP_DSCP; 2437225549Stuexen } 2438167598Srrs#ifdef INET6 2439225549Stuexen if (stcb->asoc.default_flowlabel & 0x80000000) { 2440225549Stuexen paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel & 0x000fffff; 2441225549Stuexen paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2442225549Stuexen } 2443163953Srrs#endif 2444163953Srrs /* default settings should be these */ 2445225635Stuexen if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { 2446224641Stuexen paddrp->spp_flags |= SPP_HB_DISABLE; 2447224641Stuexen } else { 2448163953Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 2449163953Srrs } 2450225635Stuexen if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) { 2451225635Stuexen paddrp->spp_flags |= SPP_PMTUD_DISABLE; 2452225635Stuexen } else { 2453170056Srrs paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2454170056Srrs } 2455225635Stuexen paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay; 2456163953Srrs } 2457163953Srrs paddrp->spp_assoc_id = sctp_get_associd(stcb); 2458163953Srrs SCTP_TCB_UNLOCK(stcb); 2459163953Srrs } else { 2460224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2461224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2462224918Stuexen (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) { 2463223132Stuexen /* Use endpoint defaults */ 2464223132Stuexen SCTP_INP_RLOCK(inp); 2465223132Stuexen paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure; 2466223132Stuexen paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); 2467223132Stuexen paddrp->spp_assoc_id = SCTP_FUTURE_ASSOC; 2468223132Stuexen /* get inp's default */ 2469225549Stuexen if (inp->sctp_ep.default_dscp & 0x01) { 2470226252Stuexen paddrp->spp_dscp = inp->sctp_ep.default_dscp & 0xfc; 2471225549Stuexen paddrp->spp_flags |= SPP_DSCP; 2472225549Stuexen } 2473167598Srrs#ifdef INET6 2474225549Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 2475225549Stuexen (inp->sctp_ep.default_flowlabel & 0x80000000)) { 2476225549Stuexen paddrp->spp_ipv6_flowlabel = inp->sctp_ep.default_flowlabel & 0x000fffff; 2477223132Stuexen paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2478223132Stuexen } 2479163953Srrs#endif 2480223132Stuexen /* can't return this */ 2481223132Stuexen paddrp->spp_pathmtu = 0; 2482170056Srrs 2483223132Stuexen if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { 2484223132Stuexen paddrp->spp_flags |= SPP_HB_ENABLE; 2485223132Stuexen } else { 2486223132Stuexen paddrp->spp_flags |= SPP_HB_DISABLE; 2487223132Stuexen } 2488225635Stuexen if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) { 2489225635Stuexen paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2490225635Stuexen } else { 2491225635Stuexen paddrp->spp_flags |= SPP_PMTUD_DISABLE; 2492225635Stuexen } 2493223132Stuexen SCTP_INP_RUNLOCK(inp); 2494170056Srrs } else { 2495223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2496223132Stuexen error = EINVAL; 2497170056Srrs } 2498163953Srrs } 2499223132Stuexen if (error == 0) { 2500223132Stuexen *optsize = sizeof(struct sctp_paddrparams); 2501223132Stuexen } 2502223132Stuexen break; 2503163953Srrs } 2504163953Srrs case SCTP_GET_PEER_ADDR_INFO: 2505163953Srrs { 2506163953Srrs struct sctp_paddrinfo *paddri; 2507163953Srrs struct sctp_nets *net; 2508163953Srrs 2509166675Srrs SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize); 2510166675Srrs SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id); 2511166675Srrs 2512163953Srrs net = NULL; 2513166675Srrs if (stcb) { 2514166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddri->spinfo_address); 2515166675Srrs } else { 2516166675Srrs /* 2517166675Srrs * We increment here since 2518166675Srrs * sctp_findassociation_ep_addr() wil do a 2519166675Srrs * decrement if it finds the stcb as long as 2520166675Srrs * the locked tcb (last argument) is NOT a 2521166675Srrs * TCB.. aka NULL. 2522166675Srrs */ 2523166675Srrs SCTP_INP_INCR_REF(inp); 2524166675Srrs stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddri->spinfo_address, &net, NULL, NULL); 2525166675Srrs if (stcb == NULL) { 2526166675Srrs SCTP_INP_DECR_REF(inp); 2527163953Srrs } 2528166675Srrs } 2529163953Srrs 2530166675Srrs if ((stcb) && (net)) { 2531217635Srrs if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { 2532217638Stuexen /* It's unconfirmed */ 2533217635Srrs paddri->spinfo_state = SCTP_UNCONFIRMED; 2534217635Srrs } else if (net->dest_state & SCTP_ADDR_REACHABLE) { 2535217638Stuexen /* It's active */ 2536217635Srrs paddri->spinfo_state = SCTP_ACTIVE; 2537217635Srrs } else { 2538217638Stuexen /* It's inactive */ 2539217635Srrs paddri->spinfo_state = SCTP_INACTIVE; 2540217635Srrs } 2541166675Srrs paddri->spinfo_cwnd = net->cwnd; 2542219014Stuexen paddri->spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT; 2543166675Srrs paddri->spinfo_rto = net->RTO; 2544166675Srrs paddri->spinfo_assoc_id = sctp_get_associd(stcb); 2545222029Stuexen paddri->spinfo_mtu = net->mtu; 2546166675Srrs SCTP_TCB_UNLOCK(stcb); 2547223132Stuexen *optsize = sizeof(struct sctp_paddrinfo); 2548163953Srrs } else { 2549163953Srrs if (stcb) { 2550163953Srrs SCTP_TCB_UNLOCK(stcb); 2551163953Srrs } 2552171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 2553163953Srrs error = ENOENT; 2554163953Srrs } 2555223132Stuexen break; 2556163953Srrs } 2557163953Srrs case SCTP_PCB_STATUS: 2558163953Srrs { 2559163953Srrs struct sctp_pcbinfo *spcb; 2560163953Srrs 2561166675Srrs SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize); 2562163953Srrs sctp_fill_pcbinfo(spcb); 2563166675Srrs *optsize = sizeof(struct sctp_pcbinfo); 2564223132Stuexen break; 2565163953Srrs } 2566163953Srrs case SCTP_STATUS: 2567163953Srrs { 2568163953Srrs struct sctp_nets *net; 2569163953Srrs struct sctp_status *sstat; 2570163953Srrs 2571166675Srrs SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize); 2572166675Srrs SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id); 2573163953Srrs 2574163953Srrs if (stcb == NULL) { 2575223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2576163953Srrs error = EINVAL; 2577163953Srrs break; 2578163953Srrs } 2579163953Srrs /* 2580163953Srrs * I think passing the state is fine since 2581163953Srrs * sctp_constants.h will be available to the user 2582163953Srrs * land. 2583163953Srrs */ 2584163953Srrs sstat->sstat_state = stcb->asoc.state; 2585173179Srrs sstat->sstat_assoc_id = sctp_get_associd(stcb); 2586163953Srrs sstat->sstat_rwnd = stcb->asoc.peers_rwnd; 2587163953Srrs sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt; 2588163953Srrs /* 2589163953Srrs * We can't include chunks that have been passed to 2590163953Srrs * the socket layer. Only things in queue. 2591163953Srrs */ 2592163953Srrs sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue + 2593163953Srrs stcb->asoc.cnt_on_all_streams); 2594163953Srrs 2595163953Srrs 2596163953Srrs sstat->sstat_instrms = stcb->asoc.streamincnt; 2597163953Srrs sstat->sstat_outstrms = stcb->asoc.streamoutcnt; 2598163953Srrs sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc); 2599163953Srrs memcpy(&sstat->sstat_primary.spinfo_address, 2600163953Srrs &stcb->asoc.primary_destination->ro._l_addr, 2601163953Srrs ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len); 2602163953Srrs net = stcb->asoc.primary_destination; 2603163953Srrs ((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport; 2604163953Srrs /* 2605163953Srrs * Again the user can get info from sctp_constants.h 2606163953Srrs * for what the state of the network is. 2607163953Srrs */ 2608217635Srrs if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { 2609217635Srrs /* It's unconfirmed */ 2610217635Srrs sstat->sstat_primary.spinfo_state = SCTP_UNCONFIRMED; 2611217635Srrs } else if (net->dest_state & SCTP_ADDR_REACHABLE) { 2612217638Stuexen /* It's active */ 2613217635Srrs sstat->sstat_primary.spinfo_state = SCTP_ACTIVE; 2614217635Srrs } else { 2615217638Stuexen /* It's inactive */ 2616217635Srrs sstat->sstat_primary.spinfo_state = SCTP_INACTIVE; 2617217635Srrs } 2618163953Srrs sstat->sstat_primary.spinfo_cwnd = net->cwnd; 2619219014Stuexen sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT; 2620163953Srrs sstat->sstat_primary.spinfo_rto = net->RTO; 2621163953Srrs sstat->sstat_primary.spinfo_mtu = net->mtu; 2622163953Srrs sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb); 2623163953Srrs SCTP_TCB_UNLOCK(stcb); 2624223132Stuexen *optsize = sizeof(struct sctp_status); 2625223132Stuexen break; 2626163953Srrs } 2627163953Srrs case SCTP_RTOINFO: 2628163953Srrs { 2629163953Srrs struct sctp_rtoinfo *srto; 2630163953Srrs 2631166675Srrs SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize); 2632166675Srrs SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); 2633166675Srrs 2634166675Srrs if (stcb) { 2635166675Srrs srto->srto_initial = stcb->asoc.initial_rto; 2636166675Srrs srto->srto_max = stcb->asoc.maxrto; 2637166675Srrs srto->srto_min = stcb->asoc.minrto; 2638166675Srrs SCTP_TCB_UNLOCK(stcb); 2639166675Srrs } else { 2640224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2641224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2642224918Stuexen (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) { 2643223132Stuexen SCTP_INP_RLOCK(inp); 2644223132Stuexen srto->srto_initial = inp->sctp_ep.initial_rto; 2645223132Stuexen srto->srto_max = inp->sctp_ep.sctp_maxrto; 2646223132Stuexen srto->srto_min = inp->sctp_ep.sctp_minrto; 2647223132Stuexen SCTP_INP_RUNLOCK(inp); 2648223132Stuexen } else { 2649223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2650223132Stuexen error = EINVAL; 2651223132Stuexen } 2652163953Srrs } 2653223132Stuexen if (error == 0) { 2654223132Stuexen *optsize = sizeof(struct sctp_rtoinfo); 2655223132Stuexen } 2656223132Stuexen break; 2657163953Srrs } 2658215410Stuexen case SCTP_TIMEOUTS: 2659215410Stuexen { 2660215410Stuexen struct sctp_timeouts *stimo; 2661215410Stuexen 2662215410Stuexen SCTP_CHECK_AND_CAST(stimo, optval, struct sctp_timeouts, *optsize); 2663215410Stuexen SCTP_FIND_STCB(inp, stcb, stimo->stimo_assoc_id); 2664215410Stuexen 2665215410Stuexen if (stcb) { 2666215410Stuexen stimo->stimo_init = stcb->asoc.timoinit; 2667215410Stuexen stimo->stimo_data = stcb->asoc.timodata; 2668215410Stuexen stimo->stimo_sack = stcb->asoc.timosack; 2669215410Stuexen stimo->stimo_shutdown = stcb->asoc.timoshutdown; 2670215410Stuexen stimo->stimo_heartbeat = stcb->asoc.timoheartbeat; 2671215410Stuexen stimo->stimo_cookie = stcb->asoc.timocookie; 2672215410Stuexen stimo->stimo_shutdownack = stcb->asoc.timoshutdownack; 2673215410Stuexen SCTP_TCB_UNLOCK(stcb); 2674223132Stuexen *optsize = sizeof(struct sctp_timeouts); 2675215410Stuexen } else { 2676223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2677215410Stuexen error = EINVAL; 2678215410Stuexen } 2679223132Stuexen break; 2680215410Stuexen } 2681163953Srrs case SCTP_ASSOCINFO: 2682163953Srrs { 2683163953Srrs struct sctp_assocparams *sasoc; 2684163953Srrs 2685166675Srrs SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize); 2686166675Srrs SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); 2687163953Srrs 2688163953Srrs if (stcb) { 2689171477Srrs sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life); 2690163953Srrs sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times; 2691163953Srrs sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets; 2692163953Srrs sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd; 2693163953Srrs sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd; 2694163953Srrs SCTP_TCB_UNLOCK(stcb); 2695163953Srrs } else { 2696224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2697224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2698224918Stuexen (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) { 2699223132Stuexen SCTP_INP_RLOCK(inp); 2700223132Stuexen sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life); 2701223132Stuexen sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times; 2702223132Stuexen sasoc->sasoc_number_peer_destinations = 0; 2703223132Stuexen sasoc->sasoc_peer_rwnd = 0; 2704223132Stuexen sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv); 2705223132Stuexen SCTP_INP_RUNLOCK(inp); 2706223132Stuexen } else { 2707223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2708223132Stuexen error = EINVAL; 2709223132Stuexen } 2710163953Srrs } 2711223132Stuexen if (error == 0) { 2712223132Stuexen *optsize = sizeof(struct sctp_assocparams); 2713223132Stuexen } 2714223132Stuexen break; 2715163953Srrs } 2716163953Srrs case SCTP_DEFAULT_SEND_PARAM: 2717163953Srrs { 2718163953Srrs struct sctp_sndrcvinfo *s_info; 2719163953Srrs 2720166675Srrs SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize); 2721166675Srrs SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); 2722166675Srrs 2723166675Srrs if (stcb) { 2724170056Srrs memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send)); 2725166675Srrs SCTP_TCB_UNLOCK(stcb); 2726166675Srrs } else { 2727224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2728224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2729224918Stuexen (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC)) { 2730223132Stuexen SCTP_INP_RLOCK(inp); 2731223132Stuexen memcpy(s_info, &inp->def_send, sizeof(inp->def_send)); 2732223132Stuexen SCTP_INP_RUNLOCK(inp); 2733223132Stuexen } else { 2734223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2735223132Stuexen error = EINVAL; 2736223132Stuexen } 2737163953Srrs } 2738223132Stuexen if (error == 0) { 2739223132Stuexen *optsize = sizeof(struct sctp_sndrcvinfo); 2740223132Stuexen } 2741223132Stuexen break; 2742163953Srrs } 2743163953Srrs case SCTP_INITMSG: 2744163953Srrs { 2745163953Srrs struct sctp_initmsg *sinit; 2746163953Srrs 2747166675Srrs SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize); 2748163953Srrs SCTP_INP_RLOCK(inp); 2749163953Srrs sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count; 2750163953Srrs sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome; 2751163953Srrs sinit->sinit_max_attempts = inp->sctp_ep.max_init_times; 2752163953Srrs sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max; 2753163953Srrs SCTP_INP_RUNLOCK(inp); 2754223132Stuexen *optsize = sizeof(struct sctp_initmsg); 2755223132Stuexen break; 2756163953Srrs } 2757163953Srrs case SCTP_PRIMARY_ADDR: 2758163953Srrs /* we allow a "get" operation on this */ 2759163953Srrs { 2760163953Srrs struct sctp_setprim *ssp; 2761163953Srrs 2762166675Srrs SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize); 2763166675Srrs SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id); 2764166675Srrs 2765166675Srrs if (stcb) { 2766166675Srrs /* simply copy out the sockaddr_storage... */ 2767170056Srrs int len; 2768170056Srrs 2769170056Srrs len = *optsize; 2770170056Srrs if (len > stcb->asoc.primary_destination->ro._l_addr.sa.sa_len) 2771170056Srrs len = stcb->asoc.primary_destination->ro._l_addr.sa.sa_len; 2772170056Srrs 2773170056Srrs memcpy(&ssp->ssp_addr, 2774170056Srrs &stcb->asoc.primary_destination->ro._l_addr, 2775170056Srrs len); 2776166675Srrs SCTP_TCB_UNLOCK(stcb); 2777223132Stuexen *optsize = sizeof(struct sctp_setprim); 2778166675Srrs } else { 2779223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2780163953Srrs error = EINVAL; 2781163953Srrs } 2782223132Stuexen break; 2783163953Srrs } 2784163953Srrs case SCTP_HMAC_IDENT: 2785163953Srrs { 2786163953Srrs struct sctp_hmacalgo *shmac; 2787163953Srrs sctp_hmaclist_t *hmaclist; 2788163953Srrs uint32_t size; 2789163953Srrs int i; 2790163953Srrs 2791166675Srrs SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize); 2792166675Srrs 2793163953Srrs SCTP_INP_RLOCK(inp); 2794163953Srrs hmaclist = inp->sctp_ep.local_hmacs; 2795163953Srrs if (hmaclist == NULL) { 2796163953Srrs /* no HMACs to return */ 2797166675Srrs *optsize = sizeof(*shmac); 2798168299Srrs SCTP_INP_RUNLOCK(inp); 2799163953Srrs break; 2800163953Srrs } 2801163953Srrs /* is there room for all of the hmac ids? */ 2802163953Srrs size = sizeof(*shmac) + (hmaclist->num_algo * 2803163953Srrs sizeof(shmac->shmac_idents[0])); 2804166675Srrs if ((size_t)(*optsize) < size) { 2805223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2806163953Srrs error = EINVAL; 2807163953Srrs SCTP_INP_RUNLOCK(inp); 2808163953Srrs break; 2809163953Srrs } 2810163953Srrs /* copy in the list */ 2811181054Srrs shmac->shmac_number_of_idents = hmaclist->num_algo; 2812181054Srrs for (i = 0; i < hmaclist->num_algo; i++) { 2813163953Srrs shmac->shmac_idents[i] = hmaclist->hmac[i]; 2814181054Srrs } 2815163953Srrs SCTP_INP_RUNLOCK(inp); 2816166675Srrs *optsize = size; 2817163953Srrs break; 2818163953Srrs } 2819163953Srrs case SCTP_AUTH_ACTIVE_KEY: 2820163953Srrs { 2821163953Srrs struct sctp_authkeyid *scact; 2822163953Srrs 2823166675Srrs SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize); 2824166675Srrs SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); 2825166675Srrs 2826166675Srrs if (stcb) { 2827163953Srrs /* get the active key on the assoc */ 2828185694Srrs scact->scact_keynumber = stcb->asoc.authinfo.active_keyid; 2829163953Srrs SCTP_TCB_UNLOCK(stcb); 2830163953Srrs } else { 2831224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2832224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2833224918Stuexen (scact->scact_assoc_id == SCTP_FUTURE_ASSOC)) { 2834223132Stuexen /* get the endpoint active key */ 2835223132Stuexen SCTP_INP_RLOCK(inp); 2836223132Stuexen scact->scact_keynumber = inp->sctp_ep.default_keyid; 2837223132Stuexen SCTP_INP_RUNLOCK(inp); 2838223132Stuexen } else { 2839223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2840223132Stuexen error = EINVAL; 2841223132Stuexen } 2842163953Srrs } 2843223132Stuexen if (error == 0) { 2844223132Stuexen *optsize = sizeof(struct sctp_authkeyid); 2845223132Stuexen } 2846163953Srrs break; 2847163953Srrs } 2848163953Srrs case SCTP_LOCAL_AUTH_CHUNKS: 2849163953Srrs { 2850163953Srrs struct sctp_authchunks *sac; 2851163953Srrs sctp_auth_chklist_t *chklist = NULL; 2852166675Srrs size_t size = 0; 2853163953Srrs 2854166675Srrs SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); 2855166675Srrs SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); 2856166675Srrs 2857166675Srrs if (stcb) { 2858163953Srrs /* get off the assoc */ 2859163953Srrs chklist = stcb->asoc.local_auth_chunks; 2860163953Srrs /* is there enough space? */ 2861163953Srrs size = sctp_auth_get_chklist_size(chklist); 2862166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2863163953Srrs error = EINVAL; 2864171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2865166675Srrs } else { 2866166675Srrs /* copy in the chunks */ 2867169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2868234832Stuexen sac->gauth_number_of_chunks = (uint32_t) size; 2869223132Stuexen *optsize = sizeof(struct sctp_authchunks) + size; 2870163953Srrs } 2871163953Srrs SCTP_TCB_UNLOCK(stcb); 2872163953Srrs } else { 2873224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2874224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2875224918Stuexen (sac->gauth_assoc_id == SCTP_FUTURE_ASSOC)) { 2876223132Stuexen /* get off the endpoint */ 2877223132Stuexen SCTP_INP_RLOCK(inp); 2878223132Stuexen chklist = inp->sctp_ep.local_auth_chunks; 2879223132Stuexen /* is there enough space? */ 2880223132Stuexen size = sctp_auth_get_chklist_size(chklist); 2881223132Stuexen if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2882223132Stuexen error = EINVAL; 2883223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2884223132Stuexen } else { 2885223132Stuexen /* copy in the chunks */ 2886223132Stuexen (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2887234832Stuexen sac->gauth_number_of_chunks = (uint32_t) size; 2888223132Stuexen *optsize = sizeof(struct sctp_authchunks) + size; 2889223132Stuexen } 2890223132Stuexen SCTP_INP_RUNLOCK(inp); 2891223132Stuexen } else { 2892223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2893163953Srrs error = EINVAL; 2894163953Srrs } 2895163953Srrs } 2896163953Srrs break; 2897163953Srrs } 2898163953Srrs case SCTP_PEER_AUTH_CHUNKS: 2899163953Srrs { 2900163953Srrs struct sctp_authchunks *sac; 2901163953Srrs sctp_auth_chklist_t *chklist = NULL; 2902166675Srrs size_t size = 0; 2903163953Srrs 2904166675Srrs SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); 2905166675Srrs SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); 2906166675Srrs 2907166675Srrs if (stcb) { 2908166675Srrs /* get off the assoc */ 2909166675Srrs chklist = stcb->asoc.peer_auth_chunks; 2910166675Srrs /* is there enough space? */ 2911166675Srrs size = sctp_auth_get_chklist_size(chklist); 2912166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2913166675Srrs error = EINVAL; 2914171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2915166675Srrs } else { 2916166675Srrs /* copy in the chunks */ 2917169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2918234832Stuexen sac->gauth_number_of_chunks = (uint32_t) size; 2919223132Stuexen *optsize = sizeof(struct sctp_authchunks) + size; 2920166675Srrs } 2921166675Srrs SCTP_TCB_UNLOCK(stcb); 2922166675Srrs } else { 2923171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 2924163953Srrs error = ENOENT; 2925163953Srrs } 2926163953Srrs break; 2927163953Srrs } 2928223132Stuexen case SCTP_EVENT: 2929223132Stuexen { 2930223132Stuexen struct sctp_event *event; 2931223132Stuexen uint32_t event_type; 2932163953Srrs 2933223132Stuexen SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, *optsize); 2934223132Stuexen SCTP_FIND_STCB(inp, stcb, event->se_assoc_id); 2935163953Srrs 2936223132Stuexen switch (event->se_type) { 2937223132Stuexen case SCTP_ASSOC_CHANGE: 2938223132Stuexen event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT; 2939223132Stuexen break; 2940223132Stuexen case SCTP_PEER_ADDR_CHANGE: 2941223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPADDREVNT; 2942223132Stuexen break; 2943223132Stuexen case SCTP_REMOTE_ERROR: 2944223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPEERERR; 2945223132Stuexen break; 2946223132Stuexen case SCTP_SEND_FAILED: 2947223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT; 2948223132Stuexen break; 2949223132Stuexen case SCTP_SHUTDOWN_EVENT: 2950223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT; 2951223132Stuexen break; 2952223132Stuexen case SCTP_ADAPTATION_INDICATION: 2953223132Stuexen event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT; 2954223132Stuexen break; 2955223132Stuexen case SCTP_PARTIAL_DELIVERY_EVENT: 2956223132Stuexen event_type = SCTP_PCB_FLAGS_PDAPIEVNT; 2957223132Stuexen break; 2958223132Stuexen case SCTP_AUTHENTICATION_EVENT: 2959223132Stuexen event_type = SCTP_PCB_FLAGS_AUTHEVNT; 2960223132Stuexen break; 2961223132Stuexen case SCTP_STREAM_RESET_EVENT: 2962223132Stuexen event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT; 2963223132Stuexen break; 2964223132Stuexen case SCTP_SENDER_DRY_EVENT: 2965223132Stuexen event_type = SCTP_PCB_FLAGS_DRYEVNT; 2966223132Stuexen break; 2967223132Stuexen case SCTP_NOTIFICATIONS_STOPPED_EVENT: 2968223132Stuexen event_type = 0; 2969223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); 2970223132Stuexen error = ENOTSUP; 2971223132Stuexen break; 2972235009Stuexen case SCTP_ASSOC_RESET_EVENT: 2973235009Stuexen event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT; 2974235009Stuexen break; 2975235009Stuexen case SCTP_STREAM_CHANGE_EVENT: 2976235009Stuexen event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT; 2977235009Stuexen break; 2978235075Stuexen case SCTP_SEND_FAILED_EVENT: 2979235075Stuexen event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT; 2980235075Stuexen break; 2981223132Stuexen default: 2982223132Stuexen event_type = 0; 2983223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2984223132Stuexen error = EINVAL; 2985223132Stuexen break; 2986223132Stuexen } 2987223132Stuexen if (event_type > 0) { 2988223132Stuexen if (stcb) { 2989223132Stuexen event->se_on = sctp_stcb_is_feature_on(inp, stcb, event_type); 2990223132Stuexen SCTP_TCB_UNLOCK(stcb); 2991223132Stuexen } else { 2992224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2993224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2994224918Stuexen (event->se_assoc_id == SCTP_FUTURE_ASSOC)) { 2995223132Stuexen SCTP_INP_RLOCK(inp); 2996223132Stuexen event->se_on = sctp_is_feature_on(inp, event_type); 2997223132Stuexen SCTP_INP_RUNLOCK(inp); 2998223132Stuexen } else { 2999223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3000223132Stuexen error = EINVAL; 3001223132Stuexen } 3002223132Stuexen } 3003223132Stuexen } 3004223132Stuexen if (error == 0) { 3005223132Stuexen *optsize = sizeof(struct sctp_event); 3006223132Stuexen } 3007223132Stuexen break; 3008223132Stuexen } 3009223132Stuexen case SCTP_RECVRCVINFO: 3010223132Stuexen { 3011223132Stuexen int onoff; 3012223132Stuexen 3013223132Stuexen if (*optsize < sizeof(int)) { 3014223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3015223132Stuexen error = EINVAL; 3016223132Stuexen } else { 3017230104Stuexen SCTP_INP_RLOCK(inp); 3018223132Stuexen onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO); 3019223132Stuexen SCTP_INP_RUNLOCK(inp); 3020223132Stuexen } 3021223132Stuexen if (error == 0) { 3022223132Stuexen /* return the option value */ 3023223132Stuexen *(int *)optval = onoff; 3024223132Stuexen *optsize = sizeof(int); 3025223132Stuexen } 3026223132Stuexen break; 3027223132Stuexen } 3028223132Stuexen case SCTP_RECVNXTINFO: 3029223132Stuexen { 3030223132Stuexen int onoff; 3031223132Stuexen 3032223132Stuexen if (*optsize < sizeof(int)) { 3033223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3034223132Stuexen error = EINVAL; 3035223132Stuexen } else { 3036230104Stuexen SCTP_INP_RLOCK(inp); 3037223132Stuexen onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO); 3038223132Stuexen SCTP_INP_RUNLOCK(inp); 3039223132Stuexen } 3040223132Stuexen if (error == 0) { 3041223132Stuexen /* return the option value */ 3042223132Stuexen *(int *)optval = onoff; 3043223132Stuexen *optsize = sizeof(int); 3044223132Stuexen } 3045223132Stuexen break; 3046223132Stuexen } 3047223132Stuexen case SCTP_DEFAULT_SNDINFO: 3048223132Stuexen { 3049223132Stuexen struct sctp_sndinfo *info; 3050223132Stuexen 3051223132Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, *optsize); 3052223132Stuexen SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id); 3053223132Stuexen 3054223132Stuexen if (stcb) { 3055223132Stuexen info->snd_sid = stcb->asoc.def_send.sinfo_stream; 3056223132Stuexen info->snd_flags = stcb->asoc.def_send.sinfo_flags; 3057223162Stuexen info->snd_flags &= 0xfff0; 3058223132Stuexen info->snd_ppid = stcb->asoc.def_send.sinfo_ppid; 3059223132Stuexen info->snd_context = stcb->asoc.def_send.sinfo_context; 3060223132Stuexen SCTP_TCB_UNLOCK(stcb); 3061223132Stuexen } else { 3062224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3063224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3064224918Stuexen (info->snd_assoc_id == SCTP_FUTURE_ASSOC)) { 3065223132Stuexen SCTP_INP_RLOCK(inp); 3066223132Stuexen info->snd_sid = inp->def_send.sinfo_stream; 3067223132Stuexen info->snd_flags = inp->def_send.sinfo_flags; 3068223162Stuexen info->snd_flags &= 0xfff0; 3069223132Stuexen info->snd_ppid = inp->def_send.sinfo_ppid; 3070223132Stuexen info->snd_context = inp->def_send.sinfo_context; 3071223132Stuexen SCTP_INP_RUNLOCK(inp); 3072223132Stuexen } else { 3073223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3074223132Stuexen error = EINVAL; 3075223132Stuexen } 3076223132Stuexen } 3077223132Stuexen if (error == 0) { 3078223132Stuexen *optsize = sizeof(struct sctp_sndinfo); 3079223132Stuexen } 3080223132Stuexen break; 3081223132Stuexen } 3082223162Stuexen case SCTP_DEFAULT_PRINFO: 3083223162Stuexen { 3084223162Stuexen struct sctp_default_prinfo *info; 3085223162Stuexen 3086223162Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, *optsize); 3087223162Stuexen SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id); 3088223162Stuexen 3089223162Stuexen if (stcb) { 3090223162Stuexen info->pr_policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); 3091223162Stuexen info->pr_value = stcb->asoc.def_send.sinfo_timetolive; 3092223162Stuexen SCTP_TCB_UNLOCK(stcb); 3093223162Stuexen } else { 3094224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3095224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3096224918Stuexen (info->pr_assoc_id == SCTP_FUTURE_ASSOC)) { 3097223162Stuexen SCTP_INP_RLOCK(inp); 3098223162Stuexen info->pr_policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags); 3099223162Stuexen info->pr_value = inp->def_send.sinfo_timetolive; 3100223162Stuexen SCTP_INP_RUNLOCK(inp); 3101223162Stuexen } else { 3102223162Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3103223162Stuexen error = EINVAL; 3104223162Stuexen } 3105223162Stuexen } 3106223162Stuexen if (error == 0) { 3107223162Stuexen *optsize = sizeof(struct sctp_default_prinfo); 3108223162Stuexen } 3109223162Stuexen break; 3110223162Stuexen } 3111224641Stuexen case SCTP_PEER_ADDR_THLDS: 3112224641Stuexen { 3113224641Stuexen struct sctp_paddrthlds *thlds; 3114224641Stuexen struct sctp_nets *net; 3115224641Stuexen 3116224641Stuexen SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, *optsize); 3117224641Stuexen SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id); 3118224641Stuexen 3119224641Stuexen net = NULL; 3120224641Stuexen if (stcb) { 3121224641Stuexen net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_address); 3122224641Stuexen } else { 3123224641Stuexen /* 3124224641Stuexen * We increment here since 3125224641Stuexen * sctp_findassociation_ep_addr() wil do a 3126224641Stuexen * decrement if it finds the stcb as long as 3127224641Stuexen * the locked tcb (last argument) is NOT a 3128224641Stuexen * TCB.. aka NULL. 3129224641Stuexen */ 3130224641Stuexen SCTP_INP_INCR_REF(inp); 3131224641Stuexen stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&thlds->spt_address, &net, NULL, NULL); 3132224641Stuexen if (stcb == NULL) { 3133224641Stuexen SCTP_INP_DECR_REF(inp); 3134224641Stuexen } 3135224641Stuexen } 3136224641Stuexen if (stcb && (net == NULL)) { 3137224641Stuexen struct sockaddr *sa; 3138224641Stuexen 3139224641Stuexen sa = (struct sockaddr *)&thlds->spt_address; 3140224641Stuexen#ifdef INET 3141224641Stuexen if (sa->sa_family == AF_INET) { 3142224641Stuexen struct sockaddr_in *sin; 3143224641Stuexen 3144224641Stuexen sin = (struct sockaddr_in *)sa; 3145224641Stuexen if (sin->sin_addr.s_addr) { 3146224641Stuexen error = EINVAL; 3147224641Stuexen SCTP_TCB_UNLOCK(stcb); 3148224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3149224641Stuexen break; 3150224641Stuexen } 3151224641Stuexen } else 3152224641Stuexen#endif 3153224641Stuexen#ifdef INET6 3154224641Stuexen if (sa->sa_family == AF_INET6) { 3155224641Stuexen struct sockaddr_in6 *sin6; 3156224641Stuexen 3157224641Stuexen sin6 = (struct sockaddr_in6 *)sa; 3158224641Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 3159224641Stuexen error = EINVAL; 3160224641Stuexen SCTP_TCB_UNLOCK(stcb); 3161224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3162224641Stuexen break; 3163224641Stuexen } 3164224641Stuexen } else 3165224641Stuexen#endif 3166224641Stuexen { 3167224641Stuexen error = EAFNOSUPPORT; 3168224641Stuexen SCTP_TCB_UNLOCK(stcb); 3169224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3170224641Stuexen break; 3171224641Stuexen } 3172224641Stuexen } 3173224641Stuexen if (stcb) { 3174224641Stuexen if (net) { 3175224641Stuexen thlds->spt_pathmaxrxt = net->failure_threshold; 3176224641Stuexen thlds->spt_pathpfthld = net->pf_threshold; 3177224641Stuexen } else { 3178224641Stuexen thlds->spt_pathmaxrxt = stcb->asoc.def_net_failure; 3179224641Stuexen thlds->spt_pathpfthld = stcb->asoc.def_net_pf_threshold; 3180224641Stuexen } 3181224641Stuexen thlds->spt_assoc_id = sctp_get_associd(stcb); 3182224641Stuexen SCTP_TCB_UNLOCK(stcb); 3183224641Stuexen } else { 3184224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3185224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3186224918Stuexen (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) { 3187224641Stuexen /* Use endpoint defaults */ 3188224641Stuexen SCTP_INP_RLOCK(inp); 3189224641Stuexen thlds->spt_pathmaxrxt = inp->sctp_ep.def_net_failure; 3190224641Stuexen thlds->spt_pathpfthld = inp->sctp_ep.def_net_pf_threshold; 3191224641Stuexen SCTP_INP_RUNLOCK(inp); 3192224641Stuexen } else { 3193224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3194224641Stuexen error = EINVAL; 3195224641Stuexen } 3196224641Stuexen } 3197224641Stuexen if (error == 0) { 3198224641Stuexen *optsize = sizeof(struct sctp_paddrthlds); 3199224641Stuexen } 3200224641Stuexen break; 3201224641Stuexen } 3202227755Stuexen case SCTP_REMOTE_UDP_ENCAPS_PORT: 3203227755Stuexen { 3204227755Stuexen struct sctp_udpencaps *encaps; 3205227755Stuexen struct sctp_nets *net; 3206227755Stuexen 3207227755Stuexen SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, *optsize); 3208227755Stuexen SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id); 3209227755Stuexen 3210227755Stuexen if (stcb) { 3211227755Stuexen net = sctp_findnet(stcb, (struct sockaddr *)&encaps->sue_address); 3212227755Stuexen } else { 3213227755Stuexen /* 3214227755Stuexen * We increment here since 3215227755Stuexen * sctp_findassociation_ep_addr() wil do a 3216227755Stuexen * decrement if it finds the stcb as long as 3217227755Stuexen * the locked tcb (last argument) is NOT a 3218227755Stuexen * TCB.. aka NULL. 3219227755Stuexen */ 3220227755Stuexen net = NULL; 3221227755Stuexen SCTP_INP_INCR_REF(inp); 3222227755Stuexen stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&encaps->sue_address, &net, NULL, NULL); 3223227755Stuexen if (stcb == NULL) { 3224227755Stuexen SCTP_INP_DECR_REF(inp); 3225227755Stuexen } 3226227755Stuexen } 3227227755Stuexen if (stcb && (net == NULL)) { 3228227755Stuexen struct sockaddr *sa; 3229227755Stuexen 3230227755Stuexen sa = (struct sockaddr *)&encaps->sue_address; 3231227755Stuexen#ifdef INET 3232227755Stuexen if (sa->sa_family == AF_INET) { 3233227755Stuexen struct sockaddr_in *sin; 3234227755Stuexen 3235227755Stuexen sin = (struct sockaddr_in *)sa; 3236227755Stuexen if (sin->sin_addr.s_addr) { 3237227755Stuexen error = EINVAL; 3238227755Stuexen SCTP_TCB_UNLOCK(stcb); 3239227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3240227755Stuexen break; 3241227755Stuexen } 3242227755Stuexen } else 3243227755Stuexen#endif 3244227755Stuexen#ifdef INET6 3245227755Stuexen if (sa->sa_family == AF_INET6) { 3246227755Stuexen struct sockaddr_in6 *sin6; 3247227755Stuexen 3248227755Stuexen sin6 = (struct sockaddr_in6 *)sa; 3249227755Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 3250227755Stuexen error = EINVAL; 3251227755Stuexen SCTP_TCB_UNLOCK(stcb); 3252227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3253227755Stuexen break; 3254227755Stuexen } 3255227755Stuexen } else 3256227755Stuexen#endif 3257227755Stuexen { 3258227755Stuexen error = EAFNOSUPPORT; 3259227755Stuexen SCTP_TCB_UNLOCK(stcb); 3260227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3261227755Stuexen break; 3262227755Stuexen } 3263227755Stuexen } 3264227755Stuexen if (stcb) { 3265227755Stuexen if (net) { 3266227755Stuexen encaps->sue_port = net->port; 3267227755Stuexen } else { 3268227755Stuexen encaps->sue_port = stcb->asoc.port; 3269227755Stuexen } 3270227755Stuexen SCTP_TCB_UNLOCK(stcb); 3271227755Stuexen } else { 3272227755Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3273227755Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3274227755Stuexen (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) { 3275227755Stuexen SCTP_INP_RLOCK(inp); 3276227755Stuexen encaps->sue_port = inp->sctp_ep.port; 3277227755Stuexen SCTP_INP_RUNLOCK(inp); 3278227755Stuexen } else { 3279227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3280227755Stuexen error = EINVAL; 3281227755Stuexen } 3282227755Stuexen } 3283227755Stuexen if (error == 0) { 3284227755Stuexen *optsize = sizeof(struct sctp_paddrparams); 3285227755Stuexen } 3286227755Stuexen break; 3287227755Stuexen } 3288235021Stuexen case SCTP_ENABLE_STREAM_RESET: 3289235021Stuexen { 3290235021Stuexen struct sctp_assoc_value *av; 3291235021Stuexen 3292235021Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 3293235021Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3294235021Stuexen 3295235021Stuexen if (stcb) { 3296235021Stuexen av->assoc_value = (uint32_t) stcb->asoc.local_strreset_support; 3297235021Stuexen SCTP_TCB_UNLOCK(stcb); 3298235021Stuexen } else { 3299235021Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3300235021Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3301235021Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 3302235021Stuexen SCTP_INP_RLOCK(inp); 3303235021Stuexen av->assoc_value = (uint32_t) inp->local_strreset_support; 3304235021Stuexen SCTP_INP_RUNLOCK(inp); 3305235021Stuexen } else { 3306235021Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3307235021Stuexen error = EINVAL; 3308235021Stuexen } 3309235021Stuexen } 3310235021Stuexen if (error == 0) { 3311235021Stuexen *optsize = sizeof(struct sctp_assoc_value); 3312235021Stuexen } 3313235021Stuexen break; 3314235021Stuexen } 3315163953Srrs default: 3316171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 3317163953Srrs error = ENOPROTOOPT; 3318163953Srrs break; 3319163953Srrs } /* end switch (sopt->sopt_name) */ 3320223132Stuexen if (error) { 3321223132Stuexen *optsize = 0; 3322223132Stuexen } 3323163953Srrs return (error); 3324163953Srrs} 3325163953Srrs 3326163953Srrsstatic int 3327166675Srrssctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, 3328166675Srrs void *p) 3329163953Srrs{ 3330166675Srrs int error, set_opt; 3331166675Srrs uint32_t *mopt; 3332163953Srrs struct sctp_tcb *stcb = NULL; 3333171943Srrs struct sctp_inpcb *inp = NULL; 3334167598Srrs uint32_t vrf_id; 3335163953Srrs 3336166675Srrs if (optval == NULL) { 3337169420Srrs SCTP_PRINTF("optval is NULL\n"); 3338171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3339163953Srrs return (EINVAL); 3340163953Srrs } 3341163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3342233005Stuexen if (inp == NULL) { 3343169420Srrs SCTP_PRINTF("inp is NULL?\n"); 3344171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3345228907Stuexen return (EINVAL); 3346167598Srrs } 3347168299Srrs vrf_id = inp->def_vrf_id; 3348163953Srrs 3349163953Srrs error = 0; 3350166675Srrs switch (optname) { 3351163953Srrs case SCTP_NODELAY: 3352163953Srrs case SCTP_AUTOCLOSE: 3353163953Srrs case SCTP_AUTO_ASCONF: 3354163953Srrs case SCTP_EXPLICIT_EOR: 3355163953Srrs case SCTP_DISABLE_FRAGMENTS: 3356163953Srrs case SCTP_USE_EXT_RCVINFO: 3357163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 3358163953Srrs /* copy in the option value */ 3359166675Srrs SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); 3360163953Srrs set_opt = 0; 3361163953Srrs if (error) 3362163953Srrs break; 3363166675Srrs switch (optname) { 3364163953Srrs case SCTP_DISABLE_FRAGMENTS: 3365163953Srrs set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT; 3366163953Srrs break; 3367163953Srrs case SCTP_AUTO_ASCONF: 3368171943Srrs /* 3369171943Srrs * NOTE: we don't really support this flag 3370171943Srrs */ 3371171943Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 3372171943Srrs /* only valid for bound all sockets */ 3373224641Stuexen if ((SCTP_BASE_SYSCTL(sctp_auto_asconf) == 0) && 3374224641Stuexen (*mopt != 0)) { 3375224641Stuexen /* forbidden by admin */ 3376224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM); 3377224641Stuexen return (EPERM); 3378224641Stuexen } 3379171943Srrs set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF; 3380171943Srrs } else { 3381171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3382171943Srrs return (EINVAL); 3383171943Srrs } 3384163953Srrs break; 3385163953Srrs case SCTP_EXPLICIT_EOR: 3386163953Srrs set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR; 3387163953Srrs break; 3388163953Srrs case SCTP_USE_EXT_RCVINFO: 3389163953Srrs set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO; 3390163953Srrs break; 3391163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 3392163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 3393163953Srrs set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4; 3394163953Srrs } else { 3395171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3396163953Srrs return (EINVAL); 3397163953Srrs } 3398163953Srrs break; 3399163953Srrs case SCTP_NODELAY: 3400163953Srrs set_opt = SCTP_PCB_FLAGS_NODELAY; 3401163953Srrs break; 3402163953Srrs case SCTP_AUTOCLOSE: 3403170056Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3404170056Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 3405171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3406170056Srrs return (EINVAL); 3407170056Srrs } 3408163953Srrs set_opt = SCTP_PCB_FLAGS_AUTOCLOSE; 3409163953Srrs /* 3410163953Srrs * The value is in ticks. Note this does not effect 3411163953Srrs * old associations, only new ones. 3412163953Srrs */ 3413163953Srrs inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt); 3414163953Srrs break; 3415163953Srrs } 3416163953Srrs SCTP_INP_WLOCK(inp); 3417163953Srrs if (*mopt != 0) { 3418163953Srrs sctp_feature_on(inp, set_opt); 3419163953Srrs } else { 3420163953Srrs sctp_feature_off(inp, set_opt); 3421163953Srrs } 3422163953Srrs SCTP_INP_WUNLOCK(inp); 3423163953Srrs break; 3424181054Srrs case SCTP_REUSE_PORT: 3425181054Srrs { 3426181054Srrs SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); 3427181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) { 3428181054Srrs /* Can't set it after we are bound */ 3429181054Srrs error = EINVAL; 3430181054Srrs break; 3431181054Srrs } 3432181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) { 3433181054Srrs /* Can't do this for a 1-m socket */ 3434181054Srrs error = EINVAL; 3435181054Srrs break; 3436181054Srrs } 3437181054Srrs if (optval) 3438181054Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE); 3439181054Srrs else 3440181054Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE); 3441223132Stuexen break; 3442181054Srrs } 3443163953Srrs case SCTP_PARTIAL_DELIVERY_POINT: 3444163953Srrs { 3445166675Srrs uint32_t *value; 3446166675Srrs 3447166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); 3448167736Srrs if (*value > SCTP_SB_LIMIT_RCV(so)) { 3449171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3450167736Srrs error = EINVAL; 3451167736Srrs break; 3452167736Srrs } 3453166675Srrs inp->partial_delivery_point = *value; 3454223132Stuexen break; 3455163953Srrs } 3456163953Srrs case SCTP_FRAGMENT_INTERLEAVE: 3457163953Srrs /* not yet until we re-write sctp_recvmsg() */ 3458163953Srrs { 3459168943Srrs uint32_t *level; 3460163953Srrs 3461168943Srrs SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize); 3462168943Srrs if (*level == SCTP_FRAG_LEVEL_2) { 3463163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 3464168943Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 3465168943Srrs } else if (*level == SCTP_FRAG_LEVEL_1) { 3466168943Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 3467168943Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 3468168943Srrs } else if (*level == SCTP_FRAG_LEVEL_0) { 3469170056Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 3470168943Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 3471168943Srrs 3472163953Srrs } else { 3473171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3474168943Srrs error = EINVAL; 3475163953Srrs } 3476223132Stuexen break; 3477163953Srrs } 3478163953Srrs case SCTP_CMT_ON_OFF: 3479211944Stuexen if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { 3480163953Srrs struct sctp_assoc_value *av; 3481163953Srrs 3482166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 3483223132Stuexen if (av->assoc_value > SCTP_CMT_MAX) { 3484223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3485223132Stuexen error = EINVAL; 3486223132Stuexen break; 3487223132Stuexen } 3488211944Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3489211944Stuexen if (stcb) { 3490223132Stuexen stcb->asoc.sctp_cmt_on_off = av->assoc_value; 3491211944Stuexen SCTP_TCB_UNLOCK(stcb); 3492166675Srrs } else { 3493224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3494224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3495224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 3496223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3497221460Stuexen SCTP_INP_WLOCK(inp); 3498221460Stuexen inp->sctp_cmt_on_off = av->assoc_value; 3499221460Stuexen SCTP_INP_WUNLOCK(inp); 3500216669Stuexen } 3501223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 3502223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3503223132Stuexen SCTP_INP_RLOCK(inp); 3504223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3505223132Stuexen SCTP_TCB_LOCK(stcb); 3506223132Stuexen stcb->asoc.sctp_cmt_on_off = av->assoc_value; 3507223132Stuexen SCTP_TCB_UNLOCK(stcb); 3508223132Stuexen } 3509224918Stuexen SCTP_INP_RUNLOCK(inp); 3510223132Stuexen } 3511163953Srrs } 3512211944Stuexen } else { 3513211944Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 3514211944Stuexen error = ENOPROTOOPT; 3515163953Srrs } 3516163953Srrs break; 3517171440Srrs case SCTP_PLUGGABLE_CC: 3518171440Srrs { 3519171440Srrs struct sctp_assoc_value *av; 3520219057Srrs struct sctp_nets *net; 3521171440Srrs 3522171440Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 3523223132Stuexen if ((av->assoc_value != SCTP_CC_RFC2581) && 3524223132Stuexen (av->assoc_value != SCTP_CC_HSTCP) && 3525223132Stuexen (av->assoc_value != SCTP_CC_HTCP) && 3526223132Stuexen (av->assoc_value != SCTP_CC_RTCC)) { 3527223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3528223132Stuexen error = EINVAL; 3529223132Stuexen break; 3530223132Stuexen } 3531171440Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3532171440Srrs if (stcb) { 3533223132Stuexen stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value]; 3534223132Stuexen stcb->asoc.congestion_control_module = av->assoc_value; 3535223132Stuexen if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) { 3536223132Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3537223132Stuexen stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); 3538219057Srrs } 3539171440Srrs } 3540217611Stuexen SCTP_TCB_UNLOCK(stcb); 3541171440Srrs } else { 3542224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3543224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3544224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 3545223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3546217611Stuexen SCTP_INP_WLOCK(inp); 3547171440Srrs inp->sctp_ep.sctp_default_cc_module = av->assoc_value; 3548217611Stuexen SCTP_INP_WUNLOCK(inp); 3549217760Stuexen } 3550223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 3551223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3552223132Stuexen SCTP_INP_RLOCK(inp); 3553223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3554223132Stuexen SCTP_TCB_LOCK(stcb); 3555223132Stuexen stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value]; 3556223132Stuexen stcb->asoc.congestion_control_module = av->assoc_value; 3557223132Stuexen if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) { 3558223132Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3559223132Stuexen stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); 3560223132Stuexen } 3561223132Stuexen } 3562223132Stuexen SCTP_TCB_UNLOCK(stcb); 3563223132Stuexen } 3564223132Stuexen SCTP_INP_RUNLOCK(inp); 3565223132Stuexen } 3566171440Srrs } 3567223132Stuexen break; 3568171440Srrs } 3569219057Srrs case SCTP_CC_OPTION: 3570219057Srrs { 3571219057Srrs struct sctp_cc_option *cc_opt; 3572219057Srrs 3573219057Srrs SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, optsize); 3574219057Srrs SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id); 3575219057Srrs if (stcb == NULL) { 3576223132Stuexen if (cc_opt->aid_value.assoc_id == SCTP_CURRENT_ASSOC) { 3577223132Stuexen SCTP_INP_RLOCK(inp); 3578223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3579223132Stuexen SCTP_TCB_LOCK(stcb); 3580223132Stuexen if (stcb->asoc.cc_functions.sctp_cwnd_socket_option) { 3581223132Stuexen (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1, cc_opt); 3582223132Stuexen } 3583223132Stuexen SCTP_TCB_UNLOCK(stcb); 3584223132Stuexen } 3585223132Stuexen SCTP_INP_RUNLOCK(inp); 3586223132Stuexen } else { 3587223132Stuexen error = EINVAL; 3588223132Stuexen } 3589219057Srrs } else { 3590219057Srrs if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) { 3591219057Srrs error = ENOTSUP; 3592219057Srrs } else { 3593219057Srrs error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1, 3594219057Srrs cc_opt); 3595219057Srrs } 3596219057Srrs SCTP_TCB_UNLOCK(stcb); 3597219057Srrs } 3598223132Stuexen break; 3599219057Srrs } 3600217760Stuexen case SCTP_PLUGGABLE_SS: 3601217760Stuexen { 3602217760Stuexen struct sctp_assoc_value *av; 3603217760Stuexen 3604217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 3605223132Stuexen if ((av->assoc_value != SCTP_SS_DEFAULT) && 3606223132Stuexen (av->assoc_value != SCTP_SS_ROUND_ROBIN) && 3607223132Stuexen (av->assoc_value != SCTP_SS_ROUND_ROBIN_PACKET) && 3608223132Stuexen (av->assoc_value != SCTP_SS_PRIORITY) && 3609223132Stuexen (av->assoc_value != SCTP_SS_FAIR_BANDWITH) && 3610223132Stuexen (av->assoc_value != SCTP_SS_FIRST_COME)) { 3611223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3612223132Stuexen error = EINVAL; 3613223132Stuexen break; 3614223132Stuexen } 3615217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3616217760Stuexen if (stcb) { 3617223132Stuexen stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1); 3618223132Stuexen stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value]; 3619223132Stuexen stcb->asoc.stream_scheduling_module = av->assoc_value; 3620223132Stuexen stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1); 3621217760Stuexen SCTP_TCB_UNLOCK(stcb); 3622217760Stuexen } else { 3623224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3624224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3625224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 3626223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3627217760Stuexen SCTP_INP_WLOCK(inp); 3628217760Stuexen inp->sctp_ep.sctp_default_ss_module = av->assoc_value; 3629217760Stuexen SCTP_INP_WUNLOCK(inp); 3630217760Stuexen } 3631223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 3632223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3633223132Stuexen SCTP_INP_RLOCK(inp); 3634223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3635223132Stuexen SCTP_TCB_LOCK(stcb); 3636223132Stuexen stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1); 3637223132Stuexen stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value]; 3638223132Stuexen stcb->asoc.stream_scheduling_module = av->assoc_value; 3639223132Stuexen stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1); 3640223132Stuexen SCTP_TCB_UNLOCK(stcb); 3641223132Stuexen } 3642223132Stuexen SCTP_INP_RUNLOCK(inp); 3643223132Stuexen } 3644217760Stuexen } 3645223132Stuexen break; 3646217760Stuexen } 3647217760Stuexen case SCTP_SS_VALUE: 3648217760Stuexen { 3649217760Stuexen struct sctp_stream_value *av; 3650217760Stuexen 3651217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize); 3652217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3653217760Stuexen if (stcb) { 3654217760Stuexen if (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], 3655217760Stuexen av->stream_value) < 0) { 3656217760Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3657217760Stuexen error = EINVAL; 3658217760Stuexen } 3659217760Stuexen SCTP_TCB_UNLOCK(stcb); 3660217760Stuexen } else { 3661223132Stuexen if (av->assoc_id == SCTP_CURRENT_ASSOC) { 3662223132Stuexen SCTP_INP_RLOCK(inp); 3663223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3664223132Stuexen SCTP_TCB_LOCK(stcb); 3665223132Stuexen stcb->asoc.ss_functions.sctp_ss_set_value(stcb, 3666223132Stuexen &stcb->asoc, 3667223132Stuexen &stcb->asoc.strmout[av->stream_id], 3668223132Stuexen av->stream_value); 3669223132Stuexen SCTP_TCB_UNLOCK(stcb); 3670223132Stuexen } 3671223132Stuexen SCTP_INP_RUNLOCK(inp); 3672223132Stuexen 3673223132Stuexen } else { 3674223132Stuexen /* 3675223132Stuexen * Can't set stream value without 3676223132Stuexen * association 3677223132Stuexen */ 3678223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3679223132Stuexen error = EINVAL; 3680223132Stuexen } 3681217760Stuexen } 3682223132Stuexen break; 3683217760Stuexen } 3684163953Srrs case SCTP_CLR_STAT_LOG: 3685171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 3686163953Srrs error = EOPNOTSUPP; 3687163953Srrs break; 3688163953Srrs case SCTP_CONTEXT: 3689163953Srrs { 3690163953Srrs struct sctp_assoc_value *av; 3691163953Srrs 3692166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 3693166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3694166675Srrs 3695166675Srrs if (stcb) { 3696166675Srrs stcb->asoc.context = av->assoc_value; 3697166675Srrs SCTP_TCB_UNLOCK(stcb); 3698163953Srrs } else { 3699224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3700224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3701224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 3702223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3703223132Stuexen SCTP_INP_WLOCK(inp); 3704223132Stuexen inp->sctp_context = av->assoc_value; 3705223132Stuexen SCTP_INP_WUNLOCK(inp); 3706223132Stuexen } 3707223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 3708223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3709223132Stuexen SCTP_INP_RLOCK(inp); 3710223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3711223132Stuexen SCTP_TCB_LOCK(stcb); 3712223132Stuexen stcb->asoc.context = av->assoc_value; 3713223132Stuexen SCTP_TCB_UNLOCK(stcb); 3714223132Stuexen } 3715223132Stuexen SCTP_INP_RUNLOCK(inp); 3716223132Stuexen } 3717163953Srrs } 3718223132Stuexen break; 3719163953Srrs } 3720167598Srrs case SCTP_VRF_ID: 3721167598Srrs { 3722170056Srrs uint32_t *default_vrfid; 3723167598Srrs 3724170056Srrs SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize); 3725170056Srrs if (*default_vrfid > SCTP_MAX_VRF_ID) { 3726171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3727167598Srrs error = EINVAL; 3728167598Srrs break; 3729167598Srrs } 3730170056Srrs inp->def_vrf_id = *default_vrfid; 3731167598Srrs break; 3732167598Srrs } 3733167598Srrs case SCTP_DEL_VRF_ID: 3734167598Srrs { 3735171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 3736167598Srrs error = EOPNOTSUPP; 3737167598Srrs break; 3738167598Srrs } 3739167598Srrs case SCTP_ADD_VRF_ID: 3740167598Srrs { 3741171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 3742167598Srrs error = EOPNOTSUPP; 3743167598Srrs break; 3744167598Srrs } 3745170056Srrs case SCTP_DELAYED_SACK: 3746163953Srrs { 3747170056Srrs struct sctp_sack_info *sack; 3748163953Srrs 3749170056Srrs SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize); 3750170056Srrs SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); 3751171477Srrs if (sack->sack_delay) { 3752171477Srrs if (sack->sack_delay > SCTP_MAX_SACK_DELAY) 3753171477Srrs sack->sack_delay = SCTP_MAX_SACK_DELAY; 3754223132Stuexen if (MSEC_TO_TICKS(sack->sack_delay) < 1) { 3755223132Stuexen sack->sack_delay = TICKS_TO_MSEC(1); 3756223132Stuexen } 3757171477Srrs } 3758166675Srrs if (stcb) { 3759170056Srrs if (sack->sack_delay) { 3760170056Srrs stcb->asoc.delayed_ack = sack->sack_delay; 3761170056Srrs } 3762170056Srrs if (sack->sack_freq) { 3763170056Srrs stcb->asoc.sack_freq = sack->sack_freq; 3764170056Srrs } 3765166675Srrs SCTP_TCB_UNLOCK(stcb); 3766166675Srrs } else { 3767224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3768224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3769224918Stuexen (sack->sack_assoc_id == SCTP_FUTURE_ASSOC) || 3770223132Stuexen (sack->sack_assoc_id == SCTP_ALL_ASSOC)) { 3771223132Stuexen SCTP_INP_WLOCK(inp); 3772223132Stuexen if (sack->sack_delay) { 3773223132Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay); 3774170056Srrs } 3775223132Stuexen if (sack->sack_freq) { 3776223132Stuexen inp->sctp_ep.sctp_sack_freq = sack->sack_freq; 3777223132Stuexen } 3778223132Stuexen SCTP_INP_WUNLOCK(inp); 3779170056Srrs } 3780223132Stuexen if ((sack->sack_assoc_id == SCTP_CURRENT_ASSOC) || 3781223132Stuexen (sack->sack_assoc_id == SCTP_ALL_ASSOC)) { 3782223132Stuexen SCTP_INP_RLOCK(inp); 3783223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3784223132Stuexen SCTP_TCB_LOCK(stcb); 3785223132Stuexen if (sack->sack_delay) { 3786223132Stuexen stcb->asoc.delayed_ack = sack->sack_delay; 3787223132Stuexen } 3788223132Stuexen if (sack->sack_freq) { 3789223132Stuexen stcb->asoc.sack_freq = sack->sack_freq; 3790223132Stuexen } 3791223132Stuexen SCTP_TCB_UNLOCK(stcb); 3792223132Stuexen } 3793223132Stuexen SCTP_INP_RUNLOCK(inp); 3794170056Srrs } 3795163953Srrs } 3796166675Srrs break; 3797163953Srrs } 3798163953Srrs case SCTP_AUTH_CHUNK: 3799163953Srrs { 3800163953Srrs struct sctp_authchunk *sauth; 3801163953Srrs 3802166675Srrs SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize); 3803166675Srrs 3804166675Srrs SCTP_INP_WLOCK(inp); 3805171943Srrs if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) { 3806171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3807163953Srrs error = EINVAL; 3808171943Srrs } 3809166675Srrs SCTP_INP_WUNLOCK(inp); 3810163953Srrs break; 3811163953Srrs } 3812163953Srrs case SCTP_AUTH_KEY: 3813163953Srrs { 3814163953Srrs struct sctp_authkey *sca; 3815163953Srrs struct sctp_keyhead *shared_keys; 3816163953Srrs sctp_sharedkey_t *shared_key; 3817163953Srrs sctp_key_t *key = NULL; 3818166675Srrs size_t size; 3819163953Srrs 3820166675Srrs SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize); 3821223697Stuexen if (sca->sca_keylength == 0) { 3822223697Stuexen size = optsize - sizeof(struct sctp_authkey); 3823223697Stuexen } else { 3824223697Stuexen if (sca->sca_keylength + sizeof(struct sctp_authkey) <= optsize) { 3825223697Stuexen size = sca->sca_keylength; 3826223697Stuexen } else { 3827223697Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3828223697Stuexen error = EINVAL; 3829223697Stuexen break; 3830223697Stuexen } 3831223697Stuexen } 3832169420Srrs SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id); 3833166675Srrs 3834166675Srrs if (stcb) { 3835163953Srrs shared_keys = &stcb->asoc.shared_keys; 3836163953Srrs /* clear the cached keys for this key id */ 3837163953Srrs sctp_clear_cachedkeys(stcb, sca->sca_keynumber); 3838163953Srrs /* 3839163953Srrs * create the new shared key and 3840163953Srrs * insert/replace it 3841163953Srrs */ 3842163953Srrs if (size > 0) { 3843163953Srrs key = sctp_set_key(sca->sca_key, (uint32_t) size); 3844163953Srrs if (key == NULL) { 3845171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3846163953Srrs error = ENOMEM; 3847163953Srrs SCTP_TCB_UNLOCK(stcb); 3848163953Srrs break; 3849163953Srrs } 3850163953Srrs } 3851163953Srrs shared_key = sctp_alloc_sharedkey(); 3852163953Srrs if (shared_key == NULL) { 3853163953Srrs sctp_free_key(key); 3854171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3855163953Srrs error = ENOMEM; 3856163953Srrs SCTP_TCB_UNLOCK(stcb); 3857163953Srrs break; 3858163953Srrs } 3859163953Srrs shared_key->key = key; 3860163953Srrs shared_key->keyid = sca->sca_keynumber; 3861185694Srrs error = sctp_insert_sharedkey(shared_keys, shared_key); 3862163953Srrs SCTP_TCB_UNLOCK(stcb); 3863163953Srrs } else { 3864224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3865224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3866224918Stuexen (sca->sca_assoc_id == SCTP_FUTURE_ASSOC) || 3867223132Stuexen (sca->sca_assoc_id == SCTP_ALL_ASSOC)) { 3868223132Stuexen SCTP_INP_WLOCK(inp); 3869223132Stuexen shared_keys = &inp->sctp_ep.shared_keys; 3870223132Stuexen /* 3871223132Stuexen * clear the cached keys on all 3872223132Stuexen * assocs for this key id 3873223132Stuexen */ 3874223132Stuexen sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber); 3875223132Stuexen /* 3876223132Stuexen * create the new shared key and 3877223132Stuexen * insert/replace it 3878223132Stuexen */ 3879223132Stuexen if (size > 0) { 3880223132Stuexen key = sctp_set_key(sca->sca_key, (uint32_t) size); 3881223132Stuexen if (key == NULL) { 3882223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3883223132Stuexen error = ENOMEM; 3884223132Stuexen SCTP_INP_WUNLOCK(inp); 3885223132Stuexen break; 3886223132Stuexen } 3887223132Stuexen } 3888223132Stuexen shared_key = sctp_alloc_sharedkey(); 3889223132Stuexen if (shared_key == NULL) { 3890223132Stuexen sctp_free_key(key); 3891171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3892163953Srrs error = ENOMEM; 3893163953Srrs SCTP_INP_WUNLOCK(inp); 3894163953Srrs break; 3895163953Srrs } 3896223132Stuexen shared_key->key = key; 3897223132Stuexen shared_key->keyid = sca->sca_keynumber; 3898223132Stuexen error = sctp_insert_sharedkey(shared_keys, shared_key); 3899163953Srrs SCTP_INP_WUNLOCK(inp); 3900163953Srrs } 3901223132Stuexen if ((sca->sca_assoc_id == SCTP_CURRENT_ASSOC) || 3902223132Stuexen (sca->sca_assoc_id == SCTP_ALL_ASSOC)) { 3903223132Stuexen SCTP_INP_RLOCK(inp); 3904223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3905223132Stuexen SCTP_TCB_LOCK(stcb); 3906223132Stuexen shared_keys = &stcb->asoc.shared_keys; 3907223132Stuexen /* 3908223132Stuexen * clear the cached keys for 3909223132Stuexen * this key id 3910223132Stuexen */ 3911223132Stuexen sctp_clear_cachedkeys(stcb, sca->sca_keynumber); 3912223132Stuexen /* 3913223132Stuexen * create the new shared key 3914223132Stuexen * and insert/replace it 3915223132Stuexen */ 3916223132Stuexen if (size > 0) { 3917223132Stuexen key = sctp_set_key(sca->sca_key, (uint32_t) size); 3918223132Stuexen if (key == NULL) { 3919223132Stuexen SCTP_TCB_UNLOCK(stcb); 3920223132Stuexen continue; 3921223132Stuexen } 3922223132Stuexen } 3923223132Stuexen shared_key = sctp_alloc_sharedkey(); 3924223132Stuexen if (shared_key == NULL) { 3925223132Stuexen sctp_free_key(key); 3926223132Stuexen SCTP_TCB_UNLOCK(stcb); 3927223132Stuexen continue; 3928223132Stuexen } 3929223132Stuexen shared_key->key = key; 3930223132Stuexen shared_key->keyid = sca->sca_keynumber; 3931223132Stuexen error = sctp_insert_sharedkey(shared_keys, shared_key); 3932223132Stuexen SCTP_TCB_UNLOCK(stcb); 3933223132Stuexen } 3934223132Stuexen SCTP_INP_RUNLOCK(inp); 3935223132Stuexen } 3936163953Srrs } 3937163953Srrs break; 3938163953Srrs } 3939163953Srrs case SCTP_HMAC_IDENT: 3940163953Srrs { 3941163953Srrs struct sctp_hmacalgo *shmac; 3942163953Srrs sctp_hmaclist_t *hmaclist; 3943181054Srrs uint16_t hmacid; 3944181054Srrs uint32_t i; 3945181054Srrs size_t found; 3946181054Srrs 3947166675Srrs SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize); 3948181054Srrs if (optsize < sizeof(struct sctp_hmacalgo) + shmac->shmac_number_of_idents * sizeof(uint16_t)) { 3949181054Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3950181054Srrs error = EINVAL; 3951181054Srrs break; 3952181054Srrs } 3953181054Srrs hmaclist = sctp_alloc_hmaclist(shmac->shmac_number_of_idents); 3954163953Srrs if (hmaclist == NULL) { 3955171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3956163953Srrs error = ENOMEM; 3957163953Srrs break; 3958163953Srrs } 3959181054Srrs for (i = 0; i < shmac->shmac_number_of_idents; i++) { 3960163953Srrs hmacid = shmac->shmac_idents[i]; 3961181054Srrs if (sctp_auth_add_hmacid(hmaclist, hmacid)) { 3962163953Srrs /* invalid HMACs were found */ ; 3963171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3964163953Srrs error = EINVAL; 3965164085Srrs sctp_free_hmaclist(hmaclist); 3966163953Srrs goto sctp_set_hmac_done; 3967163953Srrs } 3968163953Srrs } 3969170056Srrs found = 0; 3970170056Srrs for (i = 0; i < hmaclist->num_algo; i++) { 3971170056Srrs if (hmaclist->hmac[i] == SCTP_AUTH_HMAC_ID_SHA1) { 3972170056Srrs /* already in list */ 3973170056Srrs found = 1; 3974170056Srrs } 3975170056Srrs } 3976170056Srrs if (!found) { 3977170056Srrs sctp_free_hmaclist(hmaclist); 3978171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3979170056Srrs error = EINVAL; 3980170056Srrs break; 3981170056Srrs } 3982163953Srrs /* set it on the endpoint */ 3983163953Srrs SCTP_INP_WLOCK(inp); 3984163953Srrs if (inp->sctp_ep.local_hmacs) 3985163953Srrs sctp_free_hmaclist(inp->sctp_ep.local_hmacs); 3986163953Srrs inp->sctp_ep.local_hmacs = hmaclist; 3987163953Srrs SCTP_INP_WUNLOCK(inp); 3988163953Srrs sctp_set_hmac_done: 3989163953Srrs break; 3990163953Srrs } 3991163953Srrs case SCTP_AUTH_ACTIVE_KEY: 3992163953Srrs { 3993163953Srrs struct sctp_authkeyid *scact; 3994163953Srrs 3995223132Stuexen SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize); 3996166675Srrs SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); 3997166675Srrs 3998163953Srrs /* set the active key on the right place */ 3999166675Srrs if (stcb) { 4000163953Srrs /* set the active key on the assoc */ 4001185694Srrs if (sctp_auth_setactivekey(stcb, 4002185694Srrs scact->scact_keynumber)) { 4003185694Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, 4004185694Srrs SCTP_FROM_SCTP_USRREQ, 4005185694Srrs EINVAL); 4006163953Srrs error = EINVAL; 4007171943Srrs } 4008163953Srrs SCTP_TCB_UNLOCK(stcb); 4009163953Srrs } else { 4010224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4011224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4012224918Stuexen (scact->scact_assoc_id == SCTP_FUTURE_ASSOC) || 4013223132Stuexen (scact->scact_assoc_id == SCTP_ALL_ASSOC)) { 4014223132Stuexen SCTP_INP_WLOCK(inp); 4015223132Stuexen if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) { 4016223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4017223132Stuexen error = EINVAL; 4018223132Stuexen } 4019223132Stuexen SCTP_INP_WUNLOCK(inp); 4020171943Srrs } 4021223132Stuexen if ((scact->scact_assoc_id == SCTP_CURRENT_ASSOC) || 4022223132Stuexen (scact->scact_assoc_id == SCTP_ALL_ASSOC)) { 4023223132Stuexen SCTP_INP_RLOCK(inp); 4024223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4025223132Stuexen SCTP_TCB_LOCK(stcb); 4026223132Stuexen sctp_auth_setactivekey(stcb, scact->scact_keynumber); 4027223132Stuexen SCTP_TCB_UNLOCK(stcb); 4028223132Stuexen } 4029223132Stuexen SCTP_INP_RUNLOCK(inp); 4030223132Stuexen } 4031163953Srrs } 4032163953Srrs break; 4033163953Srrs } 4034163953Srrs case SCTP_AUTH_DELETE_KEY: 4035163953Srrs { 4036163953Srrs struct sctp_authkeyid *scdel; 4037163953Srrs 4038223132Stuexen SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize); 4039166675Srrs SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id); 4040166675Srrs 4041163953Srrs /* delete the key from the right place */ 4042166675Srrs if (stcb) { 4043223132Stuexen if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) { 4044223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4045163953Srrs error = EINVAL; 4046171943Srrs } 4047163953Srrs SCTP_TCB_UNLOCK(stcb); 4048163953Srrs } else { 4049224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4050224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4051224918Stuexen (scdel->scact_assoc_id == SCTP_FUTURE_ASSOC) || 4052223132Stuexen (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) { 4053223132Stuexen SCTP_INP_WLOCK(inp); 4054223132Stuexen if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) { 4055223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4056223132Stuexen error = EINVAL; 4057223132Stuexen } 4058223132Stuexen SCTP_INP_WUNLOCK(inp); 4059171943Srrs } 4060223132Stuexen if ((scdel->scact_assoc_id == SCTP_CURRENT_ASSOC) || 4061223132Stuexen (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) { 4062223132Stuexen SCTP_INP_RLOCK(inp); 4063223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4064223132Stuexen SCTP_TCB_LOCK(stcb); 4065223132Stuexen sctp_delete_sharedkey(stcb, scdel->scact_keynumber); 4066223132Stuexen SCTP_TCB_UNLOCK(stcb); 4067223132Stuexen } 4068223132Stuexen SCTP_INP_RUNLOCK(inp); 4069223132Stuexen } 4070163953Srrs } 4071163953Srrs break; 4072163953Srrs } 4073185694Srrs case SCTP_AUTH_DEACTIVATE_KEY: 4074185694Srrs { 4075185694Srrs struct sctp_authkeyid *keyid; 4076163953Srrs 4077223132Stuexen SCTP_CHECK_AND_CAST(keyid, optval, struct sctp_authkeyid, optsize); 4078185694Srrs SCTP_FIND_STCB(inp, stcb, keyid->scact_assoc_id); 4079185694Srrs 4080185694Srrs /* deactivate the key from the right place */ 4081185694Srrs if (stcb) { 4082223132Stuexen if (sctp_deact_sharedkey(stcb, keyid->scact_keynumber)) { 4083223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4084185694Srrs error = EINVAL; 4085185694Srrs } 4086185694Srrs SCTP_TCB_UNLOCK(stcb); 4087185694Srrs } else { 4088224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4089224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4090224918Stuexen (keyid->scact_assoc_id == SCTP_FUTURE_ASSOC) || 4091223132Stuexen (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) { 4092223132Stuexen SCTP_INP_WLOCK(inp); 4093223132Stuexen if (sctp_deact_sharedkey_ep(inp, keyid->scact_keynumber)) { 4094223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4095223132Stuexen error = EINVAL; 4096223132Stuexen } 4097223132Stuexen SCTP_INP_WUNLOCK(inp); 4098185694Srrs } 4099223132Stuexen if ((keyid->scact_assoc_id == SCTP_CURRENT_ASSOC) || 4100223132Stuexen (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) { 4101223132Stuexen SCTP_INP_RLOCK(inp); 4102223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4103223132Stuexen SCTP_TCB_LOCK(stcb); 4104223132Stuexen sctp_deact_sharedkey(stcb, keyid->scact_keynumber); 4105223132Stuexen SCTP_TCB_UNLOCK(stcb); 4106223132Stuexen } 4107223132Stuexen SCTP_INP_RUNLOCK(inp); 4108223132Stuexen } 4109185694Srrs } 4110185694Srrs break; 4111185694Srrs } 4112233660Srrs case SCTP_ENABLE_STREAM_RESET: 4113233660Srrs { 4114233660Srrs struct sctp_assoc_value *av; 4115185694Srrs 4116233660Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 4117233660Srrs if (av->assoc_value & (~SCTP_ENABLE_VALUE_MASK)) { 4118233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4119233660Srrs error = EINVAL; 4120233660Srrs break; 4121233660Srrs } 4122233660Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4123233660Srrs if (stcb) { 4124235021Stuexen stcb->asoc.local_strreset_support = (uint8_t) av->assoc_value; 4125233660Srrs SCTP_TCB_UNLOCK(stcb); 4126233660Srrs } else { 4127233660Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4128233660Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4129233660Srrs (av->assoc_id == SCTP_FUTURE_ASSOC) || 4130233660Srrs (av->assoc_id == SCTP_ALL_ASSOC)) { 4131233660Srrs SCTP_INP_WLOCK(inp); 4132235021Stuexen inp->local_strreset_support = (uint8_t) av->assoc_value; 4133233660Srrs SCTP_INP_WUNLOCK(inp); 4134233660Srrs } 4135233660Srrs if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 4136233660Srrs (av->assoc_id == SCTP_ALL_ASSOC)) { 4137233660Srrs SCTP_INP_RLOCK(inp); 4138233660Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4139233660Srrs SCTP_TCB_LOCK(stcb); 4140235021Stuexen stcb->asoc.local_strreset_support = (uint8_t) av->assoc_value; 4141233660Srrs SCTP_TCB_UNLOCK(stcb); 4142233660Srrs } 4143233660Srrs SCTP_INP_RUNLOCK(inp); 4144233660Srrs } 4145233660Srrs } 4146233660Srrs break; 4147233660Srrs } 4148163953Srrs case SCTP_RESET_STREAMS: 4149163953Srrs { 4150233660Srrs struct sctp_reset_streams *strrst; 4151233660Srrs int i, send_out = 0; 4152233660Srrs int send_in = 0; 4153163953Srrs 4154233660Srrs SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_reset_streams, optsize); 4155233660Srrs SCTP_FIND_STCB(inp, stcb, strrst->srs_assoc_id); 4156163953Srrs if (stcb == NULL) { 4157171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4158163953Srrs error = ENOENT; 4159163953Srrs break; 4160163953Srrs } 4161163953Srrs if (stcb->asoc.peer_supports_strreset == 0) { 4162163953Srrs /* 4163233660Srrs * Peer does not support the chunk type. 4164163953Srrs */ 4165233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4166233660Srrs error = EOPNOTSUPP; 4167163953Srrs SCTP_TCB_UNLOCK(stcb); 4168163953Srrs break; 4169163953Srrs } 4170163953Srrs if (stcb->asoc.stream_reset_outstanding) { 4171171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4172163953Srrs error = EALREADY; 4173163953Srrs SCTP_TCB_UNLOCK(stcb); 4174163953Srrs break; 4175163953Srrs } 4176233660Srrs if (strrst->srs_flags & SCTP_STREAM_RESET_INCOMING) { 4177163953Srrs send_in = 1; 4178233660Srrs } 4179233660Srrs if (strrst->srs_flags & SCTP_STREAM_RESET_OUTGOING) { 4180163953Srrs send_out = 1; 4181233660Srrs } 4182233660Srrs if ((send_in == 0) && (send_out == 0)) { 4183233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4184233660Srrs error = EINVAL; 4185233660Srrs SCTP_TCB_UNLOCK(stcb); 4186233660Srrs break; 4187233660Srrs } 4188233660Srrs for (i = 0; i < strrst->srs_number_streams; i++) { 4189233660Srrs if ((send_in) && 4190233660Srrs (strrst->srs_stream_list[i] > stcb->asoc.streamincnt)) { 4191233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4192188854Srrs error = EINVAL; 4193233660Srrs break; 4194188854Srrs } 4195233660Srrs if ((send_out) && 4196233660Srrs (strrst->srs_stream_list[i] > stcb->asoc.streamoutcnt)) { 4197233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4198233660Srrs error = EINVAL; 4199233660Srrs break; 4200188854Srrs } 4201233660Srrs } 4202233660Srrs if (error) { 4203233660Srrs SCTP_TCB_UNLOCK(stcb); 4204233660Srrs break; 4205233660Srrs } 4206233660Srrs error = sctp_send_str_reset_req(stcb, strrst->srs_number_streams, 4207233660Srrs strrst->srs_stream_list, 4208233660Srrs send_out, send_in, 0, 0, 0, 0, 0); 4209233660Srrs 4210233660Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); 4211233660Srrs SCTP_TCB_UNLOCK(stcb); 4212233660Srrs break; 4213233660Srrs } 4214233660Srrs case SCTP_ADD_STREAMS: 4215233660Srrs { 4216233660Srrs struct sctp_add_streams *stradd; 4217233660Srrs uint8_t addstream = 0; 4218233660Srrs uint16_t add_o_strmcnt = 0; 4219233660Srrs uint16_t add_i_strmcnt = 0; 4220233660Srrs 4221233660Srrs SCTP_CHECK_AND_CAST(stradd, optval, struct sctp_add_streams, optsize); 4222233660Srrs SCTP_FIND_STCB(inp, stcb, stradd->sas_assoc_id); 4223233660Srrs if (stcb == NULL) { 4224233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4225233660Srrs error = ENOENT; 4226233660Srrs break; 4227233660Srrs } 4228235057Stuexen if (stcb->asoc.peer_supports_strreset == 0) { 4229235057Stuexen /* 4230235057Stuexen * Peer does not support the chunk type. 4231235057Stuexen */ 4232235057Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4233235057Stuexen error = EOPNOTSUPP; 4234235057Stuexen SCTP_TCB_UNLOCK(stcb); 4235235057Stuexen break; 4236235057Stuexen } 4237235057Stuexen if (stcb->asoc.stream_reset_outstanding) { 4238235057Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4239235057Stuexen error = EALREADY; 4240235057Stuexen SCTP_TCB_UNLOCK(stcb); 4241235057Stuexen break; 4242235057Stuexen } 4243233660Srrs if ((stradd->sas_outstrms == 0) && 4244233660Srrs (stradd->sas_instrms == 0)) { 4245233660Srrs error = EINVAL; 4246233660Srrs goto skip_stuff; 4247233660Srrs } 4248233660Srrs if (stradd->sas_outstrms) { 4249188854Srrs addstream = 1; 4250188854Srrs /* We allocate here */ 4251233660Srrs add_o_strmcnt = stradd->sas_outstrms; 4252233660Srrs if ((((int)add_o_strmcnt) + ((int)stcb->asoc.streamoutcnt)) > 0x0000ffff) { 4253188854Srrs /* You can't have more than 64k */ 4254188854Srrs error = EINVAL; 4255188854Srrs goto skip_stuff; 4256188854Srrs } 4257163953Srrs } 4258233660Srrs if (stradd->sas_instrms) { 4259233660Srrs int cnt; 4260163953Srrs 4261233660Srrs addstream |= 2; 4262233660Srrs /* 4263233660Srrs * We allocate inside 4264233660Srrs * sctp_send_str_reset_req() 4265233660Srrs */ 4266233660Srrs add_i_strmcnt = stradd->sas_instrms; 4267233660Srrs cnt = add_i_strmcnt; 4268233660Srrs cnt += stcb->asoc.streamincnt; 4269233660Srrs if (cnt > 0x0000ffff) { 4270233660Srrs /* You can't have more than 64k */ 4271163953Srrs error = EINVAL; 4272233660Srrs goto skip_stuff; 4273163953Srrs } 4274233660Srrs if (cnt > (int)stcb->asoc.max_inbound_streams) { 4275233660Srrs /* More than you are allowed */ 4276163953Srrs error = EINVAL; 4277233660Srrs goto skip_stuff; 4278163953Srrs } 4279163953Srrs } 4280233660Srrs error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 0, addstream, add_o_strmcnt, add_i_strmcnt, 0); 4281233660Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); 4282188854Srrs skip_stuff: 4283233660Srrs SCTP_TCB_UNLOCK(stcb); 4284233660Srrs break; 4285233660Srrs } 4286233660Srrs case SCTP_RESET_ASSOC: 4287233660Srrs { 4288233660Srrs uint32_t *value; 4289233660Srrs 4290233660Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); 4291233660Srrs SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value); 4292233660Srrs if (stcb == NULL) { 4293233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4294233660Srrs error = ENOENT; 4295233660Srrs break; 4296233660Srrs } 4297233660Srrs if (stcb->asoc.peer_supports_strreset == 0) { 4298233660Srrs /* 4299233660Srrs * Peer does not support the chunk type. 4300233660Srrs */ 4301233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4302233660Srrs error = EOPNOTSUPP; 4303163953Srrs SCTP_TCB_UNLOCK(stcb); 4304163953Srrs break; 4305163953Srrs } 4306233660Srrs if (stcb->asoc.stream_reset_outstanding) { 4307233660Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4308233660Srrs error = EALREADY; 4309233660Srrs SCTP_TCB_UNLOCK(stcb); 4310233660Srrs break; 4311233660Srrs } 4312233660Srrs error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 1, 0, 0, 0, 0); 4313172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); 4314163953Srrs SCTP_TCB_UNLOCK(stcb); 4315223132Stuexen break; 4316163953Srrs } 4317163953Srrs case SCTP_CONNECT_X: 4318166675Srrs if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { 4319171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4320163953Srrs error = EINVAL; 4321163953Srrs break; 4322163953Srrs } 4323166675Srrs error = sctp_do_connect_x(so, inp, optval, optsize, p, 0); 4324163953Srrs break; 4325163953Srrs case SCTP_CONNECT_X_DELAYED: 4326166675Srrs if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { 4327171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4328163953Srrs error = EINVAL; 4329163953Srrs break; 4330163953Srrs } 4331166675Srrs error = sctp_do_connect_x(so, inp, optval, optsize, p, 1); 4332163953Srrs break; 4333163953Srrs case SCTP_CONNECT_X_COMPLETE: 4334163953Srrs { 4335163953Srrs struct sockaddr *sa; 4336163953Srrs struct sctp_nets *net; 4337163953Srrs 4338166675Srrs /* FIXME MT: check correct? */ 4339166675Srrs SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize); 4340166675Srrs 4341163953Srrs /* find tcb */ 4342163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 4343163953Srrs SCTP_INP_RLOCK(inp); 4344163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 4345163953Srrs if (stcb) { 4346163953Srrs SCTP_TCB_LOCK(stcb); 4347163953Srrs net = sctp_findnet(stcb, sa); 4348163953Srrs } 4349163953Srrs SCTP_INP_RUNLOCK(inp); 4350163953Srrs } else { 4351166675Srrs /* 4352166675Srrs * We increment here since 4353166675Srrs * sctp_findassociation_ep_addr() wil do a 4354166675Srrs * decrement if it finds the stcb as long as 4355166675Srrs * the locked tcb (last argument) is NOT a 4356166675Srrs * TCB.. aka NULL. 4357166675Srrs */ 4358163953Srrs SCTP_INP_INCR_REF(inp); 4359163953Srrs stcb = sctp_findassociation_ep_addr(&inp, sa, &net, NULL, NULL); 4360163953Srrs if (stcb == NULL) { 4361163953Srrs SCTP_INP_DECR_REF(inp); 4362163953Srrs } 4363163953Srrs } 4364163953Srrs 4365163953Srrs if (stcb == NULL) { 4366171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4367163953Srrs error = ENOENT; 4368163953Srrs break; 4369163953Srrs } 4370163953Srrs if (stcb->asoc.delayed_connection == 1) { 4371163953Srrs stcb->asoc.delayed_connection = 0; 4372169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 4373165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, 4374165220Srrs stcb->asoc.primary_destination, 4375165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9); 4376172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 4377163953Srrs } else { 4378163953Srrs /* 4379163953Srrs * already expired or did not use delayed 4380163953Srrs * connectx 4381163953Srrs */ 4382171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4383163953Srrs error = EALREADY; 4384163953Srrs } 4385163953Srrs SCTP_TCB_UNLOCK(stcb); 4386223132Stuexen break; 4387163953Srrs } 4388170056Srrs case SCTP_MAX_BURST: 4389163953Srrs { 4390217895Stuexen struct sctp_assoc_value *av; 4391163953Srrs 4392217895Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 4393217895Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4394166675Srrs 4395217895Stuexen if (stcb) { 4396217895Stuexen stcb->asoc.max_burst = av->assoc_value; 4397217895Stuexen SCTP_TCB_UNLOCK(stcb); 4398217895Stuexen } else { 4399224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4400224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4401224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 4402223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 4403223132Stuexen SCTP_INP_WLOCK(inp); 4404223132Stuexen inp->sctp_ep.max_burst = av->assoc_value; 4405223132Stuexen SCTP_INP_WUNLOCK(inp); 4406223132Stuexen } 4407223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 4408223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 4409223132Stuexen SCTP_INP_RLOCK(inp); 4410223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4411223132Stuexen SCTP_TCB_LOCK(stcb); 4412223132Stuexen stcb->asoc.max_burst = av->assoc_value; 4413223132Stuexen SCTP_TCB_UNLOCK(stcb); 4414223132Stuexen } 4415223132Stuexen SCTP_INP_RUNLOCK(inp); 4416223132Stuexen } 4417217895Stuexen } 4418223132Stuexen break; 4419163953Srrs } 4420163953Srrs case SCTP_MAXSEG: 4421163953Srrs { 4422167598Srrs struct sctp_assoc_value *av; 4423163953Srrs int ovh; 4424163953Srrs 4425167598Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 4426167598Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4427166675Srrs 4428170056Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 4429170056Srrs ovh = SCTP_MED_OVERHEAD; 4430170056Srrs } else { 4431170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 4432170056Srrs } 4433167598Srrs if (stcb) { 4434170056Srrs if (av->assoc_value) { 4435170056Srrs stcb->asoc.sctp_frag_point = (av->assoc_value + ovh); 4436170056Srrs } else { 4437170056Srrs stcb->asoc.sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; 4438170056Srrs } 4439167598Srrs SCTP_TCB_UNLOCK(stcb); 4440163953Srrs } else { 4441224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4442224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4443224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 4444223132Stuexen SCTP_INP_WLOCK(inp); 4445223132Stuexen /* 4446223132Stuexen * FIXME MT: I think this is not in 4447223132Stuexen * tune with the API ID 4448223132Stuexen */ 4449223132Stuexen if (av->assoc_value) { 4450223132Stuexen inp->sctp_frag_point = (av->assoc_value + ovh); 4451223132Stuexen } else { 4452223132Stuexen inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; 4453223132Stuexen } 4454223132Stuexen SCTP_INP_WUNLOCK(inp); 4455167598Srrs } else { 4456223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4457223132Stuexen error = EINVAL; 4458167598Srrs } 4459163953Srrs } 4460223132Stuexen break; 4461163953Srrs } 4462163953Srrs case SCTP_EVENTS: 4463163953Srrs { 4464163953Srrs struct sctp_event_subscribe *events; 4465163953Srrs 4466166675Srrs SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize); 4467166675Srrs 4468163953Srrs SCTP_INP_WLOCK(inp); 4469163953Srrs if (events->sctp_data_io_event) { 4470163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); 4471163953Srrs } else { 4472163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); 4473163953Srrs } 4474163953Srrs 4475163953Srrs if (events->sctp_association_event) { 4476163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); 4477163953Srrs } else { 4478163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); 4479163953Srrs } 4480163953Srrs 4481163953Srrs if (events->sctp_address_event) { 4482163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); 4483163953Srrs } else { 4484163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); 4485163953Srrs } 4486163953Srrs 4487163953Srrs if (events->sctp_send_failure_event) { 4488163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 4489163953Srrs } else { 4490163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 4491163953Srrs } 4492163953Srrs 4493163953Srrs if (events->sctp_peer_error_event) { 4494163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR); 4495163953Srrs } else { 4496163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR); 4497163953Srrs } 4498163953Srrs 4499163953Srrs if (events->sctp_shutdown_event) { 4500163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 4501163953Srrs } else { 4502163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 4503163953Srrs } 4504163953Srrs 4505163953Srrs if (events->sctp_partial_delivery_event) { 4506163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT); 4507163953Srrs } else { 4508163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT); 4509163953Srrs } 4510163953Srrs 4511163953Srrs if (events->sctp_adaptation_layer_event) { 4512163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 4513163953Srrs } else { 4514163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 4515163953Srrs } 4516163953Srrs 4517163953Srrs if (events->sctp_authentication_event) { 4518163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT); 4519163953Srrs } else { 4520163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT); 4521163953Srrs } 4522163953Srrs 4523185694Srrs if (events->sctp_sender_dry_event) { 4524185694Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT); 4525185694Srrs } else { 4526185694Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT); 4527185694Srrs } 4528185694Srrs 4529202520Srrs if (events->sctp_stream_reset_event) { 4530163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 4531163953Srrs } else { 4532163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 4533163953Srrs } 4534163953Srrs SCTP_INP_WUNLOCK(inp); 4535223132Stuexen 4536223132Stuexen SCTP_INP_RLOCK(inp); 4537223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4538223132Stuexen SCTP_TCB_LOCK(stcb); 4539223132Stuexen if (events->sctp_association_event) { 4540223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT); 4541223132Stuexen } else { 4542223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT); 4543223132Stuexen } 4544223132Stuexen if (events->sctp_address_event) { 4545223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT); 4546223132Stuexen } else { 4547223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT); 4548223132Stuexen } 4549223132Stuexen if (events->sctp_send_failure_event) { 4550223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 4551223132Stuexen } else { 4552223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 4553223132Stuexen } 4554223132Stuexen if (events->sctp_peer_error_event) { 4555223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR); 4556223132Stuexen } else { 4557223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR); 4558223132Stuexen } 4559223132Stuexen if (events->sctp_shutdown_event) { 4560223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 4561223132Stuexen } else { 4562223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 4563223132Stuexen } 4564223132Stuexen if (events->sctp_partial_delivery_event) { 4565223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT); 4566223132Stuexen } else { 4567223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT); 4568223132Stuexen } 4569223132Stuexen if (events->sctp_adaptation_layer_event) { 4570223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 4571223132Stuexen } else { 4572223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 4573223132Stuexen } 4574223132Stuexen if (events->sctp_authentication_event) { 4575223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT); 4576223132Stuexen } else { 4577223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT); 4578223132Stuexen } 4579223132Stuexen if (events->sctp_sender_dry_event) { 4580223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT); 4581223132Stuexen } else { 4582223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT); 4583223132Stuexen } 4584223132Stuexen if (events->sctp_stream_reset_event) { 4585223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 4586223132Stuexen } else { 4587223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 4588223132Stuexen } 4589223132Stuexen SCTP_TCB_UNLOCK(stcb); 4590223132Stuexen } 4591223132Stuexen /* 4592223132Stuexen * Send up the sender dry event only for 1-to-1 4593223132Stuexen * style sockets. 4594223132Stuexen */ 4595223132Stuexen if (events->sctp_sender_dry_event) { 4596223132Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4597223132Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 4598223132Stuexen stcb = LIST_FIRST(&inp->sctp_asoc_list); 4599223132Stuexen if (stcb) { 4600223132Stuexen SCTP_TCB_LOCK(stcb); 4601223132Stuexen if (TAILQ_EMPTY(&stcb->asoc.send_queue) && 4602223132Stuexen TAILQ_EMPTY(&stcb->asoc.sent_queue) && 4603223132Stuexen (stcb->asoc.stream_queue_cnt == 0)) { 4604223132Stuexen sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED); 4605223132Stuexen } 4606223132Stuexen SCTP_TCB_UNLOCK(stcb); 4607223132Stuexen } 4608223132Stuexen } 4609223132Stuexen } 4610223132Stuexen SCTP_INP_RUNLOCK(inp); 4611223132Stuexen break; 4612163953Srrs } 4613163953Srrs case SCTP_ADAPTATION_LAYER: 4614163953Srrs { 4615163953Srrs struct sctp_setadaptation *adap_bits; 4616163953Srrs 4617166675Srrs SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize); 4618163953Srrs SCTP_INP_WLOCK(inp); 4619163953Srrs inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind; 4620163953Srrs SCTP_INP_WUNLOCK(inp); 4621223132Stuexen break; 4622163953Srrs } 4623166675Srrs#ifdef SCTP_DEBUG 4624163953Srrs case SCTP_SET_INITIAL_DBG_SEQ: 4625163953Srrs { 4626163953Srrs uint32_t *vvv; 4627163953Srrs 4628166675Srrs SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize); 4629163953Srrs SCTP_INP_WLOCK(inp); 4630163953Srrs inp->sctp_ep.initial_sequence_debug = *vvv; 4631163953Srrs SCTP_INP_WUNLOCK(inp); 4632223132Stuexen break; 4633163953Srrs } 4634166675Srrs#endif 4635163953Srrs case SCTP_DEFAULT_SEND_PARAM: 4636163953Srrs { 4637163953Srrs struct sctp_sndrcvinfo *s_info; 4638163953Srrs 4639166675Srrs SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize); 4640166675Srrs SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); 4641163953Srrs 4642166675Srrs if (stcb) { 4643223132Stuexen if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) { 4644170056Srrs memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send))); 4645163953Srrs } else { 4646171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4647166675Srrs error = EINVAL; 4648163953Srrs } 4649166675Srrs SCTP_TCB_UNLOCK(stcb); 4650166675Srrs } else { 4651224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4652224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4653224918Stuexen (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) || 4654223132Stuexen (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) { 4655223132Stuexen SCTP_INP_WLOCK(inp); 4656223132Stuexen memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send))); 4657223132Stuexen SCTP_INP_WUNLOCK(inp); 4658223132Stuexen } 4659223132Stuexen if ((s_info->sinfo_assoc_id == SCTP_CURRENT_ASSOC) || 4660223132Stuexen (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) { 4661223132Stuexen SCTP_INP_RLOCK(inp); 4662223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4663223132Stuexen SCTP_TCB_LOCK(stcb); 4664223132Stuexen if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) { 4665223132Stuexen memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send))); 4666223132Stuexen } 4667223132Stuexen SCTP_TCB_UNLOCK(stcb); 4668223132Stuexen } 4669223132Stuexen SCTP_INP_RUNLOCK(inp); 4670223132Stuexen } 4671163953Srrs } 4672223132Stuexen break; 4673163953Srrs } 4674163953Srrs case SCTP_PEER_ADDR_PARAMS: 4675163953Srrs { 4676163953Srrs struct sctp_paddrparams *paddrp; 4677163953Srrs struct sctp_nets *net; 4678163953Srrs 4679166675Srrs SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize); 4680166675Srrs SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); 4681163953Srrs net = NULL; 4682166675Srrs if (stcb) { 4683166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address); 4684166675Srrs } else { 4685166675Srrs /* 4686166675Srrs * We increment here since 4687166675Srrs * sctp_findassociation_ep_addr() wil do a 4688166675Srrs * decrement if it finds the stcb as long as 4689166675Srrs * the locked tcb (last argument) is NOT a 4690166675Srrs * TCB.. aka NULL. 4691166675Srrs */ 4692166675Srrs SCTP_INP_INCR_REF(inp); 4693166675Srrs stcb = sctp_findassociation_ep_addr(&inp, 4694166675Srrs (struct sockaddr *)&paddrp->spp_address, 4695166675Srrs &net, NULL, NULL); 4696163953Srrs if (stcb == NULL) { 4697166675Srrs SCTP_INP_DECR_REF(inp); 4698163953Srrs } 4699163953Srrs } 4700171943Srrs if (stcb && (net == NULL)) { 4701171943Srrs struct sockaddr *sa; 4702171943Srrs 4703171943Srrs sa = (struct sockaddr *)&paddrp->spp_address; 4704221249Stuexen#ifdef INET 4705171943Srrs if (sa->sa_family == AF_INET) { 4706221249Stuexen 4707171943Srrs struct sockaddr_in *sin; 4708171943Srrs 4709171943Srrs sin = (struct sockaddr_in *)sa; 4710171943Srrs if (sin->sin_addr.s_addr) { 4711171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4712171943Srrs SCTP_TCB_UNLOCK(stcb); 4713171943Srrs error = EINVAL; 4714171943Srrs break; 4715171943Srrs } 4716221249Stuexen } else 4717221249Stuexen#endif 4718221249Stuexen#ifdef INET6 4719221249Stuexen if (sa->sa_family == AF_INET6) { 4720171943Srrs struct sockaddr_in6 *sin6; 4721171943Srrs 4722171943Srrs sin6 = (struct sockaddr_in6 *)sa; 4723171943Srrs if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 4724171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4725171943Srrs SCTP_TCB_UNLOCK(stcb); 4726171943Srrs error = EINVAL; 4727171943Srrs break; 4728171943Srrs } 4729221249Stuexen } else 4730221249Stuexen#endif 4731221249Stuexen { 4732171943Srrs error = EAFNOSUPPORT; 4733171943Srrs SCTP_TCB_UNLOCK(stcb); 4734171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 4735171943Srrs break; 4736171943Srrs } 4737171943Srrs } 4738170056Srrs /* sanity checks */ 4739170056Srrs if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) { 4740170056Srrs if (stcb) 4741170056Srrs SCTP_TCB_UNLOCK(stcb); 4742171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4743170056Srrs return (EINVAL); 4744170056Srrs } 4745170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) { 4746170056Srrs if (stcb) 4747170056Srrs SCTP_TCB_UNLOCK(stcb); 4748171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4749170056Srrs return (EINVAL); 4750170056Srrs } 4751163953Srrs if (stcb) { 4752163953Srrs /************************TCB SPECIFIC SET ******************/ 4753163953Srrs /* 4754163953Srrs * do we change the timer for HB, we run 4755163953Srrs * only one? 4756163953Srrs */ 4757170056Srrs int ovh = 0; 4758170056Srrs 4759170056Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 4760170056Srrs ovh = SCTP_MED_OVERHEAD; 4761170056Srrs } else { 4762170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 4763170056Srrs } 4764170056Srrs 4765163953Srrs /* network sets ? */ 4766163953Srrs if (net) { 4767163953Srrs /************************NET SPECIFIC SET ******************/ 4768224641Stuexen if (paddrp->spp_flags & SPP_HB_DISABLE) { 4769224641Stuexen if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) && 4770224641Stuexen !(net->dest_state & SCTP_ADDR_NOHB)) { 4771224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 4772224641Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 4773171440Srrs } 4774163953Srrs net->dest_state |= SCTP_ADDR_NOHB; 4775163953Srrs } 4776163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 4777224641Stuexen if (paddrp->spp_hbinterval) { 4778224641Stuexen net->heart_beat_delay = paddrp->spp_hbinterval; 4779224641Stuexen } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 4780224641Stuexen net->heart_beat_delay = 0; 4781224641Stuexen } 4782224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 4783224641Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 4784224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 4785163953Srrs net->dest_state &= ~SCTP_ADDR_NOHB; 4786163953Srrs } 4787224641Stuexen if (paddrp->spp_flags & SPP_HB_DEMAND) { 4788224641Stuexen /* on demand HB */ 4789224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 4790228391Stuexen sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED); 4791224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 4792224641Stuexen } 4793170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { 4794165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 4795165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 4796165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 4797163953Srrs } 4798225635Stuexen net->dest_state |= SCTP_ADDR_NO_PMTUD; 4799163953Srrs if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) { 4800170056Srrs net->mtu = paddrp->spp_pathmtu + ovh; 4801169352Srrs if (net->mtu < stcb->asoc.smallest_mtu) { 4802228653Stuexen sctp_pathmtu_adjustment(stcb, net->mtu); 4803169352Srrs } 4804163953Srrs } 4805163953Srrs } 4806163953Srrs if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 4807225635Stuexen if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 4808163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 4809163953Srrs } 4810225635Stuexen net->dest_state &= ~SCTP_ADDR_NO_PMTUD; 4811163953Srrs } 4812224641Stuexen if (paddrp->spp_pathmaxrxt) { 4813224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 4814224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 4815224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 4816224641Stuexen } 4817224641Stuexen } else { 4818224641Stuexen if ((net->error_count <= paddrp->spp_pathmaxrxt) && 4819224641Stuexen (net->error_count > net->pf_threshold)) { 4820224641Stuexen net->dest_state |= SCTP_ADDR_PF; 4821224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 4822224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); 4823224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 4824224641Stuexen } 4825224641Stuexen } 4826224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 4827224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 4828224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 4829235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); 4830224641Stuexen } 4831224641Stuexen } else { 4832224641Stuexen if (net->error_count <= paddrp->spp_pathmaxrxt) { 4833224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 4834235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); 4835224641Stuexen } 4836224641Stuexen } 4837163953Srrs net->failure_threshold = paddrp->spp_pathmaxrxt; 4838224641Stuexen } 4839224870Stuexen if (paddrp->spp_flags & SPP_DSCP) { 4840226252Stuexen net->dscp = paddrp->spp_dscp & 0xfc; 4841225549Stuexen net->dscp |= 0x01; 4842163953Srrs } 4843167598Srrs#ifdef INET6 4844163953Srrs if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { 4845225549Stuexen if (net->ro._l_addr.sa.sa_family == AF_INET6) { 4846224870Stuexen net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 4847225549Stuexen net->flowlabel |= 0x80000000; 4848163953Srrs } 4849163953Srrs } 4850163953Srrs#endif 4851163953Srrs } else { 4852163953Srrs /************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/ 4853224641Stuexen if (paddrp->spp_pathmaxrxt) { 4854163953Srrs stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt; 4855224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4856224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 4857224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 4858224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 4859224641Stuexen } 4860224641Stuexen } else { 4861224641Stuexen if ((net->error_count <= paddrp->spp_pathmaxrxt) && 4862224641Stuexen (net->error_count > net->pf_threshold)) { 4863224641Stuexen net->dest_state |= SCTP_ADDR_PF; 4864224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 4865224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); 4866224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 4867224641Stuexen } 4868224641Stuexen } 4869224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 4870224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 4871224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 4872235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); 4873224641Stuexen } 4874224641Stuexen } else { 4875224641Stuexen if (net->error_count <= paddrp->spp_pathmaxrxt) { 4876224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 4877235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); 4878224641Stuexen } 4879224641Stuexen } 4880224641Stuexen net->failure_threshold = paddrp->spp_pathmaxrxt; 4881224641Stuexen } 4882224641Stuexen } 4883163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 4884224641Stuexen if (paddrp->spp_hbinterval) { 4885224641Stuexen stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval; 4886224641Stuexen } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 4887224641Stuexen stcb->asoc.heart_beat_delay = 0; 4888224641Stuexen } 4889163953Srrs /* Turn back on the timer */ 4890224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4891224641Stuexen if (paddrp->spp_hbinterval) { 4892224641Stuexen net->heart_beat_delay = paddrp->spp_hbinterval; 4893224641Stuexen } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 4894224641Stuexen net->heart_beat_delay = 0; 4895224641Stuexen } 4896224641Stuexen if (net->dest_state & SCTP_ADDR_NOHB) { 4897224641Stuexen net->dest_state &= ~SCTP_ADDR_NOHB; 4898224641Stuexen } 4899224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 4900224641Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 4901224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 4902224641Stuexen } 4903225635Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 4904163953Srrs } 4905224641Stuexen if (paddrp->spp_flags & SPP_HB_DISABLE) { 4906224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4907224641Stuexen if (!(net->dest_state & SCTP_ADDR_NOHB)) { 4908224641Stuexen net->dest_state |= SCTP_ADDR_NOHB; 4909224641Stuexen if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { 4910224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 4911224641Stuexen } 4912224641Stuexen } 4913224641Stuexen } 4914225635Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 4915224641Stuexen } 4916170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { 4917170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4918170056Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 4919170056Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 4920170056Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 4921170056Srrs } 4922225635Stuexen net->dest_state |= SCTP_ADDR_NO_PMTUD; 4923170056Srrs if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) { 4924170056Srrs net->mtu = paddrp->spp_pathmtu + ovh; 4925170056Srrs if (net->mtu < stcb->asoc.smallest_mtu) { 4926228653Stuexen sctp_pathmtu_adjustment(stcb, net->mtu); 4927170056Srrs } 4928170056Srrs } 4929170056Srrs } 4930225635Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 4931170056Srrs } 4932170056Srrs if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 4933170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4934225635Stuexen if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 4935170056Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 4936170056Srrs } 4937225635Stuexen net->dest_state &= ~SCTP_ADDR_NO_PMTUD; 4938170056Srrs } 4939225635Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 4940170056Srrs } 4941224870Stuexen if (paddrp->spp_flags & SPP_DSCP) { 4942224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4943226252Stuexen net->dscp = paddrp->spp_dscp & 0xfc; 4944225549Stuexen net->dscp |= 0x01; 4945163953Srrs } 4946226252Stuexen stcb->asoc.default_dscp = paddrp->spp_dscp & 0xfc; 4947225549Stuexen stcb->asoc.default_dscp |= 0x01; 4948163953Srrs } 4949225549Stuexen#ifdef INET6 4950224641Stuexen if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { 4951170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4952225549Stuexen if (net->ro._l_addr.sa.sa_family == AF_INET6) { 4953225549Stuexen net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 4954225549Stuexen net->flowlabel |= 0x80000000; 4955225549Stuexen } 4956170056Srrs } 4957225549Stuexen stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 4958225549Stuexen stcb->asoc.default_flowlabel |= 0x80000000; 4959163953Srrs } 4960225549Stuexen#endif 4961163953Srrs } 4962163953Srrs SCTP_TCB_UNLOCK(stcb); 4963163953Srrs } else { 4964163953Srrs /************************NO TCB, SET TO default stuff ******************/ 4965224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4966224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4967224918Stuexen (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) { 4968223132Stuexen SCTP_INP_WLOCK(inp); 4969223132Stuexen /* 4970223132Stuexen * For the TOS/FLOWLABEL stuff you 4971223132Stuexen * set it with the options on the 4972223132Stuexen * socket 4973223132Stuexen */ 4974223132Stuexen if (paddrp->spp_pathmaxrxt) { 4975223132Stuexen inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt; 4976223132Stuexen } 4977223132Stuexen if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) 4978223132Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0; 4979223132Stuexen else if (paddrp->spp_hbinterval) { 4980223132Stuexen if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL) 4981223132Stuexen paddrp->spp_hbinterval = SCTP_MAX_HB_INTERVAL; 4982223132Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval); 4983223132Stuexen } 4984223132Stuexen if (paddrp->spp_flags & SPP_HB_ENABLE) { 4985224641Stuexen if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 4986224641Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0; 4987224641Stuexen } else if (paddrp->spp_hbinterval) { 4988224641Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval); 4989224641Stuexen } 4990223132Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 4991223132Stuexen } else if (paddrp->spp_flags & SPP_HB_DISABLE) { 4992223132Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 4993223132Stuexen } 4994225635Stuexen if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 4995225635Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 4996225635Stuexen } else if (paddrp->spp_flags & SPP_PMTUD_DISABLE) { 4997225635Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 4998225635Stuexen } 4999225549Stuexen if (paddrp->spp_flags & SPP_DSCP) { 5000226252Stuexen inp->sctp_ep.default_dscp = paddrp->spp_dscp & 0xfc; 5001225549Stuexen inp->sctp_ep.default_dscp |= 0x01; 5002225549Stuexen } 5003225549Stuexen#ifdef INET6 5004225549Stuexen if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { 5005225549Stuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 5006225549Stuexen inp->sctp_ep.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 5007225549Stuexen inp->sctp_ep.default_flowlabel |= 0x80000000; 5008225549Stuexen } 5009225549Stuexen } 5010225549Stuexen#endif 5011223132Stuexen SCTP_INP_WUNLOCK(inp); 5012223132Stuexen } else { 5013223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5014223132Stuexen error = EINVAL; 5015163953Srrs } 5016163953Srrs } 5017223132Stuexen break; 5018163953Srrs } 5019163953Srrs case SCTP_RTOINFO: 5020163953Srrs { 5021163953Srrs struct sctp_rtoinfo *srto; 5022169655Srrs uint32_t new_init, new_min, new_max; 5023163953Srrs 5024166675Srrs SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize); 5025166675Srrs SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); 5026166675Srrs 5027166675Srrs if (stcb) { 5028167598Srrs if (srto->srto_initial) 5029169655Srrs new_init = srto->srto_initial; 5030169655Srrs else 5031169655Srrs new_init = stcb->asoc.initial_rto; 5032167598Srrs if (srto->srto_max) 5033169655Srrs new_max = srto->srto_max; 5034169655Srrs else 5035169655Srrs new_max = stcb->asoc.maxrto; 5036167598Srrs if (srto->srto_min) 5037169655Srrs new_min = srto->srto_min; 5038169655Srrs else 5039169655Srrs new_min = stcb->asoc.minrto; 5040169655Srrs if ((new_min <= new_init) && (new_init <= new_max)) { 5041169655Srrs stcb->asoc.initial_rto = new_init; 5042169655Srrs stcb->asoc.maxrto = new_max; 5043169655Srrs stcb->asoc.minrto = new_min; 5044169655Srrs } else { 5045179783Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5046179783Srrs error = EINVAL; 5047169655Srrs } 5048166675Srrs SCTP_TCB_UNLOCK(stcb); 5049166675Srrs } else { 5050224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5051224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5052224918Stuexen (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) { 5053223132Stuexen SCTP_INP_WLOCK(inp); 5054223132Stuexen if (srto->srto_initial) 5055223132Stuexen new_init = srto->srto_initial; 5056223132Stuexen else 5057223132Stuexen new_init = inp->sctp_ep.initial_rto; 5058223132Stuexen if (srto->srto_max) 5059223132Stuexen new_max = srto->srto_max; 5060223132Stuexen else 5061223132Stuexen new_max = inp->sctp_ep.sctp_maxrto; 5062223132Stuexen if (srto->srto_min) 5063223132Stuexen new_min = srto->srto_min; 5064223132Stuexen else 5065223132Stuexen new_min = inp->sctp_ep.sctp_minrto; 5066223132Stuexen if ((new_min <= new_init) && (new_init <= new_max)) { 5067223132Stuexen inp->sctp_ep.initial_rto = new_init; 5068223132Stuexen inp->sctp_ep.sctp_maxrto = new_max; 5069223132Stuexen inp->sctp_ep.sctp_minrto = new_min; 5070223132Stuexen } else { 5071223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5072223132Stuexen error = EINVAL; 5073223132Stuexen } 5074223132Stuexen SCTP_INP_WUNLOCK(inp); 5075169655Srrs } else { 5076179783Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5077179783Srrs error = EINVAL; 5078169655Srrs } 5079163953Srrs } 5080223132Stuexen break; 5081163953Srrs } 5082163953Srrs case SCTP_ASSOCINFO: 5083163953Srrs { 5084163953Srrs struct sctp_assocparams *sasoc; 5085163953Srrs 5086166675Srrs SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize); 5087166675Srrs SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); 5088171477Srrs if (sasoc->sasoc_cookie_life) { 5089171477Srrs /* boundary check the cookie life */ 5090171477Srrs if (sasoc->sasoc_cookie_life < 1000) 5091171477Srrs sasoc->sasoc_cookie_life = 1000; 5092171477Srrs if (sasoc->sasoc_cookie_life > SCTP_MAX_COOKIE_LIFE) { 5093171477Srrs sasoc->sasoc_cookie_life = SCTP_MAX_COOKIE_LIFE; 5094171477Srrs } 5095171477Srrs } 5096163953Srrs if (stcb) { 5097163953Srrs if (sasoc->sasoc_asocmaxrxt) 5098163953Srrs stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt; 5099170056Srrs if (sasoc->sasoc_cookie_life) { 5100171572Srrs stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); 5101167598Srrs } 5102163953Srrs SCTP_TCB_UNLOCK(stcb); 5103163953Srrs } else { 5104224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5105224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5106224918Stuexen (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) { 5107223132Stuexen SCTP_INP_WLOCK(inp); 5108223132Stuexen if (sasoc->sasoc_asocmaxrxt) 5109223132Stuexen inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt; 5110223132Stuexen if (sasoc->sasoc_cookie_life) { 5111223132Stuexen inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); 5112223132Stuexen } 5113223132Stuexen SCTP_INP_WUNLOCK(inp); 5114223132Stuexen } else { 5115223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5116223132Stuexen error = EINVAL; 5117167598Srrs } 5118163953Srrs } 5119223132Stuexen break; 5120163953Srrs } 5121163953Srrs case SCTP_INITMSG: 5122163953Srrs { 5123163953Srrs struct sctp_initmsg *sinit; 5124163953Srrs 5125166675Srrs SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize); 5126163953Srrs SCTP_INP_WLOCK(inp); 5127163953Srrs if (sinit->sinit_num_ostreams) 5128163953Srrs inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams; 5129163953Srrs 5130163953Srrs if (sinit->sinit_max_instreams) 5131163953Srrs inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams; 5132163953Srrs 5133163953Srrs if (sinit->sinit_max_attempts) 5134163953Srrs inp->sctp_ep.max_init_times = sinit->sinit_max_attempts; 5135163953Srrs 5136167598Srrs if (sinit->sinit_max_init_timeo) 5137163953Srrs inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo; 5138163953Srrs SCTP_INP_WUNLOCK(inp); 5139223132Stuexen break; 5140163953Srrs } 5141163953Srrs case SCTP_PRIMARY_ADDR: 5142163953Srrs { 5143163953Srrs struct sctp_setprim *spa; 5144223132Stuexen struct sctp_nets *net; 5145163953Srrs 5146166675Srrs SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize); 5147166675Srrs SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id); 5148163953Srrs 5149166675Srrs net = NULL; 5150166675Srrs if (stcb) { 5151166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&spa->ssp_addr); 5152166675Srrs } else { 5153166675Srrs /* 5154166675Srrs * We increment here since 5155166675Srrs * sctp_findassociation_ep_addr() wil do a 5156166675Srrs * decrement if it finds the stcb as long as 5157166675Srrs * the locked tcb (last argument) is NOT a 5158166675Srrs * TCB.. aka NULL. 5159166675Srrs */ 5160163953Srrs SCTP_INP_INCR_REF(inp); 5161163953Srrs stcb = sctp_findassociation_ep_addr(&inp, 5162163953Srrs (struct sockaddr *)&spa->ssp_addr, 5163163953Srrs &net, NULL, NULL); 5164163953Srrs if (stcb == NULL) { 5165163953Srrs SCTP_INP_DECR_REF(inp); 5166163953Srrs } 5167163953Srrs } 5168166675Srrs 5169166675Srrs if ((stcb) && (net)) { 5170166675Srrs if ((net != stcb->asoc.primary_destination) && 5171166675Srrs (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) { 5172166675Srrs /* Ok we need to set it */ 5173166675Srrs if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) { 5174224641Stuexen if ((stcb->asoc.alternate) && 5175224641Stuexen (!(net->dest_state & SCTP_ADDR_PF)) && 5176224641Stuexen (net->dest_state & SCTP_ADDR_REACHABLE)) { 5177224641Stuexen sctp_free_remote_addr(stcb->asoc.alternate); 5178224641Stuexen stcb->asoc.alternate = NULL; 5179166675Srrs } 5180163953Srrs } 5181163953Srrs } 5182166675Srrs } else { 5183171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5184166675Srrs error = EINVAL; 5185163953Srrs } 5186166675Srrs if (stcb) { 5187166675Srrs SCTP_TCB_UNLOCK(stcb); 5188166675Srrs } 5189223132Stuexen break; 5190163953Srrs } 5191167598Srrs case SCTP_SET_DYNAMIC_PRIMARY: 5192167598Srrs { 5193167598Srrs union sctp_sockstore *ss; 5194163953Srrs 5195170587Srwatson error = priv_check(curthread, 5196170587Srwatson PRIV_NETINET_RESERVEDPORT); 5197167598Srrs if (error) 5198167598Srrs break; 5199167598Srrs 5200167598Srrs SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize); 5201167598Srrs /* SUPER USER CHECK? */ 5202167598Srrs error = sctp_dynamic_set_primary(&ss->sa, vrf_id); 5203223132Stuexen break; 5204167598Srrs } 5205163953Srrs case SCTP_SET_PEER_PRIMARY_ADDR: 5206163953Srrs { 5207163953Srrs struct sctp_setpeerprim *sspp; 5208163953Srrs 5209166675Srrs SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize); 5210166675Srrs SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id); 5211169208Srrs if (stcb != NULL) { 5212170056Srrs struct sctp_ifa *ifa; 5213170056Srrs 5214170056Srrs ifa = sctp_find_ifa_by_addr((struct sockaddr *)&sspp->sspp_addr, 5215172091Srrs stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED); 5216170056Srrs if (ifa == NULL) { 5217171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5218166675Srrs error = EINVAL; 5219170056Srrs goto out_of_it; 5220166675Srrs } 5221170056Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { 5222170056Srrs /* 5223170056Srrs * Must validate the ifa found is in 5224170056Srrs * our ep 5225170056Srrs */ 5226170056Srrs struct sctp_laddr *laddr; 5227170056Srrs int found = 0; 5228170056Srrs 5229170056Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 5230170056Srrs if (laddr->ifa == NULL) { 5231170056Srrs SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n", 5232170056Srrs __FUNCTION__); 5233170056Srrs continue; 5234170056Srrs } 5235170056Srrs if (laddr->ifa == ifa) { 5236170056Srrs found = 1; 5237170056Srrs break; 5238170056Srrs } 5239170056Srrs } 5240170056Srrs if (!found) { 5241171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5242170056Srrs error = EINVAL; 5243170056Srrs goto out_of_it; 5244170056Srrs } 5245170056Srrs } 5246170056Srrs if (sctp_set_primary_ip_address_sa(stcb, 5247170056Srrs (struct sockaddr *)&sspp->sspp_addr) != 0) { 5248171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5249170056Srrs error = EINVAL; 5250170056Srrs } 5251170056Srrs out_of_it: 5252169208Srrs SCTP_TCB_UNLOCK(stcb); 5253166675Srrs } else { 5254171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5255163953Srrs error = EINVAL; 5256163953Srrs } 5257223132Stuexen break; 5258163953Srrs } 5259163953Srrs case SCTP_BINDX_ADD_ADDR: 5260163953Srrs { 5261163953Srrs struct sctp_getaddresses *addrs; 5262171477Srrs struct thread *td; 5263163953Srrs 5264171477Srrs td = (struct thread *)p; 5265170606Srrs SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, 5266170606Srrs optsize); 5267221249Stuexen#ifdef INET 5268171477Srrs if (addrs->addr->sa_family == AF_INET) { 5269238501Stuexen if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) { 5270171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5271171477Srrs error = EINVAL; 5272171477Srrs break; 5273171477Srrs } 5274188590Srrs if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) { 5275188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5276185435Sbz break; 5277171477Srrs } 5278221249Stuexen } else 5279221249Stuexen#endif 5280185435Sbz#ifdef INET6 5281221249Stuexen if (addrs->addr->sa_family == AF_INET6) { 5282238501Stuexen if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) { 5283171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5284171477Srrs error = EINVAL; 5285171477Srrs break; 5286171477Srrs } 5287188590Srrs if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr), 5288188590Srrs (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) { 5289188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5290185435Sbz break; 5291185435Sbz } 5292221249Stuexen } else 5293185435Sbz#endif 5294221249Stuexen { 5295185435Sbz error = EAFNOSUPPORT; 5296185435Sbz break; 5297171477Srrs } 5298170606Srrs sctp_bindx_add_address(so, inp, addrs->addr, 5299170606Srrs addrs->sget_assoc_id, vrf_id, 5300170606Srrs &error, p); 5301223132Stuexen break; 5302163953Srrs } 5303163953Srrs case SCTP_BINDX_REM_ADDR: 5304163953Srrs { 5305163953Srrs struct sctp_getaddresses *addrs; 5306171477Srrs struct thread *td; 5307163953Srrs 5308171477Srrs td = (struct thread *)p; 5309185435Sbz 5310166675Srrs SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize); 5311221249Stuexen#ifdef INET 5312171477Srrs if (addrs->addr->sa_family == AF_INET) { 5313238501Stuexen if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) { 5314171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5315171477Srrs error = EINVAL; 5316171477Srrs break; 5317171477Srrs } 5318188590Srrs if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) { 5319188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5320185435Sbz break; 5321171477Srrs } 5322221249Stuexen } else 5323221249Stuexen#endif 5324185435Sbz#ifdef INET6 5325221249Stuexen if (addrs->addr->sa_family == AF_INET6) { 5326238501Stuexen if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) { 5327171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5328171477Srrs error = EINVAL; 5329171477Srrs break; 5330171477Srrs } 5331224641Stuexen if (td != NULL && 5332224641Stuexen (error = prison_local_ip6(td->td_ucred, 5333224641Stuexen &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr), 5334188590Srrs (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) { 5335188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5336185435Sbz break; 5337185435Sbz } 5338221249Stuexen } else 5339185435Sbz#endif 5340221249Stuexen { 5341185435Sbz error = EAFNOSUPPORT; 5342185435Sbz break; 5343171477Srrs } 5344228653Stuexen sctp_bindx_delete_address(inp, addrs->addr, 5345170606Srrs addrs->sget_assoc_id, vrf_id, 5346170606Srrs &error); 5347223132Stuexen break; 5348163953Srrs } 5349223132Stuexen case SCTP_EVENT: 5350223132Stuexen { 5351223132Stuexen struct sctp_event *event; 5352223132Stuexen uint32_t event_type; 5353223132Stuexen 5354223132Stuexen SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, optsize); 5355223132Stuexen SCTP_FIND_STCB(inp, stcb, event->se_assoc_id); 5356223132Stuexen switch (event->se_type) { 5357223132Stuexen case SCTP_ASSOC_CHANGE: 5358223132Stuexen event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT; 5359223132Stuexen break; 5360223132Stuexen case SCTP_PEER_ADDR_CHANGE: 5361223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPADDREVNT; 5362223132Stuexen break; 5363223132Stuexen case SCTP_REMOTE_ERROR: 5364223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPEERERR; 5365223132Stuexen break; 5366223132Stuexen case SCTP_SEND_FAILED: 5367223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT; 5368223132Stuexen break; 5369223132Stuexen case SCTP_SHUTDOWN_EVENT: 5370223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT; 5371223132Stuexen break; 5372223132Stuexen case SCTP_ADAPTATION_INDICATION: 5373223132Stuexen event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT; 5374223132Stuexen break; 5375223132Stuexen case SCTP_PARTIAL_DELIVERY_EVENT: 5376223132Stuexen event_type = SCTP_PCB_FLAGS_PDAPIEVNT; 5377223132Stuexen break; 5378223132Stuexen case SCTP_AUTHENTICATION_EVENT: 5379223132Stuexen event_type = SCTP_PCB_FLAGS_AUTHEVNT; 5380223132Stuexen break; 5381223132Stuexen case SCTP_STREAM_RESET_EVENT: 5382223132Stuexen event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT; 5383223132Stuexen break; 5384223132Stuexen case SCTP_SENDER_DRY_EVENT: 5385223132Stuexen event_type = SCTP_PCB_FLAGS_DRYEVNT; 5386223132Stuexen break; 5387223132Stuexen case SCTP_NOTIFICATIONS_STOPPED_EVENT: 5388223132Stuexen event_type = 0; 5389223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); 5390223132Stuexen error = ENOTSUP; 5391223132Stuexen break; 5392235009Stuexen case SCTP_ASSOC_RESET_EVENT: 5393235009Stuexen event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT; 5394235009Stuexen break; 5395235009Stuexen case SCTP_STREAM_CHANGE_EVENT: 5396235009Stuexen event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT; 5397235009Stuexen break; 5398235075Stuexen case SCTP_SEND_FAILED_EVENT: 5399235075Stuexen event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT; 5400235075Stuexen break; 5401223132Stuexen default: 5402223132Stuexen event_type = 0; 5403223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5404223132Stuexen error = EINVAL; 5405223132Stuexen break; 5406223132Stuexen } 5407223132Stuexen if (event_type > 0) { 5408223132Stuexen if (stcb) { 5409223132Stuexen if (event->se_on) { 5410223132Stuexen sctp_stcb_feature_on(inp, stcb, event_type); 5411223132Stuexen if (event_type == SCTP_PCB_FLAGS_DRYEVNT) { 5412223132Stuexen if (TAILQ_EMPTY(&stcb->asoc.send_queue) && 5413223132Stuexen TAILQ_EMPTY(&stcb->asoc.sent_queue) && 5414223132Stuexen (stcb->asoc.stream_queue_cnt == 0)) { 5415223132Stuexen sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED); 5416223132Stuexen } 5417223132Stuexen } 5418223132Stuexen } else { 5419223132Stuexen sctp_stcb_feature_off(inp, stcb, event_type); 5420223132Stuexen } 5421223132Stuexen SCTP_TCB_UNLOCK(stcb); 5422223132Stuexen } else { 5423223132Stuexen /* 5424223132Stuexen * We don't want to send up a storm 5425223132Stuexen * of events, so return an error for 5426223132Stuexen * sender dry events 5427223132Stuexen */ 5428223132Stuexen if ((event_type == SCTP_PCB_FLAGS_DRYEVNT) && 5429224918Stuexen ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) && 5430224918Stuexen ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) && 5431223132Stuexen ((event->se_assoc_id == SCTP_ALL_ASSOC) || 5432223132Stuexen (event->se_assoc_id == SCTP_CURRENT_ASSOC))) { 5433223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); 5434223132Stuexen error = ENOTSUP; 5435223132Stuexen break; 5436223132Stuexen } 5437224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5438224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5439224918Stuexen (event->se_assoc_id == SCTP_FUTURE_ASSOC) || 5440223132Stuexen (event->se_assoc_id == SCTP_ALL_ASSOC)) { 5441223132Stuexen SCTP_INP_WLOCK(inp); 5442223132Stuexen if (event->se_on) { 5443223132Stuexen sctp_feature_on(inp, event_type); 5444223132Stuexen } else { 5445223132Stuexen sctp_feature_off(inp, event_type); 5446223132Stuexen } 5447223132Stuexen SCTP_INP_WUNLOCK(inp); 5448223132Stuexen } 5449223132Stuexen if ((event->se_assoc_id == SCTP_CURRENT_ASSOC) || 5450223132Stuexen (event->se_assoc_id == SCTP_ALL_ASSOC)) { 5451223132Stuexen SCTP_INP_RLOCK(inp); 5452223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 5453223132Stuexen SCTP_TCB_LOCK(stcb); 5454223132Stuexen if (event->se_on) { 5455223132Stuexen sctp_stcb_feature_on(inp, stcb, event_type); 5456223132Stuexen } else { 5457223132Stuexen sctp_stcb_feature_off(inp, stcb, event_type); 5458223132Stuexen } 5459223132Stuexen SCTP_TCB_UNLOCK(stcb); 5460223132Stuexen } 5461223132Stuexen SCTP_INP_RUNLOCK(inp); 5462223132Stuexen } 5463223132Stuexen } 5464223132Stuexen } 5465223132Stuexen break; 5466223132Stuexen } 5467223132Stuexen case SCTP_RECVRCVINFO: 5468223132Stuexen { 5469223132Stuexen int *onoff; 5470223132Stuexen 5471223132Stuexen SCTP_CHECK_AND_CAST(onoff, optval, int, optsize); 5472223132Stuexen SCTP_INP_WLOCK(inp); 5473223132Stuexen if (*onoff != 0) { 5474223132Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO); 5475223132Stuexen } else { 5476223132Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO); 5477223132Stuexen } 5478223132Stuexen SCTP_INP_WUNLOCK(inp); 5479223132Stuexen break; 5480223132Stuexen } 5481223132Stuexen case SCTP_RECVNXTINFO: 5482223132Stuexen { 5483223132Stuexen int *onoff; 5484223132Stuexen 5485223132Stuexen SCTP_CHECK_AND_CAST(onoff, optval, int, optsize); 5486223132Stuexen SCTP_INP_WLOCK(inp); 5487223132Stuexen if (*onoff != 0) { 5488223132Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO); 5489223132Stuexen } else { 5490223132Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO); 5491223132Stuexen } 5492223132Stuexen SCTP_INP_WUNLOCK(inp); 5493223132Stuexen break; 5494223132Stuexen } 5495223132Stuexen case SCTP_DEFAULT_SNDINFO: 5496223132Stuexen { 5497223132Stuexen struct sctp_sndinfo *info; 5498223162Stuexen uint16_t policy; 5499223132Stuexen 5500223132Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, optsize); 5501223132Stuexen SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id); 5502223132Stuexen 5503223132Stuexen if (stcb) { 5504223132Stuexen if (info->snd_sid < stcb->asoc.streamoutcnt) { 5505223132Stuexen stcb->asoc.def_send.sinfo_stream = info->snd_sid; 5506223162Stuexen policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); 5507223132Stuexen stcb->asoc.def_send.sinfo_flags = info->snd_flags; 5508223162Stuexen stcb->asoc.def_send.sinfo_flags |= policy; 5509223132Stuexen stcb->asoc.def_send.sinfo_ppid = info->snd_ppid; 5510223132Stuexen stcb->asoc.def_send.sinfo_context = info->snd_context; 5511223132Stuexen } else { 5512223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5513223132Stuexen error = EINVAL; 5514223132Stuexen } 5515223132Stuexen SCTP_TCB_UNLOCK(stcb); 5516223132Stuexen } else { 5517224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5518224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5519224918Stuexen (info->snd_assoc_id == SCTP_FUTURE_ASSOC) || 5520223132Stuexen (info->snd_assoc_id == SCTP_ALL_ASSOC)) { 5521223132Stuexen SCTP_INP_WLOCK(inp); 5522223132Stuexen inp->def_send.sinfo_stream = info->snd_sid; 5523223162Stuexen policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags); 5524223132Stuexen inp->def_send.sinfo_flags = info->snd_flags; 5525223162Stuexen inp->def_send.sinfo_flags |= policy; 5526223132Stuexen inp->def_send.sinfo_ppid = info->snd_ppid; 5527223132Stuexen inp->def_send.sinfo_context = info->snd_context; 5528223132Stuexen SCTP_INP_WUNLOCK(inp); 5529223132Stuexen } 5530223132Stuexen if ((info->snd_assoc_id == SCTP_CURRENT_ASSOC) || 5531223132Stuexen (info->snd_assoc_id == SCTP_ALL_ASSOC)) { 5532223132Stuexen SCTP_INP_RLOCK(inp); 5533223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 5534223132Stuexen SCTP_TCB_LOCK(stcb); 5535223132Stuexen if (info->snd_sid < stcb->asoc.streamoutcnt) { 5536223132Stuexen stcb->asoc.def_send.sinfo_stream = info->snd_sid; 5537223162Stuexen policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); 5538223132Stuexen stcb->asoc.def_send.sinfo_flags = info->snd_flags; 5539223162Stuexen stcb->asoc.def_send.sinfo_flags |= policy; 5540223132Stuexen stcb->asoc.def_send.sinfo_ppid = info->snd_ppid; 5541223132Stuexen stcb->asoc.def_send.sinfo_context = info->snd_context; 5542223132Stuexen } 5543223132Stuexen SCTP_TCB_UNLOCK(stcb); 5544223132Stuexen } 5545223132Stuexen SCTP_INP_RUNLOCK(inp); 5546223132Stuexen } 5547223132Stuexen } 5548223132Stuexen break; 5549223132Stuexen } 5550223162Stuexen case SCTP_DEFAULT_PRINFO: 5551223162Stuexen { 5552223162Stuexen struct sctp_default_prinfo *info; 5553223162Stuexen 5554223162Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, optsize); 5555223162Stuexen SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id); 5556223162Stuexen 5557223162Stuexen if (PR_SCTP_INVALID_POLICY(info->pr_policy)) { 5558223162Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5559223162Stuexen error = EINVAL; 5560223162Stuexen break; 5561223162Stuexen } 5562223162Stuexen if (stcb) { 5563223162Stuexen stcb->asoc.def_send.sinfo_flags &= 0xfff0; 5564223162Stuexen stcb->asoc.def_send.sinfo_flags |= info->pr_policy; 5565224918Stuexen stcb->asoc.def_send.sinfo_timetolive = info->pr_value; 5566223162Stuexen SCTP_TCB_UNLOCK(stcb); 5567223162Stuexen } else { 5568224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5569224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5570224918Stuexen (info->pr_assoc_id == SCTP_FUTURE_ASSOC) || 5571223162Stuexen (info->pr_assoc_id == SCTP_ALL_ASSOC)) { 5572223162Stuexen SCTP_INP_WLOCK(inp); 5573223162Stuexen inp->def_send.sinfo_flags &= 0xfff0; 5574223162Stuexen inp->def_send.sinfo_flags |= info->pr_policy; 5575224918Stuexen inp->def_send.sinfo_timetolive = info->pr_value; 5576223162Stuexen SCTP_INP_WUNLOCK(inp); 5577223162Stuexen } 5578223162Stuexen if ((info->pr_assoc_id == SCTP_CURRENT_ASSOC) || 5579223162Stuexen (info->pr_assoc_id == SCTP_ALL_ASSOC)) { 5580223162Stuexen SCTP_INP_RLOCK(inp); 5581223162Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 5582223162Stuexen SCTP_TCB_LOCK(stcb); 5583223162Stuexen stcb->asoc.def_send.sinfo_flags &= 0xfff0; 5584223162Stuexen stcb->asoc.def_send.sinfo_flags |= info->pr_policy; 5585224918Stuexen stcb->asoc.def_send.sinfo_timetolive = info->pr_value; 5586223162Stuexen SCTP_TCB_UNLOCK(stcb); 5587223162Stuexen } 5588223162Stuexen SCTP_INP_RUNLOCK(inp); 5589223162Stuexen } 5590223162Stuexen } 5591223162Stuexen break; 5592223162Stuexen } 5593224641Stuexen case SCTP_PEER_ADDR_THLDS: 5594224641Stuexen /* Applies to the specific association */ 5595224641Stuexen { 5596224641Stuexen struct sctp_paddrthlds *thlds; 5597224641Stuexen struct sctp_nets *net; 5598224641Stuexen 5599224641Stuexen SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, optsize); 5600224641Stuexen SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id); 5601224641Stuexen net = NULL; 5602224641Stuexen if (stcb) { 5603224641Stuexen net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_assoc_id); 5604224641Stuexen } else { 5605224641Stuexen /* 5606224641Stuexen * We increment here since 5607224641Stuexen * sctp_findassociation_ep_addr() wil do a 5608224641Stuexen * decrement if it finds the stcb as long as 5609224641Stuexen * the locked tcb (last argument) is NOT a 5610224641Stuexen * TCB.. aka NULL. 5611224641Stuexen */ 5612224641Stuexen SCTP_INP_INCR_REF(inp); 5613224641Stuexen stcb = sctp_findassociation_ep_addr(&inp, 5614224641Stuexen (struct sockaddr *)&thlds->spt_assoc_id, 5615224641Stuexen &net, NULL, NULL); 5616224641Stuexen if (stcb == NULL) { 5617224641Stuexen SCTP_INP_DECR_REF(inp); 5618224641Stuexen } 5619224641Stuexen } 5620224641Stuexen if (stcb && (net == NULL)) { 5621224641Stuexen struct sockaddr *sa; 5622224641Stuexen 5623224641Stuexen sa = (struct sockaddr *)&thlds->spt_assoc_id; 5624224641Stuexen#ifdef INET 5625224641Stuexen if (sa->sa_family == AF_INET) { 5626224641Stuexen 5627224641Stuexen struct sockaddr_in *sin; 5628224641Stuexen 5629224641Stuexen sin = (struct sockaddr_in *)sa; 5630224641Stuexen if (sin->sin_addr.s_addr) { 5631224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5632224641Stuexen SCTP_TCB_UNLOCK(stcb); 5633224641Stuexen error = EINVAL; 5634224641Stuexen break; 5635224641Stuexen } 5636224641Stuexen } else 5637224641Stuexen#endif 5638224641Stuexen#ifdef INET6 5639224641Stuexen if (sa->sa_family == AF_INET6) { 5640224641Stuexen struct sockaddr_in6 *sin6; 5641224641Stuexen 5642224641Stuexen sin6 = (struct sockaddr_in6 *)sa; 5643224641Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 5644224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5645224641Stuexen SCTP_TCB_UNLOCK(stcb); 5646224641Stuexen error = EINVAL; 5647224641Stuexen break; 5648224641Stuexen } 5649224641Stuexen } else 5650224641Stuexen#endif 5651224641Stuexen { 5652224641Stuexen error = EAFNOSUPPORT; 5653224641Stuexen SCTP_TCB_UNLOCK(stcb); 5654224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 5655224641Stuexen break; 5656224641Stuexen } 5657224641Stuexen } 5658224641Stuexen if (stcb) { 5659224641Stuexen if (net) { 5660224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 5661224641Stuexen if ((net->failure_threshold > thlds->spt_pathmaxrxt) || 5662224641Stuexen (net->failure_threshold <= thlds->spt_pathpfthld)) { 5663224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 5664224641Stuexen } 5665224641Stuexen } else { 5666224641Stuexen if ((net->failure_threshold > thlds->spt_pathpfthld) && 5667224641Stuexen (net->failure_threshold <= thlds->spt_pathmaxrxt)) { 5668224641Stuexen net->dest_state |= SCTP_ADDR_PF; 5669224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 5670224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); 5671224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 5672224641Stuexen } 5673224641Stuexen } 5674224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 5675224641Stuexen if (net->failure_threshold > thlds->spt_pathmaxrxt) { 5676224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 5677235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); 5678224641Stuexen } 5679224641Stuexen } else { 5680224641Stuexen if (net->failure_threshold <= thlds->spt_pathmaxrxt) { 5681224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 5682235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); 5683224641Stuexen } 5684224641Stuexen } 5685224641Stuexen net->failure_threshold = thlds->spt_pathmaxrxt; 5686224641Stuexen net->pf_threshold = thlds->spt_pathpfthld; 5687224641Stuexen } else { 5688224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 5689224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 5690224641Stuexen if ((net->failure_threshold > thlds->spt_pathmaxrxt) || 5691224641Stuexen (net->failure_threshold <= thlds->spt_pathpfthld)) { 5692224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 5693224641Stuexen } 5694224641Stuexen } else { 5695224641Stuexen if ((net->failure_threshold > thlds->spt_pathpfthld) && 5696224641Stuexen (net->failure_threshold <= thlds->spt_pathmaxrxt)) { 5697224641Stuexen net->dest_state |= SCTP_ADDR_PF; 5698224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 5699224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); 5700224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 5701224641Stuexen } 5702224641Stuexen } 5703224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 5704224641Stuexen if (net->failure_threshold > thlds->spt_pathmaxrxt) { 5705224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 5706235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); 5707224641Stuexen } 5708224641Stuexen } else { 5709224641Stuexen if (net->failure_threshold <= thlds->spt_pathmaxrxt) { 5710224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 5711235414Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); 5712224641Stuexen } 5713224641Stuexen } 5714224641Stuexen net->failure_threshold = thlds->spt_pathmaxrxt; 5715224641Stuexen net->pf_threshold = thlds->spt_pathpfthld; 5716224641Stuexen } 5717224641Stuexen stcb->asoc.def_net_failure = thlds->spt_pathmaxrxt; 5718224641Stuexen stcb->asoc.def_net_pf_threshold = thlds->spt_pathpfthld; 5719224641Stuexen } 5720224641Stuexen } else { 5721224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5722224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5723224918Stuexen (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) { 5724224641Stuexen SCTP_INP_WLOCK(inp); 5725224641Stuexen inp->sctp_ep.def_net_failure = thlds->spt_pathmaxrxt; 5726224641Stuexen inp->sctp_ep.def_net_pf_threshold = thlds->spt_pathpfthld; 5727224641Stuexen SCTP_INP_WUNLOCK(inp); 5728224641Stuexen } else { 5729224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5730224641Stuexen error = EINVAL; 5731224641Stuexen } 5732224641Stuexen } 5733224641Stuexen break; 5734224641Stuexen } 5735227755Stuexen case SCTP_REMOTE_UDP_ENCAPS_PORT: 5736227755Stuexen { 5737227755Stuexen struct sctp_udpencaps *encaps; 5738227755Stuexen struct sctp_nets *net; 5739227755Stuexen 5740227755Stuexen SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, optsize); 5741227755Stuexen SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id); 5742227755Stuexen if (stcb) { 5743227755Stuexen net = sctp_findnet(stcb, (struct sockaddr *)&encaps->sue_address); 5744227755Stuexen } else { 5745227755Stuexen /* 5746227755Stuexen * We increment here since 5747227755Stuexen * sctp_findassociation_ep_addr() wil do a 5748227755Stuexen * decrement if it finds the stcb as long as 5749227755Stuexen * the locked tcb (last argument) is NOT a 5750227755Stuexen * TCB.. aka NULL. 5751227755Stuexen */ 5752227755Stuexen net = NULL; 5753227755Stuexen SCTP_INP_INCR_REF(inp); 5754227755Stuexen stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&encaps->sue_address, &net, NULL, NULL); 5755227755Stuexen if (stcb == NULL) { 5756227755Stuexen SCTP_INP_DECR_REF(inp); 5757227755Stuexen } 5758227755Stuexen } 5759227755Stuexen if (stcb && (net == NULL)) { 5760227755Stuexen struct sockaddr *sa; 5761227755Stuexen 5762227755Stuexen sa = (struct sockaddr *)&encaps->sue_address; 5763227755Stuexen#ifdef INET 5764227755Stuexen if (sa->sa_family == AF_INET) { 5765227755Stuexen 5766227755Stuexen struct sockaddr_in *sin; 5767227755Stuexen 5768227755Stuexen sin = (struct sockaddr_in *)sa; 5769227755Stuexen if (sin->sin_addr.s_addr) { 5770227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5771227755Stuexen SCTP_TCB_UNLOCK(stcb); 5772227755Stuexen error = EINVAL; 5773227755Stuexen break; 5774227755Stuexen } 5775227755Stuexen } else 5776227755Stuexen#endif 5777227755Stuexen#ifdef INET6 5778227755Stuexen if (sa->sa_family == AF_INET6) { 5779227755Stuexen struct sockaddr_in6 *sin6; 5780227755Stuexen 5781227755Stuexen sin6 = (struct sockaddr_in6 *)sa; 5782227755Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 5783227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5784227755Stuexen SCTP_TCB_UNLOCK(stcb); 5785227755Stuexen error = EINVAL; 5786227755Stuexen break; 5787227755Stuexen } 5788227755Stuexen } else 5789227755Stuexen#endif 5790227755Stuexen { 5791227755Stuexen error = EAFNOSUPPORT; 5792227755Stuexen SCTP_TCB_UNLOCK(stcb); 5793227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 5794227755Stuexen break; 5795227755Stuexen } 5796227755Stuexen } 5797227755Stuexen if (stcb) { 5798227755Stuexen if (net) { 5799227755Stuexen net->port = encaps->sue_port; 5800227755Stuexen } else { 5801227755Stuexen stcb->asoc.port = encaps->sue_port; 5802227755Stuexen } 5803227755Stuexen SCTP_TCB_UNLOCK(stcb); 5804227755Stuexen } else { 5805227755Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5806227755Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5807227755Stuexen (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) { 5808227755Stuexen SCTP_INP_WLOCK(inp); 5809227755Stuexen inp->sctp_ep.port = encaps->sue_port; 5810227755Stuexen SCTP_INP_WUNLOCK(inp); 5811227755Stuexen } else { 5812227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5813227755Stuexen error = EINVAL; 5814227755Stuexen } 5815227755Stuexen } 5816227755Stuexen break; 5817227755Stuexen } 5818163953Srrs default: 5819171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 5820163953Srrs error = ENOPROTOOPT; 5821163953Srrs break; 5822163953Srrs } /* end switch (opt) */ 5823163953Srrs return (error); 5824163953Srrs} 5825163953Srrs 5826163953Srrsint 5827163953Srrssctp_ctloutput(struct socket *so, struct sockopt *sopt) 5828163953Srrs{ 5829166675Srrs void *optval = NULL; 5830166675Srrs size_t optsize = 0; 5831166675Srrs void *p; 5832166675Srrs int error = 0; 5833163953Srrs 5834163953Srrs if (sopt->sopt_level != IPPROTO_SCTP) { 5835163953Srrs /* wrong proto level... send back up to IP */ 5836163953Srrs#ifdef INET6 5837163953Srrs if (INP_CHECK_SOCKAF(so, AF_INET6)) 5838163953Srrs error = ip6_ctloutput(so, sopt); 5839221249Stuexen#endif /* INET6 */ 5840237565Stuexen#if defined(INET) && defined(INET6) 5841163953Srrs else 5842221249Stuexen#endif 5843221249Stuexen#ifdef INET 5844163953Srrs error = ip_ctloutput(so, sopt); 5845221249Stuexen#endif 5846163953Srrs return (error); 5847163953Srrs } 5848166675Srrs optsize = sopt->sopt_valsize; 5849166675Srrs if (optsize) { 5850170091Srrs SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT); 5851166675Srrs if (optval == NULL) { 5852235091Stuexen SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS); 5853163953Srrs return (ENOBUFS); 5854163953Srrs } 5855166675Srrs error = sooptcopyin(sopt, optval, optsize, optsize); 5856163953Srrs if (error) { 5857170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 5858163953Srrs goto out; 5859163953Srrs } 5860163953Srrs } 5861166675Srrs p = (void *)sopt->sopt_td; 5862163953Srrs if (sopt->sopt_dir == SOPT_SET) { 5863166675Srrs error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p); 5864163953Srrs } else if (sopt->sopt_dir == SOPT_GET) { 5865166675Srrs error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p); 5866163953Srrs } else { 5867235091Stuexen SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5868163953Srrs error = EINVAL; 5869163953Srrs } 5870166675Srrs if ((error == 0) && (optval != NULL)) { 5871166675Srrs error = sooptcopyout(sopt, optval, optsize); 5872170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 5873166675Srrs } else if (optval != NULL) { 5874170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 5875163953Srrs } 5876163953Srrsout: 5877163953Srrs return (error); 5878163953Srrs} 5879163953Srrs 5880221249Stuexen#ifdef INET 5881163953Srrsstatic int 5882163953Srrssctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p) 5883163953Srrs{ 5884163953Srrs int error = 0; 5885163953Srrs int create_lock_on = 0; 5886167598Srrs uint32_t vrf_id; 5887163953Srrs struct sctp_inpcb *inp; 5888163953Srrs struct sctp_tcb *stcb = NULL; 5889163953Srrs 5890163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 5891233005Stuexen if (inp == NULL) { 5892163953Srrs /* I made the same as TCP since we are not setup? */ 5893171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5894163953Srrs return (ECONNRESET); 5895163953Srrs } 5896171943Srrs if (addr == NULL) { 5897171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5898170056Srrs return EINVAL; 5899171943Srrs } 5900221249Stuexen switch (addr->sa_family) { 5901185435Sbz#ifdef INET6 5902221249Stuexen case AF_INET6: 5903221249Stuexen { 5904221249Stuexen struct sockaddr_in6 *sin6p; 5905185694Srrs 5906221249Stuexen if (addr->sa_len != sizeof(struct sockaddr_in6)) { 5907221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5908221249Stuexen return (EINVAL); 5909221249Stuexen } 5910221249Stuexen sin6p = (struct sockaddr_in6 *)addr; 5911221249Stuexen if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6p->sin6_addr)) != 0) { 5912221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 5913221249Stuexen return (error); 5914221249Stuexen } 5915221249Stuexen break; 5916185435Sbz } 5917185435Sbz#endif 5918221249Stuexen#ifdef INET 5919221249Stuexen case AF_INET: 5920221249Stuexen { 5921221249Stuexen struct sockaddr_in *sinp; 5922185694Srrs 5923221249Stuexen if (addr->sa_len != sizeof(struct sockaddr_in)) { 5924221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5925221249Stuexen return (EINVAL); 5926221249Stuexen } 5927221249Stuexen sinp = (struct sockaddr_in *)addr; 5928221249Stuexen if (p != NULL && (error = prison_remote_ip4(p->td_ucred, &sinp->sin_addr)) != 0) { 5929221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 5930221249Stuexen return (error); 5931221249Stuexen } 5932221249Stuexen break; 5933185435Sbz } 5934221249Stuexen#endif 5935221249Stuexen default: 5936185435Sbz SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT); 5937185435Sbz return (EAFNOSUPPORT); 5938170056Srrs } 5939178202Srrs SCTP_INP_INCR_REF(inp); 5940163953Srrs SCTP_ASOC_CREATE_LOCK(inp); 5941163953Srrs create_lock_on = 1; 5942163953Srrs 5943178202Srrs 5944163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 5945163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 5946163953Srrs /* Should I really unlock ? */ 5947171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); 5948163953Srrs error = EFAULT; 5949163953Srrs goto out_now; 5950163953Srrs } 5951163953Srrs#ifdef INET6 5952163953Srrs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 5953163953Srrs (addr->sa_family == AF_INET6)) { 5954171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5955163953Srrs error = EINVAL; 5956163953Srrs goto out_now; 5957163953Srrs } 5958163953Srrs#endif /* INET6 */ 5959163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 5960163953Srrs SCTP_PCB_FLAGS_UNBOUND) { 5961163953Srrs /* Bind a ephemeral port */ 5962171572Srrs error = sctp_inpcb_bind(so, NULL, NULL, p); 5963163953Srrs if (error) { 5964163953Srrs goto out_now; 5965163953Srrs } 5966163953Srrs } 5967163953Srrs /* Now do we connect? */ 5968181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && 5969181054Srrs (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) { 5970171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5971163953Srrs error = EINVAL; 5972163953Srrs goto out_now; 5973163953Srrs } 5974163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 5975163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 5976163953Srrs /* We are already connected AND the TCP model */ 5977171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 5978163953Srrs error = EADDRINUSE; 5979163953Srrs goto out_now; 5980163953Srrs } 5981163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 5982163953Srrs SCTP_INP_RLOCK(inp); 5983163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 5984163953Srrs SCTP_INP_RUNLOCK(inp); 5985163953Srrs } else { 5986163953Srrs /* 5987166675Srrs * We increment here since sctp_findassociation_ep_addr() 5988181054Srrs * will do a decrement if it finds the stcb as long as the 5989166675Srrs * locked tcb (last argument) is NOT a TCB.. aka NULL. 5990163953Srrs */ 5991163953Srrs SCTP_INP_INCR_REF(inp); 5992163953Srrs stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL); 5993163953Srrs if (stcb == NULL) { 5994163953Srrs SCTP_INP_DECR_REF(inp); 5995168299Srrs } else { 5996178202Srrs SCTP_TCB_UNLOCK(stcb); 5997163953Srrs } 5998163953Srrs } 5999163953Srrs if (stcb != NULL) { 6000163953Srrs /* Already have or am bring up an association */ 6001171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 6002163953Srrs error = EALREADY; 6003163953Srrs goto out_now; 6004163953Srrs } 6005168299Srrs vrf_id = inp->def_vrf_id; 6006163953Srrs /* We are GOOD to go */ 6007206137Stuexen stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p); 6008163953Srrs if (stcb == NULL) { 6009163953Srrs /* Gak! no memory */ 6010167598Srrs goto out_now; 6011163953Srrs } 6012163953Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 6013163953Srrs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 6014163953Srrs /* Set the connected flag so we can queue data */ 6015163953Srrs soisconnecting(so); 6016163953Srrs } 6017171943Srrs SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); 6018169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 6019163953Srrs 6020163953Srrs /* initialize authentication parameters for the assoc */ 6021163953Srrs sctp_initialize_auth_params(inp, stcb); 6022163953Srrs 6023172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 6024168299Srrs SCTP_TCB_UNLOCK(stcb); 6025163953Srrsout_now: 6026169420Srrs if (create_lock_on) { 6027163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 6028169420Srrs } 6029163953Srrs SCTP_INP_DECR_REF(inp); 6030228907Stuexen return (error); 6031163953Srrs} 6032163953Srrs 6033221249Stuexen#endif 6034221249Stuexen 6035163953Srrsint 6036163953Srrssctp_listen(struct socket *so, int backlog, struct thread *p) 6037163953Srrs{ 6038163953Srrs /* 6039163953Srrs * Note this module depends on the protocol processing being called 6040163953Srrs * AFTER any socket level flags and backlog are applied to the 6041163953Srrs * socket. The traditional way that the socket flags are applied is 6042163953Srrs * AFTER protocol processing. We have made a change to the 6043163953Srrs * sys/kern/uipc_socket.c module to reverse this but this MUST be in 6044163953Srrs * place if the socket API for SCTP is to work properly. 6045163953Srrs */ 6046163953Srrs 6047163953Srrs int error = 0; 6048163953Srrs struct sctp_inpcb *inp; 6049163953Srrs 6050163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 6051233005Stuexen if (inp == NULL) { 6052163953Srrs /* I made the same as TCP since we are not setup? */ 6053171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6054163953Srrs return (ECONNRESET); 6055163953Srrs } 6056181054Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) { 6057181054Srrs /* See if we have a listener */ 6058181054Srrs struct sctp_inpcb *tinp; 6059181054Srrs union sctp_sockstore store, *sp; 6060181054Srrs 6061181054Srrs sp = &store; 6062181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { 6063181054Srrs /* not bound all */ 6064181054Srrs struct sctp_laddr *laddr; 6065181054Srrs 6066181054Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 6067181054Srrs memcpy(&store, &laddr->ifa->address, sizeof(store)); 6068221249Stuexen switch (sp->sa.sa_family) { 6069221249Stuexen#ifdef INET 6070221249Stuexen case AF_INET: 6071221249Stuexen sp->sin.sin_port = inp->sctp_lport; 6072221249Stuexen break; 6073221249Stuexen#endif 6074221249Stuexen#ifdef INET6 6075221249Stuexen case AF_INET6: 6076221249Stuexen sp->sin6.sin6_port = inp->sctp_lport; 6077221249Stuexen break; 6078221249Stuexen#endif 6079221249Stuexen default: 6080221249Stuexen break; 6081221249Stuexen } 6082181054Srrs tinp = sctp_pcb_findep(&sp->sa, 0, 0, inp->def_vrf_id); 6083181054Srrs if (tinp && (tinp != inp) && 6084181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && 6085181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 6086181054Srrs (tinp->sctp_socket->so_qlimit)) { 6087181054Srrs /* 6088181054Srrs * we have a listener already and 6089181054Srrs * its not this inp. 6090181054Srrs */ 6091181054Srrs SCTP_INP_DECR_REF(tinp); 6092181054Srrs return (EADDRINUSE); 6093181054Srrs } else if (tinp) { 6094181054Srrs SCTP_INP_DECR_REF(tinp); 6095181054Srrs } 6096181054Srrs } 6097181054Srrs } else { 6098181054Srrs /* Setup a local addr bound all */ 6099181054Srrs memset(&store, 0, sizeof(store)); 6100221249Stuexen switch (sp->sa.sa_family) { 6101221249Stuexen#ifdef INET 6102221249Stuexen case AF_INET: 6103221249Stuexen store.sin.sin_port = inp->sctp_lport; 6104221249Stuexen break; 6105221249Stuexen#endif 6106181054Srrs#ifdef INET6 6107221249Stuexen case AF_INET6: 6108221249Stuexen sp->sin6.sin6_port = inp->sctp_lport; 6109221249Stuexen break; 6110221249Stuexen#endif 6111221249Stuexen default: 6112221249Stuexen break; 6113221249Stuexen } 6114221249Stuexen#ifdef INET6 6115181054Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 6116181054Srrs store.sa.sa_family = AF_INET6; 6117181054Srrs store.sa.sa_len = sizeof(struct sockaddr_in6); 6118181054Srrs } 6119181054Srrs#endif 6120221249Stuexen#ifdef INET 6121181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { 6122181054Srrs store.sa.sa_family = AF_INET; 6123181054Srrs store.sa.sa_len = sizeof(struct sockaddr_in); 6124181054Srrs } 6125221249Stuexen#endif 6126181054Srrs tinp = sctp_pcb_findep(&sp->sa, 0, 0, inp->def_vrf_id); 6127181054Srrs if (tinp && (tinp != inp) && 6128181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && 6129181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 6130181054Srrs (tinp->sctp_socket->so_qlimit)) { 6131181054Srrs /* 6132181054Srrs * we have a listener already and its not 6133181054Srrs * this inp. 6134181054Srrs */ 6135181054Srrs SCTP_INP_DECR_REF(tinp); 6136181054Srrs return (EADDRINUSE); 6137181054Srrs } else if (tinp) { 6138181054Srrs SCTP_INP_DECR_REF(inp); 6139181054Srrs } 6140181054Srrs } 6141181054Srrs } 6142163953Srrs SCTP_INP_RLOCK(inp); 6143163953Srrs#ifdef SCTP_LOCK_LOGGING 6144179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) { 6145170744Srrs sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK); 6146170744Srrs } 6147163953Srrs#endif 6148163953Srrs SOCK_LOCK(so); 6149163953Srrs error = solisten_proto_check(so); 6150163953Srrs if (error) { 6151163953Srrs SOCK_UNLOCK(so); 6152169208Srrs SCTP_INP_RUNLOCK(inp); 6153163953Srrs return (error); 6154163953Srrs } 6155181054Srrs if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) && 6156181054Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 6157181054Srrs /* 6158181054Srrs * The unlucky case - We are in the tcp pool with this guy. 6159181054Srrs * - Someone else is in the main inp slot. - We must move 6160181054Srrs * this guy (the listener) to the main slot - We must then 6161181054Srrs * move the guy that was listener to the TCP Pool. 6162181054Srrs */ 6163181054Srrs if (sctp_swap_inpcb_for_listen(inp)) { 6164181054Srrs goto in_use; 6165181054Srrs } 6166181054Srrs } 6167163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 6168163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 6169163953Srrs /* We are already connected AND the TCP model */ 6170181054Srrsin_use: 6171163953Srrs SCTP_INP_RUNLOCK(inp); 6172163953Srrs SOCK_UNLOCK(so); 6173171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 6174163953Srrs return (EADDRINUSE); 6175163953Srrs } 6176181054Srrs SCTP_INP_RUNLOCK(inp); 6177163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { 6178163953Srrs /* We must do a bind. */ 6179166675Srrs SOCK_UNLOCK(so); 6180171572Srrs if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) { 6181163953Srrs /* bind error, probably perm */ 6182163953Srrs return (error); 6183163953Srrs } 6184166675Srrs SOCK_LOCK(so); 6185163953Srrs } 6186163953Srrs /* It appears for 7.0 and on, we must always call this. */ 6187163953Srrs solisten_proto(so, backlog); 6188163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 6189163953Srrs /* remove the ACCEPTCONN flag for one-to-many sockets */ 6190163953Srrs so->so_options &= ~SO_ACCEPTCONN; 6191163953Srrs } 6192163953Srrs if (backlog == 0) { 6193163953Srrs /* turning off listen */ 6194163953Srrs so->so_options &= ~SO_ACCEPTCONN; 6195163953Srrs } 6196163953Srrs SOCK_UNLOCK(so); 6197163953Srrs return (error); 6198163953Srrs} 6199163953Srrs 6200163953Srrsstatic int sctp_defered_wakeup_cnt = 0; 6201163953Srrs 6202163953Srrsint 6203163953Srrssctp_accept(struct socket *so, struct sockaddr **addr) 6204163953Srrs{ 6205163953Srrs struct sctp_tcb *stcb; 6206163953Srrs struct sctp_inpcb *inp; 6207163953Srrs union sctp_sockstore store; 6208163953Srrs 6209178251Srrs#ifdef INET6 6210163953Srrs int error; 6211163953Srrs 6212178251Srrs#endif 6213163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 6214163953Srrs 6215233005Stuexen if (inp == NULL) { 6216171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6217163953Srrs return (ECONNRESET); 6218163953Srrs } 6219163953Srrs SCTP_INP_RLOCK(inp); 6220163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 6221168299Srrs SCTP_INP_RUNLOCK(inp); 6222171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 6223171943Srrs return (EOPNOTSUPP); 6224163953Srrs } 6225163953Srrs if (so->so_state & SS_ISDISCONNECTED) { 6226163953Srrs SCTP_INP_RUNLOCK(inp); 6227171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED); 6228163953Srrs return (ECONNABORTED); 6229163953Srrs } 6230163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 6231163953Srrs if (stcb == NULL) { 6232163953Srrs SCTP_INP_RUNLOCK(inp); 6233171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6234163953Srrs return (ECONNRESET); 6235163953Srrs } 6236163953Srrs SCTP_TCB_LOCK(stcb); 6237163953Srrs SCTP_INP_RUNLOCK(inp); 6238163953Srrs store = stcb->asoc.primary_destination->ro._l_addr; 6239207924Srrs stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE; 6240163953Srrs SCTP_TCB_UNLOCK(stcb); 6241178251Srrs switch (store.sa.sa_family) { 6242221249Stuexen#ifdef INET 6243178251Srrs case AF_INET: 6244178251Srrs { 6245178251Srrs struct sockaddr_in *sin; 6246163953Srrs 6247178251Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 6248208863Srrs if (sin == NULL) 6249208863Srrs return (ENOMEM); 6250178251Srrs sin->sin_family = AF_INET; 6251178251Srrs sin->sin_len = sizeof(*sin); 6252178251Srrs sin->sin_port = ((struct sockaddr_in *)&store)->sin_port; 6253178251Srrs sin->sin_addr = ((struct sockaddr_in *)&store)->sin_addr; 6254178251Srrs *addr = (struct sockaddr *)sin; 6255178251Srrs break; 6256178251Srrs } 6257221249Stuexen#endif 6258178251Srrs#ifdef INET6 6259178251Srrs case AF_INET6: 6260178251Srrs { 6261178251Srrs struct sockaddr_in6 *sin6; 6262163953Srrs 6263178251Srrs SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); 6264208863Srrs if (sin6 == NULL) 6265208863Srrs return (ENOMEM); 6266178251Srrs sin6->sin6_family = AF_INET6; 6267178251Srrs sin6->sin6_len = sizeof(*sin6); 6268178251Srrs sin6->sin6_port = ((struct sockaddr_in6 *)&store)->sin6_port; 6269163953Srrs 6270178251Srrs sin6->sin6_addr = ((struct sockaddr_in6 *)&store)->sin6_addr; 6271178251Srrs if ((error = sa6_recoverscope(sin6)) != 0) { 6272178251Srrs SCTP_FREE_SONAME(sin6); 6273178251Srrs return (error); 6274178251Srrs } 6275178251Srrs *addr = (struct sockaddr *)sin6; 6276178251Srrs break; 6277164085Srrs } 6278178251Srrs#endif 6279178251Srrs default: 6280178251Srrs /* TSNH */ 6281178251Srrs break; 6282163953Srrs } 6283163953Srrs /* Wake any delayed sleep action */ 6284163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { 6285166086Srrs SCTP_INP_WLOCK(inp); 6286163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE; 6287163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) { 6288163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT; 6289166086Srrs SCTP_INP_WUNLOCK(inp); 6290163953Srrs SOCKBUF_LOCK(&inp->sctp_socket->so_snd); 6291163953Srrs if (sowriteable(inp->sctp_socket)) { 6292163953Srrs sowwakeup_locked(inp->sctp_socket); 6293163953Srrs } else { 6294163953Srrs SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd); 6295163953Srrs } 6296166086Srrs SCTP_INP_WLOCK(inp); 6297163953Srrs } 6298163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) { 6299163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT; 6300166086Srrs SCTP_INP_WUNLOCK(inp); 6301163953Srrs SOCKBUF_LOCK(&inp->sctp_socket->so_rcv); 6302163953Srrs if (soreadable(inp->sctp_socket)) { 6303163953Srrs sctp_defered_wakeup_cnt++; 6304163953Srrs sorwakeup_locked(inp->sctp_socket); 6305163953Srrs } else { 6306163953Srrs SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv); 6307163953Srrs } 6308166086Srrs SCTP_INP_WLOCK(inp); 6309163953Srrs } 6310166086Srrs SCTP_INP_WUNLOCK(inp); 6311163953Srrs } 6312207924Srrs if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 6313207924Srrs SCTP_TCB_LOCK(stcb); 6314207924Srrs sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); 6315207924Srrs } 6316163953Srrs return (0); 6317163953Srrs} 6318163953Srrs 6319221249Stuexen#ifdef INET 6320163953Srrsint 6321163953Srrssctp_ingetaddr(struct socket *so, struct sockaddr **addr) 6322163953Srrs{ 6323163953Srrs struct sockaddr_in *sin; 6324167598Srrs uint32_t vrf_id; 6325163953Srrs struct sctp_inpcb *inp; 6326167695Srrs struct sctp_ifa *sctp_ifa; 6327163953Srrs 6328163953Srrs /* 6329163953Srrs * Do the malloc first in case it blocks. 6330163953Srrs */ 6331163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 6332208863Srrs if (sin == NULL) 6333208863Srrs return (ENOMEM); 6334163953Srrs sin->sin_family = AF_INET; 6335163953Srrs sin->sin_len = sizeof(*sin); 6336163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 6337163953Srrs if (!inp) { 6338163953Srrs SCTP_FREE_SONAME(sin); 6339171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6340228907Stuexen return (ECONNRESET); 6341163953Srrs } 6342163953Srrs SCTP_INP_RLOCK(inp); 6343163953Srrs sin->sin_port = inp->sctp_lport; 6344163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 6345163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 6346163953Srrs struct sctp_tcb *stcb; 6347163953Srrs struct sockaddr_in *sin_a; 6348163953Srrs struct sctp_nets *net; 6349163953Srrs int fnd; 6350163953Srrs 6351163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 6352163953Srrs if (stcb == NULL) { 6353163953Srrs goto notConn; 6354163953Srrs } 6355163953Srrs fnd = 0; 6356163953Srrs sin_a = NULL; 6357163953Srrs SCTP_TCB_LOCK(stcb); 6358163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 6359163953Srrs sin_a = (struct sockaddr_in *)&net->ro._l_addr; 6360164085Srrs if (sin_a == NULL) 6361164085Srrs /* this will make coverity happy */ 6362164085Srrs continue; 6363164085Srrs 6364163953Srrs if (sin_a->sin_family == AF_INET) { 6365163953Srrs fnd = 1; 6366163953Srrs break; 6367163953Srrs } 6368163953Srrs } 6369163953Srrs if ((!fnd) || (sin_a == NULL)) { 6370163953Srrs /* punt */ 6371163953Srrs SCTP_TCB_UNLOCK(stcb); 6372163953Srrs goto notConn; 6373163953Srrs } 6374168299Srrs vrf_id = inp->def_vrf_id; 6375167598Srrs sctp_ifa = sctp_source_address_selection(inp, 6376167598Srrs stcb, 6377168299Srrs (sctp_route_t *) & net->ro, 6378167598Srrs net, 0, vrf_id); 6379167598Srrs if (sctp_ifa) { 6380167598Srrs sin->sin_addr = sctp_ifa->address.sin.sin_addr; 6381167598Srrs sctp_free_ifa(sctp_ifa); 6382167598Srrs } 6383163953Srrs SCTP_TCB_UNLOCK(stcb); 6384163953Srrs } else { 6385163953Srrs /* For the bound all case you get back 0 */ 6386163953Srrs notConn: 6387163953Srrs sin->sin_addr.s_addr = 0; 6388163953Srrs } 6389163953Srrs 6390163953Srrs } else { 6391163953Srrs /* Take the first IPv4 address in the list */ 6392163953Srrs struct sctp_laddr *laddr; 6393163953Srrs int fnd = 0; 6394163953Srrs 6395163953Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 6396167598Srrs if (laddr->ifa->address.sa.sa_family == AF_INET) { 6397163953Srrs struct sockaddr_in *sin_a; 6398163953Srrs 6399167598Srrs sin_a = (struct sockaddr_in *)&laddr->ifa->address.sa; 6400163953Srrs sin->sin_addr = sin_a->sin_addr; 6401163953Srrs fnd = 1; 6402163953Srrs break; 6403163953Srrs } 6404163953Srrs } 6405163953Srrs if (!fnd) { 6406163953Srrs SCTP_FREE_SONAME(sin); 6407163953Srrs SCTP_INP_RUNLOCK(inp); 6408171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 6409228907Stuexen return (ENOENT); 6410163953Srrs } 6411163953Srrs } 6412163953Srrs SCTP_INP_RUNLOCK(inp); 6413163953Srrs (*addr) = (struct sockaddr *)sin; 6414163953Srrs return (0); 6415163953Srrs} 6416163953Srrs 6417163953Srrsint 6418163953Srrssctp_peeraddr(struct socket *so, struct sockaddr **addr) 6419163953Srrs{ 6420231895Stuexen struct sockaddr_in *sin; 6421166086Srrs int fnd; 6422163953Srrs struct sockaddr_in *sin_a; 6423163953Srrs struct sctp_inpcb *inp; 6424163953Srrs struct sctp_tcb *stcb; 6425163953Srrs struct sctp_nets *net; 6426163953Srrs 6427163953Srrs /* Do the malloc first in case it blocks. */ 6428163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 6429208863Srrs if (sin == NULL) 6430208863Srrs return (ENOMEM); 6431163953Srrs sin->sin_family = AF_INET; 6432163953Srrs sin->sin_len = sizeof(*sin); 6433163953Srrs 6434163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 6435228907Stuexen if ((inp == NULL) || 6436228907Stuexen ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { 6437228907Stuexen /* UDP type and listeners will drop out here */ 6438163953Srrs SCTP_FREE_SONAME(sin); 6439228907Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 6440228907Stuexen return (ENOTCONN); 6441163953Srrs } 6442163953Srrs SCTP_INP_RLOCK(inp); 6443163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 6444169420Srrs if (stcb) { 6445163953Srrs SCTP_TCB_LOCK(stcb); 6446169420Srrs } 6447163953Srrs SCTP_INP_RUNLOCK(inp); 6448163953Srrs if (stcb == NULL) { 6449163953Srrs SCTP_FREE_SONAME(sin); 6450171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6451228907Stuexen return (ECONNRESET); 6452163953Srrs } 6453163953Srrs fnd = 0; 6454163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 6455163953Srrs sin_a = (struct sockaddr_in *)&net->ro._l_addr; 6456163953Srrs if (sin_a->sin_family == AF_INET) { 6457163953Srrs fnd = 1; 6458163953Srrs sin->sin_port = stcb->rport; 6459163953Srrs sin->sin_addr = sin_a->sin_addr; 6460163953Srrs break; 6461163953Srrs } 6462163953Srrs } 6463163953Srrs SCTP_TCB_UNLOCK(stcb); 6464163953Srrs if (!fnd) { 6465163953Srrs /* No IPv4 address */ 6466163953Srrs SCTP_FREE_SONAME(sin); 6467171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 6468228907Stuexen return (ENOENT); 6469163953Srrs } 6470163953Srrs (*addr) = (struct sockaddr *)sin; 6471163953Srrs return (0); 6472163953Srrs} 6473163953Srrs 6474163953Srrsstruct pr_usrreqs sctp_usrreqs = { 6475163953Srrs .pru_abort = sctp_abort, 6476163953Srrs .pru_accept = sctp_accept, 6477163953Srrs .pru_attach = sctp_attach, 6478163953Srrs .pru_bind = sctp_bind, 6479163953Srrs .pru_connect = sctp_connect, 6480163953Srrs .pru_control = in_control, 6481163953Srrs .pru_close = sctp_close, 6482163953Srrs .pru_detach = sctp_close, 6483163953Srrs .pru_sopoll = sopoll_generic, 6484178202Srrs .pru_flush = sctp_flush, 6485163953Srrs .pru_disconnect = sctp_disconnect, 6486163953Srrs .pru_listen = sctp_listen, 6487163953Srrs .pru_peeraddr = sctp_peeraddr, 6488163953Srrs .pru_send = sctp_sendm, 6489163953Srrs .pru_shutdown = sctp_shutdown, 6490163953Srrs .pru_sockaddr = sctp_ingetaddr, 6491163953Srrs .pru_sosend = sctp_sosend, 6492163953Srrs .pru_soreceive = sctp_soreceive 6493163953Srrs}; 6494221249Stuexen 6495221249Stuexen#endif 6496