sctp_usrreq.c revision 173179
1163953Srrs/*- 2169382Srrs * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. 3163953Srrs * 4163953Srrs * Redistribution and use in source and binary forms, with or without 5163953Srrs * modification, are permitted provided that the following conditions are met: 6163953Srrs * 7163953Srrs * a) Redistributions of source code must retain the above copyright notice, 8163953Srrs * this list of conditions and the following disclaimer. 9163953Srrs * 10163953Srrs * b) Redistributions in binary form must reproduce the above copyright 11163953Srrs * notice, this list of conditions and the following disclaimer in 12163953Srrs * the documentation and/or other materials provided with the distribution. 13163953Srrs * 14163953Srrs * c) Neither the name of Cisco Systems, Inc. nor the names of its 15163953Srrs * contributors may be used to endorse or promote products derived 16163953Srrs * from this software without specific prior written permission. 17163953Srrs * 18163953Srrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19163953Srrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 20163953Srrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22163953Srrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23163953Srrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24163953Srrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25163953Srrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26163953Srrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27163953Srrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28163953Srrs * THE POSSIBILITY OF SUCH DAMAGE. 29163953Srrs */ 30163953Srrs 31163953Srrs/* $KAME: sctp_usrreq.c,v 1.48 2005/03/07 23:26:08 itojun Exp $ */ 32163953Srrs 33163953Srrs#include <sys/cdefs.h> 34163953Srrs__FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 173179 2007-10-30 14:09:24Z rrs $"); 35166086Srrs#include <netinet/sctp_os.h> 36163953Srrs#include <sys/proc.h> 37163953Srrs#include <netinet/sctp_pcb.h> 38163953Srrs#include <netinet/sctp_header.h> 39163953Srrs#include <netinet/sctp_var.h> 40167695Srrs#if defined(INET6) 41167695Srrs#include <netinet6/sctp6_var.h> 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> 52171440Srrs#include <netinet/sctp_cc_functions.h> 53164085Srrs 54163953Srrs 55163953Srrs 56170091Srrs 57163953Srrsvoid 58163953Srrssctp_init(void) 59163953Srrs{ 60163953Srrs /* Init the SCTP pcb in sctp_pcb.c */ 61163953Srrs u_long sb_max_adj; 62163953Srrs 63163953Srrs sctp_pcb_init(); 64163953Srrs 65171440Srrs 66163953Srrs if ((nmbclusters / 8) > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE) 67163953Srrs 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)); 73163953Srrs sctp_sendspace = min((min(SB_MAX, 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 */ 80163953Srrs sctp_recvspace = sctp_sendspace; 81163953Srrs 82163953Srrs} 83163953Srrs 84163953Srrs 85166023Srrs 86166023Srrs/* 87166023Srrs * cleanup of the sctppcbinfo structure. 88166023Srrs * Assumes that the sctppcbinfo lock is held. 89166023Srrs */ 90166023Srrsvoid 91166023Srrssctp_pcbinfo_cleanup(void) 92166023Srrs{ 93166023Srrs /* free the hash tables */ 94166023Srrs if (sctppcbinfo.sctp_asochash != NULL) 95166023Srrs SCTP_HASH_FREE(sctppcbinfo.sctp_asochash, sctppcbinfo.hashasocmark); 96166023Srrs if (sctppcbinfo.sctp_ephash != NULL) 97166023Srrs SCTP_HASH_FREE(sctppcbinfo.sctp_ephash, sctppcbinfo.hashmark); 98166023Srrs if (sctppcbinfo.sctp_tcpephash != NULL) 99166023Srrs SCTP_HASH_FREE(sctppcbinfo.sctp_tcpephash, sctppcbinfo.hashtcpmark); 100166023Srrs if (sctppcbinfo.sctp_restarthash != NULL) 101166023Srrs SCTP_HASH_FREE(sctppcbinfo.sctp_restarthash, sctppcbinfo.hashrestartmark); 102166023Srrs} 103166023Srrs 104163953Srrs 105163953Srrsstatic void 106167695Srrssctp_pathmtu_adjustment(struct sctp_inpcb *inp, 107163953Srrs struct sctp_tcb *stcb, 108163953Srrs struct sctp_nets *net, 109163953Srrs uint16_t nxtsz) 110163953Srrs{ 111163953Srrs struct sctp_tmit_chunk *chk; 112163953Srrs 113163953Srrs /* Adjust that too */ 114163953Srrs stcb->asoc.smallest_mtu = nxtsz; 115163953Srrs /* now off to subtract IP_DF flag if needed */ 116169352Srrs#ifdef SCTP_PRINT_FOR_B_AND_M 117169420Srrs SCTP_PRINTF("sctp_pathmtu_adjust called inp:%p stcb:%p net:%p nxtsz:%d\n", 118169352Srrs inp, stcb, net, nxtsz); 119169352Srrs#endif 120163953Srrs TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) { 121163953Srrs if ((chk->send_size + IP_HDR_SIZE) > nxtsz) { 122163953Srrs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 123163953Srrs } 124163953Srrs } 125163953Srrs TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 126163953Srrs if ((chk->send_size + IP_HDR_SIZE) > nxtsz) { 127163953Srrs /* 128163953Srrs * For this guy we also mark for immediate resend 129163953Srrs * since we sent to big of chunk 130163953Srrs */ 131163953Srrs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 132163953Srrs if (chk->sent != SCTP_DATAGRAM_RESEND) { 133163953Srrs sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 134163953Srrs } 135163953Srrs chk->sent = SCTP_DATAGRAM_RESEND; 136163953Srrs chk->rec.data.doing_fast_retransmit = 0; 137170744Srrs if (sctp_logging_level & SCTP_FLIGHT_LOGGING_ENABLE) { 138170744Srrs sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU, 139170744Srrs chk->whoTo->flight_size, 140170744Srrs chk->book_size, 141170744Srrs (uintptr_t) chk->whoTo, 142170744Srrs chk->rec.data.TSN_seq); 143170744Srrs } 144163953Srrs /* Clear any time so NO RTT is being done */ 145163953Srrs chk->do_rtt = 0; 146168709Srrs sctp_flight_size_decrease(chk); 147168709Srrs sctp_total_flight_decrease(stcb, chk); 148163953Srrs } 149163953Srrs } 150163953Srrs} 151163953Srrs 152163953Srrsstatic void 153163953Srrssctp_notify_mbuf(struct sctp_inpcb *inp, 154163953Srrs struct sctp_tcb *stcb, 155163953Srrs struct sctp_nets *net, 156163953Srrs struct ip *ip, 157163953Srrs struct sctphdr *sh) 158163953Srrs{ 159163953Srrs struct icmp *icmph; 160163953Srrs int totsz, tmr_stopped = 0; 161163953Srrs uint16_t nxtsz; 162163953Srrs 163163953Srrs /* protection */ 164163953Srrs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 165163953Srrs (ip == NULL) || (sh == NULL)) { 166169420Srrs if (stcb != NULL) { 167163953Srrs SCTP_TCB_UNLOCK(stcb); 168169420Srrs } 169163953Srrs return; 170163953Srrs } 171163953Srrs /* First job is to verify the vtag matches what I would send */ 172163953Srrs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 173163953Srrs SCTP_TCB_UNLOCK(stcb); 174163953Srrs return; 175163953Srrs } 176163953Srrs icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) - 177163953Srrs sizeof(struct ip))); 178163953Srrs if (icmph->icmp_type != ICMP_UNREACH) { 179163953Srrs /* We only care about unreachable */ 180163953Srrs SCTP_TCB_UNLOCK(stcb); 181163953Srrs return; 182163953Srrs } 183163953Srrs if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) { 184163953Srrs /* not a unreachable message due to frag. */ 185163953Srrs SCTP_TCB_UNLOCK(stcb); 186163953Srrs return; 187163953Srrs } 188163953Srrs totsz = ip->ip_len; 189163953Srrs 190171943Srrs nxtsz = ntohs(icmph->icmp_nextmtu); 191163953Srrs if (nxtsz == 0) { 192163953Srrs /* 193163953Srrs * old type router that does not tell us what the next size 194163953Srrs * mtu is. Rats we will have to guess (in a educated fashion 195163953Srrs * of course) 196163953Srrs */ 197163953Srrs nxtsz = find_next_best_mtu(totsz); 198163953Srrs } 199163953Srrs /* Stop any PMTU timer */ 200165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 201163953Srrs tmr_stopped = 1; 202165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 203165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1); 204163953Srrs } 205163953Srrs /* Adjust destination size limit */ 206163953Srrs if (net->mtu > nxtsz) { 207163953Srrs net->mtu = nxtsz; 208163953Srrs } 209163953Srrs /* now what about the ep? */ 210163953Srrs if (stcb->asoc.smallest_mtu > nxtsz) { 211169352Srrs#ifdef SCTP_PRINT_FOR_B_AND_M 212169420Srrs SCTP_PRINTF("notify_mbuf (ICMP) calls sctp_pathmtu_adjust mtu:%d\n", 213169352Srrs nxtsz); 214169352Srrs#endif 215167695Srrs sctp_pathmtu_adjustment(inp, stcb, net, nxtsz); 216163953Srrs } 217163953Srrs if (tmr_stopped) 218163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 219163953Srrs 220163953Srrs SCTP_TCB_UNLOCK(stcb); 221163953Srrs} 222163953Srrs 223163953Srrs 224163953Srrsvoid 225163953Srrssctp_notify(struct sctp_inpcb *inp, 226172091Srrs struct ip *ip, 227163953Srrs struct sctphdr *sh, 228163953Srrs struct sockaddr *to, 229163953Srrs struct sctp_tcb *stcb, 230163953Srrs struct sctp_nets *net) 231163953Srrs{ 232172090Srrs#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 233172090Srrs struct socket *so; 234172090Srrs 235172090Srrs#endif 236163953Srrs /* protection */ 237172091Srrs int reason; 238172091Srrs struct icmp *icmph; 239172091Srrs 240172091Srrs 241163953Srrs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 242163953Srrs (sh == NULL) || (to == NULL)) { 243172091Srrs if (stcb) 244172091Srrs SCTP_TCB_UNLOCK(stcb); 245163953Srrs return; 246163953Srrs } 247163953Srrs /* First job is to verify the vtag matches what I would send */ 248163953Srrs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 249172091Srrs SCTP_TCB_UNLOCK(stcb); 250163953Srrs return; 251163953Srrs } 252172091Srrs icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) - 253172091Srrs sizeof(struct ip))); 254172091Srrs if (icmph->icmp_type != ICMP_UNREACH) { 255172091Srrs /* We only care about unreachable */ 256172091Srrs SCTP_TCB_UNLOCK(stcb); 257172091Srrs return; 258172091Srrs } 259172091Srrs if ((icmph->icmp_code == ICMP_UNREACH_NET) || 260172091Srrs (icmph->icmp_code == ICMP_UNREACH_HOST) || 261172091Srrs (icmph->icmp_code == ICMP_UNREACH_NET_UNKNOWN) || 262172091Srrs (icmph->icmp_code == ICMP_UNREACH_HOST_UNKNOWN) || 263172091Srrs (icmph->icmp_code == ICMP_UNREACH_ISOLATED) || 264172091Srrs (icmph->icmp_code == ICMP_UNREACH_NET_PROHIB) || 265172091Srrs (icmph->icmp_code == ICMP_UNREACH_HOST_PROHIB) || 266172091Srrs (icmph->icmp_code == ICMP_UNREACH_FILTER_PROHIB)) { 267163953Srrs 268163953Srrs /* 269163953Srrs * Hmm reachablity problems we must examine closely. If its 270163953Srrs * not reachable, we may have lost a network. Or if there is 271163953Srrs * NO protocol at the other end named SCTP. well we consider 272163953Srrs * it a OOTB abort. 273163953Srrs */ 274172091Srrs if (net->dest_state & SCTP_ADDR_REACHABLE) { 275172091Srrs /* Ok that destination is NOT reachable */ 276172091Srrs SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n", 277172091Srrs net->error_count, 278172091Srrs net->failure_threshold, 279172091Srrs net); 280167598Srrs 281172091Srrs net->dest_state &= ~SCTP_ADDR_REACHABLE; 282172091Srrs net->dest_state |= SCTP_ADDR_NOT_REACHABLE; 283163953Srrs /* 284172091Srrs * JRS 5/14/07 - If a destination is unreachable, 285172091Srrs * the PF bit is turned off. This allows an 286172091Srrs * unambiguous use of the PF bit for destinations 287172091Srrs * that are reachable but potentially failed. If the 288172091Srrs * destination is set to the unreachable state, also 289172091Srrs * set the destination to the PF state. 290163953Srrs */ 291172091Srrs /* 292172091Srrs * Add debug message here if destination is not in 293172091Srrs * PF state. 294172091Srrs */ 295172091Srrs /* Stop any running T3 timers here? */ 296172091Srrs if (sctp_cmt_on_off && sctp_cmt_pf) { 297172091Srrs net->dest_state &= ~SCTP_ADDR_PF; 298172091Srrs SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n", 299172091Srrs net); 300172091Srrs } 301172091Srrs net->error_count = net->failure_threshold + 1; 302172091Srrs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, 303172091Srrs stcb, SCTP_FAILED_THRESHOLD, 304172091Srrs (void *)net, SCTP_SO_NOT_LOCKED); 305172091Srrs } 306172091Srrs SCTP_TCB_UNLOCK(stcb); 307172091Srrs } else if ((icmph->icmp_code == ICMP_UNREACH_PROTOCOL) || 308172091Srrs (icmph->icmp_code == ICMP_UNREACH_PORT)) { 309172091Srrs /* 310172091Srrs * Here the peer is either playing tricks on us, including 311172091Srrs * an address that belongs to someone who does not support 312172091Srrs * SCTP OR was a userland implementation that shutdown and 313172091Srrs * now is dead. In either case treat it like a OOTB abort 314172091Srrs * with no TCB 315172091Srrs */ 316172091Srrs reason = SCTP_PEER_FAULTY; 317172091Srrs sctp_abort_notification(stcb, reason, SCTP_SO_NOT_LOCKED); 318172090Srrs#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 319172091Srrs so = SCTP_INP_SO(inp); 320172091Srrs atomic_add_int(&stcb->asoc.refcnt, 1); 321172091Srrs SCTP_TCB_UNLOCK(stcb); 322172091Srrs SCTP_SOCKET_LOCK(so, 1); 323172091Srrs SCTP_TCB_LOCK(stcb); 324172091Srrs atomic_subtract_int(&stcb->asoc.refcnt, 1); 325172090Srrs#endif 326172091Srrs (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); 327172090Srrs#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 328172091Srrs SCTP_SOCKET_UNLOCK(so, 1); 329172091Srrs /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */ 330172090Srrs#endif 331172091Srrs /* no need to unlock here, since the TCB is gone */ 332163953Srrs } else { 333172091Srrs SCTP_TCB_UNLOCK(stcb); 334163953Srrs } 335163953Srrs} 336163953Srrs 337163953Srrsvoid 338163953Srrssctp_ctlinput(cmd, sa, vip) 339163953Srrs int cmd; 340163953Srrs struct sockaddr *sa; 341163953Srrs void *vip; 342163953Srrs{ 343163953Srrs struct ip *ip = vip; 344163953Srrs struct sctphdr *sh; 345167598Srrs uint32_t vrf_id; 346163953Srrs 347168299Srrs /* FIX, for non-bsd is this right? */ 348167598Srrs vrf_id = SCTP_DEFAULT_VRFID; 349163953Srrs if (sa->sa_family != AF_INET || 350163953Srrs ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) { 351163953Srrs return; 352163953Srrs } 353163953Srrs if (PRC_IS_REDIRECT(cmd)) { 354163953Srrs ip = 0; 355163953Srrs } else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) { 356163953Srrs return; 357163953Srrs } 358163953Srrs if (ip) { 359163953Srrs struct sctp_inpcb *inp = NULL; 360163953Srrs struct sctp_tcb *stcb = NULL; 361163953Srrs struct sctp_nets *net = NULL; 362163953Srrs struct sockaddr_in to, from; 363163953Srrs 364163953Srrs sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 365163953Srrs bzero(&to, sizeof(to)); 366163953Srrs bzero(&from, sizeof(from)); 367163953Srrs from.sin_family = to.sin_family = AF_INET; 368163953Srrs from.sin_len = to.sin_len = sizeof(to); 369163953Srrs from.sin_port = sh->src_port; 370163953Srrs from.sin_addr = ip->ip_src; 371163953Srrs to.sin_port = sh->dest_port; 372163953Srrs to.sin_addr = ip->ip_dst; 373163953Srrs 374163953Srrs /* 375163953Srrs * 'to' holds the dest of the packet that failed to be sent. 376163953Srrs * 'from' holds our local endpoint address. Thus we reverse 377163953Srrs * the to and the from in the lookup. 378163953Srrs */ 379163953Srrs stcb = sctp_findassociation_addr_sa((struct sockaddr *)&from, 380163953Srrs (struct sockaddr *)&to, 381167598Srrs &inp, &net, 1, vrf_id); 382163953Srrs if (stcb != NULL && inp && (inp->sctp_socket != NULL)) { 383163953Srrs if (cmd != PRC_MSGSIZE) { 384172091Srrs sctp_notify(inp, ip, sh, 385163953Srrs (struct sockaddr *)&to, stcb, 386163953Srrs net); 387163953Srrs } else { 388163953Srrs /* handle possible ICMP size messages */ 389163953Srrs sctp_notify_mbuf(inp, stcb, net, ip, sh); 390163953Srrs } 391163953Srrs } else { 392163953Srrs if ((stcb == NULL) && (inp != NULL)) { 393163953Srrs /* reduce ref-count */ 394163953Srrs SCTP_INP_WLOCK(inp); 395163953Srrs SCTP_INP_DECR_REF(inp); 396163953Srrs SCTP_INP_WUNLOCK(inp); 397163953Srrs } 398163953Srrs } 399163953Srrs } 400163953Srrs return; 401163953Srrs} 402163953Srrs 403163953Srrsstatic int 404163953Srrssctp_getcred(SYSCTL_HANDLER_ARGS) 405163953Srrs{ 406164085Srrs struct xucred xuc; 407163953Srrs struct sockaddr_in addrs[2]; 408163953Srrs struct sctp_inpcb *inp; 409163953Srrs struct sctp_nets *net; 410163953Srrs struct sctp_tcb *stcb; 411164085Srrs int error; 412167598Srrs uint32_t vrf_id; 413163953Srrs 414168299Srrs /* FIX, for non-bsd is this right? */ 415167598Srrs vrf_id = SCTP_DEFAULT_VRFID; 416168299Srrs 417170587Srwatson error = priv_check(req->td, PRIV_NETINET_GETCRED); 418170587Srwatson 419163953Srrs if (error) 420163953Srrs return (error); 421164039Srwatson 422163953Srrs error = SYSCTL_IN(req, addrs, sizeof(addrs)); 423163953Srrs if (error) 424163953Srrs return (error); 425163953Srrs 426163953Srrs stcb = sctp_findassociation_addr_sa(sintosa(&addrs[0]), 427163953Srrs sintosa(&addrs[1]), 428167598Srrs &inp, &net, 1, vrf_id); 429163953Srrs if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) { 430163953Srrs if ((inp != NULL) && (stcb == NULL)) { 431163953Srrs /* reduce ref-count */ 432163953Srrs SCTP_INP_WLOCK(inp); 433163953Srrs SCTP_INP_DECR_REF(inp); 434164085Srrs goto cred_can_cont; 435163953Srrs } 436171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 437163953Srrs error = ENOENT; 438163953Srrs goto out; 439163953Srrs } 440163953Srrs SCTP_TCB_UNLOCK(stcb); 441164085Srrs /* 442164085Srrs * We use the write lock here, only since in the error leg we need 443164085Srrs * it. If we used RLOCK, then we would have to 444164085Srrs * wlock/decr/unlock/rlock. Which in theory could create a hole. 445164085Srrs * Better to use higher wlock. 446164085Srrs */ 447164085Srrs SCTP_INP_WLOCK(inp); 448164085Srrscred_can_cont: 449164085Srrs error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket); 450164085Srrs if (error) { 451164085Srrs SCTP_INP_WUNLOCK(inp); 452164085Srrs goto out; 453164085Srrs } 454164085Srrs cru2x(inp->sctp_socket->so_cred, &xuc); 455164085Srrs SCTP_INP_WUNLOCK(inp); 456164085Srrs error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); 457163953Srrsout: 458163953Srrs return (error); 459163953Srrs} 460163953Srrs 461163953SrrsSYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW, 462163953Srrs 0, 0, sctp_getcred, "S,ucred", "Get the ucred of a SCTP connection"); 463163953Srrs 464163953Srrs 465163953Srrsstatic void 466163953Srrssctp_abort(struct socket *so) 467163953Srrs{ 468163953Srrs struct sctp_inpcb *inp; 469163953Srrs uint32_t flags; 470163953Srrs 471163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 472171943Srrs if (inp == 0) { 473163953Srrs return; 474171943Srrs } 475163953Srrssctp_must_try_again: 476163953Srrs flags = inp->sctp_flags; 477163953Srrs#ifdef SCTP_LOG_CLOSING 478163953Srrs sctp_log_closing(inp, NULL, 17); 479163953Srrs#endif 480163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 481163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 482163953Srrs#ifdef SCTP_LOG_CLOSING 483163953Srrs sctp_log_closing(inp, NULL, 16); 484163953Srrs#endif 485169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 486169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 487163953Srrs SOCK_LOCK(so); 488167695Srrs SCTP_SB_CLEAR(so->so_snd); 489163953Srrs /* 490163953Srrs * same for the rcv ones, they are only here for the 491163953Srrs * accounting/select. 492163953Srrs */ 493167695Srrs SCTP_SB_CLEAR(so->so_rcv); 494167695Srrs 495167695Srrs /* Now null out the reference, we are completely detached. */ 496163953Srrs so->so_pcb = NULL; 497163953Srrs SOCK_UNLOCK(so); 498163953Srrs } else { 499163953Srrs flags = inp->sctp_flags; 500163953Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 501163953Srrs goto sctp_must_try_again; 502163953Srrs } 503163953Srrs } 504163953Srrs return; 505163953Srrs} 506163953Srrs 507163953Srrsstatic int 508163953Srrssctp_attach(struct socket *so, int proto, struct thread *p) 509163953Srrs{ 510163953Srrs struct sctp_inpcb *inp; 511163953Srrs struct inpcb *ip_inp; 512166086Srrs int error; 513170205Srrs uint32_t vrf_id = SCTP_DEFAULT_VRFID; 514163953Srrs 515171167Sgnn#ifdef IPSEC 516163953Srrs uint32_t flags; 517171440Srrs 518163953Srrs#endif 519163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 520163953Srrs if (inp != 0) { 521171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 522163953Srrs return EINVAL; 523163953Srrs } 524167695Srrs error = SCTP_SORESERVE(so, sctp_sendspace, sctp_recvspace); 525163953Srrs if (error) { 526163953Srrs return error; 527163953Srrs } 528170205Srrs error = sctp_inpcb_alloc(so, vrf_id); 529163953Srrs if (error) { 530163953Srrs return error; 531163953Srrs } 532163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 533163953Srrs SCTP_INP_WLOCK(inp); 534163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6; /* I'm not v6! */ 535163953Srrs ip_inp = &inp->ip_inp.inp; 536163953Srrs ip_inp->inp_vflag |= INP_IPV4; 537163953Srrs ip_inp->inp_ip_ttl = ip_defttl; 538171167Sgnn#ifdef IPSEC 539171133Sgnn error = ipsec_init_policy(so, &ip_inp->inp_sp); 540163953Srrs#ifdef SCTP_LOG_CLOSING 541163953Srrs sctp_log_closing(inp, NULL, 17); 542163953Srrs#endif 543163953Srrs if (error != 0) { 544163953Srrs flags = inp->sctp_flags; 545163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 546163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 547163953Srrs#ifdef SCTP_LOG_CLOSING 548163953Srrs sctp_log_closing(inp, NULL, 15); 549163953Srrs#endif 550169352Srrs SCTP_INP_WUNLOCK(inp); 551169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 552169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 553169254Srrs } else { 554169352Srrs SCTP_INP_WUNLOCK(inp); 555163953Srrs } 556163953Srrs return error; 557163953Srrs } 558171167Sgnn#endif /* IPSEC */ 559163953Srrs SCTP_INP_WUNLOCK(inp); 560163953Srrs return 0; 561163953Srrs} 562163953Srrs 563163953Srrsstatic int 564163953Srrssctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p) 565163953Srrs{ 566171943Srrs struct sctp_inpcb *inp = NULL; 567166086Srrs int error; 568163953Srrs 569163953Srrs#ifdef INET6 570171943Srrs if (addr && addr->sa_family != AF_INET) { 571163953Srrs /* must be a v4 address! */ 572171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 573163953Srrs return EINVAL; 574171943Srrs } 575163953Srrs#endif /* INET6 */ 576170056Srrs if (addr && (addr->sa_len != sizeof(struct sockaddr_in))) { 577171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 578170056Srrs return EINVAL; 579170056Srrs } 580163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 581171943Srrs if (inp == 0) { 582171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 583163953Srrs return EINVAL; 584171943Srrs } 585171572Srrs error = sctp_inpcb_bind(so, addr, NULL, p); 586163953Srrs return error; 587163953Srrs} 588163953Srrs 589171990Srrsvoid 590163953Srrssctp_close(struct socket *so) 591163953Srrs{ 592163953Srrs struct sctp_inpcb *inp; 593163953Srrs uint32_t flags; 594163953Srrs 595163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 596163953Srrs if (inp == 0) 597163953Srrs return; 598163953Srrs 599163953Srrs /* 600163953Srrs * Inform all the lower layer assoc that we are done. 601163953Srrs */ 602163953Srrssctp_must_try_again: 603163953Srrs flags = inp->sctp_flags; 604163953Srrs#ifdef SCTP_LOG_CLOSING 605163953Srrs sctp_log_closing(inp, NULL, 17); 606163953Srrs#endif 607163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 608163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 609163953Srrs if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || 610163953Srrs (so->so_rcv.sb_cc > 0)) { 611163953Srrs#ifdef SCTP_LOG_CLOSING 612163953Srrs sctp_log_closing(inp, NULL, 13); 613163953Srrs#endif 614169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 615169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 616163953Srrs } else { 617163953Srrs#ifdef SCTP_LOG_CLOSING 618163953Srrs sctp_log_closing(inp, NULL, 14); 619163953Srrs#endif 620169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE, 621169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 622163953Srrs } 623163953Srrs /* 624163953Srrs * The socket is now detached, no matter what the state of 625163953Srrs * the SCTP association. 626163953Srrs */ 627163953Srrs SOCK_LOCK(so); 628167695Srrs SCTP_SB_CLEAR(so->so_snd); 629163953Srrs /* 630163953Srrs * same for the rcv ones, they are only here for the 631163953Srrs * accounting/select. 632163953Srrs */ 633167695Srrs SCTP_SB_CLEAR(so->so_rcv); 634167695Srrs 635167695Srrs /* Now null out the reference, we are completely detached. */ 636163953Srrs so->so_pcb = NULL; 637163953Srrs SOCK_UNLOCK(so); 638163953Srrs } else { 639163953Srrs flags = inp->sctp_flags; 640163953Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 641163953Srrs goto sctp_must_try_again; 642163953Srrs } 643163953Srrs } 644163953Srrs return; 645163953Srrs} 646163953Srrs 647163953Srrs 648163953Srrsint 649163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 650163953Srrs struct mbuf *control, struct thread *p); 651163953Srrs 652163953Srrs 653163953Srrsint 654163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 655163953Srrs struct mbuf *control, struct thread *p) 656163953Srrs{ 657163953Srrs struct sctp_inpcb *inp; 658163953Srrs int error; 659163953Srrs 660163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 661163953Srrs if (inp == 0) { 662163953Srrs if (control) { 663163953Srrs sctp_m_freem(control); 664163953Srrs control = NULL; 665163953Srrs } 666171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 667163953Srrs sctp_m_freem(m); 668163953Srrs return EINVAL; 669163953Srrs } 670163953Srrs /* Got to have an to address if we are NOT a connected socket */ 671163953Srrs if ((addr == NULL) && 672163953Srrs ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) || 673163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)) 674163953Srrs ) { 675163953Srrs goto connected_type; 676163953Srrs } else if (addr == NULL) { 677171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); 678163953Srrs error = EDESTADDRREQ; 679163953Srrs sctp_m_freem(m); 680163953Srrs if (control) { 681163953Srrs sctp_m_freem(control); 682163953Srrs control = NULL; 683163953Srrs } 684163953Srrs return (error); 685163953Srrs } 686163953Srrs#ifdef INET6 687163953Srrs if (addr->sa_family != AF_INET) { 688163953Srrs /* must be a v4 address! */ 689171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); 690163953Srrs sctp_m_freem(m); 691163953Srrs if (control) { 692163953Srrs sctp_m_freem(control); 693163953Srrs control = NULL; 694163953Srrs } 695163953Srrs error = EDESTADDRREQ; 696171943Srrs return EDESTADDRREQ; 697163953Srrs } 698163953Srrs#endif /* INET6 */ 699163953Srrsconnected_type: 700163953Srrs /* now what about control */ 701163953Srrs if (control) { 702163953Srrs if (inp->control) { 703169420Srrs SCTP_PRINTF("huh? control set?\n"); 704163953Srrs sctp_m_freem(inp->control); 705163953Srrs inp->control = NULL; 706163953Srrs } 707163953Srrs inp->control = control; 708163953Srrs } 709163953Srrs /* Place the data */ 710163953Srrs if (inp->pkt) { 711165647Srrs SCTP_BUF_NEXT(inp->pkt_last) = m; 712163953Srrs inp->pkt_last = m; 713163953Srrs } else { 714163953Srrs inp->pkt_last = inp->pkt = m; 715163953Srrs } 716163953Srrs if ( 717163953Srrs /* FreeBSD uses a flag passed */ 718163953Srrs ((flags & PRUS_MORETOCOME) == 0) 719163953Srrs ) { 720163953Srrs /* 721163953Srrs * note with the current version this code will only be used 722163953Srrs * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for 723163953Srrs * re-defining sosend to use the sctp_sosend. One can 724163953Srrs * optionally switch back to this code (by changing back the 725163953Srrs * definitions) but this is not advisable. This code is used 726163953Srrs * by FreeBSD when sending a file with sendfile() though. 727163953Srrs */ 728163953Srrs int ret; 729163953Srrs 730163953Srrs ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags); 731163953Srrs inp->pkt = NULL; 732163953Srrs inp->control = NULL; 733163953Srrs return (ret); 734163953Srrs } else { 735163953Srrs return (0); 736163953Srrs } 737163953Srrs} 738163953Srrs 739171990Srrsint 740163953Srrssctp_disconnect(struct socket *so) 741163953Srrs{ 742163953Srrs struct sctp_inpcb *inp; 743163953Srrs 744163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 745163953Srrs if (inp == NULL) { 746171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 747163953Srrs return (ENOTCONN); 748163953Srrs } 749163953Srrs SCTP_INP_RLOCK(inp); 750171745Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 751171745Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 752166675Srrs if (SCTP_LIST_EMPTY(&inp->sctp_asoc_list)) { 753163953Srrs /* No connection */ 754163953Srrs SCTP_INP_RUNLOCK(inp); 755163953Srrs return (0); 756163953Srrs } else { 757163953Srrs struct sctp_association *asoc; 758163953Srrs struct sctp_tcb *stcb; 759163953Srrs 760163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 761163953Srrs if (stcb == NULL) { 762163953Srrs SCTP_INP_RUNLOCK(inp); 763171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 764163953Srrs return (EINVAL); 765163953Srrs } 766163953Srrs SCTP_TCB_LOCK(stcb); 767163953Srrs asoc = &stcb->asoc; 768163953Srrs if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 769163953Srrs /* We are about to be freed, out of here */ 770163953Srrs SCTP_TCB_UNLOCK(stcb); 771163953Srrs SCTP_INP_RUNLOCK(inp); 772163953Srrs return (0); 773163953Srrs } 774163953Srrs if (((so->so_options & SO_LINGER) && 775163953Srrs (so->so_linger == 0)) || 776163953Srrs (so->so_rcv.sb_cc > 0)) { 777163953Srrs if (SCTP_GET_STATE(asoc) != 778163953Srrs SCTP_STATE_COOKIE_WAIT) { 779163953Srrs /* Left with Data unread */ 780163953Srrs struct mbuf *err; 781163953Srrs 782163953Srrs err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_DONTWAIT, 1, MT_DATA); 783163953Srrs if (err) { 784163953Srrs /* 785163953Srrs * Fill in the user 786163953Srrs * initiated abort 787163953Srrs */ 788163953Srrs struct sctp_paramhdr *ph; 789163953Srrs 790163953Srrs ph = mtod(err, struct sctp_paramhdr *); 791165647Srrs SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr); 792163953Srrs ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); 793165647Srrs ph->param_length = htons(SCTP_BUF_LEN(err)); 794163953Srrs } 795172396Srrs#if defined(SCTP_PANIC_ON_ABORT) 796172396Srrs panic("disconnect does an abort"); 797172396Srrs#endif 798172090Srrs sctp_send_abort_tcb(stcb, err, SCTP_SO_LOCKED); 799163953Srrs SCTP_STAT_INCR_COUNTER32(sctps_aborted); 800163953Srrs } 801163953Srrs SCTP_INP_RUNLOCK(inp); 802163953Srrs if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 803163953Srrs (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 804163953Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 805163953Srrs } 806171943Srrs (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3); 807163953Srrs /* No unlock tcb assoc is gone */ 808163953Srrs return (0); 809163953Srrs } 810163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 811163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 812163953Srrs (asoc->stream_queue_cnt == 0)) { 813163953Srrs /* there is nothing queued to send, so done */ 814163953Srrs if (asoc->locked_on_sending) { 815163953Srrs goto abort_anyway; 816163953Srrs } 817166675Srrs if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) && 818166675Srrs (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { 819163953Srrs /* only send SHUTDOWN 1st time thru */ 820163953Srrs sctp_stop_timers_for_shutdown(stcb); 821163953Srrs sctp_send_shutdown(stcb, 822163953Srrs stcb->asoc.primary_destination); 823172090Srrs sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); 824166675Srrs if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 825166675Srrs (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 826166675Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 827166675Srrs } 828171943Srrs SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); 829172703Srrs SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 830163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 831163953Srrs stcb->sctp_ep, stcb, 832163953Srrs asoc->primary_destination); 833163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 834163953Srrs stcb->sctp_ep, stcb, 835163953Srrs asoc->primary_destination); 836163953Srrs } 837163953Srrs } else { 838163953Srrs /* 839163953Srrs * we still got (or just got) data to send, 840163953Srrs * so set SHUTDOWN_PENDING 841163953Srrs */ 842163953Srrs /* 843163953Srrs * XXX sockets draft says that SCTP_EOF 844163953Srrs * should be sent with no data. currently, 845163953Srrs * we will allow user data to be sent first 846163953Srrs * and move to SHUTDOWN-PENDING 847163953Srrs */ 848163953Srrs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 849163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, 850163953Srrs asoc->primary_destination); 851163953Srrs if (asoc->locked_on_sending) { 852163953Srrs /* Locked to send out the data */ 853163953Srrs struct sctp_stream_queue_pending *sp; 854163953Srrs 855163953Srrs sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); 856163953Srrs if (sp == NULL) { 857169420Srrs SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", 858163953Srrs asoc->locked_on_sending->stream_no); 859163953Srrs } else { 860163953Srrs if ((sp->length == 0) && (sp->msg_is_complete == 0)) 861163953Srrs asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; 862163953Srrs } 863163953Srrs } 864163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 865163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 866163953Srrs (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 867163953Srrs struct mbuf *op_err; 868163953Srrs 869163953Srrs abort_anyway: 870163953Srrs op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 871163953Srrs 0, M_DONTWAIT, 1, MT_DATA); 872163953Srrs if (op_err) { 873163953Srrs /* 874163953Srrs * Fill in the user 875163953Srrs * initiated abort 876163953Srrs */ 877163953Srrs struct sctp_paramhdr *ph; 878163953Srrs uint32_t *ippp; 879163953Srrs 880165647Srrs SCTP_BUF_LEN(op_err) = 881163953Srrs (sizeof(struct sctp_paramhdr) + sizeof(uint32_t)); 882163953Srrs ph = mtod(op_err, 883163953Srrs struct sctp_paramhdr *); 884163953Srrs ph->param_type = htons( 885163953Srrs SCTP_CAUSE_USER_INITIATED_ABT); 886165647Srrs ph->param_length = htons(SCTP_BUF_LEN(op_err)); 887163953Srrs ippp = (uint32_t *) (ph + 1); 888165220Srrs *ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4); 889163953Srrs } 890172396Srrs#if defined(SCTP_PANIC_ON_ABORT) 891172396Srrs panic("disconnect does an abort"); 892172396Srrs#endif 893172396Srrs 894165220Srrs stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4; 895172090Srrs sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED); 896163953Srrs SCTP_STAT_INCR_COUNTER32(sctps_aborted); 897163953Srrs if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 898163953Srrs (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 899163953Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 900163953Srrs } 901163953Srrs SCTP_INP_RUNLOCK(inp); 902171943Srrs (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5); 903163953Srrs return (0); 904171990Srrs } else { 905172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); 906163953Srrs } 907163953Srrs } 908163953Srrs SCTP_TCB_UNLOCK(stcb); 909163953Srrs SCTP_INP_RUNLOCK(inp); 910163953Srrs return (0); 911163953Srrs } 912163953Srrs /* not reached */ 913163953Srrs } else { 914163953Srrs /* UDP model does not support this */ 915163953Srrs SCTP_INP_RUNLOCK(inp); 916171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 917163953Srrs return EOPNOTSUPP; 918163953Srrs } 919163953Srrs} 920163953Srrs 921163953Srrsint 922163953Srrssctp_shutdown(struct socket *so) 923163953Srrs{ 924163953Srrs struct sctp_inpcb *inp; 925163953Srrs 926163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 927163953Srrs if (inp == 0) { 928171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 929163953Srrs return EINVAL; 930163953Srrs } 931163953Srrs SCTP_INP_RLOCK(inp); 932163953Srrs /* For UDP model this is a invalid call */ 933163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 934163953Srrs /* Restore the flags that the soshutdown took away. */ 935163953Srrs so->so_rcv.sb_state &= ~SBS_CANTRCVMORE; 936163953Srrs /* This proc will wakeup for read and do nothing (I hope) */ 937163953Srrs SCTP_INP_RUNLOCK(inp); 938171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 939163953Srrs return (EOPNOTSUPP); 940163953Srrs } 941163953Srrs /* 942163953Srrs * Ok if we reach here its the TCP model and it is either a SHUT_WR 943163953Srrs * or SHUT_RDWR. This means we put the shutdown flag against it. 944163953Srrs */ 945163953Srrs { 946163953Srrs struct sctp_tcb *stcb; 947163953Srrs struct sctp_association *asoc; 948163953Srrs 949163953Srrs socantsendmore(so); 950163953Srrs 951163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 952163953Srrs if (stcb == NULL) { 953163953Srrs /* 954163953Srrs * Ok we hit the case that the shutdown call was 955163953Srrs * made after an abort or something. Nothing to do 956163953Srrs * now. 957163953Srrs */ 958168299Srrs SCTP_INP_RUNLOCK(inp); 959163953Srrs return (0); 960163953Srrs } 961163953Srrs SCTP_TCB_LOCK(stcb); 962163953Srrs asoc = &stcb->asoc; 963163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 964163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 965163953Srrs (asoc->stream_queue_cnt == 0)) { 966163953Srrs if (asoc->locked_on_sending) { 967163953Srrs goto abort_anyway; 968163953Srrs } 969163953Srrs /* there is nothing queued to send, so I'm done... */ 970163953Srrs if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { 971163953Srrs /* only send SHUTDOWN the first time through */ 972163953Srrs sctp_stop_timers_for_shutdown(stcb); 973163953Srrs sctp_send_shutdown(stcb, 974163953Srrs stcb->asoc.primary_destination); 975172218Srrs sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); 976166675Srrs if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 977166675Srrs (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 978166675Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 979166675Srrs } 980171943Srrs SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); 981172703Srrs SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 982163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 983163953Srrs stcb->sctp_ep, stcb, 984163953Srrs asoc->primary_destination); 985163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 986163953Srrs stcb->sctp_ep, stcb, 987163953Srrs asoc->primary_destination); 988163953Srrs } 989163953Srrs } else { 990163953Srrs /* 991163953Srrs * we still got (or just got) data to send, so set 992163953Srrs * SHUTDOWN_PENDING 993163953Srrs */ 994163953Srrs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 995163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, 996163953Srrs asoc->primary_destination); 997163953Srrs 998163953Srrs if (asoc->locked_on_sending) { 999163953Srrs /* Locked to send out the data */ 1000163953Srrs struct sctp_stream_queue_pending *sp; 1001163953Srrs 1002163953Srrs sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); 1003163953Srrs if (sp == NULL) { 1004169420Srrs SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", 1005163953Srrs asoc->locked_on_sending->stream_no); 1006163953Srrs } else { 1007163953Srrs if ((sp->length == 0) && (sp->msg_is_complete == 0)) { 1008163953Srrs asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; 1009163953Srrs } 1010163953Srrs } 1011163953Srrs } 1012163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 1013163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 1014163953Srrs (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 1015163953Srrs struct mbuf *op_err; 1016163953Srrs 1017163953Srrs abort_anyway: 1018163953Srrs op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 1019163953Srrs 0, M_DONTWAIT, 1, MT_DATA); 1020163953Srrs if (op_err) { 1021163953Srrs /* Fill in the user initiated abort */ 1022163953Srrs struct sctp_paramhdr *ph; 1023163953Srrs uint32_t *ippp; 1024163953Srrs 1025165647Srrs SCTP_BUF_LEN(op_err) = 1026163953Srrs sizeof(struct sctp_paramhdr) + sizeof(uint32_t); 1027163953Srrs ph = mtod(op_err, 1028163953Srrs struct sctp_paramhdr *); 1029163953Srrs ph->param_type = htons( 1030163953Srrs SCTP_CAUSE_USER_INITIATED_ABT); 1031165647Srrs ph->param_length = htons(SCTP_BUF_LEN(op_err)); 1032163953Srrs ippp = (uint32_t *) (ph + 1); 1033165220Srrs *ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6); 1034163953Srrs } 1035172396Srrs#if defined(SCTP_PANIC_ON_ABORT) 1036172396Srrs panic("shutdown does an abort"); 1037172396Srrs#endif 1038165220Srrs stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6; 1039163953Srrs sctp_abort_an_association(stcb->sctp_ep, stcb, 1040163953Srrs SCTP_RESPONSE_TO_USER_REQ, 1041172090Srrs op_err, SCTP_SO_LOCKED); 1042163953Srrs goto skip_unlock; 1043171990Srrs } else { 1044172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); 1045163953Srrs } 1046163953Srrs } 1047163953Srrs SCTP_TCB_UNLOCK(stcb); 1048163953Srrs } 1049163953Srrsskip_unlock: 1050163953Srrs SCTP_INP_RUNLOCK(inp); 1051163953Srrs return 0; 1052163953Srrs} 1053163953Srrs 1054163953Srrs/* 1055163953Srrs * copies a "user" presentable address and removes embedded scope, etc. 1056163953Srrs * returns 0 on success, 1 on error 1057163953Srrs */ 1058163953Srrsstatic uint32_t 1059163953Srrssctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa) 1060163953Srrs{ 1061163953Srrs struct sockaddr_in6 lsa6; 1062163953Srrs 1063163953Srrs sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa, 1064163953Srrs &lsa6); 1065163953Srrs memcpy(ss, sa, sa->sa_len); 1066163953Srrs return (0); 1067163953Srrs} 1068163953Srrs 1069163953Srrs 1070163953Srrs 1071172091Srrs/* 1072172091Srrs * NOTE: assumes addr lock is held 1073172091Srrs */ 1074166675Srrsstatic size_t 1075168124Srrssctp_fill_up_addresses_vrf(struct sctp_inpcb *inp, 1076163953Srrs struct sctp_tcb *stcb, 1077166675Srrs size_t limit, 1078167598Srrs struct sockaddr_storage *sas, 1079167598Srrs uint32_t vrf_id) 1080163953Srrs{ 1081167598Srrs struct sctp_ifn *sctp_ifn; 1082167598Srrs struct sctp_ifa *sctp_ifa; 1083166675Srrs int loopback_scope, ipv4_local_scope, local_scope, site_scope; 1084166675Srrs size_t actual; 1085163953Srrs int ipv4_addr_legal, ipv6_addr_legal; 1086167598Srrs struct sctp_vrf *vrf; 1087163953Srrs 1088163953Srrs actual = 0; 1089163953Srrs if (limit <= 0) 1090163953Srrs return (actual); 1091163953Srrs 1092163953Srrs if (stcb) { 1093163953Srrs /* Turn on all the appropriate scope */ 1094163953Srrs loopback_scope = stcb->asoc.loopback_scope; 1095163953Srrs ipv4_local_scope = stcb->asoc.ipv4_local_scope; 1096163953Srrs local_scope = stcb->asoc.local_scope; 1097163953Srrs site_scope = stcb->asoc.site_scope; 1098163953Srrs } else { 1099163953Srrs /* Turn on ALL scope, since we look at the EP */ 1100163953Srrs loopback_scope = ipv4_local_scope = local_scope = 1101163953Srrs site_scope = 1; 1102163953Srrs } 1103163953Srrs ipv4_addr_legal = ipv6_addr_legal = 0; 1104163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 1105163953Srrs ipv6_addr_legal = 1; 1106166023Srrs if (SCTP_IPV6_V6ONLY(inp) == 0) { 1107163953Srrs ipv4_addr_legal = 1; 1108163953Srrs } 1109163953Srrs } else { 1110163953Srrs ipv4_addr_legal = 1; 1111163953Srrs } 1112167598Srrs vrf = sctp_find_vrf(vrf_id); 1113167598Srrs if (vrf == NULL) { 1114167598Srrs return (0); 1115167598Srrs } 1116163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1117167598Srrs LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 1118163953Srrs if ((loopback_scope == 0) && 1119167598Srrs SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { 1120163953Srrs /* Skip loopback if loopback_scope not set */ 1121163953Srrs continue; 1122163953Srrs } 1123167598Srrs LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 1124163953Srrs if (stcb) { 1125163953Srrs /* 1126163953Srrs * For the BOUND-ALL case, the list 1127163953Srrs * associated with a TCB is Always 1128163953Srrs * considered a reverse list.. i.e. 1129163953Srrs * it lists addresses that are NOT 1130163953Srrs * part of the association. If this 1131163953Srrs * is one of those we must skip it. 1132163953Srrs */ 1133163953Srrs if (sctp_is_addr_restricted(stcb, 1134167598Srrs sctp_ifa)) { 1135163953Srrs continue; 1136163953Srrs } 1137163953Srrs } 1138167598Srrs if ((sctp_ifa->address.sa.sa_family == AF_INET) && 1139163953Srrs (ipv4_addr_legal)) { 1140163953Srrs struct sockaddr_in *sin; 1141163953Srrs 1142167598Srrs sin = (struct sockaddr_in *)&sctp_ifa->address.sa; 1143163953Srrs if (sin->sin_addr.s_addr == 0) { 1144163953Srrs /* 1145163953Srrs * we skip unspecifed 1146163953Srrs * addresses 1147163953Srrs */ 1148163953Srrs continue; 1149163953Srrs } 1150163953Srrs if ((ipv4_local_scope == 0) && 1151163953Srrs (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { 1152163953Srrs continue; 1153163953Srrs } 1154163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) { 1155163953Srrs in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas); 1156163953Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1157163953Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6)); 1158171858Srrs actual += sizeof(struct sockaddr_in6); 1159163953Srrs } else { 1160163953Srrs memcpy(sas, sin, sizeof(*sin)); 1161163953Srrs ((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport; 1162163953Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin)); 1163163953Srrs actual += sizeof(*sin); 1164163953Srrs } 1165163953Srrs if (actual >= limit) { 1166163953Srrs return (actual); 1167163953Srrs } 1168167598Srrs } else if ((sctp_ifa->address.sa.sa_family == AF_INET6) && 1169163953Srrs (ipv6_addr_legal)) { 1170163953Srrs struct sockaddr_in6 *sin6; 1171163953Srrs 1172167598Srrs sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa; 1173163953Srrs if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 1174163953Srrs /* 1175163953Srrs * we skip unspecifed 1176163953Srrs * addresses 1177163953Srrs */ 1178163953Srrs continue; 1179163953Srrs } 1180163953Srrs if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 1181163953Srrs if (local_scope == 0) 1182163953Srrs continue; 1183163953Srrs if (sin6->sin6_scope_id == 0) { 1184163953Srrs if (sa6_recoverscope(sin6) != 0) 1185163953Srrs /* 1186163953Srrs * bad link 1187163953Srrs * local 1188163953Srrs * address 1189163953Srrs */ 1190163953Srrs continue; 1191163953Srrs } 1192163953Srrs } 1193163953Srrs if ((site_scope == 0) && 1194163953Srrs (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { 1195163953Srrs continue; 1196163953Srrs } 1197163953Srrs memcpy(sas, sin6, sizeof(*sin6)); 1198163953Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1199163953Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6)); 1200163953Srrs actual += sizeof(*sin6); 1201163953Srrs if (actual >= limit) { 1202163953Srrs return (actual); 1203163953Srrs } 1204163953Srrs } 1205163953Srrs } 1206163953Srrs } 1207163953Srrs } else { 1208163953Srrs struct sctp_laddr *laddr; 1209163953Srrs 1210167598Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1211167598Srrs if (stcb) { 1212167598Srrs if (sctp_is_addr_restricted(stcb, laddr->ifa)) { 1213163953Srrs continue; 1214163953Srrs } 1215163953Srrs } 1216167598Srrs if (sctp_fill_user_address(sas, &laddr->ifa->address.sa)) 1217167598Srrs continue; 1218167598Srrs 1219167598Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1220167598Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + 1221167598Srrs laddr->ifa->address.sa.sa_len); 1222167598Srrs actual += laddr->ifa->address.sa.sa_len; 1223167598Srrs if (actual >= limit) { 1224167598Srrs return (actual); 1225163953Srrs } 1226163953Srrs } 1227163953Srrs } 1228163953Srrs return (actual); 1229163953Srrs} 1230163953Srrs 1231168124Srrsstatic size_t 1232168124Srrssctp_fill_up_addresses(struct sctp_inpcb *inp, 1233168124Srrs struct sctp_tcb *stcb, 1234168124Srrs size_t limit, 1235168124Srrs struct sockaddr_storage *sas) 1236168124Srrs{ 1237168124Srrs size_t size = 0; 1238168124Srrs 1239172218Srrs SCTP_IPI_ADDR_RLOCK(); 1240168124Srrs /* fill up addresses for the endpoint's default vrf */ 1241168124Srrs size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas, 1242168124Srrs inp->def_vrf_id); 1243172218Srrs SCTP_IPI_ADDR_RUNLOCK(); 1244168124Srrs return (size); 1245168124Srrs} 1246168124Srrs 1247172091Srrs/* 1248172091Srrs * NOTE: assumes addr lock is held 1249172091Srrs */ 1250163953Srrsstatic int 1251168124Srrssctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) 1252163953Srrs{ 1253163953Srrs int cnt = 0; 1254167598Srrs struct sctp_vrf *vrf = NULL; 1255163953Srrs 1256163953Srrs /* 1257163953Srrs * In both sub-set bound an bound_all cases we return the MAXIMUM 1258163953Srrs * number of addresses that you COULD get. In reality the sub-set 1259163953Srrs * bound may have an exclusion list for a given TCB OR in the 1260163953Srrs * bound-all case a TCB may NOT include the loopback or other 1261163953Srrs * addresses as well. 1262163953Srrs */ 1263167598Srrs vrf = sctp_find_vrf(vrf_id); 1264167598Srrs if (vrf == NULL) { 1265167598Srrs return (0); 1266167598Srrs } 1267163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1268167598Srrs struct sctp_ifn *sctp_ifn; 1269167598Srrs struct sctp_ifa *sctp_ifa; 1270163953Srrs 1271167598Srrs LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 1272167598Srrs LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 1273163953Srrs /* Count them if they are the right type */ 1274167598Srrs if (sctp_ifa->address.sa.sa_family == AF_INET) { 1275163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) 1276163953Srrs cnt += sizeof(struct sockaddr_in6); 1277163953Srrs else 1278163953Srrs cnt += sizeof(struct sockaddr_in); 1279163953Srrs 1280167598Srrs } else if (sctp_ifa->address.sa.sa_family == AF_INET6) 1281163953Srrs cnt += sizeof(struct sockaddr_in6); 1282163953Srrs } 1283163953Srrs } 1284163953Srrs } else { 1285163953Srrs struct sctp_laddr *laddr; 1286163953Srrs 1287163953Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1288167598Srrs if (laddr->ifa->address.sa.sa_family == AF_INET) { 1289163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) 1290163953Srrs cnt += sizeof(struct sockaddr_in6); 1291163953Srrs else 1292163953Srrs cnt += sizeof(struct sockaddr_in); 1293163953Srrs 1294167598Srrs } else if (laddr->ifa->address.sa.sa_family == AF_INET6) 1295163953Srrs cnt += sizeof(struct sockaddr_in6); 1296163953Srrs } 1297163953Srrs } 1298163953Srrs return (cnt); 1299163953Srrs} 1300163953Srrs 1301168124Srrsstatic int 1302168124Srrssctp_count_max_addresses(struct sctp_inpcb *inp) 1303168124Srrs{ 1304168124Srrs int cnt = 0; 1305166675Srrs 1306172218Srrs SCTP_IPI_ADDR_RLOCK(); 1307168124Srrs /* count addresses for the endpoint's default VRF */ 1308168124Srrs cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id); 1309172218Srrs SCTP_IPI_ADDR_RUNLOCK(); 1310168124Srrs return (cnt); 1311168124Srrs} 1312168124Srrs 1313163953Srrsstatic int 1314166675Srrssctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, 1315166675Srrs size_t optsize, void *p, int delay) 1316163953Srrs{ 1317163953Srrs int error = 0; 1318163953Srrs int creat_lock_on = 0; 1319163953Srrs struct sctp_tcb *stcb = NULL; 1320163953Srrs struct sockaddr *sa; 1321169352Srrs int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr; 1322169352Srrs int added = 0; 1323167598Srrs uint32_t vrf_id; 1324170056Srrs int bad_addresses = 0; 1325167598Srrs sctp_assoc_t *a_id; 1326163953Srrs 1327169420Srrs SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n"); 1328163953Srrs 1329163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 1330163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 1331163953Srrs /* We are already connected AND the TCP model */ 1332171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 1333163953Srrs return (EADDRINUSE); 1334163953Srrs } 1335163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) { 1336171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1337163953Srrs return (EINVAL); 1338163953Srrs } 1339163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 1340163953Srrs SCTP_INP_RLOCK(inp); 1341163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 1342163953Srrs SCTP_INP_RUNLOCK(inp); 1343163953Srrs } 1344163953Srrs if (stcb) { 1345171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 1346163953Srrs return (EALREADY); 1347163953Srrs } 1348163953Srrs SCTP_INP_INCR_REF(inp); 1349163953Srrs SCTP_ASOC_CREATE_LOCK(inp); 1350163953Srrs creat_lock_on = 1; 1351163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 1352163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 1353171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); 1354163953Srrs error = EFAULT; 1355163953Srrs goto out_now; 1356163953Srrs } 1357166675Srrs totaddrp = (int *)optval; 1358163953Srrs totaddr = *totaddrp; 1359163953Srrs sa = (struct sockaddr *)(totaddrp + 1); 1360170056Srrs stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses); 1361170056Srrs if ((stcb != NULL) || bad_addresses) { 1362169352Srrs /* Already have or am bring up an association */ 1363169352Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1364169352Srrs creat_lock_on = 0; 1365170931Srrs if (stcb) 1366170931Srrs SCTP_TCB_UNLOCK(stcb); 1367171943Srrs if (bad_addresses == 0) { 1368171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 1369170056Srrs error = EALREADY; 1370171943Srrs } 1371169352Srrs goto out_now; 1372163953Srrs } 1373163953Srrs#ifdef INET6 1374163953Srrs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 1375163953Srrs (num_v6 > 0)) { 1376163953Srrs error = EINVAL; 1377163953Srrs goto out_now; 1378163953Srrs } 1379163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 1380163953Srrs (num_v4 > 0)) { 1381163953Srrs struct in6pcb *inp6; 1382163953Srrs 1383163953Srrs inp6 = (struct in6pcb *)inp; 1384166023Srrs if (SCTP_IPV6_V6ONLY(inp6)) { 1385163953Srrs /* 1386163953Srrs * if IPV6_V6ONLY flag, ignore connections destined 1387163953Srrs * to a v4 addr or v4-mapped addr 1388163953Srrs */ 1389171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1390163953Srrs error = EINVAL; 1391163953Srrs goto out_now; 1392163953Srrs } 1393163953Srrs } 1394163953Srrs#endif /* INET6 */ 1395163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 1396163953Srrs SCTP_PCB_FLAGS_UNBOUND) { 1397163953Srrs /* Bind a ephemeral port */ 1398171572Srrs error = sctp_inpcb_bind(so, NULL, NULL, p); 1399163953Srrs if (error) { 1400163953Srrs goto out_now; 1401163953Srrs } 1402163953Srrs } 1403167695Srrs /* FIX ME: do we want to pass in a vrf on the connect call? */ 1404167695Srrs vrf_id = inp->def_vrf_id; 1405167695Srrs 1406163953Srrs /* We are GOOD to go */ 1407171531Srrs stcb = sctp_aloc_assoc(inp, sa, 1, &error, 0, vrf_id, 1408171531Srrs (struct thread *)p 1409171531Srrs ); 1410163953Srrs if (stcb == NULL) { 1411163953Srrs /* Gak! no memory */ 1412163953Srrs goto out_now; 1413163953Srrs } 1414171943Srrs SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); 1415163953Srrs /* move to second address */ 1416163953Srrs if (sa->sa_family == AF_INET) 1417163953Srrs sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in)); 1418163953Srrs else 1419163953Srrs sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6)); 1420163953Srrs 1421170056Srrs error = 0; 1422169352Srrs added = sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error); 1423167598Srrs /* Fill in the return id */ 1424170056Srrs if (error) { 1425171943Srrs (void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_12); 1426170056Srrs goto out_now; 1427170056Srrs } 1428167598Srrs a_id = (sctp_assoc_t *) optval; 1429167598Srrs *a_id = sctp_get_associd(stcb); 1430163953Srrs 1431163953Srrs /* initialize authentication parameters for the assoc */ 1432163953Srrs sctp_initialize_auth_params(inp, stcb); 1433163953Srrs 1434163953Srrs if (delay) { 1435163953Srrs /* doing delayed connection */ 1436163953Srrs stcb->asoc.delayed_connection = 1; 1437163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination); 1438163953Srrs } else { 1439169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 1440172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 1441163953Srrs } 1442163953Srrs SCTP_TCB_UNLOCK(stcb); 1443163953Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 1444163953Srrs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 1445163953Srrs /* Set the connected flag so we can queue data */ 1446163953Srrs soisconnecting(so); 1447163953Srrs } 1448163953Srrsout_now: 1449169655Srrs if (creat_lock_on) { 1450163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1451169655Srrs } 1452163953Srrs SCTP_INP_DECR_REF(inp); 1453163953Srrs return error; 1454163953Srrs} 1455163953Srrs 1456169420Srrs#define SCTP_FIND_STCB(inp, stcb, assoc_id) { \ 1457169655Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||\ 1458169655Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { \ 1459166675Srrs SCTP_INP_RLOCK(inp); \ 1460166675Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); \ 1461169655Srrs if (stcb) { \ 1462166675Srrs SCTP_TCB_LOCK(stcb); \ 1463169655Srrs } \ 1464166675Srrs SCTP_INP_RUNLOCK(inp); \ 1465166675Srrs } else if (assoc_id != 0) { \ 1466166675Srrs stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \ 1467166675Srrs if (stcb == NULL) { \ 1468171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \ 1469166675Srrs error = ENOENT; \ 1470166675Srrs break; \ 1471166675Srrs } \ 1472166675Srrs } else { \ 1473166675Srrs stcb = NULL; \ 1474169420Srrs } \ 1475169420Srrs } 1476163953Srrs 1477169420Srrs 1478169420Srrs#define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\ 1479166675Srrs if (size < sizeof(type)) { \ 1480171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); \ 1481166675Srrs error = EINVAL; \ 1482166675Srrs break; \ 1483166675Srrs } else { \ 1484166675Srrs destp = (type *)srcp; \ 1485169420Srrs } \ 1486169420Srrs } 1487163953Srrs 1488163953Srrsstatic int 1489166675Srrssctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, 1490166675Srrs void *p) 1491163953Srrs{ 1492171943Srrs struct sctp_inpcb *inp = NULL; 1493166675Srrs int error, val = 0; 1494163953Srrs struct sctp_tcb *stcb = NULL; 1495163953Srrs 1496166675Srrs if (optval == NULL) { 1497171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1498166675Srrs return (EINVAL); 1499166675Srrs } 1500163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 1501171943Srrs if (inp == 0) { 1502171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1503163953Srrs return EINVAL; 1504171943Srrs } 1505163953Srrs error = 0; 1506163953Srrs 1507166675Srrs switch (optname) { 1508163953Srrs case SCTP_NODELAY: 1509163953Srrs case SCTP_AUTOCLOSE: 1510163953Srrs case SCTP_EXPLICIT_EOR: 1511163953Srrs case SCTP_AUTO_ASCONF: 1512163953Srrs case SCTP_DISABLE_FRAGMENTS: 1513163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 1514163953Srrs case SCTP_USE_EXT_RCVINFO: 1515163953Srrs SCTP_INP_RLOCK(inp); 1516166675Srrs switch (optname) { 1517163953Srrs case SCTP_DISABLE_FRAGMENTS: 1518166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT); 1519163953Srrs break; 1520163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 1521166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4); 1522163953Srrs break; 1523163953Srrs case SCTP_AUTO_ASCONF: 1524171943Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1525171943Srrs /* only valid for bound all sockets */ 1526171943Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); 1527171943Srrs } else { 1528171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1529171943Srrs error = EINVAL; 1530171943Srrs goto flags_out; 1531171943Srrs } 1532163953Srrs break; 1533163953Srrs case SCTP_EXPLICIT_EOR: 1534166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); 1535163953Srrs break; 1536163953Srrs case SCTP_NODELAY: 1537166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY); 1538163953Srrs break; 1539163953Srrs case SCTP_USE_EXT_RCVINFO: 1540166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO); 1541163953Srrs break; 1542163953Srrs case SCTP_AUTOCLOSE: 1543163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) 1544166675Srrs val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time); 1545163953Srrs else 1546166675Srrs val = 0; 1547163953Srrs break; 1548163953Srrs 1549163953Srrs default: 1550171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 1551163953Srrs error = ENOPROTOOPT; 1552163953Srrs } /* end switch (sopt->sopt_name) */ 1553166675Srrs if (optname != SCTP_AUTOCLOSE) { 1554163953Srrs /* make it an "on/off" value */ 1555166675Srrs val = (val != 0); 1556163953Srrs } 1557166675Srrs if (*optsize < sizeof(val)) { 1558171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1559163953Srrs error = EINVAL; 1560163953Srrs } 1561171943Srrsflags_out: 1562163953Srrs SCTP_INP_RUNLOCK(inp); 1563163953Srrs if (error == 0) { 1564163953Srrs /* return the option value */ 1565166675Srrs *(int *)optval = val; 1566166675Srrs *optsize = sizeof(val); 1567163953Srrs } 1568163953Srrs break; 1569170091Srrs case SCTP_GET_PACKET_LOG: 1570170091Srrs { 1571170091Srrs#ifdef SCTP_PACKET_LOGGING 1572170091Srrs uint8_t *target; 1573170091Srrs int ret; 1574167598Srrs 1575170091Srrs SCTP_CHECK_AND_CAST(target, optval, uint8_t, *optsize); 1576170091Srrs ret = sctp_copy_out_packet_log(target, (int)*optsize); 1577170091Srrs *optsize = ret; 1578170091Srrs#else 1579171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 1580170091Srrs error = EOPNOTSUPP; 1581170091Srrs#endif 1582170091Srrs break; 1583170091Srrs } 1584163953Srrs case SCTP_PARTIAL_DELIVERY_POINT: 1585163953Srrs { 1586166675Srrs uint32_t *value; 1587166675Srrs 1588166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1589166675Srrs *value = inp->partial_delivery_point; 1590166675Srrs *optsize = sizeof(uint32_t); 1591163953Srrs } 1592163953Srrs break; 1593163953Srrs case SCTP_FRAGMENT_INTERLEAVE: 1594163953Srrs { 1595166675Srrs uint32_t *value; 1596166675Srrs 1597166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1598168943Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) { 1599168943Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) { 1600168943Srrs *value = SCTP_FRAG_LEVEL_2; 1601168943Srrs } else { 1602168943Srrs *value = SCTP_FRAG_LEVEL_1; 1603168943Srrs } 1604168943Srrs } else { 1605168943Srrs *value = SCTP_FRAG_LEVEL_0; 1606168943Srrs } 1607166675Srrs *optsize = sizeof(uint32_t); 1608163953Srrs } 1609163953Srrs break; 1610163953Srrs case SCTP_CMT_ON_OFF: 1611163953Srrs { 1612166675Srrs struct sctp_assoc_value *av; 1613166675Srrs 1614166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1615166675Srrs if (sctp_cmt_on_off) { 1616166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1617166675Srrs if (stcb) { 1618166675Srrs av->assoc_value = stcb->asoc.sctp_cmt_on_off; 1619166675Srrs SCTP_TCB_UNLOCK(stcb); 1620166675Srrs 1621166675Srrs } else { 1622171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 1623166675Srrs error = ENOTCONN; 1624166675Srrs } 1625166675Srrs } else { 1626171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 1627166675Srrs error = ENOPROTOOPT; 1628163953Srrs } 1629166675Srrs *optsize = sizeof(*av); 1630163953Srrs } 1631163953Srrs break; 1632171440Srrs /* JRS - Get socket option for pluggable congestion control */ 1633171440Srrs case SCTP_PLUGGABLE_CC: 1634171440Srrs { 1635171440Srrs struct sctp_assoc_value *av; 1636171440Srrs 1637171440Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1638171440Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1639171440Srrs if (stcb) { 1640171440Srrs av->assoc_value = stcb->asoc.congestion_control_module; 1641171440Srrs SCTP_TCB_UNLOCK(stcb); 1642171440Srrs } else { 1643171440Srrs av->assoc_value = inp->sctp_ep.sctp_default_cc_module; 1644171440Srrs } 1645171440Srrs *optsize = sizeof(*av); 1646171440Srrs } 1647171440Srrs break; 1648163953Srrs case SCTP_GET_ADDR_LEN: 1649163953Srrs { 1650163953Srrs struct sctp_assoc_value *av; 1651163953Srrs 1652166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1653163953Srrs error = EINVAL; 1654167598Srrs#ifdef INET 1655163953Srrs if (av->assoc_value == AF_INET) { 1656163953Srrs av->assoc_value = sizeof(struct sockaddr_in); 1657163953Srrs error = 0; 1658163953Srrs } 1659163953Srrs#endif 1660167598Srrs#ifdef INET6 1661163953Srrs if (av->assoc_value == AF_INET6) { 1662163953Srrs av->assoc_value = sizeof(struct sockaddr_in6); 1663163953Srrs error = 0; 1664163953Srrs } 1665163953Srrs#endif 1666172091Srrs if (error) { 1667171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1668172091Srrs } 1669166675Srrs *optsize = sizeof(*av); 1670163953Srrs } 1671163953Srrs break; 1672169655Srrs case SCTP_GET_ASSOC_NUMBER: 1673163953Srrs { 1674169655Srrs uint32_t *value, cnt; 1675163953Srrs 1676169655Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1677163953Srrs cnt = 0; 1678163953Srrs SCTP_INP_RLOCK(inp); 1679169655Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 1680169655Srrs cnt++; 1681163953Srrs } 1682169655Srrs SCTP_INP_RUNLOCK(inp); 1683169655Srrs *value = cnt; 1684169655Srrs *optsize = sizeof(uint32_t); 1685169655Srrs } 1686169655Srrs break; 1687163953Srrs 1688169655Srrs case SCTP_GET_ASSOC_ID_LIST: 1689169655Srrs { 1690169655Srrs struct sctp_assoc_ids *ids; 1691169655Srrs unsigned int at, limit; 1692169655Srrs 1693169655Srrs SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize); 1694163953Srrs at = 0; 1695169655Srrs limit = *optsize / sizeof(sctp_assoc_t); 1696169655Srrs SCTP_INP_RLOCK(inp); 1697169655Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 1698169655Srrs if (at < limit) { 1699169655Srrs ids->gaids_assoc_id[at++] = sctp_get_associd(stcb); 1700169655Srrs } else { 1701169655Srrs error = EINVAL; 1702171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1703163953Srrs break; 1704163953Srrs } 1705163953Srrs } 1706163953Srrs SCTP_INP_RUNLOCK(inp); 1707169655Srrs *optsize = at * sizeof(sctp_assoc_t); 1708163953Srrs } 1709163953Srrs break; 1710163953Srrs case SCTP_CONTEXT: 1711163953Srrs { 1712163953Srrs struct sctp_assoc_value *av; 1713163953Srrs 1714166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1715166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1716166675Srrs 1717166675Srrs if (stcb) { 1718166675Srrs av->assoc_value = stcb->asoc.context; 1719166675Srrs SCTP_TCB_UNLOCK(stcb); 1720163953Srrs } else { 1721166675Srrs SCTP_INP_RLOCK(inp); 1722163953Srrs av->assoc_value = inp->sctp_context; 1723166675Srrs SCTP_INP_RUNLOCK(inp); 1724163953Srrs } 1725166675Srrs *optsize = sizeof(*av); 1726163953Srrs } 1727163953Srrs break; 1728167598Srrs case SCTP_VRF_ID: 1729167598Srrs { 1730170056Srrs uint32_t *default_vrfid; 1731167598Srrs 1732170056Srrs SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize); 1733170056Srrs *default_vrfid = inp->def_vrf_id; 1734167598Srrs break; 1735167598Srrs } 1736167598Srrs case SCTP_GET_ASOC_VRF: 1737167598Srrs { 1738167598Srrs struct sctp_assoc_value *id; 1739167598Srrs 1740167598Srrs SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize); 1741167598Srrs SCTP_FIND_STCB(inp, stcb, id->assoc_id); 1742167598Srrs if (stcb == NULL) { 1743167598Srrs error = EINVAL; 1744171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1745167598Srrs break; 1746167598Srrs } 1747167598Srrs id->assoc_value = stcb->asoc.vrf_id; 1748167598Srrs break; 1749167598Srrs } 1750167598Srrs case SCTP_GET_VRF_IDS: 1751167598Srrs { 1752171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 1753167598Srrs error = EOPNOTSUPP; 1754167598Srrs break; 1755167598Srrs } 1756163953Srrs case SCTP_GET_NONCE_VALUES: 1757163953Srrs { 1758163953Srrs struct sctp_get_nonce_values *gnv; 1759163953Srrs 1760166675Srrs SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize); 1761166675Srrs SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id); 1762166675Srrs 1763166675Srrs if (stcb) { 1764163953Srrs gnv->gn_peers_tag = stcb->asoc.peer_vtag; 1765163953Srrs gnv->gn_local_tag = stcb->asoc.my_vtag; 1766163953Srrs SCTP_TCB_UNLOCK(stcb); 1767166675Srrs } else { 1768171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 1769166675Srrs error = ENOTCONN; 1770163953Srrs } 1771166675Srrs *optsize = sizeof(*gnv); 1772163953Srrs } 1773163953Srrs break; 1774170056Srrs case SCTP_DELAYED_SACK: 1775163953Srrs { 1776170056Srrs struct sctp_sack_info *sack; 1777163953Srrs 1778170056Srrs SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, *optsize); 1779170056Srrs SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); 1780166675Srrs if (stcb) { 1781170056Srrs sack->sack_delay = stcb->asoc.delayed_ack; 1782170056Srrs sack->sack_freq = stcb->asoc.sack_freq; 1783166675Srrs SCTP_TCB_UNLOCK(stcb); 1784166675Srrs } else { 1785163953Srrs SCTP_INP_RLOCK(inp); 1786170056Srrs sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); 1787170056Srrs sack->sack_freq = inp->sctp_ep.sctp_sack_freq; 1788163953Srrs SCTP_INP_RUNLOCK(inp); 1789163953Srrs } 1790170056Srrs *optsize = sizeof(*sack); 1791163953Srrs } 1792163953Srrs break; 1793163953Srrs 1794163953Srrs case SCTP_GET_SNDBUF_USE: 1795166675Srrs { 1796163953Srrs struct sctp_sockstat *ss; 1797163953Srrs 1798166675Srrs SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize); 1799166675Srrs SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id); 1800166675Srrs 1801166675Srrs if (stcb) { 1802166675Srrs ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size; 1803166675Srrs ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue + 1804166675Srrs stcb->asoc.size_on_all_streams); 1805166675Srrs SCTP_TCB_UNLOCK(stcb); 1806166675Srrs } else { 1807171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 1808163953Srrs error = ENOTCONN; 1809163953Srrs } 1810166675Srrs *optsize = sizeof(struct sctp_sockstat); 1811163953Srrs } 1812163953Srrs break; 1813170056Srrs case SCTP_MAX_BURST: 1814163953Srrs { 1815166675Srrs uint8_t *value; 1816163953Srrs 1817166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint8_t, *optsize); 1818166675Srrs 1819163953Srrs SCTP_INP_RLOCK(inp); 1820166675Srrs *value = inp->sctp_ep.max_burst; 1821163953Srrs SCTP_INP_RUNLOCK(inp); 1822166675Srrs *optsize = sizeof(uint8_t); 1823163953Srrs } 1824163953Srrs break; 1825163953Srrs case SCTP_MAXSEG: 1826163953Srrs { 1827167598Srrs struct sctp_assoc_value *av; 1828163953Srrs int ovh; 1829163953Srrs 1830167598Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1831170056Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1832163953Srrs 1833167598Srrs if (stcb) { 1834167598Srrs av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc); 1835167598Srrs SCTP_TCB_UNLOCK(stcb); 1836163953Srrs } else { 1837167598Srrs SCTP_INP_RLOCK(inp); 1838167598Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 1839167598Srrs ovh = SCTP_MED_OVERHEAD; 1840167598Srrs } else { 1841167598Srrs ovh = SCTP_MED_V4_OVERHEAD; 1842167598Srrs } 1843170056Srrs if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT) 1844170056Srrs av->assoc_value = 0; 1845170056Srrs else 1846170056Srrs av->assoc_value = inp->sctp_frag_point - ovh; 1847167598Srrs SCTP_INP_RUNLOCK(inp); 1848163953Srrs } 1849167598Srrs *optsize = sizeof(struct sctp_assoc_value); 1850163953Srrs } 1851163953Srrs break; 1852163953Srrs case SCTP_GET_STAT_LOG: 1853167598Srrs error = sctp_fill_stat_log(optval, optsize); 1854163953Srrs break; 1855163953Srrs case SCTP_EVENTS: 1856163953Srrs { 1857163953Srrs struct sctp_event_subscribe *events; 1858163953Srrs 1859166675Srrs SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize); 1860163953Srrs memset(events, 0, sizeof(*events)); 1861163953Srrs SCTP_INP_RLOCK(inp); 1862163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) 1863163953Srrs events->sctp_data_io_event = 1; 1864163953Srrs 1865163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT)) 1866163953Srrs events->sctp_association_event = 1; 1867163953Srrs 1868163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT)) 1869163953Srrs events->sctp_address_event = 1; 1870163953Srrs 1871163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) 1872163953Srrs events->sctp_send_failure_event = 1; 1873163953Srrs 1874163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR)) 1875163953Srrs events->sctp_peer_error_event = 1; 1876163953Srrs 1877163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) 1878163953Srrs events->sctp_shutdown_event = 1; 1879163953Srrs 1880163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT)) 1881163953Srrs events->sctp_partial_delivery_event = 1; 1882163953Srrs 1883163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) 1884163953Srrs events->sctp_adaptation_layer_event = 1; 1885163953Srrs 1886163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT)) 1887163953Srrs events->sctp_authentication_event = 1; 1888163953Srrs 1889163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) 1890163953Srrs events->sctp_stream_reset_events = 1; 1891163953Srrs SCTP_INP_RUNLOCK(inp); 1892166675Srrs *optsize = sizeof(struct sctp_event_subscribe); 1893163953Srrs } 1894163953Srrs break; 1895163953Srrs 1896163953Srrs case SCTP_ADAPTATION_LAYER: 1897166675Srrs { 1898166675Srrs uint32_t *value; 1899166675Srrs 1900166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1901166675Srrs 1902166675Srrs SCTP_INP_RLOCK(inp); 1903166675Srrs *value = inp->sctp_ep.adaptation_layer_indicator; 1904166675Srrs SCTP_INP_RUNLOCK(inp); 1905166675Srrs *optsize = sizeof(uint32_t); 1906163953Srrs } 1907163953Srrs break; 1908163953Srrs case SCTP_SET_INITIAL_DBG_SEQ: 1909166675Srrs { 1910166675Srrs uint32_t *value; 1911166675Srrs 1912166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1913166675Srrs SCTP_INP_RLOCK(inp); 1914166675Srrs *value = inp->sctp_ep.initial_sequence_debug; 1915166675Srrs SCTP_INP_RUNLOCK(inp); 1916166675Srrs *optsize = sizeof(uint32_t); 1917163953Srrs } 1918163953Srrs break; 1919163953Srrs case SCTP_GET_LOCAL_ADDR_SIZE: 1920166675Srrs { 1921166675Srrs uint32_t *value; 1922166675Srrs 1923166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1924166675Srrs SCTP_INP_RLOCK(inp); 1925168124Srrs *value = sctp_count_max_addresses(inp); 1926166675Srrs SCTP_INP_RUNLOCK(inp); 1927166675Srrs *optsize = sizeof(uint32_t); 1928163953Srrs } 1929163953Srrs break; 1930163953Srrs case SCTP_GET_REMOTE_ADDR_SIZE: 1931163953Srrs { 1932166675Srrs uint32_t *value; 1933166675Srrs size_t size; 1934163953Srrs struct sctp_nets *net; 1935163953Srrs 1936166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1937166675Srrs /* FIXME MT: change to sctp_assoc_value? */ 1938166675Srrs SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value); 1939166675Srrs 1940166675Srrs if (stcb) { 1941166675Srrs size = 0; 1942166675Srrs /* Count the sizes */ 1943166675Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1944166675Srrs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) || 1945166675Srrs (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET6)) { 1946166675Srrs size += sizeof(struct sockaddr_in6); 1947166675Srrs } else if (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET) { 1948166675Srrs size += sizeof(struct sockaddr_in); 1949166675Srrs } else { 1950166675Srrs /* huh */ 1951166675Srrs break; 1952166675Srrs } 1953163953Srrs } 1954166675Srrs SCTP_TCB_UNLOCK(stcb); 1955166675Srrs *value = (uint32_t) size; 1956166675Srrs } else { 1957171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 1958166675Srrs error = ENOTCONN; 1959163953Srrs } 1960166675Srrs *optsize = sizeof(uint32_t); 1961163953Srrs } 1962163953Srrs break; 1963163953Srrs case SCTP_GET_PEER_ADDRESSES: 1964163953Srrs /* 1965163953Srrs * Get the address information, an array is passed in to 1966163953Srrs * fill up we pack it. 1967163953Srrs */ 1968163953Srrs { 1969166675Srrs size_t cpsz, left; 1970163953Srrs struct sockaddr_storage *sas; 1971163953Srrs struct sctp_nets *net; 1972163953Srrs struct sctp_getaddresses *saddr; 1973163953Srrs 1974166675Srrs SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); 1975166675Srrs SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); 1976163953Srrs 1977166675Srrs if (stcb) { 1978166675Srrs left = (*optsize) - sizeof(struct sctp_getaddresses); 1979166675Srrs *optsize = sizeof(struct sctp_getaddresses); 1980166675Srrs sas = (struct sockaddr_storage *)&saddr->addr[0]; 1981166675Srrs 1982166675Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1983166675Srrs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) || 1984166675Srrs (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET6)) { 1985166675Srrs cpsz = sizeof(struct sockaddr_in6); 1986166675Srrs } else if (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET) { 1987166675Srrs cpsz = sizeof(struct sockaddr_in); 1988166675Srrs } else { 1989166675Srrs /* huh */ 1990166675Srrs break; 1991166675Srrs } 1992166675Srrs if (left < cpsz) { 1993166675Srrs /* not enough room. */ 1994166675Srrs break; 1995166675Srrs } 1996166675Srrs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) && 1997166675Srrs (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET)) { 1998166675Srrs /* Must map the address */ 1999166675Srrs in6_sin_2_v4mapsin6((struct sockaddr_in *)&net->ro._l_addr, 2000166675Srrs (struct sockaddr_in6 *)sas); 2001166675Srrs } else { 2002166675Srrs memcpy(sas, &net->ro._l_addr, cpsz); 2003166675Srrs } 2004166675Srrs ((struct sockaddr_in *)sas)->sin_port = stcb->rport; 2005166675Srrs 2006166675Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz); 2007166675Srrs left -= cpsz; 2008166675Srrs *optsize += cpsz; 2009163953Srrs } 2010166675Srrs SCTP_TCB_UNLOCK(stcb); 2011166675Srrs } else { 2012171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 2013166675Srrs error = ENOENT; 2014163953Srrs } 2015163953Srrs } 2016163953Srrs break; 2017163953Srrs case SCTP_GET_LOCAL_ADDRESSES: 2018163953Srrs { 2019166675Srrs size_t limit, actual; 2020163953Srrs struct sockaddr_storage *sas; 2021163953Srrs struct sctp_getaddresses *saddr; 2022163953Srrs 2023166675Srrs SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); 2024166675Srrs SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); 2025163953Srrs 2026163953Srrs sas = (struct sockaddr_storage *)&saddr->addr[0]; 2027166675Srrs limit = *optsize - sizeof(sctp_assoc_t); 2028168124Srrs actual = sctp_fill_up_addresses(inp, stcb, limit, sas); 2029169655Srrs if (stcb) { 2030163953Srrs SCTP_TCB_UNLOCK(stcb); 2031169655Srrs } 2032166675Srrs *optsize = sizeof(struct sockaddr_storage) + actual; 2033163953Srrs } 2034163953Srrs break; 2035163953Srrs case SCTP_PEER_ADDR_PARAMS: 2036163953Srrs { 2037163953Srrs struct sctp_paddrparams *paddrp; 2038163953Srrs struct sctp_nets *net; 2039163953Srrs 2040166675Srrs SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize); 2041166675Srrs SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); 2042163953Srrs 2043163953Srrs net = NULL; 2044166675Srrs if (stcb) { 2045166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address); 2046166675Srrs } else { 2047166675Srrs /* 2048166675Srrs * We increment here since 2049166675Srrs * sctp_findassociation_ep_addr() wil do a 2050166675Srrs * decrement if it finds the stcb as long as 2051166675Srrs * the locked tcb (last argument) is NOT a 2052166675Srrs * TCB.. aka NULL. 2053166675Srrs */ 2054166675Srrs SCTP_INP_INCR_REF(inp); 2055166675Srrs stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddrp->spp_address, &net, NULL, NULL); 2056163953Srrs if (stcb == NULL) { 2057166675Srrs SCTP_INP_DECR_REF(inp); 2058163953Srrs } 2059163953Srrs } 2060171943Srrs if (stcb && (net == NULL)) { 2061171943Srrs struct sockaddr *sa; 2062163953Srrs 2063171943Srrs sa = (struct sockaddr *)&paddrp->spp_address; 2064171943Srrs if (sa->sa_family == AF_INET) { 2065171943Srrs struct sockaddr_in *sin; 2066171943Srrs 2067171943Srrs sin = (struct sockaddr_in *)sa; 2068171943Srrs if (sin->sin_addr.s_addr) { 2069171943Srrs error = EINVAL; 2070171943Srrs SCTP_TCB_UNLOCK(stcb); 2071171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2072171943Srrs break; 2073171943Srrs } 2074171943Srrs } else if (sa->sa_family == AF_INET6) { 2075171943Srrs struct sockaddr_in6 *sin6; 2076171943Srrs 2077171943Srrs sin6 = (struct sockaddr_in6 *)sa; 2078171943Srrs if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 2079171943Srrs error = EINVAL; 2080171943Srrs SCTP_TCB_UNLOCK(stcb); 2081171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2082171943Srrs break; 2083171943Srrs } 2084171943Srrs } else { 2085171943Srrs error = EAFNOSUPPORT; 2086171943Srrs SCTP_TCB_UNLOCK(stcb); 2087171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2088171943Srrs break; 2089171943Srrs } 2090171943Srrs } 2091163953Srrs if (stcb) { 2092163953Srrs /* Applys to the specific association */ 2093163953Srrs paddrp->spp_flags = 0; 2094163953Srrs if (net) { 2095170056Srrs int ovh; 2096170056Srrs 2097170056Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2098170056Srrs ovh = SCTP_MED_OVERHEAD; 2099170056Srrs } else { 2100170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 2101170056Srrs } 2102170056Srrs 2103170056Srrs 2104163953Srrs paddrp->spp_pathmaxrxt = net->failure_threshold; 2105170056Srrs paddrp->spp_pathmtu = net->mtu - ovh; 2106163953Srrs /* get flags for HB */ 2107163953Srrs if (net->dest_state & SCTP_ADDR_NOHB) 2108163953Srrs paddrp->spp_flags |= SPP_HB_DISABLE; 2109163953Srrs else 2110163953Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 2111163953Srrs /* get flags for PMTU */ 2112165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 2113163953Srrs paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2114163953Srrs } else { 2115163953Srrs paddrp->spp_flags |= SPP_PMTUD_DISABLE; 2116163953Srrs } 2117167598Srrs#ifdef INET 2118163953Srrs if (net->ro._l_addr.sin.sin_family == AF_INET) { 2119163953Srrs paddrp->spp_ipv4_tos = net->tos_flowlabel & 0x000000fc; 2120163953Srrs paddrp->spp_flags |= SPP_IPV4_TOS; 2121163953Srrs } 2122163953Srrs#endif 2123167598Srrs#ifdef INET6 2124163953Srrs if (net->ro._l_addr.sin6.sin6_family == AF_INET6) { 2125163953Srrs paddrp->spp_ipv6_flowlabel = net->tos_flowlabel; 2126163953Srrs paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2127163953Srrs } 2128163953Srrs#endif 2129163953Srrs } else { 2130163953Srrs /* 2131163953Srrs * No destination so return default 2132163953Srrs * value 2133163953Srrs */ 2134170056Srrs int cnt = 0; 2135170056Srrs 2136163953Srrs paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure; 2137163953Srrs paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc); 2138167598Srrs#ifdef INET 2139163953Srrs paddrp->spp_ipv4_tos = stcb->asoc.default_tos & 0x000000fc; 2140163953Srrs paddrp->spp_flags |= SPP_IPV4_TOS; 2141163953Srrs#endif 2142167598Srrs#ifdef INET6 2143163953Srrs paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel; 2144163953Srrs paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2145163953Srrs#endif 2146163953Srrs /* default settings should be these */ 2147170056Srrs if (stcb->asoc.hb_is_disabled == 0) { 2148163953Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 2149170056Srrs } else { 2150170056Srrs paddrp->spp_flags |= SPP_HB_DISABLE; 2151163953Srrs } 2152170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 2153170056Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 2154170056Srrs cnt++; 2155170056Srrs } 2156170056Srrs } 2157170056Srrs if (cnt) { 2158170056Srrs paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2159170056Srrs } 2160163953Srrs } 2161163953Srrs paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay; 2162163953Srrs paddrp->spp_assoc_id = sctp_get_associd(stcb); 2163163953Srrs SCTP_TCB_UNLOCK(stcb); 2164163953Srrs } else { 2165163953Srrs /* Use endpoint defaults */ 2166163953Srrs SCTP_INP_RLOCK(inp); 2167163953Srrs paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure; 2168163953Srrs paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); 2169163953Srrs paddrp->spp_assoc_id = (sctp_assoc_t) 0; 2170163953Srrs /* get inp's default */ 2171167598Srrs#ifdef INET 2172163953Srrs paddrp->spp_ipv4_tos = inp->ip_inp.inp.inp_ip_tos; 2173163953Srrs paddrp->spp_flags |= SPP_IPV4_TOS; 2174163953Srrs#endif 2175167598Srrs#ifdef INET6 2176163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2177163953Srrs paddrp->spp_ipv6_flowlabel = ((struct in6pcb *)inp)->in6p_flowinfo; 2178163953Srrs paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2179163953Srrs } 2180163953Srrs#endif 2181163953Srrs /* can't return this */ 2182163953Srrs paddrp->spp_pathmtu = 0; 2183170056Srrs 2184163953Srrs /* default behavior, no stcb */ 2185170056Srrs paddrp->spp_flags = SPP_PMTUD_ENABLE; 2186163953Srrs 2187170056Srrs if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { 2188170056Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 2189170056Srrs } else { 2190170056Srrs paddrp->spp_flags |= SPP_HB_DISABLE; 2191170056Srrs } 2192163953Srrs SCTP_INP_RUNLOCK(inp); 2193163953Srrs } 2194166675Srrs *optsize = sizeof(struct sctp_paddrparams); 2195163953Srrs } 2196163953Srrs break; 2197163953Srrs case SCTP_GET_PEER_ADDR_INFO: 2198163953Srrs { 2199163953Srrs struct sctp_paddrinfo *paddri; 2200163953Srrs struct sctp_nets *net; 2201163953Srrs 2202166675Srrs SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize); 2203166675Srrs SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id); 2204166675Srrs 2205163953Srrs net = NULL; 2206166675Srrs if (stcb) { 2207166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddri->spinfo_address); 2208166675Srrs } else { 2209166675Srrs /* 2210166675Srrs * We increment here since 2211166675Srrs * sctp_findassociation_ep_addr() wil do a 2212166675Srrs * decrement if it finds the stcb as long as 2213166675Srrs * the locked tcb (last argument) is NOT a 2214166675Srrs * TCB.. aka NULL. 2215166675Srrs */ 2216166675Srrs SCTP_INP_INCR_REF(inp); 2217166675Srrs stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddri->spinfo_address, &net, NULL, NULL); 2218166675Srrs if (stcb == NULL) { 2219166675Srrs SCTP_INP_DECR_REF(inp); 2220163953Srrs } 2221166675Srrs } 2222163953Srrs 2223166675Srrs if ((stcb) && (net)) { 2224166675Srrs paddri->spinfo_state = net->dest_state & (SCTP_REACHABLE_MASK | SCTP_ADDR_NOHB); 2225166675Srrs paddri->spinfo_cwnd = net->cwnd; 2226166675Srrs paddri->spinfo_srtt = ((net->lastsa >> 2) + net->lastsv) >> 1; 2227166675Srrs paddri->spinfo_rto = net->RTO; 2228166675Srrs paddri->spinfo_assoc_id = sctp_get_associd(stcb); 2229166675Srrs SCTP_TCB_UNLOCK(stcb); 2230163953Srrs } else { 2231163953Srrs if (stcb) { 2232163953Srrs SCTP_TCB_UNLOCK(stcb); 2233163953Srrs } 2234171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 2235163953Srrs error = ENOENT; 2236163953Srrs } 2237166675Srrs *optsize = sizeof(struct sctp_paddrinfo); 2238163953Srrs } 2239163953Srrs break; 2240163953Srrs case SCTP_PCB_STATUS: 2241163953Srrs { 2242163953Srrs struct sctp_pcbinfo *spcb; 2243163953Srrs 2244166675Srrs SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize); 2245163953Srrs sctp_fill_pcbinfo(spcb); 2246166675Srrs *optsize = sizeof(struct sctp_pcbinfo); 2247163953Srrs } 2248163953Srrs break; 2249167598Srrs 2250163953Srrs case SCTP_STATUS: 2251163953Srrs { 2252163953Srrs struct sctp_nets *net; 2253163953Srrs struct sctp_status *sstat; 2254163953Srrs 2255166675Srrs SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize); 2256166675Srrs SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id); 2257163953Srrs 2258163953Srrs if (stcb == NULL) { 2259171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2260163953Srrs error = EINVAL; 2261163953Srrs break; 2262163953Srrs } 2263163953Srrs /* 2264163953Srrs * I think passing the state is fine since 2265163953Srrs * sctp_constants.h will be available to the user 2266163953Srrs * land. 2267163953Srrs */ 2268163953Srrs sstat->sstat_state = stcb->asoc.state; 2269173179Srrs sstat->sstat_assoc_id = sctp_get_associd(stcb); 2270163953Srrs sstat->sstat_rwnd = stcb->asoc.peers_rwnd; 2271163953Srrs sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt; 2272163953Srrs /* 2273163953Srrs * We can't include chunks that have been passed to 2274163953Srrs * the socket layer. Only things in queue. 2275163953Srrs */ 2276163953Srrs sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue + 2277163953Srrs stcb->asoc.cnt_on_all_streams); 2278163953Srrs 2279163953Srrs 2280163953Srrs sstat->sstat_instrms = stcb->asoc.streamincnt; 2281163953Srrs sstat->sstat_outstrms = stcb->asoc.streamoutcnt; 2282163953Srrs sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc); 2283163953Srrs memcpy(&sstat->sstat_primary.spinfo_address, 2284163953Srrs &stcb->asoc.primary_destination->ro._l_addr, 2285163953Srrs ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len); 2286163953Srrs net = stcb->asoc.primary_destination; 2287163953Srrs ((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport; 2288163953Srrs /* 2289163953Srrs * Again the user can get info from sctp_constants.h 2290163953Srrs * for what the state of the network is. 2291163953Srrs */ 2292163953Srrs sstat->sstat_primary.spinfo_state = net->dest_state & SCTP_REACHABLE_MASK; 2293163953Srrs sstat->sstat_primary.spinfo_cwnd = net->cwnd; 2294163953Srrs sstat->sstat_primary.spinfo_srtt = net->lastsa; 2295163953Srrs sstat->sstat_primary.spinfo_rto = net->RTO; 2296163953Srrs sstat->sstat_primary.spinfo_mtu = net->mtu; 2297163953Srrs sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb); 2298163953Srrs SCTP_TCB_UNLOCK(stcb); 2299166675Srrs *optsize = sizeof(*sstat); 2300163953Srrs } 2301163953Srrs break; 2302163953Srrs case SCTP_RTOINFO: 2303163953Srrs { 2304163953Srrs struct sctp_rtoinfo *srto; 2305163953Srrs 2306166675Srrs SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize); 2307166675Srrs SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); 2308166675Srrs 2309166675Srrs if (stcb) { 2310166675Srrs srto->srto_initial = stcb->asoc.initial_rto; 2311166675Srrs srto->srto_max = stcb->asoc.maxrto; 2312166675Srrs srto->srto_min = stcb->asoc.minrto; 2313166675Srrs SCTP_TCB_UNLOCK(stcb); 2314166675Srrs } else { 2315163953Srrs SCTP_INP_RLOCK(inp); 2316163953Srrs srto->srto_initial = inp->sctp_ep.initial_rto; 2317163953Srrs srto->srto_max = inp->sctp_ep.sctp_maxrto; 2318163953Srrs srto->srto_min = inp->sctp_ep.sctp_minrto; 2319163953Srrs SCTP_INP_RUNLOCK(inp); 2320163953Srrs } 2321166675Srrs *optsize = sizeof(*srto); 2322163953Srrs } 2323163953Srrs break; 2324163953Srrs case SCTP_ASSOCINFO: 2325163953Srrs { 2326163953Srrs struct sctp_assocparams *sasoc; 2327171477Srrs uint32_t oldval; 2328163953Srrs 2329166675Srrs SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize); 2330166675Srrs SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); 2331163953Srrs 2332163953Srrs if (stcb) { 2333171477Srrs oldval = sasoc->sasoc_cookie_life; 2334171477Srrs sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life); 2335163953Srrs sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times; 2336163953Srrs sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets; 2337163953Srrs sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd; 2338163953Srrs sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd; 2339163953Srrs SCTP_TCB_UNLOCK(stcb); 2340163953Srrs } else { 2341163953Srrs SCTP_INP_RLOCK(inp); 2342171477Srrs sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life); 2343163953Srrs sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times; 2344163953Srrs sasoc->sasoc_number_peer_destinations = 0; 2345163953Srrs sasoc->sasoc_peer_rwnd = 0; 2346163953Srrs sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv); 2347163953Srrs SCTP_INP_RUNLOCK(inp); 2348163953Srrs } 2349166675Srrs *optsize = sizeof(*sasoc); 2350163953Srrs } 2351163953Srrs break; 2352163953Srrs case SCTP_DEFAULT_SEND_PARAM: 2353163953Srrs { 2354163953Srrs struct sctp_sndrcvinfo *s_info; 2355163953Srrs 2356166675Srrs SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize); 2357166675Srrs SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); 2358166675Srrs 2359166675Srrs if (stcb) { 2360170056Srrs memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send)); 2361166675Srrs SCTP_TCB_UNLOCK(stcb); 2362166675Srrs } else { 2363163953Srrs SCTP_INP_RLOCK(inp); 2364170056Srrs memcpy(s_info, &inp->def_send, sizeof(inp->def_send)); 2365163953Srrs SCTP_INP_RUNLOCK(inp); 2366163953Srrs } 2367166675Srrs *optsize = sizeof(*s_info); 2368163953Srrs } 2369163953Srrs break; 2370163953Srrs case SCTP_INITMSG: 2371163953Srrs { 2372163953Srrs struct sctp_initmsg *sinit; 2373163953Srrs 2374166675Srrs SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize); 2375163953Srrs SCTP_INP_RLOCK(inp); 2376163953Srrs sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count; 2377163953Srrs sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome; 2378163953Srrs sinit->sinit_max_attempts = inp->sctp_ep.max_init_times; 2379163953Srrs sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max; 2380163953Srrs SCTP_INP_RUNLOCK(inp); 2381166675Srrs *optsize = sizeof(*sinit); 2382163953Srrs } 2383163953Srrs break; 2384163953Srrs case SCTP_PRIMARY_ADDR: 2385163953Srrs /* we allow a "get" operation on this */ 2386163953Srrs { 2387163953Srrs struct sctp_setprim *ssp; 2388163953Srrs 2389166675Srrs SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize); 2390166675Srrs SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id); 2391166675Srrs 2392166675Srrs if (stcb) { 2393166675Srrs /* simply copy out the sockaddr_storage... */ 2394170056Srrs int len; 2395170056Srrs 2396170056Srrs len = *optsize; 2397170056Srrs if (len > stcb->asoc.primary_destination->ro._l_addr.sa.sa_len) 2398170056Srrs len = stcb->asoc.primary_destination->ro._l_addr.sa.sa_len; 2399170056Srrs 2400170056Srrs memcpy(&ssp->ssp_addr, 2401170056Srrs &stcb->asoc.primary_destination->ro._l_addr, 2402170056Srrs len); 2403166675Srrs SCTP_TCB_UNLOCK(stcb); 2404166675Srrs } else { 2405171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2406163953Srrs error = EINVAL; 2407163953Srrs } 2408166675Srrs *optsize = sizeof(*ssp); 2409163953Srrs } 2410163953Srrs break; 2411163953Srrs 2412163953Srrs case SCTP_HMAC_IDENT: 2413163953Srrs { 2414163953Srrs struct sctp_hmacalgo *shmac; 2415163953Srrs sctp_hmaclist_t *hmaclist; 2416163953Srrs uint32_t size; 2417163953Srrs int i; 2418163953Srrs 2419166675Srrs SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize); 2420166675Srrs 2421163953Srrs SCTP_INP_RLOCK(inp); 2422163953Srrs hmaclist = inp->sctp_ep.local_hmacs; 2423163953Srrs if (hmaclist == NULL) { 2424163953Srrs /* no HMACs to return */ 2425166675Srrs *optsize = sizeof(*shmac); 2426168299Srrs SCTP_INP_RUNLOCK(inp); 2427163953Srrs break; 2428163953Srrs } 2429163953Srrs /* is there room for all of the hmac ids? */ 2430163953Srrs size = sizeof(*shmac) + (hmaclist->num_algo * 2431163953Srrs sizeof(shmac->shmac_idents[0])); 2432166675Srrs if ((size_t)(*optsize) < size) { 2433171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2434163953Srrs error = EINVAL; 2435163953Srrs SCTP_INP_RUNLOCK(inp); 2436163953Srrs break; 2437163953Srrs } 2438163953Srrs /* copy in the list */ 2439163953Srrs for (i = 0; i < hmaclist->num_algo; i++) 2440163953Srrs shmac->shmac_idents[i] = hmaclist->hmac[i]; 2441163953Srrs SCTP_INP_RUNLOCK(inp); 2442166675Srrs *optsize = size; 2443163953Srrs break; 2444163953Srrs } 2445163953Srrs case SCTP_AUTH_ACTIVE_KEY: 2446163953Srrs { 2447163953Srrs struct sctp_authkeyid *scact; 2448163953Srrs 2449166675Srrs SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize); 2450166675Srrs SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); 2451166675Srrs 2452166675Srrs if (stcb) { 2453163953Srrs /* get the active key on the assoc */ 2454163953Srrs scact->scact_keynumber = stcb->asoc.authinfo.assoc_keyid; 2455163953Srrs SCTP_TCB_UNLOCK(stcb); 2456163953Srrs } else { 2457163953Srrs /* get the endpoint active key */ 2458163953Srrs SCTP_INP_RLOCK(inp); 2459163953Srrs scact->scact_keynumber = inp->sctp_ep.default_keyid; 2460163953Srrs SCTP_INP_RUNLOCK(inp); 2461163953Srrs } 2462166675Srrs *optsize = sizeof(*scact); 2463163953Srrs break; 2464163953Srrs } 2465163953Srrs case SCTP_LOCAL_AUTH_CHUNKS: 2466163953Srrs { 2467163953Srrs struct sctp_authchunks *sac; 2468163953Srrs sctp_auth_chklist_t *chklist = NULL; 2469166675Srrs size_t size = 0; 2470163953Srrs 2471166675Srrs SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); 2472166675Srrs SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); 2473166675Srrs 2474166675Srrs if (stcb) { 2475163953Srrs /* get off the assoc */ 2476163953Srrs chklist = stcb->asoc.local_auth_chunks; 2477163953Srrs /* is there enough space? */ 2478163953Srrs size = sctp_auth_get_chklist_size(chklist); 2479166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2480163953Srrs error = EINVAL; 2481171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2482166675Srrs } else { 2483166675Srrs /* copy in the chunks */ 2484169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2485163953Srrs } 2486163953Srrs SCTP_TCB_UNLOCK(stcb); 2487163953Srrs } else { 2488163953Srrs /* get off the endpoint */ 2489163953Srrs SCTP_INP_RLOCK(inp); 2490163953Srrs chklist = inp->sctp_ep.local_auth_chunks; 2491163953Srrs /* is there enough space? */ 2492163953Srrs size = sctp_auth_get_chklist_size(chklist); 2493166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2494163953Srrs error = EINVAL; 2495171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2496166675Srrs } else { 2497166675Srrs /* copy in the chunks */ 2498169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2499163953Srrs } 2500163953Srrs SCTP_INP_RUNLOCK(inp); 2501163953Srrs } 2502166675Srrs *optsize = sizeof(struct sctp_authchunks) + size; 2503163953Srrs break; 2504163953Srrs } 2505163953Srrs case SCTP_PEER_AUTH_CHUNKS: 2506163953Srrs { 2507163953Srrs struct sctp_authchunks *sac; 2508163953Srrs sctp_auth_chklist_t *chklist = NULL; 2509166675Srrs size_t size = 0; 2510163953Srrs 2511166675Srrs SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); 2512166675Srrs SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); 2513166675Srrs 2514166675Srrs if (stcb) { 2515166675Srrs /* get off the assoc */ 2516166675Srrs chklist = stcb->asoc.peer_auth_chunks; 2517166675Srrs /* is there enough space? */ 2518166675Srrs size = sctp_auth_get_chklist_size(chklist); 2519166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2520166675Srrs error = EINVAL; 2521171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2522166675Srrs } else { 2523166675Srrs /* copy in the chunks */ 2524169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2525166675Srrs } 2526166675Srrs SCTP_TCB_UNLOCK(stcb); 2527166675Srrs } else { 2528171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 2529163953Srrs error = ENOENT; 2530163953Srrs } 2531166675Srrs *optsize = sizeof(struct sctp_authchunks) + size; 2532163953Srrs break; 2533163953Srrs } 2534163953Srrs 2535163953Srrs 2536163953Srrs default: 2537171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 2538163953Srrs error = ENOPROTOOPT; 2539166675Srrs *optsize = 0; 2540163953Srrs break; 2541163953Srrs } /* end switch (sopt->sopt_name) */ 2542163953Srrs return (error); 2543163953Srrs} 2544163953Srrs 2545163953Srrsstatic int 2546166675Srrssctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, 2547166675Srrs void *p) 2548163953Srrs{ 2549166675Srrs int error, set_opt; 2550166675Srrs uint32_t *mopt; 2551163953Srrs struct sctp_tcb *stcb = NULL; 2552171943Srrs struct sctp_inpcb *inp = NULL; 2553167598Srrs uint32_t vrf_id; 2554163953Srrs 2555166675Srrs if (optval == NULL) { 2556169420Srrs SCTP_PRINTF("optval is NULL\n"); 2557171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2558163953Srrs return (EINVAL); 2559163953Srrs } 2560163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 2561167598Srrs if (inp == 0) { 2562169420Srrs SCTP_PRINTF("inp is NULL?\n"); 2563171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2564163953Srrs return EINVAL; 2565167598Srrs } 2566168299Srrs vrf_id = inp->def_vrf_id; 2567163953Srrs 2568163953Srrs error = 0; 2569166675Srrs switch (optname) { 2570163953Srrs case SCTP_NODELAY: 2571163953Srrs case SCTP_AUTOCLOSE: 2572163953Srrs case SCTP_AUTO_ASCONF: 2573163953Srrs case SCTP_EXPLICIT_EOR: 2574163953Srrs case SCTP_DISABLE_FRAGMENTS: 2575163953Srrs case SCTP_USE_EXT_RCVINFO: 2576163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 2577163953Srrs /* copy in the option value */ 2578166675Srrs SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); 2579163953Srrs set_opt = 0; 2580163953Srrs if (error) 2581163953Srrs break; 2582166675Srrs switch (optname) { 2583163953Srrs case SCTP_DISABLE_FRAGMENTS: 2584163953Srrs set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT; 2585163953Srrs break; 2586163953Srrs case SCTP_AUTO_ASCONF: 2587171943Srrs /* 2588171943Srrs * NOTE: we don't really support this flag 2589171943Srrs */ 2590171943Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 2591171943Srrs /* only valid for bound all sockets */ 2592171943Srrs set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF; 2593171943Srrs } else { 2594171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2595171943Srrs return (EINVAL); 2596171943Srrs } 2597163953Srrs break; 2598163953Srrs case SCTP_EXPLICIT_EOR: 2599163953Srrs set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR; 2600163953Srrs break; 2601163953Srrs case SCTP_USE_EXT_RCVINFO: 2602163953Srrs set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO; 2603163953Srrs break; 2604163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 2605163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2606163953Srrs set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4; 2607163953Srrs } else { 2608171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2609163953Srrs return (EINVAL); 2610163953Srrs } 2611163953Srrs break; 2612163953Srrs case SCTP_NODELAY: 2613163953Srrs set_opt = SCTP_PCB_FLAGS_NODELAY; 2614163953Srrs break; 2615163953Srrs case SCTP_AUTOCLOSE: 2616170056Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2617170056Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 2618171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2619170056Srrs return (EINVAL); 2620170056Srrs } 2621163953Srrs set_opt = SCTP_PCB_FLAGS_AUTOCLOSE; 2622163953Srrs /* 2623163953Srrs * The value is in ticks. Note this does not effect 2624163953Srrs * old associations, only new ones. 2625163953Srrs */ 2626163953Srrs inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt); 2627163953Srrs break; 2628163953Srrs } 2629163953Srrs SCTP_INP_WLOCK(inp); 2630163953Srrs if (*mopt != 0) { 2631163953Srrs sctp_feature_on(inp, set_opt); 2632163953Srrs } else { 2633163953Srrs sctp_feature_off(inp, set_opt); 2634163953Srrs } 2635163953Srrs SCTP_INP_WUNLOCK(inp); 2636163953Srrs break; 2637163953Srrs case SCTP_PARTIAL_DELIVERY_POINT: 2638163953Srrs { 2639166675Srrs uint32_t *value; 2640166675Srrs 2641166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); 2642167736Srrs if (*value > SCTP_SB_LIMIT_RCV(so)) { 2643171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2644167736Srrs error = EINVAL; 2645167736Srrs break; 2646167736Srrs } 2647166675Srrs inp->partial_delivery_point = *value; 2648163953Srrs } 2649163953Srrs break; 2650163953Srrs case SCTP_FRAGMENT_INTERLEAVE: 2651163953Srrs /* not yet until we re-write sctp_recvmsg() */ 2652163953Srrs { 2653168943Srrs uint32_t *level; 2654163953Srrs 2655168943Srrs SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize); 2656168943Srrs if (*level == SCTP_FRAG_LEVEL_2) { 2657163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 2658168943Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 2659168943Srrs } else if (*level == SCTP_FRAG_LEVEL_1) { 2660168943Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 2661168943Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 2662168943Srrs } else if (*level == SCTP_FRAG_LEVEL_0) { 2663170056Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 2664168943Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 2665168943Srrs 2666163953Srrs } else { 2667171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2668168943Srrs error = EINVAL; 2669163953Srrs } 2670163953Srrs } 2671163953Srrs break; 2672163953Srrs case SCTP_CMT_ON_OFF: 2673163953Srrs { 2674163953Srrs struct sctp_assoc_value *av; 2675163953Srrs 2676166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 2677166675Srrs if (sctp_cmt_on_off) { 2678166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2679166675Srrs if (stcb) { 2680163953Srrs stcb->asoc.sctp_cmt_on_off = (uint8_t) av->assoc_value; 2681166675Srrs SCTP_TCB_UNLOCK(stcb); 2682163953Srrs } else { 2683171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 2684166675Srrs error = ENOTCONN; 2685163953Srrs } 2686166675Srrs } else { 2687171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 2688166675Srrs error = ENOPROTOOPT; 2689163953Srrs } 2690163953Srrs } 2691163953Srrs break; 2692171440Srrs /* JRS - Set socket option for pluggable congestion control */ 2693171440Srrs case SCTP_PLUGGABLE_CC: 2694171440Srrs { 2695171440Srrs struct sctp_assoc_value *av; 2696171440Srrs 2697171440Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 2698171440Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2699171440Srrs if (stcb) { 2700171440Srrs switch (av->assoc_value) { 2701171440Srrs /* 2702171440Srrs * JRS - Standard TCP congestion 2703171440Srrs * control 2704171440Srrs */ 2705171440Srrs case SCTP_CC_RFC2581: 2706171440Srrs { 2707171440Srrs stcb->asoc.congestion_control_module = SCTP_CC_RFC2581; 2708171440Srrs stcb->asoc.cc_functions.sctp_set_initial_cc_param = &sctp_set_initial_cc_param; 2709171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_sack = &sctp_cwnd_update_after_sack; 2710171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_fr = &sctp_cwnd_update_after_fr; 2711171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_timeout = &sctp_cwnd_update_after_timeout; 2712171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_ecn_echo = &sctp_cwnd_update_after_ecn_echo; 2713171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_packet_dropped = &sctp_cwnd_update_after_packet_dropped; 2714171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_output = &sctp_cwnd_update_after_output; 2715171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_fr_timer = &sctp_cwnd_update_after_fr_timer; 2716171440Srrs SCTP_TCB_UNLOCK(stcb); 2717171440Srrs break; 2718171440Srrs } 2719171440Srrs /* 2720171440Srrs * JRS - High Speed TCP congestion 2721171440Srrs * control (Floyd) 2722171440Srrs */ 2723171440Srrs case SCTP_CC_HSTCP: 2724171440Srrs { 2725171440Srrs stcb->asoc.congestion_control_module = SCTP_CC_HSTCP; 2726171440Srrs stcb->asoc.cc_functions.sctp_set_initial_cc_param = &sctp_set_initial_cc_param; 2727171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_sack = &sctp_hs_cwnd_update_after_sack; 2728171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_fr = &sctp_hs_cwnd_update_after_fr; 2729171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_timeout = &sctp_cwnd_update_after_timeout; 2730171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_ecn_echo = &sctp_cwnd_update_after_ecn_echo; 2731171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_packet_dropped = &sctp_cwnd_update_after_packet_dropped; 2732171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_output = &sctp_cwnd_update_after_output; 2733171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_fr_timer = &sctp_cwnd_update_after_fr_timer; 2734171440Srrs SCTP_TCB_UNLOCK(stcb); 2735171440Srrs break; 2736171440Srrs } 2737171440Srrs /* JRS - HTCP congestion control */ 2738171440Srrs case SCTP_CC_HTCP: 2739171440Srrs { 2740171440Srrs stcb->asoc.congestion_control_module = SCTP_CC_HTCP; 2741171440Srrs stcb->asoc.cc_functions.sctp_set_initial_cc_param = &sctp_htcp_set_initial_cc_param; 2742171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_sack = &sctp_htcp_cwnd_update_after_sack; 2743171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_fr = &sctp_htcp_cwnd_update_after_fr; 2744171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_timeout = &sctp_htcp_cwnd_update_after_timeout; 2745171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_ecn_echo = &sctp_htcp_cwnd_update_after_ecn_echo; 2746171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_packet_dropped = &sctp_cwnd_update_after_packet_dropped; 2747171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_output = &sctp_cwnd_update_after_output; 2748171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_fr_timer = &sctp_htcp_cwnd_update_after_fr_timer; 2749171440Srrs SCTP_TCB_UNLOCK(stcb); 2750171440Srrs break; 2751171440Srrs } 2752171440Srrs /* 2753171440Srrs * JRS - All other values are 2754171440Srrs * invalid 2755171440Srrs */ 2756171440Srrs default: 2757171440Srrs { 2758171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2759171440Srrs error = EINVAL; 2760171440Srrs SCTP_TCB_UNLOCK(stcb); 2761171440Srrs break; 2762171440Srrs } 2763171440Srrs } 2764171440Srrs } else { 2765171440Srrs switch (av->assoc_value) { 2766171440Srrs case SCTP_CC_RFC2581: 2767171440Srrs case SCTP_CC_HSTCP: 2768171440Srrs case SCTP_CC_HTCP: 2769171440Srrs inp->sctp_ep.sctp_default_cc_module = av->assoc_value; 2770171440Srrs break; 2771171440Srrs default: 2772171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2773171440Srrs error = EINVAL; 2774171440Srrs break; 2775171440Srrs }; 2776171440Srrs } 2777171440Srrs } 2778171440Srrs break; 2779163953Srrs case SCTP_CLR_STAT_LOG: 2780171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 2781163953Srrs error = EOPNOTSUPP; 2782163953Srrs break; 2783163953Srrs case SCTP_CONTEXT: 2784163953Srrs { 2785163953Srrs struct sctp_assoc_value *av; 2786163953Srrs 2787166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 2788166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2789166675Srrs 2790166675Srrs if (stcb) { 2791166675Srrs stcb->asoc.context = av->assoc_value; 2792166675Srrs SCTP_TCB_UNLOCK(stcb); 2793163953Srrs } else { 2794166675Srrs SCTP_INP_WLOCK(inp); 2795163953Srrs inp->sctp_context = av->assoc_value; 2796166675Srrs SCTP_INP_WUNLOCK(inp); 2797163953Srrs } 2798163953Srrs } 2799163953Srrs break; 2800167598Srrs case SCTP_VRF_ID: 2801167598Srrs { 2802170056Srrs uint32_t *default_vrfid; 2803167598Srrs 2804170056Srrs SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize); 2805170056Srrs if (*default_vrfid > SCTP_MAX_VRF_ID) { 2806171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2807167598Srrs error = EINVAL; 2808167598Srrs break; 2809167598Srrs } 2810170056Srrs inp->def_vrf_id = *default_vrfid; 2811167598Srrs break; 2812167598Srrs } 2813167598Srrs case SCTP_DEL_VRF_ID: 2814167598Srrs { 2815171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 2816167598Srrs error = EOPNOTSUPP; 2817167598Srrs break; 2818167598Srrs } 2819167598Srrs case SCTP_ADD_VRF_ID: 2820167598Srrs { 2821171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 2822167598Srrs error = EOPNOTSUPP; 2823167598Srrs break; 2824167598Srrs } 2825170056Srrs case SCTP_DELAYED_SACK: 2826163953Srrs { 2827170056Srrs struct sctp_sack_info *sack; 2828163953Srrs 2829170056Srrs SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize); 2830170056Srrs SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); 2831171477Srrs if (sack->sack_delay) { 2832171477Srrs if (sack->sack_delay > SCTP_MAX_SACK_DELAY) 2833171477Srrs sack->sack_delay = SCTP_MAX_SACK_DELAY; 2834171477Srrs } 2835166675Srrs if (stcb) { 2836170056Srrs if (sack->sack_delay) { 2837170056Srrs if (MSEC_TO_TICKS(sack->sack_delay) < 1) { 2838170056Srrs sack->sack_delay = TICKS_TO_MSEC(1); 2839170056Srrs } 2840170056Srrs stcb->asoc.delayed_ack = sack->sack_delay; 2841170056Srrs } 2842170056Srrs if (sack->sack_freq) { 2843170056Srrs stcb->asoc.sack_freq = sack->sack_freq; 2844170056Srrs } 2845166675Srrs SCTP_TCB_UNLOCK(stcb); 2846166675Srrs } else { 2847163953Srrs SCTP_INP_WLOCK(inp); 2848170056Srrs if (sack->sack_delay) { 2849170056Srrs if (MSEC_TO_TICKS(sack->sack_delay) < 1) { 2850170056Srrs sack->sack_delay = TICKS_TO_MSEC(1); 2851170056Srrs } 2852170056Srrs inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay); 2853170056Srrs } 2854170056Srrs if (sack->sack_freq) { 2855170056Srrs inp->sctp_ep.sctp_sack_freq = sack->sack_freq; 2856170056Srrs } 2857163953Srrs SCTP_INP_WUNLOCK(inp); 2858163953Srrs } 2859166675Srrs break; 2860163953Srrs } 2861163953Srrs case SCTP_AUTH_CHUNK: 2862163953Srrs { 2863163953Srrs struct sctp_authchunk *sauth; 2864163953Srrs 2865166675Srrs SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize); 2866166675Srrs 2867166675Srrs SCTP_INP_WLOCK(inp); 2868171943Srrs if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) { 2869171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2870163953Srrs error = EINVAL; 2871171943Srrs } 2872166675Srrs SCTP_INP_WUNLOCK(inp); 2873163953Srrs break; 2874163953Srrs } 2875163953Srrs case SCTP_AUTH_KEY: 2876163953Srrs { 2877163953Srrs struct sctp_authkey *sca; 2878163953Srrs struct sctp_keyhead *shared_keys; 2879163953Srrs sctp_sharedkey_t *shared_key; 2880163953Srrs sctp_key_t *key = NULL; 2881166675Srrs size_t size; 2882163953Srrs 2883166675Srrs SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize); 2884169420Srrs SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id); 2885169420Srrs size = optsize - sizeof(*sca); 2886166675Srrs 2887166675Srrs if (stcb) { 2888163953Srrs /* set it on the assoc */ 2889163953Srrs shared_keys = &stcb->asoc.shared_keys; 2890163953Srrs /* clear the cached keys for this key id */ 2891163953Srrs sctp_clear_cachedkeys(stcb, sca->sca_keynumber); 2892163953Srrs /* 2893163953Srrs * create the new shared key and 2894163953Srrs * insert/replace it 2895163953Srrs */ 2896163953Srrs if (size > 0) { 2897163953Srrs key = sctp_set_key(sca->sca_key, (uint32_t) size); 2898163953Srrs if (key == NULL) { 2899171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 2900163953Srrs error = ENOMEM; 2901163953Srrs SCTP_TCB_UNLOCK(stcb); 2902163953Srrs break; 2903163953Srrs } 2904163953Srrs } 2905163953Srrs shared_key = sctp_alloc_sharedkey(); 2906163953Srrs if (shared_key == NULL) { 2907163953Srrs sctp_free_key(key); 2908171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 2909163953Srrs error = ENOMEM; 2910163953Srrs SCTP_TCB_UNLOCK(stcb); 2911163953Srrs break; 2912163953Srrs } 2913163953Srrs shared_key->key = key; 2914163953Srrs shared_key->keyid = sca->sca_keynumber; 2915163953Srrs sctp_insert_sharedkey(shared_keys, shared_key); 2916163953Srrs SCTP_TCB_UNLOCK(stcb); 2917163953Srrs } else { 2918166675Srrs /* set it on the endpoint */ 2919163953Srrs SCTP_INP_WLOCK(inp); 2920163953Srrs shared_keys = &inp->sctp_ep.shared_keys; 2921163953Srrs /* 2922163953Srrs * clear the cached keys on all assocs for 2923163953Srrs * this key id 2924163953Srrs */ 2925163953Srrs sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber); 2926163953Srrs /* 2927163953Srrs * create the new shared key and 2928163953Srrs * insert/replace it 2929163953Srrs */ 2930163953Srrs if (size > 0) { 2931163953Srrs key = sctp_set_key(sca->sca_key, (uint32_t) size); 2932163953Srrs if (key == NULL) { 2933171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 2934163953Srrs error = ENOMEM; 2935163953Srrs SCTP_INP_WUNLOCK(inp); 2936163953Srrs break; 2937163953Srrs } 2938163953Srrs } 2939163953Srrs shared_key = sctp_alloc_sharedkey(); 2940163953Srrs if (shared_key == NULL) { 2941163953Srrs sctp_free_key(key); 2942171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 2943163953Srrs error = ENOMEM; 2944163953Srrs SCTP_INP_WUNLOCK(inp); 2945163953Srrs break; 2946163953Srrs } 2947163953Srrs shared_key->key = key; 2948163953Srrs shared_key->keyid = sca->sca_keynumber; 2949163953Srrs sctp_insert_sharedkey(shared_keys, shared_key); 2950163953Srrs SCTP_INP_WUNLOCK(inp); 2951163953Srrs } 2952163953Srrs break; 2953163953Srrs } 2954163953Srrs case SCTP_HMAC_IDENT: 2955163953Srrs { 2956163953Srrs struct sctp_hmacalgo *shmac; 2957163953Srrs sctp_hmaclist_t *hmaclist; 2958163953Srrs uint32_t hmacid; 2959170056Srrs size_t size, i, found; 2960163953Srrs 2961166675Srrs SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize); 2962166675Srrs size = (optsize - sizeof(*shmac)) / sizeof(shmac->shmac_idents[0]); 2963163953Srrs hmaclist = sctp_alloc_hmaclist(size); 2964163953Srrs if (hmaclist == NULL) { 2965171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 2966163953Srrs error = ENOMEM; 2967163953Srrs break; 2968163953Srrs } 2969163953Srrs for (i = 0; i < size; i++) { 2970163953Srrs hmacid = shmac->shmac_idents[i]; 2971163953Srrs if (sctp_auth_add_hmacid(hmaclist, (uint16_t) hmacid)) { 2972163953Srrs /* invalid HMACs were found */ ; 2973171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2974163953Srrs error = EINVAL; 2975164085Srrs sctp_free_hmaclist(hmaclist); 2976163953Srrs goto sctp_set_hmac_done; 2977163953Srrs } 2978163953Srrs } 2979170056Srrs found = 0; 2980170056Srrs for (i = 0; i < hmaclist->num_algo; i++) { 2981170056Srrs if (hmaclist->hmac[i] == SCTP_AUTH_HMAC_ID_SHA1) { 2982170056Srrs /* already in list */ 2983170056Srrs found = 1; 2984170056Srrs } 2985170056Srrs } 2986170056Srrs if (!found) { 2987170056Srrs sctp_free_hmaclist(hmaclist); 2988171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2989170056Srrs error = EINVAL; 2990170056Srrs break; 2991170056Srrs } 2992163953Srrs /* set it on the endpoint */ 2993163953Srrs SCTP_INP_WLOCK(inp); 2994163953Srrs if (inp->sctp_ep.local_hmacs) 2995163953Srrs sctp_free_hmaclist(inp->sctp_ep.local_hmacs); 2996163953Srrs inp->sctp_ep.local_hmacs = hmaclist; 2997163953Srrs SCTP_INP_WUNLOCK(inp); 2998163953Srrs sctp_set_hmac_done: 2999163953Srrs break; 3000163953Srrs } 3001163953Srrs case SCTP_AUTH_ACTIVE_KEY: 3002163953Srrs { 3003163953Srrs struct sctp_authkeyid *scact; 3004163953Srrs 3005166675Srrs SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize); 3006166675Srrs SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); 3007166675Srrs 3008163953Srrs /* set the active key on the right place */ 3009166675Srrs if (stcb) { 3010163953Srrs /* set the active key on the assoc */ 3011171943Srrs if (sctp_auth_setactivekey(stcb, scact->scact_keynumber)) { 3012171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3013163953Srrs error = EINVAL; 3014171943Srrs } 3015163953Srrs SCTP_TCB_UNLOCK(stcb); 3016163953Srrs } else { 3017163953Srrs /* set the active key on the endpoint */ 3018163953Srrs SCTP_INP_WLOCK(inp); 3019171943Srrs if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) { 3020171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3021163953Srrs error = EINVAL; 3022171943Srrs } 3023163953Srrs SCTP_INP_WUNLOCK(inp); 3024163953Srrs } 3025163953Srrs break; 3026163953Srrs } 3027163953Srrs case SCTP_AUTH_DELETE_KEY: 3028163953Srrs { 3029163953Srrs struct sctp_authkeyid *scdel; 3030163953Srrs 3031166675Srrs SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize); 3032166675Srrs SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id); 3033166675Srrs 3034163953Srrs /* delete the key from the right place */ 3035166675Srrs if (stcb) { 3036171943Srrs if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) { 3037171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3038163953Srrs error = EINVAL; 3039171943Srrs } 3040163953Srrs SCTP_TCB_UNLOCK(stcb); 3041163953Srrs } else { 3042163953Srrs SCTP_INP_WLOCK(inp); 3043171943Srrs if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) { 3044171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3045163953Srrs error = EINVAL; 3046171943Srrs } 3047163953Srrs SCTP_INP_WUNLOCK(inp); 3048163953Srrs } 3049163953Srrs break; 3050163953Srrs } 3051163953Srrs 3052163953Srrs case SCTP_RESET_STREAMS: 3053163953Srrs { 3054163953Srrs struct sctp_stream_reset *strrst; 3055163953Srrs uint8_t send_in = 0, send_tsn = 0, send_out = 0; 3056163953Srrs int i; 3057163953Srrs 3058166675Srrs SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_stream_reset, optsize); 3059166675Srrs SCTP_FIND_STCB(inp, stcb, strrst->strrst_assoc_id); 3060163953Srrs 3061163953Srrs if (stcb == NULL) { 3062171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 3063163953Srrs error = ENOENT; 3064163953Srrs break; 3065163953Srrs } 3066163953Srrs if (stcb->asoc.peer_supports_strreset == 0) { 3067163953Srrs /* 3068163953Srrs * Peer does not support it, we return 3069163953Srrs * protocol not supported since this is true 3070163953Srrs * for this feature and this peer, not the 3071163953Srrs * socket request in general. 3072163953Srrs */ 3073171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPROTONOSUPPORT); 3074163953Srrs error = EPROTONOSUPPORT; 3075163953Srrs SCTP_TCB_UNLOCK(stcb); 3076163953Srrs break; 3077163953Srrs } 3078163953Srrs if (stcb->asoc.stream_reset_outstanding) { 3079171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 3080163953Srrs error = EALREADY; 3081163953Srrs SCTP_TCB_UNLOCK(stcb); 3082163953Srrs break; 3083163953Srrs } 3084163953Srrs if (strrst->strrst_flags == SCTP_RESET_LOCAL_RECV) { 3085163953Srrs send_in = 1; 3086163953Srrs } else if (strrst->strrst_flags == SCTP_RESET_LOCAL_SEND) { 3087163953Srrs send_out = 1; 3088163953Srrs } else if (strrst->strrst_flags == SCTP_RESET_BOTH) { 3089163953Srrs send_in = 1; 3090163953Srrs send_out = 1; 3091163953Srrs } else if (strrst->strrst_flags == SCTP_RESET_TSN) { 3092163953Srrs send_tsn = 1; 3093163953Srrs } else { 3094171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3095163953Srrs error = EINVAL; 3096163953Srrs SCTP_TCB_UNLOCK(stcb); 3097163953Srrs break; 3098163953Srrs } 3099163953Srrs for (i = 0; i < strrst->strrst_num_streams; i++) { 3100163953Srrs if ((send_in) && 3101163953Srrs 3102163953Srrs (strrst->strrst_list[i] > stcb->asoc.streamincnt)) { 3103171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3104163953Srrs error = EINVAL; 3105163953Srrs goto get_out; 3106163953Srrs } 3107163953Srrs if ((send_out) && 3108163953Srrs (strrst->strrst_list[i] > stcb->asoc.streamoutcnt)) { 3109171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3110163953Srrs error = EINVAL; 3111163953Srrs goto get_out; 3112163953Srrs } 3113163953Srrs } 3114163953Srrs if (error) { 3115163953Srrs get_out: 3116163953Srrs SCTP_TCB_UNLOCK(stcb); 3117163953Srrs break; 3118163953Srrs } 3119163953Srrs error = sctp_send_str_reset_req(stcb, strrst->strrst_num_streams, 3120163953Srrs strrst->strrst_list, 3121163953Srrs send_out, (stcb->asoc.str_reset_seq_in - 3), 3122163953Srrs send_in, send_tsn); 3123163953Srrs 3124172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); 3125163953Srrs SCTP_TCB_UNLOCK(stcb); 3126163953Srrs } 3127163953Srrs break; 3128166675Srrs 3129163953Srrs case SCTP_CONNECT_X: 3130166675Srrs if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { 3131171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3132163953Srrs error = EINVAL; 3133163953Srrs break; 3134163953Srrs } 3135166675Srrs error = sctp_do_connect_x(so, inp, optval, optsize, p, 0); 3136163953Srrs break; 3137163953Srrs 3138163953Srrs case SCTP_CONNECT_X_DELAYED: 3139166675Srrs if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { 3140171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3141163953Srrs error = EINVAL; 3142163953Srrs break; 3143163953Srrs } 3144166675Srrs error = sctp_do_connect_x(so, inp, optval, optsize, p, 1); 3145163953Srrs break; 3146163953Srrs 3147163953Srrs case SCTP_CONNECT_X_COMPLETE: 3148163953Srrs { 3149163953Srrs struct sockaddr *sa; 3150163953Srrs struct sctp_nets *net; 3151163953Srrs 3152166675Srrs /* FIXME MT: check correct? */ 3153166675Srrs SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize); 3154166675Srrs 3155163953Srrs /* find tcb */ 3156163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 3157163953Srrs SCTP_INP_RLOCK(inp); 3158163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 3159163953Srrs if (stcb) { 3160163953Srrs SCTP_TCB_LOCK(stcb); 3161163953Srrs net = sctp_findnet(stcb, sa); 3162163953Srrs } 3163163953Srrs SCTP_INP_RUNLOCK(inp); 3164163953Srrs } else { 3165166675Srrs /* 3166166675Srrs * We increment here since 3167166675Srrs * sctp_findassociation_ep_addr() wil do a 3168166675Srrs * decrement if it finds the stcb as long as 3169166675Srrs * the locked tcb (last argument) is NOT a 3170166675Srrs * TCB.. aka NULL. 3171166675Srrs */ 3172163953Srrs SCTP_INP_INCR_REF(inp); 3173163953Srrs stcb = sctp_findassociation_ep_addr(&inp, sa, &net, NULL, NULL); 3174163953Srrs if (stcb == NULL) { 3175163953Srrs SCTP_INP_DECR_REF(inp); 3176163953Srrs } 3177163953Srrs } 3178163953Srrs 3179163953Srrs if (stcb == NULL) { 3180171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 3181163953Srrs error = ENOENT; 3182163953Srrs break; 3183163953Srrs } 3184163953Srrs if (stcb->asoc.delayed_connection == 1) { 3185163953Srrs stcb->asoc.delayed_connection = 0; 3186169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 3187165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, 3188165220Srrs stcb->asoc.primary_destination, 3189165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9); 3190172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 3191163953Srrs } else { 3192163953Srrs /* 3193163953Srrs * already expired or did not use delayed 3194163953Srrs * connectx 3195163953Srrs */ 3196171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 3197163953Srrs error = EALREADY; 3198163953Srrs } 3199163953Srrs SCTP_TCB_UNLOCK(stcb); 3200163953Srrs } 3201163953Srrs break; 3202170056Srrs case SCTP_MAX_BURST: 3203163953Srrs { 3204163953Srrs uint8_t *burst; 3205163953Srrs 3206166675Srrs SCTP_CHECK_AND_CAST(burst, optval, uint8_t, optsize); 3207166675Srrs 3208163953Srrs SCTP_INP_WLOCK(inp); 3209163953Srrs if (*burst) { 3210163953Srrs inp->sctp_ep.max_burst = *burst; 3211163953Srrs } 3212163953Srrs SCTP_INP_WUNLOCK(inp); 3213163953Srrs } 3214163953Srrs break; 3215163953Srrs case SCTP_MAXSEG: 3216163953Srrs { 3217167598Srrs struct sctp_assoc_value *av; 3218163953Srrs int ovh; 3219163953Srrs 3220167598Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 3221167598Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3222166675Srrs 3223170056Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 3224170056Srrs ovh = SCTP_MED_OVERHEAD; 3225170056Srrs } else { 3226170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 3227170056Srrs } 3228167598Srrs if (stcb) { 3229170056Srrs if (av->assoc_value) { 3230170056Srrs stcb->asoc.sctp_frag_point = (av->assoc_value + ovh); 3231170056Srrs } else { 3232170056Srrs stcb->asoc.sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; 3233170056Srrs } 3234167598Srrs SCTP_TCB_UNLOCK(stcb); 3235163953Srrs } else { 3236167598Srrs SCTP_INP_WLOCK(inp); 3237167598Srrs /* 3238167598Srrs * FIXME MT: I think this is not in tune 3239167598Srrs * with the API ID 3240167598Srrs */ 3241167598Srrs if (av->assoc_value) { 3242167598Srrs inp->sctp_frag_point = (av->assoc_value + ovh); 3243167598Srrs } else { 3244170056Srrs inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; 3245167598Srrs } 3246167598Srrs SCTP_INP_WUNLOCK(inp); 3247163953Srrs } 3248163953Srrs } 3249163953Srrs break; 3250163953Srrs case SCTP_EVENTS: 3251163953Srrs { 3252163953Srrs struct sctp_event_subscribe *events; 3253163953Srrs 3254166675Srrs SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize); 3255166675Srrs 3256163953Srrs SCTP_INP_WLOCK(inp); 3257163953Srrs if (events->sctp_data_io_event) { 3258163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); 3259163953Srrs } else { 3260163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); 3261163953Srrs } 3262163953Srrs 3263163953Srrs if (events->sctp_association_event) { 3264163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); 3265163953Srrs } else { 3266163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); 3267163953Srrs } 3268163953Srrs 3269163953Srrs if (events->sctp_address_event) { 3270163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); 3271163953Srrs } else { 3272163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); 3273163953Srrs } 3274163953Srrs 3275163953Srrs if (events->sctp_send_failure_event) { 3276163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 3277163953Srrs } else { 3278163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 3279163953Srrs } 3280163953Srrs 3281163953Srrs if (events->sctp_peer_error_event) { 3282163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR); 3283163953Srrs } else { 3284163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR); 3285163953Srrs } 3286163953Srrs 3287163953Srrs if (events->sctp_shutdown_event) { 3288163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 3289163953Srrs } else { 3290163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 3291163953Srrs } 3292163953Srrs 3293163953Srrs if (events->sctp_partial_delivery_event) { 3294163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT); 3295163953Srrs } else { 3296163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT); 3297163953Srrs } 3298163953Srrs 3299163953Srrs if (events->sctp_adaptation_layer_event) { 3300163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 3301163953Srrs } else { 3302163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 3303163953Srrs } 3304163953Srrs 3305163953Srrs if (events->sctp_authentication_event) { 3306163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT); 3307163953Srrs } else { 3308163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT); 3309163953Srrs } 3310163953Srrs 3311163953Srrs if (events->sctp_stream_reset_events) { 3312163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 3313163953Srrs } else { 3314163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 3315163953Srrs } 3316163953Srrs SCTP_INP_WUNLOCK(inp); 3317163953Srrs } 3318163953Srrs break; 3319163953Srrs 3320163953Srrs case SCTP_ADAPTATION_LAYER: 3321163953Srrs { 3322163953Srrs struct sctp_setadaptation *adap_bits; 3323163953Srrs 3324166675Srrs SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize); 3325163953Srrs SCTP_INP_WLOCK(inp); 3326163953Srrs inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind; 3327163953Srrs SCTP_INP_WUNLOCK(inp); 3328163953Srrs } 3329163953Srrs break; 3330166675Srrs#ifdef SCTP_DEBUG 3331163953Srrs case SCTP_SET_INITIAL_DBG_SEQ: 3332163953Srrs { 3333163953Srrs uint32_t *vvv; 3334163953Srrs 3335166675Srrs SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize); 3336163953Srrs SCTP_INP_WLOCK(inp); 3337163953Srrs inp->sctp_ep.initial_sequence_debug = *vvv; 3338163953Srrs SCTP_INP_WUNLOCK(inp); 3339163953Srrs } 3340163953Srrs break; 3341166675Srrs#endif 3342163953Srrs case SCTP_DEFAULT_SEND_PARAM: 3343163953Srrs { 3344163953Srrs struct sctp_sndrcvinfo *s_info; 3345163953Srrs 3346166675Srrs SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize); 3347166675Srrs SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); 3348163953Srrs 3349166675Srrs if (stcb) { 3350166675Srrs if (s_info->sinfo_stream <= stcb->asoc.streamoutcnt) { 3351170056Srrs memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send))); 3352163953Srrs } else { 3353171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3354166675Srrs error = EINVAL; 3355163953Srrs } 3356166675Srrs SCTP_TCB_UNLOCK(stcb); 3357166675Srrs } else { 3358166675Srrs SCTP_INP_WLOCK(inp); 3359170056Srrs memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send))); 3360166675Srrs SCTP_INP_WUNLOCK(inp); 3361163953Srrs } 3362163953Srrs } 3363163953Srrs break; 3364163953Srrs case SCTP_PEER_ADDR_PARAMS: 3365163953Srrs /* Applys to the specific association */ 3366163953Srrs { 3367163953Srrs struct sctp_paddrparams *paddrp; 3368163953Srrs struct sctp_nets *net; 3369163953Srrs 3370166675Srrs SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize); 3371166675Srrs SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); 3372163953Srrs net = NULL; 3373166675Srrs if (stcb) { 3374166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address); 3375166675Srrs } else { 3376166675Srrs /* 3377166675Srrs * We increment here since 3378166675Srrs * sctp_findassociation_ep_addr() wil do a 3379166675Srrs * decrement if it finds the stcb as long as 3380166675Srrs * the locked tcb (last argument) is NOT a 3381166675Srrs * TCB.. aka NULL. 3382166675Srrs */ 3383166675Srrs SCTP_INP_INCR_REF(inp); 3384166675Srrs stcb = sctp_findassociation_ep_addr(&inp, 3385166675Srrs (struct sockaddr *)&paddrp->spp_address, 3386166675Srrs &net, NULL, NULL); 3387163953Srrs if (stcb == NULL) { 3388166675Srrs SCTP_INP_DECR_REF(inp); 3389163953Srrs } 3390163953Srrs } 3391171943Srrs if (stcb && (net == NULL)) { 3392171943Srrs struct sockaddr *sa; 3393171943Srrs 3394171943Srrs sa = (struct sockaddr *)&paddrp->spp_address; 3395171943Srrs if (sa->sa_family == AF_INET) { 3396171943Srrs struct sockaddr_in *sin; 3397171943Srrs 3398171943Srrs sin = (struct sockaddr_in *)sa; 3399171943Srrs if (sin->sin_addr.s_addr) { 3400171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3401171943Srrs SCTP_TCB_UNLOCK(stcb); 3402171943Srrs error = EINVAL; 3403171943Srrs break; 3404171943Srrs } 3405171943Srrs } else if (sa->sa_family == AF_INET6) { 3406171943Srrs struct sockaddr_in6 *sin6; 3407171943Srrs 3408171943Srrs sin6 = (struct sockaddr_in6 *)sa; 3409171943Srrs if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 3410171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3411171943Srrs SCTP_TCB_UNLOCK(stcb); 3412171943Srrs error = EINVAL; 3413171943Srrs break; 3414171943Srrs } 3415171943Srrs } else { 3416171943Srrs error = EAFNOSUPPORT; 3417171943Srrs SCTP_TCB_UNLOCK(stcb); 3418171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3419171943Srrs break; 3420171943Srrs } 3421171943Srrs } 3422170056Srrs /* sanity checks */ 3423170056Srrs if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) { 3424170056Srrs if (stcb) 3425170056Srrs SCTP_TCB_UNLOCK(stcb); 3426171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3427170056Srrs return (EINVAL); 3428170056Srrs } 3429170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) { 3430170056Srrs if (stcb) 3431170056Srrs SCTP_TCB_UNLOCK(stcb); 3432171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3433170056Srrs return (EINVAL); 3434170056Srrs } 3435163953Srrs if (stcb) { 3436163953Srrs /************************TCB SPECIFIC SET ******************/ 3437163953Srrs /* 3438163953Srrs * do we change the timer for HB, we run 3439163953Srrs * only one? 3440163953Srrs */ 3441170056Srrs int ovh = 0; 3442170056Srrs 3443170056Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 3444170056Srrs ovh = SCTP_MED_OVERHEAD; 3445170056Srrs } else { 3446170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 3447170056Srrs } 3448170056Srrs 3449163953Srrs if (paddrp->spp_hbinterval) 3450163953Srrs stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval; 3451163953Srrs else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) 3452163953Srrs stcb->asoc.heart_beat_delay = 0; 3453163953Srrs 3454163953Srrs /* network sets ? */ 3455163953Srrs if (net) { 3456163953Srrs /************************NET SPECIFIC SET ******************/ 3457163953Srrs if (paddrp->spp_flags & SPP_HB_DEMAND) { 3458163953Srrs /* on demand HB */ 3459171440Srrs if (sctp_send_hb(stcb, 1, net) < 0) { 3460171440Srrs /* asoc destroyed */ 3461171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3462171440Srrs error = EINVAL; 3463171440Srrs break; 3464171440Srrs } 3465163953Srrs } 3466163953Srrs if (paddrp->spp_flags & SPP_HB_DISABLE) { 3467163953Srrs net->dest_state |= SCTP_ADDR_NOHB; 3468163953Srrs } 3469163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 3470163953Srrs net->dest_state &= ~SCTP_ADDR_NOHB; 3471163953Srrs } 3472170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { 3473165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 3474165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 3475165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 3476163953Srrs } 3477163953Srrs if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) { 3478170056Srrs net->mtu = paddrp->spp_pathmtu + ovh; 3479169352Srrs if (net->mtu < stcb->asoc.smallest_mtu) { 3480169352Srrs#ifdef SCTP_PRINT_FOR_B_AND_M 3481169420Srrs SCTP_PRINTF("SCTP_PMTU_DISABLE calls sctp_pathmtu_adjustment:%d\n", 3482169352Srrs net->mtu); 3483169352Srrs#endif 3484167695Srrs sctp_pathmtu_adjustment(inp, stcb, net, net->mtu); 3485169352Srrs } 3486163953Srrs } 3487163953Srrs } 3488163953Srrs if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 3489165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 3490163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 3491163953Srrs } 3492163953Srrs } 3493163953Srrs if (paddrp->spp_pathmaxrxt) 3494163953Srrs net->failure_threshold = paddrp->spp_pathmaxrxt; 3495167598Srrs#ifdef INET 3496163953Srrs if (paddrp->spp_flags & SPP_IPV4_TOS) { 3497163953Srrs if (net->ro._l_addr.sin.sin_family == AF_INET) { 3498163953Srrs net->tos_flowlabel = paddrp->spp_ipv4_tos & 0x000000fc; 3499163953Srrs } 3500163953Srrs } 3501163953Srrs#endif 3502167598Srrs#ifdef INET6 3503163953Srrs if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { 3504163953Srrs if (net->ro._l_addr.sin6.sin6_family == AF_INET6) { 3505163953Srrs net->tos_flowlabel = paddrp->spp_ipv6_flowlabel; 3506163953Srrs } 3507163953Srrs } 3508163953Srrs#endif 3509163953Srrs } else { 3510163953Srrs /************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/ 3511163953Srrs if (paddrp->spp_pathmaxrxt) 3512163953Srrs stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt; 3513163953Srrs 3514163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 3515163953Srrs /* Turn back on the timer */ 3516163953Srrs stcb->asoc.hb_is_disabled = 0; 3517163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 3518163953Srrs } 3519170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { 3520170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3521170056Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 3522170056Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 3523170056Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 3524170056Srrs } 3525170056Srrs if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) { 3526170056Srrs net->mtu = paddrp->spp_pathmtu + ovh; 3527170056Srrs if (net->mtu < stcb->asoc.smallest_mtu) { 3528170056Srrs#ifdef SCTP_PRINT_FOR_B_AND_M 3529170056Srrs SCTP_PRINTF("SCTP_PMTU_DISABLE calls sctp_pathmtu_adjustment:%d\n", 3530170056Srrs net->mtu); 3531170056Srrs#endif 3532170056Srrs sctp_pathmtu_adjustment(inp, stcb, net, net->mtu); 3533170056Srrs } 3534170056Srrs } 3535170056Srrs } 3536170056Srrs } 3537170056Srrs if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 3538170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3539170056Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 3540170056Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 3541170056Srrs } 3542170056Srrs } 3543170056Srrs } 3544163953Srrs if (paddrp->spp_flags & SPP_HB_DISABLE) { 3545163953Srrs int cnt_of_unconf = 0; 3546163953Srrs struct sctp_nets *lnet; 3547163953Srrs 3548163953Srrs stcb->asoc.hb_is_disabled = 1; 3549163953Srrs TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 3550163953Srrs if (lnet->dest_state & SCTP_ADDR_UNCONFIRMED) { 3551163953Srrs cnt_of_unconf++; 3552163953Srrs } 3553163953Srrs } 3554163953Srrs /* 3555163953Srrs * stop the timer ONLY if we 3556163953Srrs * have no unconfirmed 3557163953Srrs * addresses 3558163953Srrs */ 3559163953Srrs if (cnt_of_unconf == 0) { 3560170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3561170056Srrs sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 3562170056Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11); 3563170056Srrs } 3564163953Srrs } 3565163953Srrs } 3566163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 3567163953Srrs /* start up the timer. */ 3568170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3569170056Srrs sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 3570170056Srrs } 3571163953Srrs } 3572167598Srrs#ifdef INET 3573163953Srrs if (paddrp->spp_flags & SPP_IPV4_TOS) 3574163953Srrs stcb->asoc.default_tos = paddrp->spp_ipv4_tos & 0x000000fc; 3575163953Srrs#endif 3576167598Srrs#ifdef INET6 3577163953Srrs if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) 3578163953Srrs stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel; 3579163953Srrs#endif 3580163953Srrs 3581163953Srrs } 3582163953Srrs SCTP_TCB_UNLOCK(stcb); 3583163953Srrs } else { 3584163953Srrs /************************NO TCB, SET TO default stuff ******************/ 3585163953Srrs SCTP_INP_WLOCK(inp); 3586163953Srrs /* 3587163953Srrs * For the TOS/FLOWLABEL stuff you set it 3588163953Srrs * with the options on the socket 3589163953Srrs */ 3590163953Srrs if (paddrp->spp_pathmaxrxt) { 3591163953Srrs inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt; 3592163953Srrs } 3593170056Srrs if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) 3594170056Srrs inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0; 3595171477Srrs else if (paddrp->spp_hbinterval) { 3596171477Srrs if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL) 3597171477Srrs paddrp->spp_hbinterval = SCTP_MAX_HB_INTERVAL; 3598170056Srrs inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval); 3599171477Srrs } 3600163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 3601163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 3602170056Srrs 3603163953Srrs } else if (paddrp->spp_flags & SPP_HB_DISABLE) { 3604163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 3605163953Srrs } 3606163953Srrs SCTP_INP_WUNLOCK(inp); 3607163953Srrs } 3608163953Srrs } 3609163953Srrs break; 3610163953Srrs case SCTP_RTOINFO: 3611163953Srrs { 3612163953Srrs struct sctp_rtoinfo *srto; 3613169655Srrs uint32_t new_init, new_min, new_max; 3614163953Srrs 3615166675Srrs SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize); 3616166675Srrs SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); 3617166675Srrs 3618166675Srrs if (stcb) { 3619167598Srrs if (srto->srto_initial) 3620169655Srrs new_init = srto->srto_initial; 3621169655Srrs else 3622169655Srrs new_init = stcb->asoc.initial_rto; 3623167598Srrs if (srto->srto_max) 3624169655Srrs new_max = srto->srto_max; 3625169655Srrs else 3626169655Srrs new_max = stcb->asoc.maxrto; 3627167598Srrs if (srto->srto_min) 3628169655Srrs new_min = srto->srto_min; 3629169655Srrs else 3630169655Srrs new_min = stcb->asoc.minrto; 3631169655Srrs if ((new_min <= new_init) && (new_init <= new_max)) { 3632169655Srrs stcb->asoc.initial_rto = new_init; 3633169655Srrs stcb->asoc.maxrto = new_max; 3634169655Srrs stcb->asoc.minrto = new_min; 3635169655Srrs } else { 3636171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDOM); 3637169655Srrs error = EDOM; 3638169655Srrs } 3639166675Srrs SCTP_TCB_UNLOCK(stcb); 3640166675Srrs } else { 3641163953Srrs SCTP_INP_WLOCK(inp); 3642167598Srrs if (srto->srto_initial) 3643169655Srrs new_init = srto->srto_initial; 3644169655Srrs else 3645169655Srrs new_init = inp->sctp_ep.initial_rto; 3646167598Srrs if (srto->srto_max) 3647169655Srrs new_max = srto->srto_max; 3648169655Srrs else 3649169655Srrs new_max = inp->sctp_ep.sctp_maxrto; 3650167598Srrs if (srto->srto_min) 3651169655Srrs new_min = srto->srto_min; 3652169655Srrs else 3653169655Srrs new_min = inp->sctp_ep.sctp_minrto; 3654169655Srrs if ((new_min <= new_init) && (new_init <= new_max)) { 3655169655Srrs inp->sctp_ep.initial_rto = new_init; 3656169655Srrs inp->sctp_ep.sctp_maxrto = new_max; 3657169655Srrs inp->sctp_ep.sctp_minrto = new_min; 3658169655Srrs } else { 3659171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDOM); 3660169655Srrs error = EDOM; 3661169655Srrs } 3662163953Srrs SCTP_INP_WUNLOCK(inp); 3663163953Srrs } 3664163953Srrs } 3665163953Srrs break; 3666163953Srrs case SCTP_ASSOCINFO: 3667163953Srrs { 3668163953Srrs struct sctp_assocparams *sasoc; 3669163953Srrs 3670166675Srrs SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize); 3671166675Srrs SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); 3672171477Srrs if (sasoc->sasoc_cookie_life) { 3673171477Srrs /* boundary check the cookie life */ 3674171477Srrs if (sasoc->sasoc_cookie_life < 1000) 3675171477Srrs sasoc->sasoc_cookie_life = 1000; 3676171477Srrs if (sasoc->sasoc_cookie_life > SCTP_MAX_COOKIE_LIFE) { 3677171477Srrs sasoc->sasoc_cookie_life = SCTP_MAX_COOKIE_LIFE; 3678171477Srrs } 3679171477Srrs } 3680163953Srrs if (stcb) { 3681163953Srrs if (sasoc->sasoc_asocmaxrxt) 3682163953Srrs stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt; 3683163953Srrs sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets; 3684163953Srrs sasoc->sasoc_peer_rwnd = 0; 3685163953Srrs sasoc->sasoc_local_rwnd = 0; 3686170056Srrs if (sasoc->sasoc_cookie_life) { 3687171572Srrs stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); 3688167598Srrs } 3689163953Srrs SCTP_TCB_UNLOCK(stcb); 3690163953Srrs } else { 3691163953Srrs SCTP_INP_WLOCK(inp); 3692163953Srrs if (sasoc->sasoc_asocmaxrxt) 3693163953Srrs inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt; 3694163953Srrs sasoc->sasoc_number_peer_destinations = 0; 3695163953Srrs sasoc->sasoc_peer_rwnd = 0; 3696163953Srrs sasoc->sasoc_local_rwnd = 0; 3697170056Srrs if (sasoc->sasoc_cookie_life) { 3698169655Srrs inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); 3699167598Srrs } 3700163953Srrs SCTP_INP_WUNLOCK(inp); 3701163953Srrs } 3702163953Srrs } 3703163953Srrs break; 3704163953Srrs case SCTP_INITMSG: 3705163953Srrs { 3706163953Srrs struct sctp_initmsg *sinit; 3707163953Srrs 3708166675Srrs SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize); 3709163953Srrs SCTP_INP_WLOCK(inp); 3710163953Srrs if (sinit->sinit_num_ostreams) 3711163953Srrs inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams; 3712163953Srrs 3713163953Srrs if (sinit->sinit_max_instreams) 3714163953Srrs inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams; 3715163953Srrs 3716163953Srrs if (sinit->sinit_max_attempts) 3717163953Srrs inp->sctp_ep.max_init_times = sinit->sinit_max_attempts; 3718163953Srrs 3719167598Srrs if (sinit->sinit_max_init_timeo) 3720163953Srrs inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo; 3721163953Srrs SCTP_INP_WUNLOCK(inp); 3722163953Srrs } 3723163953Srrs break; 3724163953Srrs case SCTP_PRIMARY_ADDR: 3725163953Srrs { 3726163953Srrs struct sctp_setprim *spa; 3727163953Srrs struct sctp_nets *net, *lnet; 3728163953Srrs 3729166675Srrs SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize); 3730166675Srrs SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id); 3731163953Srrs 3732166675Srrs net = NULL; 3733166675Srrs if (stcb) { 3734166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&spa->ssp_addr); 3735166675Srrs } else { 3736166675Srrs /* 3737166675Srrs * We increment here since 3738166675Srrs * sctp_findassociation_ep_addr() wil do a 3739166675Srrs * decrement if it finds the stcb as long as 3740166675Srrs * the locked tcb (last argument) is NOT a 3741166675Srrs * TCB.. aka NULL. 3742166675Srrs */ 3743163953Srrs SCTP_INP_INCR_REF(inp); 3744163953Srrs stcb = sctp_findassociation_ep_addr(&inp, 3745163953Srrs (struct sockaddr *)&spa->ssp_addr, 3746163953Srrs &net, NULL, NULL); 3747163953Srrs if (stcb == NULL) { 3748163953Srrs SCTP_INP_DECR_REF(inp); 3749163953Srrs } 3750163953Srrs } 3751166675Srrs 3752166675Srrs if ((stcb) && (net)) { 3753166675Srrs if ((net != stcb->asoc.primary_destination) && 3754166675Srrs (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) { 3755166675Srrs /* Ok we need to set it */ 3756166675Srrs lnet = stcb->asoc.primary_destination; 3757166675Srrs if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) { 3758166675Srrs if (net->dest_state & SCTP_ADDR_SWITCH_PRIMARY) { 3759166675Srrs net->dest_state |= SCTP_ADDR_DOUBLE_SWITCH; 3760166675Srrs } 3761166675Srrs net->dest_state |= SCTP_ADDR_SWITCH_PRIMARY; 3762163953Srrs } 3763163953Srrs } 3764166675Srrs } else { 3765171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3766166675Srrs error = EINVAL; 3767163953Srrs } 3768166675Srrs if (stcb) { 3769166675Srrs SCTP_TCB_UNLOCK(stcb); 3770166675Srrs } 3771163953Srrs } 3772163953Srrs break; 3773167598Srrs case SCTP_SET_DYNAMIC_PRIMARY: 3774167598Srrs { 3775167598Srrs union sctp_sockstore *ss; 3776163953Srrs 3777170587Srwatson error = priv_check(curthread, 3778170587Srwatson PRIV_NETINET_RESERVEDPORT); 3779167598Srrs if (error) 3780167598Srrs break; 3781167598Srrs 3782167598Srrs SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize); 3783167598Srrs /* SUPER USER CHECK? */ 3784167598Srrs error = sctp_dynamic_set_primary(&ss->sa, vrf_id); 3785167598Srrs } 3786167598Srrs break; 3787163953Srrs case SCTP_SET_PEER_PRIMARY_ADDR: 3788163953Srrs { 3789163953Srrs struct sctp_setpeerprim *sspp; 3790163953Srrs 3791166675Srrs SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize); 3792166675Srrs SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id); 3793169208Srrs if (stcb != NULL) { 3794170056Srrs struct sctp_ifa *ifa; 3795170056Srrs 3796170056Srrs ifa = sctp_find_ifa_by_addr((struct sockaddr *)&sspp->sspp_addr, 3797172091Srrs stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED); 3798170056Srrs if (ifa == NULL) { 3799171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3800166675Srrs error = EINVAL; 3801170056Srrs goto out_of_it; 3802166675Srrs } 3803170056Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { 3804170056Srrs /* 3805170056Srrs * Must validate the ifa found is in 3806170056Srrs * our ep 3807170056Srrs */ 3808170056Srrs struct sctp_laddr *laddr; 3809170056Srrs int found = 0; 3810170056Srrs 3811170056Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 3812170056Srrs if (laddr->ifa == NULL) { 3813170056Srrs SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n", 3814170056Srrs __FUNCTION__); 3815170056Srrs continue; 3816170056Srrs } 3817170056Srrs if (laddr->ifa == ifa) { 3818170056Srrs found = 1; 3819170056Srrs break; 3820170056Srrs } 3821170056Srrs } 3822170056Srrs if (!found) { 3823171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3824170056Srrs error = EINVAL; 3825170056Srrs goto out_of_it; 3826170056Srrs } 3827170056Srrs } 3828170056Srrs if (sctp_set_primary_ip_address_sa(stcb, 3829170056Srrs (struct sockaddr *)&sspp->sspp_addr) != 0) { 3830171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3831170056Srrs error = EINVAL; 3832170056Srrs } 3833170056Srrs out_of_it: 3834169208Srrs SCTP_TCB_UNLOCK(stcb); 3835166675Srrs } else { 3836171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3837163953Srrs error = EINVAL; 3838163953Srrs } 3839169208Srrs 3840163953Srrs } 3841163953Srrs break; 3842163953Srrs case SCTP_BINDX_ADD_ADDR: 3843163953Srrs { 3844163953Srrs struct sctp_getaddresses *addrs; 3845171531Srrs size_t sz; 3846171477Srrs struct thread *td; 3847171477Srrs int prison = 0; 3848163953Srrs 3849171477Srrs td = (struct thread *)p; 3850171477Srrs if (jailed(td->td_ucred)) { 3851171477Srrs prison = 1; 3852171477Srrs } 3853170606Srrs SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, 3854170606Srrs optsize); 3855171477Srrs if (addrs->addr->sa_family == AF_INET) { 3856171477Srrs sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in); 3857171477Srrs if (optsize < sz) { 3858171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3859171477Srrs error = EINVAL; 3860171477Srrs break; 3861171477Srrs } 3862171477Srrs if (prison && prison_ip(td->td_ucred, 0, &(((struct sockaddr_in *)(addrs->addr))->sin_addr.s_addr))) { 3863171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRNOTAVAIL); 3864171477Srrs error = EADDRNOTAVAIL; 3865171477Srrs } 3866171477Srrs } else if (addrs->addr->sa_family == AF_INET6) { 3867171477Srrs sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6); 3868171477Srrs if (optsize < sz) { 3869171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3870171477Srrs error = EINVAL; 3871171477Srrs break; 3872171477Srrs } 3873171477Srrs /* JAIL XXXX Add else here for V6 */ 3874171477Srrs } 3875170606Srrs sctp_bindx_add_address(so, inp, addrs->addr, 3876170606Srrs addrs->sget_assoc_id, vrf_id, 3877170606Srrs &error, p); 3878163953Srrs } 3879163953Srrs break; 3880163953Srrs case SCTP_BINDX_REM_ADDR: 3881163953Srrs { 3882163953Srrs struct sctp_getaddresses *addrs; 3883171531Srrs size_t sz; 3884171477Srrs struct thread *td; 3885171477Srrs int prison = 0; 3886163953Srrs 3887171477Srrs td = (struct thread *)p; 3888171477Srrs if (jailed(td->td_ucred)) { 3889171477Srrs prison = 1; 3890171477Srrs } 3891166675Srrs SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize); 3892171477Srrs if (addrs->addr->sa_family == AF_INET) { 3893171477Srrs sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in); 3894171477Srrs if (optsize < sz) { 3895171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3896171477Srrs error = EINVAL; 3897171477Srrs break; 3898171477Srrs } 3899171477Srrs if (prison && prison_ip(td->td_ucred, 0, &(((struct sockaddr_in *)(addrs->addr))->sin_addr.s_addr))) { 3900171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRNOTAVAIL); 3901171477Srrs error = EADDRNOTAVAIL; 3902171477Srrs } 3903171477Srrs } else if (addrs->addr->sa_family == AF_INET6) { 3904171477Srrs sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6); 3905171477Srrs if (optsize < sz) { 3906171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3907171477Srrs error = EINVAL; 3908171477Srrs break; 3909171477Srrs } 3910171477Srrs /* JAIL XXXX Add else here for V6 */ 3911171477Srrs } 3912170606Srrs sctp_bindx_delete_address(so, inp, addrs->addr, 3913170606Srrs addrs->sget_assoc_id, vrf_id, 3914170606Srrs &error); 3915163953Srrs } 3916163953Srrs break; 3917163953Srrs default: 3918171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 3919163953Srrs error = ENOPROTOOPT; 3920163953Srrs break; 3921163953Srrs } /* end switch (opt) */ 3922163953Srrs return (error); 3923163953Srrs} 3924163953Srrs 3925163953Srrs 3926163953Srrsint 3927163953Srrssctp_ctloutput(struct socket *so, struct sockopt *sopt) 3928163953Srrs{ 3929166675Srrs void *optval = NULL; 3930166675Srrs size_t optsize = 0; 3931163953Srrs struct sctp_inpcb *inp; 3932166675Srrs void *p; 3933166675Srrs int error = 0; 3934163953Srrs 3935163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3936163953Srrs if (inp == 0) { 3937163953Srrs /* I made the same as TCP since we are not setup? */ 3938171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3939163953Srrs return (ECONNRESET); 3940163953Srrs } 3941163953Srrs if (sopt->sopt_level != IPPROTO_SCTP) { 3942163953Srrs /* wrong proto level... send back up to IP */ 3943163953Srrs#ifdef INET6 3944163953Srrs if (INP_CHECK_SOCKAF(so, AF_INET6)) 3945163953Srrs error = ip6_ctloutput(so, sopt); 3946163953Srrs else 3947163953Srrs#endif /* INET6 */ 3948163953Srrs error = ip_ctloutput(so, sopt); 3949163953Srrs return (error); 3950163953Srrs } 3951166675Srrs optsize = sopt->sopt_valsize; 3952166675Srrs if (optsize) { 3953170091Srrs SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT); 3954166675Srrs if (optval == NULL) { 3955171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS); 3956163953Srrs return (ENOBUFS); 3957163953Srrs } 3958166675Srrs error = sooptcopyin(sopt, optval, optsize, optsize); 3959163953Srrs if (error) { 3960170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 3961163953Srrs goto out; 3962163953Srrs } 3963163953Srrs } 3964166675Srrs p = (void *)sopt->sopt_td; 3965163953Srrs if (sopt->sopt_dir == SOPT_SET) { 3966166675Srrs error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p); 3967163953Srrs } else if (sopt->sopt_dir == SOPT_GET) { 3968166675Srrs error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p); 3969163953Srrs } else { 3970171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3971163953Srrs error = EINVAL; 3972163953Srrs } 3973166675Srrs if ((error == 0) && (optval != NULL)) { 3974166675Srrs error = sooptcopyout(sopt, optval, optsize); 3975170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 3976166675Srrs } else if (optval != NULL) { 3977170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 3978163953Srrs } 3979163953Srrsout: 3980163953Srrs return (error); 3981163953Srrs} 3982163953Srrs 3983163953Srrs 3984163953Srrsstatic int 3985163953Srrssctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p) 3986163953Srrs{ 3987163953Srrs int error = 0; 3988163953Srrs int create_lock_on = 0; 3989167598Srrs uint32_t vrf_id; 3990163953Srrs struct sctp_inpcb *inp; 3991163953Srrs struct sctp_tcb *stcb = NULL; 3992163953Srrs 3993163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3994163953Srrs if (inp == 0) { 3995163953Srrs /* I made the same as TCP since we are not setup? */ 3996171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3997163953Srrs return (ECONNRESET); 3998163953Srrs } 3999171943Srrs if (addr == NULL) { 4000171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4001170056Srrs return EINVAL; 4002171943Srrs } 4003170056Srrs if ((addr->sa_family == AF_INET6) && (addr->sa_len != sizeof(struct sockaddr_in6))) { 4004171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4005170056Srrs return (EINVAL); 4006170056Srrs } 4007170056Srrs if ((addr->sa_family == AF_INET) && (addr->sa_len != sizeof(struct sockaddr_in))) { 4008171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4009170056Srrs return (EINVAL); 4010170056Srrs } 4011163953Srrs SCTP_ASOC_CREATE_LOCK(inp); 4012163953Srrs create_lock_on = 1; 4013163953Srrs 4014163953Srrs SCTP_INP_INCR_REF(inp); 4015163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 4016163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 4017163953Srrs /* Should I really unlock ? */ 4018171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); 4019163953Srrs error = EFAULT; 4020163953Srrs goto out_now; 4021163953Srrs } 4022163953Srrs#ifdef INET6 4023163953Srrs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 4024163953Srrs (addr->sa_family == AF_INET6)) { 4025171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4026163953Srrs error = EINVAL; 4027163953Srrs goto out_now; 4028163953Srrs } 4029163953Srrs#endif /* INET6 */ 4030163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 4031163953Srrs SCTP_PCB_FLAGS_UNBOUND) { 4032163953Srrs /* Bind a ephemeral port */ 4033171572Srrs error = sctp_inpcb_bind(so, NULL, NULL, p); 4034163953Srrs if (error) { 4035163953Srrs goto out_now; 4036163953Srrs } 4037163953Srrs } 4038163953Srrs /* Now do we connect? */ 4039163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) { 4040171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4041163953Srrs error = EINVAL; 4042163953Srrs goto out_now; 4043163953Srrs } 4044163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 4045163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 4046163953Srrs /* We are already connected AND the TCP model */ 4047171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 4048163953Srrs error = EADDRINUSE; 4049163953Srrs goto out_now; 4050163953Srrs } 4051163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 4052163953Srrs SCTP_INP_RLOCK(inp); 4053163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 4054163953Srrs SCTP_INP_RUNLOCK(inp); 4055163953Srrs } else { 4056163953Srrs /* 4057166675Srrs * We increment here since sctp_findassociation_ep_addr() 4058166675Srrs * wil do a decrement if it finds the stcb as long as the 4059166675Srrs * locked tcb (last argument) is NOT a TCB.. aka NULL. 4060163953Srrs */ 4061163953Srrs SCTP_INP_INCR_REF(inp); 4062163953Srrs stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL); 4063163953Srrs if (stcb == NULL) { 4064163953Srrs SCTP_INP_DECR_REF(inp); 4065168299Srrs } else { 4066168299Srrs SCTP_TCB_LOCK(stcb); 4067163953Srrs } 4068163953Srrs } 4069163953Srrs if (stcb != NULL) { 4070163953Srrs /* Already have or am bring up an association */ 4071171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4072163953Srrs error = EALREADY; 4073163953Srrs goto out_now; 4074163953Srrs } 4075168299Srrs vrf_id = inp->def_vrf_id; 4076163953Srrs /* We are GOOD to go */ 4077171531Srrs stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0, vrf_id, p); 4078163953Srrs if (stcb == NULL) { 4079163953Srrs /* Gak! no memory */ 4080167598Srrs goto out_now; 4081163953Srrs } 4082163953Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 4083163953Srrs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 4084163953Srrs /* Set the connected flag so we can queue data */ 4085163953Srrs soisconnecting(so); 4086163953Srrs } 4087171943Srrs SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); 4088169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 4089163953Srrs 4090163953Srrs /* initialize authentication parameters for the assoc */ 4091163953Srrs sctp_initialize_auth_params(inp, stcb); 4092163953Srrs 4093172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 4094168299Srrs SCTP_TCB_UNLOCK(stcb); 4095163953Srrsout_now: 4096169420Srrs if (create_lock_on) { 4097163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 4098169420Srrs } 4099163953Srrs SCTP_INP_DECR_REF(inp); 4100163953Srrs return error; 4101163953Srrs} 4102163953Srrs 4103163953Srrsint 4104163953Srrssctp_listen(struct socket *so, int backlog, struct thread *p) 4105163953Srrs{ 4106163953Srrs /* 4107163953Srrs * Note this module depends on the protocol processing being called 4108163953Srrs * AFTER any socket level flags and backlog are applied to the 4109163953Srrs * socket. The traditional way that the socket flags are applied is 4110163953Srrs * AFTER protocol processing. We have made a change to the 4111163953Srrs * sys/kern/uipc_socket.c module to reverse this but this MUST be in 4112163953Srrs * place if the socket API for SCTP is to work properly. 4113163953Srrs */ 4114163953Srrs 4115163953Srrs int error = 0; 4116163953Srrs struct sctp_inpcb *inp; 4117163953Srrs 4118163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 4119163953Srrs if (inp == 0) { 4120163953Srrs /* I made the same as TCP since we are not setup? */ 4121171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4122163953Srrs return (ECONNRESET); 4123163953Srrs } 4124163953Srrs SCTP_INP_RLOCK(inp); 4125163953Srrs#ifdef SCTP_LOCK_LOGGING 4126170744Srrs if (sctp_logging_level & SCTP_LOCK_LOGGING_ENABLE) { 4127170744Srrs sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK); 4128170744Srrs } 4129163953Srrs#endif 4130163953Srrs SOCK_LOCK(so); 4131163953Srrs error = solisten_proto_check(so); 4132163953Srrs if (error) { 4133163953Srrs SOCK_UNLOCK(so); 4134169208Srrs SCTP_INP_RUNLOCK(inp); 4135163953Srrs return (error); 4136163953Srrs } 4137163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 4138163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 4139163953Srrs /* We are already connected AND the TCP model */ 4140163953Srrs SCTP_INP_RUNLOCK(inp); 4141163953Srrs SOCK_UNLOCK(so); 4142171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 4143163953Srrs return (EADDRINUSE); 4144163953Srrs } 4145163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { 4146163953Srrs /* We must do a bind. */ 4147166675Srrs SOCK_UNLOCK(so); 4148163953Srrs SCTP_INP_RUNLOCK(inp); 4149171572Srrs if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) { 4150163953Srrs /* bind error, probably perm */ 4151163953Srrs return (error); 4152163953Srrs } 4153166675Srrs SOCK_LOCK(so); 4154163953Srrs } else { 4155163953Srrs SCTP_INP_RUNLOCK(inp); 4156163953Srrs } 4157163953Srrs /* It appears for 7.0 and on, we must always call this. */ 4158163953Srrs solisten_proto(so, backlog); 4159163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 4160163953Srrs /* remove the ACCEPTCONN flag for one-to-many sockets */ 4161163953Srrs so->so_options &= ~SO_ACCEPTCONN; 4162163953Srrs } 4163163953Srrs if (backlog == 0) { 4164163953Srrs /* turning off listen */ 4165163953Srrs so->so_options &= ~SO_ACCEPTCONN; 4166163953Srrs } 4167163953Srrs SOCK_UNLOCK(so); 4168163953Srrs return (error); 4169163953Srrs} 4170163953Srrs 4171163953Srrsstatic int sctp_defered_wakeup_cnt = 0; 4172163953Srrs 4173163953Srrsint 4174163953Srrssctp_accept(struct socket *so, struct sockaddr **addr) 4175163953Srrs{ 4176163953Srrs struct sctp_tcb *stcb; 4177163953Srrs struct sctp_inpcb *inp; 4178163953Srrs union sctp_sockstore store; 4179163953Srrs 4180163953Srrs int error; 4181163953Srrs 4182163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 4183163953Srrs 4184163953Srrs if (inp == 0) { 4185171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4186163953Srrs return (ECONNRESET); 4187163953Srrs } 4188163953Srrs SCTP_INP_RLOCK(inp); 4189163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 4190168299Srrs SCTP_INP_RUNLOCK(inp); 4191171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4192171943Srrs return (EOPNOTSUPP); 4193163953Srrs } 4194163953Srrs if (so->so_state & SS_ISDISCONNECTED) { 4195163953Srrs SCTP_INP_RUNLOCK(inp); 4196171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED); 4197163953Srrs return (ECONNABORTED); 4198163953Srrs } 4199163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 4200163953Srrs if (stcb == NULL) { 4201163953Srrs SCTP_INP_RUNLOCK(inp); 4202171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4203163953Srrs return (ECONNRESET); 4204163953Srrs } 4205163953Srrs SCTP_TCB_LOCK(stcb); 4206163953Srrs SCTP_INP_RUNLOCK(inp); 4207163953Srrs store = stcb->asoc.primary_destination->ro._l_addr; 4208163953Srrs SCTP_TCB_UNLOCK(stcb); 4209163953Srrs if (store.sa.sa_family == AF_INET) { 4210163953Srrs struct sockaddr_in *sin; 4211163953Srrs 4212163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 4213163953Srrs sin->sin_family = AF_INET; 4214163953Srrs sin->sin_len = sizeof(*sin); 4215163953Srrs sin->sin_port = ((struct sockaddr_in *)&store)->sin_port; 4216163953Srrs sin->sin_addr = ((struct sockaddr_in *)&store)->sin_addr; 4217163953Srrs *addr = (struct sockaddr *)sin; 4218163953Srrs } else { 4219163953Srrs struct sockaddr_in6 *sin6; 4220163953Srrs 4221163953Srrs SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); 4222163953Srrs sin6->sin6_family = AF_INET6; 4223163953Srrs sin6->sin6_len = sizeof(*sin6); 4224163953Srrs sin6->sin6_port = ((struct sockaddr_in6 *)&store)->sin6_port; 4225163953Srrs 4226163953Srrs sin6->sin6_addr = ((struct sockaddr_in6 *)&store)->sin6_addr; 4227164085Srrs if ((error = sa6_recoverscope(sin6)) != 0) { 4228164085Srrs SCTP_FREE_SONAME(sin6); 4229163953Srrs return (error); 4230164085Srrs } 4231163953Srrs *addr = (struct sockaddr *)sin6; 4232163953Srrs } 4233163953Srrs /* Wake any delayed sleep action */ 4234163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { 4235166086Srrs SCTP_INP_WLOCK(inp); 4236163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE; 4237163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) { 4238163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT; 4239166086Srrs SCTP_INP_WUNLOCK(inp); 4240163953Srrs SOCKBUF_LOCK(&inp->sctp_socket->so_snd); 4241163953Srrs if (sowriteable(inp->sctp_socket)) { 4242163953Srrs sowwakeup_locked(inp->sctp_socket); 4243163953Srrs } else { 4244163953Srrs SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd); 4245163953Srrs } 4246166086Srrs SCTP_INP_WLOCK(inp); 4247163953Srrs } 4248163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) { 4249163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT; 4250166086Srrs SCTP_INP_WUNLOCK(inp); 4251163953Srrs SOCKBUF_LOCK(&inp->sctp_socket->so_rcv); 4252163953Srrs if (soreadable(inp->sctp_socket)) { 4253163953Srrs sctp_defered_wakeup_cnt++; 4254163953Srrs sorwakeup_locked(inp->sctp_socket); 4255163953Srrs } else { 4256163953Srrs SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv); 4257163953Srrs } 4258166086Srrs SCTP_INP_WLOCK(inp); 4259163953Srrs } 4260166086Srrs SCTP_INP_WUNLOCK(inp); 4261163953Srrs } 4262163953Srrs return (0); 4263163953Srrs} 4264163953Srrs 4265163953Srrsint 4266163953Srrssctp_ingetaddr(struct socket *so, struct sockaddr **addr) 4267163953Srrs{ 4268163953Srrs struct sockaddr_in *sin; 4269167598Srrs uint32_t vrf_id; 4270163953Srrs struct sctp_inpcb *inp; 4271167695Srrs struct sctp_ifa *sctp_ifa; 4272163953Srrs 4273163953Srrs /* 4274163953Srrs * Do the malloc first in case it blocks. 4275163953Srrs */ 4276163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 4277163953Srrs sin->sin_family = AF_INET; 4278163953Srrs sin->sin_len = sizeof(*sin); 4279163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 4280163953Srrs if (!inp) { 4281163953Srrs SCTP_FREE_SONAME(sin); 4282171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4283163953Srrs return ECONNRESET; 4284163953Srrs } 4285163953Srrs SCTP_INP_RLOCK(inp); 4286163953Srrs sin->sin_port = inp->sctp_lport; 4287163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 4288163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 4289163953Srrs struct sctp_tcb *stcb; 4290163953Srrs struct sockaddr_in *sin_a; 4291163953Srrs struct sctp_nets *net; 4292163953Srrs int fnd; 4293163953Srrs 4294163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 4295163953Srrs if (stcb == NULL) { 4296163953Srrs goto notConn; 4297163953Srrs } 4298163953Srrs fnd = 0; 4299163953Srrs sin_a = NULL; 4300163953Srrs SCTP_TCB_LOCK(stcb); 4301163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4302163953Srrs sin_a = (struct sockaddr_in *)&net->ro._l_addr; 4303164085Srrs if (sin_a == NULL) 4304164085Srrs /* this will make coverity happy */ 4305164085Srrs continue; 4306164085Srrs 4307163953Srrs if (sin_a->sin_family == AF_INET) { 4308163953Srrs fnd = 1; 4309163953Srrs break; 4310163953Srrs } 4311163953Srrs } 4312163953Srrs if ((!fnd) || (sin_a == NULL)) { 4313163953Srrs /* punt */ 4314163953Srrs SCTP_TCB_UNLOCK(stcb); 4315163953Srrs goto notConn; 4316163953Srrs } 4317168299Srrs vrf_id = inp->def_vrf_id; 4318167598Srrs sctp_ifa = sctp_source_address_selection(inp, 4319167598Srrs stcb, 4320168299Srrs (sctp_route_t *) & net->ro, 4321167598Srrs net, 0, vrf_id); 4322167598Srrs if (sctp_ifa) { 4323167598Srrs sin->sin_addr = sctp_ifa->address.sin.sin_addr; 4324167598Srrs sctp_free_ifa(sctp_ifa); 4325167598Srrs } 4326163953Srrs SCTP_TCB_UNLOCK(stcb); 4327163953Srrs } else { 4328163953Srrs /* For the bound all case you get back 0 */ 4329163953Srrs notConn: 4330163953Srrs sin->sin_addr.s_addr = 0; 4331163953Srrs } 4332163953Srrs 4333163953Srrs } else { 4334163953Srrs /* Take the first IPv4 address in the list */ 4335163953Srrs struct sctp_laddr *laddr; 4336163953Srrs int fnd = 0; 4337163953Srrs 4338163953Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 4339167598Srrs if (laddr->ifa->address.sa.sa_family == AF_INET) { 4340163953Srrs struct sockaddr_in *sin_a; 4341163953Srrs 4342167598Srrs sin_a = (struct sockaddr_in *)&laddr->ifa->address.sa; 4343163953Srrs sin->sin_addr = sin_a->sin_addr; 4344163953Srrs fnd = 1; 4345163953Srrs break; 4346163953Srrs } 4347163953Srrs } 4348163953Srrs if (!fnd) { 4349163953Srrs SCTP_FREE_SONAME(sin); 4350163953Srrs SCTP_INP_RUNLOCK(inp); 4351171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4352163953Srrs return ENOENT; 4353163953Srrs } 4354163953Srrs } 4355163953Srrs SCTP_INP_RUNLOCK(inp); 4356163953Srrs (*addr) = (struct sockaddr *)sin; 4357163953Srrs return (0); 4358163953Srrs} 4359163953Srrs 4360163953Srrsint 4361163953Srrssctp_peeraddr(struct socket *so, struct sockaddr **addr) 4362163953Srrs{ 4363163953Srrs struct sockaddr_in *sin = (struct sockaddr_in *)*addr; 4364166086Srrs int fnd; 4365163953Srrs struct sockaddr_in *sin_a; 4366163953Srrs struct sctp_inpcb *inp; 4367163953Srrs struct sctp_tcb *stcb; 4368163953Srrs struct sctp_nets *net; 4369163953Srrs 4370163953Srrs /* Do the malloc first in case it blocks. */ 4371163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 4372163953Srrs if ((inp == NULL) || 4373163953Srrs ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { 4374163953Srrs /* UDP type and listeners will drop out here */ 4375171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 4376163953Srrs return (ENOTCONN); 4377163953Srrs } 4378163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 4379163953Srrs sin->sin_family = AF_INET; 4380163953Srrs sin->sin_len = sizeof(*sin); 4381163953Srrs 4382163953Srrs /* We must recapture incase we blocked */ 4383163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 4384163953Srrs if (!inp) { 4385163953Srrs SCTP_FREE_SONAME(sin); 4386171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4387163953Srrs return ECONNRESET; 4388163953Srrs } 4389163953Srrs SCTP_INP_RLOCK(inp); 4390163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 4391169420Srrs if (stcb) { 4392163953Srrs SCTP_TCB_LOCK(stcb); 4393169420Srrs } 4394163953Srrs SCTP_INP_RUNLOCK(inp); 4395163953Srrs if (stcb == NULL) { 4396163953Srrs SCTP_FREE_SONAME(sin); 4397171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4398163953Srrs return ECONNRESET; 4399163953Srrs } 4400163953Srrs fnd = 0; 4401163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4402163953Srrs sin_a = (struct sockaddr_in *)&net->ro._l_addr; 4403163953Srrs if (sin_a->sin_family == AF_INET) { 4404163953Srrs fnd = 1; 4405163953Srrs sin->sin_port = stcb->rport; 4406163953Srrs sin->sin_addr = sin_a->sin_addr; 4407163953Srrs break; 4408163953Srrs } 4409163953Srrs } 4410163953Srrs SCTP_TCB_UNLOCK(stcb); 4411163953Srrs if (!fnd) { 4412163953Srrs /* No IPv4 address */ 4413163953Srrs SCTP_FREE_SONAME(sin); 4414171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4415163953Srrs return ENOENT; 4416163953Srrs } 4417163953Srrs (*addr) = (struct sockaddr *)sin; 4418163953Srrs return (0); 4419163953Srrs} 4420163953Srrs 4421163953Srrsstruct pr_usrreqs sctp_usrreqs = { 4422163953Srrs .pru_abort = sctp_abort, 4423163953Srrs .pru_accept = sctp_accept, 4424163953Srrs .pru_attach = sctp_attach, 4425163953Srrs .pru_bind = sctp_bind, 4426163953Srrs .pru_connect = sctp_connect, 4427163953Srrs .pru_control = in_control, 4428163953Srrs .pru_close = sctp_close, 4429163953Srrs .pru_detach = sctp_close, 4430163953Srrs .pru_sopoll = sopoll_generic, 4431163953Srrs .pru_disconnect = sctp_disconnect, 4432163953Srrs .pru_listen = sctp_listen, 4433163953Srrs .pru_peeraddr = sctp_peeraddr, 4434163953Srrs .pru_send = sctp_sendm, 4435163953Srrs .pru_shutdown = sctp_shutdown, 4436163953Srrs .pru_sockaddr = sctp_ingetaddr, 4437163953Srrs .pru_sosend = sctp_sosend, 4438163953Srrs .pru_soreceive = sctp_soreceive 4439163953Srrs}; 4440