sctp_usrreq.c revision 233005
1163953Srrs/*- 2185694Srrs * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. 3218319Srrs * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved. 4218319Srrs * Copyright (c) 2008-2011, by Michael Tuexen. All rights reserved. 5163953Srrs * 6163953Srrs * Redistribution and use in source and binary forms, with or without 7163953Srrs * modification, are permitted provided that the following conditions are met: 8163953Srrs * 9163953Srrs * a) Redistributions of source code must retain the above copyright notice, 10228653Stuexen * this list of conditions and the following disclaimer. 11163953Srrs * 12163953Srrs * b) Redistributions in binary form must reproduce the above copyright 13163953Srrs * notice, this list of conditions and the following disclaimer in 14228653Stuexen * the documentation and/or other materials provided with the distribution. 15163953Srrs * 16163953Srrs * c) Neither the name of Cisco Systems, Inc. nor the names of its 17163953Srrs * contributors may be used to endorse or promote products derived 18163953Srrs * from this software without specific prior written permission. 19163953Srrs * 20163953Srrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21163953Srrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22163953Srrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24163953Srrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25163953Srrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26163953Srrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27163953Srrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28163953Srrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29163953Srrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30163953Srrs * THE POSSIBILITY OF SUCH DAMAGE. 31163953Srrs */ 32163953Srrs 33163953Srrs/* $KAME: sctp_usrreq.c,v 1.48 2005/03/07 23:26:08 itojun Exp $ */ 34163953Srrs 35163953Srrs#include <sys/cdefs.h> 36163953Srrs__FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 233005 2012-03-15 14:22:05Z tuexen $"); 37166086Srrs#include <netinet/sctp_os.h> 38163953Srrs#include <sys/proc.h> 39163953Srrs#include <netinet/sctp_pcb.h> 40163953Srrs#include <netinet/sctp_header.h> 41163953Srrs#include <netinet/sctp_var.h> 42167695Srrs#if defined(INET6) 43167695Srrs#endif 44167598Srrs#include <netinet/sctp_sysctl.h> 45163953Srrs#include <netinet/sctp_output.h> 46163953Srrs#include <netinet/sctp_uio.h> 47163953Srrs#include <netinet/sctp_asconf.h> 48163953Srrs#include <netinet/sctputil.h> 49163953Srrs#include <netinet/sctp_indata.h> 50163953Srrs#include <netinet/sctp_timer.h> 51163953Srrs#include <netinet/sctp_auth.h> 52170091Srrs#include <netinet/sctp_bsd_addr.h> 53185694Srrs#include <netinet/udp.h> 54164085Srrs 55163953Srrs 56163953Srrs 57217611Stuexenextern struct sctp_cc_functions sctp_cc_functions[]; 58217760Stuexenextern struct sctp_ss_functions sctp_ss_functions[]; 59170091Srrs 60163953Srrsvoid 61163953Srrssctp_init(void) 62163953Srrs{ 63163953Srrs u_long sb_max_adj; 64163953Srrs 65179783Srrs /* Initialize and modify the sysctled variables */ 66179783Srrs sctp_init_sysctls(); 67163953Srrs if ((nmbclusters / 8) > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE) 68179783Srrs SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue) = (nmbclusters / 8); 69163953Srrs /* 70163953Srrs * Allow a user to take no more than 1/2 the number of clusters or 71163953Srrs * the SB_MAX whichever is smaller for the send window. 72163953Srrs */ 73163953Srrs sb_max_adj = (u_long)((u_quad_t) (SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES)); 74179783Srrs SCTP_BASE_SYSCTL(sctp_sendspace) = min(sb_max_adj, 75170056Srrs (((uint32_t) nmbclusters / 2) * SCTP_DEFAULT_MAXSEGMENT)); 76163953Srrs /* 77163953Srrs * Now for the recv window, should we take the same amount? or 78163953Srrs * should I do 1/2 the SB_MAX instead in the SB_MAX min above. For 79163953Srrs * now I will just copy. 80163953Srrs */ 81179783Srrs SCTP_BASE_SYSCTL(sctp_recvspace) = SCTP_BASE_SYSCTL(sctp_sendspace); 82163953Srrs 83179783Srrs SCTP_BASE_VAR(first_time) = 0; 84179783Srrs SCTP_BASE_VAR(sctp_pcb_initialized) = 0; 85179783Srrs sctp_pcb_init(); 86179783Srrs#if defined(SCTP_PACKET_LOGGING) 87179783Srrs SCTP_BASE_VAR(packet_log_writers) = 0; 88179783Srrs SCTP_BASE_VAR(packet_log_end) = 0; 89179783Srrs bzero(&SCTP_BASE_VAR(packet_log_buffer), SCTP_PACKET_LOG_SIZE); 90179783Srrs#endif 91179783Srrs 92179783Srrs 93163953Srrs} 94163953Srrs 95179783Srrsvoid 96179783Srrssctp_finish(void) 97179783Srrs{ 98179783Srrs sctp_pcb_finish(); 99179783Srrs} 100163953Srrs 101166023Srrs 102163953Srrs 103179157Srrsvoid 104228653Stuexensctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint16_t nxtsz) 105163953Srrs{ 106163953Srrs struct sctp_tmit_chunk *chk; 107197257Stuexen uint16_t overhead; 108163953Srrs 109163953Srrs /* Adjust that too */ 110163953Srrs stcb->asoc.smallest_mtu = nxtsz; 111163953Srrs /* now off to subtract IP_DF flag if needed */ 112197257Stuexen overhead = IP_HDR_SIZE; 113197257Stuexen if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) { 114197257Stuexen overhead += sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); 115197257Stuexen } 116163953Srrs TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) { 117197257Stuexen if ((chk->send_size + overhead) > nxtsz) { 118163953Srrs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 119163953Srrs } 120163953Srrs } 121163953Srrs TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 122197257Stuexen if ((chk->send_size + overhead) > nxtsz) { 123163953Srrs /* 124163953Srrs * For this guy we also mark for immediate resend 125163953Srrs * since we sent to big of chunk 126163953Srrs */ 127163953Srrs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 128190689Srrs if (chk->sent < SCTP_DATAGRAM_RESEND) { 129190689Srrs sctp_flight_size_decrease(chk); 130190689Srrs sctp_total_flight_decrease(stcb, chk); 131190689Srrs } 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; 137179783Srrs if (SCTP_BASE_SYSCTL(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; 146163953Srrs } 147163953Srrs } 148163953Srrs} 149163953Srrs 150221249Stuexen#ifdef INET 151163953Srrsstatic void 152163953Srrssctp_notify_mbuf(struct sctp_inpcb *inp, 153163953Srrs struct sctp_tcb *stcb, 154163953Srrs struct sctp_nets *net, 155163953Srrs struct ip *ip, 156163953Srrs struct sctphdr *sh) 157163953Srrs{ 158163953Srrs struct icmp *icmph; 159163953Srrs int totsz, tmr_stopped = 0; 160163953Srrs uint16_t nxtsz; 161163953Srrs 162163953Srrs /* protection */ 163163953Srrs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 164163953Srrs (ip == NULL) || (sh == NULL)) { 165169420Srrs if (stcb != NULL) { 166163953Srrs SCTP_TCB_UNLOCK(stcb); 167169420Srrs } 168163953Srrs return; 169163953Srrs } 170163953Srrs /* First job is to verify the vtag matches what I would send */ 171163953Srrs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 172163953Srrs SCTP_TCB_UNLOCK(stcb); 173163953Srrs return; 174163953Srrs } 175163953Srrs icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) - 176163953Srrs sizeof(struct ip))); 177163953Srrs if (icmph->icmp_type != ICMP_UNREACH) { 178163953Srrs /* We only care about unreachable */ 179163953Srrs SCTP_TCB_UNLOCK(stcb); 180163953Srrs return; 181163953Srrs } 182163953Srrs if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) { 183163953Srrs /* not a unreachable message due to frag. */ 184163953Srrs SCTP_TCB_UNLOCK(stcb); 185163953Srrs return; 186163953Srrs } 187163953Srrs totsz = ip->ip_len; 188163953Srrs 189171943Srrs nxtsz = ntohs(icmph->icmp_nextmtu); 190163953Srrs if (nxtsz == 0) { 191163953Srrs /* 192163953Srrs * old type router that does not tell us what the next size 193163953Srrs * mtu is. Rats we will have to guess (in a educated fashion 194163953Srrs * of course) 195163953Srrs */ 196214939Stuexen nxtsz = sctp_get_prev_mtu(totsz); 197163953Srrs } 198163953Srrs /* Stop any PMTU timer */ 199165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 200163953Srrs tmr_stopped = 1; 201165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 202165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1); 203163953Srrs } 204163953Srrs /* Adjust destination size limit */ 205163953Srrs if (net->mtu > nxtsz) { 206163953Srrs net->mtu = nxtsz; 207185694Srrs if (net->port) { 208185694Srrs net->mtu -= sizeof(struct udphdr); 209185694Srrs } 210163953Srrs } 211163953Srrs /* now what about the ep? */ 212163953Srrs if (stcb->asoc.smallest_mtu > nxtsz) { 213228653Stuexen sctp_pathmtu_adjustment(stcb, nxtsz); 214163953Srrs } 215163953Srrs if (tmr_stopped) 216163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 217163953Srrs 218163953Srrs SCTP_TCB_UNLOCK(stcb); 219163953Srrs} 220163953Srrs 221221249Stuexen#endif 222163953Srrs 223163953Srrsvoid 224163953Srrssctp_notify(struct sctp_inpcb *inp, 225172091Srrs struct ip *ip, 226163953Srrs struct sctphdr *sh, 227163953Srrs struct sockaddr *to, 228163953Srrs struct sctp_tcb *stcb, 229163953Srrs struct sctp_nets *net) 230163953Srrs{ 231172090Srrs#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 232172090Srrs struct socket *so; 233172090Srrs 234172090Srrs#endif 235163953Srrs /* protection */ 236172091Srrs int reason; 237172091Srrs struct icmp *icmph; 238172091Srrs 239172091Srrs 240163953Srrs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 241163953Srrs (sh == NULL) || (to == NULL)) { 242172091Srrs if (stcb) 243172091Srrs SCTP_TCB_UNLOCK(stcb); 244163953Srrs return; 245163953Srrs } 246163953Srrs /* First job is to verify the vtag matches what I would send */ 247163953Srrs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 248172091Srrs SCTP_TCB_UNLOCK(stcb); 249163953Srrs return; 250163953Srrs } 251172091Srrs icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) - 252172091Srrs sizeof(struct ip))); 253172091Srrs if (icmph->icmp_type != ICMP_UNREACH) { 254172091Srrs /* We only care about unreachable */ 255172091Srrs SCTP_TCB_UNLOCK(stcb); 256172091Srrs return; 257172091Srrs } 258172091Srrs if ((icmph->icmp_code == ICMP_UNREACH_NET) || 259172091Srrs (icmph->icmp_code == ICMP_UNREACH_HOST) || 260172091Srrs (icmph->icmp_code == ICMP_UNREACH_NET_UNKNOWN) || 261172091Srrs (icmph->icmp_code == ICMP_UNREACH_HOST_UNKNOWN) || 262172091Srrs (icmph->icmp_code == ICMP_UNREACH_ISOLATED) || 263172091Srrs (icmph->icmp_code == ICMP_UNREACH_NET_PROHIB) || 264172091Srrs (icmph->icmp_code == ICMP_UNREACH_HOST_PROHIB) || 265172091Srrs (icmph->icmp_code == ICMP_UNREACH_FILTER_PROHIB)) { 266163953Srrs 267163953Srrs /* 268163953Srrs * Hmm reachablity problems we must examine closely. If its 269163953Srrs * not reachable, we may have lost a network. Or if there is 270163953Srrs * NO protocol at the other end named SCTP. well we consider 271163953Srrs * it a OOTB abort. 272163953Srrs */ 273172091Srrs if (net->dest_state & SCTP_ADDR_REACHABLE) { 274172091Srrs /* Ok that destination is NOT reachable */ 275172091Srrs net->dest_state &= ~SCTP_ADDR_REACHABLE; 276224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 277172091Srrs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, 278172091Srrs stcb, SCTP_FAILED_THRESHOLD, 279172091Srrs (void *)net, SCTP_SO_NOT_LOCKED); 280172091Srrs } 281172091Srrs SCTP_TCB_UNLOCK(stcb); 282172091Srrs } else if ((icmph->icmp_code == ICMP_UNREACH_PROTOCOL) || 283172091Srrs (icmph->icmp_code == ICMP_UNREACH_PORT)) { 284172091Srrs /* 285172091Srrs * Here the peer is either playing tricks on us, including 286172091Srrs * an address that belongs to someone who does not support 287172091Srrs * SCTP OR was a userland implementation that shutdown and 288172091Srrs * now is dead. In either case treat it like a OOTB abort 289172091Srrs * with no TCB 290172091Srrs */ 291172091Srrs reason = SCTP_PEER_FAULTY; 292172091Srrs sctp_abort_notification(stcb, reason, SCTP_SO_NOT_LOCKED); 293172090Srrs#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 294172091Srrs so = SCTP_INP_SO(inp); 295172091Srrs atomic_add_int(&stcb->asoc.refcnt, 1); 296172091Srrs SCTP_TCB_UNLOCK(stcb); 297172091Srrs SCTP_SOCKET_LOCK(so, 1); 298172091Srrs SCTP_TCB_LOCK(stcb); 299172091Srrs atomic_subtract_int(&stcb->asoc.refcnt, 1); 300172090Srrs#endif 301172091Srrs (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); 302172090Srrs#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 303172091Srrs SCTP_SOCKET_UNLOCK(so, 1); 304172091Srrs /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */ 305172090Srrs#endif 306172091Srrs /* no need to unlock here, since the TCB is gone */ 307163953Srrs } else { 308172091Srrs SCTP_TCB_UNLOCK(stcb); 309163953Srrs } 310163953Srrs} 311163953Srrs 312221249Stuexen#ifdef INET 313163953Srrsvoid 314163953Srrssctp_ctlinput(cmd, sa, vip) 315163953Srrs int cmd; 316163953Srrs struct sockaddr *sa; 317163953Srrs void *vip; 318163953Srrs{ 319163953Srrs struct ip *ip = vip; 320163953Srrs struct sctphdr *sh; 321167598Srrs uint32_t vrf_id; 322163953Srrs 323168299Srrs /* FIX, for non-bsd is this right? */ 324167598Srrs vrf_id = SCTP_DEFAULT_VRFID; 325163953Srrs if (sa->sa_family != AF_INET || 326163953Srrs ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) { 327163953Srrs return; 328163953Srrs } 329163953Srrs if (PRC_IS_REDIRECT(cmd)) { 330163953Srrs ip = 0; 331163953Srrs } else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) { 332163953Srrs return; 333163953Srrs } 334163953Srrs if (ip) { 335163953Srrs struct sctp_inpcb *inp = NULL; 336163953Srrs struct sctp_tcb *stcb = NULL; 337163953Srrs struct sctp_nets *net = NULL; 338163953Srrs struct sockaddr_in to, from; 339163953Srrs 340163953Srrs sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 341163953Srrs bzero(&to, sizeof(to)); 342163953Srrs bzero(&from, sizeof(from)); 343163953Srrs from.sin_family = to.sin_family = AF_INET; 344163953Srrs from.sin_len = to.sin_len = sizeof(to); 345163953Srrs from.sin_port = sh->src_port; 346163953Srrs from.sin_addr = ip->ip_src; 347163953Srrs to.sin_port = sh->dest_port; 348163953Srrs to.sin_addr = ip->ip_dst; 349163953Srrs 350163953Srrs /* 351163953Srrs * 'to' holds the dest of the packet that failed to be sent. 352163953Srrs * 'from' holds our local endpoint address. Thus we reverse 353163953Srrs * the to and the from in the lookup. 354163953Srrs */ 355163953Srrs stcb = sctp_findassociation_addr_sa((struct sockaddr *)&from, 356163953Srrs (struct sockaddr *)&to, 357167598Srrs &inp, &net, 1, vrf_id); 358163953Srrs if (stcb != NULL && inp && (inp->sctp_socket != NULL)) { 359163953Srrs if (cmd != PRC_MSGSIZE) { 360172091Srrs sctp_notify(inp, ip, sh, 361163953Srrs (struct sockaddr *)&to, stcb, 362163953Srrs net); 363163953Srrs } else { 364163953Srrs /* handle possible ICMP size messages */ 365163953Srrs sctp_notify_mbuf(inp, stcb, net, ip, sh); 366163953Srrs } 367163953Srrs } else { 368163953Srrs if ((stcb == NULL) && (inp != NULL)) { 369163953Srrs /* reduce ref-count */ 370163953Srrs SCTP_INP_WLOCK(inp); 371163953Srrs SCTP_INP_DECR_REF(inp); 372163953Srrs SCTP_INP_WUNLOCK(inp); 373163953Srrs } 374209029Srrs if (stcb) { 375209029Srrs SCTP_TCB_UNLOCK(stcb); 376209029Srrs } 377163953Srrs } 378163953Srrs } 379163953Srrs return; 380163953Srrs} 381163953Srrs 382221249Stuexen#endif 383221249Stuexen 384163953Srrsstatic int 385163953Srrssctp_getcred(SYSCTL_HANDLER_ARGS) 386163953Srrs{ 387164085Srrs struct xucred xuc; 388163953Srrs struct sockaddr_in addrs[2]; 389163953Srrs struct sctp_inpcb *inp; 390163953Srrs struct sctp_nets *net; 391163953Srrs struct sctp_tcb *stcb; 392164085Srrs int error; 393167598Srrs uint32_t vrf_id; 394163953Srrs 395168299Srrs /* FIX, for non-bsd is this right? */ 396167598Srrs vrf_id = SCTP_DEFAULT_VRFID; 397168299Srrs 398170587Srwatson error = priv_check(req->td, PRIV_NETINET_GETCRED); 399170587Srwatson 400163953Srrs if (error) 401163953Srrs return (error); 402164039Srwatson 403163953Srrs error = SYSCTL_IN(req, addrs, sizeof(addrs)); 404163953Srrs if (error) 405163953Srrs return (error); 406163953Srrs 407163953Srrs stcb = sctp_findassociation_addr_sa(sintosa(&addrs[0]), 408163953Srrs sintosa(&addrs[1]), 409167598Srrs &inp, &net, 1, vrf_id); 410163953Srrs if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) { 411163953Srrs if ((inp != NULL) && (stcb == NULL)) { 412163953Srrs /* reduce ref-count */ 413163953Srrs SCTP_INP_WLOCK(inp); 414163953Srrs SCTP_INP_DECR_REF(inp); 415164085Srrs goto cred_can_cont; 416163953Srrs } 417171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 418163953Srrs error = ENOENT; 419163953Srrs goto out; 420163953Srrs } 421163953Srrs SCTP_TCB_UNLOCK(stcb); 422164085Srrs /* 423164085Srrs * We use the write lock here, only since in the error leg we need 424164085Srrs * it. If we used RLOCK, then we would have to 425164085Srrs * wlock/decr/unlock/rlock. Which in theory could create a hole. 426164085Srrs * Better to use higher wlock. 427164085Srrs */ 428164085Srrs SCTP_INP_WLOCK(inp); 429164085Srrscred_can_cont: 430164085Srrs error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket); 431164085Srrs if (error) { 432164085Srrs SCTP_INP_WUNLOCK(inp); 433164085Srrs goto out; 434164085Srrs } 435164085Srrs cru2x(inp->sctp_socket->so_cred, &xuc); 436164085Srrs SCTP_INP_WUNLOCK(inp); 437164085Srrs error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); 438163953Srrsout: 439163953Srrs return (error); 440163953Srrs} 441163953Srrs 442163953SrrsSYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW, 443163953Srrs 0, 0, sctp_getcred, "S,ucred", "Get the ucred of a SCTP connection"); 444163953Srrs 445163953Srrs 446221249Stuexen#ifdef INET 447163953Srrsstatic void 448163953Srrssctp_abort(struct socket *so) 449163953Srrs{ 450163953Srrs struct sctp_inpcb *inp; 451163953Srrs uint32_t flags; 452163953Srrs 453163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 454233005Stuexen if (inp == NULL) { 455163953Srrs return; 456171943Srrs } 457163953Srrssctp_must_try_again: 458163953Srrs flags = inp->sctp_flags; 459163953Srrs#ifdef SCTP_LOG_CLOSING 460163953Srrs sctp_log_closing(inp, NULL, 17); 461163953Srrs#endif 462163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 463163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 464163953Srrs#ifdef SCTP_LOG_CLOSING 465163953Srrs sctp_log_closing(inp, NULL, 16); 466163953Srrs#endif 467169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 468169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 469163953Srrs SOCK_LOCK(so); 470167695Srrs SCTP_SB_CLEAR(so->so_snd); 471163953Srrs /* 472163953Srrs * same for the rcv ones, they are only here for the 473163953Srrs * accounting/select. 474163953Srrs */ 475167695Srrs SCTP_SB_CLEAR(so->so_rcv); 476167695Srrs 477167695Srrs /* Now null out the reference, we are completely detached. */ 478163953Srrs so->so_pcb = NULL; 479163953Srrs SOCK_UNLOCK(so); 480163953Srrs } else { 481163953Srrs flags = inp->sctp_flags; 482163953Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 483163953Srrs goto sctp_must_try_again; 484163953Srrs } 485163953Srrs } 486163953Srrs return; 487163953Srrs} 488163953Srrs 489163953Srrsstatic int 490228653Stuexensctp_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED) 491163953Srrs{ 492163953Srrs struct sctp_inpcb *inp; 493163953Srrs struct inpcb *ip_inp; 494166086Srrs int error; 495170205Srrs uint32_t vrf_id = SCTP_DEFAULT_VRFID; 496185694Srrs 497171167Sgnn#ifdef IPSEC 498163953Srrs uint32_t flags; 499185694Srrs 500185435Sbz#endif 501171440Srrs 502163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 503163953Srrs if (inp != 0) { 504171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 505228907Stuexen return (EINVAL); 506163953Srrs } 507184030Srrs if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 508184030Srrs error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace)); 509184030Srrs if (error) { 510228907Stuexen return (error); 511184030Srrs } 512163953Srrs } 513170205Srrs error = sctp_inpcb_alloc(so, vrf_id); 514163953Srrs if (error) { 515228907Stuexen return (error); 516163953Srrs } 517163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 518163953Srrs SCTP_INP_WLOCK(inp); 519163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6; /* I'm not v6! */ 520163953Srrs ip_inp = &inp->ip_inp.inp; 521163953Srrs ip_inp->inp_vflag |= INP_IPV4; 522197288Srrs ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl); 523171167Sgnn#ifdef IPSEC 524171133Sgnn error = ipsec_init_policy(so, &ip_inp->inp_sp); 525163953Srrs#ifdef SCTP_LOG_CLOSING 526163953Srrs sctp_log_closing(inp, NULL, 17); 527163953Srrs#endif 528163953Srrs if (error != 0) { 529202523Srrstry_again: 530163953Srrs flags = inp->sctp_flags; 531163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 532163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 533163953Srrs#ifdef SCTP_LOG_CLOSING 534163953Srrs sctp_log_closing(inp, NULL, 15); 535163953Srrs#endif 536169352Srrs SCTP_INP_WUNLOCK(inp); 537169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 538169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 539169254Srrs } else { 540202523Srrs flags = inp->sctp_flags; 541202523Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 542202523Srrs goto try_again; 543202523Srrs } else { 544202523Srrs SCTP_INP_WUNLOCK(inp); 545202523Srrs } 546163953Srrs } 547228907Stuexen return (error); 548163953Srrs } 549171167Sgnn#endif /* IPSEC */ 550163953Srrs SCTP_INP_WUNLOCK(inp); 551228907Stuexen return (0); 552163953Srrs} 553163953Srrs 554163953Srrsstatic int 555163953Srrssctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p) 556163953Srrs{ 557171943Srrs struct sctp_inpcb *inp = NULL; 558166086Srrs int error; 559163953Srrs 560225571Stuexen#ifdef INET 561171943Srrs if (addr && addr->sa_family != AF_INET) { 562163953Srrs /* must be a v4 address! */ 563171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 564228907Stuexen return (EINVAL); 565171943Srrs } 566163953Srrs#endif /* INET6 */ 567170056Srrs if (addr && (addr->sa_len != sizeof(struct sockaddr_in))) { 568171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 569228907Stuexen return (EINVAL); 570170056Srrs } 571163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 572233005Stuexen if (inp == NULL) { 573171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 574228907Stuexen return (EINVAL); 575171943Srrs } 576171572Srrs error = sctp_inpcb_bind(so, addr, NULL, p); 577228907Stuexen return (error); 578163953Srrs} 579163953Srrs 580221249Stuexen#endif 581171990Srrsvoid 582163953Srrssctp_close(struct socket *so) 583163953Srrs{ 584163953Srrs struct sctp_inpcb *inp; 585163953Srrs uint32_t flags; 586163953Srrs 587163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 588233005Stuexen if (inp == NULL) 589163953Srrs return; 590163953Srrs 591163953Srrs /* 592163953Srrs * Inform all the lower layer assoc that we are done. 593163953Srrs */ 594163953Srrssctp_must_try_again: 595163953Srrs flags = inp->sctp_flags; 596163953Srrs#ifdef SCTP_LOG_CLOSING 597163953Srrs sctp_log_closing(inp, NULL, 17); 598163953Srrs#endif 599163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 600163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 601163953Srrs if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || 602163953Srrs (so->so_rcv.sb_cc > 0)) { 603163953Srrs#ifdef SCTP_LOG_CLOSING 604163953Srrs sctp_log_closing(inp, NULL, 13); 605163953Srrs#endif 606169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 607169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 608163953Srrs } else { 609163953Srrs#ifdef SCTP_LOG_CLOSING 610163953Srrs sctp_log_closing(inp, NULL, 14); 611163953Srrs#endif 612169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE, 613169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 614163953Srrs } 615163953Srrs /* 616163953Srrs * The socket is now detached, no matter what the state of 617163953Srrs * the SCTP association. 618163953Srrs */ 619163953Srrs SOCK_LOCK(so); 620167695Srrs SCTP_SB_CLEAR(so->so_snd); 621163953Srrs /* 622163953Srrs * same for the rcv ones, they are only here for the 623163953Srrs * accounting/select. 624163953Srrs */ 625167695Srrs SCTP_SB_CLEAR(so->so_rcv); 626167695Srrs 627167695Srrs /* Now null out the reference, we are completely detached. */ 628163953Srrs so->so_pcb = NULL; 629163953Srrs SOCK_UNLOCK(so); 630163953Srrs } else { 631163953Srrs flags = inp->sctp_flags; 632163953Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 633163953Srrs goto sctp_must_try_again; 634163953Srrs } 635163953Srrs } 636163953Srrs return; 637163953Srrs} 638163953Srrs 639163953Srrs 640163953Srrsint 641163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 642163953Srrs struct mbuf *control, struct thread *p); 643163953Srrs 644163953Srrs 645163953Srrsint 646163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 647163953Srrs struct mbuf *control, struct thread *p) 648163953Srrs{ 649163953Srrs struct sctp_inpcb *inp; 650163953Srrs int error; 651163953Srrs 652163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 653233005Stuexen if (inp == NULL) { 654163953Srrs if (control) { 655163953Srrs sctp_m_freem(control); 656163953Srrs control = NULL; 657163953Srrs } 658171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 659163953Srrs sctp_m_freem(m); 660228907Stuexen return (EINVAL); 661163953Srrs } 662163953Srrs /* Got to have an to address if we are NOT a connected socket */ 663163953Srrs if ((addr == NULL) && 664163953Srrs ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) || 665228907Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE))) { 666163953Srrs goto connected_type; 667163953Srrs } else if (addr == NULL) { 668171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); 669163953Srrs error = EDESTADDRREQ; 670163953Srrs sctp_m_freem(m); 671163953Srrs if (control) { 672163953Srrs sctp_m_freem(control); 673163953Srrs control = NULL; 674163953Srrs } 675163953Srrs return (error); 676163953Srrs } 677163953Srrs#ifdef INET6 678163953Srrs if (addr->sa_family != AF_INET) { 679163953Srrs /* must be a v4 address! */ 680171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); 681163953Srrs sctp_m_freem(m); 682163953Srrs if (control) { 683163953Srrs sctp_m_freem(control); 684163953Srrs control = NULL; 685163953Srrs } 686163953Srrs error = EDESTADDRREQ; 687223132Stuexen return (error); 688163953Srrs } 689163953Srrs#endif /* INET6 */ 690163953Srrsconnected_type: 691163953Srrs /* now what about control */ 692163953Srrs if (control) { 693163953Srrs if (inp->control) { 694169420Srrs SCTP_PRINTF("huh? control set?\n"); 695163953Srrs sctp_m_freem(inp->control); 696163953Srrs inp->control = NULL; 697163953Srrs } 698163953Srrs inp->control = control; 699163953Srrs } 700163953Srrs /* Place the data */ 701163953Srrs if (inp->pkt) { 702165647Srrs SCTP_BUF_NEXT(inp->pkt_last) = m; 703163953Srrs inp->pkt_last = m; 704163953Srrs } else { 705163953Srrs inp->pkt_last = inp->pkt = m; 706163953Srrs } 707163953Srrs if ( 708163953Srrs /* FreeBSD uses a flag passed */ 709163953Srrs ((flags & PRUS_MORETOCOME) == 0) 710163953Srrs ) { 711163953Srrs /* 712163953Srrs * note with the current version this code will only be used 713163953Srrs * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for 714163953Srrs * re-defining sosend to use the sctp_sosend. One can 715163953Srrs * optionally switch back to this code (by changing back the 716163953Srrs * definitions) but this is not advisable. This code is used 717163953Srrs * by FreeBSD when sending a file with sendfile() though. 718163953Srrs */ 719163953Srrs int ret; 720163953Srrs 721163953Srrs ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags); 722163953Srrs inp->pkt = NULL; 723163953Srrs inp->control = NULL; 724163953Srrs return (ret); 725163953Srrs } else { 726163953Srrs return (0); 727163953Srrs } 728163953Srrs} 729163953Srrs 730171990Srrsint 731163953Srrssctp_disconnect(struct socket *so) 732163953Srrs{ 733163953Srrs struct sctp_inpcb *inp; 734163953Srrs 735163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 736163953Srrs if (inp == NULL) { 737171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 738163953Srrs return (ENOTCONN); 739163953Srrs } 740163953Srrs SCTP_INP_RLOCK(inp); 741171745Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 742171745Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 743199437Stuexen if (LIST_EMPTY(&inp->sctp_asoc_list)) { 744163953Srrs /* No connection */ 745163953Srrs SCTP_INP_RUNLOCK(inp); 746163953Srrs return (0); 747163953Srrs } else { 748163953Srrs struct sctp_association *asoc; 749163953Srrs struct sctp_tcb *stcb; 750163953Srrs 751163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 752163953Srrs if (stcb == NULL) { 753163953Srrs SCTP_INP_RUNLOCK(inp); 754171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 755163953Srrs return (EINVAL); 756163953Srrs } 757163953Srrs SCTP_TCB_LOCK(stcb); 758163953Srrs asoc = &stcb->asoc; 759163953Srrs if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 760163953Srrs /* We are about to be freed, out of here */ 761163953Srrs SCTP_TCB_UNLOCK(stcb); 762163953Srrs SCTP_INP_RUNLOCK(inp); 763163953Srrs return (0); 764163953Srrs } 765163953Srrs if (((so->so_options & SO_LINGER) && 766163953Srrs (so->so_linger == 0)) || 767163953Srrs (so->so_rcv.sb_cc > 0)) { 768163953Srrs if (SCTP_GET_STATE(asoc) != 769163953Srrs SCTP_STATE_COOKIE_WAIT) { 770163953Srrs /* Left with Data unread */ 771163953Srrs struct mbuf *err; 772163953Srrs 773163953Srrs err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_DONTWAIT, 1, MT_DATA); 774163953Srrs if (err) { 775163953Srrs /* 776163953Srrs * Fill in the user 777163953Srrs * initiated abort 778163953Srrs */ 779163953Srrs struct sctp_paramhdr *ph; 780163953Srrs 781163953Srrs ph = mtod(err, struct sctp_paramhdr *); 782165647Srrs SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr); 783163953Srrs ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); 784165647Srrs ph->param_length = htons(SCTP_BUF_LEN(err)); 785163953Srrs } 786172396Srrs#if defined(SCTP_PANIC_ON_ABORT) 787172396Srrs panic("disconnect does an abort"); 788172396Srrs#endif 789172090Srrs sctp_send_abort_tcb(stcb, err, SCTP_SO_LOCKED); 790163953Srrs SCTP_STAT_INCR_COUNTER32(sctps_aborted); 791163953Srrs } 792163953Srrs SCTP_INP_RUNLOCK(inp); 793163953Srrs if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 794163953Srrs (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 795163953Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 796163953Srrs } 797171943Srrs (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3); 798163953Srrs /* No unlock tcb assoc is gone */ 799163953Srrs return (0); 800163953Srrs } 801163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 802163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 803163953Srrs (asoc->stream_queue_cnt == 0)) { 804163953Srrs /* there is nothing queued to send, so done */ 805163953Srrs if (asoc->locked_on_sending) { 806163953Srrs goto abort_anyway; 807163953Srrs } 808166675Srrs if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) && 809166675Srrs (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { 810163953Srrs /* only send SHUTDOWN 1st time thru */ 811224641Stuexen struct sctp_nets *netp; 812224641Stuexen 813224641Stuexen if (stcb->asoc.alternate) { 814224641Stuexen netp = stcb->asoc.alternate; 815224641Stuexen } else { 816224641Stuexen netp = stcb->asoc.primary_destination; 817224641Stuexen } 818163953Srrs sctp_stop_timers_for_shutdown(stcb); 819224641Stuexen sctp_send_shutdown(stcb, netp); 820172090Srrs sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); 821166675Srrs if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 822166675Srrs (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 823166675Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 824166675Srrs } 825171943Srrs SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); 826172703Srrs SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 827163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 828224641Stuexen stcb->sctp_ep, stcb, netp); 829163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 830224641Stuexen stcb->sctp_ep, stcb, netp); 831224641Stuexen 832163953Srrs } 833163953Srrs } else { 834163953Srrs /* 835163953Srrs * we still got (or just got) data to send, 836163953Srrs * so set SHUTDOWN_PENDING 837163953Srrs */ 838163953Srrs /* 839163953Srrs * XXX sockets draft says that SCTP_EOF 840163953Srrs * should be sent with no data. currently, 841163953Srrs * we will allow user data to be sent first 842163953Srrs * and move to SHUTDOWN-PENDING 843163953Srrs */ 844224641Stuexen struct sctp_nets *netp; 845224641Stuexen 846224641Stuexen if (stcb->asoc.alternate) { 847224641Stuexen netp = stcb->asoc.alternate; 848224641Stuexen } else { 849224641Stuexen netp = stcb->asoc.primary_destination; 850224641Stuexen } 851224641Stuexen 852163953Srrs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 853163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, 854224641Stuexen netp); 855163953Srrs if (asoc->locked_on_sending) { 856163953Srrs /* Locked to send out the data */ 857163953Srrs struct sctp_stream_queue_pending *sp; 858163953Srrs 859163953Srrs sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); 860163953Srrs if (sp == NULL) { 861169420Srrs SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", 862163953Srrs asoc->locked_on_sending->stream_no); 863163953Srrs } else { 864163953Srrs if ((sp->length == 0) && (sp->msg_is_complete == 0)) 865163953Srrs asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; 866163953Srrs } 867163953Srrs } 868163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 869163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 870163953Srrs (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 871163953Srrs struct mbuf *op_err; 872163953Srrs 873163953Srrs abort_anyway: 874163953Srrs op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 875163953Srrs 0, M_DONTWAIT, 1, MT_DATA); 876163953Srrs if (op_err) { 877163953Srrs /* 878163953Srrs * Fill in the user 879163953Srrs * initiated abort 880163953Srrs */ 881163953Srrs struct sctp_paramhdr *ph; 882163953Srrs uint32_t *ippp; 883163953Srrs 884165647Srrs SCTP_BUF_LEN(op_err) = 885163953Srrs (sizeof(struct sctp_paramhdr) + sizeof(uint32_t)); 886163953Srrs ph = mtod(op_err, 887163953Srrs struct sctp_paramhdr *); 888163953Srrs ph->param_type = htons( 889163953Srrs SCTP_CAUSE_USER_INITIATED_ABT); 890165647Srrs ph->param_length = htons(SCTP_BUF_LEN(op_err)); 891163953Srrs ippp = (uint32_t *) (ph + 1); 892165220Srrs *ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4); 893163953Srrs } 894172396Srrs#if defined(SCTP_PANIC_ON_ABORT) 895172396Srrs panic("disconnect does an abort"); 896172396Srrs#endif 897172396Srrs 898165220Srrs stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4; 899172090Srrs sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED); 900163953Srrs SCTP_STAT_INCR_COUNTER32(sctps_aborted); 901163953Srrs if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 902163953Srrs (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 903163953Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 904163953Srrs } 905163953Srrs SCTP_INP_RUNLOCK(inp); 906171943Srrs (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5); 907163953Srrs return (0); 908171990Srrs } else { 909172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); 910163953Srrs } 911163953Srrs } 912188067Srrs soisdisconnecting(so); 913163953Srrs SCTP_TCB_UNLOCK(stcb); 914163953Srrs SCTP_INP_RUNLOCK(inp); 915163953Srrs return (0); 916163953Srrs } 917163953Srrs /* not reached */ 918163953Srrs } else { 919163953Srrs /* UDP model does not support this */ 920163953Srrs SCTP_INP_RUNLOCK(inp); 921171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 922228907Stuexen return (EOPNOTSUPP); 923163953Srrs } 924163953Srrs} 925163953Srrs 926163953Srrsint 927178202Srrssctp_flush(struct socket *so, int how) 928178202Srrs{ 929178202Srrs /* 930178202Srrs * We will just clear out the values and let subsequent close clear 931178202Srrs * out the data, if any. Note if the user did a shutdown(SHUT_RD) 932178202Srrs * they will not be able to read the data, the socket will block 933178202Srrs * that from happening. 934178202Srrs */ 935209289Stuexen struct sctp_inpcb *inp; 936209289Stuexen 937209289Stuexen inp = (struct sctp_inpcb *)so->so_pcb; 938209289Stuexen if (inp == NULL) { 939209289Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 940228907Stuexen return (EINVAL); 941209289Stuexen } 942209289Stuexen SCTP_INP_RLOCK(inp); 943209289Stuexen /* For the 1 to many model this does nothing */ 944209289Stuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 945209289Stuexen SCTP_INP_RUNLOCK(inp); 946209289Stuexen return (0); 947209289Stuexen } 948209289Stuexen SCTP_INP_RUNLOCK(inp); 949178202Srrs if ((how == PRU_FLUSH_RD) || (how == PRU_FLUSH_RDWR)) { 950178202Srrs /* 951178202Srrs * First make sure the sb will be happy, we don't use these 952178202Srrs * except maybe the count 953178202Srrs */ 954209289Stuexen SCTP_INP_WLOCK(inp); 955209289Stuexen SCTP_INP_READ_LOCK(inp); 956209289Stuexen inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ; 957209289Stuexen SCTP_INP_READ_UNLOCK(inp); 958209289Stuexen SCTP_INP_WUNLOCK(inp); 959178202Srrs so->so_rcv.sb_cc = 0; 960178202Srrs so->so_rcv.sb_mbcnt = 0; 961178202Srrs so->so_rcv.sb_mb = NULL; 962178202Srrs } 963178202Srrs if ((how == PRU_FLUSH_WR) || (how == PRU_FLUSH_RDWR)) { 964178202Srrs /* 965178202Srrs * First make sure the sb will be happy, we don't use these 966178202Srrs * except maybe the count 967178202Srrs */ 968178202Srrs so->so_snd.sb_cc = 0; 969178202Srrs so->so_snd.sb_mbcnt = 0; 970178202Srrs so->so_snd.sb_mb = NULL; 971178202Srrs 972178202Srrs } 973178202Srrs return (0); 974178202Srrs} 975178202Srrs 976178202Srrsint 977163953Srrssctp_shutdown(struct socket *so) 978163953Srrs{ 979163953Srrs struct sctp_inpcb *inp; 980163953Srrs 981163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 982233005Stuexen if (inp == NULL) { 983171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 984228907Stuexen return (EINVAL); 985163953Srrs } 986163953Srrs SCTP_INP_RLOCK(inp); 987163953Srrs /* For UDP model this is a invalid call */ 988163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 989163953Srrs /* Restore the flags that the soshutdown took away. */ 990204096Stuexen SOCKBUF_LOCK(&so->so_rcv); 991163953Srrs so->so_rcv.sb_state &= ~SBS_CANTRCVMORE; 992204096Stuexen SOCKBUF_UNLOCK(&so->so_rcv); 993163953Srrs /* This proc will wakeup for read and do nothing (I hope) */ 994163953Srrs SCTP_INP_RUNLOCK(inp); 995171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 996163953Srrs return (EOPNOTSUPP); 997163953Srrs } 998163953Srrs /* 999163953Srrs * Ok if we reach here its the TCP model and it is either a SHUT_WR 1000163953Srrs * or SHUT_RDWR. This means we put the shutdown flag against it. 1001163953Srrs */ 1002163953Srrs { 1003163953Srrs struct sctp_tcb *stcb; 1004163953Srrs struct sctp_association *asoc; 1005163953Srrs 1006188067Srrs if ((so->so_state & 1007188067Srrs (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) { 1008188067Srrs SCTP_INP_RUNLOCK(inp); 1009188067Srrs return (ENOTCONN); 1010188067Srrs } 1011163953Srrs socantsendmore(so); 1012163953Srrs 1013163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 1014163953Srrs if (stcb == NULL) { 1015163953Srrs /* 1016163953Srrs * Ok we hit the case that the shutdown call was 1017163953Srrs * made after an abort or something. Nothing to do 1018163953Srrs * now. 1019163953Srrs */ 1020168299Srrs SCTP_INP_RUNLOCK(inp); 1021163953Srrs return (0); 1022163953Srrs } 1023163953Srrs SCTP_TCB_LOCK(stcb); 1024163953Srrs asoc = &stcb->asoc; 1025163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 1026163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 1027163953Srrs (asoc->stream_queue_cnt == 0)) { 1028163953Srrs if (asoc->locked_on_sending) { 1029163953Srrs goto abort_anyway; 1030163953Srrs } 1031163953Srrs /* there is nothing queued to send, so I'm done... */ 1032163953Srrs if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { 1033163953Srrs /* only send SHUTDOWN the first time through */ 1034224641Stuexen struct sctp_nets *netp; 1035224641Stuexen 1036224641Stuexen if (stcb->asoc.alternate) { 1037224641Stuexen netp = stcb->asoc.alternate; 1038224641Stuexen } else { 1039224641Stuexen netp = stcb->asoc.primary_destination; 1040224641Stuexen } 1041163953Srrs sctp_stop_timers_for_shutdown(stcb); 1042224641Stuexen sctp_send_shutdown(stcb, netp); 1043172218Srrs sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); 1044166675Srrs if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 1045166675Srrs (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 1046166675Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 1047166675Srrs } 1048171943Srrs SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); 1049172703Srrs SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 1050163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 1051224641Stuexen stcb->sctp_ep, stcb, netp); 1052163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 1053224641Stuexen stcb->sctp_ep, stcb, netp); 1054163953Srrs } 1055163953Srrs } else { 1056163953Srrs /* 1057163953Srrs * we still got (or just got) data to send, so set 1058163953Srrs * SHUTDOWN_PENDING 1059163953Srrs */ 1060224641Stuexen struct sctp_nets *netp; 1061224641Stuexen 1062224641Stuexen if (stcb->asoc.alternate) { 1063224641Stuexen netp = stcb->asoc.alternate; 1064224641Stuexen } else { 1065224641Stuexen netp = stcb->asoc.primary_destination; 1066224641Stuexen } 1067224641Stuexen 1068163953Srrs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 1069163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, 1070224641Stuexen netp); 1071163953Srrs 1072163953Srrs if (asoc->locked_on_sending) { 1073163953Srrs /* Locked to send out the data */ 1074163953Srrs struct sctp_stream_queue_pending *sp; 1075163953Srrs 1076163953Srrs sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); 1077163953Srrs if (sp == NULL) { 1078169420Srrs SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", 1079163953Srrs asoc->locked_on_sending->stream_no); 1080163953Srrs } else { 1081163953Srrs if ((sp->length == 0) && (sp->msg_is_complete == 0)) { 1082163953Srrs asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; 1083163953Srrs } 1084163953Srrs } 1085163953Srrs } 1086163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 1087163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 1088163953Srrs (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 1089163953Srrs struct mbuf *op_err; 1090163953Srrs 1091163953Srrs abort_anyway: 1092163953Srrs op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 1093163953Srrs 0, M_DONTWAIT, 1, MT_DATA); 1094163953Srrs if (op_err) { 1095163953Srrs /* Fill in the user initiated abort */ 1096163953Srrs struct sctp_paramhdr *ph; 1097163953Srrs uint32_t *ippp; 1098163953Srrs 1099165647Srrs SCTP_BUF_LEN(op_err) = 1100163953Srrs sizeof(struct sctp_paramhdr) + sizeof(uint32_t); 1101163953Srrs ph = mtod(op_err, 1102163953Srrs struct sctp_paramhdr *); 1103163953Srrs ph->param_type = htons( 1104163953Srrs SCTP_CAUSE_USER_INITIATED_ABT); 1105165647Srrs ph->param_length = htons(SCTP_BUF_LEN(op_err)); 1106163953Srrs ippp = (uint32_t *) (ph + 1); 1107165220Srrs *ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6); 1108163953Srrs } 1109172396Srrs#if defined(SCTP_PANIC_ON_ABORT) 1110172396Srrs panic("shutdown does an abort"); 1111172396Srrs#endif 1112165220Srrs stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6; 1113163953Srrs sctp_abort_an_association(stcb->sctp_ep, stcb, 1114163953Srrs SCTP_RESPONSE_TO_USER_REQ, 1115172090Srrs op_err, SCTP_SO_LOCKED); 1116163953Srrs goto skip_unlock; 1117171990Srrs } else { 1118172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); 1119163953Srrs } 1120163953Srrs } 1121163953Srrs SCTP_TCB_UNLOCK(stcb); 1122163953Srrs } 1123163953Srrsskip_unlock: 1124163953Srrs SCTP_INP_RUNLOCK(inp); 1125228907Stuexen return (0); 1126163953Srrs} 1127163953Srrs 1128163953Srrs/* 1129163953Srrs * copies a "user" presentable address and removes embedded scope, etc. 1130163953Srrs * returns 0 on success, 1 on error 1131163953Srrs */ 1132163953Srrsstatic uint32_t 1133163953Srrssctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa) 1134163953Srrs{ 1135178251Srrs#ifdef INET6 1136163953Srrs struct sockaddr_in6 lsa6; 1137163953Srrs 1138163953Srrs sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa, 1139163953Srrs &lsa6); 1140178251Srrs#endif 1141163953Srrs memcpy(ss, sa, sa->sa_len); 1142163953Srrs return (0); 1143163953Srrs} 1144163953Srrs 1145163953Srrs 1146163953Srrs 1147172091Srrs/* 1148172091Srrs * NOTE: assumes addr lock is held 1149172091Srrs */ 1150166675Srrsstatic size_t 1151168124Srrssctp_fill_up_addresses_vrf(struct sctp_inpcb *inp, 1152163953Srrs struct sctp_tcb *stcb, 1153166675Srrs size_t limit, 1154167598Srrs struct sockaddr_storage *sas, 1155167598Srrs uint32_t vrf_id) 1156163953Srrs{ 1157167598Srrs struct sctp_ifn *sctp_ifn; 1158167598Srrs struct sctp_ifa *sctp_ifa; 1159166675Srrs int loopback_scope, ipv4_local_scope, local_scope, site_scope; 1160166675Srrs size_t actual; 1161163953Srrs int ipv4_addr_legal, ipv6_addr_legal; 1162167598Srrs struct sctp_vrf *vrf; 1163163953Srrs 1164163953Srrs actual = 0; 1165163953Srrs if (limit <= 0) 1166163953Srrs return (actual); 1167163953Srrs 1168163953Srrs if (stcb) { 1169163953Srrs /* Turn on all the appropriate scope */ 1170163953Srrs loopback_scope = stcb->asoc.loopback_scope; 1171163953Srrs ipv4_local_scope = stcb->asoc.ipv4_local_scope; 1172163953Srrs local_scope = stcb->asoc.local_scope; 1173163953Srrs site_scope = stcb->asoc.site_scope; 1174163953Srrs } else { 1175163953Srrs /* Turn on ALL scope, since we look at the EP */ 1176163953Srrs loopback_scope = ipv4_local_scope = local_scope = 1177163953Srrs site_scope = 1; 1178163953Srrs } 1179163953Srrs ipv4_addr_legal = ipv6_addr_legal = 0; 1180163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 1181163953Srrs ipv6_addr_legal = 1; 1182166023Srrs if (SCTP_IPV6_V6ONLY(inp) == 0) { 1183163953Srrs ipv4_addr_legal = 1; 1184163953Srrs } 1185163953Srrs } else { 1186163953Srrs ipv4_addr_legal = 1; 1187163953Srrs } 1188167598Srrs vrf = sctp_find_vrf(vrf_id); 1189167598Srrs if (vrf == NULL) { 1190167598Srrs return (0); 1191167598Srrs } 1192163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1193167598Srrs LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 1194163953Srrs if ((loopback_scope == 0) && 1195167598Srrs SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { 1196163953Srrs /* Skip loopback if loopback_scope not set */ 1197163953Srrs continue; 1198163953Srrs } 1199167598Srrs LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 1200163953Srrs if (stcb) { 1201163953Srrs /* 1202163953Srrs * For the BOUND-ALL case, the list 1203163953Srrs * associated with a TCB is Always 1204163953Srrs * considered a reverse list.. i.e. 1205163953Srrs * it lists addresses that are NOT 1206163953Srrs * part of the association. If this 1207163953Srrs * is one of those we must skip it. 1208163953Srrs */ 1209163953Srrs if (sctp_is_addr_restricted(stcb, 1210167598Srrs sctp_ifa)) { 1211163953Srrs continue; 1212163953Srrs } 1213163953Srrs } 1214178251Srrs switch (sctp_ifa->address.sa.sa_family) { 1215221249Stuexen#ifdef INET 1216178251Srrs case AF_INET: 1217178251Srrs if (ipv4_addr_legal) { 1218178251Srrs struct sockaddr_in *sin; 1219163953Srrs 1220178251Srrs sin = (struct sockaddr_in *)&sctp_ifa->address.sa; 1221178251Srrs if (sin->sin_addr.s_addr == 0) { 1222178251Srrs /* 1223178251Srrs * we skip 1224178251Srrs * unspecifed 1225178251Srrs * addresses 1226178251Srrs */ 1227178251Srrs continue; 1228178251Srrs } 1229178251Srrs if ((ipv4_local_scope == 0) && 1230178251Srrs (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { 1231178251Srrs continue; 1232178251Srrs } 1233178251Srrs#ifdef INET6 1234178251Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 1235178251Srrs in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas); 1236178251Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1237178251Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6)); 1238178251Srrs actual += sizeof(struct sockaddr_in6); 1239178251Srrs } else { 1240178251Srrs#endif 1241178251Srrs memcpy(sas, sin, sizeof(*sin)); 1242178251Srrs ((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport; 1243178251Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin)); 1244178251Srrs actual += sizeof(*sin); 1245178251Srrs#ifdef INET6 1246178251Srrs } 1247178251Srrs#endif 1248178251Srrs if (actual >= limit) { 1249178251Srrs return (actual); 1250178251Srrs } 1251178251Srrs } else { 1252163953Srrs continue; 1253163953Srrs } 1254178251Srrs break; 1255221249Stuexen#endif 1256178251Srrs#ifdef INET6 1257178251Srrs case AF_INET6: 1258178251Srrs if (ipv6_addr_legal) { 1259178251Srrs struct sockaddr_in6 *sin6; 1260163953Srrs 1261178251Srrs sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa; 1262178251Srrs if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 1263178251Srrs /* 1264178251Srrs * we skip 1265178251Srrs * unspecifed 1266178251Srrs * addresses 1267178251Srrs */ 1268163953Srrs continue; 1269178251Srrs } 1270178251Srrs if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 1271178251Srrs if (local_scope == 0) 1272163953Srrs continue; 1273178251Srrs if (sin6->sin6_scope_id == 0) { 1274178251Srrs if (sa6_recoverscope(sin6) != 0) 1275178251Srrs /* 1276178251Srrs * 1277178251Srrs * bad 1278178251Srrs * 1279178251Srrs * li 1280178251Srrs * nk 1281178251Srrs * 1282178251Srrs * loc 1283178251Srrs * al 1284178251Srrs * 1285178251Srrs * add 1286178251Srrs * re 1287178251Srrs * ss 1288178251Srrs * */ 1289178251Srrs continue; 1290178251Srrs } 1291163953Srrs } 1292178251Srrs if ((site_scope == 0) && 1293178251Srrs (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { 1294178251Srrs continue; 1295178251Srrs } 1296178251Srrs memcpy(sas, sin6, sizeof(*sin6)); 1297178251Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1298178251Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6)); 1299178251Srrs actual += sizeof(*sin6); 1300178251Srrs if (actual >= limit) { 1301178251Srrs return (actual); 1302178251Srrs } 1303178251Srrs } else { 1304163953Srrs continue; 1305163953Srrs } 1306178251Srrs break; 1307178251Srrs#endif 1308178251Srrs default: 1309178251Srrs /* TSNH */ 1310178251Srrs break; 1311163953Srrs } 1312163953Srrs } 1313163953Srrs } 1314163953Srrs } else { 1315163953Srrs struct sctp_laddr *laddr; 1316163953Srrs 1317167598Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1318167598Srrs if (stcb) { 1319167598Srrs if (sctp_is_addr_restricted(stcb, laddr->ifa)) { 1320163953Srrs continue; 1321163953Srrs } 1322163953Srrs } 1323167598Srrs if (sctp_fill_user_address(sas, &laddr->ifa->address.sa)) 1324167598Srrs continue; 1325167598Srrs 1326167598Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1327167598Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + 1328167598Srrs laddr->ifa->address.sa.sa_len); 1329167598Srrs actual += laddr->ifa->address.sa.sa_len; 1330167598Srrs if (actual >= limit) { 1331167598Srrs return (actual); 1332163953Srrs } 1333163953Srrs } 1334163953Srrs } 1335163953Srrs return (actual); 1336163953Srrs} 1337163953Srrs 1338168124Srrsstatic size_t 1339168124Srrssctp_fill_up_addresses(struct sctp_inpcb *inp, 1340168124Srrs struct sctp_tcb *stcb, 1341168124Srrs size_t limit, 1342168124Srrs struct sockaddr_storage *sas) 1343168124Srrs{ 1344168124Srrs size_t size = 0; 1345168124Srrs 1346172218Srrs SCTP_IPI_ADDR_RLOCK(); 1347168124Srrs /* fill up addresses for the endpoint's default vrf */ 1348168124Srrs size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas, 1349168124Srrs inp->def_vrf_id); 1350172218Srrs SCTP_IPI_ADDR_RUNLOCK(); 1351168124Srrs return (size); 1352168124Srrs} 1353168124Srrs 1354172091Srrs/* 1355172091Srrs * NOTE: assumes addr lock is held 1356172091Srrs */ 1357163953Srrsstatic int 1358168124Srrssctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) 1359163953Srrs{ 1360163953Srrs int cnt = 0; 1361167598Srrs struct sctp_vrf *vrf = NULL; 1362163953Srrs 1363163953Srrs /* 1364163953Srrs * In both sub-set bound an bound_all cases we return the MAXIMUM 1365163953Srrs * number of addresses that you COULD get. In reality the sub-set 1366163953Srrs * bound may have an exclusion list for a given TCB OR in the 1367163953Srrs * bound-all case a TCB may NOT include the loopback or other 1368163953Srrs * addresses as well. 1369163953Srrs */ 1370167598Srrs vrf = sctp_find_vrf(vrf_id); 1371167598Srrs if (vrf == NULL) { 1372167598Srrs return (0); 1373167598Srrs } 1374163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1375167598Srrs struct sctp_ifn *sctp_ifn; 1376167598Srrs struct sctp_ifa *sctp_ifa; 1377163953Srrs 1378167598Srrs LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 1379167598Srrs LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 1380163953Srrs /* Count them if they are the right type */ 1381221249Stuexen switch (sctp_ifa->address.sa.sa_family) { 1382221249Stuexen#ifdef INET 1383221249Stuexen case AF_INET: 1384178251Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) 1385163953Srrs cnt += sizeof(struct sockaddr_in6); 1386163953Srrs else 1387163953Srrs cnt += sizeof(struct sockaddr_in); 1388221249Stuexen break; 1389221249Stuexen#endif 1390221249Stuexen#ifdef INET6 1391221249Stuexen case AF_INET6: 1392163953Srrs cnt += sizeof(struct sockaddr_in6); 1393221249Stuexen break; 1394221249Stuexen#endif 1395221249Stuexen default: 1396221249Stuexen break; 1397221249Stuexen } 1398163953Srrs } 1399163953Srrs } 1400163953Srrs } else { 1401163953Srrs struct sctp_laddr *laddr; 1402163953Srrs 1403163953Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1404221249Stuexen switch (laddr->ifa->address.sa.sa_family) { 1405221249Stuexen#ifdef INET 1406221249Stuexen case AF_INET: 1407178251Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) 1408163953Srrs cnt += sizeof(struct sockaddr_in6); 1409163953Srrs else 1410163953Srrs cnt += sizeof(struct sockaddr_in); 1411221249Stuexen break; 1412221249Stuexen#endif 1413221249Stuexen#ifdef INET6 1414221249Stuexen case AF_INET6: 1415163953Srrs cnt += sizeof(struct sockaddr_in6); 1416221249Stuexen break; 1417221249Stuexen#endif 1418221249Stuexen default: 1419221249Stuexen break; 1420221249Stuexen } 1421163953Srrs } 1422163953Srrs } 1423163953Srrs return (cnt); 1424163953Srrs} 1425163953Srrs 1426168124Srrsstatic int 1427168124Srrssctp_count_max_addresses(struct sctp_inpcb *inp) 1428168124Srrs{ 1429168124Srrs int cnt = 0; 1430166675Srrs 1431172218Srrs SCTP_IPI_ADDR_RLOCK(); 1432168124Srrs /* count addresses for the endpoint's default VRF */ 1433168124Srrs cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id); 1434172218Srrs SCTP_IPI_ADDR_RUNLOCK(); 1435168124Srrs return (cnt); 1436168124Srrs} 1437168124Srrs 1438163953Srrsstatic int 1439166675Srrssctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, 1440166675Srrs size_t optsize, void *p, int delay) 1441163953Srrs{ 1442163953Srrs int error = 0; 1443163953Srrs int creat_lock_on = 0; 1444163953Srrs struct sctp_tcb *stcb = NULL; 1445163953Srrs struct sockaddr *sa; 1446169352Srrs int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr; 1447167598Srrs uint32_t vrf_id; 1448170056Srrs int bad_addresses = 0; 1449167598Srrs sctp_assoc_t *a_id; 1450163953Srrs 1451169420Srrs SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n"); 1452163953Srrs 1453163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 1454163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 1455163953Srrs /* We are already connected AND the TCP model */ 1456171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 1457163953Srrs return (EADDRINUSE); 1458163953Srrs } 1459181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && 1460181054Srrs (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) { 1461171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1462163953Srrs return (EINVAL); 1463163953Srrs } 1464163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 1465163953Srrs SCTP_INP_RLOCK(inp); 1466163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 1467163953Srrs SCTP_INP_RUNLOCK(inp); 1468163953Srrs } 1469163953Srrs if (stcb) { 1470171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 1471163953Srrs return (EALREADY); 1472163953Srrs } 1473163953Srrs SCTP_INP_INCR_REF(inp); 1474163953Srrs SCTP_ASOC_CREATE_LOCK(inp); 1475163953Srrs creat_lock_on = 1; 1476163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 1477163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 1478171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); 1479163953Srrs error = EFAULT; 1480163953Srrs goto out_now; 1481163953Srrs } 1482166675Srrs totaddrp = (int *)optval; 1483163953Srrs totaddr = *totaddrp; 1484163953Srrs sa = (struct sockaddr *)(totaddrp + 1); 1485170056Srrs stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses); 1486170056Srrs if ((stcb != NULL) || bad_addresses) { 1487169352Srrs /* Already have or am bring up an association */ 1488169352Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1489169352Srrs creat_lock_on = 0; 1490170931Srrs if (stcb) 1491170931Srrs SCTP_TCB_UNLOCK(stcb); 1492171943Srrs if (bad_addresses == 0) { 1493171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 1494170056Srrs error = EALREADY; 1495171943Srrs } 1496169352Srrs goto out_now; 1497163953Srrs } 1498163953Srrs#ifdef INET6 1499163953Srrs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 1500163953Srrs (num_v6 > 0)) { 1501163953Srrs error = EINVAL; 1502163953Srrs goto out_now; 1503163953Srrs } 1504163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 1505163953Srrs (num_v4 > 0)) { 1506163953Srrs struct in6pcb *inp6; 1507163953Srrs 1508163953Srrs inp6 = (struct in6pcb *)inp; 1509166023Srrs if (SCTP_IPV6_V6ONLY(inp6)) { 1510163953Srrs /* 1511163953Srrs * if IPV6_V6ONLY flag, ignore connections destined 1512163953Srrs * to a v4 addr or v4-mapped addr 1513163953Srrs */ 1514171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1515163953Srrs error = EINVAL; 1516163953Srrs goto out_now; 1517163953Srrs } 1518163953Srrs } 1519163953Srrs#endif /* INET6 */ 1520163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 1521163953Srrs SCTP_PCB_FLAGS_UNBOUND) { 1522163953Srrs /* Bind a ephemeral port */ 1523171572Srrs error = sctp_inpcb_bind(so, NULL, NULL, p); 1524163953Srrs if (error) { 1525163953Srrs goto out_now; 1526163953Srrs } 1527163953Srrs } 1528167695Srrs /* FIX ME: do we want to pass in a vrf on the connect call? */ 1529167695Srrs vrf_id = inp->def_vrf_id; 1530167695Srrs 1531181054Srrs 1532163953Srrs /* We are GOOD to go */ 1533206137Stuexen stcb = sctp_aloc_assoc(inp, sa, &error, 0, vrf_id, 1534171531Srrs (struct thread *)p 1535171531Srrs ); 1536163953Srrs if (stcb == NULL) { 1537163953Srrs /* Gak! no memory */ 1538163953Srrs goto out_now; 1539163953Srrs } 1540225559Stuexen if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 1541225559Stuexen stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 1542225559Stuexen /* Set the connected flag so we can queue data */ 1543225559Stuexen soisconnecting(so); 1544225559Stuexen } 1545171943Srrs SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); 1546163953Srrs /* move to second address */ 1547221249Stuexen switch (sa->sa_family) { 1548221249Stuexen#ifdef INET 1549221249Stuexen case AF_INET: 1550163953Srrs sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in)); 1551221249Stuexen break; 1552221249Stuexen#endif 1553221249Stuexen#ifdef INET6 1554221249Stuexen case AF_INET6: 1555163953Srrs sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6)); 1556221249Stuexen break; 1557221249Stuexen#endif 1558221249Stuexen default: 1559221249Stuexen break; 1560221249Stuexen } 1561163953Srrs 1562170056Srrs error = 0; 1563223132Stuexen sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error); 1564167598Srrs /* Fill in the return id */ 1565170056Srrs if (error) { 1566207924Srrs (void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6); 1567170056Srrs goto out_now; 1568170056Srrs } 1569167598Srrs a_id = (sctp_assoc_t *) optval; 1570167598Srrs *a_id = sctp_get_associd(stcb); 1571163953Srrs 1572163953Srrs /* initialize authentication parameters for the assoc */ 1573163953Srrs sctp_initialize_auth_params(inp, stcb); 1574163953Srrs 1575163953Srrs if (delay) { 1576163953Srrs /* doing delayed connection */ 1577163953Srrs stcb->asoc.delayed_connection = 1; 1578163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination); 1579163953Srrs } else { 1580169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 1581172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 1582163953Srrs } 1583163953Srrs SCTP_TCB_UNLOCK(stcb); 1584163953Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 1585163953Srrs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 1586163953Srrs /* Set the connected flag so we can queue data */ 1587163953Srrs soisconnecting(so); 1588163953Srrs } 1589163953Srrsout_now: 1590169655Srrs if (creat_lock_on) { 1591163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1592169655Srrs } 1593163953Srrs SCTP_INP_DECR_REF(inp); 1594228907Stuexen return (error); 1595163953Srrs} 1596163953Srrs 1597169420Srrs#define SCTP_FIND_STCB(inp, stcb, assoc_id) { \ 1598169655Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||\ 1599169655Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { \ 1600166675Srrs SCTP_INP_RLOCK(inp); \ 1601166675Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); \ 1602169655Srrs if (stcb) { \ 1603166675Srrs SCTP_TCB_LOCK(stcb); \ 1604169655Srrs } \ 1605166675Srrs SCTP_INP_RUNLOCK(inp); \ 1606223132Stuexen } else if (assoc_id > SCTP_ALL_ASSOC) { \ 1607166675Srrs stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \ 1608166675Srrs if (stcb == NULL) { \ 1609171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \ 1610166675Srrs error = ENOENT; \ 1611166675Srrs break; \ 1612166675Srrs } \ 1613166675Srrs } else { \ 1614166675Srrs stcb = NULL; \ 1615169420Srrs } \ 1616169420Srrs } 1617163953Srrs 1618169420Srrs 1619169420Srrs#define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\ 1620166675Srrs if (size < sizeof(type)) { \ 1621171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); \ 1622166675Srrs error = EINVAL; \ 1623166675Srrs break; \ 1624166675Srrs } else { \ 1625166675Srrs destp = (type *)srcp; \ 1626169420Srrs } \ 1627169420Srrs } 1628163953Srrs 1629163953Srrsstatic int 1630166675Srrssctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, 1631166675Srrs void *p) 1632163953Srrs{ 1633171943Srrs struct sctp_inpcb *inp = NULL; 1634166675Srrs int error, val = 0; 1635163953Srrs struct sctp_tcb *stcb = NULL; 1636163953Srrs 1637166675Srrs if (optval == NULL) { 1638171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1639166675Srrs return (EINVAL); 1640166675Srrs } 1641163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 1642233005Stuexen if (inp == NULL) { 1643171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1644163953Srrs return EINVAL; 1645171943Srrs } 1646163953Srrs error = 0; 1647163953Srrs 1648166675Srrs switch (optname) { 1649163953Srrs case SCTP_NODELAY: 1650163953Srrs case SCTP_AUTOCLOSE: 1651163953Srrs case SCTP_EXPLICIT_EOR: 1652163953Srrs case SCTP_AUTO_ASCONF: 1653163953Srrs case SCTP_DISABLE_FRAGMENTS: 1654163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 1655163953Srrs case SCTP_USE_EXT_RCVINFO: 1656163953Srrs SCTP_INP_RLOCK(inp); 1657166675Srrs switch (optname) { 1658163953Srrs case SCTP_DISABLE_FRAGMENTS: 1659166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT); 1660163953Srrs break; 1661163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 1662166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4); 1663163953Srrs break; 1664163953Srrs case SCTP_AUTO_ASCONF: 1665171943Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1666171943Srrs /* only valid for bound all sockets */ 1667171943Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); 1668171943Srrs } else { 1669171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1670171943Srrs error = EINVAL; 1671171943Srrs goto flags_out; 1672171943Srrs } 1673163953Srrs break; 1674163953Srrs case SCTP_EXPLICIT_EOR: 1675166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); 1676163953Srrs break; 1677163953Srrs case SCTP_NODELAY: 1678166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY); 1679163953Srrs break; 1680163953Srrs case SCTP_USE_EXT_RCVINFO: 1681166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO); 1682163953Srrs break; 1683163953Srrs case SCTP_AUTOCLOSE: 1684163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) 1685166675Srrs val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time); 1686163953Srrs else 1687166675Srrs val = 0; 1688163953Srrs break; 1689163953Srrs 1690163953Srrs default: 1691171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 1692163953Srrs error = ENOPROTOOPT; 1693163953Srrs } /* end switch (sopt->sopt_name) */ 1694166675Srrs if (*optsize < sizeof(val)) { 1695171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1696163953Srrs error = EINVAL; 1697163953Srrs } 1698171943Srrsflags_out: 1699163953Srrs SCTP_INP_RUNLOCK(inp); 1700163953Srrs if (error == 0) { 1701163953Srrs /* return the option value */ 1702166675Srrs *(int *)optval = val; 1703166675Srrs *optsize = sizeof(val); 1704163953Srrs } 1705163953Srrs break; 1706170091Srrs case SCTP_GET_PACKET_LOG: 1707170091Srrs { 1708170091Srrs#ifdef SCTP_PACKET_LOGGING 1709170091Srrs uint8_t *target; 1710170091Srrs int ret; 1711167598Srrs 1712170091Srrs SCTP_CHECK_AND_CAST(target, optval, uint8_t, *optsize); 1713170091Srrs ret = sctp_copy_out_packet_log(target, (int)*optsize); 1714170091Srrs *optsize = ret; 1715170091Srrs#else 1716171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 1717170091Srrs error = EOPNOTSUPP; 1718170091Srrs#endif 1719170091Srrs break; 1720170091Srrs } 1721181054Srrs case SCTP_REUSE_PORT: 1722181054Srrs { 1723181054Srrs uint32_t *value; 1724181054Srrs 1725181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) { 1726181054Srrs /* Can't do this for a 1-m socket */ 1727181054Srrs error = EINVAL; 1728181054Srrs break; 1729181054Srrs } 1730181054Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1731181054Srrs *value = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE); 1732181054Srrs *optsize = sizeof(uint32_t); 1733223132Stuexen break; 1734181054Srrs } 1735163953Srrs case SCTP_PARTIAL_DELIVERY_POINT: 1736163953Srrs { 1737166675Srrs uint32_t *value; 1738166675Srrs 1739166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1740166675Srrs *value = inp->partial_delivery_point; 1741166675Srrs *optsize = sizeof(uint32_t); 1742223132Stuexen break; 1743163953Srrs } 1744163953Srrs case SCTP_FRAGMENT_INTERLEAVE: 1745163953Srrs { 1746166675Srrs uint32_t *value; 1747166675Srrs 1748166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1749168943Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) { 1750168943Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) { 1751168943Srrs *value = SCTP_FRAG_LEVEL_2; 1752168943Srrs } else { 1753168943Srrs *value = SCTP_FRAG_LEVEL_1; 1754168943Srrs } 1755168943Srrs } else { 1756168943Srrs *value = SCTP_FRAG_LEVEL_0; 1757168943Srrs } 1758166675Srrs *optsize = sizeof(uint32_t); 1759223132Stuexen break; 1760163953Srrs } 1761163953Srrs case SCTP_CMT_ON_OFF: 1762163953Srrs { 1763166675Srrs struct sctp_assoc_value *av; 1764166675Srrs 1765166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1766211944Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1767211944Stuexen if (stcb) { 1768211944Stuexen av->assoc_value = stcb->asoc.sctp_cmt_on_off; 1769211944Stuexen SCTP_TCB_UNLOCK(stcb); 1770166675Srrs } else { 1771224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1772224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1773224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1774223132Stuexen SCTP_INP_RLOCK(inp); 1775223132Stuexen av->assoc_value = inp->sctp_cmt_on_off; 1776223132Stuexen SCTP_INP_RUNLOCK(inp); 1777223132Stuexen } else { 1778223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1779223132Stuexen error = EINVAL; 1780223132Stuexen } 1781163953Srrs } 1782223132Stuexen if (error == 0) { 1783223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1784223132Stuexen } 1785223132Stuexen break; 1786163953Srrs } 1787171440Srrs case SCTP_PLUGGABLE_CC: 1788171440Srrs { 1789171440Srrs struct sctp_assoc_value *av; 1790171440Srrs 1791171440Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1792171440Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1793171440Srrs if (stcb) { 1794171440Srrs av->assoc_value = stcb->asoc.congestion_control_module; 1795171440Srrs SCTP_TCB_UNLOCK(stcb); 1796171440Srrs } else { 1797224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1798224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1799224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1800223132Stuexen SCTP_INP_RLOCK(inp); 1801223132Stuexen av->assoc_value = inp->sctp_ep.sctp_default_cc_module; 1802223132Stuexen SCTP_INP_RUNLOCK(inp); 1803223132Stuexen } else { 1804223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1805223132Stuexen error = EINVAL; 1806223132Stuexen } 1807171440Srrs } 1808223132Stuexen if (error == 0) { 1809223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1810223132Stuexen } 1811223132Stuexen break; 1812171440Srrs } 1813219057Srrs case SCTP_CC_OPTION: 1814219057Srrs { 1815219057Srrs struct sctp_cc_option *cc_opt; 1816219057Srrs 1817219057Srrs SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, *optsize); 1818219057Srrs SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id); 1819219057Srrs if (stcb == NULL) { 1820219057Srrs error = EINVAL; 1821219057Srrs } else { 1822219057Srrs if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) { 1823219057Srrs error = ENOTSUP; 1824219057Srrs } else { 1825223132Stuexen error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 0, cc_opt); 1826223132Stuexen *optsize = sizeof(struct sctp_cc_option); 1827219057Srrs } 1828219057Srrs SCTP_TCB_UNLOCK(stcb); 1829219057Srrs } 1830223132Stuexen break; 1831219057Srrs } 1832217760Stuexen case SCTP_PLUGGABLE_SS: 1833217760Stuexen { 1834217760Stuexen struct sctp_assoc_value *av; 1835217760Stuexen 1836217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1837217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1838217760Stuexen if (stcb) { 1839217760Stuexen av->assoc_value = stcb->asoc.stream_scheduling_module; 1840217760Stuexen SCTP_TCB_UNLOCK(stcb); 1841217760Stuexen } else { 1842224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1843224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1844224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1845223132Stuexen SCTP_INP_RLOCK(inp); 1846223132Stuexen av->assoc_value = inp->sctp_ep.sctp_default_ss_module; 1847223132Stuexen SCTP_INP_RUNLOCK(inp); 1848223132Stuexen } else { 1849223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1850223132Stuexen error = EINVAL; 1851223132Stuexen } 1852217760Stuexen } 1853223132Stuexen if (error == 0) { 1854223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1855223132Stuexen } 1856223132Stuexen break; 1857217760Stuexen } 1858217760Stuexen case SCTP_SS_VALUE: 1859217760Stuexen { 1860217760Stuexen struct sctp_stream_value *av; 1861217760Stuexen 1862217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize); 1863217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1864217760Stuexen if (stcb) { 1865217760Stuexen if (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], 1866217760Stuexen &av->stream_value) < 0) { 1867217760Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1868217760Stuexen error = EINVAL; 1869217760Stuexen } else { 1870223132Stuexen *optsize = sizeof(struct sctp_stream_value); 1871217760Stuexen } 1872217760Stuexen SCTP_TCB_UNLOCK(stcb); 1873217760Stuexen } else { 1874217760Stuexen /* 1875217760Stuexen * Can't get stream value without 1876217760Stuexen * association 1877217760Stuexen */ 1878217760Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1879217760Stuexen error = EINVAL; 1880217760Stuexen } 1881223132Stuexen break; 1882217760Stuexen } 1883163953Srrs case SCTP_GET_ADDR_LEN: 1884163953Srrs { 1885163953Srrs struct sctp_assoc_value *av; 1886163953Srrs 1887166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1888163953Srrs error = EINVAL; 1889167598Srrs#ifdef INET 1890163953Srrs if (av->assoc_value == AF_INET) { 1891163953Srrs av->assoc_value = sizeof(struct sockaddr_in); 1892163953Srrs error = 0; 1893163953Srrs } 1894163953Srrs#endif 1895167598Srrs#ifdef INET6 1896163953Srrs if (av->assoc_value == AF_INET6) { 1897163953Srrs av->assoc_value = sizeof(struct sockaddr_in6); 1898163953Srrs error = 0; 1899163953Srrs } 1900163953Srrs#endif 1901172091Srrs if (error) { 1902171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1903223132Stuexen } else { 1904223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1905172091Srrs } 1906223132Stuexen break; 1907163953Srrs } 1908169655Srrs case SCTP_GET_ASSOC_NUMBER: 1909163953Srrs { 1910169655Srrs uint32_t *value, cnt; 1911163953Srrs 1912169655Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1913163953Srrs cnt = 0; 1914163953Srrs SCTP_INP_RLOCK(inp); 1915169655Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 1916169655Srrs cnt++; 1917163953Srrs } 1918169655Srrs SCTP_INP_RUNLOCK(inp); 1919169655Srrs *value = cnt; 1920169655Srrs *optsize = sizeof(uint32_t); 1921223132Stuexen break; 1922169655Srrs } 1923169655Srrs case SCTP_GET_ASSOC_ID_LIST: 1924169655Srrs { 1925169655Srrs struct sctp_assoc_ids *ids; 1926169655Srrs unsigned int at, limit; 1927169655Srrs 1928169655Srrs SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize); 1929163953Srrs at = 0; 1930185694Srrs limit = (*optsize - sizeof(uint32_t)) / sizeof(sctp_assoc_t); 1931169655Srrs SCTP_INP_RLOCK(inp); 1932169655Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 1933169655Srrs if (at < limit) { 1934169655Srrs ids->gaids_assoc_id[at++] = sctp_get_associd(stcb); 1935169655Srrs } else { 1936169655Srrs error = EINVAL; 1937171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1938163953Srrs break; 1939163953Srrs } 1940163953Srrs } 1941163953Srrs SCTP_INP_RUNLOCK(inp); 1942223132Stuexen if (error == 0) { 1943223132Stuexen ids->gaids_number_of_ids = at; 1944223132Stuexen *optsize = ((at * sizeof(sctp_assoc_t)) + sizeof(uint32_t)); 1945223132Stuexen } 1946223132Stuexen break; 1947163953Srrs } 1948163953Srrs case SCTP_CONTEXT: 1949163953Srrs { 1950163953Srrs struct sctp_assoc_value *av; 1951163953Srrs 1952166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1953166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1954166675Srrs 1955166675Srrs if (stcb) { 1956166675Srrs av->assoc_value = stcb->asoc.context; 1957166675Srrs SCTP_TCB_UNLOCK(stcb); 1958163953Srrs } else { 1959224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 1960224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 1961224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 1962223132Stuexen SCTP_INP_RLOCK(inp); 1963223132Stuexen av->assoc_value = inp->sctp_context; 1964223132Stuexen SCTP_INP_RUNLOCK(inp); 1965223132Stuexen } else { 1966223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1967223132Stuexen error = EINVAL; 1968223132Stuexen } 1969163953Srrs } 1970223132Stuexen if (error == 0) { 1971223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1972223132Stuexen } 1973223132Stuexen break; 1974163953Srrs } 1975167598Srrs case SCTP_VRF_ID: 1976167598Srrs { 1977170056Srrs uint32_t *default_vrfid; 1978167598Srrs 1979170056Srrs SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize); 1980170056Srrs *default_vrfid = inp->def_vrf_id; 1981223132Stuexen *optsize = sizeof(uint32_t); 1982167598Srrs break; 1983167598Srrs } 1984167598Srrs case SCTP_GET_ASOC_VRF: 1985167598Srrs { 1986167598Srrs struct sctp_assoc_value *id; 1987167598Srrs 1988167598Srrs SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize); 1989167598Srrs SCTP_FIND_STCB(inp, stcb, id->assoc_id); 1990167598Srrs if (stcb == NULL) { 1991167598Srrs error = EINVAL; 1992171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1993223132Stuexen } else { 1994223132Stuexen id->assoc_value = stcb->asoc.vrf_id; 1995223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 1996167598Srrs } 1997167598Srrs break; 1998167598Srrs } 1999167598Srrs case SCTP_GET_VRF_IDS: 2000167598Srrs { 2001171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 2002167598Srrs error = EOPNOTSUPP; 2003167598Srrs break; 2004167598Srrs } 2005163953Srrs case SCTP_GET_NONCE_VALUES: 2006163953Srrs { 2007163953Srrs struct sctp_get_nonce_values *gnv; 2008163953Srrs 2009166675Srrs SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize); 2010166675Srrs SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id); 2011166675Srrs 2012166675Srrs if (stcb) { 2013163953Srrs gnv->gn_peers_tag = stcb->asoc.peer_vtag; 2014163953Srrs gnv->gn_local_tag = stcb->asoc.my_vtag; 2015163953Srrs SCTP_TCB_UNLOCK(stcb); 2016223132Stuexen *optsize = sizeof(struct sctp_get_nonce_values); 2017166675Srrs } else { 2018171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 2019166675Srrs error = ENOTCONN; 2020163953Srrs } 2021223132Stuexen break; 2022163953Srrs } 2023170056Srrs case SCTP_DELAYED_SACK: 2024163953Srrs { 2025170056Srrs struct sctp_sack_info *sack; 2026163953Srrs 2027170056Srrs SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, *optsize); 2028170056Srrs SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); 2029166675Srrs if (stcb) { 2030170056Srrs sack->sack_delay = stcb->asoc.delayed_ack; 2031170056Srrs sack->sack_freq = stcb->asoc.sack_freq; 2032166675Srrs SCTP_TCB_UNLOCK(stcb); 2033166675Srrs } else { 2034224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2035224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2036224918Stuexen (sack->sack_assoc_id == SCTP_FUTURE_ASSOC)) { 2037223132Stuexen SCTP_INP_RLOCK(inp); 2038223132Stuexen sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); 2039223132Stuexen sack->sack_freq = inp->sctp_ep.sctp_sack_freq; 2040223132Stuexen SCTP_INP_RUNLOCK(inp); 2041223132Stuexen } else { 2042223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2043223132Stuexen error = EINVAL; 2044223132Stuexen } 2045163953Srrs } 2046223132Stuexen if (error == 0) { 2047223132Stuexen *optsize = sizeof(struct sctp_sack_info); 2048223132Stuexen } 2049223132Stuexen break; 2050163953Srrs } 2051163953Srrs case SCTP_GET_SNDBUF_USE: 2052166675Srrs { 2053163953Srrs struct sctp_sockstat *ss; 2054163953Srrs 2055166675Srrs SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize); 2056166675Srrs SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id); 2057166675Srrs 2058166675Srrs if (stcb) { 2059166675Srrs ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size; 2060166675Srrs ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue + 2061166675Srrs stcb->asoc.size_on_all_streams); 2062166675Srrs SCTP_TCB_UNLOCK(stcb); 2063223132Stuexen *optsize = sizeof(struct sctp_sockstat); 2064166675Srrs } else { 2065171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 2066163953Srrs error = ENOTCONN; 2067163953Srrs } 2068223132Stuexen break; 2069163953Srrs } 2070170056Srrs case SCTP_MAX_BURST: 2071163953Srrs { 2072217895Stuexen struct sctp_assoc_value *av; 2073163953Srrs 2074217895Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 2075217895Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2076166675Srrs 2077217895Stuexen if (stcb) { 2078217895Stuexen av->assoc_value = stcb->asoc.max_burst; 2079217895Stuexen SCTP_TCB_UNLOCK(stcb); 2080217894Stuexen } else { 2081224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2082224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2083224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 2084223132Stuexen SCTP_INP_RLOCK(inp); 2085223132Stuexen av->assoc_value = inp->sctp_ep.max_burst; 2086223132Stuexen SCTP_INP_RUNLOCK(inp); 2087223132Stuexen } else { 2088223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2089223132Stuexen error = EINVAL; 2090223132Stuexen } 2091217894Stuexen } 2092223132Stuexen if (error == 0) { 2093223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 2094223132Stuexen } 2095223132Stuexen break; 2096163953Srrs } 2097163953Srrs case SCTP_MAXSEG: 2098163953Srrs { 2099167598Srrs struct sctp_assoc_value *av; 2100163953Srrs int ovh; 2101163953Srrs 2102167598Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 2103170056Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2104163953Srrs 2105167598Srrs if (stcb) { 2106167598Srrs av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc); 2107167598Srrs SCTP_TCB_UNLOCK(stcb); 2108163953Srrs } else { 2109224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2110224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2111224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 2112223132Stuexen SCTP_INP_RLOCK(inp); 2113223132Stuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2114223132Stuexen ovh = SCTP_MED_OVERHEAD; 2115223132Stuexen } else { 2116223132Stuexen ovh = SCTP_MED_V4_OVERHEAD; 2117223132Stuexen } 2118223132Stuexen if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT) 2119223132Stuexen av->assoc_value = 0; 2120223132Stuexen else 2121223132Stuexen av->assoc_value = inp->sctp_frag_point - ovh; 2122223132Stuexen SCTP_INP_RUNLOCK(inp); 2123167598Srrs } else { 2124223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2125223132Stuexen error = EINVAL; 2126167598Srrs } 2127163953Srrs } 2128223132Stuexen if (error == 0) { 2129223132Stuexen *optsize = sizeof(struct sctp_assoc_value); 2130223132Stuexen } 2131223132Stuexen break; 2132163953Srrs } 2133163953Srrs case SCTP_GET_STAT_LOG: 2134167598Srrs error = sctp_fill_stat_log(optval, optsize); 2135163953Srrs break; 2136163953Srrs case SCTP_EVENTS: 2137163953Srrs { 2138163953Srrs struct sctp_event_subscribe *events; 2139163953Srrs 2140166675Srrs SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize); 2141223132Stuexen memset(events, 0, sizeof(struct sctp_event_subscribe)); 2142163953Srrs SCTP_INP_RLOCK(inp); 2143163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) 2144163953Srrs events->sctp_data_io_event = 1; 2145163953Srrs 2146163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT)) 2147163953Srrs events->sctp_association_event = 1; 2148163953Srrs 2149163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT)) 2150163953Srrs events->sctp_address_event = 1; 2151163953Srrs 2152163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) 2153163953Srrs events->sctp_send_failure_event = 1; 2154163953Srrs 2155163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR)) 2156163953Srrs events->sctp_peer_error_event = 1; 2157163953Srrs 2158163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) 2159163953Srrs events->sctp_shutdown_event = 1; 2160163953Srrs 2161163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT)) 2162163953Srrs events->sctp_partial_delivery_event = 1; 2163163953Srrs 2164163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) 2165163953Srrs events->sctp_adaptation_layer_event = 1; 2166163953Srrs 2167163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT)) 2168163953Srrs events->sctp_authentication_event = 1; 2169163953Srrs 2170185694Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT)) 2171185694Srrs events->sctp_sender_dry_event = 1; 2172185694Srrs 2173163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) 2174202520Srrs events->sctp_stream_reset_event = 1; 2175163953Srrs SCTP_INP_RUNLOCK(inp); 2176166675Srrs *optsize = sizeof(struct sctp_event_subscribe); 2177223132Stuexen break; 2178163953Srrs } 2179163953Srrs case SCTP_ADAPTATION_LAYER: 2180166675Srrs { 2181166675Srrs uint32_t *value; 2182166675Srrs 2183166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2184166675Srrs 2185166675Srrs SCTP_INP_RLOCK(inp); 2186166675Srrs *value = inp->sctp_ep.adaptation_layer_indicator; 2187166675Srrs SCTP_INP_RUNLOCK(inp); 2188166675Srrs *optsize = sizeof(uint32_t); 2189223132Stuexen break; 2190163953Srrs } 2191163953Srrs case SCTP_SET_INITIAL_DBG_SEQ: 2192166675Srrs { 2193166675Srrs uint32_t *value; 2194166675Srrs 2195166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2196166675Srrs SCTP_INP_RLOCK(inp); 2197166675Srrs *value = inp->sctp_ep.initial_sequence_debug; 2198166675Srrs SCTP_INP_RUNLOCK(inp); 2199166675Srrs *optsize = sizeof(uint32_t); 2200223132Stuexen break; 2201163953Srrs } 2202163953Srrs case SCTP_GET_LOCAL_ADDR_SIZE: 2203166675Srrs { 2204166675Srrs uint32_t *value; 2205166675Srrs 2206166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2207166675Srrs SCTP_INP_RLOCK(inp); 2208168124Srrs *value = sctp_count_max_addresses(inp); 2209166675Srrs SCTP_INP_RUNLOCK(inp); 2210166675Srrs *optsize = sizeof(uint32_t); 2211223132Stuexen break; 2212163953Srrs } 2213163953Srrs case SCTP_GET_REMOTE_ADDR_SIZE: 2214163953Srrs { 2215166675Srrs uint32_t *value; 2216166675Srrs size_t size; 2217163953Srrs struct sctp_nets *net; 2218163953Srrs 2219166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2220166675Srrs /* FIXME MT: change to sctp_assoc_value? */ 2221166675Srrs SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value); 2222166675Srrs 2223166675Srrs if (stcb) { 2224166675Srrs size = 0; 2225166675Srrs /* Count the sizes */ 2226166675Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 2227221249Stuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 2228166675Srrs size += sizeof(struct sockaddr_in6); 2229166675Srrs } else { 2230221249Stuexen switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) { 2231221249Stuexen#ifdef INET 2232221249Stuexen case AF_INET: 2233221249Stuexen size += sizeof(struct sockaddr_in); 2234221249Stuexen break; 2235221249Stuexen#endif 2236221249Stuexen#ifdef INET6 2237221249Stuexen case AF_INET6: 2238221249Stuexen size += sizeof(struct sockaddr_in6); 2239221249Stuexen break; 2240221249Stuexen#endif 2241221249Stuexen default: 2242221249Stuexen break; 2243221249Stuexen } 2244166675Srrs } 2245163953Srrs } 2246166675Srrs SCTP_TCB_UNLOCK(stcb); 2247166675Srrs *value = (uint32_t) size; 2248223132Stuexen *optsize = sizeof(uint32_t); 2249166675Srrs } else { 2250171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 2251166675Srrs error = ENOTCONN; 2252163953Srrs } 2253223132Stuexen break; 2254163953Srrs } 2255163953Srrs case SCTP_GET_PEER_ADDRESSES: 2256163953Srrs /* 2257163953Srrs * Get the address information, an array is passed in to 2258163953Srrs * fill up we pack it. 2259163953Srrs */ 2260163953Srrs { 2261166675Srrs size_t cpsz, left; 2262163953Srrs struct sockaddr_storage *sas; 2263163953Srrs struct sctp_nets *net; 2264163953Srrs struct sctp_getaddresses *saddr; 2265163953Srrs 2266166675Srrs SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); 2267166675Srrs SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); 2268163953Srrs 2269166675Srrs if (stcb) { 2270166675Srrs left = (*optsize) - sizeof(struct sctp_getaddresses); 2271166675Srrs *optsize = sizeof(struct sctp_getaddresses); 2272166675Srrs sas = (struct sockaddr_storage *)&saddr->addr[0]; 2273166675Srrs 2274166675Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 2275221249Stuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 2276166675Srrs cpsz = sizeof(struct sockaddr_in6); 2277166675Srrs } else { 2278221249Stuexen switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) { 2279221249Stuexen#ifdef INET 2280221249Stuexen case AF_INET: 2281221249Stuexen cpsz = sizeof(struct sockaddr_in); 2282221249Stuexen break; 2283221249Stuexen#endif 2284221249Stuexen#ifdef INET6 2285221249Stuexen case AF_INET6: 2286221249Stuexen cpsz = sizeof(struct sockaddr_in6); 2287221249Stuexen break; 2288221249Stuexen#endif 2289221249Stuexen default: 2290221249Stuexen cpsz = 0; 2291221249Stuexen break; 2292221249Stuexen } 2293221249Stuexen } 2294221249Stuexen if (cpsz == 0) { 2295166675Srrs break; 2296166675Srrs } 2297166675Srrs if (left < cpsz) { 2298166675Srrs /* not enough room. */ 2299166675Srrs break; 2300166675Srrs } 2301221249Stuexen#if defined(INET) && defined(INET6) 2302178251Srrs if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) && 2303166675Srrs (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET)) { 2304166675Srrs /* Must map the address */ 2305166675Srrs in6_sin_2_v4mapsin6((struct sockaddr_in *)&net->ro._l_addr, 2306166675Srrs (struct sockaddr_in6 *)sas); 2307166675Srrs } else { 2308178251Srrs#endif 2309166675Srrs memcpy(sas, &net->ro._l_addr, cpsz); 2310221249Stuexen#if defined(INET) && defined(INET6) 2311166675Srrs } 2312178251Srrs#endif 2313166675Srrs ((struct sockaddr_in *)sas)->sin_port = stcb->rport; 2314166675Srrs 2315166675Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz); 2316166675Srrs left -= cpsz; 2317166675Srrs *optsize += cpsz; 2318163953Srrs } 2319166675Srrs SCTP_TCB_UNLOCK(stcb); 2320166675Srrs } else { 2321171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 2322166675Srrs error = ENOENT; 2323163953Srrs } 2324223132Stuexen break; 2325163953Srrs } 2326163953Srrs case SCTP_GET_LOCAL_ADDRESSES: 2327163953Srrs { 2328166675Srrs size_t limit, actual; 2329163953Srrs struct sockaddr_storage *sas; 2330163953Srrs struct sctp_getaddresses *saddr; 2331163953Srrs 2332166675Srrs SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); 2333166675Srrs SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); 2334163953Srrs 2335163953Srrs sas = (struct sockaddr_storage *)&saddr->addr[0]; 2336166675Srrs limit = *optsize - sizeof(sctp_assoc_t); 2337168124Srrs actual = sctp_fill_up_addresses(inp, stcb, limit, sas); 2338169655Srrs if (stcb) { 2339163953Srrs SCTP_TCB_UNLOCK(stcb); 2340169655Srrs } 2341166675Srrs *optsize = sizeof(struct sockaddr_storage) + actual; 2342223132Stuexen break; 2343163953Srrs } 2344163953Srrs case SCTP_PEER_ADDR_PARAMS: 2345163953Srrs { 2346163953Srrs struct sctp_paddrparams *paddrp; 2347163953Srrs struct sctp_nets *net; 2348163953Srrs 2349166675Srrs SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize); 2350166675Srrs SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); 2351163953Srrs 2352163953Srrs net = NULL; 2353166675Srrs if (stcb) { 2354166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address); 2355166675Srrs } else { 2356166675Srrs /* 2357166675Srrs * We increment here since 2358166675Srrs * sctp_findassociation_ep_addr() wil do a 2359166675Srrs * decrement if it finds the stcb as long as 2360166675Srrs * the locked tcb (last argument) is NOT a 2361166675Srrs * TCB.. aka NULL. 2362166675Srrs */ 2363166675Srrs SCTP_INP_INCR_REF(inp); 2364166675Srrs stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddrp->spp_address, &net, NULL, NULL); 2365163953Srrs if (stcb == NULL) { 2366166675Srrs SCTP_INP_DECR_REF(inp); 2367163953Srrs } 2368163953Srrs } 2369171943Srrs if (stcb && (net == NULL)) { 2370171943Srrs struct sockaddr *sa; 2371163953Srrs 2372171943Srrs sa = (struct sockaddr *)&paddrp->spp_address; 2373221249Stuexen#ifdef INET 2374171943Srrs if (sa->sa_family == AF_INET) { 2375171943Srrs struct sockaddr_in *sin; 2376171943Srrs 2377171943Srrs sin = (struct sockaddr_in *)sa; 2378171943Srrs if (sin->sin_addr.s_addr) { 2379171943Srrs error = EINVAL; 2380171943Srrs SCTP_TCB_UNLOCK(stcb); 2381171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2382171943Srrs break; 2383171943Srrs } 2384221249Stuexen } else 2385221249Stuexen#endif 2386221249Stuexen#ifdef INET6 2387221249Stuexen if (sa->sa_family == AF_INET6) { 2388171943Srrs struct sockaddr_in6 *sin6; 2389171943Srrs 2390171943Srrs sin6 = (struct sockaddr_in6 *)sa; 2391171943Srrs if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 2392171943Srrs error = EINVAL; 2393171943Srrs SCTP_TCB_UNLOCK(stcb); 2394171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2395171943Srrs break; 2396171943Srrs } 2397221249Stuexen } else 2398221249Stuexen#endif 2399221249Stuexen { 2400171943Srrs error = EAFNOSUPPORT; 2401171943Srrs SCTP_TCB_UNLOCK(stcb); 2402171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2403171943Srrs break; 2404171943Srrs } 2405171943Srrs } 2406163953Srrs if (stcb) { 2407224641Stuexen /* Applies to the specific association */ 2408163953Srrs paddrp->spp_flags = 0; 2409163953Srrs if (net) { 2410170056Srrs int ovh; 2411170056Srrs 2412170056Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2413170056Srrs ovh = SCTP_MED_OVERHEAD; 2414170056Srrs } else { 2415170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 2416170056Srrs } 2417170056Srrs 2418224641Stuexen paddrp->spp_hbinterval = net->heart_beat_delay; 2419163953Srrs paddrp->spp_pathmaxrxt = net->failure_threshold; 2420170056Srrs paddrp->spp_pathmtu = net->mtu - ovh; 2421163953Srrs /* get flags for HB */ 2422225635Stuexen if (net->dest_state & SCTP_ADDR_NOHB) { 2423163953Srrs paddrp->spp_flags |= SPP_HB_DISABLE; 2424225635Stuexen } else { 2425163953Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 2426225635Stuexen } 2427163953Srrs /* get flags for PMTU */ 2428225635Stuexen if (net->dest_state & SCTP_ADDR_NO_PMTUD) { 2429163953Srrs paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2430163953Srrs } else { 2431163953Srrs paddrp->spp_flags |= SPP_PMTUD_DISABLE; 2432163953Srrs } 2433225549Stuexen if (net->dscp & 0x01) { 2434226252Stuexen paddrp->spp_dscp = net->dscp & 0xfc; 2435224870Stuexen paddrp->spp_flags |= SPP_DSCP; 2436163953Srrs } 2437167598Srrs#ifdef INET6 2438225549Stuexen if ((net->ro._l_addr.sa.sa_family == AF_INET6) && 2439225549Stuexen (net->flowlabel & 0x80000000)) { 2440225549Stuexen paddrp->spp_ipv6_flowlabel = net->flowlabel & 0x000fffff; 2441163953Srrs paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2442163953Srrs } 2443163953Srrs#endif 2444163953Srrs } else { 2445163953Srrs /* 2446163953Srrs * No destination so return default 2447163953Srrs * value 2448163953Srrs */ 2449163953Srrs paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure; 2450163953Srrs paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc); 2451225549Stuexen if (stcb->asoc.default_dscp & 0x01) { 2452226252Stuexen paddrp->spp_dscp = stcb->asoc.default_dscp & 0xfc; 2453225549Stuexen paddrp->spp_flags |= SPP_DSCP; 2454225549Stuexen } 2455167598Srrs#ifdef INET6 2456225549Stuexen if (stcb->asoc.default_flowlabel & 0x80000000) { 2457225549Stuexen paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel & 0x000fffff; 2458225549Stuexen paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2459225549Stuexen } 2460163953Srrs#endif 2461163953Srrs /* default settings should be these */ 2462225635Stuexen if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { 2463224641Stuexen paddrp->spp_flags |= SPP_HB_DISABLE; 2464224641Stuexen } else { 2465163953Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 2466163953Srrs } 2467225635Stuexen if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) { 2468225635Stuexen paddrp->spp_flags |= SPP_PMTUD_DISABLE; 2469225635Stuexen } else { 2470170056Srrs paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2471170056Srrs } 2472225635Stuexen paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay; 2473163953Srrs } 2474163953Srrs paddrp->spp_assoc_id = sctp_get_associd(stcb); 2475163953Srrs SCTP_TCB_UNLOCK(stcb); 2476163953Srrs } else { 2477224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2478224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2479224918Stuexen (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) { 2480223132Stuexen /* Use endpoint defaults */ 2481223132Stuexen SCTP_INP_RLOCK(inp); 2482223132Stuexen paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure; 2483223132Stuexen paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); 2484223132Stuexen paddrp->spp_assoc_id = SCTP_FUTURE_ASSOC; 2485223132Stuexen /* get inp's default */ 2486225549Stuexen if (inp->sctp_ep.default_dscp & 0x01) { 2487226252Stuexen paddrp->spp_dscp = inp->sctp_ep.default_dscp & 0xfc; 2488225549Stuexen paddrp->spp_flags |= SPP_DSCP; 2489225549Stuexen } 2490167598Srrs#ifdef INET6 2491225549Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 2492225549Stuexen (inp->sctp_ep.default_flowlabel & 0x80000000)) { 2493225549Stuexen paddrp->spp_ipv6_flowlabel = inp->sctp_ep.default_flowlabel & 0x000fffff; 2494223132Stuexen paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2495223132Stuexen } 2496163953Srrs#endif 2497223132Stuexen /* can't return this */ 2498223132Stuexen paddrp->spp_pathmtu = 0; 2499170056Srrs 2500223132Stuexen if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { 2501223132Stuexen paddrp->spp_flags |= SPP_HB_ENABLE; 2502223132Stuexen } else { 2503223132Stuexen paddrp->spp_flags |= SPP_HB_DISABLE; 2504223132Stuexen } 2505225635Stuexen if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) { 2506225635Stuexen paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2507225635Stuexen } else { 2508225635Stuexen paddrp->spp_flags |= SPP_PMTUD_DISABLE; 2509225635Stuexen } 2510223132Stuexen SCTP_INP_RUNLOCK(inp); 2511170056Srrs } else { 2512223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2513223132Stuexen error = EINVAL; 2514170056Srrs } 2515163953Srrs } 2516223132Stuexen if (error == 0) { 2517223132Stuexen *optsize = sizeof(struct sctp_paddrparams); 2518223132Stuexen } 2519223132Stuexen break; 2520163953Srrs } 2521163953Srrs case SCTP_GET_PEER_ADDR_INFO: 2522163953Srrs { 2523163953Srrs struct sctp_paddrinfo *paddri; 2524163953Srrs struct sctp_nets *net; 2525163953Srrs 2526166675Srrs SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize); 2527166675Srrs SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id); 2528166675Srrs 2529163953Srrs net = NULL; 2530166675Srrs if (stcb) { 2531166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddri->spinfo_address); 2532166675Srrs } else { 2533166675Srrs /* 2534166675Srrs * We increment here since 2535166675Srrs * sctp_findassociation_ep_addr() wil do a 2536166675Srrs * decrement if it finds the stcb as long as 2537166675Srrs * the locked tcb (last argument) is NOT a 2538166675Srrs * TCB.. aka NULL. 2539166675Srrs */ 2540166675Srrs SCTP_INP_INCR_REF(inp); 2541166675Srrs stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddri->spinfo_address, &net, NULL, NULL); 2542166675Srrs if (stcb == NULL) { 2543166675Srrs SCTP_INP_DECR_REF(inp); 2544163953Srrs } 2545166675Srrs } 2546163953Srrs 2547166675Srrs if ((stcb) && (net)) { 2548217635Srrs if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { 2549217638Stuexen /* It's unconfirmed */ 2550217635Srrs paddri->spinfo_state = SCTP_UNCONFIRMED; 2551217635Srrs } else if (net->dest_state & SCTP_ADDR_REACHABLE) { 2552217638Stuexen /* It's active */ 2553217635Srrs paddri->spinfo_state = SCTP_ACTIVE; 2554217635Srrs } else { 2555217638Stuexen /* It's inactive */ 2556217635Srrs paddri->spinfo_state = SCTP_INACTIVE; 2557217635Srrs } 2558166675Srrs paddri->spinfo_cwnd = net->cwnd; 2559219014Stuexen paddri->spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT; 2560166675Srrs paddri->spinfo_rto = net->RTO; 2561166675Srrs paddri->spinfo_assoc_id = sctp_get_associd(stcb); 2562222029Stuexen paddri->spinfo_mtu = net->mtu; 2563166675Srrs SCTP_TCB_UNLOCK(stcb); 2564223132Stuexen *optsize = sizeof(struct sctp_paddrinfo); 2565163953Srrs } else { 2566163953Srrs if (stcb) { 2567163953Srrs SCTP_TCB_UNLOCK(stcb); 2568163953Srrs } 2569171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 2570163953Srrs error = ENOENT; 2571163953Srrs } 2572223132Stuexen break; 2573163953Srrs } 2574163953Srrs case SCTP_PCB_STATUS: 2575163953Srrs { 2576163953Srrs struct sctp_pcbinfo *spcb; 2577163953Srrs 2578166675Srrs SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize); 2579163953Srrs sctp_fill_pcbinfo(spcb); 2580166675Srrs *optsize = sizeof(struct sctp_pcbinfo); 2581223132Stuexen break; 2582163953Srrs } 2583163953Srrs case SCTP_STATUS: 2584163953Srrs { 2585163953Srrs struct sctp_nets *net; 2586163953Srrs struct sctp_status *sstat; 2587163953Srrs 2588166675Srrs SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize); 2589166675Srrs SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id); 2590163953Srrs 2591163953Srrs if (stcb == NULL) { 2592223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2593163953Srrs error = EINVAL; 2594163953Srrs break; 2595163953Srrs } 2596163953Srrs /* 2597163953Srrs * I think passing the state is fine since 2598163953Srrs * sctp_constants.h will be available to the user 2599163953Srrs * land. 2600163953Srrs */ 2601163953Srrs sstat->sstat_state = stcb->asoc.state; 2602173179Srrs sstat->sstat_assoc_id = sctp_get_associd(stcb); 2603163953Srrs sstat->sstat_rwnd = stcb->asoc.peers_rwnd; 2604163953Srrs sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt; 2605163953Srrs /* 2606163953Srrs * We can't include chunks that have been passed to 2607163953Srrs * the socket layer. Only things in queue. 2608163953Srrs */ 2609163953Srrs sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue + 2610163953Srrs stcb->asoc.cnt_on_all_streams); 2611163953Srrs 2612163953Srrs 2613163953Srrs sstat->sstat_instrms = stcb->asoc.streamincnt; 2614163953Srrs sstat->sstat_outstrms = stcb->asoc.streamoutcnt; 2615163953Srrs sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc); 2616163953Srrs memcpy(&sstat->sstat_primary.spinfo_address, 2617163953Srrs &stcb->asoc.primary_destination->ro._l_addr, 2618163953Srrs ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len); 2619163953Srrs net = stcb->asoc.primary_destination; 2620163953Srrs ((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport; 2621163953Srrs /* 2622163953Srrs * Again the user can get info from sctp_constants.h 2623163953Srrs * for what the state of the network is. 2624163953Srrs */ 2625217635Srrs if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { 2626217635Srrs /* It's unconfirmed */ 2627217635Srrs sstat->sstat_primary.spinfo_state = SCTP_UNCONFIRMED; 2628217635Srrs } else if (net->dest_state & SCTP_ADDR_REACHABLE) { 2629217638Stuexen /* It's active */ 2630217635Srrs sstat->sstat_primary.spinfo_state = SCTP_ACTIVE; 2631217635Srrs } else { 2632217638Stuexen /* It's inactive */ 2633217635Srrs sstat->sstat_primary.spinfo_state = SCTP_INACTIVE; 2634217635Srrs } 2635163953Srrs sstat->sstat_primary.spinfo_cwnd = net->cwnd; 2636219014Stuexen sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT; 2637163953Srrs sstat->sstat_primary.spinfo_rto = net->RTO; 2638163953Srrs sstat->sstat_primary.spinfo_mtu = net->mtu; 2639163953Srrs sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb); 2640163953Srrs SCTP_TCB_UNLOCK(stcb); 2641223132Stuexen *optsize = sizeof(struct sctp_status); 2642223132Stuexen break; 2643163953Srrs } 2644163953Srrs case SCTP_RTOINFO: 2645163953Srrs { 2646163953Srrs struct sctp_rtoinfo *srto; 2647163953Srrs 2648166675Srrs SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize); 2649166675Srrs SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); 2650166675Srrs 2651166675Srrs if (stcb) { 2652166675Srrs srto->srto_initial = stcb->asoc.initial_rto; 2653166675Srrs srto->srto_max = stcb->asoc.maxrto; 2654166675Srrs srto->srto_min = stcb->asoc.minrto; 2655166675Srrs SCTP_TCB_UNLOCK(stcb); 2656166675Srrs } else { 2657224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2658224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2659224918Stuexen (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) { 2660223132Stuexen SCTP_INP_RLOCK(inp); 2661223132Stuexen srto->srto_initial = inp->sctp_ep.initial_rto; 2662223132Stuexen srto->srto_max = inp->sctp_ep.sctp_maxrto; 2663223132Stuexen srto->srto_min = inp->sctp_ep.sctp_minrto; 2664223132Stuexen SCTP_INP_RUNLOCK(inp); 2665223132Stuexen } else { 2666223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2667223132Stuexen error = EINVAL; 2668223132Stuexen } 2669163953Srrs } 2670223132Stuexen if (error == 0) { 2671223132Stuexen *optsize = sizeof(struct sctp_rtoinfo); 2672223132Stuexen } 2673223132Stuexen break; 2674163953Srrs } 2675215410Stuexen case SCTP_TIMEOUTS: 2676215410Stuexen { 2677215410Stuexen struct sctp_timeouts *stimo; 2678215410Stuexen 2679215410Stuexen SCTP_CHECK_AND_CAST(stimo, optval, struct sctp_timeouts, *optsize); 2680215410Stuexen SCTP_FIND_STCB(inp, stcb, stimo->stimo_assoc_id); 2681215410Stuexen 2682215410Stuexen if (stcb) { 2683215410Stuexen stimo->stimo_init = stcb->asoc.timoinit; 2684215410Stuexen stimo->stimo_data = stcb->asoc.timodata; 2685215410Stuexen stimo->stimo_sack = stcb->asoc.timosack; 2686215410Stuexen stimo->stimo_shutdown = stcb->asoc.timoshutdown; 2687215410Stuexen stimo->stimo_heartbeat = stcb->asoc.timoheartbeat; 2688215410Stuexen stimo->stimo_cookie = stcb->asoc.timocookie; 2689215410Stuexen stimo->stimo_shutdownack = stcb->asoc.timoshutdownack; 2690215410Stuexen SCTP_TCB_UNLOCK(stcb); 2691223132Stuexen *optsize = sizeof(struct sctp_timeouts); 2692215410Stuexen } else { 2693223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2694215410Stuexen error = EINVAL; 2695215410Stuexen } 2696223132Stuexen break; 2697215410Stuexen } 2698163953Srrs case SCTP_ASSOCINFO: 2699163953Srrs { 2700163953Srrs struct sctp_assocparams *sasoc; 2701163953Srrs 2702166675Srrs SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize); 2703166675Srrs SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); 2704163953Srrs 2705163953Srrs if (stcb) { 2706171477Srrs sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life); 2707163953Srrs sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times; 2708163953Srrs sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets; 2709163953Srrs sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd; 2710163953Srrs sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd; 2711163953Srrs SCTP_TCB_UNLOCK(stcb); 2712163953Srrs } else { 2713224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2714224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2715224918Stuexen (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) { 2716223132Stuexen SCTP_INP_RLOCK(inp); 2717223132Stuexen sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life); 2718223132Stuexen sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times; 2719223132Stuexen sasoc->sasoc_number_peer_destinations = 0; 2720223132Stuexen sasoc->sasoc_peer_rwnd = 0; 2721223132Stuexen sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv); 2722223132Stuexen SCTP_INP_RUNLOCK(inp); 2723223132Stuexen } else { 2724223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2725223132Stuexen error = EINVAL; 2726223132Stuexen } 2727163953Srrs } 2728223132Stuexen if (error == 0) { 2729223132Stuexen *optsize = sizeof(struct sctp_assocparams); 2730223132Stuexen } 2731223132Stuexen break; 2732163953Srrs } 2733163953Srrs case SCTP_DEFAULT_SEND_PARAM: 2734163953Srrs { 2735163953Srrs struct sctp_sndrcvinfo *s_info; 2736163953Srrs 2737166675Srrs SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize); 2738166675Srrs SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); 2739166675Srrs 2740166675Srrs if (stcb) { 2741170056Srrs memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send)); 2742166675Srrs SCTP_TCB_UNLOCK(stcb); 2743166675Srrs } else { 2744224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2745224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2746224918Stuexen (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC)) { 2747223132Stuexen SCTP_INP_RLOCK(inp); 2748223132Stuexen memcpy(s_info, &inp->def_send, sizeof(inp->def_send)); 2749223132Stuexen SCTP_INP_RUNLOCK(inp); 2750223132Stuexen } else { 2751223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2752223132Stuexen error = EINVAL; 2753223132Stuexen } 2754163953Srrs } 2755223132Stuexen if (error == 0) { 2756223132Stuexen *optsize = sizeof(struct sctp_sndrcvinfo); 2757223132Stuexen } 2758223132Stuexen break; 2759163953Srrs } 2760163953Srrs case SCTP_INITMSG: 2761163953Srrs { 2762163953Srrs struct sctp_initmsg *sinit; 2763163953Srrs 2764166675Srrs SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize); 2765163953Srrs SCTP_INP_RLOCK(inp); 2766163953Srrs sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count; 2767163953Srrs sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome; 2768163953Srrs sinit->sinit_max_attempts = inp->sctp_ep.max_init_times; 2769163953Srrs sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max; 2770163953Srrs SCTP_INP_RUNLOCK(inp); 2771223132Stuexen *optsize = sizeof(struct sctp_initmsg); 2772223132Stuexen break; 2773163953Srrs } 2774163953Srrs case SCTP_PRIMARY_ADDR: 2775163953Srrs /* we allow a "get" operation on this */ 2776163953Srrs { 2777163953Srrs struct sctp_setprim *ssp; 2778163953Srrs 2779166675Srrs SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize); 2780166675Srrs SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id); 2781166675Srrs 2782166675Srrs if (stcb) { 2783166675Srrs /* simply copy out the sockaddr_storage... */ 2784170056Srrs int len; 2785170056Srrs 2786170056Srrs len = *optsize; 2787170056Srrs if (len > stcb->asoc.primary_destination->ro._l_addr.sa.sa_len) 2788170056Srrs len = stcb->asoc.primary_destination->ro._l_addr.sa.sa_len; 2789170056Srrs 2790170056Srrs memcpy(&ssp->ssp_addr, 2791170056Srrs &stcb->asoc.primary_destination->ro._l_addr, 2792170056Srrs len); 2793166675Srrs SCTP_TCB_UNLOCK(stcb); 2794223132Stuexen *optsize = sizeof(struct sctp_setprim); 2795166675Srrs } else { 2796223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2797163953Srrs error = EINVAL; 2798163953Srrs } 2799223132Stuexen break; 2800163953Srrs } 2801163953Srrs case SCTP_HMAC_IDENT: 2802163953Srrs { 2803163953Srrs struct sctp_hmacalgo *shmac; 2804163953Srrs sctp_hmaclist_t *hmaclist; 2805163953Srrs uint32_t size; 2806163953Srrs int i; 2807163953Srrs 2808166675Srrs SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize); 2809166675Srrs 2810163953Srrs SCTP_INP_RLOCK(inp); 2811163953Srrs hmaclist = inp->sctp_ep.local_hmacs; 2812163953Srrs if (hmaclist == NULL) { 2813163953Srrs /* no HMACs to return */ 2814166675Srrs *optsize = sizeof(*shmac); 2815168299Srrs SCTP_INP_RUNLOCK(inp); 2816163953Srrs break; 2817163953Srrs } 2818163953Srrs /* is there room for all of the hmac ids? */ 2819163953Srrs size = sizeof(*shmac) + (hmaclist->num_algo * 2820163953Srrs sizeof(shmac->shmac_idents[0])); 2821166675Srrs if ((size_t)(*optsize) < size) { 2822223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2823163953Srrs error = EINVAL; 2824163953Srrs SCTP_INP_RUNLOCK(inp); 2825163953Srrs break; 2826163953Srrs } 2827163953Srrs /* copy in the list */ 2828181054Srrs shmac->shmac_number_of_idents = hmaclist->num_algo; 2829181054Srrs for (i = 0; i < hmaclist->num_algo; i++) { 2830163953Srrs shmac->shmac_idents[i] = hmaclist->hmac[i]; 2831181054Srrs } 2832163953Srrs SCTP_INP_RUNLOCK(inp); 2833166675Srrs *optsize = size; 2834163953Srrs break; 2835163953Srrs } 2836163953Srrs case SCTP_AUTH_ACTIVE_KEY: 2837163953Srrs { 2838163953Srrs struct sctp_authkeyid *scact; 2839163953Srrs 2840166675Srrs SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize); 2841166675Srrs SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); 2842166675Srrs 2843166675Srrs if (stcb) { 2844163953Srrs /* get the active key on the assoc */ 2845185694Srrs scact->scact_keynumber = stcb->asoc.authinfo.active_keyid; 2846163953Srrs SCTP_TCB_UNLOCK(stcb); 2847163953Srrs } else { 2848224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2849224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2850224918Stuexen (scact->scact_assoc_id == SCTP_FUTURE_ASSOC)) { 2851223132Stuexen /* get the endpoint active key */ 2852223132Stuexen SCTP_INP_RLOCK(inp); 2853223132Stuexen scact->scact_keynumber = inp->sctp_ep.default_keyid; 2854223132Stuexen SCTP_INP_RUNLOCK(inp); 2855223132Stuexen } else { 2856223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2857223132Stuexen error = EINVAL; 2858223132Stuexen } 2859163953Srrs } 2860223132Stuexen if (error == 0) { 2861223132Stuexen *optsize = sizeof(struct sctp_authkeyid); 2862223132Stuexen } 2863163953Srrs break; 2864163953Srrs } 2865163953Srrs case SCTP_LOCAL_AUTH_CHUNKS: 2866163953Srrs { 2867163953Srrs struct sctp_authchunks *sac; 2868163953Srrs sctp_auth_chklist_t *chklist = NULL; 2869166675Srrs size_t size = 0; 2870163953Srrs 2871166675Srrs SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); 2872166675Srrs SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); 2873166675Srrs 2874166675Srrs if (stcb) { 2875163953Srrs /* get off the assoc */ 2876163953Srrs chklist = stcb->asoc.local_auth_chunks; 2877163953Srrs /* is there enough space? */ 2878163953Srrs size = sctp_auth_get_chklist_size(chklist); 2879166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2880163953Srrs error = EINVAL; 2881171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2882166675Srrs } else { 2883166675Srrs /* copy in the chunks */ 2884169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2885223132Stuexen *optsize = sizeof(struct sctp_authchunks) + size; 2886163953Srrs } 2887163953Srrs SCTP_TCB_UNLOCK(stcb); 2888163953Srrs } else { 2889224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2890224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2891224918Stuexen (sac->gauth_assoc_id == SCTP_FUTURE_ASSOC)) { 2892223132Stuexen /* get off the endpoint */ 2893223132Stuexen SCTP_INP_RLOCK(inp); 2894223132Stuexen chklist = inp->sctp_ep.local_auth_chunks; 2895223132Stuexen /* is there enough space? */ 2896223132Stuexen size = sctp_auth_get_chklist_size(chklist); 2897223132Stuexen if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2898223132Stuexen error = EINVAL; 2899223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2900223132Stuexen } else { 2901223132Stuexen /* copy in the chunks */ 2902223132Stuexen (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2903223132Stuexen *optsize = sizeof(struct sctp_authchunks) + size; 2904223132Stuexen } 2905223132Stuexen SCTP_INP_RUNLOCK(inp); 2906223132Stuexen } else { 2907223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2908163953Srrs error = EINVAL; 2909163953Srrs } 2910163953Srrs } 2911163953Srrs break; 2912163953Srrs } 2913163953Srrs case SCTP_PEER_AUTH_CHUNKS: 2914163953Srrs { 2915163953Srrs struct sctp_authchunks *sac; 2916163953Srrs sctp_auth_chklist_t *chklist = NULL; 2917166675Srrs size_t size = 0; 2918163953Srrs 2919166675Srrs SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); 2920166675Srrs SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); 2921166675Srrs 2922166675Srrs if (stcb) { 2923166675Srrs /* get off the assoc */ 2924166675Srrs chklist = stcb->asoc.peer_auth_chunks; 2925166675Srrs /* is there enough space? */ 2926166675Srrs size = sctp_auth_get_chklist_size(chklist); 2927166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2928166675Srrs error = EINVAL; 2929171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2930166675Srrs } else { 2931166675Srrs /* copy in the chunks */ 2932169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2933223132Stuexen *optsize = sizeof(struct sctp_authchunks) + size; 2934166675Srrs } 2935166675Srrs SCTP_TCB_UNLOCK(stcb); 2936166675Srrs } else { 2937171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 2938163953Srrs error = ENOENT; 2939163953Srrs } 2940163953Srrs break; 2941163953Srrs } 2942223132Stuexen case SCTP_EVENT: 2943223132Stuexen { 2944223132Stuexen struct sctp_event *event; 2945223132Stuexen uint32_t event_type; 2946163953Srrs 2947223132Stuexen SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, *optsize); 2948223132Stuexen SCTP_FIND_STCB(inp, stcb, event->se_assoc_id); 2949163953Srrs 2950223132Stuexen switch (event->se_type) { 2951223132Stuexen case SCTP_ASSOC_CHANGE: 2952223132Stuexen event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT; 2953223132Stuexen break; 2954223132Stuexen case SCTP_PEER_ADDR_CHANGE: 2955223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPADDREVNT; 2956223132Stuexen break; 2957223132Stuexen case SCTP_REMOTE_ERROR: 2958223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPEERERR; 2959223132Stuexen break; 2960223132Stuexen case SCTP_SEND_FAILED: 2961223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT; 2962223132Stuexen break; 2963223132Stuexen case SCTP_SHUTDOWN_EVENT: 2964223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT; 2965223132Stuexen break; 2966223132Stuexen case SCTP_ADAPTATION_INDICATION: 2967223132Stuexen event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT; 2968223132Stuexen break; 2969223132Stuexen case SCTP_PARTIAL_DELIVERY_EVENT: 2970223132Stuexen event_type = SCTP_PCB_FLAGS_PDAPIEVNT; 2971223132Stuexen break; 2972223132Stuexen case SCTP_AUTHENTICATION_EVENT: 2973223132Stuexen event_type = SCTP_PCB_FLAGS_AUTHEVNT; 2974223132Stuexen break; 2975223132Stuexen case SCTP_STREAM_RESET_EVENT: 2976223132Stuexen event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT; 2977223132Stuexen break; 2978223132Stuexen case SCTP_SENDER_DRY_EVENT: 2979223132Stuexen event_type = SCTP_PCB_FLAGS_DRYEVNT; 2980223132Stuexen break; 2981223132Stuexen case SCTP_NOTIFICATIONS_STOPPED_EVENT: 2982223132Stuexen event_type = 0; 2983223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); 2984223132Stuexen error = ENOTSUP; 2985223132Stuexen break; 2986223132Stuexen default: 2987223132Stuexen event_type = 0; 2988223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2989223132Stuexen error = EINVAL; 2990223132Stuexen break; 2991223132Stuexen } 2992223132Stuexen if (event_type > 0) { 2993223132Stuexen if (stcb) { 2994223132Stuexen event->se_on = sctp_stcb_is_feature_on(inp, stcb, event_type); 2995223132Stuexen SCTP_TCB_UNLOCK(stcb); 2996223132Stuexen } else { 2997224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2998224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 2999224918Stuexen (event->se_assoc_id == SCTP_FUTURE_ASSOC)) { 3000223132Stuexen SCTP_INP_RLOCK(inp); 3001223132Stuexen event->se_on = sctp_is_feature_on(inp, event_type); 3002223132Stuexen SCTP_INP_RUNLOCK(inp); 3003223132Stuexen } else { 3004223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3005223132Stuexen error = EINVAL; 3006223132Stuexen } 3007223132Stuexen } 3008223132Stuexen } 3009223132Stuexen if (error == 0) { 3010223132Stuexen *optsize = sizeof(struct sctp_event); 3011223132Stuexen } 3012223132Stuexen break; 3013223132Stuexen } 3014223132Stuexen case SCTP_RECVRCVINFO: 3015223132Stuexen { 3016223132Stuexen int onoff; 3017223132Stuexen 3018223132Stuexen if (*optsize < sizeof(int)) { 3019223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3020223132Stuexen error = EINVAL; 3021223132Stuexen } else { 3022230104Stuexen SCTP_INP_RLOCK(inp); 3023223132Stuexen onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO); 3024223132Stuexen SCTP_INP_RUNLOCK(inp); 3025223132Stuexen } 3026223132Stuexen if (error == 0) { 3027223132Stuexen /* return the option value */ 3028223132Stuexen *(int *)optval = onoff; 3029223132Stuexen *optsize = sizeof(int); 3030223132Stuexen } 3031223132Stuexen break; 3032223132Stuexen } 3033223132Stuexen case SCTP_RECVNXTINFO: 3034223132Stuexen { 3035223132Stuexen int onoff; 3036223132Stuexen 3037223132Stuexen if (*optsize < sizeof(int)) { 3038223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3039223132Stuexen error = EINVAL; 3040223132Stuexen } else { 3041230104Stuexen SCTP_INP_RLOCK(inp); 3042223132Stuexen onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO); 3043223132Stuexen SCTP_INP_RUNLOCK(inp); 3044223132Stuexen } 3045223132Stuexen if (error == 0) { 3046223132Stuexen /* return the option value */ 3047223132Stuexen *(int *)optval = onoff; 3048223132Stuexen *optsize = sizeof(int); 3049223132Stuexen } 3050223132Stuexen break; 3051223132Stuexen } 3052223132Stuexen case SCTP_DEFAULT_SNDINFO: 3053223132Stuexen { 3054223132Stuexen struct sctp_sndinfo *info; 3055223132Stuexen 3056223132Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, *optsize); 3057223132Stuexen SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id); 3058223132Stuexen 3059223132Stuexen if (stcb) { 3060223132Stuexen info->snd_sid = stcb->asoc.def_send.sinfo_stream; 3061223132Stuexen info->snd_flags = stcb->asoc.def_send.sinfo_flags; 3062223162Stuexen info->snd_flags &= 0xfff0; 3063223132Stuexen info->snd_ppid = stcb->asoc.def_send.sinfo_ppid; 3064223132Stuexen info->snd_context = stcb->asoc.def_send.sinfo_context; 3065223132Stuexen SCTP_TCB_UNLOCK(stcb); 3066223132Stuexen } else { 3067224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3068224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3069224918Stuexen (info->snd_assoc_id == SCTP_FUTURE_ASSOC)) { 3070223132Stuexen SCTP_INP_RLOCK(inp); 3071223132Stuexen info->snd_sid = inp->def_send.sinfo_stream; 3072223132Stuexen info->snd_flags = inp->def_send.sinfo_flags; 3073223162Stuexen info->snd_flags &= 0xfff0; 3074223132Stuexen info->snd_ppid = inp->def_send.sinfo_ppid; 3075223132Stuexen info->snd_context = inp->def_send.sinfo_context; 3076223132Stuexen SCTP_INP_RUNLOCK(inp); 3077223132Stuexen } else { 3078223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3079223132Stuexen error = EINVAL; 3080223132Stuexen } 3081223132Stuexen } 3082223132Stuexen if (error == 0) { 3083223132Stuexen *optsize = sizeof(struct sctp_sndinfo); 3084223132Stuexen } 3085223132Stuexen break; 3086223132Stuexen } 3087223162Stuexen case SCTP_DEFAULT_PRINFO: 3088223162Stuexen { 3089223162Stuexen struct sctp_default_prinfo *info; 3090223162Stuexen 3091223162Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, *optsize); 3092223162Stuexen SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id); 3093223162Stuexen 3094223162Stuexen if (stcb) { 3095223162Stuexen info->pr_policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); 3096223162Stuexen info->pr_value = stcb->asoc.def_send.sinfo_timetolive; 3097223162Stuexen SCTP_TCB_UNLOCK(stcb); 3098223162Stuexen } else { 3099224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3100224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3101224918Stuexen (info->pr_assoc_id == SCTP_FUTURE_ASSOC)) { 3102223162Stuexen SCTP_INP_RLOCK(inp); 3103223162Stuexen info->pr_policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags); 3104223162Stuexen info->pr_value = inp->def_send.sinfo_timetolive; 3105223162Stuexen SCTP_INP_RUNLOCK(inp); 3106223162Stuexen } else { 3107223162Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3108223162Stuexen error = EINVAL; 3109223162Stuexen } 3110223162Stuexen } 3111223162Stuexen if (error == 0) { 3112223162Stuexen *optsize = sizeof(struct sctp_default_prinfo); 3113223162Stuexen } 3114223162Stuexen break; 3115223162Stuexen } 3116224641Stuexen case SCTP_PEER_ADDR_THLDS: 3117224641Stuexen { 3118224641Stuexen struct sctp_paddrthlds *thlds; 3119224641Stuexen struct sctp_nets *net; 3120224641Stuexen 3121224641Stuexen SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, *optsize); 3122224641Stuexen SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id); 3123224641Stuexen 3124224641Stuexen net = NULL; 3125224641Stuexen if (stcb) { 3126224641Stuexen net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_address); 3127224641Stuexen } else { 3128224641Stuexen /* 3129224641Stuexen * We increment here since 3130224641Stuexen * sctp_findassociation_ep_addr() wil do a 3131224641Stuexen * decrement if it finds the stcb as long as 3132224641Stuexen * the locked tcb (last argument) is NOT a 3133224641Stuexen * TCB.. aka NULL. 3134224641Stuexen */ 3135224641Stuexen SCTP_INP_INCR_REF(inp); 3136224641Stuexen stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&thlds->spt_address, &net, NULL, NULL); 3137224641Stuexen if (stcb == NULL) { 3138224641Stuexen SCTP_INP_DECR_REF(inp); 3139224641Stuexen } 3140224641Stuexen } 3141224641Stuexen if (stcb && (net == NULL)) { 3142224641Stuexen struct sockaddr *sa; 3143224641Stuexen 3144224641Stuexen sa = (struct sockaddr *)&thlds->spt_address; 3145224641Stuexen#ifdef INET 3146224641Stuexen if (sa->sa_family == AF_INET) { 3147224641Stuexen struct sockaddr_in *sin; 3148224641Stuexen 3149224641Stuexen sin = (struct sockaddr_in *)sa; 3150224641Stuexen if (sin->sin_addr.s_addr) { 3151224641Stuexen error = EINVAL; 3152224641Stuexen SCTP_TCB_UNLOCK(stcb); 3153224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3154224641Stuexen break; 3155224641Stuexen } 3156224641Stuexen } else 3157224641Stuexen#endif 3158224641Stuexen#ifdef INET6 3159224641Stuexen if (sa->sa_family == AF_INET6) { 3160224641Stuexen struct sockaddr_in6 *sin6; 3161224641Stuexen 3162224641Stuexen sin6 = (struct sockaddr_in6 *)sa; 3163224641Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 3164224641Stuexen error = EINVAL; 3165224641Stuexen SCTP_TCB_UNLOCK(stcb); 3166224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3167224641Stuexen break; 3168224641Stuexen } 3169224641Stuexen } else 3170224641Stuexen#endif 3171224641Stuexen { 3172224641Stuexen error = EAFNOSUPPORT; 3173224641Stuexen SCTP_TCB_UNLOCK(stcb); 3174224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3175224641Stuexen break; 3176224641Stuexen } 3177224641Stuexen } 3178224641Stuexen if (stcb) { 3179224641Stuexen if (net) { 3180224641Stuexen thlds->spt_pathmaxrxt = net->failure_threshold; 3181224641Stuexen thlds->spt_pathpfthld = net->pf_threshold; 3182224641Stuexen } else { 3183224641Stuexen thlds->spt_pathmaxrxt = stcb->asoc.def_net_failure; 3184224641Stuexen thlds->spt_pathpfthld = stcb->asoc.def_net_pf_threshold; 3185224641Stuexen } 3186224641Stuexen thlds->spt_assoc_id = sctp_get_associd(stcb); 3187224641Stuexen SCTP_TCB_UNLOCK(stcb); 3188224641Stuexen } else { 3189224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3190224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3191224918Stuexen (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) { 3192224641Stuexen /* Use endpoint defaults */ 3193224641Stuexen SCTP_INP_RLOCK(inp); 3194224641Stuexen thlds->spt_pathmaxrxt = inp->sctp_ep.def_net_failure; 3195224641Stuexen thlds->spt_pathpfthld = inp->sctp_ep.def_net_pf_threshold; 3196224641Stuexen SCTP_INP_RUNLOCK(inp); 3197224641Stuexen } else { 3198224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3199224641Stuexen error = EINVAL; 3200224641Stuexen } 3201224641Stuexen } 3202224641Stuexen if (error == 0) { 3203224641Stuexen *optsize = sizeof(struct sctp_paddrthlds); 3204224641Stuexen } 3205224641Stuexen break; 3206224641Stuexen } 3207227755Stuexen case SCTP_REMOTE_UDP_ENCAPS_PORT: 3208227755Stuexen { 3209227755Stuexen struct sctp_udpencaps *encaps; 3210227755Stuexen struct sctp_nets *net; 3211227755Stuexen 3212227755Stuexen SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, *optsize); 3213227755Stuexen SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id); 3214227755Stuexen 3215227755Stuexen if (stcb) { 3216227755Stuexen net = sctp_findnet(stcb, (struct sockaddr *)&encaps->sue_address); 3217227755Stuexen } else { 3218227755Stuexen /* 3219227755Stuexen * We increment here since 3220227755Stuexen * sctp_findassociation_ep_addr() wil do a 3221227755Stuexen * decrement if it finds the stcb as long as 3222227755Stuexen * the locked tcb (last argument) is NOT a 3223227755Stuexen * TCB.. aka NULL. 3224227755Stuexen */ 3225227755Stuexen net = NULL; 3226227755Stuexen SCTP_INP_INCR_REF(inp); 3227227755Stuexen stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&encaps->sue_address, &net, NULL, NULL); 3228227755Stuexen if (stcb == NULL) { 3229227755Stuexen SCTP_INP_DECR_REF(inp); 3230227755Stuexen } 3231227755Stuexen } 3232227755Stuexen if (stcb && (net == NULL)) { 3233227755Stuexen struct sockaddr *sa; 3234227755Stuexen 3235227755Stuexen sa = (struct sockaddr *)&encaps->sue_address; 3236227755Stuexen#ifdef INET 3237227755Stuexen if (sa->sa_family == AF_INET) { 3238227755Stuexen struct sockaddr_in *sin; 3239227755Stuexen 3240227755Stuexen sin = (struct sockaddr_in *)sa; 3241227755Stuexen if (sin->sin_addr.s_addr) { 3242227755Stuexen error = EINVAL; 3243227755Stuexen SCTP_TCB_UNLOCK(stcb); 3244227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3245227755Stuexen break; 3246227755Stuexen } 3247227755Stuexen } else 3248227755Stuexen#endif 3249227755Stuexen#ifdef INET6 3250227755Stuexen if (sa->sa_family == AF_INET6) { 3251227755Stuexen struct sockaddr_in6 *sin6; 3252227755Stuexen 3253227755Stuexen sin6 = (struct sockaddr_in6 *)sa; 3254227755Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 3255227755Stuexen error = EINVAL; 3256227755Stuexen SCTP_TCB_UNLOCK(stcb); 3257227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3258227755Stuexen break; 3259227755Stuexen } 3260227755Stuexen } else 3261227755Stuexen#endif 3262227755Stuexen { 3263227755Stuexen error = EAFNOSUPPORT; 3264227755Stuexen SCTP_TCB_UNLOCK(stcb); 3265227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3266227755Stuexen break; 3267227755Stuexen } 3268227755Stuexen } 3269227755Stuexen if (stcb) { 3270227755Stuexen if (net) { 3271227755Stuexen encaps->sue_port = net->port; 3272227755Stuexen } else { 3273227755Stuexen encaps->sue_port = stcb->asoc.port; 3274227755Stuexen } 3275227755Stuexen SCTP_TCB_UNLOCK(stcb); 3276227755Stuexen } else { 3277227755Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3278227755Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3279227755Stuexen (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) { 3280227755Stuexen SCTP_INP_RLOCK(inp); 3281227755Stuexen encaps->sue_port = inp->sctp_ep.port; 3282227755Stuexen SCTP_INP_RUNLOCK(inp); 3283227755Stuexen } else { 3284227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3285227755Stuexen error = EINVAL; 3286227755Stuexen } 3287227755Stuexen } 3288227755Stuexen if (error == 0) { 3289227755Stuexen *optsize = sizeof(struct sctp_paddrparams); 3290227755Stuexen } 3291227755Stuexen break; 3292227755Stuexen } 3293163953Srrs default: 3294171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 3295163953Srrs error = ENOPROTOOPT; 3296163953Srrs break; 3297163953Srrs } /* end switch (sopt->sopt_name) */ 3298223132Stuexen if (error) { 3299223132Stuexen *optsize = 0; 3300223132Stuexen } 3301163953Srrs return (error); 3302163953Srrs} 3303163953Srrs 3304163953Srrsstatic int 3305166675Srrssctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, 3306166675Srrs void *p) 3307163953Srrs{ 3308166675Srrs int error, set_opt; 3309166675Srrs uint32_t *mopt; 3310163953Srrs struct sctp_tcb *stcb = NULL; 3311171943Srrs struct sctp_inpcb *inp = NULL; 3312167598Srrs uint32_t vrf_id; 3313163953Srrs 3314166675Srrs if (optval == NULL) { 3315169420Srrs SCTP_PRINTF("optval is NULL\n"); 3316171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3317163953Srrs return (EINVAL); 3318163953Srrs } 3319163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3320233005Stuexen if (inp == NULL) { 3321169420Srrs SCTP_PRINTF("inp is NULL?\n"); 3322171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3323228907Stuexen return (EINVAL); 3324167598Srrs } 3325168299Srrs vrf_id = inp->def_vrf_id; 3326163953Srrs 3327163953Srrs error = 0; 3328166675Srrs switch (optname) { 3329163953Srrs case SCTP_NODELAY: 3330163953Srrs case SCTP_AUTOCLOSE: 3331163953Srrs case SCTP_AUTO_ASCONF: 3332163953Srrs case SCTP_EXPLICIT_EOR: 3333163953Srrs case SCTP_DISABLE_FRAGMENTS: 3334163953Srrs case SCTP_USE_EXT_RCVINFO: 3335163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 3336163953Srrs /* copy in the option value */ 3337166675Srrs SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); 3338163953Srrs set_opt = 0; 3339163953Srrs if (error) 3340163953Srrs break; 3341166675Srrs switch (optname) { 3342163953Srrs case SCTP_DISABLE_FRAGMENTS: 3343163953Srrs set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT; 3344163953Srrs break; 3345163953Srrs case SCTP_AUTO_ASCONF: 3346171943Srrs /* 3347171943Srrs * NOTE: we don't really support this flag 3348171943Srrs */ 3349171943Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 3350171943Srrs /* only valid for bound all sockets */ 3351224641Stuexen if ((SCTP_BASE_SYSCTL(sctp_auto_asconf) == 0) && 3352224641Stuexen (*mopt != 0)) { 3353224641Stuexen /* forbidden by admin */ 3354224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM); 3355224641Stuexen return (EPERM); 3356224641Stuexen } 3357171943Srrs set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF; 3358171943Srrs } else { 3359171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3360171943Srrs return (EINVAL); 3361171943Srrs } 3362163953Srrs break; 3363163953Srrs case SCTP_EXPLICIT_EOR: 3364163953Srrs set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR; 3365163953Srrs break; 3366163953Srrs case SCTP_USE_EXT_RCVINFO: 3367163953Srrs set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO; 3368163953Srrs break; 3369163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 3370163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 3371163953Srrs set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4; 3372163953Srrs } else { 3373171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3374163953Srrs return (EINVAL); 3375163953Srrs } 3376163953Srrs break; 3377163953Srrs case SCTP_NODELAY: 3378163953Srrs set_opt = SCTP_PCB_FLAGS_NODELAY; 3379163953Srrs break; 3380163953Srrs case SCTP_AUTOCLOSE: 3381170056Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3382170056Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 3383171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3384170056Srrs return (EINVAL); 3385170056Srrs } 3386163953Srrs set_opt = SCTP_PCB_FLAGS_AUTOCLOSE; 3387163953Srrs /* 3388163953Srrs * The value is in ticks. Note this does not effect 3389163953Srrs * old associations, only new ones. 3390163953Srrs */ 3391163953Srrs inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt); 3392163953Srrs break; 3393163953Srrs } 3394163953Srrs SCTP_INP_WLOCK(inp); 3395163953Srrs if (*mopt != 0) { 3396163953Srrs sctp_feature_on(inp, set_opt); 3397163953Srrs } else { 3398163953Srrs sctp_feature_off(inp, set_opt); 3399163953Srrs } 3400163953Srrs SCTP_INP_WUNLOCK(inp); 3401163953Srrs break; 3402181054Srrs case SCTP_REUSE_PORT: 3403181054Srrs { 3404181054Srrs SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); 3405181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) { 3406181054Srrs /* Can't set it after we are bound */ 3407181054Srrs error = EINVAL; 3408181054Srrs break; 3409181054Srrs } 3410181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) { 3411181054Srrs /* Can't do this for a 1-m socket */ 3412181054Srrs error = EINVAL; 3413181054Srrs break; 3414181054Srrs } 3415181054Srrs if (optval) 3416181054Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE); 3417181054Srrs else 3418181054Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE); 3419223132Stuexen break; 3420181054Srrs } 3421163953Srrs case SCTP_PARTIAL_DELIVERY_POINT: 3422163953Srrs { 3423166675Srrs uint32_t *value; 3424166675Srrs 3425166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); 3426167736Srrs if (*value > SCTP_SB_LIMIT_RCV(so)) { 3427171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3428167736Srrs error = EINVAL; 3429167736Srrs break; 3430167736Srrs } 3431166675Srrs inp->partial_delivery_point = *value; 3432223132Stuexen break; 3433163953Srrs } 3434163953Srrs case SCTP_FRAGMENT_INTERLEAVE: 3435163953Srrs /* not yet until we re-write sctp_recvmsg() */ 3436163953Srrs { 3437168943Srrs uint32_t *level; 3438163953Srrs 3439168943Srrs SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize); 3440168943Srrs if (*level == SCTP_FRAG_LEVEL_2) { 3441163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 3442168943Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 3443168943Srrs } else if (*level == SCTP_FRAG_LEVEL_1) { 3444168943Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 3445168943Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 3446168943Srrs } else if (*level == SCTP_FRAG_LEVEL_0) { 3447170056Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 3448168943Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 3449168943Srrs 3450163953Srrs } else { 3451171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3452168943Srrs error = EINVAL; 3453163953Srrs } 3454223132Stuexen break; 3455163953Srrs } 3456163953Srrs case SCTP_CMT_ON_OFF: 3457211944Stuexen if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { 3458163953Srrs struct sctp_assoc_value *av; 3459163953Srrs 3460166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 3461223132Stuexen if (av->assoc_value > SCTP_CMT_MAX) { 3462223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3463223132Stuexen error = EINVAL; 3464223132Stuexen break; 3465223132Stuexen } 3466211944Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3467211944Stuexen if (stcb) { 3468223132Stuexen stcb->asoc.sctp_cmt_on_off = av->assoc_value; 3469211944Stuexen SCTP_TCB_UNLOCK(stcb); 3470166675Srrs } else { 3471224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3472224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3473224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 3474223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3475221460Stuexen SCTP_INP_WLOCK(inp); 3476221460Stuexen inp->sctp_cmt_on_off = av->assoc_value; 3477221460Stuexen SCTP_INP_WUNLOCK(inp); 3478216669Stuexen } 3479223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 3480223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3481223132Stuexen SCTP_INP_RLOCK(inp); 3482223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3483223132Stuexen SCTP_TCB_LOCK(stcb); 3484223132Stuexen stcb->asoc.sctp_cmt_on_off = av->assoc_value; 3485223132Stuexen SCTP_TCB_UNLOCK(stcb); 3486223132Stuexen } 3487224918Stuexen SCTP_INP_RUNLOCK(inp); 3488223132Stuexen } 3489163953Srrs } 3490211944Stuexen } else { 3491211944Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 3492211944Stuexen error = ENOPROTOOPT; 3493163953Srrs } 3494163953Srrs break; 3495171440Srrs case SCTP_PLUGGABLE_CC: 3496171440Srrs { 3497171440Srrs struct sctp_assoc_value *av; 3498219057Srrs struct sctp_nets *net; 3499171440Srrs 3500171440Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 3501223132Stuexen if ((av->assoc_value != SCTP_CC_RFC2581) && 3502223132Stuexen (av->assoc_value != SCTP_CC_HSTCP) && 3503223132Stuexen (av->assoc_value != SCTP_CC_HTCP) && 3504223132Stuexen (av->assoc_value != SCTP_CC_RTCC)) { 3505223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3506223132Stuexen error = EINVAL; 3507223132Stuexen break; 3508223132Stuexen } 3509171440Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3510171440Srrs if (stcb) { 3511223132Stuexen stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value]; 3512223132Stuexen stcb->asoc.congestion_control_module = av->assoc_value; 3513223132Stuexen if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) { 3514223132Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3515223132Stuexen stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); 3516219057Srrs } 3517171440Srrs } 3518217611Stuexen SCTP_TCB_UNLOCK(stcb); 3519171440Srrs } else { 3520224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3521224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3522224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 3523223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3524217611Stuexen SCTP_INP_WLOCK(inp); 3525171440Srrs inp->sctp_ep.sctp_default_cc_module = av->assoc_value; 3526217611Stuexen SCTP_INP_WUNLOCK(inp); 3527217760Stuexen } 3528223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 3529223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3530223132Stuexen SCTP_INP_RLOCK(inp); 3531223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3532223132Stuexen SCTP_TCB_LOCK(stcb); 3533223132Stuexen stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value]; 3534223132Stuexen stcb->asoc.congestion_control_module = av->assoc_value; 3535223132Stuexen if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) { 3536223132Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3537223132Stuexen stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); 3538223132Stuexen } 3539223132Stuexen } 3540223132Stuexen SCTP_TCB_UNLOCK(stcb); 3541223132Stuexen } 3542223132Stuexen SCTP_INP_RUNLOCK(inp); 3543223132Stuexen } 3544171440Srrs } 3545223132Stuexen break; 3546171440Srrs } 3547219057Srrs case SCTP_CC_OPTION: 3548219057Srrs { 3549219057Srrs struct sctp_cc_option *cc_opt; 3550219057Srrs 3551219057Srrs SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, optsize); 3552219057Srrs SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id); 3553219057Srrs if (stcb == NULL) { 3554223132Stuexen if (cc_opt->aid_value.assoc_id == SCTP_CURRENT_ASSOC) { 3555223132Stuexen SCTP_INP_RLOCK(inp); 3556223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3557223132Stuexen SCTP_TCB_LOCK(stcb); 3558223132Stuexen if (stcb->asoc.cc_functions.sctp_cwnd_socket_option) { 3559223132Stuexen (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1, cc_opt); 3560223132Stuexen } 3561223132Stuexen SCTP_TCB_UNLOCK(stcb); 3562223132Stuexen } 3563223132Stuexen SCTP_INP_RUNLOCK(inp); 3564223132Stuexen } else { 3565223132Stuexen error = EINVAL; 3566223132Stuexen } 3567219057Srrs } else { 3568219057Srrs if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) { 3569219057Srrs error = ENOTSUP; 3570219057Srrs } else { 3571219057Srrs error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1, 3572219057Srrs cc_opt); 3573219057Srrs } 3574219057Srrs SCTP_TCB_UNLOCK(stcb); 3575219057Srrs } 3576223132Stuexen break; 3577219057Srrs } 3578217760Stuexen case SCTP_PLUGGABLE_SS: 3579217760Stuexen { 3580217760Stuexen struct sctp_assoc_value *av; 3581217760Stuexen 3582217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 3583223132Stuexen if ((av->assoc_value != SCTP_SS_DEFAULT) && 3584223132Stuexen (av->assoc_value != SCTP_SS_DEFAULT) && 3585223132Stuexen (av->assoc_value != SCTP_SS_ROUND_ROBIN) && 3586223132Stuexen (av->assoc_value != SCTP_SS_ROUND_ROBIN_PACKET) && 3587223132Stuexen (av->assoc_value != SCTP_SS_PRIORITY) && 3588223132Stuexen (av->assoc_value != SCTP_SS_FAIR_BANDWITH) && 3589223132Stuexen (av->assoc_value != SCTP_SS_FIRST_COME)) { 3590223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3591223132Stuexen error = EINVAL; 3592223132Stuexen break; 3593223132Stuexen } 3594217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3595217760Stuexen if (stcb) { 3596223132Stuexen stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1); 3597223132Stuexen stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value]; 3598223132Stuexen stcb->asoc.stream_scheduling_module = av->assoc_value; 3599223132Stuexen stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1); 3600217760Stuexen SCTP_TCB_UNLOCK(stcb); 3601217760Stuexen } else { 3602224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3603224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3604224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 3605223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3606217760Stuexen SCTP_INP_WLOCK(inp); 3607217760Stuexen inp->sctp_ep.sctp_default_ss_module = av->assoc_value; 3608217760Stuexen SCTP_INP_WUNLOCK(inp); 3609217760Stuexen } 3610223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 3611223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3612223132Stuexen SCTP_INP_RLOCK(inp); 3613223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3614223132Stuexen SCTP_TCB_LOCK(stcb); 3615223132Stuexen stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1); 3616223132Stuexen stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value]; 3617223132Stuexen stcb->asoc.stream_scheduling_module = av->assoc_value; 3618223132Stuexen stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1); 3619223132Stuexen SCTP_TCB_UNLOCK(stcb); 3620223132Stuexen } 3621223132Stuexen SCTP_INP_RUNLOCK(inp); 3622223132Stuexen } 3623217760Stuexen } 3624223132Stuexen break; 3625217760Stuexen } 3626217760Stuexen case SCTP_SS_VALUE: 3627217760Stuexen { 3628217760Stuexen struct sctp_stream_value *av; 3629217760Stuexen 3630217760Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize); 3631217760Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3632217760Stuexen if (stcb) { 3633217760Stuexen if (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], 3634217760Stuexen av->stream_value) < 0) { 3635217760Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3636217760Stuexen error = EINVAL; 3637217760Stuexen } 3638217760Stuexen SCTP_TCB_UNLOCK(stcb); 3639217760Stuexen } else { 3640223132Stuexen if (av->assoc_id == SCTP_CURRENT_ASSOC) { 3641223132Stuexen SCTP_INP_RLOCK(inp); 3642223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3643223132Stuexen SCTP_TCB_LOCK(stcb); 3644223132Stuexen stcb->asoc.ss_functions.sctp_ss_set_value(stcb, 3645223132Stuexen &stcb->asoc, 3646223132Stuexen &stcb->asoc.strmout[av->stream_id], 3647223132Stuexen av->stream_value); 3648223132Stuexen SCTP_TCB_UNLOCK(stcb); 3649223132Stuexen } 3650223132Stuexen SCTP_INP_RUNLOCK(inp); 3651223132Stuexen 3652223132Stuexen } else { 3653223132Stuexen /* 3654223132Stuexen * Can't set stream value without 3655223132Stuexen * association 3656223132Stuexen */ 3657223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3658223132Stuexen error = EINVAL; 3659223132Stuexen } 3660217760Stuexen } 3661223132Stuexen break; 3662217760Stuexen } 3663163953Srrs case SCTP_CLR_STAT_LOG: 3664171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 3665163953Srrs error = EOPNOTSUPP; 3666163953Srrs break; 3667163953Srrs case SCTP_CONTEXT: 3668163953Srrs { 3669163953Srrs struct sctp_assoc_value *av; 3670163953Srrs 3671166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 3672166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3673166675Srrs 3674166675Srrs if (stcb) { 3675166675Srrs stcb->asoc.context = av->assoc_value; 3676166675Srrs SCTP_TCB_UNLOCK(stcb); 3677163953Srrs } else { 3678224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3679224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3680224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 3681223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3682223132Stuexen SCTP_INP_WLOCK(inp); 3683223132Stuexen inp->sctp_context = av->assoc_value; 3684223132Stuexen SCTP_INP_WUNLOCK(inp); 3685223132Stuexen } 3686223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 3687223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 3688223132Stuexen SCTP_INP_RLOCK(inp); 3689223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3690223132Stuexen SCTP_TCB_LOCK(stcb); 3691223132Stuexen stcb->asoc.context = av->assoc_value; 3692223132Stuexen SCTP_TCB_UNLOCK(stcb); 3693223132Stuexen } 3694223132Stuexen SCTP_INP_RUNLOCK(inp); 3695223132Stuexen } 3696163953Srrs } 3697223132Stuexen break; 3698163953Srrs } 3699167598Srrs case SCTP_VRF_ID: 3700167598Srrs { 3701170056Srrs uint32_t *default_vrfid; 3702167598Srrs 3703170056Srrs SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize); 3704170056Srrs if (*default_vrfid > SCTP_MAX_VRF_ID) { 3705171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3706167598Srrs error = EINVAL; 3707167598Srrs break; 3708167598Srrs } 3709170056Srrs inp->def_vrf_id = *default_vrfid; 3710167598Srrs break; 3711167598Srrs } 3712167598Srrs case SCTP_DEL_VRF_ID: 3713167598Srrs { 3714171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 3715167598Srrs error = EOPNOTSUPP; 3716167598Srrs break; 3717167598Srrs } 3718167598Srrs case SCTP_ADD_VRF_ID: 3719167598Srrs { 3720171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 3721167598Srrs error = EOPNOTSUPP; 3722167598Srrs break; 3723167598Srrs } 3724170056Srrs case SCTP_DELAYED_SACK: 3725163953Srrs { 3726170056Srrs struct sctp_sack_info *sack; 3727163953Srrs 3728170056Srrs SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize); 3729170056Srrs SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); 3730171477Srrs if (sack->sack_delay) { 3731171477Srrs if (sack->sack_delay > SCTP_MAX_SACK_DELAY) 3732171477Srrs sack->sack_delay = SCTP_MAX_SACK_DELAY; 3733223132Stuexen if (MSEC_TO_TICKS(sack->sack_delay) < 1) { 3734223132Stuexen sack->sack_delay = TICKS_TO_MSEC(1); 3735223132Stuexen } 3736171477Srrs } 3737166675Srrs if (stcb) { 3738170056Srrs if (sack->sack_delay) { 3739170056Srrs stcb->asoc.delayed_ack = sack->sack_delay; 3740170056Srrs } 3741170056Srrs if (sack->sack_freq) { 3742170056Srrs stcb->asoc.sack_freq = sack->sack_freq; 3743170056Srrs } 3744166675Srrs SCTP_TCB_UNLOCK(stcb); 3745166675Srrs } else { 3746224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3747224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3748224918Stuexen (sack->sack_assoc_id == SCTP_FUTURE_ASSOC) || 3749223132Stuexen (sack->sack_assoc_id == SCTP_ALL_ASSOC)) { 3750223132Stuexen SCTP_INP_WLOCK(inp); 3751223132Stuexen if (sack->sack_delay) { 3752223132Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay); 3753170056Srrs } 3754223132Stuexen if (sack->sack_freq) { 3755223132Stuexen inp->sctp_ep.sctp_sack_freq = sack->sack_freq; 3756223132Stuexen } 3757223132Stuexen SCTP_INP_WUNLOCK(inp); 3758170056Srrs } 3759223132Stuexen if ((sack->sack_assoc_id == SCTP_CURRENT_ASSOC) || 3760223132Stuexen (sack->sack_assoc_id == SCTP_ALL_ASSOC)) { 3761223132Stuexen SCTP_INP_RLOCK(inp); 3762223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3763223132Stuexen SCTP_TCB_LOCK(stcb); 3764223132Stuexen if (sack->sack_delay) { 3765223132Stuexen stcb->asoc.delayed_ack = sack->sack_delay; 3766223132Stuexen } 3767223132Stuexen if (sack->sack_freq) { 3768223132Stuexen stcb->asoc.sack_freq = sack->sack_freq; 3769223132Stuexen } 3770223132Stuexen SCTP_TCB_UNLOCK(stcb); 3771223132Stuexen } 3772223132Stuexen SCTP_INP_RUNLOCK(inp); 3773170056Srrs } 3774163953Srrs } 3775166675Srrs break; 3776163953Srrs } 3777163953Srrs case SCTP_AUTH_CHUNK: 3778163953Srrs { 3779163953Srrs struct sctp_authchunk *sauth; 3780163953Srrs 3781166675Srrs SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize); 3782166675Srrs 3783166675Srrs SCTP_INP_WLOCK(inp); 3784171943Srrs if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) { 3785171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3786163953Srrs error = EINVAL; 3787171943Srrs } 3788166675Srrs SCTP_INP_WUNLOCK(inp); 3789163953Srrs break; 3790163953Srrs } 3791163953Srrs case SCTP_AUTH_KEY: 3792163953Srrs { 3793163953Srrs struct sctp_authkey *sca; 3794163953Srrs struct sctp_keyhead *shared_keys; 3795163953Srrs sctp_sharedkey_t *shared_key; 3796163953Srrs sctp_key_t *key = NULL; 3797166675Srrs size_t size; 3798163953Srrs 3799166675Srrs SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize); 3800223697Stuexen if (sca->sca_keylength == 0) { 3801223697Stuexen size = optsize - sizeof(struct sctp_authkey); 3802223697Stuexen } else { 3803223697Stuexen if (sca->sca_keylength + sizeof(struct sctp_authkey) <= optsize) { 3804223697Stuexen size = sca->sca_keylength; 3805223697Stuexen } else { 3806223697Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3807223697Stuexen error = EINVAL; 3808223697Stuexen break; 3809223697Stuexen } 3810223697Stuexen } 3811169420Srrs SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id); 3812166675Srrs 3813166675Srrs if (stcb) { 3814163953Srrs shared_keys = &stcb->asoc.shared_keys; 3815163953Srrs /* clear the cached keys for this key id */ 3816163953Srrs sctp_clear_cachedkeys(stcb, sca->sca_keynumber); 3817163953Srrs /* 3818163953Srrs * create the new shared key and 3819163953Srrs * insert/replace it 3820163953Srrs */ 3821163953Srrs if (size > 0) { 3822163953Srrs key = sctp_set_key(sca->sca_key, (uint32_t) size); 3823163953Srrs if (key == NULL) { 3824171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3825163953Srrs error = ENOMEM; 3826163953Srrs SCTP_TCB_UNLOCK(stcb); 3827163953Srrs break; 3828163953Srrs } 3829163953Srrs } 3830163953Srrs shared_key = sctp_alloc_sharedkey(); 3831163953Srrs if (shared_key == NULL) { 3832163953Srrs sctp_free_key(key); 3833171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3834163953Srrs error = ENOMEM; 3835163953Srrs SCTP_TCB_UNLOCK(stcb); 3836163953Srrs break; 3837163953Srrs } 3838163953Srrs shared_key->key = key; 3839163953Srrs shared_key->keyid = sca->sca_keynumber; 3840185694Srrs error = sctp_insert_sharedkey(shared_keys, shared_key); 3841163953Srrs SCTP_TCB_UNLOCK(stcb); 3842163953Srrs } else { 3843224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3844224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3845224918Stuexen (sca->sca_assoc_id == SCTP_FUTURE_ASSOC) || 3846223132Stuexen (sca->sca_assoc_id == SCTP_ALL_ASSOC)) { 3847223132Stuexen SCTP_INP_WLOCK(inp); 3848223132Stuexen shared_keys = &inp->sctp_ep.shared_keys; 3849223132Stuexen /* 3850223132Stuexen * clear the cached keys on all 3851223132Stuexen * assocs for this key id 3852223132Stuexen */ 3853223132Stuexen sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber); 3854223132Stuexen /* 3855223132Stuexen * create the new shared key and 3856223132Stuexen * insert/replace it 3857223132Stuexen */ 3858223132Stuexen if (size > 0) { 3859223132Stuexen key = sctp_set_key(sca->sca_key, (uint32_t) size); 3860223132Stuexen if (key == NULL) { 3861223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3862223132Stuexen error = ENOMEM; 3863223132Stuexen SCTP_INP_WUNLOCK(inp); 3864223132Stuexen break; 3865223132Stuexen } 3866223132Stuexen } 3867223132Stuexen shared_key = sctp_alloc_sharedkey(); 3868223132Stuexen if (shared_key == NULL) { 3869223132Stuexen sctp_free_key(key); 3870171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3871163953Srrs error = ENOMEM; 3872163953Srrs SCTP_INP_WUNLOCK(inp); 3873163953Srrs break; 3874163953Srrs } 3875223132Stuexen shared_key->key = key; 3876223132Stuexen shared_key->keyid = sca->sca_keynumber; 3877223132Stuexen error = sctp_insert_sharedkey(shared_keys, shared_key); 3878163953Srrs SCTP_INP_WUNLOCK(inp); 3879163953Srrs } 3880223132Stuexen if ((sca->sca_assoc_id == SCTP_CURRENT_ASSOC) || 3881223132Stuexen (sca->sca_assoc_id == SCTP_ALL_ASSOC)) { 3882223132Stuexen SCTP_INP_RLOCK(inp); 3883223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 3884223132Stuexen SCTP_TCB_LOCK(stcb); 3885223132Stuexen shared_keys = &stcb->asoc.shared_keys; 3886223132Stuexen /* 3887223132Stuexen * clear the cached keys for 3888223132Stuexen * this key id 3889223132Stuexen */ 3890223132Stuexen sctp_clear_cachedkeys(stcb, sca->sca_keynumber); 3891223132Stuexen /* 3892223132Stuexen * create the new shared key 3893223132Stuexen * and insert/replace it 3894223132Stuexen */ 3895223132Stuexen if (size > 0) { 3896223132Stuexen key = sctp_set_key(sca->sca_key, (uint32_t) size); 3897223132Stuexen if (key == NULL) { 3898223132Stuexen SCTP_TCB_UNLOCK(stcb); 3899223132Stuexen continue; 3900223132Stuexen } 3901223132Stuexen } 3902223132Stuexen shared_key = sctp_alloc_sharedkey(); 3903223132Stuexen if (shared_key == NULL) { 3904223132Stuexen sctp_free_key(key); 3905223132Stuexen SCTP_TCB_UNLOCK(stcb); 3906223132Stuexen continue; 3907223132Stuexen } 3908223132Stuexen shared_key->key = key; 3909223132Stuexen shared_key->keyid = sca->sca_keynumber; 3910223132Stuexen error = sctp_insert_sharedkey(shared_keys, shared_key); 3911223132Stuexen SCTP_TCB_UNLOCK(stcb); 3912223132Stuexen } 3913223132Stuexen SCTP_INP_RUNLOCK(inp); 3914223132Stuexen } 3915163953Srrs } 3916163953Srrs break; 3917163953Srrs } 3918163953Srrs case SCTP_HMAC_IDENT: 3919163953Srrs { 3920163953Srrs struct sctp_hmacalgo *shmac; 3921163953Srrs sctp_hmaclist_t *hmaclist; 3922181054Srrs uint16_t hmacid; 3923181054Srrs uint32_t i; 3924181054Srrs size_t found; 3925181054Srrs 3926166675Srrs SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize); 3927181054Srrs if (optsize < sizeof(struct sctp_hmacalgo) + shmac->shmac_number_of_idents * sizeof(uint16_t)) { 3928181054Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3929181054Srrs error = EINVAL; 3930181054Srrs break; 3931181054Srrs } 3932181054Srrs hmaclist = sctp_alloc_hmaclist(shmac->shmac_number_of_idents); 3933163953Srrs if (hmaclist == NULL) { 3934171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3935163953Srrs error = ENOMEM; 3936163953Srrs break; 3937163953Srrs } 3938181054Srrs for (i = 0; i < shmac->shmac_number_of_idents; i++) { 3939163953Srrs hmacid = shmac->shmac_idents[i]; 3940181054Srrs if (sctp_auth_add_hmacid(hmaclist, hmacid)) { 3941163953Srrs /* invalid HMACs were found */ ; 3942171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3943163953Srrs error = EINVAL; 3944164085Srrs sctp_free_hmaclist(hmaclist); 3945163953Srrs goto sctp_set_hmac_done; 3946163953Srrs } 3947163953Srrs } 3948170056Srrs found = 0; 3949170056Srrs for (i = 0; i < hmaclist->num_algo; i++) { 3950170056Srrs if (hmaclist->hmac[i] == SCTP_AUTH_HMAC_ID_SHA1) { 3951170056Srrs /* already in list */ 3952170056Srrs found = 1; 3953170056Srrs } 3954170056Srrs } 3955170056Srrs if (!found) { 3956170056Srrs sctp_free_hmaclist(hmaclist); 3957171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3958170056Srrs error = EINVAL; 3959170056Srrs break; 3960170056Srrs } 3961163953Srrs /* set it on the endpoint */ 3962163953Srrs SCTP_INP_WLOCK(inp); 3963163953Srrs if (inp->sctp_ep.local_hmacs) 3964163953Srrs sctp_free_hmaclist(inp->sctp_ep.local_hmacs); 3965163953Srrs inp->sctp_ep.local_hmacs = hmaclist; 3966163953Srrs SCTP_INP_WUNLOCK(inp); 3967163953Srrs sctp_set_hmac_done: 3968163953Srrs break; 3969163953Srrs } 3970163953Srrs case SCTP_AUTH_ACTIVE_KEY: 3971163953Srrs { 3972163953Srrs struct sctp_authkeyid *scact; 3973163953Srrs 3974223132Stuexen SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize); 3975166675Srrs SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); 3976166675Srrs 3977163953Srrs /* set the active key on the right place */ 3978166675Srrs if (stcb) { 3979163953Srrs /* set the active key on the assoc */ 3980185694Srrs if (sctp_auth_setactivekey(stcb, 3981185694Srrs scact->scact_keynumber)) { 3982185694Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, 3983185694Srrs SCTP_FROM_SCTP_USRREQ, 3984185694Srrs EINVAL); 3985163953Srrs error = EINVAL; 3986171943Srrs } 3987163953Srrs SCTP_TCB_UNLOCK(stcb); 3988163953Srrs } else { 3989224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3990224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3991224918Stuexen (scact->scact_assoc_id == SCTP_FUTURE_ASSOC) || 3992223132Stuexen (scact->scact_assoc_id == SCTP_ALL_ASSOC)) { 3993223132Stuexen SCTP_INP_WLOCK(inp); 3994223132Stuexen if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) { 3995223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3996223132Stuexen error = EINVAL; 3997223132Stuexen } 3998223132Stuexen SCTP_INP_WUNLOCK(inp); 3999171943Srrs } 4000223132Stuexen if ((scact->scact_assoc_id == SCTP_CURRENT_ASSOC) || 4001223132Stuexen (scact->scact_assoc_id == SCTP_ALL_ASSOC)) { 4002223132Stuexen SCTP_INP_RLOCK(inp); 4003223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4004223132Stuexen SCTP_TCB_LOCK(stcb); 4005223132Stuexen sctp_auth_setactivekey(stcb, scact->scact_keynumber); 4006223132Stuexen SCTP_TCB_UNLOCK(stcb); 4007223132Stuexen } 4008223132Stuexen SCTP_INP_RUNLOCK(inp); 4009223132Stuexen } 4010163953Srrs } 4011163953Srrs break; 4012163953Srrs } 4013163953Srrs case SCTP_AUTH_DELETE_KEY: 4014163953Srrs { 4015163953Srrs struct sctp_authkeyid *scdel; 4016163953Srrs 4017223132Stuexen SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize); 4018166675Srrs SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id); 4019166675Srrs 4020163953Srrs /* delete the key from the right place */ 4021166675Srrs if (stcb) { 4022223132Stuexen if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) { 4023223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4024163953Srrs error = EINVAL; 4025171943Srrs } 4026163953Srrs SCTP_TCB_UNLOCK(stcb); 4027163953Srrs } else { 4028224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4029224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4030224918Stuexen (scdel->scact_assoc_id == SCTP_FUTURE_ASSOC) || 4031223132Stuexen (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) { 4032223132Stuexen SCTP_INP_WLOCK(inp); 4033223132Stuexen if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) { 4034223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4035223132Stuexen error = EINVAL; 4036223132Stuexen } 4037223132Stuexen SCTP_INP_WUNLOCK(inp); 4038171943Srrs } 4039223132Stuexen if ((scdel->scact_assoc_id == SCTP_CURRENT_ASSOC) || 4040223132Stuexen (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) { 4041223132Stuexen SCTP_INP_RLOCK(inp); 4042223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4043223132Stuexen SCTP_TCB_LOCK(stcb); 4044223132Stuexen sctp_delete_sharedkey(stcb, scdel->scact_keynumber); 4045223132Stuexen SCTP_TCB_UNLOCK(stcb); 4046223132Stuexen } 4047223132Stuexen SCTP_INP_RUNLOCK(inp); 4048223132Stuexen } 4049163953Srrs } 4050163953Srrs break; 4051163953Srrs } 4052185694Srrs case SCTP_AUTH_DEACTIVATE_KEY: 4053185694Srrs { 4054185694Srrs struct sctp_authkeyid *keyid; 4055163953Srrs 4056223132Stuexen SCTP_CHECK_AND_CAST(keyid, optval, struct sctp_authkeyid, optsize); 4057185694Srrs SCTP_FIND_STCB(inp, stcb, keyid->scact_assoc_id); 4058185694Srrs 4059185694Srrs /* deactivate the key from the right place */ 4060185694Srrs if (stcb) { 4061223132Stuexen if (sctp_deact_sharedkey(stcb, keyid->scact_keynumber)) { 4062223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4063185694Srrs error = EINVAL; 4064185694Srrs } 4065185694Srrs SCTP_TCB_UNLOCK(stcb); 4066185694Srrs } else { 4067224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4068224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4069224918Stuexen (keyid->scact_assoc_id == SCTP_FUTURE_ASSOC) || 4070223132Stuexen (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) { 4071223132Stuexen SCTP_INP_WLOCK(inp); 4072223132Stuexen if (sctp_deact_sharedkey_ep(inp, keyid->scact_keynumber)) { 4073223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4074223132Stuexen error = EINVAL; 4075223132Stuexen } 4076223132Stuexen SCTP_INP_WUNLOCK(inp); 4077185694Srrs } 4078223132Stuexen if ((keyid->scact_assoc_id == SCTP_CURRENT_ASSOC) || 4079223132Stuexen (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) { 4080223132Stuexen SCTP_INP_RLOCK(inp); 4081223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4082223132Stuexen SCTP_TCB_LOCK(stcb); 4083223132Stuexen sctp_deact_sharedkey(stcb, keyid->scact_keynumber); 4084223132Stuexen SCTP_TCB_UNLOCK(stcb); 4085223132Stuexen } 4086223132Stuexen SCTP_INP_RUNLOCK(inp); 4087223132Stuexen } 4088185694Srrs } 4089185694Srrs break; 4090185694Srrs } 4091185694Srrs 4092163953Srrs case SCTP_RESET_STREAMS: 4093163953Srrs { 4094163953Srrs struct sctp_stream_reset *strrst; 4095188854Srrs uint8_t send_in = 0, send_tsn = 0, send_out = 0, 4096188854Srrs addstream = 0; 4097188854Srrs uint16_t addstrmcnt = 0; 4098163953Srrs int i; 4099163953Srrs 4100166675Srrs SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_stream_reset, optsize); 4101166675Srrs SCTP_FIND_STCB(inp, stcb, strrst->strrst_assoc_id); 4102163953Srrs 4103163953Srrs if (stcb == NULL) { 4104171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4105163953Srrs error = ENOENT; 4106163953Srrs break; 4107163953Srrs } 4108163953Srrs if (stcb->asoc.peer_supports_strreset == 0) { 4109163953Srrs /* 4110163953Srrs * Peer does not support it, we return 4111163953Srrs * protocol not supported since this is true 4112163953Srrs * for this feature and this peer, not the 4113163953Srrs * socket request in general. 4114163953Srrs */ 4115171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPROTONOSUPPORT); 4116163953Srrs error = EPROTONOSUPPORT; 4117163953Srrs SCTP_TCB_UNLOCK(stcb); 4118163953Srrs break; 4119163953Srrs } 4120163953Srrs if (stcb->asoc.stream_reset_outstanding) { 4121171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4122163953Srrs error = EALREADY; 4123163953Srrs SCTP_TCB_UNLOCK(stcb); 4124163953Srrs break; 4125163953Srrs } 4126163953Srrs if (strrst->strrst_flags == SCTP_RESET_LOCAL_RECV) { 4127163953Srrs send_in = 1; 4128163953Srrs } else if (strrst->strrst_flags == SCTP_RESET_LOCAL_SEND) { 4129163953Srrs send_out = 1; 4130163953Srrs } else if (strrst->strrst_flags == SCTP_RESET_BOTH) { 4131163953Srrs send_in = 1; 4132163953Srrs send_out = 1; 4133163953Srrs } else if (strrst->strrst_flags == SCTP_RESET_TSN) { 4134163953Srrs send_tsn = 1; 4135188854Srrs } else if (strrst->strrst_flags == SCTP_RESET_ADD_STREAMS) { 4136188854Srrs if (send_tsn || 4137188854Srrs send_in || 4138188854Srrs send_out) { 4139188854Srrs /* We can't do that and add streams */ 4140188854Srrs error = EINVAL; 4141188854Srrs goto skip_stuff; 4142188854Srrs } 4143188854Srrs if (stcb->asoc.stream_reset_outstanding) { 4144188854Srrs error = EBUSY; 4145188854Srrs goto skip_stuff; 4146188854Srrs } 4147188854Srrs addstream = 1; 4148188854Srrs /* We allocate here */ 4149188854Srrs addstrmcnt = strrst->strrst_num_streams; 4150188854Srrs if ((int)(addstrmcnt + stcb->asoc.streamoutcnt) > 0xffff) { 4151188854Srrs /* You can't have more than 64k */ 4152188854Srrs error = EINVAL; 4153188854Srrs goto skip_stuff; 4154188854Srrs } 4155188854Srrs if ((stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt) < addstrmcnt) { 4156188854Srrs /* Need to allocate more */ 4157188854Srrs struct sctp_stream_out *oldstream; 4158216822Stuexen struct sctp_stream_queue_pending *sp, 4159216822Stuexen *nsp; 4160188854Srrs 4161188854Srrs oldstream = stcb->asoc.strmout; 4162188854Srrs /* get some more */ 4163188854Srrs SCTP_MALLOC(stcb->asoc.strmout, struct sctp_stream_out *, 4164188854Srrs ((stcb->asoc.streamoutcnt + addstrmcnt) * sizeof(struct sctp_stream_out)), 4165188854Srrs SCTP_M_STRMO); 4166188854Srrs if (stcb->asoc.strmout == NULL) { 4167188854Srrs stcb->asoc.strmout = oldstream; 4168188854Srrs error = ENOMEM; 4169188854Srrs goto skip_stuff; 4170188854Srrs } 4171188854Srrs /* 4172188854Srrs * Ok now we proceed with copying 4173188854Srrs * the old out stuff and 4174188854Srrs * initializing the new stuff. 4175188854Srrs */ 4176189121Srrs SCTP_TCB_SEND_LOCK(stcb); 4177217760Stuexen stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 0, 1); 4178189121Srrs for (i = 0; i < stcb->asoc.streamoutcnt; i++) { 4179189121Srrs TAILQ_INIT(&stcb->asoc.strmout[i].outqueue); 4180189121Srrs stcb->asoc.strmout[i].next_sequence_sent = oldstream[i].next_sequence_sent; 4181189121Srrs stcb->asoc.strmout[i].last_msg_incomplete = oldstream[i].last_msg_incomplete; 4182189121Srrs stcb->asoc.strmout[i].stream_no = i; 4183218241Stuexen stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], &oldstream[i]); 4184189121Srrs /* 4185189121Srrs * now anything on those 4186189121Srrs * queues? 4187189121Srrs */ 4188216822Stuexen TAILQ_FOREACH_SAFE(sp, &oldstream[i].outqueue, next, nsp) { 4189189121Srrs TAILQ_REMOVE(&oldstream[i].outqueue, sp, next); 4190189121Srrs TAILQ_INSERT_TAIL(&stcb->asoc.strmout[i].outqueue, sp, next); 4191189121Srrs } 4192189121Srrs /* 4193189121Srrs * Now move assoc pointers 4194189121Srrs * too 4195189121Srrs */ 4196189121Srrs if (stcb->asoc.last_out_stream == &oldstream[i]) { 4197189121Srrs stcb->asoc.last_out_stream = &stcb->asoc.strmout[i]; 4198189121Srrs } 4199189121Srrs if (stcb->asoc.locked_on_sending == &oldstream[i]) { 4200189121Srrs stcb->asoc.locked_on_sending = &stcb->asoc.strmout[i]; 4201189121Srrs } 4202189121Srrs } 4203188854Srrs /* now the new streams */ 4204217760Stuexen stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1); 4205188854Srrs for (i = stcb->asoc.streamoutcnt; i < (stcb->asoc.streamoutcnt + addstrmcnt); i++) { 4206188854Srrs stcb->asoc.strmout[i].next_sequence_sent = 0x0; 4207188854Srrs TAILQ_INIT(&stcb->asoc.strmout[i].outqueue); 4208188854Srrs stcb->asoc.strmout[i].stream_no = i; 4209188854Srrs stcb->asoc.strmout[i].last_msg_incomplete = 0; 4210218241Stuexen stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], NULL); 4211188854Srrs } 4212188854Srrs stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + addstrmcnt; 4213188854Srrs SCTP_FREE(oldstream, SCTP_M_STRMO); 4214188854Srrs } 4215189121Srrs SCTP_TCB_SEND_UNLOCK(stcb); 4216188854Srrs goto skip_stuff; 4217163953Srrs } else { 4218171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4219163953Srrs error = EINVAL; 4220163953Srrs SCTP_TCB_UNLOCK(stcb); 4221163953Srrs break; 4222163953Srrs } 4223163953Srrs for (i = 0; i < strrst->strrst_num_streams; i++) { 4224163953Srrs if ((send_in) && 4225163953Srrs 4226163953Srrs (strrst->strrst_list[i] > stcb->asoc.streamincnt)) { 4227171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4228163953Srrs error = EINVAL; 4229163953Srrs goto get_out; 4230163953Srrs } 4231163953Srrs if ((send_out) && 4232163953Srrs (strrst->strrst_list[i] > stcb->asoc.streamoutcnt)) { 4233171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4234163953Srrs error = EINVAL; 4235163953Srrs goto get_out; 4236163953Srrs } 4237163953Srrs } 4238188854Srrs skip_stuff: 4239163953Srrs if (error) { 4240163953Srrs get_out: 4241163953Srrs SCTP_TCB_UNLOCK(stcb); 4242163953Srrs break; 4243163953Srrs } 4244163953Srrs error = sctp_send_str_reset_req(stcb, strrst->strrst_num_streams, 4245163953Srrs strrst->strrst_list, 4246163953Srrs send_out, (stcb->asoc.str_reset_seq_in - 3), 4247188854Srrs send_in, send_tsn, addstream, addstrmcnt); 4248163953Srrs 4249172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); 4250163953Srrs SCTP_TCB_UNLOCK(stcb); 4251223132Stuexen break; 4252163953Srrs } 4253163953Srrs case SCTP_CONNECT_X: 4254166675Srrs if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { 4255171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4256163953Srrs error = EINVAL; 4257163953Srrs break; 4258163953Srrs } 4259166675Srrs error = sctp_do_connect_x(so, inp, optval, optsize, p, 0); 4260163953Srrs break; 4261163953Srrs case SCTP_CONNECT_X_DELAYED: 4262166675Srrs if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { 4263171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4264163953Srrs error = EINVAL; 4265163953Srrs break; 4266163953Srrs } 4267166675Srrs error = sctp_do_connect_x(so, inp, optval, optsize, p, 1); 4268163953Srrs break; 4269163953Srrs case SCTP_CONNECT_X_COMPLETE: 4270163953Srrs { 4271163953Srrs struct sockaddr *sa; 4272163953Srrs struct sctp_nets *net; 4273163953Srrs 4274166675Srrs /* FIXME MT: check correct? */ 4275166675Srrs SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize); 4276166675Srrs 4277163953Srrs /* find tcb */ 4278163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 4279163953Srrs SCTP_INP_RLOCK(inp); 4280163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 4281163953Srrs if (stcb) { 4282163953Srrs SCTP_TCB_LOCK(stcb); 4283163953Srrs net = sctp_findnet(stcb, sa); 4284163953Srrs } 4285163953Srrs SCTP_INP_RUNLOCK(inp); 4286163953Srrs } else { 4287166675Srrs /* 4288166675Srrs * We increment here since 4289166675Srrs * sctp_findassociation_ep_addr() wil do a 4290166675Srrs * decrement if it finds the stcb as long as 4291166675Srrs * the locked tcb (last argument) is NOT a 4292166675Srrs * TCB.. aka NULL. 4293166675Srrs */ 4294163953Srrs SCTP_INP_INCR_REF(inp); 4295163953Srrs stcb = sctp_findassociation_ep_addr(&inp, sa, &net, NULL, NULL); 4296163953Srrs if (stcb == NULL) { 4297163953Srrs SCTP_INP_DECR_REF(inp); 4298163953Srrs } 4299163953Srrs } 4300163953Srrs 4301163953Srrs if (stcb == NULL) { 4302171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4303163953Srrs error = ENOENT; 4304163953Srrs break; 4305163953Srrs } 4306163953Srrs if (stcb->asoc.delayed_connection == 1) { 4307163953Srrs stcb->asoc.delayed_connection = 0; 4308169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 4309165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, 4310165220Srrs stcb->asoc.primary_destination, 4311165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9); 4312172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 4313163953Srrs } else { 4314163953Srrs /* 4315163953Srrs * already expired or did not use delayed 4316163953Srrs * connectx 4317163953Srrs */ 4318171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4319163953Srrs error = EALREADY; 4320163953Srrs } 4321163953Srrs SCTP_TCB_UNLOCK(stcb); 4322223132Stuexen break; 4323163953Srrs } 4324170056Srrs case SCTP_MAX_BURST: 4325163953Srrs { 4326217895Stuexen struct sctp_assoc_value *av; 4327163953Srrs 4328217895Stuexen SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 4329217895Stuexen SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4330166675Srrs 4331217895Stuexen if (stcb) { 4332217895Stuexen stcb->asoc.max_burst = av->assoc_value; 4333217895Stuexen SCTP_TCB_UNLOCK(stcb); 4334217895Stuexen } else { 4335224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4336224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4337224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC) || 4338223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 4339223132Stuexen SCTP_INP_WLOCK(inp); 4340223132Stuexen inp->sctp_ep.max_burst = av->assoc_value; 4341223132Stuexen SCTP_INP_WUNLOCK(inp); 4342223132Stuexen } 4343223132Stuexen if ((av->assoc_id == SCTP_CURRENT_ASSOC) || 4344223132Stuexen (av->assoc_id == SCTP_ALL_ASSOC)) { 4345223132Stuexen SCTP_INP_RLOCK(inp); 4346223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4347223132Stuexen SCTP_TCB_LOCK(stcb); 4348223132Stuexen stcb->asoc.max_burst = av->assoc_value; 4349223132Stuexen SCTP_TCB_UNLOCK(stcb); 4350223132Stuexen } 4351223132Stuexen SCTP_INP_RUNLOCK(inp); 4352223132Stuexen } 4353217895Stuexen } 4354223132Stuexen break; 4355163953Srrs } 4356163953Srrs case SCTP_MAXSEG: 4357163953Srrs { 4358167598Srrs struct sctp_assoc_value *av; 4359163953Srrs int ovh; 4360163953Srrs 4361167598Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 4362167598Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 4363166675Srrs 4364170056Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 4365170056Srrs ovh = SCTP_MED_OVERHEAD; 4366170056Srrs } else { 4367170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 4368170056Srrs } 4369167598Srrs if (stcb) { 4370170056Srrs if (av->assoc_value) { 4371170056Srrs stcb->asoc.sctp_frag_point = (av->assoc_value + ovh); 4372170056Srrs } else { 4373170056Srrs stcb->asoc.sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; 4374170056Srrs } 4375167598Srrs SCTP_TCB_UNLOCK(stcb); 4376163953Srrs } else { 4377224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4378224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4379224918Stuexen (av->assoc_id == SCTP_FUTURE_ASSOC)) { 4380223132Stuexen SCTP_INP_WLOCK(inp); 4381223132Stuexen /* 4382223132Stuexen * FIXME MT: I think this is not in 4383223132Stuexen * tune with the API ID 4384223132Stuexen */ 4385223132Stuexen if (av->assoc_value) { 4386223132Stuexen inp->sctp_frag_point = (av->assoc_value + ovh); 4387223132Stuexen } else { 4388223132Stuexen inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; 4389223132Stuexen } 4390223132Stuexen SCTP_INP_WUNLOCK(inp); 4391167598Srrs } else { 4392223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4393223132Stuexen error = EINVAL; 4394167598Srrs } 4395163953Srrs } 4396223132Stuexen break; 4397163953Srrs } 4398163953Srrs case SCTP_EVENTS: 4399163953Srrs { 4400163953Srrs struct sctp_event_subscribe *events; 4401163953Srrs 4402166675Srrs SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize); 4403166675Srrs 4404163953Srrs SCTP_INP_WLOCK(inp); 4405163953Srrs if (events->sctp_data_io_event) { 4406163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); 4407163953Srrs } else { 4408163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); 4409163953Srrs } 4410163953Srrs 4411163953Srrs if (events->sctp_association_event) { 4412163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); 4413163953Srrs } else { 4414163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); 4415163953Srrs } 4416163953Srrs 4417163953Srrs if (events->sctp_address_event) { 4418163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); 4419163953Srrs } else { 4420163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); 4421163953Srrs } 4422163953Srrs 4423163953Srrs if (events->sctp_send_failure_event) { 4424163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 4425163953Srrs } else { 4426163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 4427163953Srrs } 4428163953Srrs 4429163953Srrs if (events->sctp_peer_error_event) { 4430163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR); 4431163953Srrs } else { 4432163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR); 4433163953Srrs } 4434163953Srrs 4435163953Srrs if (events->sctp_shutdown_event) { 4436163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 4437163953Srrs } else { 4438163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 4439163953Srrs } 4440163953Srrs 4441163953Srrs if (events->sctp_partial_delivery_event) { 4442163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT); 4443163953Srrs } else { 4444163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT); 4445163953Srrs } 4446163953Srrs 4447163953Srrs if (events->sctp_adaptation_layer_event) { 4448163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 4449163953Srrs } else { 4450163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 4451163953Srrs } 4452163953Srrs 4453163953Srrs if (events->sctp_authentication_event) { 4454163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT); 4455163953Srrs } else { 4456163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT); 4457163953Srrs } 4458163953Srrs 4459185694Srrs if (events->sctp_sender_dry_event) { 4460185694Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT); 4461185694Srrs } else { 4462185694Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT); 4463185694Srrs } 4464185694Srrs 4465202520Srrs if (events->sctp_stream_reset_event) { 4466163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 4467163953Srrs } else { 4468163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 4469163953Srrs } 4470163953Srrs SCTP_INP_WUNLOCK(inp); 4471223132Stuexen 4472223132Stuexen SCTP_INP_RLOCK(inp); 4473223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4474223132Stuexen SCTP_TCB_LOCK(stcb); 4475223132Stuexen if (events->sctp_association_event) { 4476223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT); 4477223132Stuexen } else { 4478223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT); 4479223132Stuexen } 4480223132Stuexen if (events->sctp_address_event) { 4481223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT); 4482223132Stuexen } else { 4483223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT); 4484223132Stuexen } 4485223132Stuexen if (events->sctp_send_failure_event) { 4486223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 4487223132Stuexen } else { 4488223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 4489223132Stuexen } 4490223132Stuexen if (events->sctp_peer_error_event) { 4491223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR); 4492223132Stuexen } else { 4493223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR); 4494223132Stuexen } 4495223132Stuexen if (events->sctp_shutdown_event) { 4496223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 4497223132Stuexen } else { 4498223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 4499223132Stuexen } 4500223132Stuexen if (events->sctp_partial_delivery_event) { 4501223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT); 4502223132Stuexen } else { 4503223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT); 4504223132Stuexen } 4505223132Stuexen if (events->sctp_adaptation_layer_event) { 4506223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 4507223132Stuexen } else { 4508223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 4509223132Stuexen } 4510223132Stuexen if (events->sctp_authentication_event) { 4511223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT); 4512223132Stuexen } else { 4513223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT); 4514223132Stuexen } 4515223132Stuexen if (events->sctp_sender_dry_event) { 4516223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT); 4517223132Stuexen } else { 4518223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT); 4519223132Stuexen } 4520223132Stuexen if (events->sctp_stream_reset_event) { 4521223132Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 4522223132Stuexen } else { 4523223132Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 4524223132Stuexen } 4525223132Stuexen SCTP_TCB_UNLOCK(stcb); 4526223132Stuexen } 4527223132Stuexen /* 4528223132Stuexen * Send up the sender dry event only for 1-to-1 4529223132Stuexen * style sockets. 4530223132Stuexen */ 4531223132Stuexen if (events->sctp_sender_dry_event) { 4532223132Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4533223132Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 4534223132Stuexen stcb = LIST_FIRST(&inp->sctp_asoc_list); 4535223132Stuexen if (stcb) { 4536223132Stuexen SCTP_TCB_LOCK(stcb); 4537223132Stuexen if (TAILQ_EMPTY(&stcb->asoc.send_queue) && 4538223132Stuexen TAILQ_EMPTY(&stcb->asoc.sent_queue) && 4539223132Stuexen (stcb->asoc.stream_queue_cnt == 0)) { 4540223132Stuexen sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED); 4541223132Stuexen } 4542223132Stuexen SCTP_TCB_UNLOCK(stcb); 4543223132Stuexen } 4544223132Stuexen } 4545223132Stuexen } 4546223132Stuexen SCTP_INP_RUNLOCK(inp); 4547223132Stuexen break; 4548163953Srrs } 4549163953Srrs case SCTP_ADAPTATION_LAYER: 4550163953Srrs { 4551163953Srrs struct sctp_setadaptation *adap_bits; 4552163953Srrs 4553166675Srrs SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize); 4554163953Srrs SCTP_INP_WLOCK(inp); 4555163953Srrs inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind; 4556163953Srrs SCTP_INP_WUNLOCK(inp); 4557223132Stuexen break; 4558163953Srrs } 4559166675Srrs#ifdef SCTP_DEBUG 4560163953Srrs case SCTP_SET_INITIAL_DBG_SEQ: 4561163953Srrs { 4562163953Srrs uint32_t *vvv; 4563163953Srrs 4564166675Srrs SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize); 4565163953Srrs SCTP_INP_WLOCK(inp); 4566163953Srrs inp->sctp_ep.initial_sequence_debug = *vvv; 4567163953Srrs SCTP_INP_WUNLOCK(inp); 4568223132Stuexen break; 4569163953Srrs } 4570166675Srrs#endif 4571163953Srrs case SCTP_DEFAULT_SEND_PARAM: 4572163953Srrs { 4573163953Srrs struct sctp_sndrcvinfo *s_info; 4574163953Srrs 4575166675Srrs SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize); 4576166675Srrs SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); 4577163953Srrs 4578166675Srrs if (stcb) { 4579223132Stuexen if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) { 4580170056Srrs memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send))); 4581163953Srrs } else { 4582171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4583166675Srrs error = EINVAL; 4584163953Srrs } 4585166675Srrs SCTP_TCB_UNLOCK(stcb); 4586166675Srrs } else { 4587224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4588224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4589224918Stuexen (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) || 4590223132Stuexen (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) { 4591223132Stuexen SCTP_INP_WLOCK(inp); 4592223132Stuexen memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send))); 4593223132Stuexen SCTP_INP_WUNLOCK(inp); 4594223132Stuexen } 4595223132Stuexen if ((s_info->sinfo_assoc_id == SCTP_CURRENT_ASSOC) || 4596223132Stuexen (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) { 4597223132Stuexen SCTP_INP_RLOCK(inp); 4598223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 4599223132Stuexen SCTP_TCB_LOCK(stcb); 4600223132Stuexen if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) { 4601223132Stuexen memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send))); 4602223132Stuexen } 4603223132Stuexen SCTP_TCB_UNLOCK(stcb); 4604223132Stuexen } 4605223132Stuexen SCTP_INP_RUNLOCK(inp); 4606223132Stuexen } 4607163953Srrs } 4608223132Stuexen break; 4609163953Srrs } 4610163953Srrs case SCTP_PEER_ADDR_PARAMS: 4611163953Srrs { 4612163953Srrs struct sctp_paddrparams *paddrp; 4613163953Srrs struct sctp_nets *net; 4614163953Srrs 4615166675Srrs SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize); 4616166675Srrs SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); 4617163953Srrs net = NULL; 4618166675Srrs if (stcb) { 4619166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address); 4620166675Srrs } else { 4621166675Srrs /* 4622166675Srrs * We increment here since 4623166675Srrs * sctp_findassociation_ep_addr() wil do a 4624166675Srrs * decrement if it finds the stcb as long as 4625166675Srrs * the locked tcb (last argument) is NOT a 4626166675Srrs * TCB.. aka NULL. 4627166675Srrs */ 4628166675Srrs SCTP_INP_INCR_REF(inp); 4629166675Srrs stcb = sctp_findassociation_ep_addr(&inp, 4630166675Srrs (struct sockaddr *)&paddrp->spp_address, 4631166675Srrs &net, NULL, NULL); 4632163953Srrs if (stcb == NULL) { 4633166675Srrs SCTP_INP_DECR_REF(inp); 4634163953Srrs } 4635163953Srrs } 4636171943Srrs if (stcb && (net == NULL)) { 4637171943Srrs struct sockaddr *sa; 4638171943Srrs 4639171943Srrs sa = (struct sockaddr *)&paddrp->spp_address; 4640221249Stuexen#ifdef INET 4641171943Srrs if (sa->sa_family == AF_INET) { 4642221249Stuexen 4643171943Srrs struct sockaddr_in *sin; 4644171943Srrs 4645171943Srrs sin = (struct sockaddr_in *)sa; 4646171943Srrs if (sin->sin_addr.s_addr) { 4647171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4648171943Srrs SCTP_TCB_UNLOCK(stcb); 4649171943Srrs error = EINVAL; 4650171943Srrs break; 4651171943Srrs } 4652221249Stuexen } else 4653221249Stuexen#endif 4654221249Stuexen#ifdef INET6 4655221249Stuexen if (sa->sa_family == AF_INET6) { 4656171943Srrs struct sockaddr_in6 *sin6; 4657171943Srrs 4658171943Srrs sin6 = (struct sockaddr_in6 *)sa; 4659171943Srrs if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 4660171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4661171943Srrs SCTP_TCB_UNLOCK(stcb); 4662171943Srrs error = EINVAL; 4663171943Srrs break; 4664171943Srrs } 4665221249Stuexen } else 4666221249Stuexen#endif 4667221249Stuexen { 4668171943Srrs error = EAFNOSUPPORT; 4669171943Srrs SCTP_TCB_UNLOCK(stcb); 4670171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 4671171943Srrs break; 4672171943Srrs } 4673171943Srrs } 4674170056Srrs /* sanity checks */ 4675170056Srrs if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) { 4676170056Srrs if (stcb) 4677170056Srrs SCTP_TCB_UNLOCK(stcb); 4678171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4679170056Srrs return (EINVAL); 4680170056Srrs } 4681170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) { 4682170056Srrs if (stcb) 4683170056Srrs SCTP_TCB_UNLOCK(stcb); 4684171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4685170056Srrs return (EINVAL); 4686170056Srrs } 4687163953Srrs if (stcb) { 4688163953Srrs /************************TCB SPECIFIC SET ******************/ 4689163953Srrs /* 4690163953Srrs * do we change the timer for HB, we run 4691163953Srrs * only one? 4692163953Srrs */ 4693170056Srrs int ovh = 0; 4694170056Srrs 4695170056Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 4696170056Srrs ovh = SCTP_MED_OVERHEAD; 4697170056Srrs } else { 4698170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 4699170056Srrs } 4700170056Srrs 4701163953Srrs /* network sets ? */ 4702163953Srrs if (net) { 4703163953Srrs /************************NET SPECIFIC SET ******************/ 4704224641Stuexen if (paddrp->spp_flags & SPP_HB_DISABLE) { 4705224641Stuexen if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) && 4706224641Stuexen !(net->dest_state & SCTP_ADDR_NOHB)) { 4707224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 4708224641Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 4709171440Srrs } 4710163953Srrs net->dest_state |= SCTP_ADDR_NOHB; 4711163953Srrs } 4712163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 4713224641Stuexen if (paddrp->spp_hbinterval) { 4714224641Stuexen net->heart_beat_delay = paddrp->spp_hbinterval; 4715224641Stuexen } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 4716224641Stuexen net->heart_beat_delay = 0; 4717224641Stuexen } 4718224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 4719224641Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 4720224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 4721163953Srrs net->dest_state &= ~SCTP_ADDR_NOHB; 4722163953Srrs } 4723224641Stuexen if (paddrp->spp_flags & SPP_HB_DEMAND) { 4724224641Stuexen /* on demand HB */ 4725224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 4726228391Stuexen sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED); 4727224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 4728224641Stuexen } 4729170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { 4730165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 4731165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 4732165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 4733163953Srrs } 4734225635Stuexen net->dest_state |= SCTP_ADDR_NO_PMTUD; 4735163953Srrs if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) { 4736170056Srrs net->mtu = paddrp->spp_pathmtu + ovh; 4737169352Srrs if (net->mtu < stcb->asoc.smallest_mtu) { 4738228653Stuexen sctp_pathmtu_adjustment(stcb, net->mtu); 4739169352Srrs } 4740163953Srrs } 4741163953Srrs } 4742163953Srrs if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 4743225635Stuexen if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 4744163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 4745163953Srrs } 4746225635Stuexen net->dest_state &= ~SCTP_ADDR_NO_PMTUD; 4747163953Srrs } 4748224641Stuexen if (paddrp->spp_pathmaxrxt) { 4749224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 4750224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 4751224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 4752224641Stuexen } 4753224641Stuexen } else { 4754224641Stuexen if ((net->error_count <= paddrp->spp_pathmaxrxt) && 4755224641Stuexen (net->error_count > net->pf_threshold)) { 4756224641Stuexen net->dest_state |= SCTP_ADDR_PF; 4757224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 4758224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); 4759224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 4760224641Stuexen } 4761224641Stuexen } 4762224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 4763224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 4764224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 4765224641Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); 4766224641Stuexen } 4767224641Stuexen } else { 4768224641Stuexen if (net->error_count <= paddrp->spp_pathmaxrxt) { 4769224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 4770224641Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); 4771224641Stuexen } 4772224641Stuexen } 4773163953Srrs net->failure_threshold = paddrp->spp_pathmaxrxt; 4774224641Stuexen } 4775224870Stuexen if (paddrp->spp_flags & SPP_DSCP) { 4776226252Stuexen net->dscp = paddrp->spp_dscp & 0xfc; 4777225549Stuexen net->dscp |= 0x01; 4778163953Srrs } 4779167598Srrs#ifdef INET6 4780163953Srrs if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { 4781225549Stuexen if (net->ro._l_addr.sa.sa_family == AF_INET6) { 4782224870Stuexen net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 4783225549Stuexen net->flowlabel |= 0x80000000; 4784163953Srrs } 4785163953Srrs } 4786163953Srrs#endif 4787163953Srrs } else { 4788163953Srrs /************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/ 4789224641Stuexen if (paddrp->spp_pathmaxrxt) { 4790163953Srrs stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt; 4791224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4792224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 4793224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 4794224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 4795224641Stuexen } 4796224641Stuexen } else { 4797224641Stuexen if ((net->error_count <= paddrp->spp_pathmaxrxt) && 4798224641Stuexen (net->error_count > net->pf_threshold)) { 4799224641Stuexen net->dest_state |= SCTP_ADDR_PF; 4800224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 4801224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); 4802224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 4803224641Stuexen } 4804224641Stuexen } 4805224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 4806224641Stuexen if (net->error_count > paddrp->spp_pathmaxrxt) { 4807224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 4808224641Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); 4809224641Stuexen } 4810224641Stuexen } else { 4811224641Stuexen if (net->error_count <= paddrp->spp_pathmaxrxt) { 4812224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 4813224641Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); 4814224641Stuexen } 4815224641Stuexen } 4816224641Stuexen net->failure_threshold = paddrp->spp_pathmaxrxt; 4817224641Stuexen } 4818224641Stuexen } 4819163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 4820224641Stuexen if (paddrp->spp_hbinterval) { 4821224641Stuexen stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval; 4822224641Stuexen } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 4823224641Stuexen stcb->asoc.heart_beat_delay = 0; 4824224641Stuexen } 4825163953Srrs /* Turn back on the timer */ 4826224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4827224641Stuexen if (paddrp->spp_hbinterval) { 4828224641Stuexen net->heart_beat_delay = paddrp->spp_hbinterval; 4829224641Stuexen } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 4830224641Stuexen net->heart_beat_delay = 0; 4831224641Stuexen } 4832224641Stuexen if (net->dest_state & SCTP_ADDR_NOHB) { 4833224641Stuexen net->dest_state &= ~SCTP_ADDR_NOHB; 4834224641Stuexen } 4835224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 4836224641Stuexen SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 4837224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 4838224641Stuexen } 4839225635Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 4840163953Srrs } 4841224641Stuexen if (paddrp->spp_flags & SPP_HB_DISABLE) { 4842224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4843224641Stuexen if (!(net->dest_state & SCTP_ADDR_NOHB)) { 4844224641Stuexen net->dest_state |= SCTP_ADDR_NOHB; 4845224641Stuexen if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { 4846224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 4847224641Stuexen } 4848224641Stuexen } 4849224641Stuexen } 4850225635Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 4851224641Stuexen } 4852170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { 4853170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4854170056Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 4855170056Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 4856170056Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 4857170056Srrs } 4858225635Stuexen net->dest_state |= SCTP_ADDR_NO_PMTUD; 4859170056Srrs if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) { 4860170056Srrs net->mtu = paddrp->spp_pathmtu + ovh; 4861170056Srrs if (net->mtu < stcb->asoc.smallest_mtu) { 4862228653Stuexen sctp_pathmtu_adjustment(stcb, net->mtu); 4863170056Srrs } 4864170056Srrs } 4865170056Srrs } 4866225635Stuexen sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 4867170056Srrs } 4868170056Srrs if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 4869170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4870225635Stuexen if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 4871170056Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 4872170056Srrs } 4873225635Stuexen net->dest_state &= ~SCTP_ADDR_NO_PMTUD; 4874170056Srrs } 4875225635Stuexen sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 4876170056Srrs } 4877224870Stuexen if (paddrp->spp_flags & SPP_DSCP) { 4878224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4879226252Stuexen net->dscp = paddrp->spp_dscp & 0xfc; 4880225549Stuexen net->dscp |= 0x01; 4881163953Srrs } 4882226252Stuexen stcb->asoc.default_dscp = paddrp->spp_dscp & 0xfc; 4883225549Stuexen stcb->asoc.default_dscp |= 0x01; 4884163953Srrs } 4885225549Stuexen#ifdef INET6 4886224641Stuexen if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { 4887170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4888225549Stuexen if (net->ro._l_addr.sa.sa_family == AF_INET6) { 4889225549Stuexen net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 4890225549Stuexen net->flowlabel |= 0x80000000; 4891225549Stuexen } 4892170056Srrs } 4893225549Stuexen stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 4894225549Stuexen stcb->asoc.default_flowlabel |= 0x80000000; 4895163953Srrs } 4896225549Stuexen#endif 4897163953Srrs } 4898163953Srrs SCTP_TCB_UNLOCK(stcb); 4899163953Srrs } else { 4900163953Srrs /************************NO TCB, SET TO default stuff ******************/ 4901224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4902224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4903224918Stuexen (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) { 4904223132Stuexen SCTP_INP_WLOCK(inp); 4905223132Stuexen /* 4906223132Stuexen * For the TOS/FLOWLABEL stuff you 4907223132Stuexen * set it with the options on the 4908223132Stuexen * socket 4909223132Stuexen */ 4910223132Stuexen if (paddrp->spp_pathmaxrxt) { 4911223132Stuexen inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt; 4912223132Stuexen } 4913223132Stuexen if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) 4914223132Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0; 4915223132Stuexen else if (paddrp->spp_hbinterval) { 4916223132Stuexen if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL) 4917223132Stuexen paddrp->spp_hbinterval = SCTP_MAX_HB_INTERVAL; 4918223132Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval); 4919223132Stuexen } 4920223132Stuexen if (paddrp->spp_flags & SPP_HB_ENABLE) { 4921224641Stuexen if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { 4922224641Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0; 4923224641Stuexen } else if (paddrp->spp_hbinterval) { 4924224641Stuexen inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval); 4925224641Stuexen } 4926223132Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 4927223132Stuexen } else if (paddrp->spp_flags & SPP_HB_DISABLE) { 4928223132Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 4929223132Stuexen } 4930225635Stuexen if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 4931225635Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 4932225635Stuexen } else if (paddrp->spp_flags & SPP_PMTUD_DISABLE) { 4933225635Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD); 4934225635Stuexen } 4935225549Stuexen if (paddrp->spp_flags & SPP_DSCP) { 4936226252Stuexen inp->sctp_ep.default_dscp = paddrp->spp_dscp & 0xfc; 4937225549Stuexen inp->sctp_ep.default_dscp |= 0x01; 4938225549Stuexen } 4939225549Stuexen#ifdef INET6 4940225549Stuexen if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { 4941225549Stuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 4942225549Stuexen inp->sctp_ep.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; 4943225549Stuexen inp->sctp_ep.default_flowlabel |= 0x80000000; 4944225549Stuexen } 4945225549Stuexen } 4946225549Stuexen#endif 4947223132Stuexen SCTP_INP_WUNLOCK(inp); 4948223132Stuexen } else { 4949223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4950223132Stuexen error = EINVAL; 4951163953Srrs } 4952163953Srrs } 4953223132Stuexen break; 4954163953Srrs } 4955163953Srrs case SCTP_RTOINFO: 4956163953Srrs { 4957163953Srrs struct sctp_rtoinfo *srto; 4958169655Srrs uint32_t new_init, new_min, new_max; 4959163953Srrs 4960166675Srrs SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize); 4961166675Srrs SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); 4962166675Srrs 4963166675Srrs if (stcb) { 4964167598Srrs if (srto->srto_initial) 4965169655Srrs new_init = srto->srto_initial; 4966169655Srrs else 4967169655Srrs new_init = stcb->asoc.initial_rto; 4968167598Srrs if (srto->srto_max) 4969169655Srrs new_max = srto->srto_max; 4970169655Srrs else 4971169655Srrs new_max = stcb->asoc.maxrto; 4972167598Srrs if (srto->srto_min) 4973169655Srrs new_min = srto->srto_min; 4974169655Srrs else 4975169655Srrs new_min = stcb->asoc.minrto; 4976169655Srrs if ((new_min <= new_init) && (new_init <= new_max)) { 4977169655Srrs stcb->asoc.initial_rto = new_init; 4978169655Srrs stcb->asoc.maxrto = new_max; 4979169655Srrs stcb->asoc.minrto = new_min; 4980169655Srrs } else { 4981179783Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4982179783Srrs error = EINVAL; 4983169655Srrs } 4984166675Srrs SCTP_TCB_UNLOCK(stcb); 4985166675Srrs } else { 4986224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 4987224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4988224918Stuexen (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) { 4989223132Stuexen SCTP_INP_WLOCK(inp); 4990223132Stuexen if (srto->srto_initial) 4991223132Stuexen new_init = srto->srto_initial; 4992223132Stuexen else 4993223132Stuexen new_init = inp->sctp_ep.initial_rto; 4994223132Stuexen if (srto->srto_max) 4995223132Stuexen new_max = srto->srto_max; 4996223132Stuexen else 4997223132Stuexen new_max = inp->sctp_ep.sctp_maxrto; 4998223132Stuexen if (srto->srto_min) 4999223132Stuexen new_min = srto->srto_min; 5000223132Stuexen else 5001223132Stuexen new_min = inp->sctp_ep.sctp_minrto; 5002223132Stuexen if ((new_min <= new_init) && (new_init <= new_max)) { 5003223132Stuexen inp->sctp_ep.initial_rto = new_init; 5004223132Stuexen inp->sctp_ep.sctp_maxrto = new_max; 5005223132Stuexen inp->sctp_ep.sctp_minrto = new_min; 5006223132Stuexen } else { 5007223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5008223132Stuexen error = EINVAL; 5009223132Stuexen } 5010223132Stuexen SCTP_INP_WUNLOCK(inp); 5011169655Srrs } else { 5012179783Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5013179783Srrs error = EINVAL; 5014169655Srrs } 5015163953Srrs } 5016223132Stuexen break; 5017163953Srrs } 5018163953Srrs case SCTP_ASSOCINFO: 5019163953Srrs { 5020163953Srrs struct sctp_assocparams *sasoc; 5021163953Srrs 5022166675Srrs SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize); 5023166675Srrs SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); 5024171477Srrs if (sasoc->sasoc_cookie_life) { 5025171477Srrs /* boundary check the cookie life */ 5026171477Srrs if (sasoc->sasoc_cookie_life < 1000) 5027171477Srrs sasoc->sasoc_cookie_life = 1000; 5028171477Srrs if (sasoc->sasoc_cookie_life > SCTP_MAX_COOKIE_LIFE) { 5029171477Srrs sasoc->sasoc_cookie_life = SCTP_MAX_COOKIE_LIFE; 5030171477Srrs } 5031171477Srrs } 5032163953Srrs if (stcb) { 5033163953Srrs if (sasoc->sasoc_asocmaxrxt) 5034163953Srrs stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt; 5035170056Srrs if (sasoc->sasoc_cookie_life) { 5036171572Srrs stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); 5037167598Srrs } 5038163953Srrs SCTP_TCB_UNLOCK(stcb); 5039163953Srrs } else { 5040224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5041224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5042224918Stuexen (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) { 5043223132Stuexen SCTP_INP_WLOCK(inp); 5044223132Stuexen if (sasoc->sasoc_asocmaxrxt) 5045223132Stuexen inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt; 5046223132Stuexen if (sasoc->sasoc_cookie_life) { 5047223132Stuexen inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); 5048223132Stuexen } 5049223132Stuexen SCTP_INP_WUNLOCK(inp); 5050223132Stuexen } else { 5051223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5052223132Stuexen error = EINVAL; 5053167598Srrs } 5054163953Srrs } 5055223132Stuexen break; 5056163953Srrs } 5057163953Srrs case SCTP_INITMSG: 5058163953Srrs { 5059163953Srrs struct sctp_initmsg *sinit; 5060163953Srrs 5061166675Srrs SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize); 5062163953Srrs SCTP_INP_WLOCK(inp); 5063163953Srrs if (sinit->sinit_num_ostreams) 5064163953Srrs inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams; 5065163953Srrs 5066163953Srrs if (sinit->sinit_max_instreams) 5067163953Srrs inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams; 5068163953Srrs 5069163953Srrs if (sinit->sinit_max_attempts) 5070163953Srrs inp->sctp_ep.max_init_times = sinit->sinit_max_attempts; 5071163953Srrs 5072167598Srrs if (sinit->sinit_max_init_timeo) 5073163953Srrs inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo; 5074163953Srrs SCTP_INP_WUNLOCK(inp); 5075223132Stuexen break; 5076163953Srrs } 5077163953Srrs case SCTP_PRIMARY_ADDR: 5078163953Srrs { 5079163953Srrs struct sctp_setprim *spa; 5080223132Stuexen struct sctp_nets *net; 5081163953Srrs 5082166675Srrs SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize); 5083166675Srrs SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id); 5084163953Srrs 5085166675Srrs net = NULL; 5086166675Srrs if (stcb) { 5087166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&spa->ssp_addr); 5088166675Srrs } else { 5089166675Srrs /* 5090166675Srrs * We increment here since 5091166675Srrs * sctp_findassociation_ep_addr() wil do a 5092166675Srrs * decrement if it finds the stcb as long as 5093166675Srrs * the locked tcb (last argument) is NOT a 5094166675Srrs * TCB.. aka NULL. 5095166675Srrs */ 5096163953Srrs SCTP_INP_INCR_REF(inp); 5097163953Srrs stcb = sctp_findassociation_ep_addr(&inp, 5098163953Srrs (struct sockaddr *)&spa->ssp_addr, 5099163953Srrs &net, NULL, NULL); 5100163953Srrs if (stcb == NULL) { 5101163953Srrs SCTP_INP_DECR_REF(inp); 5102163953Srrs } 5103163953Srrs } 5104166675Srrs 5105166675Srrs if ((stcb) && (net)) { 5106166675Srrs if ((net != stcb->asoc.primary_destination) && 5107166675Srrs (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) { 5108166675Srrs /* Ok we need to set it */ 5109166675Srrs if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) { 5110224641Stuexen if ((stcb->asoc.alternate) && 5111224641Stuexen (!(net->dest_state & SCTP_ADDR_PF)) && 5112224641Stuexen (net->dest_state & SCTP_ADDR_REACHABLE)) { 5113224641Stuexen sctp_free_remote_addr(stcb->asoc.alternate); 5114224641Stuexen stcb->asoc.alternate = NULL; 5115166675Srrs } 5116163953Srrs } 5117163953Srrs } 5118166675Srrs } else { 5119171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5120166675Srrs error = EINVAL; 5121163953Srrs } 5122166675Srrs if (stcb) { 5123166675Srrs SCTP_TCB_UNLOCK(stcb); 5124166675Srrs } 5125223132Stuexen break; 5126163953Srrs } 5127167598Srrs case SCTP_SET_DYNAMIC_PRIMARY: 5128167598Srrs { 5129167598Srrs union sctp_sockstore *ss; 5130163953Srrs 5131170587Srwatson error = priv_check(curthread, 5132170587Srwatson PRIV_NETINET_RESERVEDPORT); 5133167598Srrs if (error) 5134167598Srrs break; 5135167598Srrs 5136167598Srrs SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize); 5137167598Srrs /* SUPER USER CHECK? */ 5138167598Srrs error = sctp_dynamic_set_primary(&ss->sa, vrf_id); 5139223132Stuexen break; 5140167598Srrs } 5141163953Srrs case SCTP_SET_PEER_PRIMARY_ADDR: 5142163953Srrs { 5143163953Srrs struct sctp_setpeerprim *sspp; 5144163953Srrs 5145166675Srrs SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize); 5146166675Srrs SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id); 5147169208Srrs if (stcb != NULL) { 5148170056Srrs struct sctp_ifa *ifa; 5149170056Srrs 5150170056Srrs ifa = sctp_find_ifa_by_addr((struct sockaddr *)&sspp->sspp_addr, 5151172091Srrs stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED); 5152170056Srrs if (ifa == NULL) { 5153171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5154166675Srrs error = EINVAL; 5155170056Srrs goto out_of_it; 5156166675Srrs } 5157170056Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { 5158170056Srrs /* 5159170056Srrs * Must validate the ifa found is in 5160170056Srrs * our ep 5161170056Srrs */ 5162170056Srrs struct sctp_laddr *laddr; 5163170056Srrs int found = 0; 5164170056Srrs 5165170056Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 5166170056Srrs if (laddr->ifa == NULL) { 5167170056Srrs SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n", 5168170056Srrs __FUNCTION__); 5169170056Srrs continue; 5170170056Srrs } 5171170056Srrs if (laddr->ifa == ifa) { 5172170056Srrs found = 1; 5173170056Srrs break; 5174170056Srrs } 5175170056Srrs } 5176170056Srrs if (!found) { 5177171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5178170056Srrs error = EINVAL; 5179170056Srrs goto out_of_it; 5180170056Srrs } 5181170056Srrs } 5182170056Srrs if (sctp_set_primary_ip_address_sa(stcb, 5183170056Srrs (struct sockaddr *)&sspp->sspp_addr) != 0) { 5184171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5185170056Srrs error = EINVAL; 5186170056Srrs } 5187170056Srrs out_of_it: 5188169208Srrs SCTP_TCB_UNLOCK(stcb); 5189166675Srrs } else { 5190171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5191163953Srrs error = EINVAL; 5192163953Srrs } 5193223132Stuexen break; 5194163953Srrs } 5195163953Srrs case SCTP_BINDX_ADD_ADDR: 5196163953Srrs { 5197163953Srrs struct sctp_getaddresses *addrs; 5198171531Srrs size_t sz; 5199171477Srrs struct thread *td; 5200163953Srrs 5201171477Srrs td = (struct thread *)p; 5202170606Srrs SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, 5203170606Srrs optsize); 5204221249Stuexen#ifdef INET 5205171477Srrs if (addrs->addr->sa_family == AF_INET) { 5206171477Srrs sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in); 5207171477Srrs if (optsize < sz) { 5208171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5209171477Srrs error = EINVAL; 5210171477Srrs break; 5211171477Srrs } 5212188590Srrs if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) { 5213188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5214185435Sbz break; 5215171477Srrs } 5216221249Stuexen } else 5217221249Stuexen#endif 5218185435Sbz#ifdef INET6 5219221249Stuexen if (addrs->addr->sa_family == AF_INET6) { 5220171477Srrs sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6); 5221171477Srrs if (optsize < sz) { 5222171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5223171477Srrs error = EINVAL; 5224171477Srrs break; 5225171477Srrs } 5226188590Srrs if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr), 5227188590Srrs (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) { 5228188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5229185435Sbz break; 5230185435Sbz } 5231221249Stuexen } else 5232185435Sbz#endif 5233221249Stuexen { 5234185435Sbz error = EAFNOSUPPORT; 5235185435Sbz break; 5236171477Srrs } 5237170606Srrs sctp_bindx_add_address(so, inp, addrs->addr, 5238170606Srrs addrs->sget_assoc_id, vrf_id, 5239170606Srrs &error, p); 5240223132Stuexen break; 5241163953Srrs } 5242163953Srrs case SCTP_BINDX_REM_ADDR: 5243163953Srrs { 5244163953Srrs struct sctp_getaddresses *addrs; 5245171531Srrs size_t sz; 5246171477Srrs struct thread *td; 5247163953Srrs 5248171477Srrs td = (struct thread *)p; 5249185435Sbz 5250166675Srrs SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize); 5251221249Stuexen#ifdef INET 5252171477Srrs if (addrs->addr->sa_family == AF_INET) { 5253171477Srrs sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in); 5254171477Srrs if (optsize < sz) { 5255171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5256171477Srrs error = EINVAL; 5257171477Srrs break; 5258171477Srrs } 5259188590Srrs if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) { 5260188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5261185435Sbz break; 5262171477Srrs } 5263221249Stuexen } else 5264221249Stuexen#endif 5265185435Sbz#ifdef INET6 5266221249Stuexen if (addrs->addr->sa_family == AF_INET6) { 5267171477Srrs sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6); 5268171477Srrs if (optsize < sz) { 5269171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5270171477Srrs error = EINVAL; 5271171477Srrs break; 5272171477Srrs } 5273224641Stuexen if (td != NULL && 5274224641Stuexen (error = prison_local_ip6(td->td_ucred, 5275224641Stuexen &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr), 5276188590Srrs (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) { 5277188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 5278185435Sbz break; 5279185435Sbz } 5280221249Stuexen } else 5281185435Sbz#endif 5282221249Stuexen { 5283185435Sbz error = EAFNOSUPPORT; 5284185435Sbz break; 5285171477Srrs } 5286228653Stuexen sctp_bindx_delete_address(inp, addrs->addr, 5287170606Srrs addrs->sget_assoc_id, vrf_id, 5288170606Srrs &error); 5289223132Stuexen break; 5290163953Srrs } 5291223132Stuexen case SCTP_EVENT: 5292223132Stuexen { 5293223132Stuexen struct sctp_event *event; 5294223132Stuexen uint32_t event_type; 5295223132Stuexen 5296223132Stuexen SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, optsize); 5297223132Stuexen SCTP_FIND_STCB(inp, stcb, event->se_assoc_id); 5298223132Stuexen switch (event->se_type) { 5299223132Stuexen case SCTP_ASSOC_CHANGE: 5300223132Stuexen event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT; 5301223132Stuexen break; 5302223132Stuexen case SCTP_PEER_ADDR_CHANGE: 5303223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPADDREVNT; 5304223132Stuexen break; 5305223132Stuexen case SCTP_REMOTE_ERROR: 5306223132Stuexen event_type = SCTP_PCB_FLAGS_RECVPEERERR; 5307223132Stuexen break; 5308223132Stuexen case SCTP_SEND_FAILED: 5309223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT; 5310223132Stuexen break; 5311223132Stuexen case SCTP_SHUTDOWN_EVENT: 5312223132Stuexen event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT; 5313223132Stuexen break; 5314223132Stuexen case SCTP_ADAPTATION_INDICATION: 5315223132Stuexen event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT; 5316223132Stuexen break; 5317223132Stuexen case SCTP_PARTIAL_DELIVERY_EVENT: 5318223132Stuexen event_type = SCTP_PCB_FLAGS_PDAPIEVNT; 5319223132Stuexen break; 5320223132Stuexen case SCTP_AUTHENTICATION_EVENT: 5321223132Stuexen event_type = SCTP_PCB_FLAGS_AUTHEVNT; 5322223132Stuexen break; 5323223132Stuexen case SCTP_STREAM_RESET_EVENT: 5324223132Stuexen event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT; 5325223132Stuexen break; 5326223132Stuexen case SCTP_SENDER_DRY_EVENT: 5327223132Stuexen event_type = SCTP_PCB_FLAGS_DRYEVNT; 5328223132Stuexen break; 5329223132Stuexen case SCTP_NOTIFICATIONS_STOPPED_EVENT: 5330223132Stuexen event_type = 0; 5331223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); 5332223132Stuexen error = ENOTSUP; 5333223132Stuexen break; 5334223132Stuexen default: 5335223132Stuexen event_type = 0; 5336223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5337223132Stuexen error = EINVAL; 5338223132Stuexen break; 5339223132Stuexen } 5340223132Stuexen if (event_type > 0) { 5341223132Stuexen if (stcb) { 5342223132Stuexen if (event->se_on) { 5343223132Stuexen sctp_stcb_feature_on(inp, stcb, event_type); 5344223132Stuexen if (event_type == SCTP_PCB_FLAGS_DRYEVNT) { 5345223132Stuexen if (TAILQ_EMPTY(&stcb->asoc.send_queue) && 5346223132Stuexen TAILQ_EMPTY(&stcb->asoc.sent_queue) && 5347223132Stuexen (stcb->asoc.stream_queue_cnt == 0)) { 5348223132Stuexen sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED); 5349223132Stuexen } 5350223132Stuexen } 5351223132Stuexen } else { 5352223132Stuexen sctp_stcb_feature_off(inp, stcb, event_type); 5353223132Stuexen } 5354223132Stuexen SCTP_TCB_UNLOCK(stcb); 5355223132Stuexen } else { 5356223132Stuexen /* 5357223132Stuexen * We don't want to send up a storm 5358223132Stuexen * of events, so return an error for 5359223132Stuexen * sender dry events 5360223132Stuexen */ 5361223132Stuexen if ((event_type == SCTP_PCB_FLAGS_DRYEVNT) && 5362224918Stuexen ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) && 5363224918Stuexen ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) && 5364223132Stuexen ((event->se_assoc_id == SCTP_ALL_ASSOC) || 5365223132Stuexen (event->se_assoc_id == SCTP_CURRENT_ASSOC))) { 5366223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); 5367223132Stuexen error = ENOTSUP; 5368223132Stuexen break; 5369223132Stuexen } 5370224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5371224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5372224918Stuexen (event->se_assoc_id == SCTP_FUTURE_ASSOC) || 5373223132Stuexen (event->se_assoc_id == SCTP_ALL_ASSOC)) { 5374223132Stuexen SCTP_INP_WLOCK(inp); 5375223132Stuexen if (event->se_on) { 5376223132Stuexen sctp_feature_on(inp, event_type); 5377223132Stuexen } else { 5378223132Stuexen sctp_feature_off(inp, event_type); 5379223132Stuexen } 5380223132Stuexen SCTP_INP_WUNLOCK(inp); 5381223132Stuexen } 5382223132Stuexen if ((event->se_assoc_id == SCTP_CURRENT_ASSOC) || 5383223132Stuexen (event->se_assoc_id == SCTP_ALL_ASSOC)) { 5384223132Stuexen SCTP_INP_RLOCK(inp); 5385223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 5386223132Stuexen SCTP_TCB_LOCK(stcb); 5387223132Stuexen if (event->se_on) { 5388223132Stuexen sctp_stcb_feature_on(inp, stcb, event_type); 5389223132Stuexen } else { 5390223132Stuexen sctp_stcb_feature_off(inp, stcb, event_type); 5391223132Stuexen } 5392223132Stuexen SCTP_TCB_UNLOCK(stcb); 5393223132Stuexen } 5394223132Stuexen SCTP_INP_RUNLOCK(inp); 5395223132Stuexen } 5396223132Stuexen } 5397223132Stuexen } 5398223132Stuexen break; 5399223132Stuexen } 5400223132Stuexen case SCTP_RECVRCVINFO: 5401223132Stuexen { 5402223132Stuexen int *onoff; 5403223132Stuexen 5404223132Stuexen SCTP_CHECK_AND_CAST(onoff, optval, int, optsize); 5405223132Stuexen SCTP_INP_WLOCK(inp); 5406223132Stuexen if (*onoff != 0) { 5407223132Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO); 5408223132Stuexen } else { 5409223132Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO); 5410223132Stuexen } 5411223132Stuexen SCTP_INP_WUNLOCK(inp); 5412223132Stuexen break; 5413223132Stuexen } 5414223132Stuexen case SCTP_RECVNXTINFO: 5415223132Stuexen { 5416223132Stuexen int *onoff; 5417223132Stuexen 5418223132Stuexen SCTP_CHECK_AND_CAST(onoff, optval, int, optsize); 5419223132Stuexen SCTP_INP_WLOCK(inp); 5420223132Stuexen if (*onoff != 0) { 5421223132Stuexen sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO); 5422223132Stuexen } else { 5423223132Stuexen sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO); 5424223132Stuexen } 5425223132Stuexen SCTP_INP_WUNLOCK(inp); 5426223132Stuexen break; 5427223132Stuexen } 5428223132Stuexen case SCTP_DEFAULT_SNDINFO: 5429223132Stuexen { 5430223132Stuexen struct sctp_sndinfo *info; 5431223162Stuexen uint16_t policy; 5432223132Stuexen 5433223132Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, optsize); 5434223132Stuexen SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id); 5435223132Stuexen 5436223132Stuexen if (stcb) { 5437223132Stuexen if (info->snd_sid < stcb->asoc.streamoutcnt) { 5438223132Stuexen stcb->asoc.def_send.sinfo_stream = info->snd_sid; 5439223162Stuexen policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); 5440223132Stuexen stcb->asoc.def_send.sinfo_flags = info->snd_flags; 5441223162Stuexen stcb->asoc.def_send.sinfo_flags |= policy; 5442223132Stuexen stcb->asoc.def_send.sinfo_ppid = info->snd_ppid; 5443223132Stuexen stcb->asoc.def_send.sinfo_context = info->snd_context; 5444223132Stuexen } else { 5445223132Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5446223132Stuexen error = EINVAL; 5447223132Stuexen } 5448223132Stuexen SCTP_TCB_UNLOCK(stcb); 5449223132Stuexen } else { 5450224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5451224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5452224918Stuexen (info->snd_assoc_id == SCTP_FUTURE_ASSOC) || 5453223132Stuexen (info->snd_assoc_id == SCTP_ALL_ASSOC)) { 5454223132Stuexen SCTP_INP_WLOCK(inp); 5455223132Stuexen inp->def_send.sinfo_stream = info->snd_sid; 5456223162Stuexen policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags); 5457223132Stuexen inp->def_send.sinfo_flags = info->snd_flags; 5458223162Stuexen inp->def_send.sinfo_flags |= policy; 5459223132Stuexen inp->def_send.sinfo_ppid = info->snd_ppid; 5460223132Stuexen inp->def_send.sinfo_context = info->snd_context; 5461223132Stuexen SCTP_INP_WUNLOCK(inp); 5462223132Stuexen } 5463223132Stuexen if ((info->snd_assoc_id == SCTP_CURRENT_ASSOC) || 5464223132Stuexen (info->snd_assoc_id == SCTP_ALL_ASSOC)) { 5465223132Stuexen SCTP_INP_RLOCK(inp); 5466223132Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 5467223132Stuexen SCTP_TCB_LOCK(stcb); 5468223132Stuexen if (info->snd_sid < stcb->asoc.streamoutcnt) { 5469223132Stuexen stcb->asoc.def_send.sinfo_stream = info->snd_sid; 5470223162Stuexen policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); 5471223132Stuexen stcb->asoc.def_send.sinfo_flags = info->snd_flags; 5472223162Stuexen stcb->asoc.def_send.sinfo_flags |= policy; 5473223132Stuexen stcb->asoc.def_send.sinfo_ppid = info->snd_ppid; 5474223132Stuexen stcb->asoc.def_send.sinfo_context = info->snd_context; 5475223132Stuexen } 5476223132Stuexen SCTP_TCB_UNLOCK(stcb); 5477223132Stuexen } 5478223132Stuexen SCTP_INP_RUNLOCK(inp); 5479223132Stuexen } 5480223132Stuexen } 5481223132Stuexen break; 5482223132Stuexen } 5483223162Stuexen case SCTP_DEFAULT_PRINFO: 5484223162Stuexen { 5485223162Stuexen struct sctp_default_prinfo *info; 5486223162Stuexen 5487223162Stuexen SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, optsize); 5488223162Stuexen SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id); 5489223162Stuexen 5490223162Stuexen if (PR_SCTP_INVALID_POLICY(info->pr_policy)) { 5491223162Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5492223162Stuexen error = EINVAL; 5493223162Stuexen break; 5494223162Stuexen } 5495223162Stuexen if (stcb) { 5496223162Stuexen stcb->asoc.def_send.sinfo_flags &= 0xfff0; 5497223162Stuexen stcb->asoc.def_send.sinfo_flags |= info->pr_policy; 5498224918Stuexen stcb->asoc.def_send.sinfo_timetolive = info->pr_value; 5499223162Stuexen SCTP_TCB_UNLOCK(stcb); 5500223162Stuexen } else { 5501224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5502224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5503224918Stuexen (info->pr_assoc_id == SCTP_FUTURE_ASSOC) || 5504223162Stuexen (info->pr_assoc_id == SCTP_ALL_ASSOC)) { 5505223162Stuexen SCTP_INP_WLOCK(inp); 5506223162Stuexen inp->def_send.sinfo_flags &= 0xfff0; 5507223162Stuexen inp->def_send.sinfo_flags |= info->pr_policy; 5508224918Stuexen inp->def_send.sinfo_timetolive = info->pr_value; 5509223162Stuexen SCTP_INP_WUNLOCK(inp); 5510223162Stuexen } 5511223162Stuexen if ((info->pr_assoc_id == SCTP_CURRENT_ASSOC) || 5512223162Stuexen (info->pr_assoc_id == SCTP_ALL_ASSOC)) { 5513223162Stuexen SCTP_INP_RLOCK(inp); 5514223162Stuexen LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 5515223162Stuexen SCTP_TCB_LOCK(stcb); 5516223162Stuexen stcb->asoc.def_send.sinfo_flags &= 0xfff0; 5517223162Stuexen stcb->asoc.def_send.sinfo_flags |= info->pr_policy; 5518224918Stuexen stcb->asoc.def_send.sinfo_timetolive = info->pr_value; 5519223162Stuexen SCTP_TCB_UNLOCK(stcb); 5520223162Stuexen } 5521223162Stuexen SCTP_INP_RUNLOCK(inp); 5522223162Stuexen } 5523223162Stuexen } 5524223162Stuexen break; 5525223162Stuexen } 5526224641Stuexen case SCTP_PEER_ADDR_THLDS: 5527224641Stuexen /* Applies to the specific association */ 5528224641Stuexen { 5529224641Stuexen struct sctp_paddrthlds *thlds; 5530224641Stuexen struct sctp_nets *net; 5531224641Stuexen 5532224641Stuexen SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, optsize); 5533224641Stuexen SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id); 5534224641Stuexen net = NULL; 5535224641Stuexen if (stcb) { 5536224641Stuexen net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_assoc_id); 5537224641Stuexen } else { 5538224641Stuexen /* 5539224641Stuexen * We increment here since 5540224641Stuexen * sctp_findassociation_ep_addr() wil do a 5541224641Stuexen * decrement if it finds the stcb as long as 5542224641Stuexen * the locked tcb (last argument) is NOT a 5543224641Stuexen * TCB.. aka NULL. 5544224641Stuexen */ 5545224641Stuexen SCTP_INP_INCR_REF(inp); 5546224641Stuexen stcb = sctp_findassociation_ep_addr(&inp, 5547224641Stuexen (struct sockaddr *)&thlds->spt_assoc_id, 5548224641Stuexen &net, NULL, NULL); 5549224641Stuexen if (stcb == NULL) { 5550224641Stuexen SCTP_INP_DECR_REF(inp); 5551224641Stuexen } 5552224641Stuexen } 5553224641Stuexen if (stcb && (net == NULL)) { 5554224641Stuexen struct sockaddr *sa; 5555224641Stuexen 5556224641Stuexen sa = (struct sockaddr *)&thlds->spt_assoc_id; 5557224641Stuexen#ifdef INET 5558224641Stuexen if (sa->sa_family == AF_INET) { 5559224641Stuexen 5560224641Stuexen struct sockaddr_in *sin; 5561224641Stuexen 5562224641Stuexen sin = (struct sockaddr_in *)sa; 5563224641Stuexen if (sin->sin_addr.s_addr) { 5564224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5565224641Stuexen SCTP_TCB_UNLOCK(stcb); 5566224641Stuexen error = EINVAL; 5567224641Stuexen break; 5568224641Stuexen } 5569224641Stuexen } else 5570224641Stuexen#endif 5571224641Stuexen#ifdef INET6 5572224641Stuexen if (sa->sa_family == AF_INET6) { 5573224641Stuexen struct sockaddr_in6 *sin6; 5574224641Stuexen 5575224641Stuexen sin6 = (struct sockaddr_in6 *)sa; 5576224641Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 5577224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5578224641Stuexen SCTP_TCB_UNLOCK(stcb); 5579224641Stuexen error = EINVAL; 5580224641Stuexen break; 5581224641Stuexen } 5582224641Stuexen } else 5583224641Stuexen#endif 5584224641Stuexen { 5585224641Stuexen error = EAFNOSUPPORT; 5586224641Stuexen SCTP_TCB_UNLOCK(stcb); 5587224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 5588224641Stuexen break; 5589224641Stuexen } 5590224641Stuexen } 5591224641Stuexen if (stcb) { 5592224641Stuexen if (net) { 5593224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 5594224641Stuexen if ((net->failure_threshold > thlds->spt_pathmaxrxt) || 5595224641Stuexen (net->failure_threshold <= thlds->spt_pathpfthld)) { 5596224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 5597224641Stuexen } 5598224641Stuexen } else { 5599224641Stuexen if ((net->failure_threshold > thlds->spt_pathpfthld) && 5600224641Stuexen (net->failure_threshold <= thlds->spt_pathmaxrxt)) { 5601224641Stuexen net->dest_state |= SCTP_ADDR_PF; 5602224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 5603224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); 5604224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 5605224641Stuexen } 5606224641Stuexen } 5607224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 5608224641Stuexen if (net->failure_threshold > thlds->spt_pathmaxrxt) { 5609224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 5610224641Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); 5611224641Stuexen } 5612224641Stuexen } else { 5613224641Stuexen if (net->failure_threshold <= thlds->spt_pathmaxrxt) { 5614224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 5615224641Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); 5616224641Stuexen } 5617224641Stuexen } 5618224641Stuexen net->failure_threshold = thlds->spt_pathmaxrxt; 5619224641Stuexen net->pf_threshold = thlds->spt_pathpfthld; 5620224641Stuexen } else { 5621224641Stuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 5622224641Stuexen if (net->dest_state & SCTP_ADDR_PF) { 5623224641Stuexen if ((net->failure_threshold > thlds->spt_pathmaxrxt) || 5624224641Stuexen (net->failure_threshold <= thlds->spt_pathpfthld)) { 5625224641Stuexen net->dest_state &= ~SCTP_ADDR_PF; 5626224641Stuexen } 5627224641Stuexen } else { 5628224641Stuexen if ((net->failure_threshold > thlds->spt_pathpfthld) && 5629224641Stuexen (net->failure_threshold <= thlds->spt_pathmaxrxt)) { 5630224641Stuexen net->dest_state |= SCTP_ADDR_PF; 5631224641Stuexen sctp_send_hb(stcb, net, SCTP_SO_LOCKED); 5632224641Stuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); 5633224641Stuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); 5634224641Stuexen } 5635224641Stuexen } 5636224641Stuexen if (net->dest_state & SCTP_ADDR_REACHABLE) { 5637224641Stuexen if (net->failure_threshold > thlds->spt_pathmaxrxt) { 5638224641Stuexen net->dest_state &= ~SCTP_ADDR_REACHABLE; 5639224641Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); 5640224641Stuexen } 5641224641Stuexen } else { 5642224641Stuexen if (net->failure_threshold <= thlds->spt_pathmaxrxt) { 5643224641Stuexen net->dest_state |= SCTP_ADDR_REACHABLE; 5644224641Stuexen sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, SCTP_RESPONSE_TO_USER_REQ, net, SCTP_SO_LOCKED); 5645224641Stuexen } 5646224641Stuexen } 5647224641Stuexen net->failure_threshold = thlds->spt_pathmaxrxt; 5648224641Stuexen net->pf_threshold = thlds->spt_pathpfthld; 5649224641Stuexen } 5650224641Stuexen stcb->asoc.def_net_failure = thlds->spt_pathmaxrxt; 5651224641Stuexen stcb->asoc.def_net_pf_threshold = thlds->spt_pathpfthld; 5652224641Stuexen } 5653224641Stuexen } else { 5654224918Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5655224918Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5656224918Stuexen (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) { 5657224641Stuexen SCTP_INP_WLOCK(inp); 5658224641Stuexen inp->sctp_ep.def_net_failure = thlds->spt_pathmaxrxt; 5659224641Stuexen inp->sctp_ep.def_net_pf_threshold = thlds->spt_pathpfthld; 5660224641Stuexen SCTP_INP_WUNLOCK(inp); 5661224641Stuexen } else { 5662224641Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5663224641Stuexen error = EINVAL; 5664224641Stuexen } 5665224641Stuexen } 5666224641Stuexen break; 5667224641Stuexen } 5668227755Stuexen case SCTP_REMOTE_UDP_ENCAPS_PORT: 5669227755Stuexen { 5670227755Stuexen struct sctp_udpencaps *encaps; 5671227755Stuexen struct sctp_nets *net; 5672227755Stuexen 5673227755Stuexen SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, optsize); 5674227755Stuexen SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id); 5675227755Stuexen if (stcb) { 5676227755Stuexen net = sctp_findnet(stcb, (struct sockaddr *)&encaps->sue_address); 5677227755Stuexen } else { 5678227755Stuexen /* 5679227755Stuexen * We increment here since 5680227755Stuexen * sctp_findassociation_ep_addr() wil do a 5681227755Stuexen * decrement if it finds the stcb as long as 5682227755Stuexen * the locked tcb (last argument) is NOT a 5683227755Stuexen * TCB.. aka NULL. 5684227755Stuexen */ 5685227755Stuexen net = NULL; 5686227755Stuexen SCTP_INP_INCR_REF(inp); 5687227755Stuexen stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&encaps->sue_address, &net, NULL, NULL); 5688227755Stuexen if (stcb == NULL) { 5689227755Stuexen SCTP_INP_DECR_REF(inp); 5690227755Stuexen } 5691227755Stuexen } 5692227755Stuexen if (stcb && (net == NULL)) { 5693227755Stuexen struct sockaddr *sa; 5694227755Stuexen 5695227755Stuexen sa = (struct sockaddr *)&encaps->sue_address; 5696227755Stuexen#ifdef INET 5697227755Stuexen if (sa->sa_family == AF_INET) { 5698227755Stuexen 5699227755Stuexen struct sockaddr_in *sin; 5700227755Stuexen 5701227755Stuexen sin = (struct sockaddr_in *)sa; 5702227755Stuexen if (sin->sin_addr.s_addr) { 5703227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5704227755Stuexen SCTP_TCB_UNLOCK(stcb); 5705227755Stuexen error = EINVAL; 5706227755Stuexen break; 5707227755Stuexen } 5708227755Stuexen } else 5709227755Stuexen#endif 5710227755Stuexen#ifdef INET6 5711227755Stuexen if (sa->sa_family == AF_INET6) { 5712227755Stuexen struct sockaddr_in6 *sin6; 5713227755Stuexen 5714227755Stuexen sin6 = (struct sockaddr_in6 *)sa; 5715227755Stuexen if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 5716227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5717227755Stuexen SCTP_TCB_UNLOCK(stcb); 5718227755Stuexen error = EINVAL; 5719227755Stuexen break; 5720227755Stuexen } 5721227755Stuexen } else 5722227755Stuexen#endif 5723227755Stuexen { 5724227755Stuexen error = EAFNOSUPPORT; 5725227755Stuexen SCTP_TCB_UNLOCK(stcb); 5726227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 5727227755Stuexen break; 5728227755Stuexen } 5729227755Stuexen } 5730227755Stuexen if (stcb) { 5731227755Stuexen if (net) { 5732227755Stuexen net->port = encaps->sue_port; 5733227755Stuexen } else { 5734227755Stuexen stcb->asoc.port = encaps->sue_port; 5735227755Stuexen } 5736227755Stuexen SCTP_TCB_UNLOCK(stcb); 5737227755Stuexen } else { 5738227755Stuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5739227755Stuexen (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 5740227755Stuexen (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) { 5741227755Stuexen SCTP_INP_WLOCK(inp); 5742227755Stuexen inp->sctp_ep.port = encaps->sue_port; 5743227755Stuexen SCTP_INP_WUNLOCK(inp); 5744227755Stuexen } else { 5745227755Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5746227755Stuexen error = EINVAL; 5747227755Stuexen } 5748227755Stuexen } 5749227755Stuexen break; 5750227755Stuexen } 5751163953Srrs default: 5752171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 5753163953Srrs error = ENOPROTOOPT; 5754163953Srrs break; 5755163953Srrs } /* end switch (opt) */ 5756163953Srrs return (error); 5757163953Srrs} 5758163953Srrs 5759163953Srrsint 5760163953Srrssctp_ctloutput(struct socket *so, struct sockopt *sopt) 5761163953Srrs{ 5762166675Srrs void *optval = NULL; 5763166675Srrs size_t optsize = 0; 5764163953Srrs struct sctp_inpcb *inp; 5765166675Srrs void *p; 5766166675Srrs int error = 0; 5767163953Srrs 5768163953Srrs if (sopt->sopt_level != IPPROTO_SCTP) { 5769163953Srrs /* wrong proto level... send back up to IP */ 5770163953Srrs#ifdef INET6 5771163953Srrs if (INP_CHECK_SOCKAF(so, AF_INET6)) 5772163953Srrs error = ip6_ctloutput(so, sopt); 5773221249Stuexen#endif /* INET6 */ 5774221249Stuexen#if defined(INET) && defined (INET6) 5775163953Srrs else 5776221249Stuexen#endif 5777221249Stuexen#ifdef INET 5778163953Srrs error = ip_ctloutput(so, sopt); 5779221249Stuexen#endif 5780163953Srrs return (error); 5781163953Srrs } 5782233005Stuexen inp = (struct sctp_inpcb *)so->so_pcb; 5783166675Srrs optsize = sopt->sopt_valsize; 5784166675Srrs if (optsize) { 5785170091Srrs SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT); 5786166675Srrs if (optval == NULL) { 5787171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS); 5788163953Srrs return (ENOBUFS); 5789163953Srrs } 5790166675Srrs error = sooptcopyin(sopt, optval, optsize, optsize); 5791163953Srrs if (error) { 5792170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 5793163953Srrs goto out; 5794163953Srrs } 5795163953Srrs } 5796166675Srrs p = (void *)sopt->sopt_td; 5797163953Srrs if (sopt->sopt_dir == SOPT_SET) { 5798166675Srrs error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p); 5799163953Srrs } else if (sopt->sopt_dir == SOPT_GET) { 5800166675Srrs error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p); 5801163953Srrs } else { 5802171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5803163953Srrs error = EINVAL; 5804163953Srrs } 5805166675Srrs if ((error == 0) && (optval != NULL)) { 5806166675Srrs error = sooptcopyout(sopt, optval, optsize); 5807170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 5808166675Srrs } else if (optval != NULL) { 5809170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 5810163953Srrs } 5811163953Srrsout: 5812163953Srrs return (error); 5813163953Srrs} 5814163953Srrs 5815221249Stuexen#ifdef INET 5816163953Srrsstatic int 5817163953Srrssctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p) 5818163953Srrs{ 5819163953Srrs int error = 0; 5820163953Srrs int create_lock_on = 0; 5821167598Srrs uint32_t vrf_id; 5822163953Srrs struct sctp_inpcb *inp; 5823163953Srrs struct sctp_tcb *stcb = NULL; 5824163953Srrs 5825163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 5826233005Stuexen if (inp == NULL) { 5827163953Srrs /* I made the same as TCP since we are not setup? */ 5828171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5829163953Srrs return (ECONNRESET); 5830163953Srrs } 5831171943Srrs if (addr == NULL) { 5832171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5833170056Srrs return EINVAL; 5834171943Srrs } 5835221249Stuexen switch (addr->sa_family) { 5836185435Sbz#ifdef INET6 5837221249Stuexen case AF_INET6: 5838221249Stuexen { 5839221249Stuexen struct sockaddr_in6 *sin6p; 5840185694Srrs 5841221249Stuexen if (addr->sa_len != sizeof(struct sockaddr_in6)) { 5842221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5843221249Stuexen return (EINVAL); 5844221249Stuexen } 5845221249Stuexen sin6p = (struct sockaddr_in6 *)addr; 5846221249Stuexen if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6p->sin6_addr)) != 0) { 5847221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 5848221249Stuexen return (error); 5849221249Stuexen } 5850221249Stuexen break; 5851185435Sbz } 5852185435Sbz#endif 5853221249Stuexen#ifdef INET 5854221249Stuexen case AF_INET: 5855221249Stuexen { 5856221249Stuexen struct sockaddr_in *sinp; 5857185694Srrs 5858221249Stuexen if (addr->sa_len != sizeof(struct sockaddr_in)) { 5859221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5860221249Stuexen return (EINVAL); 5861221249Stuexen } 5862221249Stuexen sinp = (struct sockaddr_in *)addr; 5863221249Stuexen if (p != NULL && (error = prison_remote_ip4(p->td_ucred, &sinp->sin_addr)) != 0) { 5864221249Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 5865221249Stuexen return (error); 5866221249Stuexen } 5867221249Stuexen break; 5868185435Sbz } 5869221249Stuexen#endif 5870221249Stuexen default: 5871185435Sbz SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT); 5872185435Sbz return (EAFNOSUPPORT); 5873170056Srrs } 5874178202Srrs SCTP_INP_INCR_REF(inp); 5875163953Srrs SCTP_ASOC_CREATE_LOCK(inp); 5876163953Srrs create_lock_on = 1; 5877163953Srrs 5878178202Srrs 5879163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 5880163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 5881163953Srrs /* Should I really unlock ? */ 5882171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); 5883163953Srrs error = EFAULT; 5884163953Srrs goto out_now; 5885163953Srrs } 5886163953Srrs#ifdef INET6 5887163953Srrs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 5888163953Srrs (addr->sa_family == AF_INET6)) { 5889171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5890163953Srrs error = EINVAL; 5891163953Srrs goto out_now; 5892163953Srrs } 5893163953Srrs#endif /* INET6 */ 5894163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 5895163953Srrs SCTP_PCB_FLAGS_UNBOUND) { 5896163953Srrs /* Bind a ephemeral port */ 5897171572Srrs error = sctp_inpcb_bind(so, NULL, NULL, p); 5898163953Srrs if (error) { 5899163953Srrs goto out_now; 5900163953Srrs } 5901163953Srrs } 5902163953Srrs /* Now do we connect? */ 5903181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && 5904181054Srrs (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) { 5905171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5906163953Srrs error = EINVAL; 5907163953Srrs goto out_now; 5908163953Srrs } 5909163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 5910163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 5911163953Srrs /* We are already connected AND the TCP model */ 5912171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 5913163953Srrs error = EADDRINUSE; 5914163953Srrs goto out_now; 5915163953Srrs } 5916163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 5917163953Srrs SCTP_INP_RLOCK(inp); 5918163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 5919163953Srrs SCTP_INP_RUNLOCK(inp); 5920163953Srrs } else { 5921163953Srrs /* 5922166675Srrs * We increment here since sctp_findassociation_ep_addr() 5923181054Srrs * will do a decrement if it finds the stcb as long as the 5924166675Srrs * locked tcb (last argument) is NOT a TCB.. aka NULL. 5925163953Srrs */ 5926163953Srrs SCTP_INP_INCR_REF(inp); 5927163953Srrs stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL); 5928163953Srrs if (stcb == NULL) { 5929163953Srrs SCTP_INP_DECR_REF(inp); 5930168299Srrs } else { 5931178202Srrs SCTP_TCB_UNLOCK(stcb); 5932163953Srrs } 5933163953Srrs } 5934163953Srrs if (stcb != NULL) { 5935163953Srrs /* Already have or am bring up an association */ 5936171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 5937163953Srrs error = EALREADY; 5938163953Srrs goto out_now; 5939163953Srrs } 5940168299Srrs vrf_id = inp->def_vrf_id; 5941163953Srrs /* We are GOOD to go */ 5942206137Stuexen stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p); 5943163953Srrs if (stcb == NULL) { 5944163953Srrs /* Gak! no memory */ 5945167598Srrs goto out_now; 5946163953Srrs } 5947163953Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 5948163953Srrs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 5949163953Srrs /* Set the connected flag so we can queue data */ 5950163953Srrs soisconnecting(so); 5951163953Srrs } 5952171943Srrs SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); 5953169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 5954163953Srrs 5955163953Srrs /* initialize authentication parameters for the assoc */ 5956163953Srrs sctp_initialize_auth_params(inp, stcb); 5957163953Srrs 5958172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 5959168299Srrs SCTP_TCB_UNLOCK(stcb); 5960163953Srrsout_now: 5961169420Srrs if (create_lock_on) { 5962163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 5963169420Srrs } 5964163953Srrs SCTP_INP_DECR_REF(inp); 5965228907Stuexen return (error); 5966163953Srrs} 5967163953Srrs 5968221249Stuexen#endif 5969221249Stuexen 5970163953Srrsint 5971163953Srrssctp_listen(struct socket *so, int backlog, struct thread *p) 5972163953Srrs{ 5973163953Srrs /* 5974163953Srrs * Note this module depends on the protocol processing being called 5975163953Srrs * AFTER any socket level flags and backlog are applied to the 5976163953Srrs * socket. The traditional way that the socket flags are applied is 5977163953Srrs * AFTER protocol processing. We have made a change to the 5978163953Srrs * sys/kern/uipc_socket.c module to reverse this but this MUST be in 5979163953Srrs * place if the socket API for SCTP is to work properly. 5980163953Srrs */ 5981163953Srrs 5982163953Srrs int error = 0; 5983163953Srrs struct sctp_inpcb *inp; 5984163953Srrs 5985163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 5986233005Stuexen if (inp == NULL) { 5987163953Srrs /* I made the same as TCP since we are not setup? */ 5988171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 5989163953Srrs return (ECONNRESET); 5990163953Srrs } 5991181054Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) { 5992181054Srrs /* See if we have a listener */ 5993181054Srrs struct sctp_inpcb *tinp; 5994181054Srrs union sctp_sockstore store, *sp; 5995181054Srrs 5996181054Srrs sp = &store; 5997181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { 5998181054Srrs /* not bound all */ 5999181054Srrs struct sctp_laddr *laddr; 6000181054Srrs 6001181054Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 6002181054Srrs memcpy(&store, &laddr->ifa->address, sizeof(store)); 6003221249Stuexen switch (sp->sa.sa_family) { 6004221249Stuexen#ifdef INET 6005221249Stuexen case AF_INET: 6006221249Stuexen sp->sin.sin_port = inp->sctp_lport; 6007221249Stuexen break; 6008221249Stuexen#endif 6009221249Stuexen#ifdef INET6 6010221249Stuexen case AF_INET6: 6011221249Stuexen sp->sin6.sin6_port = inp->sctp_lport; 6012221249Stuexen break; 6013221249Stuexen#endif 6014221249Stuexen default: 6015221249Stuexen break; 6016221249Stuexen } 6017181054Srrs tinp = sctp_pcb_findep(&sp->sa, 0, 0, inp->def_vrf_id); 6018181054Srrs if (tinp && (tinp != inp) && 6019181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && 6020181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 6021181054Srrs (tinp->sctp_socket->so_qlimit)) { 6022181054Srrs /* 6023181054Srrs * we have a listener already and 6024181054Srrs * its not this inp. 6025181054Srrs */ 6026181054Srrs SCTP_INP_DECR_REF(tinp); 6027181054Srrs return (EADDRINUSE); 6028181054Srrs } else if (tinp) { 6029181054Srrs SCTP_INP_DECR_REF(tinp); 6030181054Srrs } 6031181054Srrs } 6032181054Srrs } else { 6033181054Srrs /* Setup a local addr bound all */ 6034181054Srrs memset(&store, 0, sizeof(store)); 6035221249Stuexen switch (sp->sa.sa_family) { 6036221249Stuexen#ifdef INET 6037221249Stuexen case AF_INET: 6038221249Stuexen store.sin.sin_port = inp->sctp_lport; 6039221249Stuexen break; 6040221249Stuexen#endif 6041181054Srrs#ifdef INET6 6042221249Stuexen case AF_INET6: 6043221249Stuexen sp->sin6.sin6_port = inp->sctp_lport; 6044221249Stuexen break; 6045221249Stuexen#endif 6046221249Stuexen default: 6047221249Stuexen break; 6048221249Stuexen } 6049221249Stuexen#ifdef INET6 6050181054Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 6051181054Srrs store.sa.sa_family = AF_INET6; 6052181054Srrs store.sa.sa_len = sizeof(struct sockaddr_in6); 6053181054Srrs } 6054181054Srrs#endif 6055221249Stuexen#ifdef INET 6056181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { 6057181054Srrs store.sa.sa_family = AF_INET; 6058181054Srrs store.sa.sa_len = sizeof(struct sockaddr_in); 6059181054Srrs } 6060221249Stuexen#endif 6061181054Srrs tinp = sctp_pcb_findep(&sp->sa, 0, 0, inp->def_vrf_id); 6062181054Srrs if (tinp && (tinp != inp) && 6063181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && 6064181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 6065181054Srrs (tinp->sctp_socket->so_qlimit)) { 6066181054Srrs /* 6067181054Srrs * we have a listener already and its not 6068181054Srrs * this inp. 6069181054Srrs */ 6070181054Srrs SCTP_INP_DECR_REF(tinp); 6071181054Srrs return (EADDRINUSE); 6072181054Srrs } else if (tinp) { 6073181054Srrs SCTP_INP_DECR_REF(inp); 6074181054Srrs } 6075181054Srrs } 6076181054Srrs } 6077163953Srrs SCTP_INP_RLOCK(inp); 6078163953Srrs#ifdef SCTP_LOCK_LOGGING 6079179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) { 6080170744Srrs sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK); 6081170744Srrs } 6082163953Srrs#endif 6083163953Srrs SOCK_LOCK(so); 6084163953Srrs error = solisten_proto_check(so); 6085163953Srrs if (error) { 6086163953Srrs SOCK_UNLOCK(so); 6087169208Srrs SCTP_INP_RUNLOCK(inp); 6088163953Srrs return (error); 6089163953Srrs } 6090181054Srrs if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) && 6091181054Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 6092181054Srrs /* 6093181054Srrs * The unlucky case - We are in the tcp pool with this guy. 6094181054Srrs * - Someone else is in the main inp slot. - We must move 6095181054Srrs * this guy (the listener) to the main slot - We must then 6096181054Srrs * move the guy that was listener to the TCP Pool. 6097181054Srrs */ 6098181054Srrs if (sctp_swap_inpcb_for_listen(inp)) { 6099181054Srrs goto in_use; 6100181054Srrs } 6101181054Srrs } 6102163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 6103163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 6104163953Srrs /* We are already connected AND the TCP model */ 6105181054Srrsin_use: 6106163953Srrs SCTP_INP_RUNLOCK(inp); 6107163953Srrs SOCK_UNLOCK(so); 6108171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 6109163953Srrs return (EADDRINUSE); 6110163953Srrs } 6111181054Srrs SCTP_INP_RUNLOCK(inp); 6112163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { 6113163953Srrs /* We must do a bind. */ 6114166675Srrs SOCK_UNLOCK(so); 6115171572Srrs if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) { 6116163953Srrs /* bind error, probably perm */ 6117163953Srrs return (error); 6118163953Srrs } 6119166675Srrs SOCK_LOCK(so); 6120163953Srrs } 6121163953Srrs /* It appears for 7.0 and on, we must always call this. */ 6122163953Srrs solisten_proto(so, backlog); 6123163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 6124163953Srrs /* remove the ACCEPTCONN flag for one-to-many sockets */ 6125163953Srrs so->so_options &= ~SO_ACCEPTCONN; 6126163953Srrs } 6127163953Srrs if (backlog == 0) { 6128163953Srrs /* turning off listen */ 6129163953Srrs so->so_options &= ~SO_ACCEPTCONN; 6130163953Srrs } 6131163953Srrs SOCK_UNLOCK(so); 6132163953Srrs return (error); 6133163953Srrs} 6134163953Srrs 6135163953Srrsstatic int sctp_defered_wakeup_cnt = 0; 6136163953Srrs 6137163953Srrsint 6138163953Srrssctp_accept(struct socket *so, struct sockaddr **addr) 6139163953Srrs{ 6140163953Srrs struct sctp_tcb *stcb; 6141163953Srrs struct sctp_inpcb *inp; 6142163953Srrs union sctp_sockstore store; 6143163953Srrs 6144178251Srrs#ifdef INET6 6145163953Srrs int error; 6146163953Srrs 6147178251Srrs#endif 6148163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 6149163953Srrs 6150233005Stuexen if (inp == NULL) { 6151171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6152163953Srrs return (ECONNRESET); 6153163953Srrs } 6154163953Srrs SCTP_INP_RLOCK(inp); 6155163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 6156168299Srrs SCTP_INP_RUNLOCK(inp); 6157171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 6158171943Srrs return (EOPNOTSUPP); 6159163953Srrs } 6160163953Srrs if (so->so_state & SS_ISDISCONNECTED) { 6161163953Srrs SCTP_INP_RUNLOCK(inp); 6162171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED); 6163163953Srrs return (ECONNABORTED); 6164163953Srrs } 6165163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 6166163953Srrs if (stcb == NULL) { 6167163953Srrs SCTP_INP_RUNLOCK(inp); 6168171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6169163953Srrs return (ECONNRESET); 6170163953Srrs } 6171163953Srrs SCTP_TCB_LOCK(stcb); 6172163953Srrs SCTP_INP_RUNLOCK(inp); 6173163953Srrs store = stcb->asoc.primary_destination->ro._l_addr; 6174207924Srrs stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE; 6175163953Srrs SCTP_TCB_UNLOCK(stcb); 6176178251Srrs switch (store.sa.sa_family) { 6177221249Stuexen#ifdef INET 6178178251Srrs case AF_INET: 6179178251Srrs { 6180178251Srrs struct sockaddr_in *sin; 6181163953Srrs 6182178251Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 6183208863Srrs if (sin == NULL) 6184208863Srrs return (ENOMEM); 6185178251Srrs sin->sin_family = AF_INET; 6186178251Srrs sin->sin_len = sizeof(*sin); 6187178251Srrs sin->sin_port = ((struct sockaddr_in *)&store)->sin_port; 6188178251Srrs sin->sin_addr = ((struct sockaddr_in *)&store)->sin_addr; 6189178251Srrs *addr = (struct sockaddr *)sin; 6190178251Srrs break; 6191178251Srrs } 6192221249Stuexen#endif 6193178251Srrs#ifdef INET6 6194178251Srrs case AF_INET6: 6195178251Srrs { 6196178251Srrs struct sockaddr_in6 *sin6; 6197163953Srrs 6198178251Srrs SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); 6199208863Srrs if (sin6 == NULL) 6200208863Srrs return (ENOMEM); 6201178251Srrs sin6->sin6_family = AF_INET6; 6202178251Srrs sin6->sin6_len = sizeof(*sin6); 6203178251Srrs sin6->sin6_port = ((struct sockaddr_in6 *)&store)->sin6_port; 6204163953Srrs 6205178251Srrs sin6->sin6_addr = ((struct sockaddr_in6 *)&store)->sin6_addr; 6206178251Srrs if ((error = sa6_recoverscope(sin6)) != 0) { 6207178251Srrs SCTP_FREE_SONAME(sin6); 6208178251Srrs return (error); 6209178251Srrs } 6210178251Srrs *addr = (struct sockaddr *)sin6; 6211178251Srrs break; 6212164085Srrs } 6213178251Srrs#endif 6214178251Srrs default: 6215178251Srrs /* TSNH */ 6216178251Srrs break; 6217163953Srrs } 6218163953Srrs /* Wake any delayed sleep action */ 6219163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { 6220166086Srrs SCTP_INP_WLOCK(inp); 6221163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE; 6222163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) { 6223163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT; 6224166086Srrs SCTP_INP_WUNLOCK(inp); 6225163953Srrs SOCKBUF_LOCK(&inp->sctp_socket->so_snd); 6226163953Srrs if (sowriteable(inp->sctp_socket)) { 6227163953Srrs sowwakeup_locked(inp->sctp_socket); 6228163953Srrs } else { 6229163953Srrs SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd); 6230163953Srrs } 6231166086Srrs SCTP_INP_WLOCK(inp); 6232163953Srrs } 6233163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) { 6234163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT; 6235166086Srrs SCTP_INP_WUNLOCK(inp); 6236163953Srrs SOCKBUF_LOCK(&inp->sctp_socket->so_rcv); 6237163953Srrs if (soreadable(inp->sctp_socket)) { 6238163953Srrs sctp_defered_wakeup_cnt++; 6239163953Srrs sorwakeup_locked(inp->sctp_socket); 6240163953Srrs } else { 6241163953Srrs SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv); 6242163953Srrs } 6243166086Srrs SCTP_INP_WLOCK(inp); 6244163953Srrs } 6245166086Srrs SCTP_INP_WUNLOCK(inp); 6246163953Srrs } 6247207924Srrs if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 6248207924Srrs SCTP_TCB_LOCK(stcb); 6249207924Srrs sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); 6250207924Srrs } 6251163953Srrs return (0); 6252163953Srrs} 6253163953Srrs 6254221249Stuexen#ifdef INET 6255163953Srrsint 6256163953Srrssctp_ingetaddr(struct socket *so, struct sockaddr **addr) 6257163953Srrs{ 6258163953Srrs struct sockaddr_in *sin; 6259167598Srrs uint32_t vrf_id; 6260163953Srrs struct sctp_inpcb *inp; 6261167695Srrs struct sctp_ifa *sctp_ifa; 6262163953Srrs 6263163953Srrs /* 6264163953Srrs * Do the malloc first in case it blocks. 6265163953Srrs */ 6266163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 6267208863Srrs if (sin == NULL) 6268208863Srrs return (ENOMEM); 6269163953Srrs sin->sin_family = AF_INET; 6270163953Srrs sin->sin_len = sizeof(*sin); 6271163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 6272163953Srrs if (!inp) { 6273163953Srrs SCTP_FREE_SONAME(sin); 6274171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6275228907Stuexen return (ECONNRESET); 6276163953Srrs } 6277163953Srrs SCTP_INP_RLOCK(inp); 6278163953Srrs sin->sin_port = inp->sctp_lport; 6279163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 6280163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 6281163953Srrs struct sctp_tcb *stcb; 6282163953Srrs struct sockaddr_in *sin_a; 6283163953Srrs struct sctp_nets *net; 6284163953Srrs int fnd; 6285163953Srrs 6286163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 6287163953Srrs if (stcb == NULL) { 6288163953Srrs goto notConn; 6289163953Srrs } 6290163953Srrs fnd = 0; 6291163953Srrs sin_a = NULL; 6292163953Srrs SCTP_TCB_LOCK(stcb); 6293163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 6294163953Srrs sin_a = (struct sockaddr_in *)&net->ro._l_addr; 6295164085Srrs if (sin_a == NULL) 6296164085Srrs /* this will make coverity happy */ 6297164085Srrs continue; 6298164085Srrs 6299163953Srrs if (sin_a->sin_family == AF_INET) { 6300163953Srrs fnd = 1; 6301163953Srrs break; 6302163953Srrs } 6303163953Srrs } 6304163953Srrs if ((!fnd) || (sin_a == NULL)) { 6305163953Srrs /* punt */ 6306163953Srrs SCTP_TCB_UNLOCK(stcb); 6307163953Srrs goto notConn; 6308163953Srrs } 6309168299Srrs vrf_id = inp->def_vrf_id; 6310167598Srrs sctp_ifa = sctp_source_address_selection(inp, 6311167598Srrs stcb, 6312168299Srrs (sctp_route_t *) & net->ro, 6313167598Srrs net, 0, vrf_id); 6314167598Srrs if (sctp_ifa) { 6315167598Srrs sin->sin_addr = sctp_ifa->address.sin.sin_addr; 6316167598Srrs sctp_free_ifa(sctp_ifa); 6317167598Srrs } 6318163953Srrs SCTP_TCB_UNLOCK(stcb); 6319163953Srrs } else { 6320163953Srrs /* For the bound all case you get back 0 */ 6321163953Srrs notConn: 6322163953Srrs sin->sin_addr.s_addr = 0; 6323163953Srrs } 6324163953Srrs 6325163953Srrs } else { 6326163953Srrs /* Take the first IPv4 address in the list */ 6327163953Srrs struct sctp_laddr *laddr; 6328163953Srrs int fnd = 0; 6329163953Srrs 6330163953Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 6331167598Srrs if (laddr->ifa->address.sa.sa_family == AF_INET) { 6332163953Srrs struct sockaddr_in *sin_a; 6333163953Srrs 6334167598Srrs sin_a = (struct sockaddr_in *)&laddr->ifa->address.sa; 6335163953Srrs sin->sin_addr = sin_a->sin_addr; 6336163953Srrs fnd = 1; 6337163953Srrs break; 6338163953Srrs } 6339163953Srrs } 6340163953Srrs if (!fnd) { 6341163953Srrs SCTP_FREE_SONAME(sin); 6342163953Srrs SCTP_INP_RUNLOCK(inp); 6343171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 6344228907Stuexen return (ENOENT); 6345163953Srrs } 6346163953Srrs } 6347163953Srrs SCTP_INP_RUNLOCK(inp); 6348163953Srrs (*addr) = (struct sockaddr *)sin; 6349163953Srrs return (0); 6350163953Srrs} 6351163953Srrs 6352163953Srrsint 6353163953Srrssctp_peeraddr(struct socket *so, struct sockaddr **addr) 6354163953Srrs{ 6355231895Stuexen struct sockaddr_in *sin; 6356166086Srrs int fnd; 6357163953Srrs struct sockaddr_in *sin_a; 6358163953Srrs struct sctp_inpcb *inp; 6359163953Srrs struct sctp_tcb *stcb; 6360163953Srrs struct sctp_nets *net; 6361163953Srrs 6362163953Srrs /* Do the malloc first in case it blocks. */ 6363163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 6364208863Srrs if (sin == NULL) 6365208863Srrs return (ENOMEM); 6366163953Srrs sin->sin_family = AF_INET; 6367163953Srrs sin->sin_len = sizeof(*sin); 6368163953Srrs 6369163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 6370228907Stuexen if ((inp == NULL) || 6371228907Stuexen ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { 6372228907Stuexen /* UDP type and listeners will drop out here */ 6373163953Srrs SCTP_FREE_SONAME(sin); 6374228907Stuexen SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 6375228907Stuexen return (ENOTCONN); 6376163953Srrs } 6377163953Srrs SCTP_INP_RLOCK(inp); 6378163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 6379169420Srrs if (stcb) { 6380163953Srrs SCTP_TCB_LOCK(stcb); 6381169420Srrs } 6382163953Srrs SCTP_INP_RUNLOCK(inp); 6383163953Srrs if (stcb == NULL) { 6384163953Srrs SCTP_FREE_SONAME(sin); 6385171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 6386228907Stuexen return (ECONNRESET); 6387163953Srrs } 6388163953Srrs fnd = 0; 6389163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 6390163953Srrs sin_a = (struct sockaddr_in *)&net->ro._l_addr; 6391163953Srrs if (sin_a->sin_family == AF_INET) { 6392163953Srrs fnd = 1; 6393163953Srrs sin->sin_port = stcb->rport; 6394163953Srrs sin->sin_addr = sin_a->sin_addr; 6395163953Srrs break; 6396163953Srrs } 6397163953Srrs } 6398163953Srrs SCTP_TCB_UNLOCK(stcb); 6399163953Srrs if (!fnd) { 6400163953Srrs /* No IPv4 address */ 6401163953Srrs SCTP_FREE_SONAME(sin); 6402171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 6403228907Stuexen return (ENOENT); 6404163953Srrs } 6405163953Srrs (*addr) = (struct sockaddr *)sin; 6406163953Srrs return (0); 6407163953Srrs} 6408163953Srrs 6409221249Stuexen#ifdef INET 6410163953Srrsstruct pr_usrreqs sctp_usrreqs = { 6411163953Srrs .pru_abort = sctp_abort, 6412163953Srrs .pru_accept = sctp_accept, 6413163953Srrs .pru_attach = sctp_attach, 6414163953Srrs .pru_bind = sctp_bind, 6415163953Srrs .pru_connect = sctp_connect, 6416163953Srrs .pru_control = in_control, 6417163953Srrs .pru_close = sctp_close, 6418163953Srrs .pru_detach = sctp_close, 6419163953Srrs .pru_sopoll = sopoll_generic, 6420178202Srrs .pru_flush = sctp_flush, 6421163953Srrs .pru_disconnect = sctp_disconnect, 6422163953Srrs .pru_listen = sctp_listen, 6423163953Srrs .pru_peeraddr = sctp_peeraddr, 6424163953Srrs .pru_send = sctp_sendm, 6425163953Srrs .pru_shutdown = sctp_shutdown, 6426163953Srrs .pru_sockaddr = sctp_ingetaddr, 6427163953Srrs .pru_sosend = sctp_sosend, 6428163953Srrs .pru_soreceive = sctp_soreceive 6429163953Srrs}; 6430221249Stuexen 6431221249Stuexen#endif 6432221249Stuexen#endif 6433