sctp_usrreq.c revision 169420
1163953Srrs/*- 2169382Srrs * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. 3163953Srrs * 4163953Srrs * Redistribution and use in source and binary forms, with or without 5163953Srrs * modification, are permitted provided that the following conditions are met: 6163953Srrs * 7163953Srrs * a) Redistributions of source code must retain the above copyright notice, 8163953Srrs * this list of conditions and the following disclaimer. 9163953Srrs * 10163953Srrs * b) Redistributions in binary form must reproduce the above copyright 11163953Srrs * notice, this list of conditions and the following disclaimer in 12163953Srrs * the documentation and/or other materials provided with the distribution. 13163953Srrs * 14163953Srrs * c) Neither the name of Cisco Systems, Inc. nor the names of its 15163953Srrs * contributors may be used to endorse or promote products derived 16163953Srrs * from this software without specific prior written permission. 17163953Srrs * 18163953Srrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19163953Srrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 20163953Srrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22163953Srrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23163953Srrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24163953Srrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25163953Srrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26163953Srrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27163953Srrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28163953Srrs * THE POSSIBILITY OF SUCH DAMAGE. 29163953Srrs */ 30163953Srrs 31163953Srrs/* $KAME: sctp_usrreq.c,v 1.48 2005/03/07 23:26:08 itojun Exp $ */ 32163953Srrs 33163953Srrs#include <sys/cdefs.h> 34163953Srrs__FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 169420 2007-05-09 13:30:06Z rrs $"); 35166086Srrs#include <netinet/sctp_os.h> 36163953Srrs#include <sys/proc.h> 37163953Srrs#include <netinet/sctp_pcb.h> 38163953Srrs#include <netinet/sctp_header.h> 39163953Srrs#include <netinet/sctp_var.h> 40167695Srrs#if defined(INET6) 41167695Srrs#include <netinet6/sctp6_var.h> 42167695Srrs#endif 43167598Srrs#include <netinet/sctp_sysctl.h> 44163953Srrs#include <netinet/sctp_output.h> 45163953Srrs#include <netinet/sctp_uio.h> 46163953Srrs#include <netinet/sctp_asconf.h> 47163953Srrs#include <netinet/sctputil.h> 48163953Srrs#include <netinet/sctp_indata.h> 49163953Srrs#include <netinet/sctp_timer.h> 50163953Srrs#include <netinet/sctp_auth.h> 51164085Srrs 52163953Srrs 53163953Srrs 54163953Srrsvoid 55163953Srrssctp_init(void) 56163953Srrs{ 57163953Srrs /* Init the SCTP pcb in sctp_pcb.c */ 58163953Srrs u_long sb_max_adj; 59163953Srrs 60163953Srrs sctp_pcb_init(); 61163953Srrs 62163953Srrs if ((nmbclusters / 8) > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE) 63163953Srrs sctp_max_chunks_on_queue = (nmbclusters / 8); 64163953Srrs /* 65163953Srrs * Allow a user to take no more than 1/2 the number of clusters or 66163953Srrs * the SB_MAX whichever is smaller for the send window. 67163953Srrs */ 68163953Srrs sb_max_adj = (u_long)((u_quad_t) (SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES)); 69163953Srrs sctp_sendspace = min((min(SB_MAX, sb_max_adj)), 70163953Srrs ((nmbclusters / 2) * SCTP_DEFAULT_MAXSEGMENT)); 71163953Srrs /* 72163953Srrs * Now for the recv window, should we take the same amount? or 73163953Srrs * should I do 1/2 the SB_MAX instead in the SB_MAX min above. For 74163953Srrs * now I will just copy. 75163953Srrs */ 76163953Srrs sctp_recvspace = sctp_sendspace; 77163953Srrs 78163953Srrs 79163953Srrs} 80163953Srrs 81163953Srrs 82166023Srrs 83166023Srrs/* 84166023Srrs * cleanup of the sctppcbinfo structure. 85166023Srrs * Assumes that the sctppcbinfo lock is held. 86166023Srrs */ 87166023Srrsvoid 88166023Srrssctp_pcbinfo_cleanup(void) 89166023Srrs{ 90166023Srrs /* free the hash tables */ 91166023Srrs if (sctppcbinfo.sctp_asochash != NULL) 92166023Srrs SCTP_HASH_FREE(sctppcbinfo.sctp_asochash, sctppcbinfo.hashasocmark); 93166023Srrs if (sctppcbinfo.sctp_ephash != NULL) 94166023Srrs SCTP_HASH_FREE(sctppcbinfo.sctp_ephash, sctppcbinfo.hashmark); 95166023Srrs if (sctppcbinfo.sctp_tcpephash != NULL) 96166023Srrs SCTP_HASH_FREE(sctppcbinfo.sctp_tcpephash, sctppcbinfo.hashtcpmark); 97166023Srrs if (sctppcbinfo.sctp_restarthash != NULL) 98166023Srrs SCTP_HASH_FREE(sctppcbinfo.sctp_restarthash, sctppcbinfo.hashrestartmark); 99166023Srrs} 100166023Srrs 101163953Srrs 102163953Srrsstatic void 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; 109163953Srrs 110163953Srrs /* Adjust that too */ 111163953Srrs stcb->asoc.smallest_mtu = nxtsz; 112163953Srrs /* now off to subtract IP_DF flag if needed */ 113169352Srrs#ifdef SCTP_PRINT_FOR_B_AND_M 114169420Srrs SCTP_PRINTF("sctp_pathmtu_adjust called inp:%p stcb:%p net:%p nxtsz:%d\n", 115169352Srrs inp, stcb, net, nxtsz); 116169352Srrs#endif 117163953Srrs TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) { 118163953Srrs if ((chk->send_size + IP_HDR_SIZE) > nxtsz) { 119163953Srrs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 120163953Srrs } 121163953Srrs } 122163953Srrs TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 123163953Srrs if ((chk->send_size + IP_HDR_SIZE) > nxtsz) { 124163953Srrs /* 125163953Srrs * For this guy we also mark for immediate resend 126163953Srrs * since we sent to big of chunk 127163953Srrs */ 128163953Srrs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 129163953Srrs if (chk->sent != SCTP_DATAGRAM_RESEND) { 130163953Srrs sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 131163953Srrs } 132163953Srrs chk->sent = SCTP_DATAGRAM_RESEND; 133163953Srrs chk->rec.data.doing_fast_retransmit = 0; 134168709Srrs#ifdef SCTP_FLIGHT_LOGGING 135168709Srrs sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU, 136168709Srrs chk->whoTo->flight_size, 137168709Srrs chk->book_size, 138168709Srrs (uintptr_t) chk->whoTo, 139168709Srrs chk->rec.data.TSN_seq); 140168709Srrs#endif 141163953Srrs /* Clear any time so NO RTT is being done */ 142163953Srrs chk->do_rtt = 0; 143168709Srrs sctp_flight_size_decrease(chk); 144168709Srrs sctp_total_flight_decrease(stcb, chk); 145163953Srrs } 146163953Srrs } 147163953Srrs} 148163953Srrs 149163953Srrsstatic void 150163953Srrssctp_notify_mbuf(struct sctp_inpcb *inp, 151163953Srrs struct sctp_tcb *stcb, 152163953Srrs struct sctp_nets *net, 153163953Srrs struct ip *ip, 154163953Srrs struct sctphdr *sh) 155163953Srrs{ 156163953Srrs struct icmp *icmph; 157163953Srrs int totsz, tmr_stopped = 0; 158163953Srrs uint16_t nxtsz; 159163953Srrs 160163953Srrs /* protection */ 161163953Srrs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 162163953Srrs (ip == NULL) || (sh == NULL)) { 163169420Srrs if (stcb != NULL) { 164163953Srrs SCTP_TCB_UNLOCK(stcb); 165169420Srrs } 166163953Srrs return; 167163953Srrs } 168163953Srrs /* First job is to verify the vtag matches what I would send */ 169163953Srrs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 170163953Srrs SCTP_TCB_UNLOCK(stcb); 171163953Srrs return; 172163953Srrs } 173163953Srrs icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) - 174163953Srrs sizeof(struct ip))); 175163953Srrs if (icmph->icmp_type != ICMP_UNREACH) { 176163953Srrs /* We only care about unreachable */ 177163953Srrs SCTP_TCB_UNLOCK(stcb); 178163953Srrs return; 179163953Srrs } 180163953Srrs if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) { 181163953Srrs /* not a unreachable message due to frag. */ 182163953Srrs SCTP_TCB_UNLOCK(stcb); 183163953Srrs return; 184163953Srrs } 185163953Srrs totsz = ip->ip_len; 186163953Srrs 187163953Srrs nxtsz = ntohs(icmph->icmp_seq); 188163953Srrs if (nxtsz == 0) { 189163953Srrs /* 190163953Srrs * old type router that does not tell us what the next size 191163953Srrs * mtu is. Rats we will have to guess (in a educated fashion 192163953Srrs * of course) 193163953Srrs */ 194163953Srrs nxtsz = find_next_best_mtu(totsz); 195163953Srrs } 196163953Srrs /* Stop any PMTU timer */ 197165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 198163953Srrs tmr_stopped = 1; 199165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 200165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1); 201163953Srrs } 202163953Srrs /* Adjust destination size limit */ 203163953Srrs if (net->mtu > nxtsz) { 204163953Srrs net->mtu = nxtsz; 205163953Srrs } 206163953Srrs /* now what about the ep? */ 207163953Srrs if (stcb->asoc.smallest_mtu > nxtsz) { 208169352Srrs#ifdef SCTP_PRINT_FOR_B_AND_M 209169420Srrs SCTP_PRINTF("notify_mbuf (ICMP) calls sctp_pathmtu_adjust mtu:%d\n", 210169352Srrs nxtsz); 211169352Srrs#endif 212167695Srrs sctp_pathmtu_adjustment(inp, stcb, net, nxtsz); 213163953Srrs } 214163953Srrs if (tmr_stopped) 215163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 216163953Srrs 217163953Srrs SCTP_TCB_UNLOCK(stcb); 218163953Srrs} 219163953Srrs 220163953Srrs 221163953Srrsvoid 222163953Srrssctp_notify(struct sctp_inpcb *inp, 223167695Srrs int error, 224163953Srrs struct sctphdr *sh, 225163953Srrs struct sockaddr *to, 226163953Srrs struct sctp_tcb *stcb, 227163953Srrs struct sctp_nets *net) 228163953Srrs{ 229163953Srrs /* protection */ 230163953Srrs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 231163953Srrs (sh == NULL) || (to == NULL)) { 232163953Srrs return; 233163953Srrs } 234163953Srrs /* First job is to verify the vtag matches what I would send */ 235163953Srrs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 236163953Srrs return; 237163953Srrs } 238163953Srrs /* FIX ME FIX ME PROTOPT i.e. no SCTP should ALWAYS be an ABORT */ 239163953Srrs 240167695Srrs if ((error == EHOSTUNREACH) || /* Host is not reachable */ 241167695Srrs (error == EHOSTDOWN) || /* Host is down */ 242167695Srrs (error == ECONNREFUSED) || /* Host refused the connection, (not 243163953Srrs * an abort?) */ 244167695Srrs (error == ENOPROTOOPT) /* SCTP is not present on host */ 245163953Srrs ) { 246163953Srrs /* 247163953Srrs * Hmm reachablity problems we must examine closely. If its 248163953Srrs * not reachable, we may have lost a network. Or if there is 249163953Srrs * NO protocol at the other end named SCTP. well we consider 250163953Srrs * it a OOTB abort. 251163953Srrs */ 252167695Srrs if ((error == EHOSTUNREACH) || (error == EHOSTDOWN)) { 253163953Srrs if (net->dest_state & SCTP_ADDR_REACHABLE) { 254163953Srrs /* Ok that destination is NOT reachable */ 255169420Srrs SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n", 256167598Srrs net->error_count, 257167598Srrs net->failure_threshold, 258167598Srrs net); 259167598Srrs 260163953Srrs net->dest_state &= ~SCTP_ADDR_REACHABLE; 261163953Srrs net->dest_state |= SCTP_ADDR_NOT_REACHABLE; 262163953Srrs net->error_count = net->failure_threshold + 1; 263163953Srrs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, 264163953Srrs stcb, SCTP_FAILED_THRESHOLD, 265163953Srrs (void *)net); 266163953Srrs } 267169420Srrs if (stcb) { 268163953Srrs SCTP_TCB_UNLOCK(stcb); 269169420Srrs } 270163953Srrs } else { 271163953Srrs /* 272163953Srrs * Here the peer is either playing tricks on us, 273163953Srrs * including an address that belongs to someone who 274163953Srrs * does not support SCTP OR was a userland 275163953Srrs * implementation that shutdown and now is dead. In 276163953Srrs * either case treat it like a OOTB abort with no 277163953Srrs * TCB 278163953Srrs */ 279163953Srrs sctp_abort_notification(stcb, SCTP_PEER_FAULTY); 280165220Srrs sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); 281163953Srrs /* no need to unlock here, since the TCB is gone */ 282163953Srrs } 283163953Srrs } else { 284163953Srrs /* Send all others to the app */ 285169420Srrs if (stcb) { 286163953Srrs SCTP_TCB_UNLOCK(stcb); 287169420Srrs } 288163953Srrs if (inp->sctp_socket) { 289163953Srrs#ifdef SCTP_LOCK_LOGGING 290163953Srrs sctp_log_lock(inp, stcb, SCTP_LOG_LOCK_SOCK); 291163953Srrs#endif 292163953Srrs SOCK_LOCK(inp->sctp_socket); 293167695Srrs inp->sctp_socket->so_error = error; 294163953Srrs sctp_sowwakeup(inp, inp->sctp_socket); 295163953Srrs SOCK_UNLOCK(inp->sctp_socket); 296163953Srrs } 297163953Srrs } 298163953Srrs} 299163953Srrs 300163953Srrsvoid 301163953Srrssctp_ctlinput(cmd, sa, vip) 302163953Srrs int cmd; 303163953Srrs struct sockaddr *sa; 304163953Srrs void *vip; 305163953Srrs{ 306163953Srrs struct ip *ip = vip; 307163953Srrs struct sctphdr *sh; 308167598Srrs uint32_t vrf_id; 309163953Srrs 310168299Srrs /* FIX, for non-bsd is this right? */ 311167598Srrs vrf_id = SCTP_DEFAULT_VRFID; 312163953Srrs if (sa->sa_family != AF_INET || 313163953Srrs ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) { 314163953Srrs return; 315163953Srrs } 316163953Srrs if (PRC_IS_REDIRECT(cmd)) { 317163953Srrs ip = 0; 318163953Srrs } else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) { 319163953Srrs return; 320163953Srrs } 321163953Srrs if (ip) { 322163953Srrs struct sctp_inpcb *inp = NULL; 323163953Srrs struct sctp_tcb *stcb = NULL; 324163953Srrs struct sctp_nets *net = NULL; 325163953Srrs struct sockaddr_in to, from; 326163953Srrs 327163953Srrs sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 328163953Srrs bzero(&to, sizeof(to)); 329163953Srrs bzero(&from, sizeof(from)); 330163953Srrs from.sin_family = to.sin_family = AF_INET; 331163953Srrs from.sin_len = to.sin_len = sizeof(to); 332163953Srrs from.sin_port = sh->src_port; 333163953Srrs from.sin_addr = ip->ip_src; 334163953Srrs to.sin_port = sh->dest_port; 335163953Srrs to.sin_addr = ip->ip_dst; 336163953Srrs 337163953Srrs /* 338163953Srrs * 'to' holds the dest of the packet that failed to be sent. 339163953Srrs * 'from' holds our local endpoint address. Thus we reverse 340163953Srrs * the to and the from in the lookup. 341163953Srrs */ 342163953Srrs stcb = sctp_findassociation_addr_sa((struct sockaddr *)&from, 343163953Srrs (struct sockaddr *)&to, 344167598Srrs &inp, &net, 1, vrf_id); 345163953Srrs if (stcb != NULL && inp && (inp->sctp_socket != NULL)) { 346163953Srrs if (cmd != PRC_MSGSIZE) { 347163953Srrs int cm; 348163953Srrs 349163953Srrs if (cmd == PRC_HOSTDEAD) { 350163953Srrs cm = EHOSTUNREACH; 351163953Srrs } else { 352163953Srrs cm = inetctlerrmap[cmd]; 353163953Srrs } 354163953Srrs sctp_notify(inp, cm, sh, 355163953Srrs (struct sockaddr *)&to, stcb, 356163953Srrs net); 357163953Srrs } else { 358163953Srrs /* handle possible ICMP size messages */ 359163953Srrs sctp_notify_mbuf(inp, stcb, net, ip, sh); 360163953Srrs } 361163953Srrs } else { 362163953Srrs if ((stcb == NULL) && (inp != NULL)) { 363163953Srrs /* reduce ref-count */ 364163953Srrs SCTP_INP_WLOCK(inp); 365163953Srrs SCTP_INP_DECR_REF(inp); 366163953Srrs SCTP_INP_WUNLOCK(inp); 367163953Srrs } 368163953Srrs } 369163953Srrs } 370163953Srrs return; 371163953Srrs} 372163953Srrs 373163953Srrsstatic int 374163953Srrssctp_getcred(SYSCTL_HANDLER_ARGS) 375163953Srrs{ 376164085Srrs struct xucred xuc; 377163953Srrs struct sockaddr_in addrs[2]; 378163953Srrs struct sctp_inpcb *inp; 379163953Srrs struct sctp_nets *net; 380163953Srrs struct sctp_tcb *stcb; 381164085Srrs int error; 382167598Srrs uint32_t vrf_id; 383163953Srrs 384168299Srrs 385168299Srrs /* FIX, for non-bsd is this right? */ 386167598Srrs vrf_id = SCTP_DEFAULT_VRFID; 387168299Srrs 388164039Srwatson /* 389164039Srwatson * XXXRW: Other instances of getcred use SUSER_ALLOWJAIL, as socket 390164039Srwatson * visibility is scoped using cr_canseesocket(), which it is not 391164039Srwatson * here. 392164039Srwatson */ 393167598Srrs error = priv_check_cred(req->td->td_ucred, PRIV_NETINET_GETCRED, 394167598Srrs SUSER_ALLOWJAIL); 395163953Srrs if (error) 396163953Srrs return (error); 397164039Srwatson 398163953Srrs error = SYSCTL_IN(req, addrs, sizeof(addrs)); 399163953Srrs if (error) 400163953Srrs return (error); 401163953Srrs 402163953Srrs stcb = sctp_findassociation_addr_sa(sintosa(&addrs[0]), 403163953Srrs sintosa(&addrs[1]), 404167598Srrs &inp, &net, 1, vrf_id); 405163953Srrs if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) { 406163953Srrs if ((inp != NULL) && (stcb == NULL)) { 407163953Srrs /* reduce ref-count */ 408163953Srrs SCTP_INP_WLOCK(inp); 409163953Srrs SCTP_INP_DECR_REF(inp); 410164085Srrs goto cred_can_cont; 411163953Srrs } 412163953Srrs error = ENOENT; 413163953Srrs goto out; 414163953Srrs } 415163953Srrs SCTP_TCB_UNLOCK(stcb); 416164085Srrs /* 417164085Srrs * We use the write lock here, only since in the error leg we need 418164085Srrs * it. If we used RLOCK, then we would have to 419164085Srrs * wlock/decr/unlock/rlock. Which in theory could create a hole. 420164085Srrs * Better to use higher wlock. 421164085Srrs */ 422164085Srrs SCTP_INP_WLOCK(inp); 423164085Srrscred_can_cont: 424164085Srrs error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket); 425164085Srrs if (error) { 426164085Srrs SCTP_INP_WUNLOCK(inp); 427164085Srrs goto out; 428164085Srrs } 429164085Srrs cru2x(inp->sctp_socket->so_cred, &xuc); 430164085Srrs SCTP_INP_WUNLOCK(inp); 431164085Srrs error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); 432163953Srrsout: 433163953Srrs return (error); 434163953Srrs} 435163953Srrs 436163953SrrsSYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW, 437163953Srrs 0, 0, sctp_getcred, "S,ucred", "Get the ucred of a SCTP connection"); 438163953Srrs 439163953Srrs 440163953Srrsstatic void 441163953Srrssctp_abort(struct socket *so) 442163953Srrs{ 443163953Srrs struct sctp_inpcb *inp; 444163953Srrs uint32_t flags; 445163953Srrs 446163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 447163953Srrs if (inp == 0) 448163953Srrs return; 449163953Srrs 450163953Srrssctp_must_try_again: 451163953Srrs flags = inp->sctp_flags; 452163953Srrs#ifdef SCTP_LOG_CLOSING 453163953Srrs sctp_log_closing(inp, NULL, 17); 454163953Srrs#endif 455163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 456163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 457163953Srrs#ifdef SCTP_LOG_CLOSING 458163953Srrs sctp_log_closing(inp, NULL, 16); 459163953Srrs#endif 460169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 461169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 462163953Srrs SOCK_LOCK(so); 463167695Srrs SCTP_SB_CLEAR(so->so_snd); 464163953Srrs /* 465163953Srrs * same for the rcv ones, they are only here for the 466163953Srrs * accounting/select. 467163953Srrs */ 468167695Srrs SCTP_SB_CLEAR(so->so_rcv); 469167695Srrs 470167695Srrs /* Now null out the reference, we are completely detached. */ 471163953Srrs so->so_pcb = NULL; 472163953Srrs SOCK_UNLOCK(so); 473163953Srrs } else { 474163953Srrs flags = inp->sctp_flags; 475163953Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 476163953Srrs goto sctp_must_try_again; 477163953Srrs } 478163953Srrs } 479163953Srrs return; 480163953Srrs} 481163953Srrs 482163953Srrsstatic int 483163953Srrssctp_attach(struct socket *so, int proto, struct thread *p) 484163953Srrs{ 485163953Srrs struct sctp_inpcb *inp; 486163953Srrs struct inpcb *ip_inp; 487166086Srrs int error; 488163953Srrs 489163953Srrs#ifdef IPSEC 490163953Srrs uint32_t flags; 491163953Srrs 492163953Srrs#endif 493163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 494163953Srrs if (inp != 0) { 495163953Srrs return EINVAL; 496163953Srrs } 497167695Srrs error = SCTP_SORESERVE(so, sctp_sendspace, sctp_recvspace); 498163953Srrs if (error) { 499163953Srrs return error; 500163953Srrs } 501163953Srrs error = sctp_inpcb_alloc(so); 502163953Srrs if (error) { 503163953Srrs return error; 504163953Srrs } 505163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 506163953Srrs SCTP_INP_WLOCK(inp); 507163953Srrs 508163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6; /* I'm not v6! */ 509163953Srrs ip_inp = &inp->ip_inp.inp; 510163953Srrs ip_inp->inp_vflag |= INP_IPV4; 511163953Srrs ip_inp->inp_ip_ttl = ip_defttl; 512163953Srrs 513163953Srrs#ifdef IPSEC 514163953Srrs error = ipsec_init_pcbpolicy(so, &ip_inp->inp_sp); 515163953Srrs#ifdef SCTP_LOG_CLOSING 516163953Srrs sctp_log_closing(inp, NULL, 17); 517163953Srrs#endif 518163953Srrs if (error != 0) { 519163953Srrs flags = inp->sctp_flags; 520163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 521163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 522163953Srrs#ifdef SCTP_LOG_CLOSING 523163953Srrs sctp_log_closing(inp, NULL, 15); 524163953Srrs#endif 525169352Srrs SCTP_INP_WUNLOCK(inp); 526169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 527169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 528169254Srrs } else { 529169352Srrs SCTP_INP_WUNLOCK(inp); 530163953Srrs } 531163953Srrs return error; 532163953Srrs } 533163953Srrs#endif /* IPSEC */ 534163953Srrs SCTP_INP_WUNLOCK(inp); 535163953Srrs return 0; 536163953Srrs} 537163953Srrs 538163953Srrsstatic int 539163953Srrssctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p) 540163953Srrs{ 541163953Srrs struct sctp_inpcb *inp; 542166086Srrs int error; 543163953Srrs 544163953Srrs#ifdef INET6 545163953Srrs if (addr && addr->sa_family != AF_INET) 546163953Srrs /* must be a v4 address! */ 547163953Srrs return EINVAL; 548163953Srrs#endif /* INET6 */ 549163953Srrs 550163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 551163953Srrs if (inp == 0) 552163953Srrs return EINVAL; 553163953Srrs 554163953Srrs error = sctp_inpcb_bind(so, addr, p); 555163953Srrs return error; 556163953Srrs} 557163953Srrs 558163953Srrsstatic void 559163953Srrssctp_close(struct socket *so) 560163953Srrs{ 561163953Srrs struct sctp_inpcb *inp; 562163953Srrs uint32_t flags; 563163953Srrs 564163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 565163953Srrs if (inp == 0) 566163953Srrs return; 567163953Srrs 568163953Srrs /* 569163953Srrs * Inform all the lower layer assoc that we are done. 570163953Srrs */ 571163953Srrssctp_must_try_again: 572163953Srrs flags = inp->sctp_flags; 573163953Srrs#ifdef SCTP_LOG_CLOSING 574163953Srrs sctp_log_closing(inp, NULL, 17); 575163953Srrs#endif 576163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 577163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 578163953Srrs if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || 579163953Srrs (so->so_rcv.sb_cc > 0)) { 580163953Srrs#ifdef SCTP_LOG_CLOSING 581163953Srrs sctp_log_closing(inp, NULL, 13); 582163953Srrs#endif 583169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 584169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 585163953Srrs } else { 586163953Srrs#ifdef SCTP_LOG_CLOSING 587163953Srrs sctp_log_closing(inp, NULL, 14); 588163953Srrs#endif 589169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE, 590169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 591163953Srrs } 592163953Srrs /* 593163953Srrs * The socket is now detached, no matter what the state of 594163953Srrs * the SCTP association. 595163953Srrs */ 596163953Srrs SOCK_LOCK(so); 597167695Srrs SCTP_SB_CLEAR(so->so_snd); 598163953Srrs /* 599163953Srrs * same for the rcv ones, they are only here for the 600163953Srrs * accounting/select. 601163953Srrs */ 602167695Srrs SCTP_SB_CLEAR(so->so_rcv); 603167695Srrs 604167695Srrs /* Now null out the reference, we are completely detached. */ 605163953Srrs so->so_pcb = NULL; 606163953Srrs SOCK_UNLOCK(so); 607163953Srrs } else { 608163953Srrs flags = inp->sctp_flags; 609163953Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 610163953Srrs goto sctp_must_try_again; 611163953Srrs } 612163953Srrs } 613163953Srrs return; 614163953Srrs} 615163953Srrs 616163953Srrs 617163953Srrsint 618163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 619163953Srrs struct mbuf *control, struct thread *p); 620163953Srrs 621163953Srrs 622163953Srrsint 623163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 624163953Srrs struct mbuf *control, struct thread *p) 625163953Srrs{ 626163953Srrs struct sctp_inpcb *inp; 627163953Srrs int error; 628163953Srrs 629163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 630163953Srrs if (inp == 0) { 631163953Srrs if (control) { 632163953Srrs sctp_m_freem(control); 633163953Srrs control = NULL; 634163953Srrs } 635163953Srrs sctp_m_freem(m); 636163953Srrs return EINVAL; 637163953Srrs } 638163953Srrs /* Got to have an to address if we are NOT a connected socket */ 639163953Srrs if ((addr == NULL) && 640163953Srrs ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) || 641163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)) 642163953Srrs ) { 643163953Srrs goto connected_type; 644163953Srrs } else if (addr == NULL) { 645163953Srrs error = EDESTADDRREQ; 646163953Srrs sctp_m_freem(m); 647163953Srrs if (control) { 648163953Srrs sctp_m_freem(control); 649163953Srrs control = NULL; 650163953Srrs } 651163953Srrs return (error); 652163953Srrs } 653163953Srrs#ifdef INET6 654163953Srrs if (addr->sa_family != AF_INET) { 655163953Srrs /* must be a v4 address! */ 656163953Srrs sctp_m_freem(m); 657163953Srrs if (control) { 658163953Srrs sctp_m_freem(control); 659163953Srrs control = NULL; 660163953Srrs } 661163953Srrs error = EDESTADDRREQ; 662163953Srrs return EINVAL; 663163953Srrs } 664163953Srrs#endif /* INET6 */ 665163953Srrsconnected_type: 666163953Srrs /* now what about control */ 667163953Srrs if (control) { 668163953Srrs if (inp->control) { 669169420Srrs SCTP_PRINTF("huh? control set?\n"); 670163953Srrs sctp_m_freem(inp->control); 671163953Srrs inp->control = NULL; 672163953Srrs } 673163953Srrs inp->control = control; 674163953Srrs } 675163953Srrs /* Place the data */ 676163953Srrs if (inp->pkt) { 677165647Srrs SCTP_BUF_NEXT(inp->pkt_last) = m; 678163953Srrs inp->pkt_last = m; 679163953Srrs } else { 680163953Srrs inp->pkt_last = inp->pkt = m; 681163953Srrs } 682163953Srrs if ( 683163953Srrs /* FreeBSD uses a flag passed */ 684163953Srrs ((flags & PRUS_MORETOCOME) == 0) 685163953Srrs ) { 686163953Srrs /* 687163953Srrs * note with the current version this code will only be used 688163953Srrs * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for 689163953Srrs * re-defining sosend to use the sctp_sosend. One can 690163953Srrs * optionally switch back to this code (by changing back the 691163953Srrs * definitions) but this is not advisable. This code is used 692163953Srrs * by FreeBSD when sending a file with sendfile() though. 693163953Srrs */ 694163953Srrs int ret; 695163953Srrs 696163953Srrs ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags); 697163953Srrs inp->pkt = NULL; 698163953Srrs inp->control = NULL; 699163953Srrs return (ret); 700163953Srrs } else { 701163953Srrs return (0); 702163953Srrs } 703163953Srrs} 704163953Srrs 705163953Srrsstatic int 706163953Srrssctp_disconnect(struct socket *so) 707163953Srrs{ 708163953Srrs struct sctp_inpcb *inp; 709163953Srrs 710163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 711163953Srrs if (inp == NULL) { 712163953Srrs return (ENOTCONN); 713163953Srrs } 714163953Srrs SCTP_INP_RLOCK(inp); 715163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 716166675Srrs if (SCTP_LIST_EMPTY(&inp->sctp_asoc_list)) { 717163953Srrs /* No connection */ 718163953Srrs SCTP_INP_RUNLOCK(inp); 719163953Srrs return (0); 720163953Srrs } else { 721163953Srrs struct sctp_association *asoc; 722163953Srrs struct sctp_tcb *stcb; 723163953Srrs 724163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 725163953Srrs if (stcb == NULL) { 726163953Srrs SCTP_INP_RUNLOCK(inp); 727163953Srrs return (EINVAL); 728163953Srrs } 729163953Srrs SCTP_TCB_LOCK(stcb); 730163953Srrs asoc = &stcb->asoc; 731163953Srrs if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 732163953Srrs /* We are about to be freed, out of here */ 733163953Srrs SCTP_TCB_UNLOCK(stcb); 734163953Srrs SCTP_INP_RUNLOCK(inp); 735163953Srrs return (0); 736163953Srrs } 737163953Srrs if (((so->so_options & SO_LINGER) && 738163953Srrs (so->so_linger == 0)) || 739163953Srrs (so->so_rcv.sb_cc > 0)) { 740163953Srrs if (SCTP_GET_STATE(asoc) != 741163953Srrs SCTP_STATE_COOKIE_WAIT) { 742163953Srrs /* Left with Data unread */ 743163953Srrs struct mbuf *err; 744163953Srrs 745163953Srrs err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_DONTWAIT, 1, MT_DATA); 746163953Srrs if (err) { 747163953Srrs /* 748163953Srrs * Fill in the user 749163953Srrs * initiated abort 750163953Srrs */ 751163953Srrs struct sctp_paramhdr *ph; 752163953Srrs 753163953Srrs ph = mtod(err, struct sctp_paramhdr *); 754165647Srrs SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr); 755163953Srrs ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); 756165647Srrs ph->param_length = htons(SCTP_BUF_LEN(err)); 757163953Srrs } 758163953Srrs sctp_send_abort_tcb(stcb, err); 759163953Srrs SCTP_STAT_INCR_COUNTER32(sctps_aborted); 760163953Srrs } 761163953Srrs SCTP_INP_RUNLOCK(inp); 762163953Srrs if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 763163953Srrs (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 764163953Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 765163953Srrs } 766165220Srrs sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3); 767163953Srrs /* No unlock tcb assoc is gone */ 768163953Srrs return (0); 769163953Srrs } 770163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 771163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 772163953Srrs (asoc->stream_queue_cnt == 0)) { 773163953Srrs /* there is nothing queued to send, so done */ 774163953Srrs if (asoc->locked_on_sending) { 775163953Srrs goto abort_anyway; 776163953Srrs } 777166675Srrs if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) && 778166675Srrs (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { 779163953Srrs /* only send SHUTDOWN 1st time thru */ 780163953Srrs sctp_stop_timers_for_shutdown(stcb); 781163953Srrs sctp_send_shutdown(stcb, 782163953Srrs stcb->asoc.primary_destination); 783163953Srrs sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3); 784166675Srrs if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 785166675Srrs (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 786166675Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 787166675Srrs } 788163953Srrs asoc->state = SCTP_STATE_SHUTDOWN_SENT; 789163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 790163953Srrs stcb->sctp_ep, stcb, 791163953Srrs asoc->primary_destination); 792163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 793163953Srrs stcb->sctp_ep, stcb, 794163953Srrs asoc->primary_destination); 795163953Srrs } 796163953Srrs } else { 797163953Srrs /* 798163953Srrs * we still got (or just got) data to send, 799163953Srrs * so set SHUTDOWN_PENDING 800163953Srrs */ 801163953Srrs /* 802163953Srrs * XXX sockets draft says that SCTP_EOF 803163953Srrs * should be sent with no data. currently, 804163953Srrs * we will allow user data to be sent first 805163953Srrs * and move to SHUTDOWN-PENDING 806163953Srrs */ 807163953Srrs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 808163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, 809163953Srrs asoc->primary_destination); 810163953Srrs if (asoc->locked_on_sending) { 811163953Srrs /* Locked to send out the data */ 812163953Srrs struct sctp_stream_queue_pending *sp; 813163953Srrs 814163953Srrs sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); 815163953Srrs if (sp == NULL) { 816169420Srrs SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", 817163953Srrs asoc->locked_on_sending->stream_no); 818163953Srrs } else { 819163953Srrs if ((sp->length == 0) && (sp->msg_is_complete == 0)) 820163953Srrs asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; 821163953Srrs } 822163953Srrs } 823163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 824163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 825163953Srrs (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 826163953Srrs struct mbuf *op_err; 827163953Srrs 828163953Srrs abort_anyway: 829163953Srrs op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 830163953Srrs 0, M_DONTWAIT, 1, MT_DATA); 831163953Srrs if (op_err) { 832163953Srrs /* 833163953Srrs * Fill in the user 834163953Srrs * initiated abort 835163953Srrs */ 836163953Srrs struct sctp_paramhdr *ph; 837163953Srrs uint32_t *ippp; 838163953Srrs 839165647Srrs SCTP_BUF_LEN(op_err) = 840163953Srrs (sizeof(struct sctp_paramhdr) + sizeof(uint32_t)); 841163953Srrs ph = mtod(op_err, 842163953Srrs struct sctp_paramhdr *); 843163953Srrs ph->param_type = htons( 844163953Srrs SCTP_CAUSE_USER_INITIATED_ABT); 845165647Srrs ph->param_length = htons(SCTP_BUF_LEN(op_err)); 846163953Srrs ippp = (uint32_t *) (ph + 1); 847165220Srrs *ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4); 848163953Srrs } 849165220Srrs stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4; 850163953Srrs sctp_send_abort_tcb(stcb, op_err); 851163953Srrs SCTP_STAT_INCR_COUNTER32(sctps_aborted); 852163953Srrs if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 853163953Srrs (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 854163953Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 855163953Srrs } 856163953Srrs SCTP_INP_RUNLOCK(inp); 857165220Srrs sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5); 858163953Srrs return (0); 859163953Srrs } 860163953Srrs } 861163953Srrs SCTP_TCB_UNLOCK(stcb); 862163953Srrs SCTP_INP_RUNLOCK(inp); 863163953Srrs return (0); 864163953Srrs } 865163953Srrs /* not reached */ 866163953Srrs } else { 867163953Srrs /* UDP model does not support this */ 868163953Srrs SCTP_INP_RUNLOCK(inp); 869163953Srrs return EOPNOTSUPP; 870163953Srrs } 871163953Srrs} 872163953Srrs 873163953Srrsint 874163953Srrssctp_shutdown(struct socket *so) 875163953Srrs{ 876163953Srrs struct sctp_inpcb *inp; 877163953Srrs 878163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 879163953Srrs if (inp == 0) { 880163953Srrs return EINVAL; 881163953Srrs } 882163953Srrs SCTP_INP_RLOCK(inp); 883163953Srrs /* For UDP model this is a invalid call */ 884163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 885163953Srrs /* Restore the flags that the soshutdown took away. */ 886163953Srrs so->so_rcv.sb_state &= ~SBS_CANTRCVMORE; 887163953Srrs /* This proc will wakeup for read and do nothing (I hope) */ 888163953Srrs SCTP_INP_RUNLOCK(inp); 889163953Srrs return (EOPNOTSUPP); 890163953Srrs } 891163953Srrs /* 892163953Srrs * Ok if we reach here its the TCP model and it is either a SHUT_WR 893163953Srrs * or SHUT_RDWR. This means we put the shutdown flag against it. 894163953Srrs */ 895163953Srrs { 896163953Srrs struct sctp_tcb *stcb; 897163953Srrs struct sctp_association *asoc; 898163953Srrs 899163953Srrs socantsendmore(so); 900163953Srrs 901163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 902163953Srrs if (stcb == NULL) { 903163953Srrs /* 904163953Srrs * Ok we hit the case that the shutdown call was 905163953Srrs * made after an abort or something. Nothing to do 906163953Srrs * now. 907163953Srrs */ 908168299Srrs SCTP_INP_RUNLOCK(inp); 909163953Srrs return (0); 910163953Srrs } 911163953Srrs SCTP_TCB_LOCK(stcb); 912163953Srrs asoc = &stcb->asoc; 913163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 914163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 915163953Srrs (asoc->stream_queue_cnt == 0)) { 916163953Srrs if (asoc->locked_on_sending) { 917163953Srrs goto abort_anyway; 918163953Srrs } 919163953Srrs /* there is nothing queued to send, so I'm done... */ 920163953Srrs if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { 921163953Srrs /* only send SHUTDOWN the first time through */ 922163953Srrs sctp_stop_timers_for_shutdown(stcb); 923163953Srrs sctp_send_shutdown(stcb, 924163953Srrs stcb->asoc.primary_destination); 925163953Srrs sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3); 926166675Srrs if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 927166675Srrs (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 928166675Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 929166675Srrs } 930163953Srrs asoc->state = SCTP_STATE_SHUTDOWN_SENT; 931163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 932163953Srrs stcb->sctp_ep, stcb, 933163953Srrs asoc->primary_destination); 934163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 935163953Srrs stcb->sctp_ep, stcb, 936163953Srrs asoc->primary_destination); 937163953Srrs } 938163953Srrs } else { 939163953Srrs /* 940163953Srrs * we still got (or just got) data to send, so set 941163953Srrs * SHUTDOWN_PENDING 942163953Srrs */ 943163953Srrs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 944163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, 945163953Srrs asoc->primary_destination); 946163953Srrs 947163953Srrs if (asoc->locked_on_sending) { 948163953Srrs /* Locked to send out the data */ 949163953Srrs struct sctp_stream_queue_pending *sp; 950163953Srrs 951163953Srrs sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); 952163953Srrs if (sp == NULL) { 953169420Srrs SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", 954163953Srrs asoc->locked_on_sending->stream_no); 955163953Srrs } else { 956163953Srrs if ((sp->length == 0) && (sp->msg_is_complete == 0)) { 957163953Srrs asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; 958163953Srrs } 959163953Srrs } 960163953Srrs } 961163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 962163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 963163953Srrs (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 964163953Srrs struct mbuf *op_err; 965163953Srrs 966163953Srrs abort_anyway: 967163953Srrs op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 968163953Srrs 0, M_DONTWAIT, 1, MT_DATA); 969163953Srrs if (op_err) { 970163953Srrs /* Fill in the user initiated abort */ 971163953Srrs struct sctp_paramhdr *ph; 972163953Srrs uint32_t *ippp; 973163953Srrs 974165647Srrs SCTP_BUF_LEN(op_err) = 975163953Srrs sizeof(struct sctp_paramhdr) + sizeof(uint32_t); 976163953Srrs ph = mtod(op_err, 977163953Srrs struct sctp_paramhdr *); 978163953Srrs ph->param_type = htons( 979163953Srrs SCTP_CAUSE_USER_INITIATED_ABT); 980165647Srrs ph->param_length = htons(SCTP_BUF_LEN(op_err)); 981163953Srrs ippp = (uint32_t *) (ph + 1); 982165220Srrs *ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6); 983163953Srrs } 984165220Srrs stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6; 985163953Srrs sctp_abort_an_association(stcb->sctp_ep, stcb, 986163953Srrs SCTP_RESPONSE_TO_USER_REQ, 987163953Srrs op_err); 988163953Srrs goto skip_unlock; 989163953Srrs } 990163953Srrs } 991163953Srrs SCTP_TCB_UNLOCK(stcb); 992163953Srrs } 993163953Srrsskip_unlock: 994163953Srrs SCTP_INP_RUNLOCK(inp); 995163953Srrs return 0; 996163953Srrs} 997163953Srrs 998163953Srrs/* 999163953Srrs * copies a "user" presentable address and removes embedded scope, etc. 1000163953Srrs * returns 0 on success, 1 on error 1001163953Srrs */ 1002163953Srrsstatic uint32_t 1003163953Srrssctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa) 1004163953Srrs{ 1005163953Srrs struct sockaddr_in6 lsa6; 1006163953Srrs 1007163953Srrs sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa, 1008163953Srrs &lsa6); 1009163953Srrs memcpy(ss, sa, sa->sa_len); 1010163953Srrs return (0); 1011163953Srrs} 1012163953Srrs 1013163953Srrs 1014163953Srrs 1015166675Srrsstatic size_t 1016168124Srrssctp_fill_up_addresses_vrf(struct sctp_inpcb *inp, 1017163953Srrs struct sctp_tcb *stcb, 1018166675Srrs size_t limit, 1019167598Srrs struct sockaddr_storage *sas, 1020167598Srrs uint32_t vrf_id) 1021163953Srrs{ 1022167598Srrs struct sctp_ifn *sctp_ifn; 1023167598Srrs struct sctp_ifa *sctp_ifa; 1024166675Srrs int loopback_scope, ipv4_local_scope, local_scope, site_scope; 1025166675Srrs size_t actual; 1026163953Srrs int ipv4_addr_legal, ipv6_addr_legal; 1027167598Srrs struct sctp_vrf *vrf; 1028163953Srrs 1029163953Srrs actual = 0; 1030163953Srrs if (limit <= 0) 1031163953Srrs return (actual); 1032163953Srrs 1033163953Srrs if (stcb) { 1034163953Srrs /* Turn on all the appropriate scope */ 1035163953Srrs loopback_scope = stcb->asoc.loopback_scope; 1036163953Srrs ipv4_local_scope = stcb->asoc.ipv4_local_scope; 1037163953Srrs local_scope = stcb->asoc.local_scope; 1038163953Srrs site_scope = stcb->asoc.site_scope; 1039163953Srrs } else { 1040163953Srrs /* Turn on ALL scope, since we look at the EP */ 1041163953Srrs loopback_scope = ipv4_local_scope = local_scope = 1042163953Srrs site_scope = 1; 1043163953Srrs } 1044163953Srrs ipv4_addr_legal = ipv6_addr_legal = 0; 1045163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 1046163953Srrs ipv6_addr_legal = 1; 1047166023Srrs if (SCTP_IPV6_V6ONLY(inp) == 0) { 1048163953Srrs ipv4_addr_legal = 1; 1049163953Srrs } 1050163953Srrs } else { 1051163953Srrs ipv4_addr_legal = 1; 1052163953Srrs } 1053167598Srrs vrf = sctp_find_vrf(vrf_id); 1054167598Srrs if (vrf == NULL) { 1055167598Srrs return (0); 1056167598Srrs } 1057163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1058167598Srrs LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 1059163953Srrs if ((loopback_scope == 0) && 1060167598Srrs SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { 1061163953Srrs /* Skip loopback if loopback_scope not set */ 1062163953Srrs continue; 1063163953Srrs } 1064167598Srrs LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 1065163953Srrs if (stcb) { 1066163953Srrs /* 1067163953Srrs * For the BOUND-ALL case, the list 1068163953Srrs * associated with a TCB is Always 1069163953Srrs * considered a reverse list.. i.e. 1070163953Srrs * it lists addresses that are NOT 1071163953Srrs * part of the association. If this 1072163953Srrs * is one of those we must skip it. 1073163953Srrs */ 1074163953Srrs if (sctp_is_addr_restricted(stcb, 1075167598Srrs sctp_ifa)) { 1076163953Srrs continue; 1077163953Srrs } 1078163953Srrs } 1079167598Srrs if ((sctp_ifa->address.sa.sa_family == AF_INET) && 1080163953Srrs (ipv4_addr_legal)) { 1081163953Srrs struct sockaddr_in *sin; 1082163953Srrs 1083167598Srrs sin = (struct sockaddr_in *)&sctp_ifa->address.sa; 1084163953Srrs if (sin->sin_addr.s_addr == 0) { 1085163953Srrs /* 1086163953Srrs * we skip unspecifed 1087163953Srrs * addresses 1088163953Srrs */ 1089163953Srrs continue; 1090163953Srrs } 1091163953Srrs if ((ipv4_local_scope == 0) && 1092163953Srrs (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { 1093163953Srrs continue; 1094163953Srrs } 1095163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) { 1096163953Srrs in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas); 1097163953Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1098163953Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6)); 1099163953Srrs actual += sizeof(sizeof(struct sockaddr_in6)); 1100163953Srrs } else { 1101163953Srrs memcpy(sas, sin, sizeof(*sin)); 1102163953Srrs ((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport; 1103163953Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin)); 1104163953Srrs actual += sizeof(*sin); 1105163953Srrs } 1106163953Srrs if (actual >= limit) { 1107163953Srrs return (actual); 1108163953Srrs } 1109167598Srrs } else if ((sctp_ifa->address.sa.sa_family == AF_INET6) && 1110163953Srrs (ipv6_addr_legal)) { 1111163953Srrs struct sockaddr_in6 *sin6; 1112163953Srrs 1113167598Srrs sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa; 1114163953Srrs if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 1115163953Srrs /* 1116163953Srrs * we skip unspecifed 1117163953Srrs * addresses 1118163953Srrs */ 1119163953Srrs continue; 1120163953Srrs } 1121163953Srrs if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 1122163953Srrs if (local_scope == 0) 1123163953Srrs continue; 1124163953Srrs if (sin6->sin6_scope_id == 0) { 1125163953Srrs if (sa6_recoverscope(sin6) != 0) 1126163953Srrs /* 1127163953Srrs * bad link 1128163953Srrs * local 1129163953Srrs * address 1130163953Srrs */ 1131163953Srrs continue; 1132163953Srrs } 1133163953Srrs } 1134163953Srrs if ((site_scope == 0) && 1135163953Srrs (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { 1136163953Srrs continue; 1137163953Srrs } 1138163953Srrs memcpy(sas, sin6, sizeof(*sin6)); 1139163953Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1140163953Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6)); 1141163953Srrs actual += sizeof(*sin6); 1142163953Srrs if (actual >= limit) { 1143163953Srrs return (actual); 1144163953Srrs } 1145163953Srrs } 1146163953Srrs } 1147163953Srrs } 1148163953Srrs } else { 1149163953Srrs struct sctp_laddr *laddr; 1150163953Srrs 1151167598Srrs /* The list is a NEGATIVE list */ 1152167598Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1153167598Srrs if (stcb) { 1154167598Srrs if (sctp_is_addr_restricted(stcb, laddr->ifa)) { 1155163953Srrs continue; 1156163953Srrs } 1157163953Srrs } 1158167598Srrs if (sctp_fill_user_address(sas, &laddr->ifa->address.sa)) 1159167598Srrs continue; 1160167598Srrs 1161167598Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1162167598Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + 1163167598Srrs laddr->ifa->address.sa.sa_len); 1164167598Srrs actual += laddr->ifa->address.sa.sa_len; 1165167598Srrs if (actual >= limit) { 1166167598Srrs return (actual); 1167163953Srrs } 1168163953Srrs } 1169163953Srrs } 1170163953Srrs return (actual); 1171163953Srrs} 1172163953Srrs 1173168124Srrsstatic size_t 1174168124Srrssctp_fill_up_addresses(struct sctp_inpcb *inp, 1175168124Srrs struct sctp_tcb *stcb, 1176168124Srrs size_t limit, 1177168124Srrs struct sockaddr_storage *sas) 1178168124Srrs{ 1179168124Srrs size_t size = 0; 1180168124Srrs 1181168124Srrs /* fill up addresses for the endpoint's default vrf */ 1182168124Srrs size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas, 1183168124Srrs inp->def_vrf_id); 1184168124Srrs return (size); 1185168124Srrs} 1186168124Srrs 1187163953Srrsstatic int 1188168124Srrssctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) 1189163953Srrs{ 1190163953Srrs int cnt = 0; 1191167598Srrs struct sctp_vrf *vrf = NULL; 1192163953Srrs 1193163953Srrs /* 1194163953Srrs * In both sub-set bound an bound_all cases we return the MAXIMUM 1195163953Srrs * number of addresses that you COULD get. In reality the sub-set 1196163953Srrs * bound may have an exclusion list for a given TCB OR in the 1197163953Srrs * bound-all case a TCB may NOT include the loopback or other 1198163953Srrs * addresses as well. 1199163953Srrs */ 1200167598Srrs vrf = sctp_find_vrf(vrf_id); 1201167598Srrs if (vrf == NULL) { 1202167598Srrs return (0); 1203167598Srrs } 1204163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1205167598Srrs struct sctp_ifn *sctp_ifn; 1206167598Srrs struct sctp_ifa *sctp_ifa; 1207163953Srrs 1208167598Srrs LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 1209167598Srrs LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 1210163953Srrs /* Count them if they are the right type */ 1211167598Srrs if (sctp_ifa->address.sa.sa_family == AF_INET) { 1212163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) 1213163953Srrs cnt += sizeof(struct sockaddr_in6); 1214163953Srrs else 1215163953Srrs cnt += sizeof(struct sockaddr_in); 1216163953Srrs 1217167598Srrs } else if (sctp_ifa->address.sa.sa_family == AF_INET6) 1218163953Srrs cnt += sizeof(struct sockaddr_in6); 1219163953Srrs } 1220163953Srrs } 1221163953Srrs } else { 1222163953Srrs struct sctp_laddr *laddr; 1223163953Srrs 1224163953Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1225167598Srrs if (laddr->ifa->address.sa.sa_family == AF_INET) { 1226163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) 1227163953Srrs cnt += sizeof(struct sockaddr_in6); 1228163953Srrs else 1229163953Srrs cnt += sizeof(struct sockaddr_in); 1230163953Srrs 1231167598Srrs } else if (laddr->ifa->address.sa.sa_family == AF_INET6) 1232163953Srrs cnt += sizeof(struct sockaddr_in6); 1233163953Srrs } 1234163953Srrs } 1235163953Srrs return (cnt); 1236163953Srrs} 1237163953Srrs 1238168124Srrsstatic int 1239168124Srrssctp_count_max_addresses(struct sctp_inpcb *inp) 1240168124Srrs{ 1241168124Srrs int cnt = 0; 1242166675Srrs 1243168124Srrs /* count addresses for the endpoint's default VRF */ 1244168124Srrs cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id); 1245168124Srrs return (cnt); 1246168124Srrs} 1247168124Srrs 1248163953Srrsstatic int 1249166675Srrssctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, 1250166675Srrs size_t optsize, void *p, int delay) 1251163953Srrs{ 1252163953Srrs int error = 0; 1253163953Srrs int creat_lock_on = 0; 1254163953Srrs struct sctp_tcb *stcb = NULL; 1255163953Srrs struct sockaddr *sa; 1256169352Srrs int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr; 1257169352Srrs int added = 0; 1258167598Srrs uint32_t vrf_id; 1259167598Srrs sctp_assoc_t *a_id; 1260163953Srrs 1261169420Srrs SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n"); 1262163953Srrs 1263163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 1264163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 1265163953Srrs /* We are already connected AND the TCP model */ 1266163953Srrs return (EADDRINUSE); 1267163953Srrs } 1268163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) { 1269163953Srrs return (EINVAL); 1270163953Srrs } 1271163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 1272163953Srrs SCTP_INP_RLOCK(inp); 1273163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 1274163953Srrs SCTP_INP_RUNLOCK(inp); 1275163953Srrs } 1276163953Srrs if (stcb) { 1277163953Srrs return (EALREADY); 1278163953Srrs } 1279163953Srrs SCTP_INP_INCR_REF(inp); 1280163953Srrs SCTP_ASOC_CREATE_LOCK(inp); 1281163953Srrs creat_lock_on = 1; 1282163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 1283163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 1284163953Srrs error = EFAULT; 1285163953Srrs goto out_now; 1286163953Srrs } 1287166675Srrs totaddrp = (int *)optval; 1288163953Srrs totaddr = *totaddrp; 1289163953Srrs sa = (struct sockaddr *)(totaddrp + 1); 1290169352Srrs stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int))); 1291169352Srrs if (stcb != NULL) { 1292169352Srrs /* Already have or am bring up an association */ 1293169352Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1294169352Srrs creat_lock_on = 0; 1295169352Srrs SCTP_TCB_UNLOCK(stcb); 1296169352Srrs error = EALREADY; 1297169352Srrs goto out_now; 1298163953Srrs } 1299163953Srrs#ifdef INET6 1300163953Srrs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 1301163953Srrs (num_v6 > 0)) { 1302163953Srrs error = EINVAL; 1303163953Srrs goto out_now; 1304163953Srrs } 1305163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 1306163953Srrs (num_v4 > 0)) { 1307163953Srrs struct in6pcb *inp6; 1308163953Srrs 1309163953Srrs inp6 = (struct in6pcb *)inp; 1310166023Srrs if (SCTP_IPV6_V6ONLY(inp6)) { 1311163953Srrs /* 1312163953Srrs * if IPV6_V6ONLY flag, ignore connections destined 1313163953Srrs * to a v4 addr or v4-mapped addr 1314163953Srrs */ 1315163953Srrs error = EINVAL; 1316163953Srrs goto out_now; 1317163953Srrs } 1318163953Srrs } 1319163953Srrs#endif /* INET6 */ 1320163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 1321163953Srrs SCTP_PCB_FLAGS_UNBOUND) { 1322163953Srrs /* Bind a ephemeral port */ 1323163953Srrs error = sctp_inpcb_bind(so, NULL, p); 1324163953Srrs if (error) { 1325163953Srrs goto out_now; 1326163953Srrs } 1327163953Srrs } 1328167695Srrs /* FIX ME: do we want to pass in a vrf on the connect call? */ 1329167695Srrs vrf_id = inp->def_vrf_id; 1330167695Srrs 1331163953Srrs /* We are GOOD to go */ 1332167598Srrs stcb = sctp_aloc_assoc(inp, sa, 1, &error, 0, vrf_id); 1333163953Srrs if (stcb == NULL) { 1334163953Srrs /* Gak! no memory */ 1335163953Srrs goto out_now; 1336163953Srrs } 1337169352Srrs stcb->asoc.state = SCTP_STATE_COOKIE_WAIT; 1338163953Srrs /* move to second address */ 1339163953Srrs if (sa->sa_family == AF_INET) 1340163953Srrs sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in)); 1341163953Srrs else 1342163953Srrs sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6)); 1343163953Srrs 1344169352Srrs added = sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error); 1345167598Srrs /* Fill in the return id */ 1346167598Srrs a_id = (sctp_assoc_t *) optval; 1347167598Srrs *a_id = sctp_get_associd(stcb); 1348163953Srrs 1349163953Srrs /* initialize authentication parameters for the assoc */ 1350163953Srrs sctp_initialize_auth_params(inp, stcb); 1351163953Srrs 1352163953Srrs if (delay) { 1353163953Srrs /* doing delayed connection */ 1354163953Srrs stcb->asoc.delayed_connection = 1; 1355163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination); 1356163953Srrs } else { 1357169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 1358163953Srrs sctp_send_initiate(inp, stcb); 1359163953Srrs } 1360163953Srrs SCTP_TCB_UNLOCK(stcb); 1361163953Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 1362163953Srrs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 1363163953Srrs /* Set the connected flag so we can queue data */ 1364163953Srrs soisconnecting(so); 1365163953Srrs } 1366163953Srrsout_now: 1367163953Srrs if (creat_lock_on) 1368163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1369163953Srrs SCTP_INP_DECR_REF(inp); 1370163953Srrs return error; 1371163953Srrs} 1372163953Srrs 1373169420Srrs#define SCTP_FIND_STCB(inp, stcb, assoc_id) { \ 1374166675Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { \ 1375166675Srrs SCTP_INP_RLOCK(inp); \ 1376166675Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); \ 1377166675Srrs if (stcb) \ 1378166675Srrs SCTP_TCB_LOCK(stcb); \ 1379166675Srrs SCTP_INP_RUNLOCK(inp); \ 1380166675Srrs } else if (assoc_id != 0) { \ 1381166675Srrs stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \ 1382166675Srrs if (stcb == NULL) { \ 1383166675Srrs error = ENOENT; \ 1384166675Srrs break; \ 1385166675Srrs } \ 1386166675Srrs } else { \ 1387166675Srrs stcb = NULL; \ 1388169420Srrs } \ 1389169420Srrs } 1390163953Srrs 1391169420Srrs 1392169420Srrs#define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\ 1393166675Srrs if (size < sizeof(type)) { \ 1394166675Srrs error = EINVAL; \ 1395166675Srrs break; \ 1396166675Srrs } else { \ 1397166675Srrs destp = (type *)srcp; \ 1398169420Srrs } \ 1399169420Srrs } 1400163953Srrs 1401163953Srrsstatic int 1402166675Srrssctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, 1403166675Srrs void *p) 1404163953Srrs{ 1405163953Srrs struct sctp_inpcb *inp; 1406166675Srrs int error, val = 0; 1407163953Srrs struct sctp_tcb *stcb = NULL; 1408163953Srrs 1409166675Srrs if (optval == NULL) { 1410166675Srrs return (EINVAL); 1411166675Srrs } 1412163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 1413163953Srrs if (inp == 0) 1414163953Srrs return EINVAL; 1415163953Srrs error = 0; 1416163953Srrs 1417166675Srrs switch (optname) { 1418163953Srrs case SCTP_NODELAY: 1419163953Srrs case SCTP_AUTOCLOSE: 1420163953Srrs case SCTP_EXPLICIT_EOR: 1421163953Srrs case SCTP_AUTO_ASCONF: 1422163953Srrs case SCTP_DISABLE_FRAGMENTS: 1423163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 1424163953Srrs case SCTP_USE_EXT_RCVINFO: 1425163953Srrs SCTP_INP_RLOCK(inp); 1426166675Srrs switch (optname) { 1427163953Srrs case SCTP_DISABLE_FRAGMENTS: 1428166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT); 1429163953Srrs break; 1430163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 1431166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4); 1432163953Srrs break; 1433163953Srrs case SCTP_AUTO_ASCONF: 1434166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); 1435163953Srrs break; 1436163953Srrs case SCTP_EXPLICIT_EOR: 1437166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); 1438163953Srrs break; 1439163953Srrs case SCTP_NODELAY: 1440166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY); 1441163953Srrs break; 1442163953Srrs case SCTP_USE_EXT_RCVINFO: 1443166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO); 1444163953Srrs break; 1445163953Srrs case SCTP_AUTOCLOSE: 1446163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) 1447166675Srrs val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time); 1448163953Srrs else 1449166675Srrs val = 0; 1450163953Srrs break; 1451163953Srrs 1452163953Srrs default: 1453163953Srrs error = ENOPROTOOPT; 1454163953Srrs } /* end switch (sopt->sopt_name) */ 1455166675Srrs if (optname != SCTP_AUTOCLOSE) { 1456163953Srrs /* make it an "on/off" value */ 1457166675Srrs val = (val != 0); 1458163953Srrs } 1459166675Srrs if (*optsize < sizeof(val)) { 1460163953Srrs error = EINVAL; 1461163953Srrs } 1462163953Srrs SCTP_INP_RUNLOCK(inp); 1463163953Srrs if (error == 0) { 1464163953Srrs /* return the option value */ 1465166675Srrs *(int *)optval = val; 1466166675Srrs *optsize = sizeof(val); 1467163953Srrs } 1468163953Srrs break; 1469167598Srrs 1470163953Srrs case SCTP_PARTIAL_DELIVERY_POINT: 1471163953Srrs { 1472166675Srrs uint32_t *value; 1473166675Srrs 1474166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1475166675Srrs *value = inp->partial_delivery_point; 1476166675Srrs *optsize = sizeof(uint32_t); 1477163953Srrs } 1478163953Srrs break; 1479163953Srrs case SCTP_FRAGMENT_INTERLEAVE: 1480163953Srrs { 1481166675Srrs uint32_t *value; 1482166675Srrs 1483166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1484168943Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) { 1485168943Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) { 1486168943Srrs *value = SCTP_FRAG_LEVEL_2; 1487168943Srrs } else { 1488168943Srrs *value = SCTP_FRAG_LEVEL_1; 1489168943Srrs } 1490168943Srrs } else { 1491168943Srrs *value = SCTP_FRAG_LEVEL_0; 1492168943Srrs } 1493166675Srrs *optsize = sizeof(uint32_t); 1494163953Srrs } 1495163953Srrs break; 1496163953Srrs case SCTP_CMT_ON_OFF: 1497163953Srrs { 1498166675Srrs struct sctp_assoc_value *av; 1499166675Srrs 1500166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1501166675Srrs if (sctp_cmt_on_off) { 1502166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1503166675Srrs if (stcb) { 1504166675Srrs av->assoc_value = stcb->asoc.sctp_cmt_on_off; 1505166675Srrs SCTP_TCB_UNLOCK(stcb); 1506166675Srrs 1507166675Srrs } else { 1508166675Srrs error = ENOTCONN; 1509166675Srrs } 1510166675Srrs } else { 1511166675Srrs error = ENOPROTOOPT; 1512163953Srrs } 1513166675Srrs *optsize = sizeof(*av); 1514163953Srrs } 1515163953Srrs break; 1516163953Srrs case SCTP_GET_ADDR_LEN: 1517163953Srrs { 1518163953Srrs struct sctp_assoc_value *av; 1519163953Srrs 1520166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1521163953Srrs error = EINVAL; 1522167598Srrs#ifdef INET 1523163953Srrs if (av->assoc_value == AF_INET) { 1524163953Srrs av->assoc_value = sizeof(struct sockaddr_in); 1525163953Srrs error = 0; 1526163953Srrs } 1527163953Srrs#endif 1528167598Srrs#ifdef INET6 1529163953Srrs if (av->assoc_value == AF_INET6) { 1530163953Srrs av->assoc_value = sizeof(struct sockaddr_in6); 1531163953Srrs error = 0; 1532163953Srrs } 1533163953Srrs#endif 1534166675Srrs *optsize = sizeof(*av); 1535163953Srrs } 1536163953Srrs break; 1537163953Srrs case SCTP_GET_ASOC_ID_LIST: 1538163953Srrs { 1539163953Srrs struct sctp_assoc_ids *ids; 1540163953Srrs int cnt, at; 1541163953Srrs uint16_t orig; 1542163953Srrs 1543166675Srrs SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize); 1544163953Srrs cnt = 0; 1545163953Srrs SCTP_INP_RLOCK(inp); 1546163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 1547163953Srrs if (stcb == NULL) { 1548163953Srrs none_out_now: 1549163953Srrs ids->asls_numb_present = 0; 1550163953Srrs ids->asls_more_to_get = 0; 1551163953Srrs SCTP_INP_RUNLOCK(inp); 1552163953Srrs break; 1553163953Srrs } 1554163953Srrs orig = ids->asls_assoc_start; 1555163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 1556163953Srrs while (orig) { 1557163953Srrs stcb = LIST_NEXT(stcb, sctp_tcblist); 1558163953Srrs orig--; 1559163953Srrs cnt--; 1560163953Srrs if (stcb == NULL) 1561163953Srrs goto none_out_now; 1562163953Srrs } 1563163953Srrs if (stcb == NULL) 1564163953Srrs goto none_out_now; 1565163953Srrs 1566163953Srrs at = 0; 1567163953Srrs ids->asls_numb_present = 0; 1568163953Srrs ids->asls_more_to_get = 1; 1569163953Srrs while (at < MAX_ASOC_IDS_RET) { 1570163953Srrs ids->asls_assoc_id[at] = sctp_get_associd(stcb); 1571163953Srrs at++; 1572163953Srrs ids->asls_numb_present++; 1573163953Srrs stcb = LIST_NEXT(stcb, sctp_tcblist); 1574163953Srrs if (stcb == NULL) { 1575163953Srrs ids->asls_more_to_get = 0; 1576163953Srrs break; 1577163953Srrs } 1578163953Srrs } 1579163953Srrs SCTP_INP_RUNLOCK(inp); 1580163953Srrs } 1581163953Srrs break; 1582163953Srrs case SCTP_CONTEXT: 1583163953Srrs { 1584163953Srrs struct sctp_assoc_value *av; 1585163953Srrs 1586166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1587166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1588166675Srrs 1589166675Srrs if (stcb) { 1590166675Srrs av->assoc_value = stcb->asoc.context; 1591166675Srrs SCTP_TCB_UNLOCK(stcb); 1592163953Srrs } else { 1593166675Srrs SCTP_INP_RLOCK(inp); 1594163953Srrs av->assoc_value = inp->sctp_context; 1595166675Srrs SCTP_INP_RUNLOCK(inp); 1596163953Srrs } 1597166675Srrs *optsize = sizeof(*av); 1598163953Srrs } 1599163953Srrs break; 1600167598Srrs case SCTP_VRF_ID: 1601167598Srrs { 1602167598Srrs uint32_t *vrf_id; 1603167598Srrs 1604167598Srrs SCTP_CHECK_AND_CAST(vrf_id, optval, uint32_t, *optsize); 1605167598Srrs *vrf_id = inp->def_vrf_id; 1606167598Srrs break; 1607167598Srrs } 1608167598Srrs case SCTP_GET_ASOC_VRF: 1609167598Srrs { 1610167598Srrs struct sctp_assoc_value *id; 1611167598Srrs 1612167598Srrs SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize); 1613167598Srrs SCTP_FIND_STCB(inp, stcb, id->assoc_id); 1614167598Srrs if (stcb == NULL) { 1615167598Srrs error = EINVAL; 1616167598Srrs break; 1617167598Srrs } 1618167598Srrs id->assoc_value = stcb->asoc.vrf_id; 1619167598Srrs break; 1620167598Srrs } 1621167598Srrs case SCTP_GET_VRF_IDS: 1622167598Srrs { 1623167598Srrs error = EOPNOTSUPP; 1624167598Srrs break; 1625167598Srrs } 1626163953Srrs case SCTP_GET_NONCE_VALUES: 1627163953Srrs { 1628163953Srrs struct sctp_get_nonce_values *gnv; 1629163953Srrs 1630166675Srrs SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize); 1631166675Srrs SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id); 1632166675Srrs 1633166675Srrs if (stcb) { 1634163953Srrs gnv->gn_peers_tag = stcb->asoc.peer_vtag; 1635163953Srrs gnv->gn_local_tag = stcb->asoc.my_vtag; 1636163953Srrs SCTP_TCB_UNLOCK(stcb); 1637166675Srrs } else { 1638166675Srrs error = ENOTCONN; 1639163953Srrs } 1640166675Srrs *optsize = sizeof(*gnv); 1641163953Srrs } 1642163953Srrs break; 1643163953Srrs case SCTP_DELAYED_ACK_TIME: 1644163953Srrs { 1645163953Srrs struct sctp_assoc_value *tm; 1646163953Srrs 1647166675Srrs SCTP_CHECK_AND_CAST(tm, optval, struct sctp_assoc_value, *optsize); 1648166675Srrs SCTP_FIND_STCB(inp, stcb, tm->assoc_id); 1649163953Srrs 1650166675Srrs if (stcb) { 1651166675Srrs tm->assoc_value = stcb->asoc.delayed_ack; 1652166675Srrs SCTP_TCB_UNLOCK(stcb); 1653166675Srrs } else { 1654163953Srrs SCTP_INP_RLOCK(inp); 1655166675Srrs tm->assoc_value = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); 1656163953Srrs SCTP_INP_RUNLOCK(inp); 1657163953Srrs } 1658166675Srrs *optsize = sizeof(*tm); 1659163953Srrs } 1660163953Srrs break; 1661163953Srrs 1662163953Srrs case SCTP_GET_SNDBUF_USE: 1663166675Srrs { 1664163953Srrs struct sctp_sockstat *ss; 1665163953Srrs 1666166675Srrs SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize); 1667166675Srrs SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id); 1668166675Srrs 1669166675Srrs if (stcb) { 1670166675Srrs ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size; 1671166675Srrs ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue + 1672166675Srrs stcb->asoc.size_on_all_streams); 1673166675Srrs SCTP_TCB_UNLOCK(stcb); 1674166675Srrs } else { 1675163953Srrs error = ENOTCONN; 1676163953Srrs } 1677166675Srrs *optsize = sizeof(struct sctp_sockstat); 1678163953Srrs } 1679163953Srrs break; 1680163953Srrs case SCTP_MAXBURST: 1681163953Srrs { 1682166675Srrs uint8_t *value; 1683163953Srrs 1684166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint8_t, *optsize); 1685166675Srrs 1686163953Srrs SCTP_INP_RLOCK(inp); 1687166675Srrs *value = inp->sctp_ep.max_burst; 1688163953Srrs SCTP_INP_RUNLOCK(inp); 1689166675Srrs *optsize = sizeof(uint8_t); 1690163953Srrs } 1691163953Srrs break; 1692163953Srrs case SCTP_MAXSEG: 1693163953Srrs { 1694167598Srrs struct sctp_assoc_value *av; 1695163953Srrs int ovh; 1696163953Srrs 1697167598Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1698168859Srrs if (av->assoc_id) { 1699168859Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1700168859Srrs } else { 1701168859Srrs stcb = NULL; 1702168859Srrs } 1703163953Srrs 1704167598Srrs if (stcb) { 1705167598Srrs av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc); 1706167598Srrs SCTP_TCB_UNLOCK(stcb); 1707163953Srrs } else { 1708167598Srrs SCTP_INP_RLOCK(inp); 1709167598Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 1710167598Srrs ovh = SCTP_MED_OVERHEAD; 1711167598Srrs } else { 1712167598Srrs ovh = SCTP_MED_V4_OVERHEAD; 1713167598Srrs } 1714167598Srrs av->assoc_value = inp->sctp_frag_point - ovh; 1715167598Srrs SCTP_INP_RUNLOCK(inp); 1716163953Srrs } 1717167598Srrs *optsize = sizeof(struct sctp_assoc_value); 1718163953Srrs } 1719163953Srrs break; 1720163953Srrs case SCTP_GET_STAT_LOG: 1721163953Srrs#ifdef SCTP_STAT_LOGGING 1722167598Srrs error = sctp_fill_stat_log(optval, optsize); 1723167598Srrs#else 1724163953Srrs error = EOPNOTSUPP; 1725163953Srrs#endif 1726163953Srrs break; 1727163953Srrs case SCTP_EVENTS: 1728163953Srrs { 1729163953Srrs struct sctp_event_subscribe *events; 1730163953Srrs 1731166675Srrs SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize); 1732163953Srrs memset(events, 0, sizeof(*events)); 1733163953Srrs SCTP_INP_RLOCK(inp); 1734163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) 1735163953Srrs events->sctp_data_io_event = 1; 1736163953Srrs 1737163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT)) 1738163953Srrs events->sctp_association_event = 1; 1739163953Srrs 1740163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT)) 1741163953Srrs events->sctp_address_event = 1; 1742163953Srrs 1743163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) 1744163953Srrs events->sctp_send_failure_event = 1; 1745163953Srrs 1746163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR)) 1747163953Srrs events->sctp_peer_error_event = 1; 1748163953Srrs 1749163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) 1750163953Srrs events->sctp_shutdown_event = 1; 1751163953Srrs 1752163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT)) 1753163953Srrs events->sctp_partial_delivery_event = 1; 1754163953Srrs 1755163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) 1756163953Srrs events->sctp_adaptation_layer_event = 1; 1757163953Srrs 1758163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT)) 1759163953Srrs events->sctp_authentication_event = 1; 1760163953Srrs 1761163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) 1762163953Srrs events->sctp_stream_reset_events = 1; 1763163953Srrs SCTP_INP_RUNLOCK(inp); 1764166675Srrs *optsize = sizeof(struct sctp_event_subscribe); 1765163953Srrs } 1766163953Srrs break; 1767163953Srrs 1768163953Srrs case SCTP_ADAPTATION_LAYER: 1769166675Srrs { 1770166675Srrs uint32_t *value; 1771166675Srrs 1772166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1773166675Srrs 1774166675Srrs SCTP_INP_RLOCK(inp); 1775166675Srrs *value = inp->sctp_ep.adaptation_layer_indicator; 1776166675Srrs SCTP_INP_RUNLOCK(inp); 1777166675Srrs *optsize = sizeof(uint32_t); 1778163953Srrs } 1779163953Srrs break; 1780163953Srrs case SCTP_SET_INITIAL_DBG_SEQ: 1781166675Srrs { 1782166675Srrs uint32_t *value; 1783166675Srrs 1784166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1785166675Srrs SCTP_INP_RLOCK(inp); 1786166675Srrs *value = inp->sctp_ep.initial_sequence_debug; 1787166675Srrs SCTP_INP_RUNLOCK(inp); 1788166675Srrs *optsize = sizeof(uint32_t); 1789163953Srrs } 1790163953Srrs break; 1791163953Srrs case SCTP_GET_LOCAL_ADDR_SIZE: 1792166675Srrs { 1793166675Srrs uint32_t *value; 1794166675Srrs 1795166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1796166675Srrs SCTP_INP_RLOCK(inp); 1797168124Srrs *value = sctp_count_max_addresses(inp); 1798166675Srrs SCTP_INP_RUNLOCK(inp); 1799166675Srrs *optsize = sizeof(uint32_t); 1800163953Srrs } 1801163953Srrs break; 1802163953Srrs case SCTP_GET_REMOTE_ADDR_SIZE: 1803163953Srrs { 1804166675Srrs uint32_t *value; 1805166675Srrs size_t size; 1806163953Srrs struct sctp_nets *net; 1807163953Srrs 1808166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1809166675Srrs /* FIXME MT: change to sctp_assoc_value? */ 1810166675Srrs SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value); 1811166675Srrs 1812166675Srrs if (stcb) { 1813166675Srrs size = 0; 1814166675Srrs /* Count the sizes */ 1815166675Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1816166675Srrs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) || 1817166675Srrs (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET6)) { 1818166675Srrs size += sizeof(struct sockaddr_in6); 1819166675Srrs } else if (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET) { 1820166675Srrs size += sizeof(struct sockaddr_in); 1821166675Srrs } else { 1822166675Srrs /* huh */ 1823166675Srrs break; 1824166675Srrs } 1825163953Srrs } 1826166675Srrs SCTP_TCB_UNLOCK(stcb); 1827166675Srrs *value = (uint32_t) size; 1828166675Srrs } else { 1829166675Srrs error = ENOTCONN; 1830163953Srrs } 1831166675Srrs *optsize = sizeof(uint32_t); 1832163953Srrs } 1833163953Srrs break; 1834163953Srrs case SCTP_GET_PEER_ADDRESSES: 1835163953Srrs /* 1836163953Srrs * Get the address information, an array is passed in to 1837163953Srrs * fill up we pack it. 1838163953Srrs */ 1839163953Srrs { 1840166675Srrs size_t cpsz, left; 1841163953Srrs struct sockaddr_storage *sas; 1842163953Srrs struct sctp_nets *net; 1843163953Srrs struct sctp_getaddresses *saddr; 1844163953Srrs 1845166675Srrs SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); 1846166675Srrs SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); 1847163953Srrs 1848166675Srrs if (stcb) { 1849166675Srrs left = (*optsize) - sizeof(struct sctp_getaddresses); 1850166675Srrs *optsize = sizeof(struct sctp_getaddresses); 1851166675Srrs sas = (struct sockaddr_storage *)&saddr->addr[0]; 1852166675Srrs 1853166675Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1854166675Srrs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) || 1855166675Srrs (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET6)) { 1856166675Srrs cpsz = sizeof(struct sockaddr_in6); 1857166675Srrs } else if (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET) { 1858166675Srrs cpsz = sizeof(struct sockaddr_in); 1859166675Srrs } else { 1860166675Srrs /* huh */ 1861166675Srrs break; 1862166675Srrs } 1863166675Srrs if (left < cpsz) { 1864166675Srrs /* not enough room. */ 1865166675Srrs break; 1866166675Srrs } 1867166675Srrs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) && 1868166675Srrs (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET)) { 1869166675Srrs /* Must map the address */ 1870166675Srrs in6_sin_2_v4mapsin6((struct sockaddr_in *)&net->ro._l_addr, 1871166675Srrs (struct sockaddr_in6 *)sas); 1872166675Srrs } else { 1873166675Srrs memcpy(sas, &net->ro._l_addr, cpsz); 1874166675Srrs } 1875166675Srrs ((struct sockaddr_in *)sas)->sin_port = stcb->rport; 1876166675Srrs 1877166675Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz); 1878166675Srrs left -= cpsz; 1879166675Srrs *optsize += cpsz; 1880163953Srrs } 1881166675Srrs SCTP_TCB_UNLOCK(stcb); 1882166675Srrs } else { 1883166675Srrs error = ENOENT; 1884163953Srrs } 1885163953Srrs } 1886163953Srrs break; 1887163953Srrs case SCTP_GET_LOCAL_ADDRESSES: 1888163953Srrs { 1889166675Srrs size_t limit, actual; 1890163953Srrs struct sockaddr_storage *sas; 1891163953Srrs struct sctp_getaddresses *saddr; 1892163953Srrs 1893166675Srrs SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); 1894166675Srrs SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); 1895163953Srrs 1896163953Srrs sas = (struct sockaddr_storage *)&saddr->addr[0]; 1897166675Srrs limit = *optsize - sizeof(sctp_assoc_t); 1898168124Srrs actual = sctp_fill_up_addresses(inp, stcb, limit, sas); 1899163953Srrs if (stcb) 1900163953Srrs SCTP_TCB_UNLOCK(stcb); 1901166675Srrs *optsize = sizeof(struct sockaddr_storage) + actual; 1902163953Srrs } 1903163953Srrs break; 1904163953Srrs case SCTP_PEER_ADDR_PARAMS: 1905163953Srrs { 1906163953Srrs struct sctp_paddrparams *paddrp; 1907163953Srrs struct sctp_nets *net; 1908163953Srrs 1909166675Srrs SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize); 1910166675Srrs SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); 1911163953Srrs 1912163953Srrs net = NULL; 1913166675Srrs if (stcb) { 1914166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address); 1915166675Srrs } else { 1916166675Srrs /* 1917166675Srrs * We increment here since 1918166675Srrs * sctp_findassociation_ep_addr() wil do a 1919166675Srrs * decrement if it finds the stcb as long as 1920166675Srrs * the locked tcb (last argument) is NOT a 1921166675Srrs * TCB.. aka NULL. 1922166675Srrs */ 1923166675Srrs SCTP_INP_INCR_REF(inp); 1924166675Srrs stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddrp->spp_address, &net, NULL, NULL); 1925163953Srrs if (stcb == NULL) { 1926166675Srrs SCTP_INP_DECR_REF(inp); 1927163953Srrs } 1928163953Srrs } 1929163953Srrs 1930163953Srrs if (stcb) { 1931163953Srrs /* Applys to the specific association */ 1932163953Srrs paddrp->spp_flags = 0; 1933163953Srrs if (net) { 1934163953Srrs paddrp->spp_pathmaxrxt = net->failure_threshold; 1935163953Srrs paddrp->spp_pathmtu = net->mtu; 1936163953Srrs /* get flags for HB */ 1937163953Srrs if (net->dest_state & SCTP_ADDR_NOHB) 1938163953Srrs paddrp->spp_flags |= SPP_HB_DISABLE; 1939163953Srrs else 1940163953Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 1941163953Srrs /* get flags for PMTU */ 1942165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 1943163953Srrs paddrp->spp_flags |= SPP_PMTUD_ENABLE; 1944163953Srrs } else { 1945163953Srrs paddrp->spp_flags |= SPP_PMTUD_DISABLE; 1946163953Srrs } 1947167598Srrs#ifdef INET 1948163953Srrs if (net->ro._l_addr.sin.sin_family == AF_INET) { 1949163953Srrs paddrp->spp_ipv4_tos = net->tos_flowlabel & 0x000000fc; 1950163953Srrs paddrp->spp_flags |= SPP_IPV4_TOS; 1951163953Srrs } 1952163953Srrs#endif 1953167598Srrs#ifdef INET6 1954163953Srrs if (net->ro._l_addr.sin6.sin6_family == AF_INET6) { 1955163953Srrs paddrp->spp_ipv6_flowlabel = net->tos_flowlabel; 1956163953Srrs paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 1957163953Srrs } 1958163953Srrs#endif 1959163953Srrs } else { 1960163953Srrs /* 1961163953Srrs * No destination so return default 1962163953Srrs * value 1963163953Srrs */ 1964163953Srrs paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure; 1965163953Srrs paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc); 1966167598Srrs#ifdef INET 1967163953Srrs paddrp->spp_ipv4_tos = stcb->asoc.default_tos & 0x000000fc; 1968163953Srrs paddrp->spp_flags |= SPP_IPV4_TOS; 1969163953Srrs#endif 1970167598Srrs#ifdef INET6 1971163953Srrs paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel; 1972163953Srrs paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 1973163953Srrs#endif 1974163953Srrs /* default settings should be these */ 1975163953Srrs if (sctp_is_hb_timer_running(stcb)) { 1976163953Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 1977163953Srrs } 1978163953Srrs } 1979163953Srrs paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay; 1980163953Srrs paddrp->spp_assoc_id = sctp_get_associd(stcb); 1981163953Srrs SCTP_TCB_UNLOCK(stcb); 1982163953Srrs } else { 1983163953Srrs /* Use endpoint defaults */ 1984163953Srrs SCTP_INP_RLOCK(inp); 1985163953Srrs paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure; 1986163953Srrs paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); 1987163953Srrs paddrp->spp_assoc_id = (sctp_assoc_t) 0; 1988163953Srrs /* get inp's default */ 1989167598Srrs#ifdef INET 1990163953Srrs paddrp->spp_ipv4_tos = inp->ip_inp.inp.inp_ip_tos; 1991163953Srrs paddrp->spp_flags |= SPP_IPV4_TOS; 1992163953Srrs#endif 1993167598Srrs#ifdef INET6 1994163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 1995163953Srrs paddrp->spp_ipv6_flowlabel = ((struct in6pcb *)inp)->in6p_flowinfo; 1996163953Srrs paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 1997163953Srrs } 1998163953Srrs#endif 1999163953Srrs /* can't return this */ 2000163953Srrs paddrp->spp_pathmaxrxt = 0; 2001163953Srrs paddrp->spp_pathmtu = 0; 2002163953Srrs /* default behavior, no stcb */ 2003167598Srrs paddrp->spp_flags = SPP_HB_ENABLE | SPP_PMTUD_ENABLE; 2004163953Srrs 2005163953Srrs SCTP_INP_RUNLOCK(inp); 2006163953Srrs } 2007166675Srrs *optsize = sizeof(struct sctp_paddrparams); 2008163953Srrs } 2009163953Srrs break; 2010163953Srrs case SCTP_GET_PEER_ADDR_INFO: 2011163953Srrs { 2012163953Srrs struct sctp_paddrinfo *paddri; 2013163953Srrs struct sctp_nets *net; 2014163953Srrs 2015166675Srrs SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize); 2016166675Srrs SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id); 2017166675Srrs 2018163953Srrs net = NULL; 2019166675Srrs if (stcb) { 2020166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddri->spinfo_address); 2021166675Srrs } else { 2022166675Srrs /* 2023166675Srrs * We increment here since 2024166675Srrs * sctp_findassociation_ep_addr() wil do a 2025166675Srrs * decrement if it finds the stcb as long as 2026166675Srrs * the locked tcb (last argument) is NOT a 2027166675Srrs * TCB.. aka NULL. 2028166675Srrs */ 2029166675Srrs SCTP_INP_INCR_REF(inp); 2030166675Srrs stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddri->spinfo_address, &net, NULL, NULL); 2031166675Srrs if (stcb == NULL) { 2032166675Srrs SCTP_INP_DECR_REF(inp); 2033163953Srrs } 2034166675Srrs } 2035163953Srrs 2036166675Srrs if ((stcb) && (net)) { 2037166675Srrs paddri->spinfo_state = net->dest_state & (SCTP_REACHABLE_MASK | SCTP_ADDR_NOHB); 2038166675Srrs paddri->spinfo_cwnd = net->cwnd; 2039166675Srrs paddri->spinfo_srtt = ((net->lastsa >> 2) + net->lastsv) >> 1; 2040166675Srrs paddri->spinfo_rto = net->RTO; 2041166675Srrs paddri->spinfo_assoc_id = sctp_get_associd(stcb); 2042166675Srrs SCTP_TCB_UNLOCK(stcb); 2043163953Srrs } else { 2044163953Srrs if (stcb) { 2045163953Srrs SCTP_TCB_UNLOCK(stcb); 2046163953Srrs } 2047163953Srrs error = ENOENT; 2048163953Srrs } 2049166675Srrs *optsize = sizeof(struct sctp_paddrinfo); 2050163953Srrs } 2051163953Srrs break; 2052163953Srrs case SCTP_PCB_STATUS: 2053163953Srrs { 2054163953Srrs struct sctp_pcbinfo *spcb; 2055163953Srrs 2056166675Srrs SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize); 2057163953Srrs sctp_fill_pcbinfo(spcb); 2058166675Srrs *optsize = sizeof(struct sctp_pcbinfo); 2059163953Srrs } 2060163953Srrs break; 2061167598Srrs 2062163953Srrs case SCTP_STATUS: 2063163953Srrs { 2064163953Srrs struct sctp_nets *net; 2065163953Srrs struct sctp_status *sstat; 2066163953Srrs 2067166675Srrs SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize); 2068166675Srrs SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id); 2069163953Srrs 2070163953Srrs if (stcb == NULL) { 2071163953Srrs error = EINVAL; 2072163953Srrs break; 2073163953Srrs } 2074163953Srrs /* 2075163953Srrs * I think passing the state is fine since 2076163953Srrs * sctp_constants.h will be available to the user 2077163953Srrs * land. 2078163953Srrs */ 2079163953Srrs sstat->sstat_state = stcb->asoc.state; 2080163953Srrs sstat->sstat_rwnd = stcb->asoc.peers_rwnd; 2081163953Srrs sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt; 2082163953Srrs /* 2083163953Srrs * We can't include chunks that have been passed to 2084163953Srrs * the socket layer. Only things in queue. 2085163953Srrs */ 2086163953Srrs sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue + 2087163953Srrs stcb->asoc.cnt_on_all_streams); 2088163953Srrs 2089163953Srrs 2090163953Srrs sstat->sstat_instrms = stcb->asoc.streamincnt; 2091163953Srrs sstat->sstat_outstrms = stcb->asoc.streamoutcnt; 2092163953Srrs sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc); 2093163953Srrs memcpy(&sstat->sstat_primary.spinfo_address, 2094163953Srrs &stcb->asoc.primary_destination->ro._l_addr, 2095163953Srrs ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len); 2096163953Srrs net = stcb->asoc.primary_destination; 2097163953Srrs ((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport; 2098163953Srrs /* 2099163953Srrs * Again the user can get info from sctp_constants.h 2100163953Srrs * for what the state of the network is. 2101163953Srrs */ 2102163953Srrs sstat->sstat_primary.spinfo_state = net->dest_state & SCTP_REACHABLE_MASK; 2103163953Srrs sstat->sstat_primary.spinfo_cwnd = net->cwnd; 2104163953Srrs sstat->sstat_primary.spinfo_srtt = net->lastsa; 2105163953Srrs sstat->sstat_primary.spinfo_rto = net->RTO; 2106163953Srrs sstat->sstat_primary.spinfo_mtu = net->mtu; 2107163953Srrs sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb); 2108163953Srrs SCTP_TCB_UNLOCK(stcb); 2109166675Srrs *optsize = sizeof(*sstat); 2110163953Srrs } 2111163953Srrs break; 2112163953Srrs case SCTP_RTOINFO: 2113163953Srrs { 2114163953Srrs struct sctp_rtoinfo *srto; 2115163953Srrs 2116166675Srrs SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize); 2117166675Srrs SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); 2118166675Srrs 2119166675Srrs if (stcb) { 2120166675Srrs srto->srto_initial = stcb->asoc.initial_rto; 2121166675Srrs srto->srto_max = stcb->asoc.maxrto; 2122166675Srrs srto->srto_min = stcb->asoc.minrto; 2123166675Srrs SCTP_TCB_UNLOCK(stcb); 2124166675Srrs } else { 2125163953Srrs SCTP_INP_RLOCK(inp); 2126163953Srrs srto->srto_initial = inp->sctp_ep.initial_rto; 2127163953Srrs srto->srto_max = inp->sctp_ep.sctp_maxrto; 2128163953Srrs srto->srto_min = inp->sctp_ep.sctp_minrto; 2129163953Srrs SCTP_INP_RUNLOCK(inp); 2130163953Srrs } 2131166675Srrs *optsize = sizeof(*srto); 2132163953Srrs } 2133163953Srrs break; 2134163953Srrs case SCTP_ASSOCINFO: 2135163953Srrs { 2136163953Srrs struct sctp_assocparams *sasoc; 2137163953Srrs 2138166675Srrs SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize); 2139166675Srrs SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); 2140163953Srrs 2141163953Srrs if (stcb) { 2142163953Srrs sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times; 2143163953Srrs sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets; 2144163953Srrs sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd; 2145163953Srrs sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd; 2146163953Srrs sasoc->sasoc_cookie_life = stcb->asoc.cookie_life; 2147167598Srrs sasoc->sasoc_sack_delay = stcb->asoc.delayed_ack; 2148167598Srrs sasoc->sasoc_sack_freq = stcb->asoc.sack_freq; 2149163953Srrs SCTP_TCB_UNLOCK(stcb); 2150163953Srrs } else { 2151163953Srrs SCTP_INP_RLOCK(inp); 2152163953Srrs sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times; 2153163953Srrs sasoc->sasoc_number_peer_destinations = 0; 2154163953Srrs sasoc->sasoc_peer_rwnd = 0; 2155163953Srrs sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv); 2156163953Srrs sasoc->sasoc_cookie_life = inp->sctp_ep.def_cookie_life; 2157167598Srrs sasoc->sasoc_sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); 2158167598Srrs sasoc->sasoc_sack_freq = inp->sctp_ep.sctp_sack_freq; 2159163953Srrs SCTP_INP_RUNLOCK(inp); 2160163953Srrs } 2161166675Srrs *optsize = sizeof(*sasoc); 2162163953Srrs } 2163163953Srrs break; 2164163953Srrs case SCTP_DEFAULT_SEND_PARAM: 2165163953Srrs { 2166163953Srrs struct sctp_sndrcvinfo *s_info; 2167163953Srrs 2168166675Srrs SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize); 2169166675Srrs SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); 2170166675Srrs 2171166675Srrs if (stcb) { 2172166675Srrs *s_info = stcb->asoc.def_send; 2173166675Srrs SCTP_TCB_UNLOCK(stcb); 2174166675Srrs } else { 2175163953Srrs SCTP_INP_RLOCK(inp); 2176166675Srrs *s_info = inp->def_send; 2177163953Srrs SCTP_INP_RUNLOCK(inp); 2178163953Srrs } 2179166675Srrs *optsize = sizeof(*s_info); 2180163953Srrs } 2181163953Srrs break; 2182163953Srrs case SCTP_INITMSG: 2183163953Srrs { 2184163953Srrs struct sctp_initmsg *sinit; 2185163953Srrs 2186166675Srrs SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize); 2187163953Srrs SCTP_INP_RLOCK(inp); 2188163953Srrs sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count; 2189163953Srrs sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome; 2190163953Srrs sinit->sinit_max_attempts = inp->sctp_ep.max_init_times; 2191163953Srrs sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max; 2192163953Srrs SCTP_INP_RUNLOCK(inp); 2193166675Srrs *optsize = sizeof(*sinit); 2194163953Srrs } 2195163953Srrs break; 2196163953Srrs case SCTP_PRIMARY_ADDR: 2197163953Srrs /* we allow a "get" operation on this */ 2198163953Srrs { 2199163953Srrs struct sctp_setprim *ssp; 2200163953Srrs 2201166675Srrs SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize); 2202166675Srrs SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id); 2203166675Srrs 2204166675Srrs if (stcb) { 2205166675Srrs /* simply copy out the sockaddr_storage... */ 2206166675Srrs memcpy(&ssp->ssp_addr, &stcb->asoc.primary_destination->ro._l_addr, 2207166675Srrs ((struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr)->sa_len); 2208166675Srrs SCTP_TCB_UNLOCK(stcb); 2209166675Srrs } else { 2210163953Srrs error = EINVAL; 2211163953Srrs } 2212166675Srrs *optsize = sizeof(*ssp); 2213163953Srrs } 2214163953Srrs break; 2215163953Srrs 2216163953Srrs case SCTP_HMAC_IDENT: 2217163953Srrs { 2218163953Srrs struct sctp_hmacalgo *shmac; 2219163953Srrs sctp_hmaclist_t *hmaclist; 2220163953Srrs uint32_t size; 2221163953Srrs int i; 2222163953Srrs 2223166675Srrs SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize); 2224166675Srrs 2225163953Srrs SCTP_INP_RLOCK(inp); 2226163953Srrs hmaclist = inp->sctp_ep.local_hmacs; 2227163953Srrs if (hmaclist == NULL) { 2228163953Srrs /* no HMACs to return */ 2229166675Srrs *optsize = sizeof(*shmac); 2230168299Srrs SCTP_INP_RUNLOCK(inp); 2231163953Srrs break; 2232163953Srrs } 2233163953Srrs /* is there room for all of the hmac ids? */ 2234163953Srrs size = sizeof(*shmac) + (hmaclist->num_algo * 2235163953Srrs sizeof(shmac->shmac_idents[0])); 2236166675Srrs if ((size_t)(*optsize) < size) { 2237163953Srrs error = EINVAL; 2238163953Srrs SCTP_INP_RUNLOCK(inp); 2239163953Srrs break; 2240163953Srrs } 2241163953Srrs /* copy in the list */ 2242163953Srrs for (i = 0; i < hmaclist->num_algo; i++) 2243163953Srrs shmac->shmac_idents[i] = hmaclist->hmac[i]; 2244163953Srrs SCTP_INP_RUNLOCK(inp); 2245166675Srrs *optsize = size; 2246163953Srrs break; 2247163953Srrs } 2248163953Srrs case SCTP_AUTH_ACTIVE_KEY: 2249163953Srrs { 2250163953Srrs struct sctp_authkeyid *scact; 2251163953Srrs 2252166675Srrs SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize); 2253166675Srrs SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); 2254166675Srrs 2255166675Srrs if (stcb) { 2256163953Srrs /* get the active key on the assoc */ 2257163953Srrs scact->scact_keynumber = stcb->asoc.authinfo.assoc_keyid; 2258163953Srrs SCTP_TCB_UNLOCK(stcb); 2259163953Srrs } else { 2260163953Srrs /* get the endpoint active key */ 2261163953Srrs SCTP_INP_RLOCK(inp); 2262163953Srrs scact->scact_keynumber = inp->sctp_ep.default_keyid; 2263163953Srrs SCTP_INP_RUNLOCK(inp); 2264163953Srrs } 2265166675Srrs *optsize = sizeof(*scact); 2266163953Srrs break; 2267163953Srrs } 2268163953Srrs case SCTP_LOCAL_AUTH_CHUNKS: 2269163953Srrs { 2270163953Srrs struct sctp_authchunks *sac; 2271163953Srrs sctp_auth_chklist_t *chklist = NULL; 2272166675Srrs size_t size = 0; 2273163953Srrs 2274166675Srrs SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); 2275166675Srrs SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); 2276166675Srrs 2277166675Srrs if (stcb) { 2278163953Srrs /* get off the assoc */ 2279163953Srrs chklist = stcb->asoc.local_auth_chunks; 2280163953Srrs /* is there enough space? */ 2281163953Srrs size = sctp_auth_get_chklist_size(chklist); 2282166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2283163953Srrs error = EINVAL; 2284166675Srrs } else { 2285166675Srrs /* copy in the chunks */ 2286169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2287163953Srrs } 2288163953Srrs SCTP_TCB_UNLOCK(stcb); 2289163953Srrs } else { 2290163953Srrs /* get off the endpoint */ 2291163953Srrs SCTP_INP_RLOCK(inp); 2292163953Srrs chklist = inp->sctp_ep.local_auth_chunks; 2293163953Srrs /* is there enough space? */ 2294163953Srrs size = sctp_auth_get_chklist_size(chklist); 2295166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2296163953Srrs error = EINVAL; 2297166675Srrs } else { 2298166675Srrs /* copy in the chunks */ 2299169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2300163953Srrs } 2301163953Srrs SCTP_INP_RUNLOCK(inp); 2302163953Srrs } 2303166675Srrs *optsize = sizeof(struct sctp_authchunks) + size; 2304163953Srrs break; 2305163953Srrs } 2306163953Srrs case SCTP_PEER_AUTH_CHUNKS: 2307163953Srrs { 2308163953Srrs struct sctp_authchunks *sac; 2309163953Srrs sctp_auth_chklist_t *chklist = NULL; 2310166675Srrs size_t size = 0; 2311163953Srrs 2312166675Srrs SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); 2313166675Srrs SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); 2314166675Srrs 2315166675Srrs if (stcb) { 2316166675Srrs /* get off the assoc */ 2317166675Srrs chklist = stcb->asoc.peer_auth_chunks; 2318166675Srrs /* is there enough space? */ 2319166675Srrs size = sctp_auth_get_chklist_size(chklist); 2320166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2321166675Srrs error = EINVAL; 2322166675Srrs } else { 2323166675Srrs /* copy in the chunks */ 2324169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2325166675Srrs } 2326166675Srrs SCTP_TCB_UNLOCK(stcb); 2327166675Srrs } else { 2328163953Srrs error = ENOENT; 2329163953Srrs } 2330166675Srrs *optsize = sizeof(struct sctp_authchunks) + size; 2331163953Srrs break; 2332163953Srrs } 2333163953Srrs 2334163953Srrs 2335163953Srrs default: 2336163953Srrs error = ENOPROTOOPT; 2337166675Srrs *optsize = 0; 2338163953Srrs break; 2339163953Srrs } /* end switch (sopt->sopt_name) */ 2340163953Srrs return (error); 2341163953Srrs} 2342163953Srrs 2343163953Srrsstatic int 2344166675Srrssctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, 2345166675Srrs void *p) 2346163953Srrs{ 2347166675Srrs int error, set_opt; 2348166675Srrs uint32_t *mopt; 2349163953Srrs struct sctp_tcb *stcb = NULL; 2350163953Srrs struct sctp_inpcb *inp; 2351167598Srrs uint32_t vrf_id; 2352163953Srrs 2353166675Srrs if (optval == NULL) { 2354169420Srrs SCTP_PRINTF("optval is NULL\n"); 2355163953Srrs return (EINVAL); 2356163953Srrs } 2357163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 2358167598Srrs if (inp == 0) { 2359169420Srrs SCTP_PRINTF("inp is NULL?\n"); 2360163953Srrs return EINVAL; 2361167598Srrs } 2362168299Srrs vrf_id = inp->def_vrf_id; 2363163953Srrs 2364163953Srrs error = 0; 2365166675Srrs switch (optname) { 2366163953Srrs case SCTP_NODELAY: 2367163953Srrs case SCTP_AUTOCLOSE: 2368163953Srrs case SCTP_AUTO_ASCONF: 2369163953Srrs case SCTP_EXPLICIT_EOR: 2370163953Srrs case SCTP_DISABLE_FRAGMENTS: 2371163953Srrs case SCTP_USE_EXT_RCVINFO: 2372163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 2373163953Srrs /* copy in the option value */ 2374166675Srrs SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); 2375163953Srrs set_opt = 0; 2376163953Srrs if (error) 2377163953Srrs break; 2378166675Srrs switch (optname) { 2379163953Srrs case SCTP_DISABLE_FRAGMENTS: 2380163953Srrs set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT; 2381163953Srrs break; 2382163953Srrs case SCTP_AUTO_ASCONF: 2383163953Srrs set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF; 2384163953Srrs break; 2385163953Srrs case SCTP_EXPLICIT_EOR: 2386163953Srrs set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR; 2387163953Srrs break; 2388163953Srrs case SCTP_USE_EXT_RCVINFO: 2389163953Srrs set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO; 2390163953Srrs break; 2391163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 2392163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2393163953Srrs set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4; 2394163953Srrs } else { 2395163953Srrs return (EINVAL); 2396163953Srrs } 2397163953Srrs break; 2398163953Srrs case SCTP_NODELAY: 2399163953Srrs set_opt = SCTP_PCB_FLAGS_NODELAY; 2400163953Srrs break; 2401163953Srrs case SCTP_AUTOCLOSE: 2402163953Srrs set_opt = SCTP_PCB_FLAGS_AUTOCLOSE; 2403163953Srrs /* 2404163953Srrs * The value is in ticks. Note this does not effect 2405163953Srrs * old associations, only new ones. 2406163953Srrs */ 2407163953Srrs inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt); 2408163953Srrs break; 2409163953Srrs } 2410163953Srrs SCTP_INP_WLOCK(inp); 2411163953Srrs if (*mopt != 0) { 2412163953Srrs sctp_feature_on(inp, set_opt); 2413163953Srrs } else { 2414163953Srrs sctp_feature_off(inp, set_opt); 2415163953Srrs } 2416163953Srrs SCTP_INP_WUNLOCK(inp); 2417163953Srrs break; 2418163953Srrs case SCTP_PARTIAL_DELIVERY_POINT: 2419163953Srrs { 2420166675Srrs uint32_t *value; 2421166675Srrs 2422166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); 2423167736Srrs if (*value > SCTP_SB_LIMIT_RCV(so)) { 2424167736Srrs error = EINVAL; 2425167736Srrs break; 2426167736Srrs } 2427166675Srrs inp->partial_delivery_point = *value; 2428163953Srrs } 2429163953Srrs break; 2430163953Srrs case SCTP_FRAGMENT_INTERLEAVE: 2431163953Srrs /* not yet until we re-write sctp_recvmsg() */ 2432163953Srrs { 2433168943Srrs uint32_t *level; 2434163953Srrs 2435168943Srrs SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize); 2436168943Srrs if (*level == SCTP_FRAG_LEVEL_2) { 2437163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 2438168943Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 2439168943Srrs } else if (*level == SCTP_FRAG_LEVEL_1) { 2440168943Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 2441168943Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 2442168943Srrs } else if (*level == SCTP_FRAG_LEVEL_0) { 2443168943Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 2444168943Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 2445168943Srrs 2446163953Srrs } else { 2447168943Srrs error = EINVAL; 2448163953Srrs } 2449163953Srrs } 2450163953Srrs break; 2451163953Srrs case SCTP_CMT_ON_OFF: 2452163953Srrs { 2453163953Srrs struct sctp_assoc_value *av; 2454163953Srrs 2455166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 2456166675Srrs if (sctp_cmt_on_off) { 2457166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2458166675Srrs if (stcb) { 2459163953Srrs stcb->asoc.sctp_cmt_on_off = (uint8_t) av->assoc_value; 2460166675Srrs SCTP_TCB_UNLOCK(stcb); 2461163953Srrs } else { 2462166675Srrs error = ENOTCONN; 2463163953Srrs } 2464166675Srrs } else { 2465166675Srrs error = ENOPROTOOPT; 2466163953Srrs } 2467163953Srrs } 2468163953Srrs break; 2469163953Srrs case SCTP_CLR_STAT_LOG: 2470163953Srrs#ifdef SCTP_STAT_LOGGING 2471163953Srrs sctp_clr_stat_log(); 2472163953Srrs#else 2473163953Srrs error = EOPNOTSUPP; 2474163953Srrs#endif 2475163953Srrs break; 2476163953Srrs case SCTP_CONTEXT: 2477163953Srrs { 2478163953Srrs struct sctp_assoc_value *av; 2479163953Srrs 2480166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 2481166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2482166675Srrs 2483166675Srrs if (stcb) { 2484166675Srrs stcb->asoc.context = av->assoc_value; 2485166675Srrs SCTP_TCB_UNLOCK(stcb); 2486163953Srrs } else { 2487166675Srrs SCTP_INP_WLOCK(inp); 2488163953Srrs inp->sctp_context = av->assoc_value; 2489166675Srrs SCTP_INP_WUNLOCK(inp); 2490163953Srrs } 2491163953Srrs } 2492163953Srrs break; 2493167598Srrs case SCTP_VRF_ID: 2494167598Srrs { 2495167598Srrs uint32_t *vrf_id; 2496167598Srrs 2497167598Srrs SCTP_CHECK_AND_CAST(vrf_id, optval, uint32_t, optsize); 2498167598Srrs if (*vrf_id > SCTP_MAX_VRF_ID) { 2499167598Srrs error = EINVAL; 2500167598Srrs break; 2501167598Srrs } 2502167598Srrs inp->def_vrf_id = *vrf_id; 2503167598Srrs break; 2504167598Srrs } 2505167598Srrs case SCTP_DEL_VRF_ID: 2506167598Srrs { 2507167598Srrs error = EOPNOTSUPP; 2508167598Srrs break; 2509167598Srrs } 2510167598Srrs case SCTP_ADD_VRF_ID: 2511167598Srrs { 2512167598Srrs error = EOPNOTSUPP; 2513167598Srrs break; 2514167598Srrs } 2515167598Srrs 2516163953Srrs case SCTP_DELAYED_ACK_TIME: 2517163953Srrs { 2518163953Srrs struct sctp_assoc_value *tm; 2519163953Srrs 2520166675Srrs SCTP_CHECK_AND_CAST(tm, optval, struct sctp_assoc_value, optsize); 2521166675Srrs SCTP_FIND_STCB(inp, stcb, tm->assoc_id); 2522163953Srrs 2523166675Srrs if (stcb) { 2524166675Srrs stcb->asoc.delayed_ack = tm->assoc_value; 2525166675Srrs SCTP_TCB_UNLOCK(stcb); 2526166675Srrs } else { 2527163953Srrs SCTP_INP_WLOCK(inp); 2528166675Srrs inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(tm->assoc_value); 2529163953Srrs SCTP_INP_WUNLOCK(inp); 2530163953Srrs } 2531166675Srrs break; 2532163953Srrs } 2533163953Srrs case SCTP_AUTH_CHUNK: 2534163953Srrs { 2535163953Srrs struct sctp_authchunk *sauth; 2536163953Srrs 2537166675Srrs SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize); 2538166675Srrs 2539166675Srrs SCTP_INP_WLOCK(inp); 2540166675Srrs if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) 2541163953Srrs error = EINVAL; 2542166675Srrs SCTP_INP_WUNLOCK(inp); 2543163953Srrs break; 2544163953Srrs } 2545163953Srrs case SCTP_AUTH_KEY: 2546163953Srrs { 2547163953Srrs struct sctp_authkey *sca; 2548163953Srrs struct sctp_keyhead *shared_keys; 2549163953Srrs sctp_sharedkey_t *shared_key; 2550163953Srrs sctp_key_t *key = NULL; 2551166675Srrs size_t size; 2552163953Srrs 2553166675Srrs SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize); 2554169420Srrs SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id); 2555169420Srrs size = optsize - sizeof(*sca); 2556166675Srrs 2557166675Srrs if (stcb) { 2558163953Srrs /* set it on the assoc */ 2559163953Srrs shared_keys = &stcb->asoc.shared_keys; 2560163953Srrs /* clear the cached keys for this key id */ 2561163953Srrs sctp_clear_cachedkeys(stcb, sca->sca_keynumber); 2562163953Srrs /* 2563163953Srrs * create the new shared key and 2564163953Srrs * insert/replace it 2565163953Srrs */ 2566163953Srrs if (size > 0) { 2567163953Srrs key = sctp_set_key(sca->sca_key, (uint32_t) size); 2568163953Srrs if (key == NULL) { 2569163953Srrs error = ENOMEM; 2570163953Srrs SCTP_TCB_UNLOCK(stcb); 2571163953Srrs break; 2572163953Srrs } 2573163953Srrs } 2574163953Srrs shared_key = sctp_alloc_sharedkey(); 2575163953Srrs if (shared_key == NULL) { 2576163953Srrs sctp_free_key(key); 2577163953Srrs error = ENOMEM; 2578163953Srrs SCTP_TCB_UNLOCK(stcb); 2579163953Srrs break; 2580163953Srrs } 2581163953Srrs shared_key->key = key; 2582163953Srrs shared_key->keyid = sca->sca_keynumber; 2583163953Srrs sctp_insert_sharedkey(shared_keys, shared_key); 2584163953Srrs SCTP_TCB_UNLOCK(stcb); 2585163953Srrs } else { 2586166675Srrs /* set it on the endpoint */ 2587163953Srrs SCTP_INP_WLOCK(inp); 2588163953Srrs shared_keys = &inp->sctp_ep.shared_keys; 2589163953Srrs /* 2590163953Srrs * clear the cached keys on all assocs for 2591163953Srrs * this key id 2592163953Srrs */ 2593163953Srrs sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber); 2594163953Srrs /* 2595163953Srrs * create the new shared key and 2596163953Srrs * insert/replace it 2597163953Srrs */ 2598163953Srrs if (size > 0) { 2599163953Srrs key = sctp_set_key(sca->sca_key, (uint32_t) size); 2600163953Srrs if (key == NULL) { 2601163953Srrs error = ENOMEM; 2602163953Srrs SCTP_INP_WUNLOCK(inp); 2603163953Srrs break; 2604163953Srrs } 2605163953Srrs } 2606163953Srrs shared_key = sctp_alloc_sharedkey(); 2607163953Srrs if (shared_key == NULL) { 2608163953Srrs sctp_free_key(key); 2609163953Srrs error = ENOMEM; 2610163953Srrs SCTP_INP_WUNLOCK(inp); 2611163953Srrs break; 2612163953Srrs } 2613163953Srrs shared_key->key = key; 2614163953Srrs shared_key->keyid = sca->sca_keynumber; 2615163953Srrs sctp_insert_sharedkey(shared_keys, shared_key); 2616163953Srrs SCTP_INP_WUNLOCK(inp); 2617163953Srrs } 2618163953Srrs break; 2619163953Srrs } 2620163953Srrs case SCTP_HMAC_IDENT: 2621163953Srrs { 2622163953Srrs struct sctp_hmacalgo *shmac; 2623163953Srrs sctp_hmaclist_t *hmaclist; 2624163953Srrs uint32_t hmacid; 2625166675Srrs size_t size, i; 2626163953Srrs 2627166675Srrs SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize); 2628166675Srrs size = (optsize - sizeof(*shmac)) / sizeof(shmac->shmac_idents[0]); 2629163953Srrs hmaclist = sctp_alloc_hmaclist(size); 2630163953Srrs if (hmaclist == NULL) { 2631163953Srrs error = ENOMEM; 2632163953Srrs break; 2633163953Srrs } 2634163953Srrs for (i = 0; i < size; i++) { 2635163953Srrs hmacid = shmac->shmac_idents[i]; 2636163953Srrs if (sctp_auth_add_hmacid(hmaclist, (uint16_t) hmacid)) { 2637163953Srrs /* invalid HMACs were found */ ; 2638163953Srrs error = EINVAL; 2639164085Srrs sctp_free_hmaclist(hmaclist); 2640163953Srrs goto sctp_set_hmac_done; 2641163953Srrs } 2642163953Srrs } 2643163953Srrs /* set it on the endpoint */ 2644163953Srrs SCTP_INP_WLOCK(inp); 2645163953Srrs if (inp->sctp_ep.local_hmacs) 2646163953Srrs sctp_free_hmaclist(inp->sctp_ep.local_hmacs); 2647163953Srrs inp->sctp_ep.local_hmacs = hmaclist; 2648163953Srrs SCTP_INP_WUNLOCK(inp); 2649163953Srrs sctp_set_hmac_done: 2650163953Srrs break; 2651163953Srrs } 2652163953Srrs case SCTP_AUTH_ACTIVE_KEY: 2653163953Srrs { 2654163953Srrs struct sctp_authkeyid *scact; 2655163953Srrs 2656166675Srrs SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize); 2657166675Srrs SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); 2658166675Srrs 2659163953Srrs /* set the active key on the right place */ 2660166675Srrs if (stcb) { 2661163953Srrs /* set the active key on the assoc */ 2662163953Srrs if (sctp_auth_setactivekey(stcb, scact->scact_keynumber)) 2663163953Srrs error = EINVAL; 2664163953Srrs SCTP_TCB_UNLOCK(stcb); 2665163953Srrs } else { 2666163953Srrs /* set the active key on the endpoint */ 2667163953Srrs SCTP_INP_WLOCK(inp); 2668163953Srrs if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) 2669163953Srrs error = EINVAL; 2670163953Srrs SCTP_INP_WUNLOCK(inp); 2671163953Srrs } 2672163953Srrs break; 2673163953Srrs } 2674163953Srrs case SCTP_AUTH_DELETE_KEY: 2675163953Srrs { 2676163953Srrs struct sctp_authkeyid *scdel; 2677163953Srrs 2678166675Srrs SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize); 2679166675Srrs SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id); 2680166675Srrs 2681163953Srrs /* delete the key from the right place */ 2682166675Srrs if (stcb) { 2683163953Srrs if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) 2684163953Srrs error = EINVAL; 2685163953Srrs SCTP_TCB_UNLOCK(stcb); 2686163953Srrs } else { 2687163953Srrs SCTP_INP_WLOCK(inp); 2688163953Srrs if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) 2689163953Srrs error = EINVAL; 2690163953Srrs SCTP_INP_WUNLOCK(inp); 2691163953Srrs } 2692163953Srrs break; 2693163953Srrs } 2694163953Srrs 2695163953Srrs case SCTP_RESET_STREAMS: 2696163953Srrs { 2697163953Srrs struct sctp_stream_reset *strrst; 2698163953Srrs uint8_t send_in = 0, send_tsn = 0, send_out = 0; 2699163953Srrs int i; 2700163953Srrs 2701166675Srrs SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_stream_reset, optsize); 2702166675Srrs SCTP_FIND_STCB(inp, stcb, strrst->strrst_assoc_id); 2703163953Srrs 2704163953Srrs if (stcb == NULL) { 2705163953Srrs error = ENOENT; 2706163953Srrs break; 2707163953Srrs } 2708163953Srrs if (stcb->asoc.peer_supports_strreset == 0) { 2709163953Srrs /* 2710163953Srrs * Peer does not support it, we return 2711163953Srrs * protocol not supported since this is true 2712163953Srrs * for this feature and this peer, not the 2713163953Srrs * socket request in general. 2714163953Srrs */ 2715163953Srrs error = EPROTONOSUPPORT; 2716163953Srrs SCTP_TCB_UNLOCK(stcb); 2717163953Srrs break; 2718163953Srrs } 2719163953Srrs if (stcb->asoc.stream_reset_outstanding) { 2720163953Srrs error = EALREADY; 2721163953Srrs SCTP_TCB_UNLOCK(stcb); 2722163953Srrs break; 2723163953Srrs } 2724163953Srrs if (strrst->strrst_flags == SCTP_RESET_LOCAL_RECV) { 2725163953Srrs send_in = 1; 2726163953Srrs } else if (strrst->strrst_flags == SCTP_RESET_LOCAL_SEND) { 2727163953Srrs send_out = 1; 2728163953Srrs } else if (strrst->strrst_flags == SCTP_RESET_BOTH) { 2729163953Srrs send_in = 1; 2730163953Srrs send_out = 1; 2731163953Srrs } else if (strrst->strrst_flags == SCTP_RESET_TSN) { 2732163953Srrs send_tsn = 1; 2733163953Srrs } else { 2734163953Srrs error = EINVAL; 2735163953Srrs SCTP_TCB_UNLOCK(stcb); 2736163953Srrs break; 2737163953Srrs } 2738163953Srrs for (i = 0; i < strrst->strrst_num_streams; i++) { 2739163953Srrs if ((send_in) && 2740163953Srrs 2741163953Srrs (strrst->strrst_list[i] > stcb->asoc.streamincnt)) { 2742163953Srrs error = EINVAL; 2743163953Srrs goto get_out; 2744163953Srrs } 2745163953Srrs if ((send_out) && 2746163953Srrs (strrst->strrst_list[i] > stcb->asoc.streamoutcnt)) { 2747163953Srrs error = EINVAL; 2748163953Srrs goto get_out; 2749163953Srrs } 2750163953Srrs } 2751163953Srrs if (error) { 2752163953Srrs get_out: 2753163953Srrs SCTP_TCB_UNLOCK(stcb); 2754163953Srrs break; 2755163953Srrs } 2756163953Srrs error = sctp_send_str_reset_req(stcb, strrst->strrst_num_streams, 2757163953Srrs strrst->strrst_list, 2758163953Srrs send_out, (stcb->asoc.str_reset_seq_in - 3), 2759163953Srrs send_in, send_tsn); 2760163953Srrs 2761163953Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ); 2762163953Srrs SCTP_TCB_UNLOCK(stcb); 2763163953Srrs } 2764163953Srrs break; 2765166675Srrs 2766163953Srrs case SCTP_CONNECT_X: 2767166675Srrs if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { 2768163953Srrs error = EINVAL; 2769163953Srrs break; 2770163953Srrs } 2771166675Srrs error = sctp_do_connect_x(so, inp, optval, optsize, p, 0); 2772163953Srrs break; 2773163953Srrs 2774163953Srrs case SCTP_CONNECT_X_DELAYED: 2775166675Srrs if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { 2776163953Srrs error = EINVAL; 2777163953Srrs break; 2778163953Srrs } 2779166675Srrs error = sctp_do_connect_x(so, inp, optval, optsize, p, 1); 2780163953Srrs break; 2781163953Srrs 2782163953Srrs case SCTP_CONNECT_X_COMPLETE: 2783163953Srrs { 2784163953Srrs struct sockaddr *sa; 2785163953Srrs struct sctp_nets *net; 2786163953Srrs 2787166675Srrs /* FIXME MT: check correct? */ 2788166675Srrs SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize); 2789166675Srrs 2790163953Srrs /* find tcb */ 2791163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 2792163953Srrs SCTP_INP_RLOCK(inp); 2793163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 2794163953Srrs if (stcb) { 2795163953Srrs SCTP_TCB_LOCK(stcb); 2796163953Srrs net = sctp_findnet(stcb, sa); 2797163953Srrs } 2798163953Srrs SCTP_INP_RUNLOCK(inp); 2799163953Srrs } else { 2800166675Srrs /* 2801166675Srrs * We increment here since 2802166675Srrs * sctp_findassociation_ep_addr() wil do a 2803166675Srrs * decrement if it finds the stcb as long as 2804166675Srrs * the locked tcb (last argument) is NOT a 2805166675Srrs * TCB.. aka NULL. 2806166675Srrs */ 2807163953Srrs SCTP_INP_INCR_REF(inp); 2808163953Srrs stcb = sctp_findassociation_ep_addr(&inp, sa, &net, NULL, NULL); 2809163953Srrs if (stcb == NULL) { 2810163953Srrs SCTP_INP_DECR_REF(inp); 2811163953Srrs } 2812163953Srrs } 2813163953Srrs 2814163953Srrs if (stcb == NULL) { 2815163953Srrs error = ENOENT; 2816163953Srrs break; 2817163953Srrs } 2818163953Srrs if (stcb->asoc.delayed_connection == 1) { 2819163953Srrs stcb->asoc.delayed_connection = 0; 2820169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 2821165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, 2822165220Srrs stcb->asoc.primary_destination, 2823165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9); 2824163953Srrs sctp_send_initiate(inp, stcb); 2825163953Srrs } else { 2826163953Srrs /* 2827163953Srrs * already expired or did not use delayed 2828163953Srrs * connectx 2829163953Srrs */ 2830163953Srrs error = EALREADY; 2831163953Srrs } 2832163953Srrs SCTP_TCB_UNLOCK(stcb); 2833163953Srrs } 2834163953Srrs break; 2835163953Srrs case SCTP_MAXBURST: 2836163953Srrs { 2837163953Srrs uint8_t *burst; 2838163953Srrs 2839166675Srrs SCTP_CHECK_AND_CAST(burst, optval, uint8_t, optsize); 2840166675Srrs 2841163953Srrs SCTP_INP_WLOCK(inp); 2842163953Srrs if (*burst) { 2843163953Srrs inp->sctp_ep.max_burst = *burst; 2844163953Srrs } 2845163953Srrs SCTP_INP_WUNLOCK(inp); 2846163953Srrs } 2847163953Srrs break; 2848163953Srrs case SCTP_MAXSEG: 2849163953Srrs { 2850167598Srrs struct sctp_assoc_value *av; 2851163953Srrs int ovh; 2852163953Srrs 2853167598Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 2854167598Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2855166675Srrs 2856167598Srrs if (stcb) { 2857167598Srrs error = EINVAL; 2858167598Srrs SCTP_TCB_UNLOCK(stcb); 2859163953Srrs } else { 2860167598Srrs SCTP_INP_WLOCK(inp); 2861167598Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2862167598Srrs ovh = SCTP_MED_OVERHEAD; 2863167598Srrs } else { 2864167598Srrs ovh = SCTP_MED_V4_OVERHEAD; 2865167598Srrs } 2866167598Srrs /* 2867167598Srrs * FIXME MT: I think this is not in tune 2868167598Srrs * with the API ID 2869167598Srrs */ 2870167598Srrs if (av->assoc_value) { 2871167598Srrs inp->sctp_frag_point = (av->assoc_value + ovh); 2872167598Srrs } else { 2873167598Srrs error = EINVAL; 2874167598Srrs } 2875167598Srrs SCTP_INP_WUNLOCK(inp); 2876163953Srrs } 2877163953Srrs } 2878163953Srrs break; 2879163953Srrs case SCTP_EVENTS: 2880163953Srrs { 2881163953Srrs struct sctp_event_subscribe *events; 2882163953Srrs 2883166675Srrs SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize); 2884166675Srrs 2885163953Srrs SCTP_INP_WLOCK(inp); 2886163953Srrs if (events->sctp_data_io_event) { 2887163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); 2888163953Srrs } else { 2889163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); 2890163953Srrs } 2891163953Srrs 2892163953Srrs if (events->sctp_association_event) { 2893163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); 2894163953Srrs } else { 2895163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); 2896163953Srrs } 2897163953Srrs 2898163953Srrs if (events->sctp_address_event) { 2899163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); 2900163953Srrs } else { 2901163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); 2902163953Srrs } 2903163953Srrs 2904163953Srrs if (events->sctp_send_failure_event) { 2905163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 2906163953Srrs } else { 2907163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 2908163953Srrs } 2909163953Srrs 2910163953Srrs if (events->sctp_peer_error_event) { 2911163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR); 2912163953Srrs } else { 2913163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR); 2914163953Srrs } 2915163953Srrs 2916163953Srrs if (events->sctp_shutdown_event) { 2917163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 2918163953Srrs } else { 2919163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 2920163953Srrs } 2921163953Srrs 2922163953Srrs if (events->sctp_partial_delivery_event) { 2923163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT); 2924163953Srrs } else { 2925163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT); 2926163953Srrs } 2927163953Srrs 2928163953Srrs if (events->sctp_adaptation_layer_event) { 2929163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 2930163953Srrs } else { 2931163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 2932163953Srrs } 2933163953Srrs 2934163953Srrs if (events->sctp_authentication_event) { 2935163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT); 2936163953Srrs } else { 2937163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT); 2938163953Srrs } 2939163953Srrs 2940163953Srrs if (events->sctp_stream_reset_events) { 2941163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 2942163953Srrs } else { 2943163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 2944163953Srrs } 2945163953Srrs SCTP_INP_WUNLOCK(inp); 2946163953Srrs } 2947163953Srrs break; 2948163953Srrs 2949163953Srrs case SCTP_ADAPTATION_LAYER: 2950163953Srrs { 2951163953Srrs struct sctp_setadaptation *adap_bits; 2952163953Srrs 2953166675Srrs SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize); 2954163953Srrs SCTP_INP_WLOCK(inp); 2955163953Srrs inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind; 2956163953Srrs SCTP_INP_WUNLOCK(inp); 2957163953Srrs } 2958163953Srrs break; 2959166675Srrs#ifdef SCTP_DEBUG 2960163953Srrs case SCTP_SET_INITIAL_DBG_SEQ: 2961163953Srrs { 2962163953Srrs uint32_t *vvv; 2963163953Srrs 2964166675Srrs SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize); 2965163953Srrs SCTP_INP_WLOCK(inp); 2966163953Srrs inp->sctp_ep.initial_sequence_debug = *vvv; 2967163953Srrs SCTP_INP_WUNLOCK(inp); 2968163953Srrs } 2969163953Srrs break; 2970166675Srrs#endif 2971163953Srrs case SCTP_DEFAULT_SEND_PARAM: 2972163953Srrs { 2973163953Srrs struct sctp_sndrcvinfo *s_info; 2974163953Srrs 2975166675Srrs SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize); 2976166675Srrs SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); 2977163953Srrs 2978166675Srrs if (stcb) { 2979166675Srrs if (s_info->sinfo_stream <= stcb->asoc.streamoutcnt) { 2980166675Srrs stcb->asoc.def_send = *s_info; 2981163953Srrs } else { 2982166675Srrs error = EINVAL; 2983163953Srrs } 2984166675Srrs SCTP_TCB_UNLOCK(stcb); 2985166675Srrs } else { 2986166675Srrs SCTP_INP_WLOCK(inp); 2987163953Srrs inp->def_send = *s_info; 2988166675Srrs SCTP_INP_WUNLOCK(inp); 2989163953Srrs } 2990163953Srrs } 2991163953Srrs break; 2992163953Srrs case SCTP_PEER_ADDR_PARAMS: 2993163953Srrs /* Applys to the specific association */ 2994163953Srrs { 2995163953Srrs struct sctp_paddrparams *paddrp; 2996163953Srrs struct sctp_nets *net; 2997163953Srrs 2998166675Srrs SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize); 2999166675Srrs SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); 3000163953Srrs net = NULL; 3001166675Srrs if (stcb) { 3002166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address); 3003166675Srrs } else { 3004166675Srrs /* 3005166675Srrs * We increment here since 3006166675Srrs * sctp_findassociation_ep_addr() wil do a 3007166675Srrs * decrement if it finds the stcb as long as 3008166675Srrs * the locked tcb (last argument) is NOT a 3009166675Srrs * TCB.. aka NULL. 3010166675Srrs */ 3011166675Srrs SCTP_INP_INCR_REF(inp); 3012166675Srrs stcb = sctp_findassociation_ep_addr(&inp, 3013166675Srrs (struct sockaddr *)&paddrp->spp_address, 3014166675Srrs &net, NULL, NULL); 3015163953Srrs if (stcb == NULL) { 3016166675Srrs SCTP_INP_DECR_REF(inp); 3017163953Srrs } 3018163953Srrs } 3019166675Srrs 3020166675Srrs 3021163953Srrs if (stcb) { 3022163953Srrs /************************TCB SPECIFIC SET ******************/ 3023163953Srrs /* 3024163953Srrs * do we change the timer for HB, we run 3025163953Srrs * only one? 3026163953Srrs */ 3027163953Srrs if (paddrp->spp_hbinterval) 3028163953Srrs stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval; 3029163953Srrs else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) 3030163953Srrs stcb->asoc.heart_beat_delay = 0; 3031163953Srrs 3032163953Srrs /* network sets ? */ 3033163953Srrs if (net) { 3034163953Srrs /************************NET SPECIFIC SET ******************/ 3035163953Srrs if (paddrp->spp_flags & SPP_HB_DEMAND) { 3036163953Srrs /* on demand HB */ 3037169378Srrs (void)sctp_send_hb(stcb, 1, net); 3038163953Srrs } 3039163953Srrs if (paddrp->spp_flags & SPP_HB_DISABLE) { 3040163953Srrs net->dest_state |= SCTP_ADDR_NOHB; 3041163953Srrs } 3042163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 3043163953Srrs net->dest_state &= ~SCTP_ADDR_NOHB; 3044163953Srrs } 3045163953Srrs if (paddrp->spp_flags & SPP_PMTUD_DISABLE) { 3046165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 3047165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 3048165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 3049163953Srrs } 3050163953Srrs if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) { 3051163953Srrs net->mtu = paddrp->spp_pathmtu; 3052169352Srrs if (net->mtu < stcb->asoc.smallest_mtu) { 3053169352Srrs#ifdef SCTP_PRINT_FOR_B_AND_M 3054169420Srrs SCTP_PRINTF("SCTP_PMTU_DISABLE calls sctp_pathmtu_adjustment:%d\n", 3055169352Srrs net->mtu); 3056169352Srrs#endif 3057167695Srrs sctp_pathmtu_adjustment(inp, stcb, net, net->mtu); 3058169352Srrs } 3059163953Srrs } 3060163953Srrs } 3061163953Srrs if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 3062165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 3063163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 3064163953Srrs } 3065163953Srrs } 3066163953Srrs if (paddrp->spp_pathmaxrxt) 3067163953Srrs net->failure_threshold = paddrp->spp_pathmaxrxt; 3068167598Srrs#ifdef INET 3069163953Srrs if (paddrp->spp_flags & SPP_IPV4_TOS) { 3070163953Srrs if (net->ro._l_addr.sin.sin_family == AF_INET) { 3071163953Srrs net->tos_flowlabel = paddrp->spp_ipv4_tos & 0x000000fc; 3072163953Srrs } 3073163953Srrs } 3074163953Srrs#endif 3075167598Srrs#ifdef INET6 3076163953Srrs if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { 3077163953Srrs if (net->ro._l_addr.sin6.sin6_family == AF_INET6) { 3078163953Srrs net->tos_flowlabel = paddrp->spp_ipv6_flowlabel; 3079163953Srrs } 3080163953Srrs } 3081163953Srrs#endif 3082163953Srrs } else { 3083163953Srrs /************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/ 3084163953Srrs if (paddrp->spp_pathmaxrxt) 3085163953Srrs stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt; 3086163953Srrs 3087163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 3088163953Srrs /* Turn back on the timer */ 3089163953Srrs stcb->asoc.hb_is_disabled = 0; 3090163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 3091163953Srrs } 3092163953Srrs if (paddrp->spp_flags & SPP_HB_DISABLE) { 3093163953Srrs int cnt_of_unconf = 0; 3094163953Srrs struct sctp_nets *lnet; 3095163953Srrs 3096163953Srrs stcb->asoc.hb_is_disabled = 1; 3097163953Srrs TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 3098163953Srrs if (lnet->dest_state & SCTP_ADDR_UNCONFIRMED) { 3099163953Srrs cnt_of_unconf++; 3100163953Srrs } 3101163953Srrs } 3102163953Srrs /* 3103163953Srrs * stop the timer ONLY if we 3104163953Srrs * have no unconfirmed 3105163953Srrs * addresses 3106163953Srrs */ 3107163953Srrs if (cnt_of_unconf == 0) { 3108165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11); 3109163953Srrs } 3110163953Srrs } 3111163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 3112163953Srrs /* start up the timer. */ 3113163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 3114163953Srrs } 3115167598Srrs#ifdef INET 3116163953Srrs if (paddrp->spp_flags & SPP_IPV4_TOS) 3117163953Srrs stcb->asoc.default_tos = paddrp->spp_ipv4_tos & 0x000000fc; 3118163953Srrs#endif 3119167598Srrs#ifdef INET6 3120163953Srrs if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) 3121163953Srrs stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel; 3122163953Srrs#endif 3123163953Srrs 3124163953Srrs } 3125163953Srrs SCTP_TCB_UNLOCK(stcb); 3126163953Srrs } else { 3127163953Srrs /************************NO TCB, SET TO default stuff ******************/ 3128163953Srrs SCTP_INP_WLOCK(inp); 3129163953Srrs /* 3130163953Srrs * For the TOS/FLOWLABEL stuff you set it 3131163953Srrs * with the options on the socket 3132163953Srrs */ 3133163953Srrs if (paddrp->spp_pathmaxrxt) { 3134163953Srrs inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt; 3135163953Srrs } 3136163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 3137163953Srrs inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval); 3138163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 3139163953Srrs } else if (paddrp->spp_flags & SPP_HB_DISABLE) { 3140163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 3141163953Srrs } 3142163953Srrs SCTP_INP_WUNLOCK(inp); 3143163953Srrs } 3144163953Srrs } 3145163953Srrs break; 3146163953Srrs case SCTP_RTOINFO: 3147163953Srrs { 3148163953Srrs struct sctp_rtoinfo *srto; 3149163953Srrs 3150166675Srrs SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize); 3151166675Srrs SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); 3152166675Srrs 3153166675Srrs if (stcb) { 3154166675Srrs /* Set in ms we hope :-) */ 3155167598Srrs if (srto->srto_initial) 3156166675Srrs stcb->asoc.initial_rto = srto->srto_initial; 3157167598Srrs if (srto->srto_max) 3158166675Srrs stcb->asoc.maxrto = srto->srto_max; 3159167598Srrs if (srto->srto_min) 3160166675Srrs stcb->asoc.minrto = srto->srto_min; 3161166675Srrs SCTP_TCB_UNLOCK(stcb); 3162166675Srrs } else { 3163163953Srrs SCTP_INP_WLOCK(inp); 3164163953Srrs /* 3165163953Srrs * If we have a null asoc, its default for 3166163953Srrs * the endpoint 3167163953Srrs */ 3168167598Srrs if (srto->srto_initial) 3169163953Srrs inp->sctp_ep.initial_rto = srto->srto_initial; 3170167598Srrs if (srto->srto_max) 3171163953Srrs inp->sctp_ep.sctp_maxrto = srto->srto_max; 3172167598Srrs if (srto->srto_min) 3173163953Srrs inp->sctp_ep.sctp_minrto = srto->srto_min; 3174163953Srrs SCTP_INP_WUNLOCK(inp); 3175163953Srrs } 3176163953Srrs } 3177163953Srrs break; 3178163953Srrs case SCTP_ASSOCINFO: 3179163953Srrs { 3180163953Srrs struct sctp_assocparams *sasoc; 3181163953Srrs 3182166675Srrs SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize); 3183166675Srrs SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); 3184166675Srrs 3185163953Srrs if (stcb) { 3186163953Srrs if (sasoc->sasoc_asocmaxrxt) 3187163953Srrs stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt; 3188163953Srrs sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets; 3189163953Srrs sasoc->sasoc_peer_rwnd = 0; 3190163953Srrs sasoc->sasoc_local_rwnd = 0; 3191163953Srrs if (stcb->asoc.cookie_life) 3192163953Srrs stcb->asoc.cookie_life = sasoc->sasoc_cookie_life; 3193167598Srrs stcb->asoc.delayed_ack = sasoc->sasoc_sack_delay; 3194167598Srrs if (sasoc->sasoc_sack_freq) { 3195167598Srrs stcb->asoc.sack_freq = sasoc->sasoc_sack_freq; 3196167598Srrs } 3197163953Srrs SCTP_TCB_UNLOCK(stcb); 3198163953Srrs } else { 3199163953Srrs SCTP_INP_WLOCK(inp); 3200163953Srrs if (sasoc->sasoc_asocmaxrxt) 3201163953Srrs inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt; 3202163953Srrs sasoc->sasoc_number_peer_destinations = 0; 3203163953Srrs sasoc->sasoc_peer_rwnd = 0; 3204163953Srrs sasoc->sasoc_local_rwnd = 0; 3205163953Srrs if (sasoc->sasoc_cookie_life) 3206163953Srrs inp->sctp_ep.def_cookie_life = sasoc->sasoc_cookie_life; 3207167598Srrs inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sasoc->sasoc_sack_delay); 3208167598Srrs if (sasoc->sasoc_sack_freq) { 3209167598Srrs inp->sctp_ep.sctp_sack_freq = sasoc->sasoc_sack_freq; 3210167598Srrs } 3211163953Srrs SCTP_INP_WUNLOCK(inp); 3212163953Srrs } 3213163953Srrs } 3214163953Srrs break; 3215163953Srrs case SCTP_INITMSG: 3216163953Srrs { 3217163953Srrs struct sctp_initmsg *sinit; 3218163953Srrs 3219166675Srrs SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize); 3220163953Srrs SCTP_INP_WLOCK(inp); 3221163953Srrs if (sinit->sinit_num_ostreams) 3222163953Srrs inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams; 3223163953Srrs 3224163953Srrs if (sinit->sinit_max_instreams) 3225163953Srrs inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams; 3226163953Srrs 3227163953Srrs if (sinit->sinit_max_attempts) 3228163953Srrs inp->sctp_ep.max_init_times = sinit->sinit_max_attempts; 3229163953Srrs 3230167598Srrs if (sinit->sinit_max_init_timeo) 3231163953Srrs inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo; 3232163953Srrs SCTP_INP_WUNLOCK(inp); 3233163953Srrs } 3234163953Srrs break; 3235163953Srrs case SCTP_PRIMARY_ADDR: 3236163953Srrs { 3237163953Srrs struct sctp_setprim *spa; 3238163953Srrs struct sctp_nets *net, *lnet; 3239163953Srrs 3240166675Srrs SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize); 3241166675Srrs SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id); 3242163953Srrs 3243166675Srrs net = NULL; 3244166675Srrs if (stcb) { 3245166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&spa->ssp_addr); 3246166675Srrs } else { 3247166675Srrs /* 3248166675Srrs * We increment here since 3249166675Srrs * sctp_findassociation_ep_addr() wil do a 3250166675Srrs * decrement if it finds the stcb as long as 3251166675Srrs * the locked tcb (last argument) is NOT a 3252166675Srrs * TCB.. aka NULL. 3253166675Srrs */ 3254163953Srrs SCTP_INP_INCR_REF(inp); 3255163953Srrs stcb = sctp_findassociation_ep_addr(&inp, 3256163953Srrs (struct sockaddr *)&spa->ssp_addr, 3257163953Srrs &net, NULL, NULL); 3258163953Srrs if (stcb == NULL) { 3259163953Srrs SCTP_INP_DECR_REF(inp); 3260163953Srrs } 3261163953Srrs } 3262166675Srrs 3263166675Srrs if ((stcb) && (net)) { 3264166675Srrs if ((net != stcb->asoc.primary_destination) && 3265166675Srrs (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) { 3266166675Srrs /* Ok we need to set it */ 3267166675Srrs lnet = stcb->asoc.primary_destination; 3268166675Srrs if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) { 3269166675Srrs if (net->dest_state & SCTP_ADDR_SWITCH_PRIMARY) { 3270166675Srrs net->dest_state |= SCTP_ADDR_DOUBLE_SWITCH; 3271166675Srrs } 3272166675Srrs net->dest_state |= SCTP_ADDR_SWITCH_PRIMARY; 3273163953Srrs } 3274163953Srrs } 3275166675Srrs } else { 3276166675Srrs error = EINVAL; 3277163953Srrs } 3278166675Srrs if (stcb) { 3279166675Srrs SCTP_TCB_UNLOCK(stcb); 3280166675Srrs } 3281163953Srrs } 3282163953Srrs break; 3283167598Srrs case SCTP_SET_DYNAMIC_PRIMARY: 3284167598Srrs { 3285167598Srrs union sctp_sockstore *ss; 3286163953Srrs 3287167598Srrs error = priv_check_cred(curthread->td_ucred, 3288167598Srrs PRIV_NETINET_RESERVEDPORT, 3289167598Srrs SUSER_ALLOWJAIL); 3290167598Srrs if (error) 3291167598Srrs break; 3292167598Srrs 3293167598Srrs SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize); 3294167598Srrs /* SUPER USER CHECK? */ 3295167598Srrs error = sctp_dynamic_set_primary(&ss->sa, vrf_id); 3296167598Srrs } 3297167598Srrs break; 3298163953Srrs case SCTP_SET_PEER_PRIMARY_ADDR: 3299163953Srrs { 3300163953Srrs struct sctp_setpeerprim *sspp; 3301163953Srrs 3302166675Srrs SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize); 3303166675Srrs SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id); 3304169208Srrs if (stcb != NULL) { 3305166675Srrs if (sctp_set_primary_ip_address_sa(stcb, (struct sockaddr *)&sspp->sspp_addr) != 0) { 3306166675Srrs error = EINVAL; 3307166675Srrs } 3308169208Srrs SCTP_TCB_UNLOCK(stcb); 3309166675Srrs } else { 3310163953Srrs error = EINVAL; 3311163953Srrs } 3312169208Srrs 3313163953Srrs } 3314163953Srrs break; 3315163953Srrs case SCTP_BINDX_ADD_ADDR: 3316163953Srrs { 3317163953Srrs struct sctp_getaddresses *addrs; 3318163953Srrs struct sockaddr *addr_touse; 3319163953Srrs struct sockaddr_in sin; 3320163953Srrs 3321166675Srrs SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize); 3322166675Srrs 3323163953Srrs /* see if we're bound all already! */ 3324163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 3325163953Srrs error = EINVAL; 3326163953Srrs break; 3327163953Srrs } 3328167598Srrs /* Is the VRF one we have */ 3329163953Srrs addr_touse = addrs->addr; 3330167695Srrs#if defined(INET6) 3331163953Srrs if (addrs->addr->sa_family == AF_INET6) { 3332163953Srrs struct sockaddr_in6 *sin6; 3333163953Srrs 3334163953Srrs sin6 = (struct sockaddr_in6 *)addr_touse; 3335163953Srrs if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 3336163953Srrs in6_sin6_2_sin(&sin, sin6); 3337163953Srrs addr_touse = (struct sockaddr *)&sin; 3338163953Srrs } 3339163953Srrs } 3340167695Srrs#endif 3341163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { 3342163953Srrs if (p == NULL) { 3343163953Srrs /* Can't get proc for Net/Open BSD */ 3344163953Srrs error = EINVAL; 3345163953Srrs break; 3346163953Srrs } 3347163953Srrs error = sctp_inpcb_bind(so, addr_touse, p); 3348163953Srrs break; 3349163953Srrs } 3350163953Srrs /* 3351163953Srrs * No locks required here since bind and mgmt_ep_sa 3352163953Srrs * all do their own locking. If we do something for 3353163953Srrs * the FIX: below we may need to lock in that case. 3354163953Srrs */ 3355163953Srrs if (addrs->sget_assoc_id == 0) { 3356163953Srrs /* add the address */ 3357163953Srrs struct sctp_inpcb *lep; 3358163953Srrs 3359163953Srrs ((struct sockaddr_in *)addr_touse)->sin_port = inp->sctp_lport; 3360167598Srrs lep = sctp_pcb_findep(addr_touse, 1, 0, vrf_id); 3361163953Srrs if (lep != NULL) { 3362163953Srrs /* 3363163953Srrs * We must decrement the refcount 3364163953Srrs * since we have the ep already and 3365163953Srrs * are binding. No remove going on 3366163953Srrs * here. 3367163953Srrs */ 3368163953Srrs SCTP_INP_DECR_REF(inp); 3369163953Srrs } 3370163953Srrs if (lep == inp) { 3371163953Srrs /* already bound to it.. ok */ 3372163953Srrs break; 3373163953Srrs } else if (lep == NULL) { 3374163953Srrs ((struct sockaddr_in *)addr_touse)->sin_port = 0; 3375163953Srrs error = sctp_addr_mgmt_ep_sa(inp, addr_touse, 3376167598Srrs SCTP_ADD_IP_ADDRESS, vrf_id); 3377163953Srrs } else { 3378163953Srrs error = EADDRNOTAVAIL; 3379163953Srrs } 3380163953Srrs if (error) 3381163953Srrs break; 3382163953Srrs 3383163953Srrs } else { 3384163953Srrs /* 3385163953Srrs * FIX: decide whether we allow assoc based 3386163953Srrs * bindx 3387163953Srrs */ 3388163953Srrs } 3389163953Srrs } 3390163953Srrs break; 3391163953Srrs case SCTP_BINDX_REM_ADDR: 3392163953Srrs { 3393163953Srrs struct sctp_getaddresses *addrs; 3394163953Srrs struct sockaddr *addr_touse; 3395163953Srrs struct sockaddr_in sin; 3396163953Srrs 3397166675Srrs SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize); 3398163953Srrs /* see if we're bound all already! */ 3399163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 3400163953Srrs error = EINVAL; 3401163953Srrs break; 3402163953Srrs } 3403163953Srrs addr_touse = addrs->addr; 3404167695Srrs#if defined(INET6) 3405163953Srrs if (addrs->addr->sa_family == AF_INET6) { 3406163953Srrs struct sockaddr_in6 *sin6; 3407163953Srrs 3408163953Srrs sin6 = (struct sockaddr_in6 *)addr_touse; 3409163953Srrs if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 3410163953Srrs in6_sin6_2_sin(&sin, sin6); 3411163953Srrs addr_touse = (struct sockaddr *)&sin; 3412163953Srrs } 3413163953Srrs } 3414167695Srrs#endif 3415163953Srrs /* 3416163953Srrs * No lock required mgmt_ep_sa does its own locking. 3417163953Srrs * If the FIX: below is ever changed we may need to 3418163953Srrs * lock before calling association level binding. 3419163953Srrs */ 3420163953Srrs if (addrs->sget_assoc_id == 0) { 3421163953Srrs /* delete the address */ 3422169420Srrs (void)sctp_addr_mgmt_ep_sa(inp, addr_touse, 3423167598Srrs SCTP_DEL_IP_ADDRESS, vrf_id); 3424163953Srrs } else { 3425163953Srrs /* 3426163953Srrs * FIX: decide whether we allow assoc based 3427163953Srrs * bindx 3428163953Srrs */ 3429163953Srrs } 3430163953Srrs } 3431163953Srrs break; 3432163953Srrs default: 3433163953Srrs error = ENOPROTOOPT; 3434163953Srrs break; 3435163953Srrs } /* end switch (opt) */ 3436163953Srrs return (error); 3437163953Srrs} 3438163953Srrs 3439163953Srrs 3440163953Srrsint 3441163953Srrssctp_ctloutput(struct socket *so, struct sockopt *sopt) 3442163953Srrs{ 3443166675Srrs void *optval = NULL; 3444166675Srrs size_t optsize = 0; 3445163953Srrs struct sctp_inpcb *inp; 3446166675Srrs void *p; 3447166675Srrs int error = 0; 3448163953Srrs 3449163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3450163953Srrs if (inp == 0) { 3451163953Srrs /* I made the same as TCP since we are not setup? */ 3452163953Srrs return (ECONNRESET); 3453163953Srrs } 3454163953Srrs if (sopt->sopt_level != IPPROTO_SCTP) { 3455163953Srrs /* wrong proto level... send back up to IP */ 3456163953Srrs#ifdef INET6 3457163953Srrs if (INP_CHECK_SOCKAF(so, AF_INET6)) 3458163953Srrs error = ip6_ctloutput(so, sopt); 3459163953Srrs else 3460163953Srrs#endif /* INET6 */ 3461163953Srrs error = ip_ctloutput(so, sopt); 3462163953Srrs return (error); 3463163953Srrs } 3464166675Srrs optsize = sopt->sopt_valsize; 3465166675Srrs if (optsize) { 3466166675Srrs SCTP_MALLOC(optval, void *, optsize, "SCTPSockOpt"); 3467166675Srrs if (optval == NULL) { 3468163953Srrs return (ENOBUFS); 3469163953Srrs } 3470166675Srrs error = sooptcopyin(sopt, optval, optsize, optsize); 3471163953Srrs if (error) { 3472166675Srrs SCTP_FREE(optval); 3473163953Srrs goto out; 3474163953Srrs } 3475163953Srrs } 3476166675Srrs p = (void *)sopt->sopt_td; 3477163953Srrs if (sopt->sopt_dir == SOPT_SET) { 3478166675Srrs error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p); 3479163953Srrs } else if (sopt->sopt_dir == SOPT_GET) { 3480166675Srrs error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p); 3481163953Srrs } else { 3482163953Srrs error = EINVAL; 3483163953Srrs } 3484166675Srrs if ((error == 0) && (optval != NULL)) { 3485166675Srrs error = sooptcopyout(sopt, optval, optsize); 3486166675Srrs SCTP_FREE(optval); 3487166675Srrs } else if (optval != NULL) { 3488166675Srrs SCTP_FREE(optval); 3489163953Srrs } 3490163953Srrsout: 3491163953Srrs return (error); 3492163953Srrs} 3493163953Srrs 3494163953Srrs 3495163953Srrsstatic int 3496163953Srrssctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p) 3497163953Srrs{ 3498163953Srrs int error = 0; 3499163953Srrs int create_lock_on = 0; 3500167598Srrs uint32_t vrf_id; 3501163953Srrs struct sctp_inpcb *inp; 3502163953Srrs struct sctp_tcb *stcb = NULL; 3503163953Srrs 3504163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3505163953Srrs if (inp == 0) { 3506163953Srrs /* I made the same as TCP since we are not setup? */ 3507163953Srrs return (ECONNRESET); 3508163953Srrs } 3509163953Srrs SCTP_ASOC_CREATE_LOCK(inp); 3510163953Srrs create_lock_on = 1; 3511163953Srrs 3512163953Srrs SCTP_INP_INCR_REF(inp); 3513163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 3514163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 3515163953Srrs /* Should I really unlock ? */ 3516163953Srrs error = EFAULT; 3517163953Srrs goto out_now; 3518163953Srrs } 3519163953Srrs#ifdef INET6 3520163953Srrs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 3521163953Srrs (addr->sa_family == AF_INET6)) { 3522163953Srrs error = EINVAL; 3523163953Srrs goto out_now; 3524163953Srrs } 3525163953Srrs#endif /* INET6 */ 3526163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 3527163953Srrs SCTP_PCB_FLAGS_UNBOUND) { 3528163953Srrs /* Bind a ephemeral port */ 3529163953Srrs error = sctp_inpcb_bind(so, NULL, p); 3530163953Srrs if (error) { 3531163953Srrs goto out_now; 3532163953Srrs } 3533163953Srrs } 3534163953Srrs /* Now do we connect? */ 3535163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) { 3536163953Srrs error = EINVAL; 3537163953Srrs goto out_now; 3538163953Srrs } 3539163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 3540163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 3541163953Srrs /* We are already connected AND the TCP model */ 3542163953Srrs error = EADDRINUSE; 3543163953Srrs goto out_now; 3544163953Srrs } 3545163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 3546163953Srrs SCTP_INP_RLOCK(inp); 3547163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 3548163953Srrs SCTP_INP_RUNLOCK(inp); 3549163953Srrs } else { 3550163953Srrs /* 3551166675Srrs * We increment here since sctp_findassociation_ep_addr() 3552166675Srrs * wil do a decrement if it finds the stcb as long as the 3553166675Srrs * locked tcb (last argument) is NOT a TCB.. aka NULL. 3554163953Srrs */ 3555163953Srrs SCTP_INP_INCR_REF(inp); 3556163953Srrs stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL); 3557163953Srrs if (stcb == NULL) { 3558163953Srrs SCTP_INP_DECR_REF(inp); 3559168299Srrs } else { 3560168299Srrs SCTP_TCB_LOCK(stcb); 3561163953Srrs } 3562163953Srrs } 3563163953Srrs if (stcb != NULL) { 3564163953Srrs /* Already have or am bring up an association */ 3565163953Srrs error = EALREADY; 3566163953Srrs goto out_now; 3567163953Srrs } 3568168299Srrs vrf_id = inp->def_vrf_id; 3569163953Srrs /* We are GOOD to go */ 3570167598Srrs stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0, vrf_id); 3571163953Srrs if (stcb == NULL) { 3572163953Srrs /* Gak! no memory */ 3573167598Srrs goto out_now; 3574163953Srrs } 3575163953Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 3576163953Srrs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 3577163953Srrs /* Set the connected flag so we can queue data */ 3578163953Srrs soisconnecting(so); 3579163953Srrs } 3580163953Srrs stcb->asoc.state = SCTP_STATE_COOKIE_WAIT; 3581169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 3582163953Srrs 3583163953Srrs /* initialize authentication parameters for the assoc */ 3584163953Srrs sctp_initialize_auth_params(inp, stcb); 3585163953Srrs 3586163953Srrs sctp_send_initiate(inp, stcb); 3587168299Srrs SCTP_TCB_UNLOCK(stcb); 3588163953Srrsout_now: 3589169420Srrs if (create_lock_on) { 3590163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 3591169420Srrs } 3592163953Srrs SCTP_INP_DECR_REF(inp); 3593163953Srrs return error; 3594163953Srrs} 3595163953Srrs 3596163953Srrsint 3597163953Srrssctp_listen(struct socket *so, int backlog, struct thread *p) 3598163953Srrs{ 3599163953Srrs /* 3600163953Srrs * Note this module depends on the protocol processing being called 3601163953Srrs * AFTER any socket level flags and backlog are applied to the 3602163953Srrs * socket. The traditional way that the socket flags are applied is 3603163953Srrs * AFTER protocol processing. We have made a change to the 3604163953Srrs * sys/kern/uipc_socket.c module to reverse this but this MUST be in 3605163953Srrs * place if the socket API for SCTP is to work properly. 3606163953Srrs */ 3607163953Srrs 3608163953Srrs int error = 0; 3609163953Srrs struct sctp_inpcb *inp; 3610163953Srrs 3611163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3612163953Srrs if (inp == 0) { 3613163953Srrs /* I made the same as TCP since we are not setup? */ 3614163953Srrs return (ECONNRESET); 3615163953Srrs } 3616163953Srrs SCTP_INP_RLOCK(inp); 3617163953Srrs#ifdef SCTP_LOCK_LOGGING 3618163953Srrs sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK); 3619163953Srrs#endif 3620163953Srrs SOCK_LOCK(so); 3621163953Srrs error = solisten_proto_check(so); 3622163953Srrs if (error) { 3623163953Srrs SOCK_UNLOCK(so); 3624169208Srrs SCTP_INP_RUNLOCK(inp); 3625163953Srrs return (error); 3626163953Srrs } 3627163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 3628163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 3629163953Srrs /* We are already connected AND the TCP model */ 3630163953Srrs SCTP_INP_RUNLOCK(inp); 3631163953Srrs SOCK_UNLOCK(so); 3632163953Srrs return (EADDRINUSE); 3633163953Srrs } 3634163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { 3635163953Srrs /* We must do a bind. */ 3636166675Srrs SOCK_UNLOCK(so); 3637163953Srrs SCTP_INP_RUNLOCK(inp); 3638163953Srrs if ((error = sctp_inpcb_bind(so, NULL, p))) { 3639163953Srrs /* bind error, probably perm */ 3640163953Srrs return (error); 3641163953Srrs } 3642166675Srrs SOCK_LOCK(so); 3643163953Srrs } else { 3644163953Srrs SCTP_INP_RUNLOCK(inp); 3645163953Srrs } 3646163953Srrs /* It appears for 7.0 and on, we must always call this. */ 3647163953Srrs solisten_proto(so, backlog); 3648163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 3649163953Srrs /* remove the ACCEPTCONN flag for one-to-many sockets */ 3650163953Srrs so->so_options &= ~SO_ACCEPTCONN; 3651163953Srrs } 3652163953Srrs if (backlog == 0) { 3653163953Srrs /* turning off listen */ 3654163953Srrs so->so_options &= ~SO_ACCEPTCONN; 3655163953Srrs } 3656163953Srrs SOCK_UNLOCK(so); 3657163953Srrs return (error); 3658163953Srrs} 3659163953Srrs 3660163953Srrsstatic int sctp_defered_wakeup_cnt = 0; 3661163953Srrs 3662163953Srrsint 3663163953Srrssctp_accept(struct socket *so, struct sockaddr **addr) 3664163953Srrs{ 3665163953Srrs struct sctp_tcb *stcb; 3666163953Srrs struct sctp_inpcb *inp; 3667163953Srrs union sctp_sockstore store; 3668163953Srrs 3669163953Srrs int error; 3670163953Srrs 3671163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3672163953Srrs 3673163953Srrs if (inp == 0) { 3674163953Srrs return (ECONNRESET); 3675163953Srrs } 3676163953Srrs SCTP_INP_RLOCK(inp); 3677163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 3678168299Srrs SCTP_INP_RUNLOCK(inp); 3679163953Srrs return (ENOTSUP); 3680163953Srrs } 3681163953Srrs if (so->so_state & SS_ISDISCONNECTED) { 3682163953Srrs SCTP_INP_RUNLOCK(inp); 3683163953Srrs return (ECONNABORTED); 3684163953Srrs } 3685163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 3686163953Srrs if (stcb == NULL) { 3687163953Srrs SCTP_INP_RUNLOCK(inp); 3688163953Srrs return (ECONNRESET); 3689163953Srrs } 3690163953Srrs SCTP_TCB_LOCK(stcb); 3691163953Srrs SCTP_INP_RUNLOCK(inp); 3692163953Srrs store = stcb->asoc.primary_destination->ro._l_addr; 3693163953Srrs SCTP_TCB_UNLOCK(stcb); 3694163953Srrs if (store.sa.sa_family == AF_INET) { 3695163953Srrs struct sockaddr_in *sin; 3696163953Srrs 3697163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 3698163953Srrs sin->sin_family = AF_INET; 3699163953Srrs sin->sin_len = sizeof(*sin); 3700163953Srrs sin->sin_port = ((struct sockaddr_in *)&store)->sin_port; 3701163953Srrs sin->sin_addr = ((struct sockaddr_in *)&store)->sin_addr; 3702163953Srrs *addr = (struct sockaddr *)sin; 3703163953Srrs } else { 3704163953Srrs struct sockaddr_in6 *sin6; 3705163953Srrs 3706163953Srrs SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); 3707163953Srrs sin6->sin6_family = AF_INET6; 3708163953Srrs sin6->sin6_len = sizeof(*sin6); 3709163953Srrs sin6->sin6_port = ((struct sockaddr_in6 *)&store)->sin6_port; 3710163953Srrs 3711163953Srrs sin6->sin6_addr = ((struct sockaddr_in6 *)&store)->sin6_addr; 3712164085Srrs if ((error = sa6_recoverscope(sin6)) != 0) { 3713164085Srrs SCTP_FREE_SONAME(sin6); 3714163953Srrs return (error); 3715164085Srrs } 3716163953Srrs *addr = (struct sockaddr *)sin6; 3717163953Srrs } 3718163953Srrs /* Wake any delayed sleep action */ 3719163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { 3720166086Srrs SCTP_INP_WLOCK(inp); 3721163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE; 3722163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) { 3723163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT; 3724166086Srrs SCTP_INP_WUNLOCK(inp); 3725163953Srrs SOCKBUF_LOCK(&inp->sctp_socket->so_snd); 3726163953Srrs if (sowriteable(inp->sctp_socket)) { 3727163953Srrs sowwakeup_locked(inp->sctp_socket); 3728163953Srrs } else { 3729163953Srrs SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd); 3730163953Srrs } 3731166086Srrs SCTP_INP_WLOCK(inp); 3732163953Srrs } 3733163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) { 3734163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT; 3735166086Srrs SCTP_INP_WUNLOCK(inp); 3736163953Srrs SOCKBUF_LOCK(&inp->sctp_socket->so_rcv); 3737163953Srrs if (soreadable(inp->sctp_socket)) { 3738163953Srrs sctp_defered_wakeup_cnt++; 3739163953Srrs sorwakeup_locked(inp->sctp_socket); 3740163953Srrs } else { 3741163953Srrs SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv); 3742163953Srrs } 3743166086Srrs SCTP_INP_WLOCK(inp); 3744163953Srrs } 3745166086Srrs SCTP_INP_WUNLOCK(inp); 3746163953Srrs } 3747163953Srrs return (0); 3748163953Srrs} 3749163953Srrs 3750163953Srrsint 3751163953Srrssctp_ingetaddr(struct socket *so, struct sockaddr **addr) 3752163953Srrs{ 3753163953Srrs struct sockaddr_in *sin; 3754167598Srrs uint32_t vrf_id; 3755163953Srrs struct sctp_inpcb *inp; 3756167695Srrs struct sctp_ifa *sctp_ifa; 3757163953Srrs 3758163953Srrs /* 3759163953Srrs * Do the malloc first in case it blocks. 3760163953Srrs */ 3761163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 3762163953Srrs sin->sin_family = AF_INET; 3763163953Srrs sin->sin_len = sizeof(*sin); 3764163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3765163953Srrs if (!inp) { 3766163953Srrs SCTP_FREE_SONAME(sin); 3767163953Srrs return ECONNRESET; 3768163953Srrs } 3769163953Srrs SCTP_INP_RLOCK(inp); 3770163953Srrs sin->sin_port = inp->sctp_lport; 3771163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 3772163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 3773163953Srrs struct sctp_tcb *stcb; 3774163953Srrs struct sockaddr_in *sin_a; 3775163953Srrs struct sctp_nets *net; 3776163953Srrs int fnd; 3777163953Srrs 3778163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 3779163953Srrs if (stcb == NULL) { 3780163953Srrs goto notConn; 3781163953Srrs } 3782163953Srrs fnd = 0; 3783163953Srrs sin_a = NULL; 3784163953Srrs SCTP_TCB_LOCK(stcb); 3785163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3786163953Srrs sin_a = (struct sockaddr_in *)&net->ro._l_addr; 3787164085Srrs if (sin_a == NULL) 3788164085Srrs /* this will make coverity happy */ 3789164085Srrs continue; 3790164085Srrs 3791163953Srrs if (sin_a->sin_family == AF_INET) { 3792163953Srrs fnd = 1; 3793163953Srrs break; 3794163953Srrs } 3795163953Srrs } 3796163953Srrs if ((!fnd) || (sin_a == NULL)) { 3797163953Srrs /* punt */ 3798163953Srrs SCTP_TCB_UNLOCK(stcb); 3799163953Srrs goto notConn; 3800163953Srrs } 3801168299Srrs vrf_id = inp->def_vrf_id; 3802167598Srrs sctp_ifa = sctp_source_address_selection(inp, 3803167598Srrs stcb, 3804168299Srrs (sctp_route_t *) & net->ro, 3805167598Srrs net, 0, vrf_id); 3806167598Srrs if (sctp_ifa) { 3807167598Srrs sin->sin_addr = sctp_ifa->address.sin.sin_addr; 3808167598Srrs sctp_free_ifa(sctp_ifa); 3809167598Srrs } 3810163953Srrs SCTP_TCB_UNLOCK(stcb); 3811163953Srrs } else { 3812163953Srrs /* For the bound all case you get back 0 */ 3813163953Srrs notConn: 3814163953Srrs sin->sin_addr.s_addr = 0; 3815163953Srrs } 3816163953Srrs 3817163953Srrs } else { 3818163953Srrs /* Take the first IPv4 address in the list */ 3819163953Srrs struct sctp_laddr *laddr; 3820163953Srrs int fnd = 0; 3821163953Srrs 3822163953Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 3823167598Srrs if (laddr->ifa->address.sa.sa_family == AF_INET) { 3824163953Srrs struct sockaddr_in *sin_a; 3825163953Srrs 3826167598Srrs sin_a = (struct sockaddr_in *)&laddr->ifa->address.sa; 3827163953Srrs sin->sin_addr = sin_a->sin_addr; 3828163953Srrs fnd = 1; 3829163953Srrs break; 3830163953Srrs } 3831163953Srrs } 3832163953Srrs if (!fnd) { 3833163953Srrs SCTP_FREE_SONAME(sin); 3834163953Srrs SCTP_INP_RUNLOCK(inp); 3835163953Srrs return ENOENT; 3836163953Srrs } 3837163953Srrs } 3838163953Srrs SCTP_INP_RUNLOCK(inp); 3839163953Srrs (*addr) = (struct sockaddr *)sin; 3840163953Srrs return (0); 3841163953Srrs} 3842163953Srrs 3843163953Srrsint 3844163953Srrssctp_peeraddr(struct socket *so, struct sockaddr **addr) 3845163953Srrs{ 3846163953Srrs struct sockaddr_in *sin = (struct sockaddr_in *)*addr; 3847166086Srrs int fnd; 3848163953Srrs struct sockaddr_in *sin_a; 3849163953Srrs struct sctp_inpcb *inp; 3850163953Srrs struct sctp_tcb *stcb; 3851163953Srrs struct sctp_nets *net; 3852163953Srrs 3853163953Srrs /* Do the malloc first in case it blocks. */ 3854163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3855163953Srrs if ((inp == NULL) || 3856163953Srrs ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { 3857163953Srrs /* UDP type and listeners will drop out here */ 3858163953Srrs return (ENOTCONN); 3859163953Srrs } 3860163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 3861163953Srrs sin->sin_family = AF_INET; 3862163953Srrs sin->sin_len = sizeof(*sin); 3863163953Srrs 3864163953Srrs /* We must recapture incase we blocked */ 3865163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3866163953Srrs if (!inp) { 3867163953Srrs SCTP_FREE_SONAME(sin); 3868163953Srrs return ECONNRESET; 3869163953Srrs } 3870163953Srrs SCTP_INP_RLOCK(inp); 3871163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 3872169420Srrs if (stcb) { 3873163953Srrs SCTP_TCB_LOCK(stcb); 3874169420Srrs } 3875163953Srrs SCTP_INP_RUNLOCK(inp); 3876163953Srrs if (stcb == NULL) { 3877163953Srrs SCTP_FREE_SONAME(sin); 3878163953Srrs return ECONNRESET; 3879163953Srrs } 3880163953Srrs fnd = 0; 3881163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3882163953Srrs sin_a = (struct sockaddr_in *)&net->ro._l_addr; 3883163953Srrs if (sin_a->sin_family == AF_INET) { 3884163953Srrs fnd = 1; 3885163953Srrs sin->sin_port = stcb->rport; 3886163953Srrs sin->sin_addr = sin_a->sin_addr; 3887163953Srrs break; 3888163953Srrs } 3889163953Srrs } 3890163953Srrs SCTP_TCB_UNLOCK(stcb); 3891163953Srrs if (!fnd) { 3892163953Srrs /* No IPv4 address */ 3893163953Srrs SCTP_FREE_SONAME(sin); 3894163953Srrs return ENOENT; 3895163953Srrs } 3896163953Srrs (*addr) = (struct sockaddr *)sin; 3897163953Srrs return (0); 3898163953Srrs} 3899163953Srrs 3900163953Srrsstruct pr_usrreqs sctp_usrreqs = { 3901163953Srrs .pru_abort = sctp_abort, 3902163953Srrs .pru_accept = sctp_accept, 3903163953Srrs .pru_attach = sctp_attach, 3904163953Srrs .pru_bind = sctp_bind, 3905163953Srrs .pru_connect = sctp_connect, 3906163953Srrs .pru_control = in_control, 3907163953Srrs .pru_close = sctp_close, 3908163953Srrs .pru_detach = sctp_close, 3909163953Srrs .pru_sopoll = sopoll_generic, 3910163953Srrs .pru_disconnect = sctp_disconnect, 3911163953Srrs .pru_listen = sctp_listen, 3912163953Srrs .pru_peeraddr = sctp_peeraddr, 3913163953Srrs .pru_send = sctp_sendm, 3914163953Srrs .pru_shutdown = sctp_shutdown, 3915163953Srrs .pru_sockaddr = sctp_ingetaddr, 3916163953Srrs .pru_sosend = sctp_sosend, 3917163953Srrs .pru_soreceive = sctp_soreceive 3918163953Srrs}; 3919