sctp_usrreq.c revision 202520
1163953Srrs/*- 2185694Srrs * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. 3163953Srrs * 4163953Srrs * Redistribution and use in source and binary forms, with or without 5163953Srrs * modification, are permitted provided that the following conditions are met: 6163953Srrs * 7163953Srrs * a) Redistributions of source code must retain the above copyright notice, 8163953Srrs * this list of conditions and the following disclaimer. 9163953Srrs * 10163953Srrs * b) Redistributions in binary form must reproduce the above copyright 11163953Srrs * notice, this list of conditions and the following disclaimer in 12163953Srrs * the documentation and/or other materials provided with the distribution. 13163953Srrs * 14163953Srrs * c) Neither the name of Cisco Systems, Inc. nor the names of its 15163953Srrs * contributors may be used to endorse or promote products derived 16163953Srrs * from this software without specific prior written permission. 17163953Srrs * 18163953Srrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19163953Srrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 20163953Srrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22163953Srrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23163953Srrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24163953Srrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25163953Srrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26163953Srrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27163953Srrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28163953Srrs * THE POSSIBILITY OF SUCH DAMAGE. 29163953Srrs */ 30163953Srrs 31163953Srrs/* $KAME: sctp_usrreq.c,v 1.48 2005/03/07 23:26:08 itojun Exp $ */ 32163953Srrs 33163953Srrs#include <sys/cdefs.h> 34163953Srrs__FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 202520 2010-01-17 19:35:38Z rrs $"); 35166086Srrs#include <netinet/sctp_os.h> 36163953Srrs#include <sys/proc.h> 37163953Srrs#include <netinet/sctp_pcb.h> 38163953Srrs#include <netinet/sctp_header.h> 39163953Srrs#include <netinet/sctp_var.h> 40167695Srrs#if defined(INET6) 41167695Srrs#endif 42167598Srrs#include <netinet/sctp_sysctl.h> 43163953Srrs#include <netinet/sctp_output.h> 44163953Srrs#include <netinet/sctp_uio.h> 45163953Srrs#include <netinet/sctp_asconf.h> 46163953Srrs#include <netinet/sctputil.h> 47163953Srrs#include <netinet/sctp_indata.h> 48163953Srrs#include <netinet/sctp_timer.h> 49163953Srrs#include <netinet/sctp_auth.h> 50170091Srrs#include <netinet/sctp_bsd_addr.h> 51171440Srrs#include <netinet/sctp_cc_functions.h> 52185694Srrs#include <netinet/udp.h> 53164085Srrs 54163953Srrs 55163953Srrs 56170091Srrs 57163953Srrsvoid 58163953Srrssctp_init(void) 59163953Srrs{ 60163953Srrs u_long sb_max_adj; 61163953Srrs 62179783Srrs bzero(&SCTP_BASE_STATS, sizeof(struct sctpstat)); 63163953Srrs 64179783Srrs /* Initialize and modify the sysctled variables */ 65179783Srrs sctp_init_sysctls(); 66163953Srrs if ((nmbclusters / 8) > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE) 67179783Srrs SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue) = (nmbclusters / 8); 68163953Srrs /* 69163953Srrs * Allow a user to take no more than 1/2 the number of clusters or 70163953Srrs * the SB_MAX whichever is smaller for the send window. 71163953Srrs */ 72163953Srrs sb_max_adj = (u_long)((u_quad_t) (SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES)); 73179783Srrs SCTP_BASE_SYSCTL(sctp_sendspace) = min(sb_max_adj, 74170056Srrs (((uint32_t) nmbclusters / 2) * SCTP_DEFAULT_MAXSEGMENT)); 75163953Srrs /* 76163953Srrs * Now for the recv window, should we take the same amount? or 77163953Srrs * should I do 1/2 the SB_MAX instead in the SB_MAX min above. For 78163953Srrs * now I will just copy. 79163953Srrs */ 80179783Srrs SCTP_BASE_SYSCTL(sctp_recvspace) = SCTP_BASE_SYSCTL(sctp_sendspace); 81163953Srrs 82179783Srrs SCTP_BASE_VAR(first_time) = 0; 83179783Srrs SCTP_BASE_VAR(sctp_pcb_initialized) = 0; 84179783Srrs sctp_pcb_init(); 85179783Srrs#if defined(SCTP_PACKET_LOGGING) 86179783Srrs SCTP_BASE_VAR(packet_log_writers) = 0; 87179783Srrs SCTP_BASE_VAR(packet_log_end) = 0; 88179783Srrs bzero(&SCTP_BASE_VAR(packet_log_buffer), SCTP_PACKET_LOG_SIZE); 89179783Srrs#endif 90179783Srrs 91179783Srrs 92163953Srrs} 93163953Srrs 94179783Srrsvoid 95179783Srrssctp_finish(void) 96179783Srrs{ 97179783Srrs sctp_pcb_finish(); 98179783Srrs} 99163953Srrs 100166023Srrs 101163953Srrs 102179157Srrsvoid 103167695Srrssctp_pathmtu_adjustment(struct sctp_inpcb *inp, 104163953Srrs struct sctp_tcb *stcb, 105163953Srrs struct sctp_nets *net, 106163953Srrs uint16_t nxtsz) 107163953Srrs{ 108163953Srrs struct sctp_tmit_chunk *chk; 109197257Stuexen uint16_t overhead; 110163953Srrs 111163953Srrs /* Adjust that too */ 112163953Srrs stcb->asoc.smallest_mtu = nxtsz; 113163953Srrs /* now off to subtract IP_DF flag if needed */ 114169352Srrs#ifdef SCTP_PRINT_FOR_B_AND_M 115169420Srrs SCTP_PRINTF("sctp_pathmtu_adjust called inp:%p stcb:%p net:%p nxtsz:%d\n", 116169352Srrs inp, stcb, net, nxtsz); 117169352Srrs#endif 118197257Stuexen overhead = IP_HDR_SIZE; 119197257Stuexen if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) { 120197257Stuexen overhead += sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); 121197257Stuexen } 122163953Srrs TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) { 123197257Stuexen if ((chk->send_size + overhead) > nxtsz) { 124163953Srrs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 125163953Srrs } 126163953Srrs } 127163953Srrs TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 128197257Stuexen if ((chk->send_size + overhead) > nxtsz) { 129163953Srrs /* 130163953Srrs * For this guy we also mark for immediate resend 131163953Srrs * since we sent to big of chunk 132163953Srrs */ 133163953Srrs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 134190689Srrs if (chk->sent < SCTP_DATAGRAM_RESEND) { 135190689Srrs sctp_flight_size_decrease(chk); 136190689Srrs sctp_total_flight_decrease(stcb, chk); 137190689Srrs } 138163953Srrs if (chk->sent != SCTP_DATAGRAM_RESEND) { 139163953Srrs sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 140163953Srrs } 141163953Srrs chk->sent = SCTP_DATAGRAM_RESEND; 142163953Srrs chk->rec.data.doing_fast_retransmit = 0; 143179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { 144170744Srrs sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU, 145170744Srrs chk->whoTo->flight_size, 146170744Srrs chk->book_size, 147170744Srrs (uintptr_t) chk->whoTo, 148170744Srrs chk->rec.data.TSN_seq); 149170744Srrs } 150163953Srrs /* Clear any time so NO RTT is being done */ 151163953Srrs chk->do_rtt = 0; 152163953Srrs } 153163953Srrs } 154163953Srrs} 155163953Srrs 156163953Srrsstatic void 157163953Srrssctp_notify_mbuf(struct sctp_inpcb *inp, 158163953Srrs struct sctp_tcb *stcb, 159163953Srrs struct sctp_nets *net, 160163953Srrs struct ip *ip, 161163953Srrs struct sctphdr *sh) 162163953Srrs{ 163163953Srrs struct icmp *icmph; 164163953Srrs int totsz, tmr_stopped = 0; 165163953Srrs uint16_t nxtsz; 166163953Srrs 167163953Srrs /* protection */ 168163953Srrs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 169163953Srrs (ip == NULL) || (sh == NULL)) { 170169420Srrs if (stcb != NULL) { 171163953Srrs SCTP_TCB_UNLOCK(stcb); 172169420Srrs } 173163953Srrs return; 174163953Srrs } 175163953Srrs /* First job is to verify the vtag matches what I would send */ 176163953Srrs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 177163953Srrs SCTP_TCB_UNLOCK(stcb); 178163953Srrs return; 179163953Srrs } 180163953Srrs icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) - 181163953Srrs sizeof(struct ip))); 182163953Srrs if (icmph->icmp_type != ICMP_UNREACH) { 183163953Srrs /* We only care about unreachable */ 184163953Srrs SCTP_TCB_UNLOCK(stcb); 185163953Srrs return; 186163953Srrs } 187163953Srrs if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) { 188163953Srrs /* not a unreachable message due to frag. */ 189163953Srrs SCTP_TCB_UNLOCK(stcb); 190163953Srrs return; 191163953Srrs } 192163953Srrs totsz = ip->ip_len; 193163953Srrs 194171943Srrs nxtsz = ntohs(icmph->icmp_nextmtu); 195163953Srrs if (nxtsz == 0) { 196163953Srrs /* 197163953Srrs * old type router that does not tell us what the next size 198163953Srrs * mtu is. Rats we will have to guess (in a educated fashion 199163953Srrs * of course) 200163953Srrs */ 201163953Srrs nxtsz = find_next_best_mtu(totsz); 202163953Srrs } 203163953Srrs /* Stop any PMTU timer */ 204165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 205163953Srrs tmr_stopped = 1; 206165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 207165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1); 208163953Srrs } 209163953Srrs /* Adjust destination size limit */ 210163953Srrs if (net->mtu > nxtsz) { 211163953Srrs net->mtu = nxtsz; 212185694Srrs if (net->port) { 213185694Srrs net->mtu -= sizeof(struct udphdr); 214185694Srrs } 215163953Srrs } 216163953Srrs /* now what about the ep? */ 217163953Srrs if (stcb->asoc.smallest_mtu > nxtsz) { 218169352Srrs#ifdef SCTP_PRINT_FOR_B_AND_M 219169420Srrs SCTP_PRINTF("notify_mbuf (ICMP) calls sctp_pathmtu_adjust mtu:%d\n", 220169352Srrs nxtsz); 221169352Srrs#endif 222167695Srrs sctp_pathmtu_adjustment(inp, stcb, net, nxtsz); 223163953Srrs } 224163953Srrs if (tmr_stopped) 225163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 226163953Srrs 227163953Srrs SCTP_TCB_UNLOCK(stcb); 228163953Srrs} 229163953Srrs 230163953Srrs 231163953Srrsvoid 232163953Srrssctp_notify(struct sctp_inpcb *inp, 233172091Srrs struct ip *ip, 234163953Srrs struct sctphdr *sh, 235163953Srrs struct sockaddr *to, 236163953Srrs struct sctp_tcb *stcb, 237163953Srrs struct sctp_nets *net) 238163953Srrs{ 239172090Srrs#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 240172090Srrs struct socket *so; 241172090Srrs 242172090Srrs#endif 243163953Srrs /* protection */ 244172091Srrs int reason; 245172091Srrs struct icmp *icmph; 246172091Srrs 247172091Srrs 248163953Srrs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 249163953Srrs (sh == NULL) || (to == NULL)) { 250172091Srrs if (stcb) 251172091Srrs SCTP_TCB_UNLOCK(stcb); 252163953Srrs return; 253163953Srrs } 254163953Srrs /* First job is to verify the vtag matches what I would send */ 255163953Srrs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 256172091Srrs SCTP_TCB_UNLOCK(stcb); 257163953Srrs return; 258163953Srrs } 259172091Srrs icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) - 260172091Srrs sizeof(struct ip))); 261172091Srrs if (icmph->icmp_type != ICMP_UNREACH) { 262172091Srrs /* We only care about unreachable */ 263172091Srrs SCTP_TCB_UNLOCK(stcb); 264172091Srrs return; 265172091Srrs } 266172091Srrs if ((icmph->icmp_code == ICMP_UNREACH_NET) || 267172091Srrs (icmph->icmp_code == ICMP_UNREACH_HOST) || 268172091Srrs (icmph->icmp_code == ICMP_UNREACH_NET_UNKNOWN) || 269172091Srrs (icmph->icmp_code == ICMP_UNREACH_HOST_UNKNOWN) || 270172091Srrs (icmph->icmp_code == ICMP_UNREACH_ISOLATED) || 271172091Srrs (icmph->icmp_code == ICMP_UNREACH_NET_PROHIB) || 272172091Srrs (icmph->icmp_code == ICMP_UNREACH_HOST_PROHIB) || 273172091Srrs (icmph->icmp_code == ICMP_UNREACH_FILTER_PROHIB)) { 274163953Srrs 275163953Srrs /* 276163953Srrs * Hmm reachablity problems we must examine closely. If its 277163953Srrs * not reachable, we may have lost a network. Or if there is 278163953Srrs * NO protocol at the other end named SCTP. well we consider 279163953Srrs * it a OOTB abort. 280163953Srrs */ 281172091Srrs if (net->dest_state & SCTP_ADDR_REACHABLE) { 282172091Srrs /* Ok that destination is NOT reachable */ 283172091Srrs SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n", 284172091Srrs net->error_count, 285172091Srrs net->failure_threshold, 286172091Srrs net); 287167598Srrs 288172091Srrs net->dest_state &= ~SCTP_ADDR_REACHABLE; 289172091Srrs net->dest_state |= SCTP_ADDR_NOT_REACHABLE; 290163953Srrs /* 291172091Srrs * JRS 5/14/07 - If a destination is unreachable, 292172091Srrs * the PF bit is turned off. This allows an 293172091Srrs * unambiguous use of the PF bit for destinations 294172091Srrs * that are reachable but potentially failed. If the 295172091Srrs * destination is set to the unreachable state, also 296172091Srrs * set the destination to the PF state. 297163953Srrs */ 298172091Srrs /* 299172091Srrs * Add debug message here if destination is not in 300172091Srrs * PF state. 301172091Srrs */ 302172091Srrs /* Stop any running T3 timers here? */ 303179783Srrs if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_pf)) { 304172091Srrs net->dest_state &= ~SCTP_ADDR_PF; 305172091Srrs SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n", 306172091Srrs net); 307172091Srrs } 308172091Srrs net->error_count = net->failure_threshold + 1; 309172091Srrs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, 310172091Srrs stcb, SCTP_FAILED_THRESHOLD, 311172091Srrs (void *)net, SCTP_SO_NOT_LOCKED); 312172091Srrs } 313172091Srrs SCTP_TCB_UNLOCK(stcb); 314172091Srrs } else if ((icmph->icmp_code == ICMP_UNREACH_PROTOCOL) || 315172091Srrs (icmph->icmp_code == ICMP_UNREACH_PORT)) { 316172091Srrs /* 317172091Srrs * Here the peer is either playing tricks on us, including 318172091Srrs * an address that belongs to someone who does not support 319172091Srrs * SCTP OR was a userland implementation that shutdown and 320172091Srrs * now is dead. In either case treat it like a OOTB abort 321172091Srrs * with no TCB 322172091Srrs */ 323172091Srrs reason = SCTP_PEER_FAULTY; 324172091Srrs sctp_abort_notification(stcb, reason, SCTP_SO_NOT_LOCKED); 325172090Srrs#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 326172091Srrs so = SCTP_INP_SO(inp); 327172091Srrs atomic_add_int(&stcb->asoc.refcnt, 1); 328172091Srrs SCTP_TCB_UNLOCK(stcb); 329172091Srrs SCTP_SOCKET_LOCK(so, 1); 330172091Srrs SCTP_TCB_LOCK(stcb); 331172091Srrs atomic_subtract_int(&stcb->asoc.refcnt, 1); 332172090Srrs#endif 333172091Srrs (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); 334172090Srrs#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 335172091Srrs SCTP_SOCKET_UNLOCK(so, 1); 336172091Srrs /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */ 337172090Srrs#endif 338172091Srrs /* no need to unlock here, since the TCB is gone */ 339163953Srrs } else { 340172091Srrs SCTP_TCB_UNLOCK(stcb); 341163953Srrs } 342163953Srrs} 343163953Srrs 344163953Srrsvoid 345163953Srrssctp_ctlinput(cmd, sa, vip) 346163953Srrs int cmd; 347163953Srrs struct sockaddr *sa; 348163953Srrs void *vip; 349163953Srrs{ 350163953Srrs struct ip *ip = vip; 351163953Srrs struct sctphdr *sh; 352167598Srrs uint32_t vrf_id; 353163953Srrs 354168299Srrs /* FIX, for non-bsd is this right? */ 355167598Srrs vrf_id = SCTP_DEFAULT_VRFID; 356163953Srrs if (sa->sa_family != AF_INET || 357163953Srrs ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) { 358163953Srrs return; 359163953Srrs } 360163953Srrs if (PRC_IS_REDIRECT(cmd)) { 361163953Srrs ip = 0; 362163953Srrs } else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) { 363163953Srrs return; 364163953Srrs } 365163953Srrs if (ip) { 366163953Srrs struct sctp_inpcb *inp = NULL; 367163953Srrs struct sctp_tcb *stcb = NULL; 368163953Srrs struct sctp_nets *net = NULL; 369163953Srrs struct sockaddr_in to, from; 370163953Srrs 371163953Srrs sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 372163953Srrs bzero(&to, sizeof(to)); 373163953Srrs bzero(&from, sizeof(from)); 374163953Srrs from.sin_family = to.sin_family = AF_INET; 375163953Srrs from.sin_len = to.sin_len = sizeof(to); 376163953Srrs from.sin_port = sh->src_port; 377163953Srrs from.sin_addr = ip->ip_src; 378163953Srrs to.sin_port = sh->dest_port; 379163953Srrs to.sin_addr = ip->ip_dst; 380163953Srrs 381163953Srrs /* 382163953Srrs * 'to' holds the dest of the packet that failed to be sent. 383163953Srrs * 'from' holds our local endpoint address. Thus we reverse 384163953Srrs * the to and the from in the lookup. 385163953Srrs */ 386163953Srrs stcb = sctp_findassociation_addr_sa((struct sockaddr *)&from, 387163953Srrs (struct sockaddr *)&to, 388167598Srrs &inp, &net, 1, vrf_id); 389163953Srrs if (stcb != NULL && inp && (inp->sctp_socket != NULL)) { 390163953Srrs if (cmd != PRC_MSGSIZE) { 391172091Srrs sctp_notify(inp, ip, sh, 392163953Srrs (struct sockaddr *)&to, stcb, 393163953Srrs net); 394163953Srrs } else { 395163953Srrs /* handle possible ICMP size messages */ 396163953Srrs sctp_notify_mbuf(inp, stcb, net, ip, sh); 397163953Srrs } 398163953Srrs } else { 399163953Srrs if ((stcb == NULL) && (inp != NULL)) { 400163953Srrs /* reduce ref-count */ 401163953Srrs SCTP_INP_WLOCK(inp); 402163953Srrs SCTP_INP_DECR_REF(inp); 403163953Srrs SCTP_INP_WUNLOCK(inp); 404163953Srrs } 405163953Srrs } 406163953Srrs } 407163953Srrs return; 408163953Srrs} 409163953Srrs 410163953Srrsstatic int 411163953Srrssctp_getcred(SYSCTL_HANDLER_ARGS) 412163953Srrs{ 413164085Srrs struct xucred xuc; 414163953Srrs struct sockaddr_in addrs[2]; 415163953Srrs struct sctp_inpcb *inp; 416163953Srrs struct sctp_nets *net; 417163953Srrs struct sctp_tcb *stcb; 418164085Srrs int error; 419167598Srrs uint32_t vrf_id; 420163953Srrs 421168299Srrs /* FIX, for non-bsd is this right? */ 422167598Srrs vrf_id = SCTP_DEFAULT_VRFID; 423168299Srrs 424170587Srwatson error = priv_check(req->td, PRIV_NETINET_GETCRED); 425170587Srwatson 426163953Srrs if (error) 427163953Srrs return (error); 428164039Srwatson 429163953Srrs error = SYSCTL_IN(req, addrs, sizeof(addrs)); 430163953Srrs if (error) 431163953Srrs return (error); 432163953Srrs 433163953Srrs stcb = sctp_findassociation_addr_sa(sintosa(&addrs[0]), 434163953Srrs sintosa(&addrs[1]), 435167598Srrs &inp, &net, 1, vrf_id); 436163953Srrs if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) { 437163953Srrs if ((inp != NULL) && (stcb == NULL)) { 438163953Srrs /* reduce ref-count */ 439163953Srrs SCTP_INP_WLOCK(inp); 440163953Srrs SCTP_INP_DECR_REF(inp); 441164085Srrs goto cred_can_cont; 442163953Srrs } 443171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 444163953Srrs error = ENOENT; 445163953Srrs goto out; 446163953Srrs } 447163953Srrs SCTP_TCB_UNLOCK(stcb); 448164085Srrs /* 449164085Srrs * We use the write lock here, only since in the error leg we need 450164085Srrs * it. If we used RLOCK, then we would have to 451164085Srrs * wlock/decr/unlock/rlock. Which in theory could create a hole. 452164085Srrs * Better to use higher wlock. 453164085Srrs */ 454164085Srrs SCTP_INP_WLOCK(inp); 455164085Srrscred_can_cont: 456164085Srrs error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket); 457164085Srrs if (error) { 458164085Srrs SCTP_INP_WUNLOCK(inp); 459164085Srrs goto out; 460164085Srrs } 461164085Srrs cru2x(inp->sctp_socket->so_cred, &xuc); 462164085Srrs SCTP_INP_WUNLOCK(inp); 463164085Srrs error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); 464163953Srrsout: 465163953Srrs return (error); 466163953Srrs} 467163953Srrs 468163953SrrsSYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW, 469163953Srrs 0, 0, sctp_getcred, "S,ucred", "Get the ucred of a SCTP connection"); 470163953Srrs 471163953Srrs 472163953Srrsstatic void 473163953Srrssctp_abort(struct socket *so) 474163953Srrs{ 475163953Srrs struct sctp_inpcb *inp; 476163953Srrs uint32_t flags; 477163953Srrs 478163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 479171943Srrs if (inp == 0) { 480163953Srrs return; 481171943Srrs } 482163953Srrssctp_must_try_again: 483163953Srrs flags = inp->sctp_flags; 484163953Srrs#ifdef SCTP_LOG_CLOSING 485163953Srrs sctp_log_closing(inp, NULL, 17); 486163953Srrs#endif 487163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 488163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 489163953Srrs#ifdef SCTP_LOG_CLOSING 490163953Srrs sctp_log_closing(inp, NULL, 16); 491163953Srrs#endif 492169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 493169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 494163953Srrs SOCK_LOCK(so); 495167695Srrs SCTP_SB_CLEAR(so->so_snd); 496163953Srrs /* 497163953Srrs * same for the rcv ones, they are only here for the 498163953Srrs * accounting/select. 499163953Srrs */ 500167695Srrs SCTP_SB_CLEAR(so->so_rcv); 501167695Srrs 502167695Srrs /* Now null out the reference, we are completely detached. */ 503163953Srrs so->so_pcb = NULL; 504163953Srrs SOCK_UNLOCK(so); 505163953Srrs } else { 506163953Srrs flags = inp->sctp_flags; 507163953Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 508163953Srrs goto sctp_must_try_again; 509163953Srrs } 510163953Srrs } 511163953Srrs return; 512163953Srrs} 513163953Srrs 514163953Srrsstatic int 515163953Srrssctp_attach(struct socket *so, int proto, struct thread *p) 516163953Srrs{ 517163953Srrs struct sctp_inpcb *inp; 518163953Srrs struct inpcb *ip_inp; 519166086Srrs int error; 520170205Srrs uint32_t vrf_id = SCTP_DEFAULT_VRFID; 521185694Srrs 522171167Sgnn#ifdef IPSEC 523163953Srrs uint32_t flags; 524185694Srrs 525185435Sbz#endif 526171440Srrs 527163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 528163953Srrs if (inp != 0) { 529171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 530163953Srrs return EINVAL; 531163953Srrs } 532184030Srrs if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 533184030Srrs error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace)); 534184030Srrs if (error) { 535184030Srrs return error; 536184030Srrs } 537163953Srrs } 538170205Srrs error = sctp_inpcb_alloc(so, vrf_id); 539163953Srrs if (error) { 540163953Srrs return error; 541163953Srrs } 542163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 543163953Srrs SCTP_INP_WLOCK(inp); 544163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6; /* I'm not v6! */ 545163953Srrs ip_inp = &inp->ip_inp.inp; 546163953Srrs ip_inp->inp_vflag |= INP_IPV4; 547197288Srrs ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl); 548171167Sgnn#ifdef IPSEC 549171133Sgnn error = ipsec_init_policy(so, &ip_inp->inp_sp); 550163953Srrs#ifdef SCTP_LOG_CLOSING 551163953Srrs sctp_log_closing(inp, NULL, 17); 552163953Srrs#endif 553163953Srrs if (error != 0) { 554163953Srrs flags = inp->sctp_flags; 555163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 556163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 557163953Srrs#ifdef SCTP_LOG_CLOSING 558163953Srrs sctp_log_closing(inp, NULL, 15); 559163953Srrs#endif 560169352Srrs SCTP_INP_WUNLOCK(inp); 561169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 562169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 563169254Srrs } else { 564169352Srrs SCTP_INP_WUNLOCK(inp); 565163953Srrs } 566163953Srrs return error; 567163953Srrs } 568171167Sgnn#endif /* IPSEC */ 569163953Srrs SCTP_INP_WUNLOCK(inp); 570163953Srrs return 0; 571163953Srrs} 572163953Srrs 573163953Srrsstatic int 574163953Srrssctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p) 575163953Srrs{ 576171943Srrs struct sctp_inpcb *inp = NULL; 577166086Srrs int error; 578163953Srrs 579163953Srrs#ifdef INET6 580171943Srrs if (addr && addr->sa_family != AF_INET) { 581163953Srrs /* must be a v4 address! */ 582171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 583163953Srrs return EINVAL; 584171943Srrs } 585163953Srrs#endif /* INET6 */ 586170056Srrs if (addr && (addr->sa_len != sizeof(struct sockaddr_in))) { 587171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 588170056Srrs return EINVAL; 589170056Srrs } 590163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 591171943Srrs if (inp == 0) { 592171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 593163953Srrs return EINVAL; 594171943Srrs } 595171572Srrs error = sctp_inpcb_bind(so, addr, NULL, p); 596163953Srrs return error; 597163953Srrs} 598163953Srrs 599171990Srrsvoid 600163953Srrssctp_close(struct socket *so) 601163953Srrs{ 602163953Srrs struct sctp_inpcb *inp; 603163953Srrs uint32_t flags; 604163953Srrs 605163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 606163953Srrs if (inp == 0) 607163953Srrs return; 608163953Srrs 609163953Srrs /* 610163953Srrs * Inform all the lower layer assoc that we are done. 611163953Srrs */ 612163953Srrssctp_must_try_again: 613163953Srrs flags = inp->sctp_flags; 614163953Srrs#ifdef SCTP_LOG_CLOSING 615163953Srrs sctp_log_closing(inp, NULL, 17); 616163953Srrs#endif 617163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 618163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 619163953Srrs if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || 620163953Srrs (so->so_rcv.sb_cc > 0)) { 621163953Srrs#ifdef SCTP_LOG_CLOSING 622163953Srrs sctp_log_closing(inp, NULL, 13); 623163953Srrs#endif 624169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 625169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 626163953Srrs } else { 627163953Srrs#ifdef SCTP_LOG_CLOSING 628163953Srrs sctp_log_closing(inp, NULL, 14); 629163953Srrs#endif 630169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE, 631169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 632163953Srrs } 633163953Srrs /* 634163953Srrs * The socket is now detached, no matter what the state of 635163953Srrs * the SCTP association. 636163953Srrs */ 637163953Srrs SOCK_LOCK(so); 638167695Srrs SCTP_SB_CLEAR(so->so_snd); 639163953Srrs /* 640163953Srrs * same for the rcv ones, they are only here for the 641163953Srrs * accounting/select. 642163953Srrs */ 643167695Srrs SCTP_SB_CLEAR(so->so_rcv); 644167695Srrs 645167695Srrs /* Now null out the reference, we are completely detached. */ 646163953Srrs so->so_pcb = NULL; 647163953Srrs SOCK_UNLOCK(so); 648163953Srrs } else { 649163953Srrs flags = inp->sctp_flags; 650163953Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 651163953Srrs goto sctp_must_try_again; 652163953Srrs } 653163953Srrs } 654163953Srrs return; 655163953Srrs} 656163953Srrs 657163953Srrs 658163953Srrsint 659163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 660163953Srrs struct mbuf *control, struct thread *p); 661163953Srrs 662163953Srrs 663163953Srrsint 664163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 665163953Srrs struct mbuf *control, struct thread *p) 666163953Srrs{ 667163953Srrs struct sctp_inpcb *inp; 668163953Srrs int error; 669163953Srrs 670163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 671163953Srrs if (inp == 0) { 672163953Srrs if (control) { 673163953Srrs sctp_m_freem(control); 674163953Srrs control = NULL; 675163953Srrs } 676171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 677163953Srrs sctp_m_freem(m); 678163953Srrs return EINVAL; 679163953Srrs } 680163953Srrs /* Got to have an to address if we are NOT a connected socket */ 681163953Srrs if ((addr == NULL) && 682163953Srrs ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) || 683163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)) 684163953Srrs ) { 685163953Srrs goto connected_type; 686163953Srrs } else if (addr == NULL) { 687171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); 688163953Srrs error = EDESTADDRREQ; 689163953Srrs sctp_m_freem(m); 690163953Srrs if (control) { 691163953Srrs sctp_m_freem(control); 692163953Srrs control = NULL; 693163953Srrs } 694163953Srrs return (error); 695163953Srrs } 696163953Srrs#ifdef INET6 697163953Srrs if (addr->sa_family != AF_INET) { 698163953Srrs /* must be a v4 address! */ 699171943Srrs SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); 700163953Srrs sctp_m_freem(m); 701163953Srrs if (control) { 702163953Srrs sctp_m_freem(control); 703163953Srrs control = NULL; 704163953Srrs } 705163953Srrs error = EDESTADDRREQ; 706171943Srrs return EDESTADDRREQ; 707163953Srrs } 708163953Srrs#endif /* INET6 */ 709163953Srrsconnected_type: 710163953Srrs /* now what about control */ 711163953Srrs if (control) { 712163953Srrs if (inp->control) { 713169420Srrs SCTP_PRINTF("huh? control set?\n"); 714163953Srrs sctp_m_freem(inp->control); 715163953Srrs inp->control = NULL; 716163953Srrs } 717163953Srrs inp->control = control; 718163953Srrs } 719163953Srrs /* Place the data */ 720163953Srrs if (inp->pkt) { 721165647Srrs SCTP_BUF_NEXT(inp->pkt_last) = m; 722163953Srrs inp->pkt_last = m; 723163953Srrs } else { 724163953Srrs inp->pkt_last = inp->pkt = m; 725163953Srrs } 726163953Srrs if ( 727163953Srrs /* FreeBSD uses a flag passed */ 728163953Srrs ((flags & PRUS_MORETOCOME) == 0) 729163953Srrs ) { 730163953Srrs /* 731163953Srrs * note with the current version this code will only be used 732163953Srrs * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for 733163953Srrs * re-defining sosend to use the sctp_sosend. One can 734163953Srrs * optionally switch back to this code (by changing back the 735163953Srrs * definitions) but this is not advisable. This code is used 736163953Srrs * by FreeBSD when sending a file with sendfile() though. 737163953Srrs */ 738163953Srrs int ret; 739163953Srrs 740163953Srrs ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags); 741163953Srrs inp->pkt = NULL; 742163953Srrs inp->control = NULL; 743163953Srrs return (ret); 744163953Srrs } else { 745163953Srrs return (0); 746163953Srrs } 747163953Srrs} 748163953Srrs 749171990Srrsint 750163953Srrssctp_disconnect(struct socket *so) 751163953Srrs{ 752163953Srrs struct sctp_inpcb *inp; 753163953Srrs 754163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 755163953Srrs if (inp == NULL) { 756171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 757163953Srrs return (ENOTCONN); 758163953Srrs } 759163953Srrs SCTP_INP_RLOCK(inp); 760171745Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 761171745Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 762199437Stuexen if (LIST_EMPTY(&inp->sctp_asoc_list)) { 763163953Srrs /* No connection */ 764163953Srrs SCTP_INP_RUNLOCK(inp); 765163953Srrs return (0); 766163953Srrs } else { 767163953Srrs struct sctp_association *asoc; 768163953Srrs struct sctp_tcb *stcb; 769163953Srrs 770163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 771163953Srrs if (stcb == NULL) { 772163953Srrs SCTP_INP_RUNLOCK(inp); 773171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 774163953Srrs return (EINVAL); 775163953Srrs } 776163953Srrs SCTP_TCB_LOCK(stcb); 777163953Srrs asoc = &stcb->asoc; 778163953Srrs if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 779163953Srrs /* We are about to be freed, out of here */ 780163953Srrs SCTP_TCB_UNLOCK(stcb); 781163953Srrs SCTP_INP_RUNLOCK(inp); 782163953Srrs return (0); 783163953Srrs } 784163953Srrs if (((so->so_options & SO_LINGER) && 785163953Srrs (so->so_linger == 0)) || 786163953Srrs (so->so_rcv.sb_cc > 0)) { 787163953Srrs if (SCTP_GET_STATE(asoc) != 788163953Srrs SCTP_STATE_COOKIE_WAIT) { 789163953Srrs /* Left with Data unread */ 790163953Srrs struct mbuf *err; 791163953Srrs 792163953Srrs err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_DONTWAIT, 1, MT_DATA); 793163953Srrs if (err) { 794163953Srrs /* 795163953Srrs * Fill in the user 796163953Srrs * initiated abort 797163953Srrs */ 798163953Srrs struct sctp_paramhdr *ph; 799163953Srrs 800163953Srrs ph = mtod(err, struct sctp_paramhdr *); 801165647Srrs SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr); 802163953Srrs ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); 803165647Srrs ph->param_length = htons(SCTP_BUF_LEN(err)); 804163953Srrs } 805172396Srrs#if defined(SCTP_PANIC_ON_ABORT) 806172396Srrs panic("disconnect does an abort"); 807172396Srrs#endif 808172090Srrs sctp_send_abort_tcb(stcb, err, SCTP_SO_LOCKED); 809163953Srrs SCTP_STAT_INCR_COUNTER32(sctps_aborted); 810163953Srrs } 811163953Srrs SCTP_INP_RUNLOCK(inp); 812163953Srrs if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 813163953Srrs (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 814163953Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 815163953Srrs } 816171943Srrs (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3); 817163953Srrs /* No unlock tcb assoc is gone */ 818163953Srrs return (0); 819163953Srrs } 820163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 821163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 822163953Srrs (asoc->stream_queue_cnt == 0)) { 823163953Srrs /* there is nothing queued to send, so done */ 824163953Srrs if (asoc->locked_on_sending) { 825163953Srrs goto abort_anyway; 826163953Srrs } 827166675Srrs if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) && 828166675Srrs (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { 829163953Srrs /* only send SHUTDOWN 1st time thru */ 830163953Srrs sctp_stop_timers_for_shutdown(stcb); 831163953Srrs sctp_send_shutdown(stcb, 832163953Srrs stcb->asoc.primary_destination); 833172090Srrs sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); 834166675Srrs if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 835166675Srrs (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 836166675Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 837166675Srrs } 838171943Srrs SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); 839172703Srrs SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 840163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 841163953Srrs stcb->sctp_ep, stcb, 842163953Srrs asoc->primary_destination); 843163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 844163953Srrs stcb->sctp_ep, stcb, 845163953Srrs asoc->primary_destination); 846163953Srrs } 847163953Srrs } else { 848163953Srrs /* 849163953Srrs * we still got (or just got) data to send, 850163953Srrs * so set SHUTDOWN_PENDING 851163953Srrs */ 852163953Srrs /* 853163953Srrs * XXX sockets draft says that SCTP_EOF 854163953Srrs * should be sent with no data. currently, 855163953Srrs * we will allow user data to be sent first 856163953Srrs * and move to SHUTDOWN-PENDING 857163953Srrs */ 858163953Srrs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 859163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, 860163953Srrs asoc->primary_destination); 861163953Srrs if (asoc->locked_on_sending) { 862163953Srrs /* Locked to send out the data */ 863163953Srrs struct sctp_stream_queue_pending *sp; 864163953Srrs 865163953Srrs sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); 866163953Srrs if (sp == NULL) { 867169420Srrs SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", 868163953Srrs asoc->locked_on_sending->stream_no); 869163953Srrs } else { 870163953Srrs if ((sp->length == 0) && (sp->msg_is_complete == 0)) 871163953Srrs asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; 872163953Srrs } 873163953Srrs } 874163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 875163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 876163953Srrs (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 877163953Srrs struct mbuf *op_err; 878163953Srrs 879163953Srrs abort_anyway: 880163953Srrs op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 881163953Srrs 0, M_DONTWAIT, 1, MT_DATA); 882163953Srrs if (op_err) { 883163953Srrs /* 884163953Srrs * Fill in the user 885163953Srrs * initiated abort 886163953Srrs */ 887163953Srrs struct sctp_paramhdr *ph; 888163953Srrs uint32_t *ippp; 889163953Srrs 890165647Srrs SCTP_BUF_LEN(op_err) = 891163953Srrs (sizeof(struct sctp_paramhdr) + sizeof(uint32_t)); 892163953Srrs ph = mtod(op_err, 893163953Srrs struct sctp_paramhdr *); 894163953Srrs ph->param_type = htons( 895163953Srrs SCTP_CAUSE_USER_INITIATED_ABT); 896165647Srrs ph->param_length = htons(SCTP_BUF_LEN(op_err)); 897163953Srrs ippp = (uint32_t *) (ph + 1); 898165220Srrs *ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4); 899163953Srrs } 900172396Srrs#if defined(SCTP_PANIC_ON_ABORT) 901172396Srrs panic("disconnect does an abort"); 902172396Srrs#endif 903172396Srrs 904165220Srrs stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4; 905172090Srrs sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED); 906163953Srrs SCTP_STAT_INCR_COUNTER32(sctps_aborted); 907163953Srrs if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 908163953Srrs (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 909163953Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 910163953Srrs } 911163953Srrs SCTP_INP_RUNLOCK(inp); 912171943Srrs (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5); 913163953Srrs return (0); 914171990Srrs } else { 915172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); 916163953Srrs } 917163953Srrs } 918188067Srrs soisdisconnecting(so); 919163953Srrs SCTP_TCB_UNLOCK(stcb); 920163953Srrs SCTP_INP_RUNLOCK(inp); 921163953Srrs return (0); 922163953Srrs } 923163953Srrs /* not reached */ 924163953Srrs } else { 925163953Srrs /* UDP model does not support this */ 926163953Srrs SCTP_INP_RUNLOCK(inp); 927171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 928163953Srrs return EOPNOTSUPP; 929163953Srrs } 930163953Srrs} 931163953Srrs 932163953Srrsint 933178202Srrssctp_flush(struct socket *so, int how) 934178202Srrs{ 935178202Srrs /* 936178202Srrs * We will just clear out the values and let subsequent close clear 937178202Srrs * out the data, if any. Note if the user did a shutdown(SHUT_RD) 938178202Srrs * they will not be able to read the data, the socket will block 939178202Srrs * that from happening. 940178202Srrs */ 941178202Srrs if ((how == PRU_FLUSH_RD) || (how == PRU_FLUSH_RDWR)) { 942178202Srrs /* 943178202Srrs * First make sure the sb will be happy, we don't use these 944178202Srrs * except maybe the count 945178202Srrs */ 946178202Srrs so->so_rcv.sb_cc = 0; 947178202Srrs so->so_rcv.sb_mbcnt = 0; 948178202Srrs so->so_rcv.sb_mb = NULL; 949178202Srrs } 950178202Srrs if ((how == PRU_FLUSH_WR) || (how == PRU_FLUSH_RDWR)) { 951178202Srrs /* 952178202Srrs * First make sure the sb will be happy, we don't use these 953178202Srrs * except maybe the count 954178202Srrs */ 955178202Srrs so->so_snd.sb_cc = 0; 956178202Srrs so->so_snd.sb_mbcnt = 0; 957178202Srrs so->so_snd.sb_mb = NULL; 958178202Srrs 959178202Srrs } 960178202Srrs return (0); 961178202Srrs} 962178202Srrs 963178202Srrsint 964163953Srrssctp_shutdown(struct socket *so) 965163953Srrs{ 966163953Srrs struct sctp_inpcb *inp; 967163953Srrs 968163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 969163953Srrs if (inp == 0) { 970171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 971163953Srrs return EINVAL; 972163953Srrs } 973163953Srrs SCTP_INP_RLOCK(inp); 974163953Srrs /* For UDP model this is a invalid call */ 975163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 976163953Srrs /* Restore the flags that the soshutdown took away. */ 977163953Srrs so->so_rcv.sb_state &= ~SBS_CANTRCVMORE; 978163953Srrs /* This proc will wakeup for read and do nothing (I hope) */ 979163953Srrs SCTP_INP_RUNLOCK(inp); 980171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 981163953Srrs return (EOPNOTSUPP); 982163953Srrs } 983163953Srrs /* 984163953Srrs * Ok if we reach here its the TCP model and it is either a SHUT_WR 985163953Srrs * or SHUT_RDWR. This means we put the shutdown flag against it. 986163953Srrs */ 987163953Srrs { 988163953Srrs struct sctp_tcb *stcb; 989163953Srrs struct sctp_association *asoc; 990163953Srrs 991188067Srrs if ((so->so_state & 992188067Srrs (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) { 993188067Srrs SCTP_INP_RUNLOCK(inp); 994188067Srrs return (ENOTCONN); 995188067Srrs } 996163953Srrs socantsendmore(so); 997163953Srrs 998163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 999163953Srrs if (stcb == NULL) { 1000163953Srrs /* 1001163953Srrs * Ok we hit the case that the shutdown call was 1002163953Srrs * made after an abort or something. Nothing to do 1003163953Srrs * now. 1004163953Srrs */ 1005168299Srrs SCTP_INP_RUNLOCK(inp); 1006163953Srrs return (0); 1007163953Srrs } 1008163953Srrs SCTP_TCB_LOCK(stcb); 1009163953Srrs asoc = &stcb->asoc; 1010163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 1011163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 1012163953Srrs (asoc->stream_queue_cnt == 0)) { 1013163953Srrs if (asoc->locked_on_sending) { 1014163953Srrs goto abort_anyway; 1015163953Srrs } 1016163953Srrs /* there is nothing queued to send, so I'm done... */ 1017163953Srrs if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { 1018163953Srrs /* only send SHUTDOWN the first time through */ 1019163953Srrs sctp_stop_timers_for_shutdown(stcb); 1020163953Srrs sctp_send_shutdown(stcb, 1021163953Srrs stcb->asoc.primary_destination); 1022172218Srrs sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); 1023166675Srrs if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 1024166675Srrs (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 1025166675Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 1026166675Srrs } 1027171943Srrs SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); 1028172703Srrs SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); 1029163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 1030163953Srrs stcb->sctp_ep, stcb, 1031163953Srrs asoc->primary_destination); 1032163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 1033163953Srrs stcb->sctp_ep, stcb, 1034163953Srrs asoc->primary_destination); 1035163953Srrs } 1036163953Srrs } else { 1037163953Srrs /* 1038163953Srrs * we still got (or just got) data to send, so set 1039163953Srrs * SHUTDOWN_PENDING 1040163953Srrs */ 1041163953Srrs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 1042163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, 1043163953Srrs asoc->primary_destination); 1044163953Srrs 1045163953Srrs if (asoc->locked_on_sending) { 1046163953Srrs /* Locked to send out the data */ 1047163953Srrs struct sctp_stream_queue_pending *sp; 1048163953Srrs 1049163953Srrs sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); 1050163953Srrs if (sp == NULL) { 1051169420Srrs SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", 1052163953Srrs asoc->locked_on_sending->stream_no); 1053163953Srrs } else { 1054163953Srrs if ((sp->length == 0) && (sp->msg_is_complete == 0)) { 1055163953Srrs asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; 1056163953Srrs } 1057163953Srrs } 1058163953Srrs } 1059163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 1060163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 1061163953Srrs (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 1062163953Srrs struct mbuf *op_err; 1063163953Srrs 1064163953Srrs abort_anyway: 1065163953Srrs op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 1066163953Srrs 0, M_DONTWAIT, 1, MT_DATA); 1067163953Srrs if (op_err) { 1068163953Srrs /* Fill in the user initiated abort */ 1069163953Srrs struct sctp_paramhdr *ph; 1070163953Srrs uint32_t *ippp; 1071163953Srrs 1072165647Srrs SCTP_BUF_LEN(op_err) = 1073163953Srrs sizeof(struct sctp_paramhdr) + sizeof(uint32_t); 1074163953Srrs ph = mtod(op_err, 1075163953Srrs struct sctp_paramhdr *); 1076163953Srrs ph->param_type = htons( 1077163953Srrs SCTP_CAUSE_USER_INITIATED_ABT); 1078165647Srrs ph->param_length = htons(SCTP_BUF_LEN(op_err)); 1079163953Srrs ippp = (uint32_t *) (ph + 1); 1080165220Srrs *ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6); 1081163953Srrs } 1082172396Srrs#if defined(SCTP_PANIC_ON_ABORT) 1083172396Srrs panic("shutdown does an abort"); 1084172396Srrs#endif 1085165220Srrs stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6; 1086163953Srrs sctp_abort_an_association(stcb->sctp_ep, stcb, 1087163953Srrs SCTP_RESPONSE_TO_USER_REQ, 1088172090Srrs op_err, SCTP_SO_LOCKED); 1089163953Srrs goto skip_unlock; 1090171990Srrs } else { 1091172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); 1092163953Srrs } 1093163953Srrs } 1094163953Srrs SCTP_TCB_UNLOCK(stcb); 1095163953Srrs } 1096163953Srrsskip_unlock: 1097163953Srrs SCTP_INP_RUNLOCK(inp); 1098163953Srrs return 0; 1099163953Srrs} 1100163953Srrs 1101163953Srrs/* 1102163953Srrs * copies a "user" presentable address and removes embedded scope, etc. 1103163953Srrs * returns 0 on success, 1 on error 1104163953Srrs */ 1105163953Srrsstatic uint32_t 1106163953Srrssctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa) 1107163953Srrs{ 1108178251Srrs#ifdef INET6 1109163953Srrs struct sockaddr_in6 lsa6; 1110163953Srrs 1111163953Srrs sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa, 1112163953Srrs &lsa6); 1113178251Srrs#endif 1114163953Srrs memcpy(ss, sa, sa->sa_len); 1115163953Srrs return (0); 1116163953Srrs} 1117163953Srrs 1118163953Srrs 1119163953Srrs 1120172091Srrs/* 1121172091Srrs * NOTE: assumes addr lock is held 1122172091Srrs */ 1123166675Srrsstatic size_t 1124168124Srrssctp_fill_up_addresses_vrf(struct sctp_inpcb *inp, 1125163953Srrs struct sctp_tcb *stcb, 1126166675Srrs size_t limit, 1127167598Srrs struct sockaddr_storage *sas, 1128167598Srrs uint32_t vrf_id) 1129163953Srrs{ 1130167598Srrs struct sctp_ifn *sctp_ifn; 1131167598Srrs struct sctp_ifa *sctp_ifa; 1132166675Srrs int loopback_scope, ipv4_local_scope, local_scope, site_scope; 1133166675Srrs size_t actual; 1134163953Srrs int ipv4_addr_legal, ipv6_addr_legal; 1135167598Srrs struct sctp_vrf *vrf; 1136163953Srrs 1137163953Srrs actual = 0; 1138163953Srrs if (limit <= 0) 1139163953Srrs return (actual); 1140163953Srrs 1141163953Srrs if (stcb) { 1142163953Srrs /* Turn on all the appropriate scope */ 1143163953Srrs loopback_scope = stcb->asoc.loopback_scope; 1144163953Srrs ipv4_local_scope = stcb->asoc.ipv4_local_scope; 1145163953Srrs local_scope = stcb->asoc.local_scope; 1146163953Srrs site_scope = stcb->asoc.site_scope; 1147163953Srrs } else { 1148163953Srrs /* Turn on ALL scope, since we look at the EP */ 1149163953Srrs loopback_scope = ipv4_local_scope = local_scope = 1150163953Srrs site_scope = 1; 1151163953Srrs } 1152163953Srrs ipv4_addr_legal = ipv6_addr_legal = 0; 1153163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 1154163953Srrs ipv6_addr_legal = 1; 1155166023Srrs if (SCTP_IPV6_V6ONLY(inp) == 0) { 1156163953Srrs ipv4_addr_legal = 1; 1157163953Srrs } 1158163953Srrs } else { 1159163953Srrs ipv4_addr_legal = 1; 1160163953Srrs } 1161167598Srrs vrf = sctp_find_vrf(vrf_id); 1162167598Srrs if (vrf == NULL) { 1163167598Srrs return (0); 1164167598Srrs } 1165163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1166167598Srrs LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 1167163953Srrs if ((loopback_scope == 0) && 1168167598Srrs SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { 1169163953Srrs /* Skip loopback if loopback_scope not set */ 1170163953Srrs continue; 1171163953Srrs } 1172167598Srrs LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 1173163953Srrs if (stcb) { 1174163953Srrs /* 1175163953Srrs * For the BOUND-ALL case, the list 1176163953Srrs * associated with a TCB is Always 1177163953Srrs * considered a reverse list.. i.e. 1178163953Srrs * it lists addresses that are NOT 1179163953Srrs * part of the association. If this 1180163953Srrs * is one of those we must skip it. 1181163953Srrs */ 1182163953Srrs if (sctp_is_addr_restricted(stcb, 1183167598Srrs sctp_ifa)) { 1184163953Srrs continue; 1185163953Srrs } 1186163953Srrs } 1187178251Srrs switch (sctp_ifa->address.sa.sa_family) { 1188178251Srrs case AF_INET: 1189178251Srrs if (ipv4_addr_legal) { 1190178251Srrs struct sockaddr_in *sin; 1191163953Srrs 1192178251Srrs sin = (struct sockaddr_in *)&sctp_ifa->address.sa; 1193178251Srrs if (sin->sin_addr.s_addr == 0) { 1194178251Srrs /* 1195178251Srrs * we skip 1196178251Srrs * unspecifed 1197178251Srrs * addresses 1198178251Srrs */ 1199178251Srrs continue; 1200178251Srrs } 1201178251Srrs if ((ipv4_local_scope == 0) && 1202178251Srrs (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { 1203178251Srrs continue; 1204178251Srrs } 1205178251Srrs#ifdef INET6 1206178251Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 1207178251Srrs in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas); 1208178251Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1209178251Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6)); 1210178251Srrs actual += sizeof(struct sockaddr_in6); 1211178251Srrs } else { 1212178251Srrs#endif 1213178251Srrs memcpy(sas, sin, sizeof(*sin)); 1214178251Srrs ((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport; 1215178251Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin)); 1216178251Srrs actual += sizeof(*sin); 1217178251Srrs#ifdef INET6 1218178251Srrs } 1219178251Srrs#endif 1220178251Srrs if (actual >= limit) { 1221178251Srrs return (actual); 1222178251Srrs } 1223178251Srrs } else { 1224163953Srrs continue; 1225163953Srrs } 1226178251Srrs break; 1227178251Srrs#ifdef INET6 1228178251Srrs case AF_INET6: 1229178251Srrs if (ipv6_addr_legal) { 1230178251Srrs struct sockaddr_in6 *sin6; 1231163953Srrs 1232178251Srrs sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa; 1233178251Srrs if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 1234178251Srrs /* 1235178251Srrs * we skip 1236178251Srrs * unspecifed 1237178251Srrs * addresses 1238178251Srrs */ 1239163953Srrs continue; 1240178251Srrs } 1241178251Srrs if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 1242178251Srrs if (local_scope == 0) 1243163953Srrs continue; 1244178251Srrs if (sin6->sin6_scope_id == 0) { 1245178251Srrs if (sa6_recoverscope(sin6) != 0) 1246178251Srrs /* 1247178251Srrs * 1248178251Srrs * bad 1249178251Srrs * 1250178251Srrs * li 1251178251Srrs * nk 1252178251Srrs * 1253178251Srrs * loc 1254178251Srrs * al 1255178251Srrs * 1256178251Srrs * add 1257178251Srrs * re 1258178251Srrs * ss 1259178251Srrs * */ 1260178251Srrs continue; 1261178251Srrs } 1262163953Srrs } 1263178251Srrs if ((site_scope == 0) && 1264178251Srrs (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { 1265178251Srrs continue; 1266178251Srrs } 1267178251Srrs memcpy(sas, sin6, sizeof(*sin6)); 1268178251Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1269178251Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6)); 1270178251Srrs actual += sizeof(*sin6); 1271178251Srrs if (actual >= limit) { 1272178251Srrs return (actual); 1273178251Srrs } 1274178251Srrs } else { 1275163953Srrs continue; 1276163953Srrs } 1277178251Srrs break; 1278178251Srrs#endif 1279178251Srrs default: 1280178251Srrs /* TSNH */ 1281178251Srrs break; 1282163953Srrs } 1283163953Srrs } 1284163953Srrs } 1285163953Srrs } else { 1286163953Srrs struct sctp_laddr *laddr; 1287163953Srrs 1288167598Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1289167598Srrs if (stcb) { 1290167598Srrs if (sctp_is_addr_restricted(stcb, laddr->ifa)) { 1291163953Srrs continue; 1292163953Srrs } 1293163953Srrs } 1294167598Srrs if (sctp_fill_user_address(sas, &laddr->ifa->address.sa)) 1295167598Srrs continue; 1296167598Srrs 1297167598Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1298167598Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + 1299167598Srrs laddr->ifa->address.sa.sa_len); 1300167598Srrs actual += laddr->ifa->address.sa.sa_len; 1301167598Srrs if (actual >= limit) { 1302167598Srrs return (actual); 1303163953Srrs } 1304163953Srrs } 1305163953Srrs } 1306163953Srrs return (actual); 1307163953Srrs} 1308163953Srrs 1309168124Srrsstatic size_t 1310168124Srrssctp_fill_up_addresses(struct sctp_inpcb *inp, 1311168124Srrs struct sctp_tcb *stcb, 1312168124Srrs size_t limit, 1313168124Srrs struct sockaddr_storage *sas) 1314168124Srrs{ 1315168124Srrs size_t size = 0; 1316168124Srrs 1317172218Srrs SCTP_IPI_ADDR_RLOCK(); 1318168124Srrs /* fill up addresses for the endpoint's default vrf */ 1319168124Srrs size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas, 1320168124Srrs inp->def_vrf_id); 1321172218Srrs SCTP_IPI_ADDR_RUNLOCK(); 1322168124Srrs return (size); 1323168124Srrs} 1324168124Srrs 1325172091Srrs/* 1326172091Srrs * NOTE: assumes addr lock is held 1327172091Srrs */ 1328163953Srrsstatic int 1329168124Srrssctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) 1330163953Srrs{ 1331163953Srrs int cnt = 0; 1332167598Srrs struct sctp_vrf *vrf = NULL; 1333163953Srrs 1334163953Srrs /* 1335163953Srrs * In both sub-set bound an bound_all cases we return the MAXIMUM 1336163953Srrs * number of addresses that you COULD get. In reality the sub-set 1337163953Srrs * bound may have an exclusion list for a given TCB OR in the 1338163953Srrs * bound-all case a TCB may NOT include the loopback or other 1339163953Srrs * addresses as well. 1340163953Srrs */ 1341167598Srrs vrf = sctp_find_vrf(vrf_id); 1342167598Srrs if (vrf == NULL) { 1343167598Srrs return (0); 1344167598Srrs } 1345163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1346167598Srrs struct sctp_ifn *sctp_ifn; 1347167598Srrs struct sctp_ifa *sctp_ifa; 1348163953Srrs 1349167598Srrs LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 1350167598Srrs LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 1351163953Srrs /* Count them if they are the right type */ 1352167598Srrs if (sctp_ifa->address.sa.sa_family == AF_INET) { 1353178251Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) 1354163953Srrs cnt += sizeof(struct sockaddr_in6); 1355163953Srrs else 1356163953Srrs cnt += sizeof(struct sockaddr_in); 1357163953Srrs 1358167598Srrs } else if (sctp_ifa->address.sa.sa_family == AF_INET6) 1359163953Srrs cnt += sizeof(struct sockaddr_in6); 1360163953Srrs } 1361163953Srrs } 1362163953Srrs } else { 1363163953Srrs struct sctp_laddr *laddr; 1364163953Srrs 1365163953Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1366167598Srrs if (laddr->ifa->address.sa.sa_family == AF_INET) { 1367178251Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) 1368163953Srrs cnt += sizeof(struct sockaddr_in6); 1369163953Srrs else 1370163953Srrs cnt += sizeof(struct sockaddr_in); 1371163953Srrs 1372167598Srrs } else if (laddr->ifa->address.sa.sa_family == AF_INET6) 1373163953Srrs cnt += sizeof(struct sockaddr_in6); 1374163953Srrs } 1375163953Srrs } 1376163953Srrs return (cnt); 1377163953Srrs} 1378163953Srrs 1379168124Srrsstatic int 1380168124Srrssctp_count_max_addresses(struct sctp_inpcb *inp) 1381168124Srrs{ 1382168124Srrs int cnt = 0; 1383166675Srrs 1384172218Srrs SCTP_IPI_ADDR_RLOCK(); 1385168124Srrs /* count addresses for the endpoint's default VRF */ 1386168124Srrs cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id); 1387172218Srrs SCTP_IPI_ADDR_RUNLOCK(); 1388168124Srrs return (cnt); 1389168124Srrs} 1390168124Srrs 1391163953Srrsstatic int 1392166675Srrssctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, 1393166675Srrs size_t optsize, void *p, int delay) 1394163953Srrs{ 1395163953Srrs int error = 0; 1396163953Srrs int creat_lock_on = 0; 1397163953Srrs struct sctp_tcb *stcb = NULL; 1398163953Srrs struct sockaddr *sa; 1399169352Srrs int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr; 1400169352Srrs int added = 0; 1401167598Srrs uint32_t vrf_id; 1402170056Srrs int bad_addresses = 0; 1403167598Srrs sctp_assoc_t *a_id; 1404163953Srrs 1405169420Srrs SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n"); 1406163953Srrs 1407163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 1408163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 1409163953Srrs /* We are already connected AND the TCP model */ 1410171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 1411163953Srrs return (EADDRINUSE); 1412163953Srrs } 1413181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && 1414181054Srrs (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) { 1415171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1416163953Srrs return (EINVAL); 1417163953Srrs } 1418163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 1419163953Srrs SCTP_INP_RLOCK(inp); 1420163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 1421163953Srrs SCTP_INP_RUNLOCK(inp); 1422163953Srrs } 1423163953Srrs if (stcb) { 1424171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 1425163953Srrs return (EALREADY); 1426163953Srrs } 1427163953Srrs SCTP_INP_INCR_REF(inp); 1428163953Srrs SCTP_ASOC_CREATE_LOCK(inp); 1429163953Srrs creat_lock_on = 1; 1430163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 1431163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 1432171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); 1433163953Srrs error = EFAULT; 1434163953Srrs goto out_now; 1435163953Srrs } 1436166675Srrs totaddrp = (int *)optval; 1437163953Srrs totaddr = *totaddrp; 1438163953Srrs sa = (struct sockaddr *)(totaddrp + 1); 1439170056Srrs stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses); 1440170056Srrs if ((stcb != NULL) || bad_addresses) { 1441169352Srrs /* Already have or am bring up an association */ 1442169352Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1443169352Srrs creat_lock_on = 0; 1444170931Srrs if (stcb) 1445170931Srrs SCTP_TCB_UNLOCK(stcb); 1446171943Srrs if (bad_addresses == 0) { 1447171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 1448170056Srrs error = EALREADY; 1449171943Srrs } 1450169352Srrs goto out_now; 1451163953Srrs } 1452163953Srrs#ifdef INET6 1453163953Srrs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 1454163953Srrs (num_v6 > 0)) { 1455163953Srrs error = EINVAL; 1456163953Srrs goto out_now; 1457163953Srrs } 1458163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 1459163953Srrs (num_v4 > 0)) { 1460163953Srrs struct in6pcb *inp6; 1461163953Srrs 1462163953Srrs inp6 = (struct in6pcb *)inp; 1463166023Srrs if (SCTP_IPV6_V6ONLY(inp6)) { 1464163953Srrs /* 1465163953Srrs * if IPV6_V6ONLY flag, ignore connections destined 1466163953Srrs * to a v4 addr or v4-mapped addr 1467163953Srrs */ 1468171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1469163953Srrs error = EINVAL; 1470163953Srrs goto out_now; 1471163953Srrs } 1472163953Srrs } 1473163953Srrs#endif /* INET6 */ 1474163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 1475163953Srrs SCTP_PCB_FLAGS_UNBOUND) { 1476163953Srrs /* Bind a ephemeral port */ 1477171572Srrs error = sctp_inpcb_bind(so, NULL, NULL, p); 1478163953Srrs if (error) { 1479163953Srrs goto out_now; 1480163953Srrs } 1481163953Srrs } 1482167695Srrs /* FIX ME: do we want to pass in a vrf on the connect call? */ 1483167695Srrs vrf_id = inp->def_vrf_id; 1484167695Srrs 1485181054Srrs 1486163953Srrs /* We are GOOD to go */ 1487171531Srrs stcb = sctp_aloc_assoc(inp, sa, 1, &error, 0, vrf_id, 1488171531Srrs (struct thread *)p 1489171531Srrs ); 1490163953Srrs if (stcb == NULL) { 1491163953Srrs /* Gak! no memory */ 1492163953Srrs goto out_now; 1493163953Srrs } 1494171943Srrs SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); 1495163953Srrs /* move to second address */ 1496163953Srrs if (sa->sa_family == AF_INET) 1497163953Srrs sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in)); 1498163953Srrs else 1499163953Srrs sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6)); 1500163953Srrs 1501170056Srrs error = 0; 1502169352Srrs added = sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error); 1503167598Srrs /* Fill in the return id */ 1504170056Srrs if (error) { 1505171943Srrs (void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_12); 1506170056Srrs goto out_now; 1507170056Srrs } 1508167598Srrs a_id = (sctp_assoc_t *) optval; 1509167598Srrs *a_id = sctp_get_associd(stcb); 1510163953Srrs 1511163953Srrs /* initialize authentication parameters for the assoc */ 1512163953Srrs sctp_initialize_auth_params(inp, stcb); 1513163953Srrs 1514163953Srrs if (delay) { 1515163953Srrs /* doing delayed connection */ 1516163953Srrs stcb->asoc.delayed_connection = 1; 1517163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination); 1518163953Srrs } else { 1519169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 1520172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 1521163953Srrs } 1522163953Srrs SCTP_TCB_UNLOCK(stcb); 1523163953Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 1524163953Srrs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 1525163953Srrs /* Set the connected flag so we can queue data */ 1526163953Srrs soisconnecting(so); 1527163953Srrs } 1528163953Srrsout_now: 1529169655Srrs if (creat_lock_on) { 1530163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1531169655Srrs } 1532163953Srrs SCTP_INP_DECR_REF(inp); 1533163953Srrs return error; 1534163953Srrs} 1535163953Srrs 1536169420Srrs#define SCTP_FIND_STCB(inp, stcb, assoc_id) { \ 1537169655Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||\ 1538169655Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { \ 1539166675Srrs SCTP_INP_RLOCK(inp); \ 1540166675Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); \ 1541169655Srrs if (stcb) { \ 1542166675Srrs SCTP_TCB_LOCK(stcb); \ 1543169655Srrs } \ 1544166675Srrs SCTP_INP_RUNLOCK(inp); \ 1545166675Srrs } else if (assoc_id != 0) { \ 1546166675Srrs stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \ 1547166675Srrs if (stcb == NULL) { \ 1548171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \ 1549166675Srrs error = ENOENT; \ 1550166675Srrs break; \ 1551166675Srrs } \ 1552166675Srrs } else { \ 1553166675Srrs stcb = NULL; \ 1554169420Srrs } \ 1555169420Srrs } 1556163953Srrs 1557169420Srrs 1558169420Srrs#define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\ 1559166675Srrs if (size < sizeof(type)) { \ 1560171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); \ 1561166675Srrs error = EINVAL; \ 1562166675Srrs break; \ 1563166675Srrs } else { \ 1564166675Srrs destp = (type *)srcp; \ 1565169420Srrs } \ 1566169420Srrs } 1567163953Srrs 1568163953Srrsstatic int 1569166675Srrssctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, 1570166675Srrs void *p) 1571163953Srrs{ 1572171943Srrs struct sctp_inpcb *inp = NULL; 1573166675Srrs int error, val = 0; 1574163953Srrs struct sctp_tcb *stcb = NULL; 1575163953Srrs 1576166675Srrs if (optval == NULL) { 1577171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1578166675Srrs return (EINVAL); 1579166675Srrs } 1580163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 1581171943Srrs if (inp == 0) { 1582171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1583163953Srrs return EINVAL; 1584171943Srrs } 1585163953Srrs error = 0; 1586163953Srrs 1587166675Srrs switch (optname) { 1588163953Srrs case SCTP_NODELAY: 1589163953Srrs case SCTP_AUTOCLOSE: 1590163953Srrs case SCTP_EXPLICIT_EOR: 1591163953Srrs case SCTP_AUTO_ASCONF: 1592163953Srrs case SCTP_DISABLE_FRAGMENTS: 1593163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 1594163953Srrs case SCTP_USE_EXT_RCVINFO: 1595163953Srrs SCTP_INP_RLOCK(inp); 1596166675Srrs switch (optname) { 1597163953Srrs case SCTP_DISABLE_FRAGMENTS: 1598166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT); 1599163953Srrs break; 1600163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 1601166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4); 1602163953Srrs break; 1603163953Srrs case SCTP_AUTO_ASCONF: 1604171943Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1605171943Srrs /* only valid for bound all sockets */ 1606171943Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); 1607171943Srrs } else { 1608171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1609171943Srrs error = EINVAL; 1610171943Srrs goto flags_out; 1611171943Srrs } 1612163953Srrs break; 1613163953Srrs case SCTP_EXPLICIT_EOR: 1614166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); 1615163953Srrs break; 1616163953Srrs case SCTP_NODELAY: 1617166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY); 1618163953Srrs break; 1619163953Srrs case SCTP_USE_EXT_RCVINFO: 1620166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO); 1621163953Srrs break; 1622163953Srrs case SCTP_AUTOCLOSE: 1623163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) 1624166675Srrs val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time); 1625163953Srrs else 1626166675Srrs val = 0; 1627163953Srrs break; 1628163953Srrs 1629163953Srrs default: 1630171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 1631163953Srrs error = ENOPROTOOPT; 1632163953Srrs } /* end switch (sopt->sopt_name) */ 1633166675Srrs if (optname != SCTP_AUTOCLOSE) { 1634163953Srrs /* make it an "on/off" value */ 1635166675Srrs val = (val != 0); 1636163953Srrs } 1637166675Srrs if (*optsize < sizeof(val)) { 1638171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 1639163953Srrs error = EINVAL; 1640163953Srrs } 1641171943Srrsflags_out: 1642163953Srrs SCTP_INP_RUNLOCK(inp); 1643163953Srrs if (error == 0) { 1644163953Srrs /* return the option value */ 1645166675Srrs *(int *)optval = val; 1646166675Srrs *optsize = sizeof(val); 1647163953Srrs } 1648163953Srrs break; 1649170091Srrs case SCTP_GET_PACKET_LOG: 1650170091Srrs { 1651170091Srrs#ifdef SCTP_PACKET_LOGGING 1652170091Srrs uint8_t *target; 1653170091Srrs int ret; 1654167598Srrs 1655170091Srrs SCTP_CHECK_AND_CAST(target, optval, uint8_t, *optsize); 1656170091Srrs ret = sctp_copy_out_packet_log(target, (int)*optsize); 1657170091Srrs *optsize = ret; 1658170091Srrs#else 1659171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 1660170091Srrs error = EOPNOTSUPP; 1661170091Srrs#endif 1662170091Srrs break; 1663170091Srrs } 1664181054Srrs case SCTP_REUSE_PORT: 1665181054Srrs { 1666181054Srrs uint32_t *value; 1667181054Srrs 1668181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) { 1669181054Srrs /* Can't do this for a 1-m socket */ 1670181054Srrs error = EINVAL; 1671181054Srrs break; 1672181054Srrs } 1673181054Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1674181054Srrs *value = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE); 1675181054Srrs *optsize = sizeof(uint32_t); 1676181054Srrs } 1677181054Srrs break; 1678163953Srrs case SCTP_PARTIAL_DELIVERY_POINT: 1679163953Srrs { 1680166675Srrs uint32_t *value; 1681166675Srrs 1682166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1683166675Srrs *value = inp->partial_delivery_point; 1684166675Srrs *optsize = sizeof(uint32_t); 1685163953Srrs } 1686163953Srrs break; 1687163953Srrs case SCTP_FRAGMENT_INTERLEAVE: 1688163953Srrs { 1689166675Srrs uint32_t *value; 1690166675Srrs 1691166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1692168943Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) { 1693168943Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) { 1694168943Srrs *value = SCTP_FRAG_LEVEL_2; 1695168943Srrs } else { 1696168943Srrs *value = SCTP_FRAG_LEVEL_1; 1697168943Srrs } 1698168943Srrs } else { 1699168943Srrs *value = SCTP_FRAG_LEVEL_0; 1700168943Srrs } 1701166675Srrs *optsize = sizeof(uint32_t); 1702163953Srrs } 1703163953Srrs break; 1704163953Srrs case SCTP_CMT_ON_OFF: 1705163953Srrs { 1706166675Srrs struct sctp_assoc_value *av; 1707166675Srrs 1708166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1709179783Srrs if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { 1710166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1711166675Srrs if (stcb) { 1712166675Srrs av->assoc_value = stcb->asoc.sctp_cmt_on_off; 1713166675Srrs SCTP_TCB_UNLOCK(stcb); 1714166675Srrs 1715166675Srrs } else { 1716171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 1717166675Srrs error = ENOTCONN; 1718166675Srrs } 1719166675Srrs } else { 1720171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 1721166675Srrs error = ENOPROTOOPT; 1722163953Srrs } 1723166675Srrs *optsize = sizeof(*av); 1724163953Srrs } 1725163953Srrs break; 1726185694Srrs /* EY - set socket option for nr_sacks */ 1727185694Srrs case SCTP_NR_SACK_ON_OFF: 1728185694Srrs { 1729185694Srrs struct sctp_assoc_value *av; 1730185694Srrs 1731185694Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1732185694Srrs if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off)) { 1733185694Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1734185694Srrs if (stcb) { 1735185694Srrs av->assoc_value = stcb->asoc.sctp_nr_sack_on_off; 1736185694Srrs SCTP_TCB_UNLOCK(stcb); 1737185694Srrs 1738185694Srrs } else { 1739185694Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 1740185694Srrs error = ENOTCONN; 1741185694Srrs } 1742185694Srrs } else { 1743185694Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 1744185694Srrs error = ENOPROTOOPT; 1745185694Srrs } 1746185694Srrs *optsize = sizeof(*av); 1747185694Srrs } 1748185694Srrs break; 1749171440Srrs /* JRS - Get socket option for pluggable congestion control */ 1750171440Srrs case SCTP_PLUGGABLE_CC: 1751171440Srrs { 1752171440Srrs struct sctp_assoc_value *av; 1753171440Srrs 1754171440Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1755171440Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1756171440Srrs if (stcb) { 1757171440Srrs av->assoc_value = stcb->asoc.congestion_control_module; 1758171440Srrs SCTP_TCB_UNLOCK(stcb); 1759171440Srrs } else { 1760171440Srrs av->assoc_value = inp->sctp_ep.sctp_default_cc_module; 1761171440Srrs } 1762171440Srrs *optsize = sizeof(*av); 1763171440Srrs } 1764171440Srrs break; 1765163953Srrs case SCTP_GET_ADDR_LEN: 1766163953Srrs { 1767163953Srrs struct sctp_assoc_value *av; 1768163953Srrs 1769166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1770163953Srrs error = EINVAL; 1771167598Srrs#ifdef INET 1772163953Srrs if (av->assoc_value == AF_INET) { 1773163953Srrs av->assoc_value = sizeof(struct sockaddr_in); 1774163953Srrs error = 0; 1775163953Srrs } 1776163953Srrs#endif 1777167598Srrs#ifdef INET6 1778163953Srrs if (av->assoc_value == AF_INET6) { 1779163953Srrs av->assoc_value = sizeof(struct sockaddr_in6); 1780163953Srrs error = 0; 1781163953Srrs } 1782163953Srrs#endif 1783172091Srrs if (error) { 1784171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1785172091Srrs } 1786166675Srrs *optsize = sizeof(*av); 1787163953Srrs } 1788163953Srrs break; 1789169655Srrs case SCTP_GET_ASSOC_NUMBER: 1790163953Srrs { 1791169655Srrs uint32_t *value, cnt; 1792163953Srrs 1793169655Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1794163953Srrs cnt = 0; 1795163953Srrs SCTP_INP_RLOCK(inp); 1796169655Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 1797169655Srrs cnt++; 1798163953Srrs } 1799169655Srrs SCTP_INP_RUNLOCK(inp); 1800169655Srrs *value = cnt; 1801169655Srrs *optsize = sizeof(uint32_t); 1802169655Srrs } 1803169655Srrs break; 1804163953Srrs 1805169655Srrs case SCTP_GET_ASSOC_ID_LIST: 1806169655Srrs { 1807169655Srrs struct sctp_assoc_ids *ids; 1808169655Srrs unsigned int at, limit; 1809169655Srrs 1810169655Srrs SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize); 1811163953Srrs at = 0; 1812185694Srrs limit = (*optsize - sizeof(uint32_t)) / sizeof(sctp_assoc_t); 1813169655Srrs SCTP_INP_RLOCK(inp); 1814169655Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 1815169655Srrs if (at < limit) { 1816169655Srrs ids->gaids_assoc_id[at++] = sctp_get_associd(stcb); 1817169655Srrs } else { 1818169655Srrs error = EINVAL; 1819171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1820163953Srrs break; 1821163953Srrs } 1822163953Srrs } 1823163953Srrs SCTP_INP_RUNLOCK(inp); 1824185694Srrs ids->gaids_number_of_ids = at; 1825185694Srrs *optsize = ((at * sizeof(sctp_assoc_t)) + sizeof(uint32_t)); 1826163953Srrs } 1827163953Srrs break; 1828163953Srrs case SCTP_CONTEXT: 1829163953Srrs { 1830163953Srrs struct sctp_assoc_value *av; 1831163953Srrs 1832166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1833166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1834166675Srrs 1835166675Srrs if (stcb) { 1836166675Srrs av->assoc_value = stcb->asoc.context; 1837166675Srrs SCTP_TCB_UNLOCK(stcb); 1838163953Srrs } else { 1839166675Srrs SCTP_INP_RLOCK(inp); 1840163953Srrs av->assoc_value = inp->sctp_context; 1841166675Srrs SCTP_INP_RUNLOCK(inp); 1842163953Srrs } 1843166675Srrs *optsize = sizeof(*av); 1844163953Srrs } 1845163953Srrs break; 1846167598Srrs case SCTP_VRF_ID: 1847167598Srrs { 1848170056Srrs uint32_t *default_vrfid; 1849167598Srrs 1850170056Srrs SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize); 1851170056Srrs *default_vrfid = inp->def_vrf_id; 1852167598Srrs break; 1853167598Srrs } 1854167598Srrs case SCTP_GET_ASOC_VRF: 1855167598Srrs { 1856167598Srrs struct sctp_assoc_value *id; 1857167598Srrs 1858167598Srrs SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize); 1859167598Srrs SCTP_FIND_STCB(inp, stcb, id->assoc_id); 1860167598Srrs if (stcb == NULL) { 1861167598Srrs error = EINVAL; 1862171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 1863167598Srrs break; 1864167598Srrs } 1865167598Srrs id->assoc_value = stcb->asoc.vrf_id; 1866167598Srrs break; 1867167598Srrs } 1868167598Srrs case SCTP_GET_VRF_IDS: 1869167598Srrs { 1870171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 1871167598Srrs error = EOPNOTSUPP; 1872167598Srrs break; 1873167598Srrs } 1874163953Srrs case SCTP_GET_NONCE_VALUES: 1875163953Srrs { 1876163953Srrs struct sctp_get_nonce_values *gnv; 1877163953Srrs 1878166675Srrs SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize); 1879166675Srrs SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id); 1880166675Srrs 1881166675Srrs if (stcb) { 1882163953Srrs gnv->gn_peers_tag = stcb->asoc.peer_vtag; 1883163953Srrs gnv->gn_local_tag = stcb->asoc.my_vtag; 1884163953Srrs SCTP_TCB_UNLOCK(stcb); 1885166675Srrs } else { 1886171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 1887166675Srrs error = ENOTCONN; 1888163953Srrs } 1889166675Srrs *optsize = sizeof(*gnv); 1890163953Srrs } 1891163953Srrs break; 1892170056Srrs case SCTP_DELAYED_SACK: 1893163953Srrs { 1894170056Srrs struct sctp_sack_info *sack; 1895163953Srrs 1896170056Srrs SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, *optsize); 1897170056Srrs SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); 1898166675Srrs if (stcb) { 1899170056Srrs sack->sack_delay = stcb->asoc.delayed_ack; 1900170056Srrs sack->sack_freq = stcb->asoc.sack_freq; 1901166675Srrs SCTP_TCB_UNLOCK(stcb); 1902166675Srrs } else { 1903163953Srrs SCTP_INP_RLOCK(inp); 1904170056Srrs sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); 1905170056Srrs sack->sack_freq = inp->sctp_ep.sctp_sack_freq; 1906163953Srrs SCTP_INP_RUNLOCK(inp); 1907163953Srrs } 1908170056Srrs *optsize = sizeof(*sack); 1909163953Srrs } 1910163953Srrs break; 1911163953Srrs 1912163953Srrs case SCTP_GET_SNDBUF_USE: 1913166675Srrs { 1914163953Srrs struct sctp_sockstat *ss; 1915163953Srrs 1916166675Srrs SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize); 1917166675Srrs SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id); 1918166675Srrs 1919166675Srrs if (stcb) { 1920166675Srrs ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size; 1921166675Srrs ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue + 1922166675Srrs stcb->asoc.size_on_all_streams); 1923166675Srrs SCTP_TCB_UNLOCK(stcb); 1924166675Srrs } else { 1925171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 1926163953Srrs error = ENOTCONN; 1927163953Srrs } 1928166675Srrs *optsize = sizeof(struct sctp_sockstat); 1929163953Srrs } 1930163953Srrs break; 1931170056Srrs case SCTP_MAX_BURST: 1932163953Srrs { 1933166675Srrs uint8_t *value; 1934163953Srrs 1935166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint8_t, *optsize); 1936166675Srrs 1937163953Srrs SCTP_INP_RLOCK(inp); 1938166675Srrs *value = inp->sctp_ep.max_burst; 1939163953Srrs SCTP_INP_RUNLOCK(inp); 1940166675Srrs *optsize = sizeof(uint8_t); 1941163953Srrs } 1942163953Srrs break; 1943163953Srrs case SCTP_MAXSEG: 1944163953Srrs { 1945167598Srrs struct sctp_assoc_value *av; 1946163953Srrs int ovh; 1947163953Srrs 1948167598Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1949170056Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1950163953Srrs 1951167598Srrs if (stcb) { 1952167598Srrs av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc); 1953167598Srrs SCTP_TCB_UNLOCK(stcb); 1954163953Srrs } else { 1955167598Srrs SCTP_INP_RLOCK(inp); 1956167598Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 1957167598Srrs ovh = SCTP_MED_OVERHEAD; 1958167598Srrs } else { 1959167598Srrs ovh = SCTP_MED_V4_OVERHEAD; 1960167598Srrs } 1961170056Srrs if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT) 1962170056Srrs av->assoc_value = 0; 1963170056Srrs else 1964170056Srrs av->assoc_value = inp->sctp_frag_point - ovh; 1965167598Srrs SCTP_INP_RUNLOCK(inp); 1966163953Srrs } 1967167598Srrs *optsize = sizeof(struct sctp_assoc_value); 1968163953Srrs } 1969163953Srrs break; 1970163953Srrs case SCTP_GET_STAT_LOG: 1971167598Srrs error = sctp_fill_stat_log(optval, optsize); 1972163953Srrs break; 1973163953Srrs case SCTP_EVENTS: 1974163953Srrs { 1975163953Srrs struct sctp_event_subscribe *events; 1976163953Srrs 1977166675Srrs SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize); 1978163953Srrs memset(events, 0, sizeof(*events)); 1979163953Srrs SCTP_INP_RLOCK(inp); 1980163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) 1981163953Srrs events->sctp_data_io_event = 1; 1982163953Srrs 1983163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT)) 1984163953Srrs events->sctp_association_event = 1; 1985163953Srrs 1986163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT)) 1987163953Srrs events->sctp_address_event = 1; 1988163953Srrs 1989163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) 1990163953Srrs events->sctp_send_failure_event = 1; 1991163953Srrs 1992163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR)) 1993163953Srrs events->sctp_peer_error_event = 1; 1994163953Srrs 1995163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) 1996163953Srrs events->sctp_shutdown_event = 1; 1997163953Srrs 1998163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT)) 1999163953Srrs events->sctp_partial_delivery_event = 1; 2000163953Srrs 2001163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) 2002163953Srrs events->sctp_adaptation_layer_event = 1; 2003163953Srrs 2004163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT)) 2005163953Srrs events->sctp_authentication_event = 1; 2006163953Srrs 2007185694Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT)) 2008185694Srrs events->sctp_sender_dry_event = 1; 2009185694Srrs 2010163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) 2011202520Srrs events->sctp_stream_reset_event = 1; 2012163953Srrs SCTP_INP_RUNLOCK(inp); 2013166675Srrs *optsize = sizeof(struct sctp_event_subscribe); 2014163953Srrs } 2015163953Srrs break; 2016163953Srrs 2017163953Srrs case SCTP_ADAPTATION_LAYER: 2018166675Srrs { 2019166675Srrs uint32_t *value; 2020166675Srrs 2021166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2022166675Srrs 2023166675Srrs SCTP_INP_RLOCK(inp); 2024166675Srrs *value = inp->sctp_ep.adaptation_layer_indicator; 2025166675Srrs SCTP_INP_RUNLOCK(inp); 2026166675Srrs *optsize = sizeof(uint32_t); 2027163953Srrs } 2028163953Srrs break; 2029163953Srrs case SCTP_SET_INITIAL_DBG_SEQ: 2030166675Srrs { 2031166675Srrs uint32_t *value; 2032166675Srrs 2033166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2034166675Srrs SCTP_INP_RLOCK(inp); 2035166675Srrs *value = inp->sctp_ep.initial_sequence_debug; 2036166675Srrs SCTP_INP_RUNLOCK(inp); 2037166675Srrs *optsize = sizeof(uint32_t); 2038163953Srrs } 2039163953Srrs break; 2040163953Srrs case SCTP_GET_LOCAL_ADDR_SIZE: 2041166675Srrs { 2042166675Srrs uint32_t *value; 2043166675Srrs 2044166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2045166675Srrs SCTP_INP_RLOCK(inp); 2046168124Srrs *value = sctp_count_max_addresses(inp); 2047166675Srrs SCTP_INP_RUNLOCK(inp); 2048166675Srrs *optsize = sizeof(uint32_t); 2049163953Srrs } 2050163953Srrs break; 2051163953Srrs case SCTP_GET_REMOTE_ADDR_SIZE: 2052163953Srrs { 2053166675Srrs uint32_t *value; 2054166675Srrs size_t size; 2055163953Srrs struct sctp_nets *net; 2056163953Srrs 2057166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 2058166675Srrs /* FIXME MT: change to sctp_assoc_value? */ 2059166675Srrs SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value); 2060166675Srrs 2061166675Srrs if (stcb) { 2062166675Srrs size = 0; 2063166675Srrs /* Count the sizes */ 2064166675Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 2065178251Srrs if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) || 2066166675Srrs (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET6)) { 2067166675Srrs size += sizeof(struct sockaddr_in6); 2068166675Srrs } else if (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET) { 2069166675Srrs size += sizeof(struct sockaddr_in); 2070166675Srrs } else { 2071166675Srrs /* huh */ 2072166675Srrs break; 2073166675Srrs } 2074163953Srrs } 2075166675Srrs SCTP_TCB_UNLOCK(stcb); 2076166675Srrs *value = (uint32_t) size; 2077166675Srrs } else { 2078171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 2079166675Srrs error = ENOTCONN; 2080163953Srrs } 2081166675Srrs *optsize = sizeof(uint32_t); 2082163953Srrs } 2083163953Srrs break; 2084163953Srrs case SCTP_GET_PEER_ADDRESSES: 2085163953Srrs /* 2086163953Srrs * Get the address information, an array is passed in to 2087163953Srrs * fill up we pack it. 2088163953Srrs */ 2089163953Srrs { 2090166675Srrs size_t cpsz, left; 2091163953Srrs struct sockaddr_storage *sas; 2092163953Srrs struct sctp_nets *net; 2093163953Srrs struct sctp_getaddresses *saddr; 2094163953Srrs 2095166675Srrs SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); 2096166675Srrs SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); 2097163953Srrs 2098166675Srrs if (stcb) { 2099166675Srrs left = (*optsize) - sizeof(struct sctp_getaddresses); 2100166675Srrs *optsize = sizeof(struct sctp_getaddresses); 2101166675Srrs sas = (struct sockaddr_storage *)&saddr->addr[0]; 2102166675Srrs 2103166675Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 2104178251Srrs if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) || 2105166675Srrs (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET6)) { 2106166675Srrs cpsz = sizeof(struct sockaddr_in6); 2107166675Srrs } else if (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET) { 2108166675Srrs cpsz = sizeof(struct sockaddr_in); 2109166675Srrs } else { 2110166675Srrs /* huh */ 2111166675Srrs break; 2112166675Srrs } 2113166675Srrs if (left < cpsz) { 2114166675Srrs /* not enough room. */ 2115166675Srrs break; 2116166675Srrs } 2117178251Srrs#ifdef INET6 2118178251Srrs if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) && 2119166675Srrs (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET)) { 2120166675Srrs /* Must map the address */ 2121166675Srrs in6_sin_2_v4mapsin6((struct sockaddr_in *)&net->ro._l_addr, 2122166675Srrs (struct sockaddr_in6 *)sas); 2123166675Srrs } else { 2124178251Srrs#endif 2125166675Srrs memcpy(sas, &net->ro._l_addr, cpsz); 2126178251Srrs#ifdef INET6 2127166675Srrs } 2128178251Srrs#endif 2129166675Srrs ((struct sockaddr_in *)sas)->sin_port = stcb->rport; 2130166675Srrs 2131166675Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz); 2132166675Srrs left -= cpsz; 2133166675Srrs *optsize += cpsz; 2134163953Srrs } 2135166675Srrs SCTP_TCB_UNLOCK(stcb); 2136166675Srrs } else { 2137171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 2138166675Srrs error = ENOENT; 2139163953Srrs } 2140163953Srrs } 2141163953Srrs break; 2142163953Srrs case SCTP_GET_LOCAL_ADDRESSES: 2143163953Srrs { 2144166675Srrs size_t limit, actual; 2145163953Srrs struct sockaddr_storage *sas; 2146163953Srrs struct sctp_getaddresses *saddr; 2147163953Srrs 2148166675Srrs SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); 2149166675Srrs SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); 2150163953Srrs 2151163953Srrs sas = (struct sockaddr_storage *)&saddr->addr[0]; 2152166675Srrs limit = *optsize - sizeof(sctp_assoc_t); 2153168124Srrs actual = sctp_fill_up_addresses(inp, stcb, limit, sas); 2154169655Srrs if (stcb) { 2155163953Srrs SCTP_TCB_UNLOCK(stcb); 2156169655Srrs } 2157166675Srrs *optsize = sizeof(struct sockaddr_storage) + actual; 2158163953Srrs } 2159163953Srrs break; 2160163953Srrs case SCTP_PEER_ADDR_PARAMS: 2161163953Srrs { 2162163953Srrs struct sctp_paddrparams *paddrp; 2163163953Srrs struct sctp_nets *net; 2164163953Srrs 2165166675Srrs SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize); 2166166675Srrs SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); 2167163953Srrs 2168163953Srrs net = NULL; 2169166675Srrs if (stcb) { 2170166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address); 2171166675Srrs } else { 2172166675Srrs /* 2173166675Srrs * We increment here since 2174166675Srrs * sctp_findassociation_ep_addr() wil do a 2175166675Srrs * decrement if it finds the stcb as long as 2176166675Srrs * the locked tcb (last argument) is NOT a 2177166675Srrs * TCB.. aka NULL. 2178166675Srrs */ 2179166675Srrs SCTP_INP_INCR_REF(inp); 2180166675Srrs stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddrp->spp_address, &net, NULL, NULL); 2181163953Srrs if (stcb == NULL) { 2182166675Srrs SCTP_INP_DECR_REF(inp); 2183163953Srrs } 2184163953Srrs } 2185171943Srrs if (stcb && (net == NULL)) { 2186171943Srrs struct sockaddr *sa; 2187163953Srrs 2188171943Srrs sa = (struct sockaddr *)&paddrp->spp_address; 2189171943Srrs if (sa->sa_family == AF_INET) { 2190171943Srrs struct sockaddr_in *sin; 2191171943Srrs 2192171943Srrs sin = (struct sockaddr_in *)sa; 2193171943Srrs if (sin->sin_addr.s_addr) { 2194171943Srrs error = EINVAL; 2195171943Srrs SCTP_TCB_UNLOCK(stcb); 2196171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2197171943Srrs break; 2198171943Srrs } 2199171943Srrs } else if (sa->sa_family == AF_INET6) { 2200171943Srrs struct sockaddr_in6 *sin6; 2201171943Srrs 2202171943Srrs sin6 = (struct sockaddr_in6 *)sa; 2203171943Srrs if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 2204171943Srrs error = EINVAL; 2205171943Srrs SCTP_TCB_UNLOCK(stcb); 2206171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2207171943Srrs break; 2208171943Srrs } 2209171943Srrs } else { 2210171943Srrs error = EAFNOSUPPORT; 2211171943Srrs SCTP_TCB_UNLOCK(stcb); 2212171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2213171943Srrs break; 2214171943Srrs } 2215171943Srrs } 2216163953Srrs if (stcb) { 2217163953Srrs /* Applys to the specific association */ 2218163953Srrs paddrp->spp_flags = 0; 2219163953Srrs if (net) { 2220170056Srrs int ovh; 2221170056Srrs 2222170056Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2223170056Srrs ovh = SCTP_MED_OVERHEAD; 2224170056Srrs } else { 2225170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 2226170056Srrs } 2227170056Srrs 2228170056Srrs 2229163953Srrs paddrp->spp_pathmaxrxt = net->failure_threshold; 2230170056Srrs paddrp->spp_pathmtu = net->mtu - ovh; 2231163953Srrs /* get flags for HB */ 2232163953Srrs if (net->dest_state & SCTP_ADDR_NOHB) 2233163953Srrs paddrp->spp_flags |= SPP_HB_DISABLE; 2234163953Srrs else 2235163953Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 2236163953Srrs /* get flags for PMTU */ 2237165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 2238163953Srrs paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2239163953Srrs } else { 2240163953Srrs paddrp->spp_flags |= SPP_PMTUD_DISABLE; 2241163953Srrs } 2242167598Srrs#ifdef INET 2243163953Srrs if (net->ro._l_addr.sin.sin_family == AF_INET) { 2244163953Srrs paddrp->spp_ipv4_tos = net->tos_flowlabel & 0x000000fc; 2245163953Srrs paddrp->spp_flags |= SPP_IPV4_TOS; 2246163953Srrs } 2247163953Srrs#endif 2248167598Srrs#ifdef INET6 2249163953Srrs if (net->ro._l_addr.sin6.sin6_family == AF_INET6) { 2250163953Srrs paddrp->spp_ipv6_flowlabel = net->tos_flowlabel; 2251163953Srrs paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2252163953Srrs } 2253163953Srrs#endif 2254163953Srrs } else { 2255163953Srrs /* 2256163953Srrs * No destination so return default 2257163953Srrs * value 2258163953Srrs */ 2259170056Srrs int cnt = 0; 2260170056Srrs 2261163953Srrs paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure; 2262163953Srrs paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc); 2263167598Srrs#ifdef INET 2264163953Srrs paddrp->spp_ipv4_tos = stcb->asoc.default_tos & 0x000000fc; 2265163953Srrs paddrp->spp_flags |= SPP_IPV4_TOS; 2266163953Srrs#endif 2267167598Srrs#ifdef INET6 2268163953Srrs paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel; 2269163953Srrs paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2270163953Srrs#endif 2271163953Srrs /* default settings should be these */ 2272170056Srrs if (stcb->asoc.hb_is_disabled == 0) { 2273163953Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 2274170056Srrs } else { 2275170056Srrs paddrp->spp_flags |= SPP_HB_DISABLE; 2276163953Srrs } 2277170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 2278170056Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 2279170056Srrs cnt++; 2280170056Srrs } 2281170056Srrs } 2282170056Srrs if (cnt) { 2283170056Srrs paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2284170056Srrs } 2285163953Srrs } 2286163953Srrs paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay; 2287163953Srrs paddrp->spp_assoc_id = sctp_get_associd(stcb); 2288163953Srrs SCTP_TCB_UNLOCK(stcb); 2289163953Srrs } else { 2290163953Srrs /* Use endpoint defaults */ 2291163953Srrs SCTP_INP_RLOCK(inp); 2292163953Srrs paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure; 2293163953Srrs paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); 2294163953Srrs paddrp->spp_assoc_id = (sctp_assoc_t) 0; 2295163953Srrs /* get inp's default */ 2296167598Srrs#ifdef INET 2297163953Srrs paddrp->spp_ipv4_tos = inp->ip_inp.inp.inp_ip_tos; 2298163953Srrs paddrp->spp_flags |= SPP_IPV4_TOS; 2299163953Srrs#endif 2300167598Srrs#ifdef INET6 2301163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2302163953Srrs paddrp->spp_ipv6_flowlabel = ((struct in6pcb *)inp)->in6p_flowinfo; 2303163953Srrs paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2304163953Srrs } 2305163953Srrs#endif 2306163953Srrs /* can't return this */ 2307163953Srrs paddrp->spp_pathmtu = 0; 2308170056Srrs 2309163953Srrs /* default behavior, no stcb */ 2310170056Srrs paddrp->spp_flags = SPP_PMTUD_ENABLE; 2311163953Srrs 2312170056Srrs if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { 2313170056Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 2314170056Srrs } else { 2315170056Srrs paddrp->spp_flags |= SPP_HB_DISABLE; 2316170056Srrs } 2317163953Srrs SCTP_INP_RUNLOCK(inp); 2318163953Srrs } 2319166675Srrs *optsize = sizeof(struct sctp_paddrparams); 2320163953Srrs } 2321163953Srrs break; 2322163953Srrs case SCTP_GET_PEER_ADDR_INFO: 2323163953Srrs { 2324163953Srrs struct sctp_paddrinfo *paddri; 2325163953Srrs struct sctp_nets *net; 2326163953Srrs 2327166675Srrs SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize); 2328166675Srrs SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id); 2329166675Srrs 2330163953Srrs net = NULL; 2331166675Srrs if (stcb) { 2332166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddri->spinfo_address); 2333166675Srrs } else { 2334166675Srrs /* 2335166675Srrs * We increment here since 2336166675Srrs * sctp_findassociation_ep_addr() wil do a 2337166675Srrs * decrement if it finds the stcb as long as 2338166675Srrs * the locked tcb (last argument) is NOT a 2339166675Srrs * TCB.. aka NULL. 2340166675Srrs */ 2341166675Srrs SCTP_INP_INCR_REF(inp); 2342166675Srrs stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddri->spinfo_address, &net, NULL, NULL); 2343166675Srrs if (stcb == NULL) { 2344166675Srrs SCTP_INP_DECR_REF(inp); 2345163953Srrs } 2346166675Srrs } 2347163953Srrs 2348166675Srrs if ((stcb) && (net)) { 2349166675Srrs paddri->spinfo_state = net->dest_state & (SCTP_REACHABLE_MASK | SCTP_ADDR_NOHB); 2350166675Srrs paddri->spinfo_cwnd = net->cwnd; 2351166675Srrs paddri->spinfo_srtt = ((net->lastsa >> 2) + net->lastsv) >> 1; 2352166675Srrs paddri->spinfo_rto = net->RTO; 2353166675Srrs paddri->spinfo_assoc_id = sctp_get_associd(stcb); 2354166675Srrs SCTP_TCB_UNLOCK(stcb); 2355163953Srrs } else { 2356163953Srrs if (stcb) { 2357163953Srrs SCTP_TCB_UNLOCK(stcb); 2358163953Srrs } 2359171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 2360163953Srrs error = ENOENT; 2361163953Srrs } 2362166675Srrs *optsize = sizeof(struct sctp_paddrinfo); 2363163953Srrs } 2364163953Srrs break; 2365163953Srrs case SCTP_PCB_STATUS: 2366163953Srrs { 2367163953Srrs struct sctp_pcbinfo *spcb; 2368163953Srrs 2369166675Srrs SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize); 2370163953Srrs sctp_fill_pcbinfo(spcb); 2371166675Srrs *optsize = sizeof(struct sctp_pcbinfo); 2372163953Srrs } 2373163953Srrs break; 2374167598Srrs 2375163953Srrs case SCTP_STATUS: 2376163953Srrs { 2377163953Srrs struct sctp_nets *net; 2378163953Srrs struct sctp_status *sstat; 2379163953Srrs 2380166675Srrs SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize); 2381166675Srrs SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id); 2382163953Srrs 2383163953Srrs if (stcb == NULL) { 2384171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2385163953Srrs error = EINVAL; 2386163953Srrs break; 2387163953Srrs } 2388163953Srrs /* 2389163953Srrs * I think passing the state is fine since 2390163953Srrs * sctp_constants.h will be available to the user 2391163953Srrs * land. 2392163953Srrs */ 2393163953Srrs sstat->sstat_state = stcb->asoc.state; 2394173179Srrs sstat->sstat_assoc_id = sctp_get_associd(stcb); 2395163953Srrs sstat->sstat_rwnd = stcb->asoc.peers_rwnd; 2396163953Srrs sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt; 2397163953Srrs /* 2398163953Srrs * We can't include chunks that have been passed to 2399163953Srrs * the socket layer. Only things in queue. 2400163953Srrs */ 2401163953Srrs sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue + 2402163953Srrs stcb->asoc.cnt_on_all_streams); 2403163953Srrs 2404163953Srrs 2405163953Srrs sstat->sstat_instrms = stcb->asoc.streamincnt; 2406163953Srrs sstat->sstat_outstrms = stcb->asoc.streamoutcnt; 2407163953Srrs sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc); 2408163953Srrs memcpy(&sstat->sstat_primary.spinfo_address, 2409163953Srrs &stcb->asoc.primary_destination->ro._l_addr, 2410163953Srrs ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len); 2411163953Srrs net = stcb->asoc.primary_destination; 2412163953Srrs ((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport; 2413163953Srrs /* 2414163953Srrs * Again the user can get info from sctp_constants.h 2415163953Srrs * for what the state of the network is. 2416163953Srrs */ 2417163953Srrs sstat->sstat_primary.spinfo_state = net->dest_state & SCTP_REACHABLE_MASK; 2418163953Srrs sstat->sstat_primary.spinfo_cwnd = net->cwnd; 2419163953Srrs sstat->sstat_primary.spinfo_srtt = net->lastsa; 2420163953Srrs sstat->sstat_primary.spinfo_rto = net->RTO; 2421163953Srrs sstat->sstat_primary.spinfo_mtu = net->mtu; 2422163953Srrs sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb); 2423163953Srrs SCTP_TCB_UNLOCK(stcb); 2424166675Srrs *optsize = sizeof(*sstat); 2425163953Srrs } 2426163953Srrs break; 2427163953Srrs case SCTP_RTOINFO: 2428163953Srrs { 2429163953Srrs struct sctp_rtoinfo *srto; 2430163953Srrs 2431166675Srrs SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize); 2432166675Srrs SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); 2433166675Srrs 2434166675Srrs if (stcb) { 2435166675Srrs srto->srto_initial = stcb->asoc.initial_rto; 2436166675Srrs srto->srto_max = stcb->asoc.maxrto; 2437166675Srrs srto->srto_min = stcb->asoc.minrto; 2438166675Srrs SCTP_TCB_UNLOCK(stcb); 2439166675Srrs } else { 2440163953Srrs SCTP_INP_RLOCK(inp); 2441163953Srrs srto->srto_initial = inp->sctp_ep.initial_rto; 2442163953Srrs srto->srto_max = inp->sctp_ep.sctp_maxrto; 2443163953Srrs srto->srto_min = inp->sctp_ep.sctp_minrto; 2444163953Srrs SCTP_INP_RUNLOCK(inp); 2445163953Srrs } 2446166675Srrs *optsize = sizeof(*srto); 2447163953Srrs } 2448163953Srrs break; 2449163953Srrs case SCTP_ASSOCINFO: 2450163953Srrs { 2451163953Srrs struct sctp_assocparams *sasoc; 2452171477Srrs uint32_t oldval; 2453163953Srrs 2454166675Srrs SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize); 2455166675Srrs SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); 2456163953Srrs 2457163953Srrs if (stcb) { 2458171477Srrs oldval = sasoc->sasoc_cookie_life; 2459171477Srrs sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life); 2460163953Srrs sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times; 2461163953Srrs sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets; 2462163953Srrs sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd; 2463163953Srrs sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd; 2464163953Srrs SCTP_TCB_UNLOCK(stcb); 2465163953Srrs } else { 2466163953Srrs SCTP_INP_RLOCK(inp); 2467171477Srrs sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life); 2468163953Srrs sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times; 2469163953Srrs sasoc->sasoc_number_peer_destinations = 0; 2470163953Srrs sasoc->sasoc_peer_rwnd = 0; 2471163953Srrs sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv); 2472163953Srrs SCTP_INP_RUNLOCK(inp); 2473163953Srrs } 2474166675Srrs *optsize = sizeof(*sasoc); 2475163953Srrs } 2476163953Srrs break; 2477163953Srrs case SCTP_DEFAULT_SEND_PARAM: 2478163953Srrs { 2479163953Srrs struct sctp_sndrcvinfo *s_info; 2480163953Srrs 2481166675Srrs SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize); 2482166675Srrs SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); 2483166675Srrs 2484166675Srrs if (stcb) { 2485170056Srrs memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send)); 2486166675Srrs SCTP_TCB_UNLOCK(stcb); 2487166675Srrs } else { 2488163953Srrs SCTP_INP_RLOCK(inp); 2489170056Srrs memcpy(s_info, &inp->def_send, sizeof(inp->def_send)); 2490163953Srrs SCTP_INP_RUNLOCK(inp); 2491163953Srrs } 2492166675Srrs *optsize = sizeof(*s_info); 2493163953Srrs } 2494163953Srrs break; 2495163953Srrs case SCTP_INITMSG: 2496163953Srrs { 2497163953Srrs struct sctp_initmsg *sinit; 2498163953Srrs 2499166675Srrs SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize); 2500163953Srrs SCTP_INP_RLOCK(inp); 2501163953Srrs sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count; 2502163953Srrs sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome; 2503163953Srrs sinit->sinit_max_attempts = inp->sctp_ep.max_init_times; 2504163953Srrs sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max; 2505163953Srrs SCTP_INP_RUNLOCK(inp); 2506166675Srrs *optsize = sizeof(*sinit); 2507163953Srrs } 2508163953Srrs break; 2509163953Srrs case SCTP_PRIMARY_ADDR: 2510163953Srrs /* we allow a "get" operation on this */ 2511163953Srrs { 2512163953Srrs struct sctp_setprim *ssp; 2513163953Srrs 2514166675Srrs SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize); 2515166675Srrs SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id); 2516166675Srrs 2517166675Srrs if (stcb) { 2518166675Srrs /* simply copy out the sockaddr_storage... */ 2519170056Srrs int len; 2520170056Srrs 2521170056Srrs len = *optsize; 2522170056Srrs if (len > stcb->asoc.primary_destination->ro._l_addr.sa.sa_len) 2523170056Srrs len = stcb->asoc.primary_destination->ro._l_addr.sa.sa_len; 2524170056Srrs 2525170056Srrs memcpy(&ssp->ssp_addr, 2526170056Srrs &stcb->asoc.primary_destination->ro._l_addr, 2527170056Srrs len); 2528166675Srrs SCTP_TCB_UNLOCK(stcb); 2529166675Srrs } else { 2530171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2531163953Srrs error = EINVAL; 2532163953Srrs } 2533166675Srrs *optsize = sizeof(*ssp); 2534163953Srrs } 2535163953Srrs break; 2536163953Srrs 2537163953Srrs case SCTP_HMAC_IDENT: 2538163953Srrs { 2539163953Srrs struct sctp_hmacalgo *shmac; 2540163953Srrs sctp_hmaclist_t *hmaclist; 2541163953Srrs uint32_t size; 2542163953Srrs int i; 2543163953Srrs 2544166675Srrs SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize); 2545166675Srrs 2546163953Srrs SCTP_INP_RLOCK(inp); 2547163953Srrs hmaclist = inp->sctp_ep.local_hmacs; 2548163953Srrs if (hmaclist == NULL) { 2549163953Srrs /* no HMACs to return */ 2550166675Srrs *optsize = sizeof(*shmac); 2551168299Srrs SCTP_INP_RUNLOCK(inp); 2552163953Srrs break; 2553163953Srrs } 2554163953Srrs /* is there room for all of the hmac ids? */ 2555163953Srrs size = sizeof(*shmac) + (hmaclist->num_algo * 2556163953Srrs sizeof(shmac->shmac_idents[0])); 2557166675Srrs if ((size_t)(*optsize) < size) { 2558171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2559163953Srrs error = EINVAL; 2560163953Srrs SCTP_INP_RUNLOCK(inp); 2561163953Srrs break; 2562163953Srrs } 2563163953Srrs /* copy in the list */ 2564181054Srrs shmac->shmac_number_of_idents = hmaclist->num_algo; 2565181054Srrs for (i = 0; i < hmaclist->num_algo; i++) { 2566163953Srrs shmac->shmac_idents[i] = hmaclist->hmac[i]; 2567181054Srrs } 2568163953Srrs SCTP_INP_RUNLOCK(inp); 2569166675Srrs *optsize = size; 2570163953Srrs break; 2571163953Srrs } 2572163953Srrs case SCTP_AUTH_ACTIVE_KEY: 2573163953Srrs { 2574163953Srrs struct sctp_authkeyid *scact; 2575163953Srrs 2576166675Srrs SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize); 2577166675Srrs SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); 2578166675Srrs 2579166675Srrs if (stcb) { 2580163953Srrs /* get the active key on the assoc */ 2581185694Srrs scact->scact_keynumber = stcb->asoc.authinfo.active_keyid; 2582163953Srrs SCTP_TCB_UNLOCK(stcb); 2583163953Srrs } else { 2584163953Srrs /* get the endpoint active key */ 2585163953Srrs SCTP_INP_RLOCK(inp); 2586163953Srrs scact->scact_keynumber = inp->sctp_ep.default_keyid; 2587163953Srrs SCTP_INP_RUNLOCK(inp); 2588163953Srrs } 2589166675Srrs *optsize = sizeof(*scact); 2590163953Srrs break; 2591163953Srrs } 2592163953Srrs case SCTP_LOCAL_AUTH_CHUNKS: 2593163953Srrs { 2594163953Srrs struct sctp_authchunks *sac; 2595163953Srrs sctp_auth_chklist_t *chklist = NULL; 2596166675Srrs size_t size = 0; 2597163953Srrs 2598166675Srrs SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); 2599166675Srrs SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); 2600166675Srrs 2601166675Srrs if (stcb) { 2602163953Srrs /* get off the assoc */ 2603163953Srrs chklist = stcb->asoc.local_auth_chunks; 2604163953Srrs /* is there enough space? */ 2605163953Srrs size = sctp_auth_get_chklist_size(chklist); 2606166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2607163953Srrs error = EINVAL; 2608171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2609166675Srrs } else { 2610166675Srrs /* copy in the chunks */ 2611169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2612163953Srrs } 2613163953Srrs SCTP_TCB_UNLOCK(stcb); 2614163953Srrs } else { 2615163953Srrs /* get off the endpoint */ 2616163953Srrs SCTP_INP_RLOCK(inp); 2617163953Srrs chklist = inp->sctp_ep.local_auth_chunks; 2618163953Srrs /* is there enough space? */ 2619163953Srrs size = sctp_auth_get_chklist_size(chklist); 2620166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2621163953Srrs error = EINVAL; 2622171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2623166675Srrs } else { 2624166675Srrs /* copy in the chunks */ 2625169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2626163953Srrs } 2627163953Srrs SCTP_INP_RUNLOCK(inp); 2628163953Srrs } 2629166675Srrs *optsize = sizeof(struct sctp_authchunks) + size; 2630163953Srrs break; 2631163953Srrs } 2632163953Srrs case SCTP_PEER_AUTH_CHUNKS: 2633163953Srrs { 2634163953Srrs struct sctp_authchunks *sac; 2635163953Srrs sctp_auth_chklist_t *chklist = NULL; 2636166675Srrs size_t size = 0; 2637163953Srrs 2638166675Srrs SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); 2639166675Srrs SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); 2640166675Srrs 2641166675Srrs if (stcb) { 2642166675Srrs /* get off the assoc */ 2643166675Srrs chklist = stcb->asoc.peer_auth_chunks; 2644166675Srrs /* is there enough space? */ 2645166675Srrs size = sctp_auth_get_chklist_size(chklist); 2646166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2647166675Srrs error = EINVAL; 2648171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 2649166675Srrs } else { 2650166675Srrs /* copy in the chunks */ 2651169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2652166675Srrs } 2653166675Srrs SCTP_TCB_UNLOCK(stcb); 2654166675Srrs } else { 2655171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 2656163953Srrs error = ENOENT; 2657163953Srrs } 2658166675Srrs *optsize = sizeof(struct sctp_authchunks) + size; 2659163953Srrs break; 2660163953Srrs } 2661163953Srrs 2662163953Srrs 2663163953Srrs default: 2664171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 2665163953Srrs error = ENOPROTOOPT; 2666166675Srrs *optsize = 0; 2667163953Srrs break; 2668163953Srrs } /* end switch (sopt->sopt_name) */ 2669163953Srrs return (error); 2670163953Srrs} 2671163953Srrs 2672163953Srrsstatic int 2673166675Srrssctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, 2674166675Srrs void *p) 2675163953Srrs{ 2676166675Srrs int error, set_opt; 2677166675Srrs uint32_t *mopt; 2678163953Srrs struct sctp_tcb *stcb = NULL; 2679171943Srrs struct sctp_inpcb *inp = NULL; 2680167598Srrs uint32_t vrf_id; 2681163953Srrs 2682166675Srrs if (optval == NULL) { 2683169420Srrs SCTP_PRINTF("optval is NULL\n"); 2684171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2685163953Srrs return (EINVAL); 2686163953Srrs } 2687163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 2688167598Srrs if (inp == 0) { 2689169420Srrs SCTP_PRINTF("inp is NULL?\n"); 2690171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2691163953Srrs return EINVAL; 2692167598Srrs } 2693168299Srrs vrf_id = inp->def_vrf_id; 2694163953Srrs 2695163953Srrs error = 0; 2696166675Srrs switch (optname) { 2697163953Srrs case SCTP_NODELAY: 2698163953Srrs case SCTP_AUTOCLOSE: 2699163953Srrs case SCTP_AUTO_ASCONF: 2700163953Srrs case SCTP_EXPLICIT_EOR: 2701163953Srrs case SCTP_DISABLE_FRAGMENTS: 2702163953Srrs case SCTP_USE_EXT_RCVINFO: 2703163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 2704163953Srrs /* copy in the option value */ 2705166675Srrs SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); 2706163953Srrs set_opt = 0; 2707163953Srrs if (error) 2708163953Srrs break; 2709166675Srrs switch (optname) { 2710163953Srrs case SCTP_DISABLE_FRAGMENTS: 2711163953Srrs set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT; 2712163953Srrs break; 2713163953Srrs case SCTP_AUTO_ASCONF: 2714171943Srrs /* 2715171943Srrs * NOTE: we don't really support this flag 2716171943Srrs */ 2717171943Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 2718171943Srrs /* only valid for bound all sockets */ 2719171943Srrs set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF; 2720171943Srrs } else { 2721171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2722171943Srrs return (EINVAL); 2723171943Srrs } 2724163953Srrs break; 2725163953Srrs case SCTP_EXPLICIT_EOR: 2726163953Srrs set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR; 2727163953Srrs break; 2728163953Srrs case SCTP_USE_EXT_RCVINFO: 2729163953Srrs set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO; 2730163953Srrs break; 2731163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 2732163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2733163953Srrs set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4; 2734163953Srrs } else { 2735171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2736163953Srrs return (EINVAL); 2737163953Srrs } 2738163953Srrs break; 2739163953Srrs case SCTP_NODELAY: 2740163953Srrs set_opt = SCTP_PCB_FLAGS_NODELAY; 2741163953Srrs break; 2742163953Srrs case SCTP_AUTOCLOSE: 2743170056Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2744170056Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 2745171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2746170056Srrs return (EINVAL); 2747170056Srrs } 2748163953Srrs set_opt = SCTP_PCB_FLAGS_AUTOCLOSE; 2749163953Srrs /* 2750163953Srrs * The value is in ticks. Note this does not effect 2751163953Srrs * old associations, only new ones. 2752163953Srrs */ 2753163953Srrs inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt); 2754163953Srrs break; 2755163953Srrs } 2756163953Srrs SCTP_INP_WLOCK(inp); 2757163953Srrs if (*mopt != 0) { 2758163953Srrs sctp_feature_on(inp, set_opt); 2759163953Srrs } else { 2760163953Srrs sctp_feature_off(inp, set_opt); 2761163953Srrs } 2762163953Srrs SCTP_INP_WUNLOCK(inp); 2763163953Srrs break; 2764181054Srrs case SCTP_REUSE_PORT: 2765181054Srrs { 2766181054Srrs SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); 2767181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) { 2768181054Srrs /* Can't set it after we are bound */ 2769181054Srrs error = EINVAL; 2770181054Srrs break; 2771181054Srrs } 2772181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) { 2773181054Srrs /* Can't do this for a 1-m socket */ 2774181054Srrs error = EINVAL; 2775181054Srrs break; 2776181054Srrs } 2777181054Srrs if (optval) 2778181054Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE); 2779181054Srrs else 2780181054Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE); 2781181054Srrs } 2782181054Srrs break; 2783163953Srrs case SCTP_PARTIAL_DELIVERY_POINT: 2784163953Srrs { 2785166675Srrs uint32_t *value; 2786166675Srrs 2787166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); 2788167736Srrs if (*value > SCTP_SB_LIMIT_RCV(so)) { 2789171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2790167736Srrs error = EINVAL; 2791167736Srrs break; 2792167736Srrs } 2793166675Srrs inp->partial_delivery_point = *value; 2794163953Srrs } 2795163953Srrs break; 2796163953Srrs case SCTP_FRAGMENT_INTERLEAVE: 2797163953Srrs /* not yet until we re-write sctp_recvmsg() */ 2798163953Srrs { 2799168943Srrs uint32_t *level; 2800163953Srrs 2801168943Srrs SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize); 2802168943Srrs if (*level == SCTP_FRAG_LEVEL_2) { 2803163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 2804168943Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 2805168943Srrs } else if (*level == SCTP_FRAG_LEVEL_1) { 2806168943Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 2807168943Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 2808168943Srrs } else if (*level == SCTP_FRAG_LEVEL_0) { 2809170056Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 2810168943Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 2811168943Srrs 2812163953Srrs } else { 2813171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2814168943Srrs error = EINVAL; 2815163953Srrs } 2816163953Srrs } 2817163953Srrs break; 2818163953Srrs case SCTP_CMT_ON_OFF: 2819163953Srrs { 2820163953Srrs struct sctp_assoc_value *av; 2821163953Srrs 2822166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 2823179783Srrs if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { 2824166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2825166675Srrs if (stcb) { 2826163953Srrs stcb->asoc.sctp_cmt_on_off = (uint8_t) av->assoc_value; 2827166675Srrs SCTP_TCB_UNLOCK(stcb); 2828163953Srrs } else { 2829171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 2830166675Srrs error = ENOTCONN; 2831163953Srrs } 2832166675Srrs } else { 2833171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 2834166675Srrs error = ENOPROTOOPT; 2835163953Srrs } 2836163953Srrs } 2837163953Srrs break; 2838185694Srrs /* EY nr_sack_on_off socket option */ 2839185694Srrs case SCTP_NR_SACK_ON_OFF: 2840185694Srrs { 2841185694Srrs struct sctp_assoc_value *av; 2842185694Srrs 2843185694Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 2844185694Srrs if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off)) { 2845185694Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2846185694Srrs if (stcb) { 2847185694Srrs stcb->asoc.sctp_nr_sack_on_off = (uint8_t) av->assoc_value; 2848185694Srrs SCTP_TCB_UNLOCK(stcb); 2849185694Srrs } else { 2850185694Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 2851185694Srrs error = ENOTCONN; 2852185694Srrs } 2853185694Srrs } else { 2854185694Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 2855185694Srrs error = ENOPROTOOPT; 2856185694Srrs } 2857185694Srrs } 2858185694Srrs break; 2859171440Srrs /* JRS - Set socket option for pluggable congestion control */ 2860171440Srrs case SCTP_PLUGGABLE_CC: 2861171440Srrs { 2862171440Srrs struct sctp_assoc_value *av; 2863171440Srrs 2864171440Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 2865171440Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2866171440Srrs if (stcb) { 2867171440Srrs switch (av->assoc_value) { 2868171440Srrs /* 2869171440Srrs * JRS - Standard TCP congestion 2870171440Srrs * control 2871171440Srrs */ 2872171440Srrs case SCTP_CC_RFC2581: 2873171440Srrs { 2874171440Srrs stcb->asoc.congestion_control_module = SCTP_CC_RFC2581; 2875171440Srrs stcb->asoc.cc_functions.sctp_set_initial_cc_param = &sctp_set_initial_cc_param; 2876171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_sack = &sctp_cwnd_update_after_sack; 2877171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_fr = &sctp_cwnd_update_after_fr; 2878171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_timeout = &sctp_cwnd_update_after_timeout; 2879171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_ecn_echo = &sctp_cwnd_update_after_ecn_echo; 2880171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_packet_dropped = &sctp_cwnd_update_after_packet_dropped; 2881171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_output = &sctp_cwnd_update_after_output; 2882171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_fr_timer = &sctp_cwnd_update_after_fr_timer; 2883171440Srrs SCTP_TCB_UNLOCK(stcb); 2884171440Srrs break; 2885171440Srrs } 2886171440Srrs /* 2887171440Srrs * JRS - High Speed TCP congestion 2888171440Srrs * control (Floyd) 2889171440Srrs */ 2890171440Srrs case SCTP_CC_HSTCP: 2891171440Srrs { 2892171440Srrs stcb->asoc.congestion_control_module = SCTP_CC_HSTCP; 2893171440Srrs stcb->asoc.cc_functions.sctp_set_initial_cc_param = &sctp_set_initial_cc_param; 2894171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_sack = &sctp_hs_cwnd_update_after_sack; 2895171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_fr = &sctp_hs_cwnd_update_after_fr; 2896171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_timeout = &sctp_cwnd_update_after_timeout; 2897171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_ecn_echo = &sctp_cwnd_update_after_ecn_echo; 2898171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_packet_dropped = &sctp_cwnd_update_after_packet_dropped; 2899171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_output = &sctp_cwnd_update_after_output; 2900171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_fr_timer = &sctp_cwnd_update_after_fr_timer; 2901171440Srrs SCTP_TCB_UNLOCK(stcb); 2902171440Srrs break; 2903171440Srrs } 2904171440Srrs /* JRS - HTCP congestion control */ 2905171440Srrs case SCTP_CC_HTCP: 2906171440Srrs { 2907171440Srrs stcb->asoc.congestion_control_module = SCTP_CC_HTCP; 2908171440Srrs stcb->asoc.cc_functions.sctp_set_initial_cc_param = &sctp_htcp_set_initial_cc_param; 2909171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_sack = &sctp_htcp_cwnd_update_after_sack; 2910171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_fr = &sctp_htcp_cwnd_update_after_fr; 2911171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_timeout = &sctp_htcp_cwnd_update_after_timeout; 2912171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_ecn_echo = &sctp_htcp_cwnd_update_after_ecn_echo; 2913171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_packet_dropped = &sctp_cwnd_update_after_packet_dropped; 2914171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_output = &sctp_cwnd_update_after_output; 2915171440Srrs stcb->asoc.cc_functions.sctp_cwnd_update_after_fr_timer = &sctp_htcp_cwnd_update_after_fr_timer; 2916171440Srrs SCTP_TCB_UNLOCK(stcb); 2917171440Srrs break; 2918171440Srrs } 2919171440Srrs /* 2920171440Srrs * JRS - All other values are 2921171440Srrs * invalid 2922171440Srrs */ 2923171440Srrs default: 2924171440Srrs { 2925171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2926171440Srrs error = EINVAL; 2927171440Srrs SCTP_TCB_UNLOCK(stcb); 2928171440Srrs break; 2929171440Srrs } 2930171440Srrs } 2931171440Srrs } else { 2932171440Srrs switch (av->assoc_value) { 2933171440Srrs case SCTP_CC_RFC2581: 2934171440Srrs case SCTP_CC_HSTCP: 2935171440Srrs case SCTP_CC_HTCP: 2936171440Srrs inp->sctp_ep.sctp_default_cc_module = av->assoc_value; 2937171440Srrs break; 2938171440Srrs default: 2939171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2940171440Srrs error = EINVAL; 2941171440Srrs break; 2942171440Srrs }; 2943171440Srrs } 2944171440Srrs } 2945171440Srrs break; 2946163953Srrs case SCTP_CLR_STAT_LOG: 2947171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 2948163953Srrs error = EOPNOTSUPP; 2949163953Srrs break; 2950163953Srrs case SCTP_CONTEXT: 2951163953Srrs { 2952163953Srrs struct sctp_assoc_value *av; 2953163953Srrs 2954166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 2955166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2956166675Srrs 2957166675Srrs if (stcb) { 2958166675Srrs stcb->asoc.context = av->assoc_value; 2959166675Srrs SCTP_TCB_UNLOCK(stcb); 2960163953Srrs } else { 2961166675Srrs SCTP_INP_WLOCK(inp); 2962163953Srrs inp->sctp_context = av->assoc_value; 2963166675Srrs SCTP_INP_WUNLOCK(inp); 2964163953Srrs } 2965163953Srrs } 2966163953Srrs break; 2967167598Srrs case SCTP_VRF_ID: 2968167598Srrs { 2969170056Srrs uint32_t *default_vrfid; 2970167598Srrs 2971170056Srrs SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize); 2972170056Srrs if (*default_vrfid > SCTP_MAX_VRF_ID) { 2973171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 2974167598Srrs error = EINVAL; 2975167598Srrs break; 2976167598Srrs } 2977170056Srrs inp->def_vrf_id = *default_vrfid; 2978167598Srrs break; 2979167598Srrs } 2980167598Srrs case SCTP_DEL_VRF_ID: 2981167598Srrs { 2982171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 2983167598Srrs error = EOPNOTSUPP; 2984167598Srrs break; 2985167598Srrs } 2986167598Srrs case SCTP_ADD_VRF_ID: 2987167598Srrs { 2988171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 2989167598Srrs error = EOPNOTSUPP; 2990167598Srrs break; 2991167598Srrs } 2992170056Srrs case SCTP_DELAYED_SACK: 2993163953Srrs { 2994170056Srrs struct sctp_sack_info *sack; 2995163953Srrs 2996170056Srrs SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize); 2997170056Srrs SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); 2998171477Srrs if (sack->sack_delay) { 2999171477Srrs if (sack->sack_delay > SCTP_MAX_SACK_DELAY) 3000171477Srrs sack->sack_delay = SCTP_MAX_SACK_DELAY; 3001171477Srrs } 3002166675Srrs if (stcb) { 3003170056Srrs if (sack->sack_delay) { 3004170056Srrs if (MSEC_TO_TICKS(sack->sack_delay) < 1) { 3005170056Srrs sack->sack_delay = TICKS_TO_MSEC(1); 3006170056Srrs } 3007170056Srrs stcb->asoc.delayed_ack = sack->sack_delay; 3008170056Srrs } 3009170056Srrs if (sack->sack_freq) { 3010170056Srrs stcb->asoc.sack_freq = sack->sack_freq; 3011170056Srrs } 3012166675Srrs SCTP_TCB_UNLOCK(stcb); 3013166675Srrs } else { 3014163953Srrs SCTP_INP_WLOCK(inp); 3015170056Srrs if (sack->sack_delay) { 3016170056Srrs if (MSEC_TO_TICKS(sack->sack_delay) < 1) { 3017170056Srrs sack->sack_delay = TICKS_TO_MSEC(1); 3018170056Srrs } 3019170056Srrs inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay); 3020170056Srrs } 3021170056Srrs if (sack->sack_freq) { 3022170056Srrs inp->sctp_ep.sctp_sack_freq = sack->sack_freq; 3023170056Srrs } 3024163953Srrs SCTP_INP_WUNLOCK(inp); 3025163953Srrs } 3026166675Srrs break; 3027163953Srrs } 3028163953Srrs case SCTP_AUTH_CHUNK: 3029163953Srrs { 3030163953Srrs struct sctp_authchunk *sauth; 3031163953Srrs 3032166675Srrs SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize); 3033166675Srrs 3034166675Srrs SCTP_INP_WLOCK(inp); 3035171943Srrs if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) { 3036171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3037163953Srrs error = EINVAL; 3038171943Srrs } 3039166675Srrs SCTP_INP_WUNLOCK(inp); 3040163953Srrs break; 3041163953Srrs } 3042163953Srrs case SCTP_AUTH_KEY: 3043163953Srrs { 3044163953Srrs struct sctp_authkey *sca; 3045163953Srrs struct sctp_keyhead *shared_keys; 3046163953Srrs sctp_sharedkey_t *shared_key; 3047163953Srrs sctp_key_t *key = NULL; 3048166675Srrs size_t size; 3049163953Srrs 3050166675Srrs SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize); 3051169420Srrs SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id); 3052169420Srrs size = optsize - sizeof(*sca); 3053166675Srrs 3054166675Srrs if (stcb) { 3055163953Srrs /* set it on the assoc */ 3056163953Srrs shared_keys = &stcb->asoc.shared_keys; 3057163953Srrs /* clear the cached keys for this key id */ 3058163953Srrs sctp_clear_cachedkeys(stcb, sca->sca_keynumber); 3059163953Srrs /* 3060163953Srrs * create the new shared key and 3061163953Srrs * insert/replace it 3062163953Srrs */ 3063163953Srrs if (size > 0) { 3064163953Srrs key = sctp_set_key(sca->sca_key, (uint32_t) size); 3065163953Srrs if (key == NULL) { 3066171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3067163953Srrs error = ENOMEM; 3068163953Srrs SCTP_TCB_UNLOCK(stcb); 3069163953Srrs break; 3070163953Srrs } 3071163953Srrs } 3072163953Srrs shared_key = sctp_alloc_sharedkey(); 3073163953Srrs if (shared_key == NULL) { 3074163953Srrs sctp_free_key(key); 3075171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3076163953Srrs error = ENOMEM; 3077163953Srrs SCTP_TCB_UNLOCK(stcb); 3078163953Srrs break; 3079163953Srrs } 3080163953Srrs shared_key->key = key; 3081163953Srrs shared_key->keyid = sca->sca_keynumber; 3082185694Srrs error = sctp_insert_sharedkey(shared_keys, shared_key); 3083163953Srrs SCTP_TCB_UNLOCK(stcb); 3084163953Srrs } else { 3085166675Srrs /* set it on the endpoint */ 3086163953Srrs SCTP_INP_WLOCK(inp); 3087163953Srrs shared_keys = &inp->sctp_ep.shared_keys; 3088163953Srrs /* 3089163953Srrs * clear the cached keys on all assocs for 3090163953Srrs * this key id 3091163953Srrs */ 3092163953Srrs sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber); 3093163953Srrs /* 3094163953Srrs * create the new shared key and 3095163953Srrs * insert/replace it 3096163953Srrs */ 3097163953Srrs if (size > 0) { 3098163953Srrs key = sctp_set_key(sca->sca_key, (uint32_t) size); 3099163953Srrs if (key == NULL) { 3100171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3101163953Srrs error = ENOMEM; 3102163953Srrs SCTP_INP_WUNLOCK(inp); 3103163953Srrs break; 3104163953Srrs } 3105163953Srrs } 3106163953Srrs shared_key = sctp_alloc_sharedkey(); 3107163953Srrs if (shared_key == NULL) { 3108163953Srrs sctp_free_key(key); 3109171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3110163953Srrs error = ENOMEM; 3111163953Srrs SCTP_INP_WUNLOCK(inp); 3112163953Srrs break; 3113163953Srrs } 3114163953Srrs shared_key->key = key; 3115163953Srrs shared_key->keyid = sca->sca_keynumber; 3116185694Srrs error = sctp_insert_sharedkey(shared_keys, shared_key); 3117163953Srrs SCTP_INP_WUNLOCK(inp); 3118163953Srrs } 3119163953Srrs break; 3120163953Srrs } 3121163953Srrs case SCTP_HMAC_IDENT: 3122163953Srrs { 3123163953Srrs struct sctp_hmacalgo *shmac; 3124163953Srrs sctp_hmaclist_t *hmaclist; 3125181054Srrs uint16_t hmacid; 3126181054Srrs uint32_t i; 3127163953Srrs 3128181054Srrs size_t found; 3129181054Srrs 3130166675Srrs SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize); 3131181054Srrs if (optsize < sizeof(struct sctp_hmacalgo) + shmac->shmac_number_of_idents * sizeof(uint16_t)) { 3132181054Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3133181054Srrs error = EINVAL; 3134181054Srrs break; 3135181054Srrs } 3136181054Srrs hmaclist = sctp_alloc_hmaclist(shmac->shmac_number_of_idents); 3137163953Srrs if (hmaclist == NULL) { 3138171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); 3139163953Srrs error = ENOMEM; 3140163953Srrs break; 3141163953Srrs } 3142181054Srrs for (i = 0; i < shmac->shmac_number_of_idents; i++) { 3143163953Srrs hmacid = shmac->shmac_idents[i]; 3144181054Srrs if (sctp_auth_add_hmacid(hmaclist, hmacid)) { 3145163953Srrs /* invalid HMACs were found */ ; 3146171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3147163953Srrs error = EINVAL; 3148164085Srrs sctp_free_hmaclist(hmaclist); 3149163953Srrs goto sctp_set_hmac_done; 3150163953Srrs } 3151163953Srrs } 3152170056Srrs found = 0; 3153170056Srrs for (i = 0; i < hmaclist->num_algo; i++) { 3154170056Srrs if (hmaclist->hmac[i] == SCTP_AUTH_HMAC_ID_SHA1) { 3155170056Srrs /* already in list */ 3156170056Srrs found = 1; 3157170056Srrs } 3158170056Srrs } 3159170056Srrs if (!found) { 3160170056Srrs sctp_free_hmaclist(hmaclist); 3161171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3162170056Srrs error = EINVAL; 3163170056Srrs break; 3164170056Srrs } 3165163953Srrs /* set it on the endpoint */ 3166163953Srrs SCTP_INP_WLOCK(inp); 3167163953Srrs if (inp->sctp_ep.local_hmacs) 3168163953Srrs sctp_free_hmaclist(inp->sctp_ep.local_hmacs); 3169163953Srrs inp->sctp_ep.local_hmacs = hmaclist; 3170163953Srrs SCTP_INP_WUNLOCK(inp); 3171163953Srrs sctp_set_hmac_done: 3172163953Srrs break; 3173163953Srrs } 3174163953Srrs case SCTP_AUTH_ACTIVE_KEY: 3175163953Srrs { 3176163953Srrs struct sctp_authkeyid *scact; 3177163953Srrs 3178185694Srrs SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, 3179185694Srrs optsize); 3180166675Srrs SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); 3181166675Srrs 3182163953Srrs /* set the active key on the right place */ 3183166675Srrs if (stcb) { 3184163953Srrs /* set the active key on the assoc */ 3185185694Srrs if (sctp_auth_setactivekey(stcb, 3186185694Srrs scact->scact_keynumber)) { 3187185694Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, 3188185694Srrs SCTP_FROM_SCTP_USRREQ, 3189185694Srrs EINVAL); 3190163953Srrs error = EINVAL; 3191171943Srrs } 3192163953Srrs SCTP_TCB_UNLOCK(stcb); 3193163953Srrs } else { 3194163953Srrs /* set the active key on the endpoint */ 3195163953Srrs SCTP_INP_WLOCK(inp); 3196185694Srrs if (sctp_auth_setactivekey_ep(inp, 3197185694Srrs scact->scact_keynumber)) { 3198185694Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, 3199185694Srrs SCTP_FROM_SCTP_USRREQ, 3200185694Srrs EINVAL); 3201163953Srrs error = EINVAL; 3202171943Srrs } 3203163953Srrs SCTP_INP_WUNLOCK(inp); 3204163953Srrs } 3205163953Srrs break; 3206163953Srrs } 3207163953Srrs case SCTP_AUTH_DELETE_KEY: 3208163953Srrs { 3209163953Srrs struct sctp_authkeyid *scdel; 3210163953Srrs 3211185694Srrs SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, 3212185694Srrs optsize); 3213166675Srrs SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id); 3214166675Srrs 3215163953Srrs /* delete the key from the right place */ 3216166675Srrs if (stcb) { 3217185694Srrs if (sctp_delete_sharedkey(stcb, 3218185694Srrs scdel->scact_keynumber)) { 3219185694Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, 3220185694Srrs SCTP_FROM_SCTP_USRREQ, 3221185694Srrs EINVAL); 3222163953Srrs error = EINVAL; 3223171943Srrs } 3224163953Srrs SCTP_TCB_UNLOCK(stcb); 3225163953Srrs } else { 3226163953Srrs SCTP_INP_WLOCK(inp); 3227185694Srrs if (sctp_delete_sharedkey_ep(inp, 3228185694Srrs scdel->scact_keynumber)) { 3229185694Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, 3230185694Srrs SCTP_FROM_SCTP_USRREQ, 3231185694Srrs EINVAL); 3232163953Srrs error = EINVAL; 3233171943Srrs } 3234163953Srrs SCTP_INP_WUNLOCK(inp); 3235163953Srrs } 3236163953Srrs break; 3237163953Srrs } 3238185694Srrs case SCTP_AUTH_DEACTIVATE_KEY: 3239185694Srrs { 3240185694Srrs struct sctp_authkeyid *keyid; 3241163953Srrs 3242185694Srrs SCTP_CHECK_AND_CAST(keyid, optval, struct sctp_authkeyid, 3243185694Srrs optsize); 3244185694Srrs SCTP_FIND_STCB(inp, stcb, keyid->scact_assoc_id); 3245185694Srrs 3246185694Srrs /* deactivate the key from the right place */ 3247185694Srrs if (stcb) { 3248185694Srrs if (sctp_deact_sharedkey(stcb, 3249185694Srrs keyid->scact_keynumber)) { 3250185694Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, 3251185694Srrs SCTP_FROM_SCTP_USRREQ, 3252185694Srrs EINVAL); 3253185694Srrs error = EINVAL; 3254185694Srrs } 3255185694Srrs SCTP_TCB_UNLOCK(stcb); 3256185694Srrs } else { 3257185694Srrs SCTP_INP_WLOCK(inp); 3258185694Srrs if (sctp_deact_sharedkey_ep(inp, 3259185694Srrs keyid->scact_keynumber)) { 3260185694Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, 3261185694Srrs SCTP_FROM_SCTP_USRREQ, 3262185694Srrs EINVAL); 3263185694Srrs error = EINVAL; 3264185694Srrs } 3265185694Srrs SCTP_INP_WUNLOCK(inp); 3266185694Srrs } 3267185694Srrs break; 3268185694Srrs } 3269185694Srrs 3270163953Srrs case SCTP_RESET_STREAMS: 3271163953Srrs { 3272163953Srrs struct sctp_stream_reset *strrst; 3273188854Srrs uint8_t send_in = 0, send_tsn = 0, send_out = 0, 3274188854Srrs addstream = 0; 3275188854Srrs uint16_t addstrmcnt = 0; 3276163953Srrs int i; 3277163953Srrs 3278166675Srrs SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_stream_reset, optsize); 3279166675Srrs SCTP_FIND_STCB(inp, stcb, strrst->strrst_assoc_id); 3280163953Srrs 3281163953Srrs if (stcb == NULL) { 3282171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 3283163953Srrs error = ENOENT; 3284163953Srrs break; 3285163953Srrs } 3286163953Srrs if (stcb->asoc.peer_supports_strreset == 0) { 3287163953Srrs /* 3288163953Srrs * Peer does not support it, we return 3289163953Srrs * protocol not supported since this is true 3290163953Srrs * for this feature and this peer, not the 3291163953Srrs * socket request in general. 3292163953Srrs */ 3293171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPROTONOSUPPORT); 3294163953Srrs error = EPROTONOSUPPORT; 3295163953Srrs SCTP_TCB_UNLOCK(stcb); 3296163953Srrs break; 3297163953Srrs } 3298163953Srrs if (stcb->asoc.stream_reset_outstanding) { 3299171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 3300163953Srrs error = EALREADY; 3301163953Srrs SCTP_TCB_UNLOCK(stcb); 3302163953Srrs break; 3303163953Srrs } 3304163953Srrs if (strrst->strrst_flags == SCTP_RESET_LOCAL_RECV) { 3305163953Srrs send_in = 1; 3306163953Srrs } else if (strrst->strrst_flags == SCTP_RESET_LOCAL_SEND) { 3307163953Srrs send_out = 1; 3308163953Srrs } else if (strrst->strrst_flags == SCTP_RESET_BOTH) { 3309163953Srrs send_in = 1; 3310163953Srrs send_out = 1; 3311163953Srrs } else if (strrst->strrst_flags == SCTP_RESET_TSN) { 3312163953Srrs send_tsn = 1; 3313188854Srrs } else if (strrst->strrst_flags == SCTP_RESET_ADD_STREAMS) { 3314188854Srrs if (send_tsn || 3315188854Srrs send_in || 3316188854Srrs send_out) { 3317188854Srrs /* We can't do that and add streams */ 3318188854Srrs error = EINVAL; 3319188854Srrs goto skip_stuff; 3320188854Srrs } 3321188854Srrs if (stcb->asoc.stream_reset_outstanding) { 3322188854Srrs error = EBUSY; 3323188854Srrs goto skip_stuff; 3324188854Srrs } 3325188854Srrs addstream = 1; 3326188854Srrs /* We allocate here */ 3327188854Srrs addstrmcnt = strrst->strrst_num_streams; 3328188854Srrs if ((int)(addstrmcnt + stcb->asoc.streamoutcnt) > 0xffff) { 3329188854Srrs /* You can't have more than 64k */ 3330188854Srrs error = EINVAL; 3331188854Srrs goto skip_stuff; 3332188854Srrs } 3333188854Srrs if ((stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt) < addstrmcnt) { 3334188854Srrs /* Need to allocate more */ 3335188854Srrs struct sctp_stream_out *oldstream; 3336189121Srrs struct sctp_stream_queue_pending *sp; 3337189121Srrs int removed; 3338188854Srrs 3339188854Srrs oldstream = stcb->asoc.strmout; 3340188854Srrs /* get some more */ 3341188854Srrs SCTP_MALLOC(stcb->asoc.strmout, struct sctp_stream_out *, 3342188854Srrs ((stcb->asoc.streamoutcnt + addstrmcnt) * sizeof(struct sctp_stream_out)), 3343188854Srrs SCTP_M_STRMO); 3344188854Srrs if (stcb->asoc.strmout == NULL) { 3345188854Srrs stcb->asoc.strmout = oldstream; 3346188854Srrs error = ENOMEM; 3347188854Srrs goto skip_stuff; 3348188854Srrs } 3349188854Srrs /* 3350188854Srrs * Ok now we proceed with copying 3351188854Srrs * the old out stuff and 3352188854Srrs * initializing the new stuff. 3353188854Srrs */ 3354189121Srrs SCTP_TCB_SEND_LOCK(stcb); 3355189121Srrs for (i = 0; i < stcb->asoc.streamoutcnt; i++) { 3356189121Srrs TAILQ_INIT(&stcb->asoc.strmout[i].outqueue); 3357189121Srrs stcb->asoc.strmout[i].next_sequence_sent = oldstream[i].next_sequence_sent; 3358189121Srrs stcb->asoc.strmout[i].last_msg_incomplete = oldstream[i].last_msg_incomplete; 3359189121Srrs stcb->asoc.strmout[i].stream_no = i; 3360189121Srrs if (oldstream[i].next_spoke.tqe_next) { 3361189121Srrs sctp_remove_from_wheel(stcb, &stcb->asoc, &oldstream[i], 1); 3362189121Srrs stcb->asoc.strmout[i].next_spoke.tqe_next = NULL; 3363189121Srrs stcb->asoc.strmout[i].next_spoke.tqe_prev = NULL; 3364189121Srrs removed = 1; 3365189121Srrs } else { 3366189121Srrs /* not on out wheel */ 3367189121Srrs stcb->asoc.strmout[i].next_spoke.tqe_next = NULL; 3368189121Srrs stcb->asoc.strmout[i].next_spoke.tqe_prev = NULL; 3369189121Srrs removed = 0; 3370189121Srrs } 3371189121Srrs /* 3372189121Srrs * now anything on those 3373189121Srrs * queues? 3374189121Srrs */ 3375189121Srrs while (TAILQ_EMPTY(&oldstream[i].outqueue) == 0) { 3376189121Srrs sp = TAILQ_FIRST(&oldstream[i].outqueue); 3377189121Srrs TAILQ_REMOVE(&oldstream[i].outqueue, sp, next); 3378189121Srrs TAILQ_INSERT_TAIL(&stcb->asoc.strmout[i].outqueue, sp, next); 3379189121Srrs } 3380189121Srrs /* Did we disrupt the wheel? */ 3381189121Srrs if (removed) { 3382189121Srrs sctp_insert_on_wheel(stcb, 3383189121Srrs &stcb->asoc, 3384189121Srrs &stcb->asoc.strmout[i], 3385189121Srrs 1); 3386189121Srrs } 3387189121Srrs /* 3388189121Srrs * Now move assoc pointers 3389189121Srrs * too 3390189121Srrs */ 3391189121Srrs if (stcb->asoc.last_out_stream == &oldstream[i]) { 3392189121Srrs stcb->asoc.last_out_stream = &stcb->asoc.strmout[i]; 3393189121Srrs } 3394189121Srrs if (stcb->asoc.locked_on_sending == &oldstream[i]) { 3395189121Srrs stcb->asoc.locked_on_sending = &stcb->asoc.strmout[i]; 3396189121Srrs } 3397189121Srrs } 3398188854Srrs /* now the new streams */ 3399188854Srrs for (i = stcb->asoc.streamoutcnt; i < (stcb->asoc.streamoutcnt + addstrmcnt); i++) { 3400188854Srrs stcb->asoc.strmout[i].next_sequence_sent = 0x0; 3401188854Srrs TAILQ_INIT(&stcb->asoc.strmout[i].outqueue); 3402188854Srrs stcb->asoc.strmout[i].stream_no = i; 3403188854Srrs stcb->asoc.strmout[i].last_msg_incomplete = 0; 3404189121Srrs stcb->asoc.strmout[i].next_spoke.tqe_next = NULL; 3405189121Srrs stcb->asoc.strmout[i].next_spoke.tqe_prev = NULL; 3406188854Srrs } 3407188854Srrs stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + addstrmcnt; 3408188854Srrs SCTP_FREE(oldstream, SCTP_M_STRMO); 3409188854Srrs } 3410189121Srrs SCTP_TCB_SEND_UNLOCK(stcb); 3411188854Srrs goto skip_stuff; 3412163953Srrs } else { 3413171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3414163953Srrs error = EINVAL; 3415163953Srrs SCTP_TCB_UNLOCK(stcb); 3416163953Srrs break; 3417163953Srrs } 3418163953Srrs for (i = 0; i < strrst->strrst_num_streams; i++) { 3419163953Srrs if ((send_in) && 3420163953Srrs 3421163953Srrs (strrst->strrst_list[i] > stcb->asoc.streamincnt)) { 3422171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3423163953Srrs error = EINVAL; 3424163953Srrs goto get_out; 3425163953Srrs } 3426163953Srrs if ((send_out) && 3427163953Srrs (strrst->strrst_list[i] > stcb->asoc.streamoutcnt)) { 3428171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3429163953Srrs error = EINVAL; 3430163953Srrs goto get_out; 3431163953Srrs } 3432163953Srrs } 3433188854Srrs skip_stuff: 3434163953Srrs if (error) { 3435163953Srrs get_out: 3436163953Srrs SCTP_TCB_UNLOCK(stcb); 3437163953Srrs break; 3438163953Srrs } 3439163953Srrs error = sctp_send_str_reset_req(stcb, strrst->strrst_num_streams, 3440163953Srrs strrst->strrst_list, 3441163953Srrs send_out, (stcb->asoc.str_reset_seq_in - 3), 3442188854Srrs send_in, send_tsn, addstream, addstrmcnt); 3443163953Srrs 3444172090Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); 3445163953Srrs SCTP_TCB_UNLOCK(stcb); 3446163953Srrs } 3447163953Srrs break; 3448166675Srrs 3449163953Srrs case SCTP_CONNECT_X: 3450166675Srrs if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { 3451171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3452163953Srrs error = EINVAL; 3453163953Srrs break; 3454163953Srrs } 3455166675Srrs error = sctp_do_connect_x(so, inp, optval, optsize, p, 0); 3456163953Srrs break; 3457163953Srrs 3458163953Srrs case SCTP_CONNECT_X_DELAYED: 3459166675Srrs if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { 3460171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3461163953Srrs error = EINVAL; 3462163953Srrs break; 3463163953Srrs } 3464166675Srrs error = sctp_do_connect_x(so, inp, optval, optsize, p, 1); 3465163953Srrs break; 3466163953Srrs 3467163953Srrs case SCTP_CONNECT_X_COMPLETE: 3468163953Srrs { 3469163953Srrs struct sockaddr *sa; 3470163953Srrs struct sctp_nets *net; 3471163953Srrs 3472166675Srrs /* FIXME MT: check correct? */ 3473166675Srrs SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize); 3474166675Srrs 3475163953Srrs /* find tcb */ 3476163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 3477163953Srrs SCTP_INP_RLOCK(inp); 3478163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 3479163953Srrs if (stcb) { 3480163953Srrs SCTP_TCB_LOCK(stcb); 3481163953Srrs net = sctp_findnet(stcb, sa); 3482163953Srrs } 3483163953Srrs SCTP_INP_RUNLOCK(inp); 3484163953Srrs } else { 3485166675Srrs /* 3486166675Srrs * We increment here since 3487166675Srrs * sctp_findassociation_ep_addr() wil do a 3488166675Srrs * decrement if it finds the stcb as long as 3489166675Srrs * the locked tcb (last argument) is NOT a 3490166675Srrs * TCB.. aka NULL. 3491166675Srrs */ 3492163953Srrs SCTP_INP_INCR_REF(inp); 3493163953Srrs stcb = sctp_findassociation_ep_addr(&inp, sa, &net, NULL, NULL); 3494163953Srrs if (stcb == NULL) { 3495163953Srrs SCTP_INP_DECR_REF(inp); 3496163953Srrs } 3497163953Srrs } 3498163953Srrs 3499163953Srrs if (stcb == NULL) { 3500171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 3501163953Srrs error = ENOENT; 3502163953Srrs break; 3503163953Srrs } 3504163953Srrs if (stcb->asoc.delayed_connection == 1) { 3505163953Srrs stcb->asoc.delayed_connection = 0; 3506169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 3507165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, 3508165220Srrs stcb->asoc.primary_destination, 3509165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9); 3510172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 3511163953Srrs } else { 3512163953Srrs /* 3513163953Srrs * already expired or did not use delayed 3514163953Srrs * connectx 3515163953Srrs */ 3516171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 3517163953Srrs error = EALREADY; 3518163953Srrs } 3519163953Srrs SCTP_TCB_UNLOCK(stcb); 3520163953Srrs } 3521163953Srrs break; 3522170056Srrs case SCTP_MAX_BURST: 3523163953Srrs { 3524163953Srrs uint8_t *burst; 3525163953Srrs 3526166675Srrs SCTP_CHECK_AND_CAST(burst, optval, uint8_t, optsize); 3527166675Srrs 3528163953Srrs SCTP_INP_WLOCK(inp); 3529163953Srrs if (*burst) { 3530163953Srrs inp->sctp_ep.max_burst = *burst; 3531163953Srrs } 3532163953Srrs SCTP_INP_WUNLOCK(inp); 3533163953Srrs } 3534163953Srrs break; 3535163953Srrs case SCTP_MAXSEG: 3536163953Srrs { 3537167598Srrs struct sctp_assoc_value *av; 3538163953Srrs int ovh; 3539163953Srrs 3540167598Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 3541167598Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 3542166675Srrs 3543170056Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 3544170056Srrs ovh = SCTP_MED_OVERHEAD; 3545170056Srrs } else { 3546170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 3547170056Srrs } 3548167598Srrs if (stcb) { 3549170056Srrs if (av->assoc_value) { 3550170056Srrs stcb->asoc.sctp_frag_point = (av->assoc_value + ovh); 3551170056Srrs } else { 3552170056Srrs stcb->asoc.sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; 3553170056Srrs } 3554167598Srrs SCTP_TCB_UNLOCK(stcb); 3555163953Srrs } else { 3556167598Srrs SCTP_INP_WLOCK(inp); 3557167598Srrs /* 3558167598Srrs * FIXME MT: I think this is not in tune 3559167598Srrs * with the API ID 3560167598Srrs */ 3561167598Srrs if (av->assoc_value) { 3562167598Srrs inp->sctp_frag_point = (av->assoc_value + ovh); 3563167598Srrs } else { 3564170056Srrs inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; 3565167598Srrs } 3566167598Srrs SCTP_INP_WUNLOCK(inp); 3567163953Srrs } 3568163953Srrs } 3569163953Srrs break; 3570163953Srrs case SCTP_EVENTS: 3571163953Srrs { 3572163953Srrs struct sctp_event_subscribe *events; 3573163953Srrs 3574166675Srrs SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize); 3575166675Srrs 3576163953Srrs SCTP_INP_WLOCK(inp); 3577163953Srrs if (events->sctp_data_io_event) { 3578163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); 3579163953Srrs } else { 3580163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); 3581163953Srrs } 3582163953Srrs 3583163953Srrs if (events->sctp_association_event) { 3584163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); 3585163953Srrs } else { 3586163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); 3587163953Srrs } 3588163953Srrs 3589163953Srrs if (events->sctp_address_event) { 3590163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); 3591163953Srrs } else { 3592163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); 3593163953Srrs } 3594163953Srrs 3595163953Srrs if (events->sctp_send_failure_event) { 3596163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 3597163953Srrs } else { 3598163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 3599163953Srrs } 3600163953Srrs 3601163953Srrs if (events->sctp_peer_error_event) { 3602163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR); 3603163953Srrs } else { 3604163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR); 3605163953Srrs } 3606163953Srrs 3607163953Srrs if (events->sctp_shutdown_event) { 3608163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 3609163953Srrs } else { 3610163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 3611163953Srrs } 3612163953Srrs 3613163953Srrs if (events->sctp_partial_delivery_event) { 3614163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT); 3615163953Srrs } else { 3616163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT); 3617163953Srrs } 3618163953Srrs 3619163953Srrs if (events->sctp_adaptation_layer_event) { 3620163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 3621163953Srrs } else { 3622163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 3623163953Srrs } 3624163953Srrs 3625163953Srrs if (events->sctp_authentication_event) { 3626163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT); 3627163953Srrs } else { 3628163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT); 3629163953Srrs } 3630163953Srrs 3631185694Srrs if (events->sctp_sender_dry_event) { 3632185694Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT); 3633188067Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3634188067Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 3635188067Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 3636188067Srrs if (stcb) { 3637188067Srrs SCTP_TCB_LOCK(stcb); 3638188067Srrs } 3639188067Srrs if (stcb && 3640188067Srrs TAILQ_EMPTY(&stcb->asoc.send_queue) && 3641188067Srrs TAILQ_EMPTY(&stcb->asoc.sent_queue) && 3642188067Srrs (stcb->asoc.stream_queue_cnt == 0)) { 3643188067Srrs sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED); 3644188067Srrs } 3645188067Srrs if (stcb) { 3646188067Srrs SCTP_TCB_UNLOCK(stcb); 3647188067Srrs } 3648188067Srrs } 3649185694Srrs } else { 3650185694Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT); 3651185694Srrs } 3652185694Srrs 3653202520Srrs if (events->sctp_stream_reset_event) { 3654163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 3655163953Srrs } else { 3656163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 3657163953Srrs } 3658163953Srrs SCTP_INP_WUNLOCK(inp); 3659163953Srrs } 3660163953Srrs break; 3661163953Srrs 3662163953Srrs case SCTP_ADAPTATION_LAYER: 3663163953Srrs { 3664163953Srrs struct sctp_setadaptation *adap_bits; 3665163953Srrs 3666166675Srrs SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize); 3667163953Srrs SCTP_INP_WLOCK(inp); 3668163953Srrs inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind; 3669163953Srrs SCTP_INP_WUNLOCK(inp); 3670163953Srrs } 3671163953Srrs break; 3672166675Srrs#ifdef SCTP_DEBUG 3673163953Srrs case SCTP_SET_INITIAL_DBG_SEQ: 3674163953Srrs { 3675163953Srrs uint32_t *vvv; 3676163953Srrs 3677166675Srrs SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize); 3678163953Srrs SCTP_INP_WLOCK(inp); 3679163953Srrs inp->sctp_ep.initial_sequence_debug = *vvv; 3680163953Srrs SCTP_INP_WUNLOCK(inp); 3681163953Srrs } 3682163953Srrs break; 3683166675Srrs#endif 3684163953Srrs case SCTP_DEFAULT_SEND_PARAM: 3685163953Srrs { 3686163953Srrs struct sctp_sndrcvinfo *s_info; 3687163953Srrs 3688166675Srrs SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize); 3689166675Srrs SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); 3690163953Srrs 3691166675Srrs if (stcb) { 3692166675Srrs if (s_info->sinfo_stream <= stcb->asoc.streamoutcnt) { 3693170056Srrs memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send))); 3694163953Srrs } else { 3695171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3696166675Srrs error = EINVAL; 3697163953Srrs } 3698166675Srrs SCTP_TCB_UNLOCK(stcb); 3699166675Srrs } else { 3700166675Srrs SCTP_INP_WLOCK(inp); 3701170056Srrs memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send))); 3702166675Srrs SCTP_INP_WUNLOCK(inp); 3703163953Srrs } 3704163953Srrs } 3705163953Srrs break; 3706163953Srrs case SCTP_PEER_ADDR_PARAMS: 3707163953Srrs /* Applys to the specific association */ 3708163953Srrs { 3709163953Srrs struct sctp_paddrparams *paddrp; 3710163953Srrs struct sctp_nets *net; 3711163953Srrs 3712166675Srrs SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize); 3713166675Srrs SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); 3714163953Srrs net = NULL; 3715166675Srrs if (stcb) { 3716166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address); 3717166675Srrs } else { 3718166675Srrs /* 3719166675Srrs * We increment here since 3720166675Srrs * sctp_findassociation_ep_addr() wil do a 3721166675Srrs * decrement if it finds the stcb as long as 3722166675Srrs * the locked tcb (last argument) is NOT a 3723166675Srrs * TCB.. aka NULL. 3724166675Srrs */ 3725166675Srrs SCTP_INP_INCR_REF(inp); 3726166675Srrs stcb = sctp_findassociation_ep_addr(&inp, 3727166675Srrs (struct sockaddr *)&paddrp->spp_address, 3728166675Srrs &net, NULL, NULL); 3729163953Srrs if (stcb == NULL) { 3730166675Srrs SCTP_INP_DECR_REF(inp); 3731163953Srrs } 3732163953Srrs } 3733171943Srrs if (stcb && (net == NULL)) { 3734171943Srrs struct sockaddr *sa; 3735171943Srrs 3736171943Srrs sa = (struct sockaddr *)&paddrp->spp_address; 3737171943Srrs if (sa->sa_family == AF_INET) { 3738171943Srrs struct sockaddr_in *sin; 3739171943Srrs 3740171943Srrs sin = (struct sockaddr_in *)sa; 3741171943Srrs if (sin->sin_addr.s_addr) { 3742171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3743171943Srrs SCTP_TCB_UNLOCK(stcb); 3744171943Srrs error = EINVAL; 3745171943Srrs break; 3746171943Srrs } 3747171943Srrs } else if (sa->sa_family == AF_INET6) { 3748171943Srrs struct sockaddr_in6 *sin6; 3749171943Srrs 3750171943Srrs sin6 = (struct sockaddr_in6 *)sa; 3751171943Srrs if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 3752171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3753171943Srrs SCTP_TCB_UNLOCK(stcb); 3754171943Srrs error = EINVAL; 3755171943Srrs break; 3756171943Srrs } 3757171943Srrs } else { 3758171943Srrs error = EAFNOSUPPORT; 3759171943Srrs SCTP_TCB_UNLOCK(stcb); 3760171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 3761171943Srrs break; 3762171943Srrs } 3763171943Srrs } 3764170056Srrs /* sanity checks */ 3765170056Srrs if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) { 3766170056Srrs if (stcb) 3767170056Srrs SCTP_TCB_UNLOCK(stcb); 3768171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3769170056Srrs return (EINVAL); 3770170056Srrs } 3771170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) { 3772170056Srrs if (stcb) 3773170056Srrs SCTP_TCB_UNLOCK(stcb); 3774171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3775170056Srrs return (EINVAL); 3776170056Srrs } 3777163953Srrs if (stcb) { 3778163953Srrs /************************TCB SPECIFIC SET ******************/ 3779163953Srrs /* 3780163953Srrs * do we change the timer for HB, we run 3781163953Srrs * only one? 3782163953Srrs */ 3783170056Srrs int ovh = 0; 3784170056Srrs 3785170056Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 3786170056Srrs ovh = SCTP_MED_OVERHEAD; 3787170056Srrs } else { 3788170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 3789170056Srrs } 3790170056Srrs 3791163953Srrs if (paddrp->spp_hbinterval) 3792163953Srrs stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval; 3793163953Srrs else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) 3794163953Srrs stcb->asoc.heart_beat_delay = 0; 3795163953Srrs 3796163953Srrs /* network sets ? */ 3797163953Srrs if (net) { 3798163953Srrs /************************NET SPECIFIC SET ******************/ 3799163953Srrs if (paddrp->spp_flags & SPP_HB_DEMAND) { 3800163953Srrs /* on demand HB */ 3801171440Srrs if (sctp_send_hb(stcb, 1, net) < 0) { 3802171440Srrs /* asoc destroyed */ 3803171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3804171440Srrs error = EINVAL; 3805171440Srrs break; 3806171440Srrs } 3807163953Srrs } 3808163953Srrs if (paddrp->spp_flags & SPP_HB_DISABLE) { 3809163953Srrs net->dest_state |= SCTP_ADDR_NOHB; 3810163953Srrs } 3811163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 3812163953Srrs net->dest_state &= ~SCTP_ADDR_NOHB; 3813163953Srrs } 3814170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { 3815165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 3816165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 3817165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 3818163953Srrs } 3819163953Srrs if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) { 3820170056Srrs net->mtu = paddrp->spp_pathmtu + ovh; 3821169352Srrs if (net->mtu < stcb->asoc.smallest_mtu) { 3822169352Srrs#ifdef SCTP_PRINT_FOR_B_AND_M 3823169420Srrs SCTP_PRINTF("SCTP_PMTU_DISABLE calls sctp_pathmtu_adjustment:%d\n", 3824169352Srrs net->mtu); 3825169352Srrs#endif 3826167695Srrs sctp_pathmtu_adjustment(inp, stcb, net, net->mtu); 3827169352Srrs } 3828163953Srrs } 3829163953Srrs } 3830163953Srrs if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 3831165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 3832163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 3833163953Srrs } 3834163953Srrs } 3835163953Srrs if (paddrp->spp_pathmaxrxt) 3836163953Srrs net->failure_threshold = paddrp->spp_pathmaxrxt; 3837167598Srrs#ifdef INET 3838163953Srrs if (paddrp->spp_flags & SPP_IPV4_TOS) { 3839163953Srrs if (net->ro._l_addr.sin.sin_family == AF_INET) { 3840163953Srrs net->tos_flowlabel = paddrp->spp_ipv4_tos & 0x000000fc; 3841163953Srrs } 3842163953Srrs } 3843163953Srrs#endif 3844167598Srrs#ifdef INET6 3845163953Srrs if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { 3846163953Srrs if (net->ro._l_addr.sin6.sin6_family == AF_INET6) { 3847163953Srrs net->tos_flowlabel = paddrp->spp_ipv6_flowlabel; 3848163953Srrs } 3849163953Srrs } 3850163953Srrs#endif 3851163953Srrs } else { 3852163953Srrs /************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/ 3853163953Srrs if (paddrp->spp_pathmaxrxt) 3854163953Srrs stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt; 3855163953Srrs 3856163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 3857163953Srrs /* Turn back on the timer */ 3858163953Srrs stcb->asoc.hb_is_disabled = 0; 3859163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 3860163953Srrs } 3861170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { 3862170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3863170056Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 3864170056Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 3865170056Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 3866170056Srrs } 3867170056Srrs if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) { 3868170056Srrs net->mtu = paddrp->spp_pathmtu + ovh; 3869170056Srrs if (net->mtu < stcb->asoc.smallest_mtu) { 3870170056Srrs#ifdef SCTP_PRINT_FOR_B_AND_M 3871170056Srrs SCTP_PRINTF("SCTP_PMTU_DISABLE calls sctp_pathmtu_adjustment:%d\n", 3872170056Srrs net->mtu); 3873170056Srrs#endif 3874170056Srrs sctp_pathmtu_adjustment(inp, stcb, net, net->mtu); 3875170056Srrs } 3876170056Srrs } 3877170056Srrs } 3878170056Srrs } 3879170056Srrs if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 3880170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3881170056Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 3882170056Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 3883170056Srrs } 3884170056Srrs } 3885170056Srrs } 3886163953Srrs if (paddrp->spp_flags & SPP_HB_DISABLE) { 3887163953Srrs int cnt_of_unconf = 0; 3888163953Srrs struct sctp_nets *lnet; 3889163953Srrs 3890163953Srrs stcb->asoc.hb_is_disabled = 1; 3891163953Srrs TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 3892163953Srrs if (lnet->dest_state & SCTP_ADDR_UNCONFIRMED) { 3893163953Srrs cnt_of_unconf++; 3894163953Srrs } 3895163953Srrs } 3896163953Srrs /* 3897163953Srrs * stop the timer ONLY if we 3898163953Srrs * have no unconfirmed 3899163953Srrs * addresses 3900163953Srrs */ 3901163953Srrs if (cnt_of_unconf == 0) { 3902170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3903170056Srrs sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 3904170056Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11); 3905170056Srrs } 3906163953Srrs } 3907163953Srrs } 3908163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 3909163953Srrs /* start up the timer. */ 3910170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3911170056Srrs sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 3912170056Srrs } 3913163953Srrs } 3914167598Srrs#ifdef INET 3915163953Srrs if (paddrp->spp_flags & SPP_IPV4_TOS) 3916163953Srrs stcb->asoc.default_tos = paddrp->spp_ipv4_tos & 0x000000fc; 3917163953Srrs#endif 3918167598Srrs#ifdef INET6 3919163953Srrs if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) 3920163953Srrs stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel; 3921163953Srrs#endif 3922163953Srrs 3923163953Srrs } 3924163953Srrs SCTP_TCB_UNLOCK(stcb); 3925163953Srrs } else { 3926163953Srrs /************************NO TCB, SET TO default stuff ******************/ 3927163953Srrs SCTP_INP_WLOCK(inp); 3928163953Srrs /* 3929163953Srrs * For the TOS/FLOWLABEL stuff you set it 3930163953Srrs * with the options on the socket 3931163953Srrs */ 3932163953Srrs if (paddrp->spp_pathmaxrxt) { 3933163953Srrs inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt; 3934163953Srrs } 3935170056Srrs if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) 3936170056Srrs inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0; 3937171477Srrs else if (paddrp->spp_hbinterval) { 3938171477Srrs if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL) 3939171477Srrs paddrp->spp_hbinterval = SCTP_MAX_HB_INTERVAL; 3940170056Srrs inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval); 3941171477Srrs } 3942163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 3943163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 3944170056Srrs 3945163953Srrs } else if (paddrp->spp_flags & SPP_HB_DISABLE) { 3946163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 3947163953Srrs } 3948163953Srrs SCTP_INP_WUNLOCK(inp); 3949163953Srrs } 3950163953Srrs } 3951163953Srrs break; 3952163953Srrs case SCTP_RTOINFO: 3953163953Srrs { 3954163953Srrs struct sctp_rtoinfo *srto; 3955169655Srrs uint32_t new_init, new_min, new_max; 3956163953Srrs 3957166675Srrs SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize); 3958166675Srrs SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); 3959166675Srrs 3960166675Srrs if (stcb) { 3961167598Srrs if (srto->srto_initial) 3962169655Srrs new_init = srto->srto_initial; 3963169655Srrs else 3964169655Srrs new_init = stcb->asoc.initial_rto; 3965167598Srrs if (srto->srto_max) 3966169655Srrs new_max = srto->srto_max; 3967169655Srrs else 3968169655Srrs new_max = stcb->asoc.maxrto; 3969167598Srrs if (srto->srto_min) 3970169655Srrs new_min = srto->srto_min; 3971169655Srrs else 3972169655Srrs new_min = stcb->asoc.minrto; 3973169655Srrs if ((new_min <= new_init) && (new_init <= new_max)) { 3974169655Srrs stcb->asoc.initial_rto = new_init; 3975169655Srrs stcb->asoc.maxrto = new_max; 3976169655Srrs stcb->asoc.minrto = new_min; 3977169655Srrs } else { 3978179783Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 3979179783Srrs error = EINVAL; 3980169655Srrs } 3981166675Srrs SCTP_TCB_UNLOCK(stcb); 3982166675Srrs } else { 3983163953Srrs SCTP_INP_WLOCK(inp); 3984167598Srrs if (srto->srto_initial) 3985169655Srrs new_init = srto->srto_initial; 3986169655Srrs else 3987169655Srrs new_init = inp->sctp_ep.initial_rto; 3988167598Srrs if (srto->srto_max) 3989169655Srrs new_max = srto->srto_max; 3990169655Srrs else 3991169655Srrs new_max = inp->sctp_ep.sctp_maxrto; 3992167598Srrs if (srto->srto_min) 3993169655Srrs new_min = srto->srto_min; 3994169655Srrs else 3995169655Srrs new_min = inp->sctp_ep.sctp_minrto; 3996169655Srrs if ((new_min <= new_init) && (new_init <= new_max)) { 3997169655Srrs inp->sctp_ep.initial_rto = new_init; 3998169655Srrs inp->sctp_ep.sctp_maxrto = new_max; 3999169655Srrs inp->sctp_ep.sctp_minrto = new_min; 4000169655Srrs } else { 4001179783Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4002179783Srrs error = EINVAL; 4003169655Srrs } 4004163953Srrs SCTP_INP_WUNLOCK(inp); 4005163953Srrs } 4006163953Srrs } 4007163953Srrs break; 4008163953Srrs case SCTP_ASSOCINFO: 4009163953Srrs { 4010163953Srrs struct sctp_assocparams *sasoc; 4011163953Srrs 4012166675Srrs SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize); 4013166675Srrs SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); 4014171477Srrs if (sasoc->sasoc_cookie_life) { 4015171477Srrs /* boundary check the cookie life */ 4016171477Srrs if (sasoc->sasoc_cookie_life < 1000) 4017171477Srrs sasoc->sasoc_cookie_life = 1000; 4018171477Srrs if (sasoc->sasoc_cookie_life > SCTP_MAX_COOKIE_LIFE) { 4019171477Srrs sasoc->sasoc_cookie_life = SCTP_MAX_COOKIE_LIFE; 4020171477Srrs } 4021171477Srrs } 4022163953Srrs if (stcb) { 4023163953Srrs if (sasoc->sasoc_asocmaxrxt) 4024163953Srrs stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt; 4025163953Srrs sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets; 4026163953Srrs sasoc->sasoc_peer_rwnd = 0; 4027163953Srrs sasoc->sasoc_local_rwnd = 0; 4028170056Srrs if (sasoc->sasoc_cookie_life) { 4029171572Srrs stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); 4030167598Srrs } 4031163953Srrs SCTP_TCB_UNLOCK(stcb); 4032163953Srrs } else { 4033163953Srrs SCTP_INP_WLOCK(inp); 4034163953Srrs if (sasoc->sasoc_asocmaxrxt) 4035163953Srrs inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt; 4036163953Srrs sasoc->sasoc_number_peer_destinations = 0; 4037163953Srrs sasoc->sasoc_peer_rwnd = 0; 4038163953Srrs sasoc->sasoc_local_rwnd = 0; 4039170056Srrs if (sasoc->sasoc_cookie_life) { 4040169655Srrs inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); 4041167598Srrs } 4042163953Srrs SCTP_INP_WUNLOCK(inp); 4043163953Srrs } 4044163953Srrs } 4045163953Srrs break; 4046163953Srrs case SCTP_INITMSG: 4047163953Srrs { 4048163953Srrs struct sctp_initmsg *sinit; 4049163953Srrs 4050166675Srrs SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize); 4051163953Srrs SCTP_INP_WLOCK(inp); 4052163953Srrs if (sinit->sinit_num_ostreams) 4053163953Srrs inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams; 4054163953Srrs 4055163953Srrs if (sinit->sinit_max_instreams) 4056163953Srrs inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams; 4057163953Srrs 4058163953Srrs if (sinit->sinit_max_attempts) 4059163953Srrs inp->sctp_ep.max_init_times = sinit->sinit_max_attempts; 4060163953Srrs 4061167598Srrs if (sinit->sinit_max_init_timeo) 4062163953Srrs inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo; 4063163953Srrs SCTP_INP_WUNLOCK(inp); 4064163953Srrs } 4065163953Srrs break; 4066163953Srrs case SCTP_PRIMARY_ADDR: 4067163953Srrs { 4068163953Srrs struct sctp_setprim *spa; 4069163953Srrs struct sctp_nets *net, *lnet; 4070163953Srrs 4071166675Srrs SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize); 4072166675Srrs SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id); 4073163953Srrs 4074166675Srrs net = NULL; 4075166675Srrs if (stcb) { 4076166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&spa->ssp_addr); 4077166675Srrs } else { 4078166675Srrs /* 4079166675Srrs * We increment here since 4080166675Srrs * sctp_findassociation_ep_addr() wil do a 4081166675Srrs * decrement if it finds the stcb as long as 4082166675Srrs * the locked tcb (last argument) is NOT a 4083166675Srrs * TCB.. aka NULL. 4084166675Srrs */ 4085163953Srrs SCTP_INP_INCR_REF(inp); 4086163953Srrs stcb = sctp_findassociation_ep_addr(&inp, 4087163953Srrs (struct sockaddr *)&spa->ssp_addr, 4088163953Srrs &net, NULL, NULL); 4089163953Srrs if (stcb == NULL) { 4090163953Srrs SCTP_INP_DECR_REF(inp); 4091163953Srrs } 4092163953Srrs } 4093166675Srrs 4094166675Srrs if ((stcb) && (net)) { 4095166675Srrs if ((net != stcb->asoc.primary_destination) && 4096166675Srrs (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) { 4097166675Srrs /* Ok we need to set it */ 4098166675Srrs lnet = stcb->asoc.primary_destination; 4099166675Srrs if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) { 4100166675Srrs if (net->dest_state & SCTP_ADDR_SWITCH_PRIMARY) { 4101166675Srrs net->dest_state |= SCTP_ADDR_DOUBLE_SWITCH; 4102166675Srrs } 4103166675Srrs net->dest_state |= SCTP_ADDR_SWITCH_PRIMARY; 4104163953Srrs } 4105163953Srrs } 4106166675Srrs } else { 4107171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4108166675Srrs error = EINVAL; 4109163953Srrs } 4110166675Srrs if (stcb) { 4111166675Srrs SCTP_TCB_UNLOCK(stcb); 4112166675Srrs } 4113163953Srrs } 4114163953Srrs break; 4115167598Srrs case SCTP_SET_DYNAMIC_PRIMARY: 4116167598Srrs { 4117167598Srrs union sctp_sockstore *ss; 4118163953Srrs 4119170587Srwatson error = priv_check(curthread, 4120170587Srwatson PRIV_NETINET_RESERVEDPORT); 4121167598Srrs if (error) 4122167598Srrs break; 4123167598Srrs 4124167598Srrs SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize); 4125167598Srrs /* SUPER USER CHECK? */ 4126167598Srrs error = sctp_dynamic_set_primary(&ss->sa, vrf_id); 4127167598Srrs } 4128167598Srrs break; 4129163953Srrs case SCTP_SET_PEER_PRIMARY_ADDR: 4130163953Srrs { 4131163953Srrs struct sctp_setpeerprim *sspp; 4132163953Srrs 4133166675Srrs SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize); 4134166675Srrs SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id); 4135169208Srrs if (stcb != NULL) { 4136170056Srrs struct sctp_ifa *ifa; 4137170056Srrs 4138170056Srrs ifa = sctp_find_ifa_by_addr((struct sockaddr *)&sspp->sspp_addr, 4139172091Srrs stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED); 4140170056Srrs if (ifa == NULL) { 4141171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4142166675Srrs error = EINVAL; 4143170056Srrs goto out_of_it; 4144166675Srrs } 4145170056Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { 4146170056Srrs /* 4147170056Srrs * Must validate the ifa found is in 4148170056Srrs * our ep 4149170056Srrs */ 4150170056Srrs struct sctp_laddr *laddr; 4151170056Srrs int found = 0; 4152170056Srrs 4153170056Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 4154170056Srrs if (laddr->ifa == NULL) { 4155170056Srrs SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n", 4156170056Srrs __FUNCTION__); 4157170056Srrs continue; 4158170056Srrs } 4159170056Srrs if (laddr->ifa == ifa) { 4160170056Srrs found = 1; 4161170056Srrs break; 4162170056Srrs } 4163170056Srrs } 4164170056Srrs if (!found) { 4165171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4166170056Srrs error = EINVAL; 4167170056Srrs goto out_of_it; 4168170056Srrs } 4169170056Srrs } 4170170056Srrs if (sctp_set_primary_ip_address_sa(stcb, 4171170056Srrs (struct sockaddr *)&sspp->sspp_addr) != 0) { 4172171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4173170056Srrs error = EINVAL; 4174170056Srrs } 4175170056Srrs out_of_it: 4176169208Srrs SCTP_TCB_UNLOCK(stcb); 4177166675Srrs } else { 4178171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4179163953Srrs error = EINVAL; 4180163953Srrs } 4181169208Srrs 4182163953Srrs } 4183163953Srrs break; 4184163953Srrs case SCTP_BINDX_ADD_ADDR: 4185163953Srrs { 4186163953Srrs struct sctp_getaddresses *addrs; 4187171531Srrs size_t sz; 4188171477Srrs struct thread *td; 4189163953Srrs 4190171477Srrs td = (struct thread *)p; 4191170606Srrs SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, 4192170606Srrs optsize); 4193171477Srrs if (addrs->addr->sa_family == AF_INET) { 4194171477Srrs sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in); 4195171477Srrs if (optsize < sz) { 4196171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4197171477Srrs error = EINVAL; 4198171477Srrs break; 4199171477Srrs } 4200188590Srrs if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) { 4201188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 4202185435Sbz break; 4203171477Srrs } 4204185435Sbz#ifdef INET6 4205171477Srrs } else if (addrs->addr->sa_family == AF_INET6) { 4206171477Srrs sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6); 4207171477Srrs if (optsize < sz) { 4208171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4209171477Srrs error = EINVAL; 4210171477Srrs break; 4211171477Srrs } 4212188590Srrs if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr), 4213188590Srrs (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) { 4214188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 4215185435Sbz break; 4216185435Sbz } 4217185435Sbz#endif 4218185435Sbz } else { 4219185435Sbz error = EAFNOSUPPORT; 4220185435Sbz break; 4221171477Srrs } 4222170606Srrs sctp_bindx_add_address(so, inp, addrs->addr, 4223170606Srrs addrs->sget_assoc_id, vrf_id, 4224170606Srrs &error, p); 4225163953Srrs } 4226163953Srrs break; 4227163953Srrs case SCTP_BINDX_REM_ADDR: 4228163953Srrs { 4229163953Srrs struct sctp_getaddresses *addrs; 4230171531Srrs size_t sz; 4231171477Srrs struct thread *td; 4232163953Srrs 4233171477Srrs td = (struct thread *)p; 4234185435Sbz 4235166675Srrs SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize); 4236171477Srrs if (addrs->addr->sa_family == AF_INET) { 4237171477Srrs sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in); 4238171477Srrs if (optsize < sz) { 4239171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4240171477Srrs error = EINVAL; 4241171477Srrs break; 4242171477Srrs } 4243188590Srrs if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) { 4244188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 4245185435Sbz break; 4246171477Srrs } 4247185435Sbz#ifdef INET6 4248171477Srrs } else if (addrs->addr->sa_family == AF_INET6) { 4249171477Srrs sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6); 4250171477Srrs if (optsize < sz) { 4251171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4252171477Srrs error = EINVAL; 4253171477Srrs break; 4254171477Srrs } 4255188590Srrs if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr), 4256188590Srrs (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) { 4257188590Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); 4258185435Sbz break; 4259185435Sbz } 4260185435Sbz#endif 4261185435Sbz } else { 4262185435Sbz error = EAFNOSUPPORT; 4263185435Sbz break; 4264171477Srrs } 4265170606Srrs sctp_bindx_delete_address(so, inp, addrs->addr, 4266170606Srrs addrs->sget_assoc_id, vrf_id, 4267170606Srrs &error); 4268163953Srrs } 4269163953Srrs break; 4270163953Srrs default: 4271171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); 4272163953Srrs error = ENOPROTOOPT; 4273163953Srrs break; 4274163953Srrs } /* end switch (opt) */ 4275163953Srrs return (error); 4276163953Srrs} 4277163953Srrs 4278163953Srrsint 4279163953Srrssctp_ctloutput(struct socket *so, struct sockopt *sopt) 4280163953Srrs{ 4281166675Srrs void *optval = NULL; 4282166675Srrs size_t optsize = 0; 4283163953Srrs struct sctp_inpcb *inp; 4284166675Srrs void *p; 4285166675Srrs int error = 0; 4286163953Srrs 4287163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 4288163953Srrs if (inp == 0) { 4289163953Srrs /* I made the same as TCP since we are not setup? */ 4290171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4291163953Srrs return (ECONNRESET); 4292163953Srrs } 4293163953Srrs if (sopt->sopt_level != IPPROTO_SCTP) { 4294163953Srrs /* wrong proto level... send back up to IP */ 4295163953Srrs#ifdef INET6 4296163953Srrs if (INP_CHECK_SOCKAF(so, AF_INET6)) 4297163953Srrs error = ip6_ctloutput(so, sopt); 4298163953Srrs else 4299163953Srrs#endif /* INET6 */ 4300163953Srrs error = ip_ctloutput(so, sopt); 4301163953Srrs return (error); 4302163953Srrs } 4303166675Srrs optsize = sopt->sopt_valsize; 4304166675Srrs if (optsize) { 4305170091Srrs SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT); 4306166675Srrs if (optval == NULL) { 4307171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS); 4308163953Srrs return (ENOBUFS); 4309163953Srrs } 4310166675Srrs error = sooptcopyin(sopt, optval, optsize, optsize); 4311163953Srrs if (error) { 4312170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 4313163953Srrs goto out; 4314163953Srrs } 4315163953Srrs } 4316166675Srrs p = (void *)sopt->sopt_td; 4317163953Srrs if (sopt->sopt_dir == SOPT_SET) { 4318166675Srrs error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p); 4319163953Srrs } else if (sopt->sopt_dir == SOPT_GET) { 4320166675Srrs error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p); 4321163953Srrs } else { 4322171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4323163953Srrs error = EINVAL; 4324163953Srrs } 4325166675Srrs if ((error == 0) && (optval != NULL)) { 4326166675Srrs error = sooptcopyout(sopt, optval, optsize); 4327170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 4328166675Srrs } else if (optval != NULL) { 4329170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 4330163953Srrs } 4331163953Srrsout: 4332163953Srrs return (error); 4333163953Srrs} 4334163953Srrs 4335163953Srrs 4336163953Srrsstatic int 4337163953Srrssctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p) 4338163953Srrs{ 4339163953Srrs int error = 0; 4340163953Srrs int create_lock_on = 0; 4341167598Srrs uint32_t vrf_id; 4342163953Srrs struct sctp_inpcb *inp; 4343163953Srrs struct sctp_tcb *stcb = NULL; 4344163953Srrs 4345163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 4346163953Srrs if (inp == 0) { 4347163953Srrs /* I made the same as TCP since we are not setup? */ 4348171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4349163953Srrs return (ECONNRESET); 4350163953Srrs } 4351171943Srrs if (addr == NULL) { 4352171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4353170056Srrs return EINVAL; 4354171943Srrs } 4355185435Sbz#ifdef INET6 4356185435Sbz if (addr->sa_family == AF_INET6) { 4357185435Sbz struct sockaddr_in6 *sin6p; 4358185694Srrs 4359185435Sbz if (addr->sa_len != sizeof(struct sockaddr_in6)) { 4360185435Sbz SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4361185435Sbz return (EINVAL); 4362185435Sbz } 4363185435Sbz sin6p = (struct sockaddr_in6 *)addr; 4364188590Srrs if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6p->sin6_addr)) != 0) { 4365188590Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 4366188590Srrs return (error); 4367185435Sbz } 4368185435Sbz } else 4369185435Sbz#endif 4370185435Sbz if (addr->sa_family == AF_INET) { 4371185435Sbz struct sockaddr_in *sinp; 4372185694Srrs 4373185435Sbz if (addr->sa_len != sizeof(struct sockaddr_in)) { 4374185435Sbz SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4375185435Sbz return (EINVAL); 4376185435Sbz } 4377185435Sbz sinp = (struct sockaddr_in *)addr; 4378188590Srrs if (p != NULL && (error = prison_remote_ip4(p->td_ucred, &sinp->sin_addr)) != 0) { 4379188590Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); 4380188590Srrs return (error); 4381185435Sbz } 4382185435Sbz } else { 4383185435Sbz SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT); 4384185435Sbz return (EAFNOSUPPORT); 4385170056Srrs } 4386178202Srrs SCTP_INP_INCR_REF(inp); 4387163953Srrs SCTP_ASOC_CREATE_LOCK(inp); 4388163953Srrs create_lock_on = 1; 4389163953Srrs 4390178202Srrs 4391163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 4392163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 4393163953Srrs /* Should I really unlock ? */ 4394171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); 4395163953Srrs error = EFAULT; 4396163953Srrs goto out_now; 4397163953Srrs } 4398163953Srrs#ifdef INET6 4399163953Srrs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 4400163953Srrs (addr->sa_family == AF_INET6)) { 4401171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4402163953Srrs error = EINVAL; 4403163953Srrs goto out_now; 4404163953Srrs } 4405163953Srrs#endif /* INET6 */ 4406163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 4407163953Srrs SCTP_PCB_FLAGS_UNBOUND) { 4408163953Srrs /* Bind a ephemeral port */ 4409171572Srrs error = sctp_inpcb_bind(so, NULL, NULL, p); 4410163953Srrs if (error) { 4411163953Srrs goto out_now; 4412163953Srrs } 4413163953Srrs } 4414163953Srrs /* Now do we connect? */ 4415181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && 4416181054Srrs (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) { 4417171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4418163953Srrs error = EINVAL; 4419163953Srrs goto out_now; 4420163953Srrs } 4421163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 4422163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 4423163953Srrs /* We are already connected AND the TCP model */ 4424171943Srrs SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 4425163953Srrs error = EADDRINUSE; 4426163953Srrs goto out_now; 4427163953Srrs } 4428163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 4429163953Srrs SCTP_INP_RLOCK(inp); 4430163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 4431163953Srrs SCTP_INP_RUNLOCK(inp); 4432163953Srrs } else { 4433163953Srrs /* 4434166675Srrs * We increment here since sctp_findassociation_ep_addr() 4435181054Srrs * will do a decrement if it finds the stcb as long as the 4436166675Srrs * locked tcb (last argument) is NOT a TCB.. aka NULL. 4437163953Srrs */ 4438163953Srrs SCTP_INP_INCR_REF(inp); 4439163953Srrs stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL); 4440163953Srrs if (stcb == NULL) { 4441163953Srrs SCTP_INP_DECR_REF(inp); 4442168299Srrs } else { 4443178202Srrs SCTP_TCB_UNLOCK(stcb); 4444163953Srrs } 4445163953Srrs } 4446163953Srrs if (stcb != NULL) { 4447163953Srrs /* Already have or am bring up an association */ 4448171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); 4449163953Srrs error = EALREADY; 4450163953Srrs goto out_now; 4451163953Srrs } 4452168299Srrs vrf_id = inp->def_vrf_id; 4453163953Srrs /* We are GOOD to go */ 4454171531Srrs stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0, vrf_id, p); 4455163953Srrs if (stcb == NULL) { 4456163953Srrs /* Gak! no memory */ 4457167598Srrs goto out_now; 4458163953Srrs } 4459163953Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 4460163953Srrs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 4461163953Srrs /* Set the connected flag so we can queue data */ 4462163953Srrs soisconnecting(so); 4463163953Srrs } 4464171943Srrs SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); 4465169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 4466163953Srrs 4467163953Srrs /* initialize authentication parameters for the assoc */ 4468163953Srrs sctp_initialize_auth_params(inp, stcb); 4469163953Srrs 4470172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 4471168299Srrs SCTP_TCB_UNLOCK(stcb); 4472163953Srrsout_now: 4473169420Srrs if (create_lock_on) { 4474163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 4475169420Srrs } 4476163953Srrs SCTP_INP_DECR_REF(inp); 4477163953Srrs return error; 4478163953Srrs} 4479163953Srrs 4480163953Srrsint 4481163953Srrssctp_listen(struct socket *so, int backlog, struct thread *p) 4482163953Srrs{ 4483163953Srrs /* 4484163953Srrs * Note this module depends on the protocol processing being called 4485163953Srrs * AFTER any socket level flags and backlog are applied to the 4486163953Srrs * socket. The traditional way that the socket flags are applied is 4487163953Srrs * AFTER protocol processing. We have made a change to the 4488163953Srrs * sys/kern/uipc_socket.c module to reverse this but this MUST be in 4489163953Srrs * place if the socket API for SCTP is to work properly. 4490163953Srrs */ 4491163953Srrs 4492163953Srrs int error = 0; 4493163953Srrs struct sctp_inpcb *inp; 4494163953Srrs 4495163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 4496163953Srrs if (inp == 0) { 4497163953Srrs /* I made the same as TCP since we are not setup? */ 4498171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4499163953Srrs return (ECONNRESET); 4500163953Srrs } 4501181054Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) { 4502181054Srrs /* See if we have a listener */ 4503181054Srrs struct sctp_inpcb *tinp; 4504181054Srrs union sctp_sockstore store, *sp; 4505181054Srrs 4506181054Srrs sp = &store; 4507181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { 4508181054Srrs /* not bound all */ 4509181054Srrs struct sctp_laddr *laddr; 4510181054Srrs 4511181054Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 4512181054Srrs memcpy(&store, &laddr->ifa->address, sizeof(store)); 4513181054Srrs sp->sin.sin_port = inp->sctp_lport; 4514181054Srrs tinp = sctp_pcb_findep(&sp->sa, 0, 0, inp->def_vrf_id); 4515181054Srrs if (tinp && (tinp != inp) && 4516181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && 4517181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 4518181054Srrs (tinp->sctp_socket->so_qlimit)) { 4519181054Srrs /* 4520181054Srrs * we have a listener already and 4521181054Srrs * its not this inp. 4522181054Srrs */ 4523181054Srrs SCTP_INP_DECR_REF(tinp); 4524181054Srrs return (EADDRINUSE); 4525181054Srrs } else if (tinp) { 4526181054Srrs SCTP_INP_DECR_REF(tinp); 4527181054Srrs } 4528181054Srrs } 4529181054Srrs } else { 4530181054Srrs /* Setup a local addr bound all */ 4531181054Srrs memset(&store, 0, sizeof(store)); 4532181054Srrs store.sin.sin_port = inp->sctp_lport; 4533181054Srrs#ifdef INET6 4534181054Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 4535181054Srrs store.sa.sa_family = AF_INET6; 4536181054Srrs store.sa.sa_len = sizeof(struct sockaddr_in6); 4537181054Srrs } 4538181054Srrs#endif 4539181054Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { 4540181054Srrs store.sa.sa_family = AF_INET; 4541181054Srrs store.sa.sa_len = sizeof(struct sockaddr_in); 4542181054Srrs } 4543181054Srrs tinp = sctp_pcb_findep(&sp->sa, 0, 0, inp->def_vrf_id); 4544181054Srrs if (tinp && (tinp != inp) && 4545181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && 4546181054Srrs ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 4547181054Srrs (tinp->sctp_socket->so_qlimit)) { 4548181054Srrs /* 4549181054Srrs * we have a listener already and its not 4550181054Srrs * this inp. 4551181054Srrs */ 4552181054Srrs SCTP_INP_DECR_REF(tinp); 4553181054Srrs return (EADDRINUSE); 4554181054Srrs } else if (tinp) { 4555181054Srrs SCTP_INP_DECR_REF(inp); 4556181054Srrs } 4557181054Srrs } 4558181054Srrs } 4559163953Srrs SCTP_INP_RLOCK(inp); 4560163953Srrs#ifdef SCTP_LOCK_LOGGING 4561179783Srrs if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) { 4562170744Srrs sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK); 4563170744Srrs } 4564163953Srrs#endif 4565163953Srrs SOCK_LOCK(so); 4566163953Srrs error = solisten_proto_check(so); 4567163953Srrs if (error) { 4568163953Srrs SOCK_UNLOCK(so); 4569169208Srrs SCTP_INP_RUNLOCK(inp); 4570163953Srrs return (error); 4571163953Srrs } 4572181054Srrs if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) && 4573181054Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 4574181054Srrs /* 4575181054Srrs * The unlucky case - We are in the tcp pool with this guy. 4576181054Srrs * - Someone else is in the main inp slot. - We must move 4577181054Srrs * this guy (the listener) to the main slot - We must then 4578181054Srrs * move the guy that was listener to the TCP Pool. 4579181054Srrs */ 4580181054Srrs if (sctp_swap_inpcb_for_listen(inp)) { 4581181054Srrs goto in_use; 4582181054Srrs } 4583181054Srrs } 4584163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 4585163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 4586163953Srrs /* We are already connected AND the TCP model */ 4587181054Srrsin_use: 4588163953Srrs SCTP_INP_RUNLOCK(inp); 4589163953Srrs SOCK_UNLOCK(so); 4590171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); 4591163953Srrs return (EADDRINUSE); 4592163953Srrs } 4593181054Srrs SCTP_INP_RUNLOCK(inp); 4594163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { 4595163953Srrs /* We must do a bind. */ 4596166675Srrs SOCK_UNLOCK(so); 4597171572Srrs if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) { 4598163953Srrs /* bind error, probably perm */ 4599163953Srrs return (error); 4600163953Srrs } 4601166675Srrs SOCK_LOCK(so); 4602163953Srrs } 4603163953Srrs /* It appears for 7.0 and on, we must always call this. */ 4604163953Srrs solisten_proto(so, backlog); 4605163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 4606163953Srrs /* remove the ACCEPTCONN flag for one-to-many sockets */ 4607163953Srrs so->so_options &= ~SO_ACCEPTCONN; 4608163953Srrs } 4609163953Srrs if (backlog == 0) { 4610163953Srrs /* turning off listen */ 4611163953Srrs so->so_options &= ~SO_ACCEPTCONN; 4612163953Srrs } 4613163953Srrs SOCK_UNLOCK(so); 4614163953Srrs return (error); 4615163953Srrs} 4616163953Srrs 4617163953Srrsstatic int sctp_defered_wakeup_cnt = 0; 4618163953Srrs 4619163953Srrsint 4620163953Srrssctp_accept(struct socket *so, struct sockaddr **addr) 4621163953Srrs{ 4622163953Srrs struct sctp_tcb *stcb; 4623163953Srrs struct sctp_inpcb *inp; 4624163953Srrs union sctp_sockstore store; 4625163953Srrs 4626178251Srrs#ifdef INET6 4627163953Srrs int error; 4628163953Srrs 4629178251Srrs#endif 4630163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 4631163953Srrs 4632163953Srrs if (inp == 0) { 4633171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4634163953Srrs return (ECONNRESET); 4635163953Srrs } 4636163953Srrs SCTP_INP_RLOCK(inp); 4637163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 4638168299Srrs SCTP_INP_RUNLOCK(inp); 4639171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); 4640171943Srrs return (EOPNOTSUPP); 4641163953Srrs } 4642163953Srrs if (so->so_state & SS_ISDISCONNECTED) { 4643163953Srrs SCTP_INP_RUNLOCK(inp); 4644171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED); 4645163953Srrs return (ECONNABORTED); 4646163953Srrs } 4647163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 4648163953Srrs if (stcb == NULL) { 4649163953Srrs SCTP_INP_RUNLOCK(inp); 4650171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4651163953Srrs return (ECONNRESET); 4652163953Srrs } 4653163953Srrs SCTP_TCB_LOCK(stcb); 4654163953Srrs SCTP_INP_RUNLOCK(inp); 4655163953Srrs store = stcb->asoc.primary_destination->ro._l_addr; 4656163953Srrs SCTP_TCB_UNLOCK(stcb); 4657178251Srrs switch (store.sa.sa_family) { 4658178251Srrs case AF_INET: 4659178251Srrs { 4660178251Srrs struct sockaddr_in *sin; 4661163953Srrs 4662178251Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 4663178251Srrs sin->sin_family = AF_INET; 4664178251Srrs sin->sin_len = sizeof(*sin); 4665178251Srrs sin->sin_port = ((struct sockaddr_in *)&store)->sin_port; 4666178251Srrs sin->sin_addr = ((struct sockaddr_in *)&store)->sin_addr; 4667178251Srrs *addr = (struct sockaddr *)sin; 4668178251Srrs break; 4669178251Srrs } 4670178251Srrs#ifdef INET6 4671178251Srrs case AF_INET6: 4672178251Srrs { 4673178251Srrs struct sockaddr_in6 *sin6; 4674163953Srrs 4675178251Srrs SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); 4676178251Srrs sin6->sin6_family = AF_INET6; 4677178251Srrs sin6->sin6_len = sizeof(*sin6); 4678178251Srrs sin6->sin6_port = ((struct sockaddr_in6 *)&store)->sin6_port; 4679163953Srrs 4680178251Srrs sin6->sin6_addr = ((struct sockaddr_in6 *)&store)->sin6_addr; 4681178251Srrs if ((error = sa6_recoverscope(sin6)) != 0) { 4682178251Srrs SCTP_FREE_SONAME(sin6); 4683178251Srrs return (error); 4684178251Srrs } 4685178251Srrs *addr = (struct sockaddr *)sin6; 4686178251Srrs break; 4687164085Srrs } 4688178251Srrs#endif 4689178251Srrs default: 4690178251Srrs /* TSNH */ 4691178251Srrs break; 4692163953Srrs } 4693163953Srrs /* Wake any delayed sleep action */ 4694163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { 4695166086Srrs SCTP_INP_WLOCK(inp); 4696163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE; 4697163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) { 4698163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT; 4699166086Srrs SCTP_INP_WUNLOCK(inp); 4700163953Srrs SOCKBUF_LOCK(&inp->sctp_socket->so_snd); 4701163953Srrs if (sowriteable(inp->sctp_socket)) { 4702163953Srrs sowwakeup_locked(inp->sctp_socket); 4703163953Srrs } else { 4704163953Srrs SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd); 4705163953Srrs } 4706166086Srrs SCTP_INP_WLOCK(inp); 4707163953Srrs } 4708163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) { 4709163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT; 4710166086Srrs SCTP_INP_WUNLOCK(inp); 4711163953Srrs SOCKBUF_LOCK(&inp->sctp_socket->so_rcv); 4712163953Srrs if (soreadable(inp->sctp_socket)) { 4713163953Srrs sctp_defered_wakeup_cnt++; 4714163953Srrs sorwakeup_locked(inp->sctp_socket); 4715163953Srrs } else { 4716163953Srrs SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv); 4717163953Srrs } 4718166086Srrs SCTP_INP_WLOCK(inp); 4719163953Srrs } 4720166086Srrs SCTP_INP_WUNLOCK(inp); 4721163953Srrs } 4722163953Srrs return (0); 4723163953Srrs} 4724163953Srrs 4725163953Srrsint 4726163953Srrssctp_ingetaddr(struct socket *so, struct sockaddr **addr) 4727163953Srrs{ 4728163953Srrs struct sockaddr_in *sin; 4729167598Srrs uint32_t vrf_id; 4730163953Srrs struct sctp_inpcb *inp; 4731167695Srrs struct sctp_ifa *sctp_ifa; 4732163953Srrs 4733163953Srrs /* 4734163953Srrs * Do the malloc first in case it blocks. 4735163953Srrs */ 4736163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 4737163953Srrs sin->sin_family = AF_INET; 4738163953Srrs sin->sin_len = sizeof(*sin); 4739163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 4740163953Srrs if (!inp) { 4741163953Srrs SCTP_FREE_SONAME(sin); 4742171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4743163953Srrs return ECONNRESET; 4744163953Srrs } 4745163953Srrs SCTP_INP_RLOCK(inp); 4746163953Srrs sin->sin_port = inp->sctp_lport; 4747163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 4748163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 4749163953Srrs struct sctp_tcb *stcb; 4750163953Srrs struct sockaddr_in *sin_a; 4751163953Srrs struct sctp_nets *net; 4752163953Srrs int fnd; 4753163953Srrs 4754163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 4755163953Srrs if (stcb == NULL) { 4756163953Srrs goto notConn; 4757163953Srrs } 4758163953Srrs fnd = 0; 4759163953Srrs sin_a = NULL; 4760163953Srrs SCTP_TCB_LOCK(stcb); 4761163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4762163953Srrs sin_a = (struct sockaddr_in *)&net->ro._l_addr; 4763164085Srrs if (sin_a == NULL) 4764164085Srrs /* this will make coverity happy */ 4765164085Srrs continue; 4766164085Srrs 4767163953Srrs if (sin_a->sin_family == AF_INET) { 4768163953Srrs fnd = 1; 4769163953Srrs break; 4770163953Srrs } 4771163953Srrs } 4772163953Srrs if ((!fnd) || (sin_a == NULL)) { 4773163953Srrs /* punt */ 4774163953Srrs SCTP_TCB_UNLOCK(stcb); 4775163953Srrs goto notConn; 4776163953Srrs } 4777168299Srrs vrf_id = inp->def_vrf_id; 4778167598Srrs sctp_ifa = sctp_source_address_selection(inp, 4779167598Srrs stcb, 4780168299Srrs (sctp_route_t *) & net->ro, 4781167598Srrs net, 0, vrf_id); 4782167598Srrs if (sctp_ifa) { 4783167598Srrs sin->sin_addr = sctp_ifa->address.sin.sin_addr; 4784167598Srrs sctp_free_ifa(sctp_ifa); 4785167598Srrs } 4786163953Srrs SCTP_TCB_UNLOCK(stcb); 4787163953Srrs } else { 4788163953Srrs /* For the bound all case you get back 0 */ 4789163953Srrs notConn: 4790163953Srrs sin->sin_addr.s_addr = 0; 4791163953Srrs } 4792163953Srrs 4793163953Srrs } else { 4794163953Srrs /* Take the first IPv4 address in the list */ 4795163953Srrs struct sctp_laddr *laddr; 4796163953Srrs int fnd = 0; 4797163953Srrs 4798163953Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 4799167598Srrs if (laddr->ifa->address.sa.sa_family == AF_INET) { 4800163953Srrs struct sockaddr_in *sin_a; 4801163953Srrs 4802167598Srrs sin_a = (struct sockaddr_in *)&laddr->ifa->address.sa; 4803163953Srrs sin->sin_addr = sin_a->sin_addr; 4804163953Srrs fnd = 1; 4805163953Srrs break; 4806163953Srrs } 4807163953Srrs } 4808163953Srrs if (!fnd) { 4809163953Srrs SCTP_FREE_SONAME(sin); 4810163953Srrs SCTP_INP_RUNLOCK(inp); 4811171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4812163953Srrs return ENOENT; 4813163953Srrs } 4814163953Srrs } 4815163953Srrs SCTP_INP_RUNLOCK(inp); 4816163953Srrs (*addr) = (struct sockaddr *)sin; 4817163953Srrs return (0); 4818163953Srrs} 4819163953Srrs 4820163953Srrsint 4821163953Srrssctp_peeraddr(struct socket *so, struct sockaddr **addr) 4822163953Srrs{ 4823163953Srrs struct sockaddr_in *sin = (struct sockaddr_in *)*addr; 4824166086Srrs int fnd; 4825163953Srrs struct sockaddr_in *sin_a; 4826163953Srrs struct sctp_inpcb *inp; 4827163953Srrs struct sctp_tcb *stcb; 4828163953Srrs struct sctp_nets *net; 4829163953Srrs 4830163953Srrs /* Do the malloc first in case it blocks. */ 4831163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 4832163953Srrs if ((inp == NULL) || 4833163953Srrs ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { 4834163953Srrs /* UDP type and listeners will drop out here */ 4835171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); 4836163953Srrs return (ENOTCONN); 4837163953Srrs } 4838163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 4839163953Srrs sin->sin_family = AF_INET; 4840163953Srrs sin->sin_len = sizeof(*sin); 4841163953Srrs 4842163953Srrs /* We must recapture incase we blocked */ 4843163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 4844163953Srrs if (!inp) { 4845163953Srrs SCTP_FREE_SONAME(sin); 4846171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4847163953Srrs return ECONNRESET; 4848163953Srrs } 4849163953Srrs SCTP_INP_RLOCK(inp); 4850163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 4851169420Srrs if (stcb) { 4852163953Srrs SCTP_TCB_LOCK(stcb); 4853169420Srrs } 4854163953Srrs SCTP_INP_RUNLOCK(inp); 4855163953Srrs if (stcb == NULL) { 4856163953Srrs SCTP_FREE_SONAME(sin); 4857171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); 4858163953Srrs return ECONNRESET; 4859163953Srrs } 4860163953Srrs fnd = 0; 4861163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 4862163953Srrs sin_a = (struct sockaddr_in *)&net->ro._l_addr; 4863163953Srrs if (sin_a->sin_family == AF_INET) { 4864163953Srrs fnd = 1; 4865163953Srrs sin->sin_port = stcb->rport; 4866163953Srrs sin->sin_addr = sin_a->sin_addr; 4867163953Srrs break; 4868163953Srrs } 4869163953Srrs } 4870163953Srrs SCTP_TCB_UNLOCK(stcb); 4871163953Srrs if (!fnd) { 4872163953Srrs /* No IPv4 address */ 4873163953Srrs SCTP_FREE_SONAME(sin); 4874171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); 4875163953Srrs return ENOENT; 4876163953Srrs } 4877163953Srrs (*addr) = (struct sockaddr *)sin; 4878163953Srrs return (0); 4879163953Srrs} 4880163953Srrs 4881163953Srrsstruct pr_usrreqs sctp_usrreqs = { 4882163953Srrs .pru_abort = sctp_abort, 4883163953Srrs .pru_accept = sctp_accept, 4884163953Srrs .pru_attach = sctp_attach, 4885163953Srrs .pru_bind = sctp_bind, 4886163953Srrs .pru_connect = sctp_connect, 4887163953Srrs .pru_control = in_control, 4888163953Srrs .pru_close = sctp_close, 4889163953Srrs .pru_detach = sctp_close, 4890163953Srrs .pru_sopoll = sopoll_generic, 4891178202Srrs .pru_flush = sctp_flush, 4892163953Srrs .pru_disconnect = sctp_disconnect, 4893163953Srrs .pru_listen = sctp_listen, 4894163953Srrs .pru_peeraddr = sctp_peeraddr, 4895163953Srrs .pru_send = sctp_sendm, 4896163953Srrs .pru_shutdown = sctp_shutdown, 4897163953Srrs .pru_sockaddr = sctp_ingetaddr, 4898163953Srrs .pru_sosend = sctp_sosend, 4899163953Srrs .pru_soreceive = sctp_soreceive 4900163953Srrs}; 4901