sctp_usrreq.c revision 170931
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 170931 2007-06-18 21:59:15Z rrs $"); 35166086Srrs#include <netinet/sctp_os.h> 36163953Srrs#include <sys/proc.h> 37163953Srrs#include <netinet/sctp_pcb.h> 38163953Srrs#include <netinet/sctp_header.h> 39163953Srrs#include <netinet/sctp_var.h> 40167695Srrs#if defined(INET6) 41167695Srrs#include <netinet6/sctp6_var.h> 42167695Srrs#endif 43167598Srrs#include <netinet/sctp_sysctl.h> 44163953Srrs#include <netinet/sctp_output.h> 45163953Srrs#include <netinet/sctp_uio.h> 46163953Srrs#include <netinet/sctp_asconf.h> 47163953Srrs#include <netinet/sctputil.h> 48163953Srrs#include <netinet/sctp_indata.h> 49163953Srrs#include <netinet/sctp_timer.h> 50163953Srrs#include <netinet/sctp_auth.h> 51170091Srrs#include <netinet/sctp_bsd_addr.h> 52164085Srrs 53163953Srrs 54163953Srrs 55170091Srrs 56163953Srrsvoid 57163953Srrssctp_init(void) 58163953Srrs{ 59163953Srrs /* Init the SCTP pcb in sctp_pcb.c */ 60163953Srrs u_long sb_max_adj; 61163953Srrs 62163953Srrs sctp_pcb_init(); 63163953Srrs 64163953Srrs if ((nmbclusters / 8) > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE) 65163953Srrs sctp_max_chunks_on_queue = (nmbclusters / 8); 66163953Srrs /* 67163953Srrs * Allow a user to take no more than 1/2 the number of clusters or 68163953Srrs * the SB_MAX whichever is smaller for the send window. 69163953Srrs */ 70163953Srrs sb_max_adj = (u_long)((u_quad_t) (SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES)); 71163953Srrs sctp_sendspace = min((min(SB_MAX, sb_max_adj)), 72170056Srrs (((uint32_t) nmbclusters / 2) * SCTP_DEFAULT_MAXSEGMENT)); 73163953Srrs /* 74163953Srrs * Now for the recv window, should we take the same amount? or 75163953Srrs * should I do 1/2 the SB_MAX instead in the SB_MAX min above. For 76163953Srrs * now I will just copy. 77163953Srrs */ 78163953Srrs sctp_recvspace = sctp_sendspace; 79163953Srrs 80163953Srrs 81163953Srrs} 82163953Srrs 83163953Srrs 84166023Srrs 85166023Srrs/* 86166023Srrs * cleanup of the sctppcbinfo structure. 87166023Srrs * Assumes that the sctppcbinfo lock is held. 88166023Srrs */ 89166023Srrsvoid 90166023Srrssctp_pcbinfo_cleanup(void) 91166023Srrs{ 92166023Srrs /* free the hash tables */ 93166023Srrs if (sctppcbinfo.sctp_asochash != NULL) 94166023Srrs SCTP_HASH_FREE(sctppcbinfo.sctp_asochash, sctppcbinfo.hashasocmark); 95166023Srrs if (sctppcbinfo.sctp_ephash != NULL) 96166023Srrs SCTP_HASH_FREE(sctppcbinfo.sctp_ephash, sctppcbinfo.hashmark); 97166023Srrs if (sctppcbinfo.sctp_tcpephash != NULL) 98166023Srrs SCTP_HASH_FREE(sctppcbinfo.sctp_tcpephash, sctppcbinfo.hashtcpmark); 99166023Srrs if (sctppcbinfo.sctp_restarthash != NULL) 100166023Srrs SCTP_HASH_FREE(sctppcbinfo.sctp_restarthash, sctppcbinfo.hashrestartmark); 101166023Srrs} 102166023Srrs 103163953Srrs 104163953Srrsstatic void 105167695Srrssctp_pathmtu_adjustment(struct sctp_inpcb *inp, 106163953Srrs struct sctp_tcb *stcb, 107163953Srrs struct sctp_nets *net, 108163953Srrs uint16_t nxtsz) 109163953Srrs{ 110163953Srrs struct sctp_tmit_chunk *chk; 111163953Srrs 112163953Srrs /* Adjust that too */ 113163953Srrs stcb->asoc.smallest_mtu = nxtsz; 114163953Srrs /* now off to subtract IP_DF flag if needed */ 115169352Srrs#ifdef SCTP_PRINT_FOR_B_AND_M 116169420Srrs SCTP_PRINTF("sctp_pathmtu_adjust called inp:%p stcb:%p net:%p nxtsz:%d\n", 117169352Srrs inp, stcb, net, nxtsz); 118169352Srrs#endif 119163953Srrs TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) { 120163953Srrs if ((chk->send_size + IP_HDR_SIZE) > nxtsz) { 121163953Srrs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 122163953Srrs } 123163953Srrs } 124163953Srrs TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 125163953Srrs if ((chk->send_size + IP_HDR_SIZE) > nxtsz) { 126163953Srrs /* 127163953Srrs * For this guy we also mark for immediate resend 128163953Srrs * since we sent to big of chunk 129163953Srrs */ 130163953Srrs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 131163953Srrs if (chk->sent != SCTP_DATAGRAM_RESEND) { 132163953Srrs sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); 133163953Srrs } 134163953Srrs chk->sent = SCTP_DATAGRAM_RESEND; 135163953Srrs chk->rec.data.doing_fast_retransmit = 0; 136170744Srrs if (sctp_logging_level & SCTP_FLIGHT_LOGGING_ENABLE) { 137170744Srrs sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU, 138170744Srrs chk->whoTo->flight_size, 139170744Srrs chk->book_size, 140170744Srrs (uintptr_t) chk->whoTo, 141170744Srrs chk->rec.data.TSN_seq); 142170744Srrs } 143163953Srrs /* Clear any time so NO RTT is being done */ 144163953Srrs chk->do_rtt = 0; 145168709Srrs sctp_flight_size_decrease(chk); 146168709Srrs sctp_total_flight_decrease(stcb, chk); 147163953Srrs } 148163953Srrs } 149163953Srrs} 150163953Srrs 151163953Srrsstatic void 152163953Srrssctp_notify_mbuf(struct sctp_inpcb *inp, 153163953Srrs struct sctp_tcb *stcb, 154163953Srrs struct sctp_nets *net, 155163953Srrs struct ip *ip, 156163953Srrs struct sctphdr *sh) 157163953Srrs{ 158163953Srrs struct icmp *icmph; 159163953Srrs int totsz, tmr_stopped = 0; 160163953Srrs uint16_t nxtsz; 161163953Srrs 162163953Srrs /* protection */ 163163953Srrs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 164163953Srrs (ip == NULL) || (sh == NULL)) { 165169420Srrs if (stcb != NULL) { 166163953Srrs SCTP_TCB_UNLOCK(stcb); 167169420Srrs } 168163953Srrs return; 169163953Srrs } 170163953Srrs /* First job is to verify the vtag matches what I would send */ 171163953Srrs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 172163953Srrs SCTP_TCB_UNLOCK(stcb); 173163953Srrs return; 174163953Srrs } 175163953Srrs icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) - 176163953Srrs sizeof(struct ip))); 177163953Srrs if (icmph->icmp_type != ICMP_UNREACH) { 178163953Srrs /* We only care about unreachable */ 179163953Srrs SCTP_TCB_UNLOCK(stcb); 180163953Srrs return; 181163953Srrs } 182163953Srrs if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) { 183163953Srrs /* not a unreachable message due to frag. */ 184163953Srrs SCTP_TCB_UNLOCK(stcb); 185163953Srrs return; 186163953Srrs } 187163953Srrs totsz = ip->ip_len; 188163953Srrs 189163953Srrs nxtsz = ntohs(icmph->icmp_seq); 190163953Srrs if (nxtsz == 0) { 191163953Srrs /* 192163953Srrs * old type router that does not tell us what the next size 193163953Srrs * mtu is. Rats we will have to guess (in a educated fashion 194163953Srrs * of course) 195163953Srrs */ 196163953Srrs nxtsz = find_next_best_mtu(totsz); 197163953Srrs } 198163953Srrs /* Stop any PMTU timer */ 199165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 200163953Srrs tmr_stopped = 1; 201165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 202165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1); 203163953Srrs } 204163953Srrs /* Adjust destination size limit */ 205163953Srrs if (net->mtu > nxtsz) { 206163953Srrs net->mtu = nxtsz; 207163953Srrs } 208163953Srrs /* now what about the ep? */ 209163953Srrs if (stcb->asoc.smallest_mtu > nxtsz) { 210169352Srrs#ifdef SCTP_PRINT_FOR_B_AND_M 211169420Srrs SCTP_PRINTF("notify_mbuf (ICMP) calls sctp_pathmtu_adjust mtu:%d\n", 212169352Srrs nxtsz); 213169352Srrs#endif 214167695Srrs sctp_pathmtu_adjustment(inp, stcb, net, nxtsz); 215163953Srrs } 216163953Srrs if (tmr_stopped) 217163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 218163953Srrs 219163953Srrs SCTP_TCB_UNLOCK(stcb); 220163953Srrs} 221163953Srrs 222163953Srrs 223163953Srrsvoid 224163953Srrssctp_notify(struct sctp_inpcb *inp, 225167695Srrs int error, 226163953Srrs struct sctphdr *sh, 227163953Srrs struct sockaddr *to, 228163953Srrs struct sctp_tcb *stcb, 229163953Srrs struct sctp_nets *net) 230163953Srrs{ 231163953Srrs /* protection */ 232163953Srrs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 233163953Srrs (sh == NULL) || (to == NULL)) { 234163953Srrs return; 235163953Srrs } 236163953Srrs /* First job is to verify the vtag matches what I would send */ 237163953Srrs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 238163953Srrs return; 239163953Srrs } 240163953Srrs /* FIX ME FIX ME PROTOPT i.e. no SCTP should ALWAYS be an ABORT */ 241163953Srrs 242167695Srrs if ((error == EHOSTUNREACH) || /* Host is not reachable */ 243167695Srrs (error == EHOSTDOWN) || /* Host is down */ 244167695Srrs (error == ECONNREFUSED) || /* Host refused the connection, (not 245163953Srrs * an abort?) */ 246167695Srrs (error == ENOPROTOOPT) /* SCTP is not present on host */ 247163953Srrs ) { 248163953Srrs /* 249163953Srrs * Hmm reachablity problems we must examine closely. If its 250163953Srrs * not reachable, we may have lost a network. Or if there is 251163953Srrs * NO protocol at the other end named SCTP. well we consider 252163953Srrs * it a OOTB abort. 253163953Srrs */ 254167695Srrs if ((error == EHOSTUNREACH) || (error == EHOSTDOWN)) { 255163953Srrs if (net->dest_state & SCTP_ADDR_REACHABLE) { 256163953Srrs /* Ok that destination is NOT reachable */ 257169420Srrs SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n", 258167598Srrs net->error_count, 259167598Srrs net->failure_threshold, 260167598Srrs net); 261167598Srrs 262163953Srrs net->dest_state &= ~SCTP_ADDR_REACHABLE; 263163953Srrs net->dest_state |= SCTP_ADDR_NOT_REACHABLE; 264163953Srrs net->error_count = net->failure_threshold + 1; 265163953Srrs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, 266163953Srrs stcb, SCTP_FAILED_THRESHOLD, 267163953Srrs (void *)net); 268163953Srrs } 269169420Srrs if (stcb) { 270163953Srrs SCTP_TCB_UNLOCK(stcb); 271169420Srrs } 272163953Srrs } else { 273163953Srrs /* 274163953Srrs * Here the peer is either playing tricks on us, 275163953Srrs * including an address that belongs to someone who 276163953Srrs * does not support SCTP OR was a userland 277163953Srrs * implementation that shutdown and now is dead. In 278163953Srrs * either case treat it like a OOTB abort with no 279163953Srrs * TCB 280163953Srrs */ 281163953Srrs sctp_abort_notification(stcb, SCTP_PEER_FAULTY); 282165220Srrs sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); 283163953Srrs /* no need to unlock here, since the TCB is gone */ 284163953Srrs } 285163953Srrs } else { 286163953Srrs /* Send all others to the app */ 287169420Srrs if (stcb) { 288163953Srrs SCTP_TCB_UNLOCK(stcb); 289169420Srrs } 290163953Srrs if (inp->sctp_socket) { 291163953Srrs#ifdef SCTP_LOCK_LOGGING 292170744Srrs if (sctp_logging_level & SCTP_LOCK_LOGGING_ENABLE) { 293170744Srrs sctp_log_lock(inp, stcb, SCTP_LOG_LOCK_SOCK); 294170744Srrs } 295163953Srrs#endif 296163953Srrs SOCK_LOCK(inp->sctp_socket); 297167695Srrs inp->sctp_socket->so_error = error; 298163953Srrs sctp_sowwakeup(inp, inp->sctp_socket); 299163953Srrs SOCK_UNLOCK(inp->sctp_socket); 300163953Srrs } 301163953Srrs } 302163953Srrs} 303163953Srrs 304163953Srrsvoid 305163953Srrssctp_ctlinput(cmd, sa, vip) 306163953Srrs int cmd; 307163953Srrs struct sockaddr *sa; 308163953Srrs void *vip; 309163953Srrs{ 310163953Srrs struct ip *ip = vip; 311163953Srrs struct sctphdr *sh; 312167598Srrs uint32_t vrf_id; 313163953Srrs 314168299Srrs /* FIX, for non-bsd is this right? */ 315167598Srrs vrf_id = SCTP_DEFAULT_VRFID; 316163953Srrs if (sa->sa_family != AF_INET || 317163953Srrs ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) { 318163953Srrs return; 319163953Srrs } 320163953Srrs if (PRC_IS_REDIRECT(cmd)) { 321163953Srrs ip = 0; 322163953Srrs } else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) { 323163953Srrs return; 324163953Srrs } 325163953Srrs if (ip) { 326163953Srrs struct sctp_inpcb *inp = NULL; 327163953Srrs struct sctp_tcb *stcb = NULL; 328163953Srrs struct sctp_nets *net = NULL; 329163953Srrs struct sockaddr_in to, from; 330163953Srrs 331163953Srrs sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 332163953Srrs bzero(&to, sizeof(to)); 333163953Srrs bzero(&from, sizeof(from)); 334163953Srrs from.sin_family = to.sin_family = AF_INET; 335163953Srrs from.sin_len = to.sin_len = sizeof(to); 336163953Srrs from.sin_port = sh->src_port; 337163953Srrs from.sin_addr = ip->ip_src; 338163953Srrs to.sin_port = sh->dest_port; 339163953Srrs to.sin_addr = ip->ip_dst; 340163953Srrs 341163953Srrs /* 342163953Srrs * 'to' holds the dest of the packet that failed to be sent. 343163953Srrs * 'from' holds our local endpoint address. Thus we reverse 344163953Srrs * the to and the from in the lookup. 345163953Srrs */ 346163953Srrs stcb = sctp_findassociation_addr_sa((struct sockaddr *)&from, 347163953Srrs (struct sockaddr *)&to, 348167598Srrs &inp, &net, 1, vrf_id); 349163953Srrs if (stcb != NULL && inp && (inp->sctp_socket != NULL)) { 350163953Srrs if (cmd != PRC_MSGSIZE) { 351163953Srrs int cm; 352163953Srrs 353163953Srrs if (cmd == PRC_HOSTDEAD) { 354163953Srrs cm = EHOSTUNREACH; 355163953Srrs } else { 356163953Srrs cm = inetctlerrmap[cmd]; 357163953Srrs } 358163953Srrs sctp_notify(inp, cm, sh, 359163953Srrs (struct sockaddr *)&to, stcb, 360163953Srrs net); 361163953Srrs } else { 362163953Srrs /* handle possible ICMP size messages */ 363163953Srrs sctp_notify_mbuf(inp, stcb, net, ip, sh); 364163953Srrs } 365163953Srrs } else { 366163953Srrs if ((stcb == NULL) && (inp != NULL)) { 367163953Srrs /* reduce ref-count */ 368163953Srrs SCTP_INP_WLOCK(inp); 369163953Srrs SCTP_INP_DECR_REF(inp); 370163953Srrs SCTP_INP_WUNLOCK(inp); 371163953Srrs } 372163953Srrs } 373163953Srrs } 374163953Srrs return; 375163953Srrs} 376163953Srrs 377163953Srrsstatic int 378163953Srrssctp_getcred(SYSCTL_HANDLER_ARGS) 379163953Srrs{ 380164085Srrs struct xucred xuc; 381163953Srrs struct sockaddr_in addrs[2]; 382163953Srrs struct sctp_inpcb *inp; 383163953Srrs struct sctp_nets *net; 384163953Srrs struct sctp_tcb *stcb; 385164085Srrs int error; 386167598Srrs uint32_t vrf_id; 387163953Srrs 388168299Srrs /* FIX, for non-bsd is this right? */ 389167598Srrs vrf_id = SCTP_DEFAULT_VRFID; 390168299Srrs 391170587Srwatson error = priv_check(req->td, PRIV_NETINET_GETCRED); 392170587Srwatson 393163953Srrs if (error) 394163953Srrs return (error); 395164039Srwatson 396163953Srrs error = SYSCTL_IN(req, addrs, sizeof(addrs)); 397163953Srrs if (error) 398163953Srrs return (error); 399163953Srrs 400163953Srrs stcb = sctp_findassociation_addr_sa(sintosa(&addrs[0]), 401163953Srrs sintosa(&addrs[1]), 402167598Srrs &inp, &net, 1, vrf_id); 403163953Srrs if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) { 404163953Srrs if ((inp != NULL) && (stcb == NULL)) { 405163953Srrs /* reduce ref-count */ 406163953Srrs SCTP_INP_WLOCK(inp); 407163953Srrs SCTP_INP_DECR_REF(inp); 408164085Srrs goto cred_can_cont; 409163953Srrs } 410163953Srrs error = ENOENT; 411163953Srrs goto out; 412163953Srrs } 413163953Srrs SCTP_TCB_UNLOCK(stcb); 414164085Srrs /* 415164085Srrs * We use the write lock here, only since in the error leg we need 416164085Srrs * it. If we used RLOCK, then we would have to 417164085Srrs * wlock/decr/unlock/rlock. Which in theory could create a hole. 418164085Srrs * Better to use higher wlock. 419164085Srrs */ 420164085Srrs SCTP_INP_WLOCK(inp); 421164085Srrscred_can_cont: 422164085Srrs error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket); 423164085Srrs if (error) { 424164085Srrs SCTP_INP_WUNLOCK(inp); 425164085Srrs goto out; 426164085Srrs } 427164085Srrs cru2x(inp->sctp_socket->so_cred, &xuc); 428164085Srrs SCTP_INP_WUNLOCK(inp); 429164085Srrs error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); 430163953Srrsout: 431163953Srrs return (error); 432163953Srrs} 433163953Srrs 434163953SrrsSYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW, 435163953Srrs 0, 0, sctp_getcred, "S,ucred", "Get the ucred of a SCTP connection"); 436163953Srrs 437163953Srrs 438163953Srrsstatic void 439163953Srrssctp_abort(struct socket *so) 440163953Srrs{ 441163953Srrs struct sctp_inpcb *inp; 442163953Srrs uint32_t flags; 443163953Srrs 444163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 445163953Srrs if (inp == 0) 446163953Srrs return; 447163953Srrs 448163953Srrssctp_must_try_again: 449163953Srrs flags = inp->sctp_flags; 450163953Srrs#ifdef SCTP_LOG_CLOSING 451163953Srrs sctp_log_closing(inp, NULL, 17); 452163953Srrs#endif 453163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 454163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 455163953Srrs#ifdef SCTP_LOG_CLOSING 456163953Srrs sctp_log_closing(inp, NULL, 16); 457163953Srrs#endif 458169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 459169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 460163953Srrs SOCK_LOCK(so); 461167695Srrs SCTP_SB_CLEAR(so->so_snd); 462163953Srrs /* 463163953Srrs * same for the rcv ones, they are only here for the 464163953Srrs * accounting/select. 465163953Srrs */ 466167695Srrs SCTP_SB_CLEAR(so->so_rcv); 467167695Srrs 468167695Srrs /* Now null out the reference, we are completely detached. */ 469163953Srrs so->so_pcb = NULL; 470163953Srrs SOCK_UNLOCK(so); 471163953Srrs } else { 472163953Srrs flags = inp->sctp_flags; 473163953Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 474163953Srrs goto sctp_must_try_again; 475163953Srrs } 476163953Srrs } 477163953Srrs return; 478163953Srrs} 479163953Srrs 480163953Srrsstatic int 481163953Srrssctp_attach(struct socket *so, int proto, struct thread *p) 482163953Srrs{ 483163953Srrs struct sctp_inpcb *inp; 484163953Srrs struct inpcb *ip_inp; 485166086Srrs int error; 486170205Srrs uint32_t vrf_id = SCTP_DEFAULT_VRFID; 487163953Srrs 488163953Srrs#ifdef IPSEC 489163953Srrs uint32_t flags; 490163953Srrs 491163953Srrs#endif 492163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 493163953Srrs if (inp != 0) { 494163953Srrs return EINVAL; 495163953Srrs } 496167695Srrs error = SCTP_SORESERVE(so, sctp_sendspace, sctp_recvspace); 497163953Srrs if (error) { 498163953Srrs return error; 499163953Srrs } 500170205Srrs error = sctp_inpcb_alloc(so, vrf_id); 501163953Srrs if (error) { 502163953Srrs return error; 503163953Srrs } 504163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 505163953Srrs SCTP_INP_WLOCK(inp); 506163953Srrs 507163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6; /* I'm not v6! */ 508163953Srrs ip_inp = &inp->ip_inp.inp; 509163953Srrs ip_inp->inp_vflag |= INP_IPV4; 510163953Srrs ip_inp->inp_ip_ttl = ip_defttl; 511163953Srrs 512163953Srrs#ifdef IPSEC 513163953Srrs error = ipsec_init_pcbpolicy(so, &ip_inp->inp_sp); 514163953Srrs#ifdef SCTP_LOG_CLOSING 515163953Srrs sctp_log_closing(inp, NULL, 17); 516163953Srrs#endif 517163953Srrs if (error != 0) { 518163953Srrs flags = inp->sctp_flags; 519163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 520163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 521163953Srrs#ifdef SCTP_LOG_CLOSING 522163953Srrs sctp_log_closing(inp, NULL, 15); 523163953Srrs#endif 524169352Srrs SCTP_INP_WUNLOCK(inp); 525169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 526169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 527169254Srrs } else { 528169352Srrs SCTP_INP_WUNLOCK(inp); 529163953Srrs } 530163953Srrs return error; 531163953Srrs } 532163953Srrs#endif /* IPSEC */ 533163953Srrs SCTP_INP_WUNLOCK(inp); 534163953Srrs return 0; 535163953Srrs} 536163953Srrs 537163953Srrsstatic int 538163953Srrssctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p) 539163953Srrs{ 540163953Srrs struct sctp_inpcb *inp; 541166086Srrs int error; 542163953Srrs 543163953Srrs#ifdef INET6 544163953Srrs if (addr && addr->sa_family != AF_INET) 545163953Srrs /* must be a v4 address! */ 546163953Srrs return EINVAL; 547163953Srrs#endif /* INET6 */ 548170056Srrs if (addr && (addr->sa_len != sizeof(struct sockaddr_in))) { 549170056Srrs return EINVAL; 550170056Srrs } 551163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 552163953Srrs if (inp == 0) 553163953Srrs return EINVAL; 554163953Srrs 555170744Srrs error = sctp_inpcb_bind(so, addr, NULL, p); 556163953Srrs return error; 557163953Srrs} 558163953Srrs 559163953Srrsstatic void 560163953Srrssctp_close(struct socket *so) 561163953Srrs{ 562163953Srrs struct sctp_inpcb *inp; 563163953Srrs uint32_t flags; 564163953Srrs 565163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 566163953Srrs if (inp == 0) 567163953Srrs return; 568163953Srrs 569163953Srrs /* 570163953Srrs * Inform all the lower layer assoc that we are done. 571163953Srrs */ 572163953Srrssctp_must_try_again: 573163953Srrs flags = inp->sctp_flags; 574163953Srrs#ifdef SCTP_LOG_CLOSING 575163953Srrs sctp_log_closing(inp, NULL, 17); 576163953Srrs#endif 577163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 578163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 579163953Srrs if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || 580163953Srrs (so->so_rcv.sb_cc > 0)) { 581163953Srrs#ifdef SCTP_LOG_CLOSING 582163953Srrs sctp_log_closing(inp, NULL, 13); 583163953Srrs#endif 584169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 585169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 586163953Srrs } else { 587163953Srrs#ifdef SCTP_LOG_CLOSING 588163953Srrs sctp_log_closing(inp, NULL, 14); 589163953Srrs#endif 590169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE, 591169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 592163953Srrs } 593163953Srrs /* 594163953Srrs * The socket is now detached, no matter what the state of 595163953Srrs * the SCTP association. 596163953Srrs */ 597163953Srrs SOCK_LOCK(so); 598167695Srrs SCTP_SB_CLEAR(so->so_snd); 599163953Srrs /* 600163953Srrs * same for the rcv ones, they are only here for the 601163953Srrs * accounting/select. 602163953Srrs */ 603167695Srrs SCTP_SB_CLEAR(so->so_rcv); 604167695Srrs 605167695Srrs /* Now null out the reference, we are completely detached. */ 606163953Srrs so->so_pcb = NULL; 607163953Srrs SOCK_UNLOCK(so); 608163953Srrs } else { 609163953Srrs flags = inp->sctp_flags; 610163953Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 611163953Srrs goto sctp_must_try_again; 612163953Srrs } 613163953Srrs } 614163953Srrs return; 615163953Srrs} 616163953Srrs 617163953Srrs 618163953Srrsint 619163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 620163953Srrs struct mbuf *control, struct thread *p); 621163953Srrs 622163953Srrs 623163953Srrsint 624163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 625163953Srrs struct mbuf *control, struct thread *p) 626163953Srrs{ 627163953Srrs struct sctp_inpcb *inp; 628163953Srrs int error; 629163953Srrs 630163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 631163953Srrs if (inp == 0) { 632163953Srrs if (control) { 633163953Srrs sctp_m_freem(control); 634163953Srrs control = NULL; 635163953Srrs } 636163953Srrs sctp_m_freem(m); 637163953Srrs return EINVAL; 638163953Srrs } 639163953Srrs /* Got to have an to address if we are NOT a connected socket */ 640163953Srrs if ((addr == NULL) && 641163953Srrs ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) || 642163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)) 643163953Srrs ) { 644163953Srrs goto connected_type; 645163953Srrs } else if (addr == NULL) { 646163953Srrs error = EDESTADDRREQ; 647163953Srrs sctp_m_freem(m); 648163953Srrs if (control) { 649163953Srrs sctp_m_freem(control); 650163953Srrs control = NULL; 651163953Srrs } 652163953Srrs return (error); 653163953Srrs } 654163953Srrs#ifdef INET6 655163953Srrs if (addr->sa_family != AF_INET) { 656163953Srrs /* must be a v4 address! */ 657163953Srrs sctp_m_freem(m); 658163953Srrs if (control) { 659163953Srrs sctp_m_freem(control); 660163953Srrs control = NULL; 661163953Srrs } 662163953Srrs error = EDESTADDRREQ; 663163953Srrs return EINVAL; 664163953Srrs } 665163953Srrs#endif /* INET6 */ 666163953Srrsconnected_type: 667163953Srrs /* now what about control */ 668163953Srrs if (control) { 669163953Srrs if (inp->control) { 670169420Srrs SCTP_PRINTF("huh? control set?\n"); 671163953Srrs sctp_m_freem(inp->control); 672163953Srrs inp->control = NULL; 673163953Srrs } 674163953Srrs inp->control = control; 675163953Srrs } 676163953Srrs /* Place the data */ 677163953Srrs if (inp->pkt) { 678165647Srrs SCTP_BUF_NEXT(inp->pkt_last) = m; 679163953Srrs inp->pkt_last = m; 680163953Srrs } else { 681163953Srrs inp->pkt_last = inp->pkt = m; 682163953Srrs } 683163953Srrs if ( 684163953Srrs /* FreeBSD uses a flag passed */ 685163953Srrs ((flags & PRUS_MORETOCOME) == 0) 686163953Srrs ) { 687163953Srrs /* 688163953Srrs * note with the current version this code will only be used 689163953Srrs * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for 690163953Srrs * re-defining sosend to use the sctp_sosend. One can 691163953Srrs * optionally switch back to this code (by changing back the 692163953Srrs * definitions) but this is not advisable. This code is used 693163953Srrs * by FreeBSD when sending a file with sendfile() though. 694163953Srrs */ 695163953Srrs int ret; 696163953Srrs 697163953Srrs ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags); 698163953Srrs inp->pkt = NULL; 699163953Srrs inp->control = NULL; 700163953Srrs return (ret); 701163953Srrs } else { 702163953Srrs return (0); 703163953Srrs } 704163953Srrs} 705163953Srrs 706163953Srrsstatic int 707163953Srrssctp_disconnect(struct socket *so) 708163953Srrs{ 709163953Srrs struct sctp_inpcb *inp; 710163953Srrs 711163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 712163953Srrs if (inp == NULL) { 713163953Srrs return (ENOTCONN); 714163953Srrs } 715163953Srrs SCTP_INP_RLOCK(inp); 716163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 717166675Srrs if (SCTP_LIST_EMPTY(&inp->sctp_asoc_list)) { 718163953Srrs /* No connection */ 719163953Srrs SCTP_INP_RUNLOCK(inp); 720163953Srrs return (0); 721163953Srrs } else { 722163953Srrs struct sctp_association *asoc; 723163953Srrs struct sctp_tcb *stcb; 724163953Srrs 725163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 726163953Srrs if (stcb == NULL) { 727163953Srrs SCTP_INP_RUNLOCK(inp); 728163953Srrs return (EINVAL); 729163953Srrs } 730163953Srrs SCTP_TCB_LOCK(stcb); 731163953Srrs asoc = &stcb->asoc; 732163953Srrs if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 733163953Srrs /* We are about to be freed, out of here */ 734163953Srrs SCTP_TCB_UNLOCK(stcb); 735163953Srrs SCTP_INP_RUNLOCK(inp); 736163953Srrs return (0); 737163953Srrs } 738163953Srrs if (((so->so_options & SO_LINGER) && 739163953Srrs (so->so_linger == 0)) || 740163953Srrs (so->so_rcv.sb_cc > 0)) { 741163953Srrs if (SCTP_GET_STATE(asoc) != 742163953Srrs SCTP_STATE_COOKIE_WAIT) { 743163953Srrs /* Left with Data unread */ 744163953Srrs struct mbuf *err; 745163953Srrs 746163953Srrs err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_DONTWAIT, 1, MT_DATA); 747163953Srrs if (err) { 748163953Srrs /* 749163953Srrs * Fill in the user 750163953Srrs * initiated abort 751163953Srrs */ 752163953Srrs struct sctp_paramhdr *ph; 753163953Srrs 754163953Srrs ph = mtod(err, struct sctp_paramhdr *); 755165647Srrs SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr); 756163953Srrs ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); 757165647Srrs ph->param_length = htons(SCTP_BUF_LEN(err)); 758163953Srrs } 759163953Srrs sctp_send_abort_tcb(stcb, err); 760163953Srrs SCTP_STAT_INCR_COUNTER32(sctps_aborted); 761163953Srrs } 762163953Srrs SCTP_INP_RUNLOCK(inp); 763163953Srrs if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 764163953Srrs (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 765163953Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 766163953Srrs } 767165220Srrs sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3); 768163953Srrs /* No unlock tcb assoc is gone */ 769163953Srrs return (0); 770163953Srrs } 771163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 772163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 773163953Srrs (asoc->stream_queue_cnt == 0)) { 774163953Srrs /* there is nothing queued to send, so done */ 775163953Srrs if (asoc->locked_on_sending) { 776163953Srrs goto abort_anyway; 777163953Srrs } 778166675Srrs if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) && 779166675Srrs (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { 780163953Srrs /* only send SHUTDOWN 1st time thru */ 781163953Srrs sctp_stop_timers_for_shutdown(stcb); 782163953Srrs sctp_send_shutdown(stcb, 783163953Srrs stcb->asoc.primary_destination); 784163953Srrs sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3); 785166675Srrs if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 786166675Srrs (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 787166675Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 788166675Srrs } 789163953Srrs asoc->state = SCTP_STATE_SHUTDOWN_SENT; 790163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 791163953Srrs stcb->sctp_ep, stcb, 792163953Srrs asoc->primary_destination); 793163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 794163953Srrs stcb->sctp_ep, stcb, 795163953Srrs asoc->primary_destination); 796163953Srrs } 797163953Srrs } else { 798163953Srrs /* 799163953Srrs * we still got (or just got) data to send, 800163953Srrs * so set SHUTDOWN_PENDING 801163953Srrs */ 802163953Srrs /* 803163953Srrs * XXX sockets draft says that SCTP_EOF 804163953Srrs * should be sent with no data. currently, 805163953Srrs * we will allow user data to be sent first 806163953Srrs * and move to SHUTDOWN-PENDING 807163953Srrs */ 808163953Srrs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 809163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, 810163953Srrs asoc->primary_destination); 811163953Srrs if (asoc->locked_on_sending) { 812163953Srrs /* Locked to send out the data */ 813163953Srrs struct sctp_stream_queue_pending *sp; 814163953Srrs 815163953Srrs sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); 816163953Srrs if (sp == NULL) { 817169420Srrs SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", 818163953Srrs asoc->locked_on_sending->stream_no); 819163953Srrs } else { 820163953Srrs if ((sp->length == 0) && (sp->msg_is_complete == 0)) 821163953Srrs asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; 822163953Srrs } 823163953Srrs } 824163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 825163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 826163953Srrs (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 827163953Srrs struct mbuf *op_err; 828163953Srrs 829163953Srrs abort_anyway: 830163953Srrs op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 831163953Srrs 0, M_DONTWAIT, 1, MT_DATA); 832163953Srrs if (op_err) { 833163953Srrs /* 834163953Srrs * Fill in the user 835163953Srrs * initiated abort 836163953Srrs */ 837163953Srrs struct sctp_paramhdr *ph; 838163953Srrs uint32_t *ippp; 839163953Srrs 840165647Srrs SCTP_BUF_LEN(op_err) = 841163953Srrs (sizeof(struct sctp_paramhdr) + sizeof(uint32_t)); 842163953Srrs ph = mtod(op_err, 843163953Srrs struct sctp_paramhdr *); 844163953Srrs ph->param_type = htons( 845163953Srrs SCTP_CAUSE_USER_INITIATED_ABT); 846165647Srrs ph->param_length = htons(SCTP_BUF_LEN(op_err)); 847163953Srrs ippp = (uint32_t *) (ph + 1); 848165220Srrs *ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4); 849163953Srrs } 850165220Srrs stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4; 851163953Srrs sctp_send_abort_tcb(stcb, op_err); 852163953Srrs SCTP_STAT_INCR_COUNTER32(sctps_aborted); 853163953Srrs if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 854163953Srrs (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 855163953Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 856163953Srrs } 857163953Srrs SCTP_INP_RUNLOCK(inp); 858165220Srrs sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5); 859163953Srrs return (0); 860163953Srrs } 861163953Srrs } 862163953Srrs SCTP_TCB_UNLOCK(stcb); 863163953Srrs SCTP_INP_RUNLOCK(inp); 864163953Srrs return (0); 865163953Srrs } 866163953Srrs /* not reached */ 867163953Srrs } else { 868163953Srrs /* UDP model does not support this */ 869163953Srrs SCTP_INP_RUNLOCK(inp); 870163953Srrs return EOPNOTSUPP; 871163953Srrs } 872163953Srrs} 873163953Srrs 874163953Srrsint 875163953Srrssctp_shutdown(struct socket *so) 876163953Srrs{ 877163953Srrs struct sctp_inpcb *inp; 878163953Srrs 879163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 880163953Srrs if (inp == 0) { 881163953Srrs return EINVAL; 882163953Srrs } 883163953Srrs SCTP_INP_RLOCK(inp); 884163953Srrs /* For UDP model this is a invalid call */ 885163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 886163953Srrs /* Restore the flags that the soshutdown took away. */ 887163953Srrs so->so_rcv.sb_state &= ~SBS_CANTRCVMORE; 888163953Srrs /* This proc will wakeup for read and do nothing (I hope) */ 889163953Srrs SCTP_INP_RUNLOCK(inp); 890163953Srrs return (EOPNOTSUPP); 891163953Srrs } 892163953Srrs /* 893163953Srrs * Ok if we reach here its the TCP model and it is either a SHUT_WR 894163953Srrs * or SHUT_RDWR. This means we put the shutdown flag against it. 895163953Srrs */ 896163953Srrs { 897163953Srrs struct sctp_tcb *stcb; 898163953Srrs struct sctp_association *asoc; 899163953Srrs 900163953Srrs socantsendmore(so); 901163953Srrs 902163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 903163953Srrs if (stcb == NULL) { 904163953Srrs /* 905163953Srrs * Ok we hit the case that the shutdown call was 906163953Srrs * made after an abort or something. Nothing to do 907163953Srrs * now. 908163953Srrs */ 909168299Srrs SCTP_INP_RUNLOCK(inp); 910163953Srrs return (0); 911163953Srrs } 912163953Srrs SCTP_TCB_LOCK(stcb); 913163953Srrs asoc = &stcb->asoc; 914163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 915163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 916163953Srrs (asoc->stream_queue_cnt == 0)) { 917163953Srrs if (asoc->locked_on_sending) { 918163953Srrs goto abort_anyway; 919163953Srrs } 920163953Srrs /* there is nothing queued to send, so I'm done... */ 921163953Srrs if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { 922163953Srrs /* only send SHUTDOWN the first time through */ 923163953Srrs sctp_stop_timers_for_shutdown(stcb); 924163953Srrs sctp_send_shutdown(stcb, 925163953Srrs stcb->asoc.primary_destination); 926163953Srrs sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3); 927166675Srrs if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || 928166675Srrs (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 929166675Srrs SCTP_STAT_DECR_GAUGE32(sctps_currestab); 930166675Srrs } 931163953Srrs asoc->state = SCTP_STATE_SHUTDOWN_SENT; 932163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 933163953Srrs stcb->sctp_ep, stcb, 934163953Srrs asoc->primary_destination); 935163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 936163953Srrs stcb->sctp_ep, stcb, 937163953Srrs asoc->primary_destination); 938163953Srrs } 939163953Srrs } else { 940163953Srrs /* 941163953Srrs * we still got (or just got) data to send, so set 942163953Srrs * SHUTDOWN_PENDING 943163953Srrs */ 944163953Srrs asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 945163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, 946163953Srrs asoc->primary_destination); 947163953Srrs 948163953Srrs if (asoc->locked_on_sending) { 949163953Srrs /* Locked to send out the data */ 950163953Srrs struct sctp_stream_queue_pending *sp; 951163953Srrs 952163953Srrs sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); 953163953Srrs if (sp == NULL) { 954169420Srrs SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", 955163953Srrs asoc->locked_on_sending->stream_no); 956163953Srrs } else { 957163953Srrs if ((sp->length == 0) && (sp->msg_is_complete == 0)) { 958163953Srrs asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; 959163953Srrs } 960163953Srrs } 961163953Srrs } 962163953Srrs if (TAILQ_EMPTY(&asoc->send_queue) && 963163953Srrs TAILQ_EMPTY(&asoc->sent_queue) && 964163953Srrs (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { 965163953Srrs struct mbuf *op_err; 966163953Srrs 967163953Srrs abort_anyway: 968163953Srrs op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)), 969163953Srrs 0, M_DONTWAIT, 1, MT_DATA); 970163953Srrs if (op_err) { 971163953Srrs /* Fill in the user initiated abort */ 972163953Srrs struct sctp_paramhdr *ph; 973163953Srrs uint32_t *ippp; 974163953Srrs 975165647Srrs SCTP_BUF_LEN(op_err) = 976163953Srrs sizeof(struct sctp_paramhdr) + sizeof(uint32_t); 977163953Srrs ph = mtod(op_err, 978163953Srrs struct sctp_paramhdr *); 979163953Srrs ph->param_type = htons( 980163953Srrs SCTP_CAUSE_USER_INITIATED_ABT); 981165647Srrs ph->param_length = htons(SCTP_BUF_LEN(op_err)); 982163953Srrs ippp = (uint32_t *) (ph + 1); 983165220Srrs *ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6); 984163953Srrs } 985165220Srrs stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6; 986163953Srrs sctp_abort_an_association(stcb->sctp_ep, stcb, 987163953Srrs SCTP_RESPONSE_TO_USER_REQ, 988163953Srrs op_err); 989163953Srrs goto skip_unlock; 990163953Srrs } 991163953Srrs } 992163953Srrs SCTP_TCB_UNLOCK(stcb); 993163953Srrs } 994163953Srrsskip_unlock: 995163953Srrs SCTP_INP_RUNLOCK(inp); 996163953Srrs return 0; 997163953Srrs} 998163953Srrs 999163953Srrs/* 1000163953Srrs * copies a "user" presentable address and removes embedded scope, etc. 1001163953Srrs * returns 0 on success, 1 on error 1002163953Srrs */ 1003163953Srrsstatic uint32_t 1004163953Srrssctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa) 1005163953Srrs{ 1006163953Srrs struct sockaddr_in6 lsa6; 1007163953Srrs 1008163953Srrs sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa, 1009163953Srrs &lsa6); 1010163953Srrs memcpy(ss, sa, sa->sa_len); 1011163953Srrs return (0); 1012163953Srrs} 1013163953Srrs 1014163953Srrs 1015163953Srrs 1016166675Srrsstatic size_t 1017168124Srrssctp_fill_up_addresses_vrf(struct sctp_inpcb *inp, 1018163953Srrs struct sctp_tcb *stcb, 1019166675Srrs size_t limit, 1020167598Srrs struct sockaddr_storage *sas, 1021167598Srrs uint32_t vrf_id) 1022163953Srrs{ 1023167598Srrs struct sctp_ifn *sctp_ifn; 1024167598Srrs struct sctp_ifa *sctp_ifa; 1025166675Srrs int loopback_scope, ipv4_local_scope, local_scope, site_scope; 1026166675Srrs size_t actual; 1027163953Srrs int ipv4_addr_legal, ipv6_addr_legal; 1028167598Srrs struct sctp_vrf *vrf; 1029163953Srrs 1030163953Srrs actual = 0; 1031163953Srrs if (limit <= 0) 1032163953Srrs return (actual); 1033163953Srrs 1034163953Srrs if (stcb) { 1035163953Srrs /* Turn on all the appropriate scope */ 1036163953Srrs loopback_scope = stcb->asoc.loopback_scope; 1037163953Srrs ipv4_local_scope = stcb->asoc.ipv4_local_scope; 1038163953Srrs local_scope = stcb->asoc.local_scope; 1039163953Srrs site_scope = stcb->asoc.site_scope; 1040163953Srrs } else { 1041163953Srrs /* Turn on ALL scope, since we look at the EP */ 1042163953Srrs loopback_scope = ipv4_local_scope = local_scope = 1043163953Srrs site_scope = 1; 1044163953Srrs } 1045163953Srrs ipv4_addr_legal = ipv6_addr_legal = 0; 1046163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 1047163953Srrs ipv6_addr_legal = 1; 1048166023Srrs if (SCTP_IPV6_V6ONLY(inp) == 0) { 1049163953Srrs ipv4_addr_legal = 1; 1050163953Srrs } 1051163953Srrs } else { 1052163953Srrs ipv4_addr_legal = 1; 1053163953Srrs } 1054167598Srrs vrf = sctp_find_vrf(vrf_id); 1055167598Srrs if (vrf == NULL) { 1056167598Srrs return (0); 1057167598Srrs } 1058163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1059167598Srrs LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 1060163953Srrs if ((loopback_scope == 0) && 1061167598Srrs SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { 1062163953Srrs /* Skip loopback if loopback_scope not set */ 1063163953Srrs continue; 1064163953Srrs } 1065167598Srrs LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 1066163953Srrs if (stcb) { 1067163953Srrs /* 1068163953Srrs * For the BOUND-ALL case, the list 1069163953Srrs * associated with a TCB is Always 1070163953Srrs * considered a reverse list.. i.e. 1071163953Srrs * it lists addresses that are NOT 1072163953Srrs * part of the association. If this 1073163953Srrs * is one of those we must skip it. 1074163953Srrs */ 1075163953Srrs if (sctp_is_addr_restricted(stcb, 1076167598Srrs sctp_ifa)) { 1077163953Srrs continue; 1078163953Srrs } 1079163953Srrs } 1080167598Srrs if ((sctp_ifa->address.sa.sa_family == AF_INET) && 1081163953Srrs (ipv4_addr_legal)) { 1082163953Srrs struct sockaddr_in *sin; 1083163953Srrs 1084167598Srrs sin = (struct sockaddr_in *)&sctp_ifa->address.sa; 1085163953Srrs if (sin->sin_addr.s_addr == 0) { 1086163953Srrs /* 1087163953Srrs * we skip unspecifed 1088163953Srrs * addresses 1089163953Srrs */ 1090163953Srrs continue; 1091163953Srrs } 1092163953Srrs if ((ipv4_local_scope == 0) && 1093163953Srrs (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { 1094163953Srrs continue; 1095163953Srrs } 1096163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) { 1097163953Srrs in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas); 1098163953Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1099163953Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6)); 1100163953Srrs actual += sizeof(sizeof(struct sockaddr_in6)); 1101163953Srrs } else { 1102163953Srrs memcpy(sas, sin, sizeof(*sin)); 1103163953Srrs ((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport; 1104163953Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin)); 1105163953Srrs actual += sizeof(*sin); 1106163953Srrs } 1107163953Srrs if (actual >= limit) { 1108163953Srrs return (actual); 1109163953Srrs } 1110167598Srrs } else if ((sctp_ifa->address.sa.sa_family == AF_INET6) && 1111163953Srrs (ipv6_addr_legal)) { 1112163953Srrs struct sockaddr_in6 *sin6; 1113163953Srrs 1114167598Srrs sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa; 1115163953Srrs if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 1116163953Srrs /* 1117163953Srrs * we skip unspecifed 1118163953Srrs * addresses 1119163953Srrs */ 1120163953Srrs continue; 1121163953Srrs } 1122163953Srrs if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 1123163953Srrs if (local_scope == 0) 1124163953Srrs continue; 1125163953Srrs if (sin6->sin6_scope_id == 0) { 1126163953Srrs if (sa6_recoverscope(sin6) != 0) 1127163953Srrs /* 1128163953Srrs * bad link 1129163953Srrs * local 1130163953Srrs * address 1131163953Srrs */ 1132163953Srrs continue; 1133163953Srrs } 1134163953Srrs } 1135163953Srrs if ((site_scope == 0) && 1136163953Srrs (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { 1137163953Srrs continue; 1138163953Srrs } 1139163953Srrs memcpy(sas, sin6, sizeof(*sin6)); 1140163953Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1141163953Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6)); 1142163953Srrs actual += sizeof(*sin6); 1143163953Srrs if (actual >= limit) { 1144163953Srrs return (actual); 1145163953Srrs } 1146163953Srrs } 1147163953Srrs } 1148163953Srrs } 1149163953Srrs } else { 1150163953Srrs struct sctp_laddr *laddr; 1151163953Srrs 1152167598Srrs /* The list is a NEGATIVE list */ 1153167598Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1154167598Srrs if (stcb) { 1155167598Srrs if (sctp_is_addr_restricted(stcb, laddr->ifa)) { 1156163953Srrs continue; 1157163953Srrs } 1158163953Srrs } 1159167598Srrs if (sctp_fill_user_address(sas, &laddr->ifa->address.sa)) 1160167598Srrs continue; 1161167598Srrs 1162167598Srrs ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; 1163167598Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + 1164167598Srrs laddr->ifa->address.sa.sa_len); 1165167598Srrs actual += laddr->ifa->address.sa.sa_len; 1166167598Srrs if (actual >= limit) { 1167167598Srrs return (actual); 1168163953Srrs } 1169163953Srrs } 1170163953Srrs } 1171163953Srrs return (actual); 1172163953Srrs} 1173163953Srrs 1174168124Srrsstatic size_t 1175168124Srrssctp_fill_up_addresses(struct sctp_inpcb *inp, 1176168124Srrs struct sctp_tcb *stcb, 1177168124Srrs size_t limit, 1178168124Srrs struct sockaddr_storage *sas) 1179168124Srrs{ 1180168124Srrs size_t size = 0; 1181168124Srrs 1182168124Srrs /* fill up addresses for the endpoint's default vrf */ 1183168124Srrs size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas, 1184168124Srrs inp->def_vrf_id); 1185168124Srrs return (size); 1186168124Srrs} 1187168124Srrs 1188163953Srrsstatic int 1189168124Srrssctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) 1190163953Srrs{ 1191163953Srrs int cnt = 0; 1192167598Srrs struct sctp_vrf *vrf = NULL; 1193163953Srrs 1194163953Srrs /* 1195163953Srrs * In both sub-set bound an bound_all cases we return the MAXIMUM 1196163953Srrs * number of addresses that you COULD get. In reality the sub-set 1197163953Srrs * bound may have an exclusion list for a given TCB OR in the 1198163953Srrs * bound-all case a TCB may NOT include the loopback or other 1199163953Srrs * addresses as well. 1200163953Srrs */ 1201167598Srrs vrf = sctp_find_vrf(vrf_id); 1202167598Srrs if (vrf == NULL) { 1203167598Srrs return (0); 1204167598Srrs } 1205163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1206167598Srrs struct sctp_ifn *sctp_ifn; 1207167598Srrs struct sctp_ifa *sctp_ifa; 1208163953Srrs 1209167598Srrs LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 1210167598Srrs LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 1211163953Srrs /* Count them if they are the right type */ 1212167598Srrs if (sctp_ifa->address.sa.sa_family == AF_INET) { 1213163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) 1214163953Srrs cnt += sizeof(struct sockaddr_in6); 1215163953Srrs else 1216163953Srrs cnt += sizeof(struct sockaddr_in); 1217163953Srrs 1218167598Srrs } else if (sctp_ifa->address.sa.sa_family == AF_INET6) 1219163953Srrs cnt += sizeof(struct sockaddr_in6); 1220163953Srrs } 1221163953Srrs } 1222163953Srrs } else { 1223163953Srrs struct sctp_laddr *laddr; 1224163953Srrs 1225163953Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1226167598Srrs if (laddr->ifa->address.sa.sa_family == AF_INET) { 1227163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) 1228163953Srrs cnt += sizeof(struct sockaddr_in6); 1229163953Srrs else 1230163953Srrs cnt += sizeof(struct sockaddr_in); 1231163953Srrs 1232167598Srrs } else if (laddr->ifa->address.sa.sa_family == AF_INET6) 1233163953Srrs cnt += sizeof(struct sockaddr_in6); 1234163953Srrs } 1235163953Srrs } 1236163953Srrs return (cnt); 1237163953Srrs} 1238163953Srrs 1239168124Srrsstatic int 1240168124Srrssctp_count_max_addresses(struct sctp_inpcb *inp) 1241168124Srrs{ 1242168124Srrs int cnt = 0; 1243166675Srrs 1244168124Srrs /* count addresses for the endpoint's default VRF */ 1245168124Srrs cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id); 1246168124Srrs return (cnt); 1247168124Srrs} 1248168124Srrs 1249163953Srrsstatic int 1250166675Srrssctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, 1251166675Srrs size_t optsize, void *p, int delay) 1252163953Srrs{ 1253163953Srrs int error = 0; 1254163953Srrs int creat_lock_on = 0; 1255163953Srrs struct sctp_tcb *stcb = NULL; 1256163953Srrs struct sockaddr *sa; 1257169352Srrs int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr; 1258169352Srrs int added = 0; 1259167598Srrs uint32_t vrf_id; 1260170056Srrs int bad_addresses = 0; 1261167598Srrs sctp_assoc_t *a_id; 1262163953Srrs 1263169420Srrs SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n"); 1264163953Srrs 1265163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 1266163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 1267163953Srrs /* We are already connected AND the TCP model */ 1268163953Srrs return (EADDRINUSE); 1269163953Srrs } 1270163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) { 1271163953Srrs return (EINVAL); 1272163953Srrs } 1273163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 1274163953Srrs SCTP_INP_RLOCK(inp); 1275163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 1276163953Srrs SCTP_INP_RUNLOCK(inp); 1277163953Srrs } 1278163953Srrs if (stcb) { 1279163953Srrs return (EALREADY); 1280163953Srrs } 1281163953Srrs SCTP_INP_INCR_REF(inp); 1282163953Srrs SCTP_ASOC_CREATE_LOCK(inp); 1283163953Srrs creat_lock_on = 1; 1284163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 1285163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 1286163953Srrs error = EFAULT; 1287163953Srrs goto out_now; 1288163953Srrs } 1289166675Srrs totaddrp = (int *)optval; 1290163953Srrs totaddr = *totaddrp; 1291163953Srrs sa = (struct sockaddr *)(totaddrp + 1); 1292170056Srrs stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses); 1293170056Srrs if ((stcb != NULL) || bad_addresses) { 1294169352Srrs /* Already have or am bring up an association */ 1295169352Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1296169352Srrs creat_lock_on = 0; 1297170931Srrs if (stcb) 1298170931Srrs SCTP_TCB_UNLOCK(stcb); 1299170056Srrs if (bad_addresses == 0) 1300170056Srrs error = EALREADY; 1301169352Srrs goto out_now; 1302163953Srrs } 1303163953Srrs#ifdef INET6 1304163953Srrs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 1305163953Srrs (num_v6 > 0)) { 1306163953Srrs error = EINVAL; 1307163953Srrs goto out_now; 1308163953Srrs } 1309163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 1310163953Srrs (num_v4 > 0)) { 1311163953Srrs struct in6pcb *inp6; 1312163953Srrs 1313163953Srrs inp6 = (struct in6pcb *)inp; 1314166023Srrs if (SCTP_IPV6_V6ONLY(inp6)) { 1315163953Srrs /* 1316163953Srrs * if IPV6_V6ONLY flag, ignore connections destined 1317163953Srrs * to a v4 addr or v4-mapped addr 1318163953Srrs */ 1319163953Srrs error = EINVAL; 1320163953Srrs goto out_now; 1321163953Srrs } 1322163953Srrs } 1323163953Srrs#endif /* INET6 */ 1324163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 1325163953Srrs SCTP_PCB_FLAGS_UNBOUND) { 1326163953Srrs /* Bind a ephemeral port */ 1327170744Srrs error = sctp_inpcb_bind(so, NULL, NULL, p); 1328163953Srrs if (error) { 1329163953Srrs goto out_now; 1330163953Srrs } 1331163953Srrs } 1332167695Srrs /* FIX ME: do we want to pass in a vrf on the connect call? */ 1333167695Srrs vrf_id = inp->def_vrf_id; 1334167695Srrs 1335163953Srrs /* We are GOOD to go */ 1336167598Srrs stcb = sctp_aloc_assoc(inp, sa, 1, &error, 0, vrf_id); 1337163953Srrs if (stcb == NULL) { 1338163953Srrs /* Gak! no memory */ 1339163953Srrs goto out_now; 1340163953Srrs } 1341169352Srrs stcb->asoc.state = SCTP_STATE_COOKIE_WAIT; 1342163953Srrs /* move to second address */ 1343163953Srrs if (sa->sa_family == AF_INET) 1344163953Srrs sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in)); 1345163953Srrs else 1346163953Srrs sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6)); 1347163953Srrs 1348170056Srrs error = 0; 1349169352Srrs added = sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error); 1350167598Srrs /* Fill in the return id */ 1351170056Srrs if (error) { 1352170056Srrs sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_12); 1353170056Srrs goto out_now; 1354170056Srrs } 1355167598Srrs a_id = (sctp_assoc_t *) optval; 1356167598Srrs *a_id = sctp_get_associd(stcb); 1357163953Srrs 1358163953Srrs /* initialize authentication parameters for the assoc */ 1359163953Srrs sctp_initialize_auth_params(inp, stcb); 1360163953Srrs 1361163953Srrs if (delay) { 1362163953Srrs /* doing delayed connection */ 1363163953Srrs stcb->asoc.delayed_connection = 1; 1364163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination); 1365163953Srrs } else { 1366169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 1367163953Srrs sctp_send_initiate(inp, stcb); 1368163953Srrs } 1369163953Srrs SCTP_TCB_UNLOCK(stcb); 1370163953Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 1371163953Srrs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 1372163953Srrs /* Set the connected flag so we can queue data */ 1373163953Srrs soisconnecting(so); 1374163953Srrs } 1375163953Srrsout_now: 1376169655Srrs if (creat_lock_on) { 1377163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1378169655Srrs } 1379163953Srrs SCTP_INP_DECR_REF(inp); 1380163953Srrs return error; 1381163953Srrs} 1382163953Srrs 1383169420Srrs#define SCTP_FIND_STCB(inp, stcb, assoc_id) { \ 1384169655Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||\ 1385169655Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { \ 1386166675Srrs SCTP_INP_RLOCK(inp); \ 1387166675Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); \ 1388169655Srrs if (stcb) { \ 1389166675Srrs SCTP_TCB_LOCK(stcb); \ 1390169655Srrs } \ 1391166675Srrs SCTP_INP_RUNLOCK(inp); \ 1392166675Srrs } else if (assoc_id != 0) { \ 1393166675Srrs stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \ 1394166675Srrs if (stcb == NULL) { \ 1395166675Srrs error = ENOENT; \ 1396166675Srrs break; \ 1397166675Srrs } \ 1398166675Srrs } else { \ 1399166675Srrs stcb = NULL; \ 1400169420Srrs } \ 1401169420Srrs } 1402163953Srrs 1403169420Srrs 1404169420Srrs#define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\ 1405166675Srrs if (size < sizeof(type)) { \ 1406166675Srrs error = EINVAL; \ 1407166675Srrs break; \ 1408166675Srrs } else { \ 1409166675Srrs destp = (type *)srcp; \ 1410169420Srrs } \ 1411169420Srrs } 1412163953Srrs 1413163953Srrsstatic int 1414166675Srrssctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, 1415166675Srrs void *p) 1416163953Srrs{ 1417163953Srrs struct sctp_inpcb *inp; 1418166675Srrs int error, val = 0; 1419163953Srrs struct sctp_tcb *stcb = NULL; 1420163953Srrs 1421166675Srrs if (optval == NULL) { 1422166675Srrs return (EINVAL); 1423166675Srrs } 1424163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 1425163953Srrs if (inp == 0) 1426163953Srrs return EINVAL; 1427163953Srrs error = 0; 1428163953Srrs 1429166675Srrs switch (optname) { 1430163953Srrs case SCTP_NODELAY: 1431163953Srrs case SCTP_AUTOCLOSE: 1432163953Srrs case SCTP_EXPLICIT_EOR: 1433163953Srrs case SCTP_AUTO_ASCONF: 1434163953Srrs case SCTP_DISABLE_FRAGMENTS: 1435163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 1436163953Srrs case SCTP_USE_EXT_RCVINFO: 1437163953Srrs SCTP_INP_RLOCK(inp); 1438166675Srrs switch (optname) { 1439163953Srrs case SCTP_DISABLE_FRAGMENTS: 1440166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT); 1441163953Srrs break; 1442163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 1443166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4); 1444163953Srrs break; 1445163953Srrs case SCTP_AUTO_ASCONF: 1446166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); 1447163953Srrs break; 1448163953Srrs case SCTP_EXPLICIT_EOR: 1449166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); 1450163953Srrs break; 1451163953Srrs case SCTP_NODELAY: 1452166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY); 1453163953Srrs break; 1454163953Srrs case SCTP_USE_EXT_RCVINFO: 1455166675Srrs val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO); 1456163953Srrs break; 1457163953Srrs case SCTP_AUTOCLOSE: 1458163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) 1459166675Srrs val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time); 1460163953Srrs else 1461166675Srrs val = 0; 1462163953Srrs break; 1463163953Srrs 1464163953Srrs default: 1465163953Srrs error = ENOPROTOOPT; 1466163953Srrs } /* end switch (sopt->sopt_name) */ 1467166675Srrs if (optname != SCTP_AUTOCLOSE) { 1468163953Srrs /* make it an "on/off" value */ 1469166675Srrs val = (val != 0); 1470163953Srrs } 1471166675Srrs if (*optsize < sizeof(val)) { 1472163953Srrs error = EINVAL; 1473163953Srrs } 1474163953Srrs SCTP_INP_RUNLOCK(inp); 1475163953Srrs if (error == 0) { 1476163953Srrs /* return the option value */ 1477166675Srrs *(int *)optval = val; 1478166675Srrs *optsize = sizeof(val); 1479163953Srrs } 1480163953Srrs break; 1481170091Srrs case SCTP_GET_PACKET_LOG: 1482170091Srrs { 1483170091Srrs#ifdef SCTP_PACKET_LOGGING 1484170091Srrs uint8_t *target; 1485170091Srrs int ret; 1486167598Srrs 1487170091Srrs SCTP_CHECK_AND_CAST(target, optval, uint8_t, *optsize); 1488170091Srrs ret = sctp_copy_out_packet_log(target, (int)*optsize); 1489170091Srrs *optsize = ret; 1490170091Srrs#else 1491170091Srrs error = EOPNOTSUPP; 1492170091Srrs#endif 1493170091Srrs break; 1494170091Srrs } 1495163953Srrs case SCTP_PARTIAL_DELIVERY_POINT: 1496163953Srrs { 1497166675Srrs uint32_t *value; 1498166675Srrs 1499166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1500166675Srrs *value = inp->partial_delivery_point; 1501166675Srrs *optsize = sizeof(uint32_t); 1502163953Srrs } 1503163953Srrs break; 1504163953Srrs case SCTP_FRAGMENT_INTERLEAVE: 1505163953Srrs { 1506166675Srrs uint32_t *value; 1507166675Srrs 1508166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1509168943Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) { 1510168943Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) { 1511168943Srrs *value = SCTP_FRAG_LEVEL_2; 1512168943Srrs } else { 1513168943Srrs *value = SCTP_FRAG_LEVEL_1; 1514168943Srrs } 1515168943Srrs } else { 1516168943Srrs *value = SCTP_FRAG_LEVEL_0; 1517168943Srrs } 1518166675Srrs *optsize = sizeof(uint32_t); 1519163953Srrs } 1520163953Srrs break; 1521163953Srrs case SCTP_CMT_ON_OFF: 1522163953Srrs { 1523166675Srrs struct sctp_assoc_value *av; 1524166675Srrs 1525166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1526166675Srrs if (sctp_cmt_on_off) { 1527166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1528166675Srrs if (stcb) { 1529166675Srrs av->assoc_value = stcb->asoc.sctp_cmt_on_off; 1530166675Srrs SCTP_TCB_UNLOCK(stcb); 1531166675Srrs 1532166675Srrs } else { 1533166675Srrs error = ENOTCONN; 1534166675Srrs } 1535166675Srrs } else { 1536166675Srrs error = ENOPROTOOPT; 1537163953Srrs } 1538166675Srrs *optsize = sizeof(*av); 1539163953Srrs } 1540163953Srrs break; 1541163953Srrs case SCTP_GET_ADDR_LEN: 1542163953Srrs { 1543163953Srrs struct sctp_assoc_value *av; 1544163953Srrs 1545166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1546163953Srrs error = EINVAL; 1547167598Srrs#ifdef INET 1548163953Srrs if (av->assoc_value == AF_INET) { 1549163953Srrs av->assoc_value = sizeof(struct sockaddr_in); 1550163953Srrs error = 0; 1551163953Srrs } 1552163953Srrs#endif 1553167598Srrs#ifdef INET6 1554163953Srrs if (av->assoc_value == AF_INET6) { 1555163953Srrs av->assoc_value = sizeof(struct sockaddr_in6); 1556163953Srrs error = 0; 1557163953Srrs } 1558163953Srrs#endif 1559166675Srrs *optsize = sizeof(*av); 1560163953Srrs } 1561163953Srrs break; 1562169655Srrs case SCTP_GET_ASSOC_NUMBER: 1563163953Srrs { 1564169655Srrs uint32_t *value, cnt; 1565163953Srrs 1566169655Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1567163953Srrs cnt = 0; 1568163953Srrs SCTP_INP_RLOCK(inp); 1569169655Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 1570169655Srrs cnt++; 1571163953Srrs } 1572169655Srrs SCTP_INP_RUNLOCK(inp); 1573169655Srrs *value = cnt; 1574169655Srrs *optsize = sizeof(uint32_t); 1575169655Srrs } 1576169655Srrs break; 1577163953Srrs 1578169655Srrs case SCTP_GET_ASSOC_ID_LIST: 1579169655Srrs { 1580169655Srrs struct sctp_assoc_ids *ids; 1581169655Srrs unsigned int at, limit; 1582169655Srrs 1583169655Srrs SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize); 1584163953Srrs at = 0; 1585169655Srrs limit = *optsize / sizeof(sctp_assoc_t); 1586169655Srrs SCTP_INP_RLOCK(inp); 1587169655Srrs LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { 1588169655Srrs if (at < limit) { 1589169655Srrs ids->gaids_assoc_id[at++] = sctp_get_associd(stcb); 1590169655Srrs } else { 1591169655Srrs error = EINVAL; 1592163953Srrs break; 1593163953Srrs } 1594163953Srrs } 1595163953Srrs SCTP_INP_RUNLOCK(inp); 1596169655Srrs *optsize = at * sizeof(sctp_assoc_t); 1597163953Srrs } 1598163953Srrs break; 1599163953Srrs case SCTP_CONTEXT: 1600163953Srrs { 1601163953Srrs struct sctp_assoc_value *av; 1602163953Srrs 1603166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1604166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1605166675Srrs 1606166675Srrs if (stcb) { 1607166675Srrs av->assoc_value = stcb->asoc.context; 1608166675Srrs SCTP_TCB_UNLOCK(stcb); 1609163953Srrs } else { 1610166675Srrs SCTP_INP_RLOCK(inp); 1611163953Srrs av->assoc_value = inp->sctp_context; 1612166675Srrs SCTP_INP_RUNLOCK(inp); 1613163953Srrs } 1614166675Srrs *optsize = sizeof(*av); 1615163953Srrs } 1616163953Srrs break; 1617167598Srrs case SCTP_VRF_ID: 1618167598Srrs { 1619170056Srrs uint32_t *default_vrfid; 1620167598Srrs 1621170056Srrs SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize); 1622170056Srrs *default_vrfid = inp->def_vrf_id; 1623167598Srrs break; 1624167598Srrs } 1625167598Srrs case SCTP_GET_ASOC_VRF: 1626167598Srrs { 1627167598Srrs struct sctp_assoc_value *id; 1628167598Srrs 1629167598Srrs SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize); 1630167598Srrs SCTP_FIND_STCB(inp, stcb, id->assoc_id); 1631167598Srrs if (stcb == NULL) { 1632167598Srrs error = EINVAL; 1633167598Srrs break; 1634167598Srrs } 1635167598Srrs id->assoc_value = stcb->asoc.vrf_id; 1636167598Srrs break; 1637167598Srrs } 1638167598Srrs case SCTP_GET_VRF_IDS: 1639167598Srrs { 1640167598Srrs error = EOPNOTSUPP; 1641167598Srrs break; 1642167598Srrs } 1643163953Srrs case SCTP_GET_NONCE_VALUES: 1644163953Srrs { 1645163953Srrs struct sctp_get_nonce_values *gnv; 1646163953Srrs 1647166675Srrs SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize); 1648166675Srrs SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id); 1649166675Srrs 1650166675Srrs if (stcb) { 1651163953Srrs gnv->gn_peers_tag = stcb->asoc.peer_vtag; 1652163953Srrs gnv->gn_local_tag = stcb->asoc.my_vtag; 1653163953Srrs SCTP_TCB_UNLOCK(stcb); 1654166675Srrs } else { 1655166675Srrs error = ENOTCONN; 1656163953Srrs } 1657166675Srrs *optsize = sizeof(*gnv); 1658163953Srrs } 1659163953Srrs break; 1660170056Srrs case SCTP_DELAYED_SACK: 1661163953Srrs { 1662170056Srrs struct sctp_sack_info *sack; 1663163953Srrs 1664170056Srrs SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, *optsize); 1665170056Srrs SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); 1666166675Srrs if (stcb) { 1667170056Srrs sack->sack_delay = stcb->asoc.delayed_ack; 1668170056Srrs sack->sack_freq = stcb->asoc.sack_freq; 1669166675Srrs SCTP_TCB_UNLOCK(stcb); 1670166675Srrs } else { 1671163953Srrs SCTP_INP_RLOCK(inp); 1672170056Srrs sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); 1673170056Srrs sack->sack_freq = inp->sctp_ep.sctp_sack_freq; 1674163953Srrs SCTP_INP_RUNLOCK(inp); 1675163953Srrs } 1676170056Srrs *optsize = sizeof(*sack); 1677163953Srrs } 1678163953Srrs break; 1679163953Srrs 1680163953Srrs case SCTP_GET_SNDBUF_USE: 1681166675Srrs { 1682163953Srrs struct sctp_sockstat *ss; 1683163953Srrs 1684166675Srrs SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize); 1685166675Srrs SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id); 1686166675Srrs 1687166675Srrs if (stcb) { 1688166675Srrs ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size; 1689166675Srrs ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue + 1690166675Srrs stcb->asoc.size_on_all_streams); 1691166675Srrs SCTP_TCB_UNLOCK(stcb); 1692166675Srrs } else { 1693163953Srrs error = ENOTCONN; 1694163953Srrs } 1695166675Srrs *optsize = sizeof(struct sctp_sockstat); 1696163953Srrs } 1697163953Srrs break; 1698170056Srrs case SCTP_MAX_BURST: 1699163953Srrs { 1700166675Srrs uint8_t *value; 1701163953Srrs 1702166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint8_t, *optsize); 1703166675Srrs 1704163953Srrs SCTP_INP_RLOCK(inp); 1705166675Srrs *value = inp->sctp_ep.max_burst; 1706163953Srrs SCTP_INP_RUNLOCK(inp); 1707166675Srrs *optsize = sizeof(uint8_t); 1708163953Srrs } 1709163953Srrs break; 1710163953Srrs case SCTP_MAXSEG: 1711163953Srrs { 1712167598Srrs struct sctp_assoc_value *av; 1713163953Srrs int ovh; 1714163953Srrs 1715167598Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); 1716170056Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 1717163953Srrs 1718167598Srrs if (stcb) { 1719167598Srrs av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc); 1720167598Srrs SCTP_TCB_UNLOCK(stcb); 1721163953Srrs } else { 1722167598Srrs SCTP_INP_RLOCK(inp); 1723167598Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 1724167598Srrs ovh = SCTP_MED_OVERHEAD; 1725167598Srrs } else { 1726167598Srrs ovh = SCTP_MED_V4_OVERHEAD; 1727167598Srrs } 1728170056Srrs if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT) 1729170056Srrs av->assoc_value = 0; 1730170056Srrs else 1731170056Srrs av->assoc_value = inp->sctp_frag_point - ovh; 1732167598Srrs SCTP_INP_RUNLOCK(inp); 1733163953Srrs } 1734167598Srrs *optsize = sizeof(struct sctp_assoc_value); 1735163953Srrs } 1736163953Srrs break; 1737163953Srrs case SCTP_GET_STAT_LOG: 1738167598Srrs error = sctp_fill_stat_log(optval, optsize); 1739163953Srrs break; 1740163953Srrs case SCTP_EVENTS: 1741163953Srrs { 1742163953Srrs struct sctp_event_subscribe *events; 1743163953Srrs 1744166675Srrs SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize); 1745163953Srrs memset(events, 0, sizeof(*events)); 1746163953Srrs SCTP_INP_RLOCK(inp); 1747163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) 1748163953Srrs events->sctp_data_io_event = 1; 1749163953Srrs 1750163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT)) 1751163953Srrs events->sctp_association_event = 1; 1752163953Srrs 1753163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT)) 1754163953Srrs events->sctp_address_event = 1; 1755163953Srrs 1756163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) 1757163953Srrs events->sctp_send_failure_event = 1; 1758163953Srrs 1759163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR)) 1760163953Srrs events->sctp_peer_error_event = 1; 1761163953Srrs 1762163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) 1763163953Srrs events->sctp_shutdown_event = 1; 1764163953Srrs 1765163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT)) 1766163953Srrs events->sctp_partial_delivery_event = 1; 1767163953Srrs 1768163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) 1769163953Srrs events->sctp_adaptation_layer_event = 1; 1770163953Srrs 1771163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT)) 1772163953Srrs events->sctp_authentication_event = 1; 1773163953Srrs 1774163953Srrs if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) 1775163953Srrs events->sctp_stream_reset_events = 1; 1776163953Srrs SCTP_INP_RUNLOCK(inp); 1777166675Srrs *optsize = sizeof(struct sctp_event_subscribe); 1778163953Srrs } 1779163953Srrs break; 1780163953Srrs 1781163953Srrs case SCTP_ADAPTATION_LAYER: 1782166675Srrs { 1783166675Srrs uint32_t *value; 1784166675Srrs 1785166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1786166675Srrs 1787166675Srrs SCTP_INP_RLOCK(inp); 1788166675Srrs *value = inp->sctp_ep.adaptation_layer_indicator; 1789166675Srrs SCTP_INP_RUNLOCK(inp); 1790166675Srrs *optsize = sizeof(uint32_t); 1791163953Srrs } 1792163953Srrs break; 1793163953Srrs case SCTP_SET_INITIAL_DBG_SEQ: 1794166675Srrs { 1795166675Srrs uint32_t *value; 1796166675Srrs 1797166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1798166675Srrs SCTP_INP_RLOCK(inp); 1799166675Srrs *value = inp->sctp_ep.initial_sequence_debug; 1800166675Srrs SCTP_INP_RUNLOCK(inp); 1801166675Srrs *optsize = sizeof(uint32_t); 1802163953Srrs } 1803163953Srrs break; 1804163953Srrs case SCTP_GET_LOCAL_ADDR_SIZE: 1805166675Srrs { 1806166675Srrs uint32_t *value; 1807166675Srrs 1808166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1809166675Srrs SCTP_INP_RLOCK(inp); 1810168124Srrs *value = sctp_count_max_addresses(inp); 1811166675Srrs SCTP_INP_RUNLOCK(inp); 1812166675Srrs *optsize = sizeof(uint32_t); 1813163953Srrs } 1814163953Srrs break; 1815163953Srrs case SCTP_GET_REMOTE_ADDR_SIZE: 1816163953Srrs { 1817166675Srrs uint32_t *value; 1818166675Srrs size_t size; 1819163953Srrs struct sctp_nets *net; 1820163953Srrs 1821166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); 1822166675Srrs /* FIXME MT: change to sctp_assoc_value? */ 1823166675Srrs SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value); 1824166675Srrs 1825166675Srrs if (stcb) { 1826166675Srrs size = 0; 1827166675Srrs /* Count the sizes */ 1828166675Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1829166675Srrs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) || 1830166675Srrs (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET6)) { 1831166675Srrs size += sizeof(struct sockaddr_in6); 1832166675Srrs } else if (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET) { 1833166675Srrs size += sizeof(struct sockaddr_in); 1834166675Srrs } else { 1835166675Srrs /* huh */ 1836166675Srrs break; 1837166675Srrs } 1838163953Srrs } 1839166675Srrs SCTP_TCB_UNLOCK(stcb); 1840166675Srrs *value = (uint32_t) size; 1841166675Srrs } else { 1842166675Srrs error = ENOTCONN; 1843163953Srrs } 1844166675Srrs *optsize = sizeof(uint32_t); 1845163953Srrs } 1846163953Srrs break; 1847163953Srrs case SCTP_GET_PEER_ADDRESSES: 1848163953Srrs /* 1849163953Srrs * Get the address information, an array is passed in to 1850163953Srrs * fill up we pack it. 1851163953Srrs */ 1852163953Srrs { 1853166675Srrs size_t cpsz, left; 1854163953Srrs struct sockaddr_storage *sas; 1855163953Srrs struct sctp_nets *net; 1856163953Srrs struct sctp_getaddresses *saddr; 1857163953Srrs 1858166675Srrs SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); 1859166675Srrs SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); 1860163953Srrs 1861166675Srrs if (stcb) { 1862166675Srrs left = (*optsize) - sizeof(struct sctp_getaddresses); 1863166675Srrs *optsize = sizeof(struct sctp_getaddresses); 1864166675Srrs sas = (struct sockaddr_storage *)&saddr->addr[0]; 1865166675Srrs 1866166675Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1867166675Srrs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) || 1868166675Srrs (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET6)) { 1869166675Srrs cpsz = sizeof(struct sockaddr_in6); 1870166675Srrs } else if (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET) { 1871166675Srrs cpsz = sizeof(struct sockaddr_in); 1872166675Srrs } else { 1873166675Srrs /* huh */ 1874166675Srrs break; 1875166675Srrs } 1876166675Srrs if (left < cpsz) { 1877166675Srrs /* not enough room. */ 1878166675Srrs break; 1879166675Srrs } 1880166675Srrs if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) && 1881166675Srrs (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET)) { 1882166675Srrs /* Must map the address */ 1883166675Srrs in6_sin_2_v4mapsin6((struct sockaddr_in *)&net->ro._l_addr, 1884166675Srrs (struct sockaddr_in6 *)sas); 1885166675Srrs } else { 1886166675Srrs memcpy(sas, &net->ro._l_addr, cpsz); 1887166675Srrs } 1888166675Srrs ((struct sockaddr_in *)sas)->sin_port = stcb->rport; 1889166675Srrs 1890166675Srrs sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz); 1891166675Srrs left -= cpsz; 1892166675Srrs *optsize += cpsz; 1893163953Srrs } 1894166675Srrs SCTP_TCB_UNLOCK(stcb); 1895166675Srrs } else { 1896166675Srrs error = ENOENT; 1897163953Srrs } 1898163953Srrs } 1899163953Srrs break; 1900163953Srrs case SCTP_GET_LOCAL_ADDRESSES: 1901163953Srrs { 1902166675Srrs size_t limit, actual; 1903163953Srrs struct sockaddr_storage *sas; 1904163953Srrs struct sctp_getaddresses *saddr; 1905163953Srrs 1906166675Srrs SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); 1907166675Srrs SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); 1908163953Srrs 1909163953Srrs sas = (struct sockaddr_storage *)&saddr->addr[0]; 1910166675Srrs limit = *optsize - sizeof(sctp_assoc_t); 1911168124Srrs actual = sctp_fill_up_addresses(inp, stcb, limit, sas); 1912169655Srrs if (stcb) { 1913163953Srrs SCTP_TCB_UNLOCK(stcb); 1914169655Srrs } 1915166675Srrs *optsize = sizeof(struct sockaddr_storage) + actual; 1916163953Srrs } 1917163953Srrs break; 1918163953Srrs case SCTP_PEER_ADDR_PARAMS: 1919163953Srrs { 1920163953Srrs struct sctp_paddrparams *paddrp; 1921163953Srrs struct sctp_nets *net; 1922163953Srrs 1923166675Srrs SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize); 1924166675Srrs SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); 1925163953Srrs 1926163953Srrs net = NULL; 1927166675Srrs if (stcb) { 1928166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address); 1929166675Srrs } else { 1930166675Srrs /* 1931166675Srrs * We increment here since 1932166675Srrs * sctp_findassociation_ep_addr() wil do a 1933166675Srrs * decrement if it finds the stcb as long as 1934166675Srrs * the locked tcb (last argument) is NOT a 1935166675Srrs * TCB.. aka NULL. 1936166675Srrs */ 1937166675Srrs SCTP_INP_INCR_REF(inp); 1938166675Srrs stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddrp->spp_address, &net, NULL, NULL); 1939163953Srrs if (stcb == NULL) { 1940166675Srrs SCTP_INP_DECR_REF(inp); 1941163953Srrs } 1942163953Srrs } 1943163953Srrs 1944163953Srrs if (stcb) { 1945163953Srrs /* Applys to the specific association */ 1946163953Srrs paddrp->spp_flags = 0; 1947163953Srrs if (net) { 1948170056Srrs int ovh; 1949170056Srrs 1950170056Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 1951170056Srrs ovh = SCTP_MED_OVERHEAD; 1952170056Srrs } else { 1953170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 1954170056Srrs } 1955170056Srrs 1956170056Srrs 1957163953Srrs paddrp->spp_pathmaxrxt = net->failure_threshold; 1958170056Srrs paddrp->spp_pathmtu = net->mtu - ovh; 1959163953Srrs /* get flags for HB */ 1960163953Srrs if (net->dest_state & SCTP_ADDR_NOHB) 1961163953Srrs paddrp->spp_flags |= SPP_HB_DISABLE; 1962163953Srrs else 1963163953Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 1964163953Srrs /* get flags for PMTU */ 1965165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 1966163953Srrs paddrp->spp_flags |= SPP_PMTUD_ENABLE; 1967163953Srrs } else { 1968163953Srrs paddrp->spp_flags |= SPP_PMTUD_DISABLE; 1969163953Srrs } 1970167598Srrs#ifdef INET 1971163953Srrs if (net->ro._l_addr.sin.sin_family == AF_INET) { 1972163953Srrs paddrp->spp_ipv4_tos = net->tos_flowlabel & 0x000000fc; 1973163953Srrs paddrp->spp_flags |= SPP_IPV4_TOS; 1974163953Srrs } 1975163953Srrs#endif 1976167598Srrs#ifdef INET6 1977163953Srrs if (net->ro._l_addr.sin6.sin6_family == AF_INET6) { 1978163953Srrs paddrp->spp_ipv6_flowlabel = net->tos_flowlabel; 1979163953Srrs paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 1980163953Srrs } 1981163953Srrs#endif 1982163953Srrs } else { 1983163953Srrs /* 1984163953Srrs * No destination so return default 1985163953Srrs * value 1986163953Srrs */ 1987170056Srrs int cnt = 0; 1988170056Srrs 1989163953Srrs paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure; 1990163953Srrs paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc); 1991167598Srrs#ifdef INET 1992163953Srrs paddrp->spp_ipv4_tos = stcb->asoc.default_tos & 0x000000fc; 1993163953Srrs paddrp->spp_flags |= SPP_IPV4_TOS; 1994163953Srrs#endif 1995167598Srrs#ifdef INET6 1996163953Srrs paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel; 1997163953Srrs paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 1998163953Srrs#endif 1999163953Srrs /* default settings should be these */ 2000170056Srrs if (stcb->asoc.hb_is_disabled == 0) { 2001163953Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 2002170056Srrs } else { 2003170056Srrs paddrp->spp_flags |= SPP_HB_DISABLE; 2004163953Srrs } 2005170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 2006170056Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 2007170056Srrs cnt++; 2008170056Srrs } 2009170056Srrs } 2010170056Srrs if (cnt) { 2011170056Srrs paddrp->spp_flags |= SPP_PMTUD_ENABLE; 2012170056Srrs } 2013163953Srrs } 2014163953Srrs paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay; 2015163953Srrs paddrp->spp_assoc_id = sctp_get_associd(stcb); 2016163953Srrs SCTP_TCB_UNLOCK(stcb); 2017163953Srrs } else { 2018163953Srrs /* Use endpoint defaults */ 2019163953Srrs SCTP_INP_RLOCK(inp); 2020163953Srrs paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure; 2021163953Srrs paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); 2022163953Srrs paddrp->spp_assoc_id = (sctp_assoc_t) 0; 2023163953Srrs /* get inp's default */ 2024167598Srrs#ifdef INET 2025163953Srrs paddrp->spp_ipv4_tos = inp->ip_inp.inp.inp_ip_tos; 2026163953Srrs paddrp->spp_flags |= SPP_IPV4_TOS; 2027163953Srrs#endif 2028167598Srrs#ifdef INET6 2029163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2030163953Srrs paddrp->spp_ipv6_flowlabel = ((struct in6pcb *)inp)->in6p_flowinfo; 2031163953Srrs paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; 2032163953Srrs } 2033163953Srrs#endif 2034163953Srrs /* can't return this */ 2035163953Srrs paddrp->spp_pathmtu = 0; 2036170056Srrs 2037163953Srrs /* default behavior, no stcb */ 2038170056Srrs paddrp->spp_flags = SPP_PMTUD_ENABLE; 2039163953Srrs 2040170056Srrs if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { 2041170056Srrs paddrp->spp_flags |= SPP_HB_ENABLE; 2042170056Srrs } else { 2043170056Srrs paddrp->spp_flags |= SPP_HB_DISABLE; 2044170056Srrs } 2045163953Srrs SCTP_INP_RUNLOCK(inp); 2046163953Srrs } 2047166675Srrs *optsize = sizeof(struct sctp_paddrparams); 2048163953Srrs } 2049163953Srrs break; 2050163953Srrs case SCTP_GET_PEER_ADDR_INFO: 2051163953Srrs { 2052163953Srrs struct sctp_paddrinfo *paddri; 2053163953Srrs struct sctp_nets *net; 2054163953Srrs 2055166675Srrs SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize); 2056166675Srrs SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id); 2057166675Srrs 2058163953Srrs net = NULL; 2059166675Srrs if (stcb) { 2060166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddri->spinfo_address); 2061166675Srrs } else { 2062166675Srrs /* 2063166675Srrs * We increment here since 2064166675Srrs * sctp_findassociation_ep_addr() wil do a 2065166675Srrs * decrement if it finds the stcb as long as 2066166675Srrs * the locked tcb (last argument) is NOT a 2067166675Srrs * TCB.. aka NULL. 2068166675Srrs */ 2069166675Srrs SCTP_INP_INCR_REF(inp); 2070166675Srrs stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddri->spinfo_address, &net, NULL, NULL); 2071166675Srrs if (stcb == NULL) { 2072166675Srrs SCTP_INP_DECR_REF(inp); 2073163953Srrs } 2074166675Srrs } 2075163953Srrs 2076166675Srrs if ((stcb) && (net)) { 2077166675Srrs paddri->spinfo_state = net->dest_state & (SCTP_REACHABLE_MASK | SCTP_ADDR_NOHB); 2078166675Srrs paddri->spinfo_cwnd = net->cwnd; 2079166675Srrs paddri->spinfo_srtt = ((net->lastsa >> 2) + net->lastsv) >> 1; 2080166675Srrs paddri->spinfo_rto = net->RTO; 2081166675Srrs paddri->spinfo_assoc_id = sctp_get_associd(stcb); 2082166675Srrs SCTP_TCB_UNLOCK(stcb); 2083163953Srrs } else { 2084163953Srrs if (stcb) { 2085163953Srrs SCTP_TCB_UNLOCK(stcb); 2086163953Srrs } 2087163953Srrs error = ENOENT; 2088163953Srrs } 2089166675Srrs *optsize = sizeof(struct sctp_paddrinfo); 2090163953Srrs } 2091163953Srrs break; 2092163953Srrs case SCTP_PCB_STATUS: 2093163953Srrs { 2094163953Srrs struct sctp_pcbinfo *spcb; 2095163953Srrs 2096166675Srrs SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize); 2097163953Srrs sctp_fill_pcbinfo(spcb); 2098166675Srrs *optsize = sizeof(struct sctp_pcbinfo); 2099163953Srrs } 2100163953Srrs break; 2101167598Srrs 2102163953Srrs case SCTP_STATUS: 2103163953Srrs { 2104163953Srrs struct sctp_nets *net; 2105163953Srrs struct sctp_status *sstat; 2106163953Srrs 2107166675Srrs SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize); 2108166675Srrs SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id); 2109163953Srrs 2110163953Srrs if (stcb == NULL) { 2111163953Srrs error = EINVAL; 2112163953Srrs break; 2113163953Srrs } 2114163953Srrs /* 2115163953Srrs * I think passing the state is fine since 2116163953Srrs * sctp_constants.h will be available to the user 2117163953Srrs * land. 2118163953Srrs */ 2119163953Srrs sstat->sstat_state = stcb->asoc.state; 2120163953Srrs sstat->sstat_rwnd = stcb->asoc.peers_rwnd; 2121163953Srrs sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt; 2122163953Srrs /* 2123163953Srrs * We can't include chunks that have been passed to 2124163953Srrs * the socket layer. Only things in queue. 2125163953Srrs */ 2126163953Srrs sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue + 2127163953Srrs stcb->asoc.cnt_on_all_streams); 2128163953Srrs 2129163953Srrs 2130163953Srrs sstat->sstat_instrms = stcb->asoc.streamincnt; 2131163953Srrs sstat->sstat_outstrms = stcb->asoc.streamoutcnt; 2132163953Srrs sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc); 2133163953Srrs memcpy(&sstat->sstat_primary.spinfo_address, 2134163953Srrs &stcb->asoc.primary_destination->ro._l_addr, 2135163953Srrs ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len); 2136163953Srrs net = stcb->asoc.primary_destination; 2137163953Srrs ((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport; 2138163953Srrs /* 2139163953Srrs * Again the user can get info from sctp_constants.h 2140163953Srrs * for what the state of the network is. 2141163953Srrs */ 2142163953Srrs sstat->sstat_primary.spinfo_state = net->dest_state & SCTP_REACHABLE_MASK; 2143163953Srrs sstat->sstat_primary.spinfo_cwnd = net->cwnd; 2144163953Srrs sstat->sstat_primary.spinfo_srtt = net->lastsa; 2145163953Srrs sstat->sstat_primary.spinfo_rto = net->RTO; 2146163953Srrs sstat->sstat_primary.spinfo_mtu = net->mtu; 2147163953Srrs sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb); 2148163953Srrs SCTP_TCB_UNLOCK(stcb); 2149166675Srrs *optsize = sizeof(*sstat); 2150163953Srrs } 2151163953Srrs break; 2152163953Srrs case SCTP_RTOINFO: 2153163953Srrs { 2154163953Srrs struct sctp_rtoinfo *srto; 2155163953Srrs 2156166675Srrs SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize); 2157166675Srrs SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); 2158166675Srrs 2159166675Srrs if (stcb) { 2160166675Srrs srto->srto_initial = stcb->asoc.initial_rto; 2161166675Srrs srto->srto_max = stcb->asoc.maxrto; 2162166675Srrs srto->srto_min = stcb->asoc.minrto; 2163166675Srrs SCTP_TCB_UNLOCK(stcb); 2164166675Srrs } else { 2165163953Srrs SCTP_INP_RLOCK(inp); 2166163953Srrs srto->srto_initial = inp->sctp_ep.initial_rto; 2167163953Srrs srto->srto_max = inp->sctp_ep.sctp_maxrto; 2168163953Srrs srto->srto_min = inp->sctp_ep.sctp_minrto; 2169163953Srrs SCTP_INP_RUNLOCK(inp); 2170163953Srrs } 2171166675Srrs *optsize = sizeof(*srto); 2172163953Srrs } 2173163953Srrs break; 2174163953Srrs case SCTP_ASSOCINFO: 2175163953Srrs { 2176163953Srrs struct sctp_assocparams *sasoc; 2177163953Srrs 2178166675Srrs SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize); 2179166675Srrs SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); 2180163953Srrs 2181163953Srrs if (stcb) { 2182163953Srrs sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times; 2183163953Srrs sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets; 2184163953Srrs sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd; 2185163953Srrs sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd; 2186169655Srrs sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life); 2187163953Srrs SCTP_TCB_UNLOCK(stcb); 2188163953Srrs } else { 2189163953Srrs SCTP_INP_RLOCK(inp); 2190163953Srrs sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times; 2191163953Srrs sasoc->sasoc_number_peer_destinations = 0; 2192163953Srrs sasoc->sasoc_peer_rwnd = 0; 2193163953Srrs sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv); 2194169655Srrs sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life); 2195163953Srrs SCTP_INP_RUNLOCK(inp); 2196163953Srrs } 2197166675Srrs *optsize = sizeof(*sasoc); 2198163953Srrs } 2199163953Srrs break; 2200163953Srrs case SCTP_DEFAULT_SEND_PARAM: 2201163953Srrs { 2202163953Srrs struct sctp_sndrcvinfo *s_info; 2203163953Srrs 2204166675Srrs SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize); 2205166675Srrs SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); 2206166675Srrs 2207166675Srrs if (stcb) { 2208170056Srrs memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send)); 2209166675Srrs SCTP_TCB_UNLOCK(stcb); 2210166675Srrs } else { 2211163953Srrs SCTP_INP_RLOCK(inp); 2212170056Srrs memcpy(s_info, &inp->def_send, sizeof(inp->def_send)); 2213163953Srrs SCTP_INP_RUNLOCK(inp); 2214163953Srrs } 2215166675Srrs *optsize = sizeof(*s_info); 2216163953Srrs } 2217163953Srrs break; 2218163953Srrs case SCTP_INITMSG: 2219163953Srrs { 2220163953Srrs struct sctp_initmsg *sinit; 2221163953Srrs 2222166675Srrs SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize); 2223163953Srrs SCTP_INP_RLOCK(inp); 2224163953Srrs sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count; 2225163953Srrs sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome; 2226163953Srrs sinit->sinit_max_attempts = inp->sctp_ep.max_init_times; 2227163953Srrs sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max; 2228163953Srrs SCTP_INP_RUNLOCK(inp); 2229166675Srrs *optsize = sizeof(*sinit); 2230163953Srrs } 2231163953Srrs break; 2232163953Srrs case SCTP_PRIMARY_ADDR: 2233163953Srrs /* we allow a "get" operation on this */ 2234163953Srrs { 2235163953Srrs struct sctp_setprim *ssp; 2236163953Srrs 2237166675Srrs SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize); 2238166675Srrs SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id); 2239166675Srrs 2240166675Srrs if (stcb) { 2241166675Srrs /* simply copy out the sockaddr_storage... */ 2242170056Srrs int len; 2243170056Srrs 2244170056Srrs len = *optsize; 2245170056Srrs if (len > stcb->asoc.primary_destination->ro._l_addr.sa.sa_len) 2246170056Srrs len = stcb->asoc.primary_destination->ro._l_addr.sa.sa_len; 2247170056Srrs 2248170056Srrs memcpy(&ssp->ssp_addr, 2249170056Srrs &stcb->asoc.primary_destination->ro._l_addr, 2250170056Srrs len); 2251166675Srrs SCTP_TCB_UNLOCK(stcb); 2252166675Srrs } else { 2253163953Srrs error = EINVAL; 2254163953Srrs } 2255166675Srrs *optsize = sizeof(*ssp); 2256163953Srrs } 2257163953Srrs break; 2258163953Srrs 2259163953Srrs case SCTP_HMAC_IDENT: 2260163953Srrs { 2261163953Srrs struct sctp_hmacalgo *shmac; 2262163953Srrs sctp_hmaclist_t *hmaclist; 2263163953Srrs uint32_t size; 2264163953Srrs int i; 2265163953Srrs 2266166675Srrs SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize); 2267166675Srrs 2268163953Srrs SCTP_INP_RLOCK(inp); 2269163953Srrs hmaclist = inp->sctp_ep.local_hmacs; 2270163953Srrs if (hmaclist == NULL) { 2271163953Srrs /* no HMACs to return */ 2272166675Srrs *optsize = sizeof(*shmac); 2273168299Srrs SCTP_INP_RUNLOCK(inp); 2274163953Srrs break; 2275163953Srrs } 2276163953Srrs /* is there room for all of the hmac ids? */ 2277163953Srrs size = sizeof(*shmac) + (hmaclist->num_algo * 2278163953Srrs sizeof(shmac->shmac_idents[0])); 2279166675Srrs if ((size_t)(*optsize) < size) { 2280163953Srrs error = EINVAL; 2281163953Srrs SCTP_INP_RUNLOCK(inp); 2282163953Srrs break; 2283163953Srrs } 2284163953Srrs /* copy in the list */ 2285163953Srrs for (i = 0; i < hmaclist->num_algo; i++) 2286163953Srrs shmac->shmac_idents[i] = hmaclist->hmac[i]; 2287163953Srrs SCTP_INP_RUNLOCK(inp); 2288166675Srrs *optsize = size; 2289163953Srrs break; 2290163953Srrs } 2291163953Srrs case SCTP_AUTH_ACTIVE_KEY: 2292163953Srrs { 2293163953Srrs struct sctp_authkeyid *scact; 2294163953Srrs 2295166675Srrs SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize); 2296166675Srrs SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); 2297166675Srrs 2298166675Srrs if (stcb) { 2299163953Srrs /* get the active key on the assoc */ 2300163953Srrs scact->scact_keynumber = stcb->asoc.authinfo.assoc_keyid; 2301163953Srrs SCTP_TCB_UNLOCK(stcb); 2302163953Srrs } else { 2303163953Srrs /* get the endpoint active key */ 2304163953Srrs SCTP_INP_RLOCK(inp); 2305163953Srrs scact->scact_keynumber = inp->sctp_ep.default_keyid; 2306163953Srrs SCTP_INP_RUNLOCK(inp); 2307163953Srrs } 2308166675Srrs *optsize = sizeof(*scact); 2309163953Srrs break; 2310163953Srrs } 2311163953Srrs case SCTP_LOCAL_AUTH_CHUNKS: 2312163953Srrs { 2313163953Srrs struct sctp_authchunks *sac; 2314163953Srrs sctp_auth_chklist_t *chklist = NULL; 2315166675Srrs size_t size = 0; 2316163953Srrs 2317166675Srrs SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); 2318166675Srrs SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); 2319166675Srrs 2320166675Srrs if (stcb) { 2321163953Srrs /* get off the assoc */ 2322163953Srrs chklist = stcb->asoc.local_auth_chunks; 2323163953Srrs /* is there enough space? */ 2324163953Srrs size = sctp_auth_get_chklist_size(chklist); 2325166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2326163953Srrs error = EINVAL; 2327166675Srrs } else { 2328166675Srrs /* copy in the chunks */ 2329169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2330163953Srrs } 2331163953Srrs SCTP_TCB_UNLOCK(stcb); 2332163953Srrs } else { 2333163953Srrs /* get off the endpoint */ 2334163953Srrs SCTP_INP_RLOCK(inp); 2335163953Srrs chklist = inp->sctp_ep.local_auth_chunks; 2336163953Srrs /* is there enough space? */ 2337163953Srrs size = sctp_auth_get_chklist_size(chklist); 2338166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2339163953Srrs error = EINVAL; 2340166675Srrs } else { 2341166675Srrs /* copy in the chunks */ 2342169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2343163953Srrs } 2344163953Srrs SCTP_INP_RUNLOCK(inp); 2345163953Srrs } 2346166675Srrs *optsize = sizeof(struct sctp_authchunks) + size; 2347163953Srrs break; 2348163953Srrs } 2349163953Srrs case SCTP_PEER_AUTH_CHUNKS: 2350163953Srrs { 2351163953Srrs struct sctp_authchunks *sac; 2352163953Srrs sctp_auth_chklist_t *chklist = NULL; 2353166675Srrs size_t size = 0; 2354163953Srrs 2355166675Srrs SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); 2356166675Srrs SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); 2357166675Srrs 2358166675Srrs if (stcb) { 2359166675Srrs /* get off the assoc */ 2360166675Srrs chklist = stcb->asoc.peer_auth_chunks; 2361166675Srrs /* is there enough space? */ 2362166675Srrs size = sctp_auth_get_chklist_size(chklist); 2363166675Srrs if (*optsize < (sizeof(struct sctp_authchunks) + size)) { 2364166675Srrs error = EINVAL; 2365166675Srrs } else { 2366166675Srrs /* copy in the chunks */ 2367169420Srrs (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); 2368166675Srrs } 2369166675Srrs SCTP_TCB_UNLOCK(stcb); 2370166675Srrs } else { 2371163953Srrs error = ENOENT; 2372163953Srrs } 2373166675Srrs *optsize = sizeof(struct sctp_authchunks) + size; 2374163953Srrs break; 2375163953Srrs } 2376163953Srrs 2377163953Srrs 2378163953Srrs default: 2379163953Srrs error = ENOPROTOOPT; 2380166675Srrs *optsize = 0; 2381163953Srrs break; 2382163953Srrs } /* end switch (sopt->sopt_name) */ 2383163953Srrs return (error); 2384163953Srrs} 2385163953Srrs 2386163953Srrsstatic int 2387166675Srrssctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, 2388166675Srrs void *p) 2389163953Srrs{ 2390166675Srrs int error, set_opt; 2391166675Srrs uint32_t *mopt; 2392163953Srrs struct sctp_tcb *stcb = NULL; 2393163953Srrs struct sctp_inpcb *inp; 2394167598Srrs uint32_t vrf_id; 2395163953Srrs 2396166675Srrs if (optval == NULL) { 2397169420Srrs SCTP_PRINTF("optval is NULL\n"); 2398163953Srrs return (EINVAL); 2399163953Srrs } 2400163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 2401167598Srrs if (inp == 0) { 2402169420Srrs SCTP_PRINTF("inp is NULL?\n"); 2403163953Srrs return EINVAL; 2404167598Srrs } 2405168299Srrs vrf_id = inp->def_vrf_id; 2406163953Srrs 2407163953Srrs error = 0; 2408166675Srrs switch (optname) { 2409163953Srrs case SCTP_NODELAY: 2410163953Srrs case SCTP_AUTOCLOSE: 2411163953Srrs case SCTP_AUTO_ASCONF: 2412163953Srrs case SCTP_EXPLICIT_EOR: 2413163953Srrs case SCTP_DISABLE_FRAGMENTS: 2414163953Srrs case SCTP_USE_EXT_RCVINFO: 2415163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 2416163953Srrs /* copy in the option value */ 2417166675Srrs SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); 2418163953Srrs set_opt = 0; 2419163953Srrs if (error) 2420163953Srrs break; 2421166675Srrs switch (optname) { 2422163953Srrs case SCTP_DISABLE_FRAGMENTS: 2423163953Srrs set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT; 2424163953Srrs break; 2425163953Srrs case SCTP_AUTO_ASCONF: 2426163953Srrs set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF; 2427163953Srrs break; 2428163953Srrs case SCTP_EXPLICIT_EOR: 2429163953Srrs set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR; 2430163953Srrs break; 2431163953Srrs case SCTP_USE_EXT_RCVINFO: 2432163953Srrs set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO; 2433163953Srrs break; 2434163953Srrs case SCTP_I_WANT_MAPPED_V4_ADDR: 2435163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2436163953Srrs set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4; 2437163953Srrs } else { 2438163953Srrs return (EINVAL); 2439163953Srrs } 2440163953Srrs break; 2441163953Srrs case SCTP_NODELAY: 2442163953Srrs set_opt = SCTP_PCB_FLAGS_NODELAY; 2443163953Srrs break; 2444163953Srrs case SCTP_AUTOCLOSE: 2445170056Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2446170056Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 2447170056Srrs return (EINVAL); 2448170056Srrs } 2449163953Srrs set_opt = SCTP_PCB_FLAGS_AUTOCLOSE; 2450163953Srrs /* 2451163953Srrs * The value is in ticks. Note this does not effect 2452163953Srrs * old associations, only new ones. 2453163953Srrs */ 2454163953Srrs inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt); 2455163953Srrs break; 2456163953Srrs } 2457163953Srrs SCTP_INP_WLOCK(inp); 2458163953Srrs if (*mopt != 0) { 2459163953Srrs sctp_feature_on(inp, set_opt); 2460163953Srrs } else { 2461163953Srrs sctp_feature_off(inp, set_opt); 2462163953Srrs } 2463163953Srrs SCTP_INP_WUNLOCK(inp); 2464163953Srrs break; 2465163953Srrs case SCTP_PARTIAL_DELIVERY_POINT: 2466163953Srrs { 2467166675Srrs uint32_t *value; 2468166675Srrs 2469166675Srrs SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); 2470167736Srrs if (*value > SCTP_SB_LIMIT_RCV(so)) { 2471167736Srrs error = EINVAL; 2472167736Srrs break; 2473167736Srrs } 2474166675Srrs inp->partial_delivery_point = *value; 2475163953Srrs } 2476163953Srrs break; 2477163953Srrs case SCTP_FRAGMENT_INTERLEAVE: 2478163953Srrs /* not yet until we re-write sctp_recvmsg() */ 2479163953Srrs { 2480168943Srrs uint32_t *level; 2481163953Srrs 2482168943Srrs SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize); 2483168943Srrs if (*level == SCTP_FRAG_LEVEL_2) { 2484163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 2485168943Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 2486168943Srrs } else if (*level == SCTP_FRAG_LEVEL_1) { 2487168943Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 2488168943Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 2489168943Srrs } else if (*level == SCTP_FRAG_LEVEL_0) { 2490170056Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); 2491168943Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); 2492168943Srrs 2493163953Srrs } else { 2494168943Srrs error = EINVAL; 2495163953Srrs } 2496163953Srrs } 2497163953Srrs break; 2498163953Srrs case SCTP_CMT_ON_OFF: 2499163953Srrs { 2500163953Srrs struct sctp_assoc_value *av; 2501163953Srrs 2502166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 2503166675Srrs if (sctp_cmt_on_off) { 2504166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2505166675Srrs if (stcb) { 2506163953Srrs stcb->asoc.sctp_cmt_on_off = (uint8_t) av->assoc_value; 2507166675Srrs SCTP_TCB_UNLOCK(stcb); 2508163953Srrs } else { 2509166675Srrs error = ENOTCONN; 2510163953Srrs } 2511166675Srrs } else { 2512166675Srrs error = ENOPROTOOPT; 2513163953Srrs } 2514163953Srrs } 2515163953Srrs break; 2516163953Srrs case SCTP_CLR_STAT_LOG: 2517163953Srrs error = EOPNOTSUPP; 2518163953Srrs break; 2519163953Srrs case SCTP_CONTEXT: 2520163953Srrs { 2521163953Srrs struct sctp_assoc_value *av; 2522163953Srrs 2523166675Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 2524166675Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2525166675Srrs 2526166675Srrs if (stcb) { 2527166675Srrs stcb->asoc.context = av->assoc_value; 2528166675Srrs SCTP_TCB_UNLOCK(stcb); 2529163953Srrs } else { 2530166675Srrs SCTP_INP_WLOCK(inp); 2531163953Srrs inp->sctp_context = av->assoc_value; 2532166675Srrs SCTP_INP_WUNLOCK(inp); 2533163953Srrs } 2534163953Srrs } 2535163953Srrs break; 2536167598Srrs case SCTP_VRF_ID: 2537167598Srrs { 2538170056Srrs uint32_t *default_vrfid; 2539167598Srrs 2540170056Srrs SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize); 2541170056Srrs if (*default_vrfid > SCTP_MAX_VRF_ID) { 2542167598Srrs error = EINVAL; 2543167598Srrs break; 2544167598Srrs } 2545170056Srrs inp->def_vrf_id = *default_vrfid; 2546167598Srrs break; 2547167598Srrs } 2548167598Srrs case SCTP_DEL_VRF_ID: 2549167598Srrs { 2550167598Srrs error = EOPNOTSUPP; 2551167598Srrs break; 2552167598Srrs } 2553167598Srrs case SCTP_ADD_VRF_ID: 2554167598Srrs { 2555167598Srrs error = EOPNOTSUPP; 2556167598Srrs break; 2557167598Srrs } 2558170056Srrs case SCTP_DELAYED_SACK: 2559163953Srrs { 2560170056Srrs struct sctp_sack_info *sack; 2561163953Srrs 2562170056Srrs SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize); 2563170056Srrs SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); 2564166675Srrs if (stcb) { 2565170056Srrs if (sack->sack_delay) { 2566170056Srrs if (MSEC_TO_TICKS(sack->sack_delay) < 1) { 2567170056Srrs sack->sack_delay = TICKS_TO_MSEC(1); 2568170056Srrs } 2569170056Srrs stcb->asoc.delayed_ack = sack->sack_delay; 2570170056Srrs } 2571170056Srrs if (sack->sack_freq) { 2572170056Srrs stcb->asoc.sack_freq = sack->sack_freq; 2573170056Srrs } 2574166675Srrs SCTP_TCB_UNLOCK(stcb); 2575166675Srrs } else { 2576163953Srrs SCTP_INP_WLOCK(inp); 2577170056Srrs if (sack->sack_delay) { 2578170056Srrs if (MSEC_TO_TICKS(sack->sack_delay) < 1) { 2579170056Srrs sack->sack_delay = TICKS_TO_MSEC(1); 2580170056Srrs } 2581170056Srrs inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay); 2582170056Srrs } 2583170056Srrs if (sack->sack_freq) { 2584170056Srrs inp->sctp_ep.sctp_sack_freq = sack->sack_freq; 2585170056Srrs } 2586163953Srrs SCTP_INP_WUNLOCK(inp); 2587163953Srrs } 2588166675Srrs break; 2589163953Srrs } 2590163953Srrs case SCTP_AUTH_CHUNK: 2591163953Srrs { 2592163953Srrs struct sctp_authchunk *sauth; 2593163953Srrs 2594166675Srrs SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize); 2595166675Srrs 2596166675Srrs SCTP_INP_WLOCK(inp); 2597166675Srrs if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) 2598163953Srrs error = EINVAL; 2599166675Srrs SCTP_INP_WUNLOCK(inp); 2600163953Srrs break; 2601163953Srrs } 2602163953Srrs case SCTP_AUTH_KEY: 2603163953Srrs { 2604163953Srrs struct sctp_authkey *sca; 2605163953Srrs struct sctp_keyhead *shared_keys; 2606163953Srrs sctp_sharedkey_t *shared_key; 2607163953Srrs sctp_key_t *key = NULL; 2608166675Srrs size_t size; 2609163953Srrs 2610166675Srrs SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize); 2611169420Srrs SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id); 2612169420Srrs size = optsize - sizeof(*sca); 2613166675Srrs 2614166675Srrs if (stcb) { 2615163953Srrs /* set it on the assoc */ 2616163953Srrs shared_keys = &stcb->asoc.shared_keys; 2617163953Srrs /* clear the cached keys for this key id */ 2618163953Srrs sctp_clear_cachedkeys(stcb, sca->sca_keynumber); 2619163953Srrs /* 2620163953Srrs * create the new shared key and 2621163953Srrs * insert/replace it 2622163953Srrs */ 2623163953Srrs if (size > 0) { 2624163953Srrs key = sctp_set_key(sca->sca_key, (uint32_t) size); 2625163953Srrs if (key == NULL) { 2626163953Srrs error = ENOMEM; 2627163953Srrs SCTP_TCB_UNLOCK(stcb); 2628163953Srrs break; 2629163953Srrs } 2630163953Srrs } 2631163953Srrs shared_key = sctp_alloc_sharedkey(); 2632163953Srrs if (shared_key == NULL) { 2633163953Srrs sctp_free_key(key); 2634163953Srrs error = ENOMEM; 2635163953Srrs SCTP_TCB_UNLOCK(stcb); 2636163953Srrs break; 2637163953Srrs } 2638163953Srrs shared_key->key = key; 2639163953Srrs shared_key->keyid = sca->sca_keynumber; 2640163953Srrs sctp_insert_sharedkey(shared_keys, shared_key); 2641163953Srrs SCTP_TCB_UNLOCK(stcb); 2642163953Srrs } else { 2643166675Srrs /* set it on the endpoint */ 2644163953Srrs SCTP_INP_WLOCK(inp); 2645163953Srrs shared_keys = &inp->sctp_ep.shared_keys; 2646163953Srrs /* 2647163953Srrs * clear the cached keys on all assocs for 2648163953Srrs * this key id 2649163953Srrs */ 2650163953Srrs sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber); 2651163953Srrs /* 2652163953Srrs * create the new shared key and 2653163953Srrs * insert/replace it 2654163953Srrs */ 2655163953Srrs if (size > 0) { 2656163953Srrs key = sctp_set_key(sca->sca_key, (uint32_t) size); 2657163953Srrs if (key == NULL) { 2658163953Srrs error = ENOMEM; 2659163953Srrs SCTP_INP_WUNLOCK(inp); 2660163953Srrs break; 2661163953Srrs } 2662163953Srrs } 2663163953Srrs shared_key = sctp_alloc_sharedkey(); 2664163953Srrs if (shared_key == NULL) { 2665163953Srrs sctp_free_key(key); 2666163953Srrs error = ENOMEM; 2667163953Srrs SCTP_INP_WUNLOCK(inp); 2668163953Srrs break; 2669163953Srrs } 2670163953Srrs shared_key->key = key; 2671163953Srrs shared_key->keyid = sca->sca_keynumber; 2672163953Srrs sctp_insert_sharedkey(shared_keys, shared_key); 2673163953Srrs SCTP_INP_WUNLOCK(inp); 2674163953Srrs } 2675163953Srrs break; 2676163953Srrs } 2677163953Srrs case SCTP_HMAC_IDENT: 2678163953Srrs { 2679163953Srrs struct sctp_hmacalgo *shmac; 2680163953Srrs sctp_hmaclist_t *hmaclist; 2681163953Srrs uint32_t hmacid; 2682170056Srrs size_t size, i, found; 2683163953Srrs 2684166675Srrs SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize); 2685166675Srrs size = (optsize - sizeof(*shmac)) / sizeof(shmac->shmac_idents[0]); 2686163953Srrs hmaclist = sctp_alloc_hmaclist(size); 2687163953Srrs if (hmaclist == NULL) { 2688163953Srrs error = ENOMEM; 2689163953Srrs break; 2690163953Srrs } 2691163953Srrs for (i = 0; i < size; i++) { 2692163953Srrs hmacid = shmac->shmac_idents[i]; 2693163953Srrs if (sctp_auth_add_hmacid(hmaclist, (uint16_t) hmacid)) { 2694163953Srrs /* invalid HMACs were found */ ; 2695163953Srrs error = EINVAL; 2696164085Srrs sctp_free_hmaclist(hmaclist); 2697163953Srrs goto sctp_set_hmac_done; 2698163953Srrs } 2699163953Srrs } 2700170056Srrs found = 0; 2701170056Srrs for (i = 0; i < hmaclist->num_algo; i++) { 2702170056Srrs if (hmaclist->hmac[i] == SCTP_AUTH_HMAC_ID_SHA1) { 2703170056Srrs /* already in list */ 2704170056Srrs found = 1; 2705170056Srrs } 2706170056Srrs } 2707170056Srrs if (!found) { 2708170056Srrs sctp_free_hmaclist(hmaclist); 2709170056Srrs error = EINVAL; 2710170056Srrs break; 2711170056Srrs } 2712163953Srrs /* set it on the endpoint */ 2713163953Srrs SCTP_INP_WLOCK(inp); 2714163953Srrs if (inp->sctp_ep.local_hmacs) 2715163953Srrs sctp_free_hmaclist(inp->sctp_ep.local_hmacs); 2716163953Srrs inp->sctp_ep.local_hmacs = hmaclist; 2717163953Srrs SCTP_INP_WUNLOCK(inp); 2718163953Srrs sctp_set_hmac_done: 2719163953Srrs break; 2720163953Srrs } 2721163953Srrs case SCTP_AUTH_ACTIVE_KEY: 2722163953Srrs { 2723163953Srrs struct sctp_authkeyid *scact; 2724163953Srrs 2725166675Srrs SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize); 2726166675Srrs SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); 2727166675Srrs 2728163953Srrs /* set the active key on the right place */ 2729166675Srrs if (stcb) { 2730163953Srrs /* set the active key on the assoc */ 2731163953Srrs if (sctp_auth_setactivekey(stcb, scact->scact_keynumber)) 2732163953Srrs error = EINVAL; 2733163953Srrs SCTP_TCB_UNLOCK(stcb); 2734163953Srrs } else { 2735163953Srrs /* set the active key on the endpoint */ 2736163953Srrs SCTP_INP_WLOCK(inp); 2737163953Srrs if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) 2738163953Srrs error = EINVAL; 2739163953Srrs SCTP_INP_WUNLOCK(inp); 2740163953Srrs } 2741163953Srrs break; 2742163953Srrs } 2743163953Srrs case SCTP_AUTH_DELETE_KEY: 2744163953Srrs { 2745163953Srrs struct sctp_authkeyid *scdel; 2746163953Srrs 2747166675Srrs SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize); 2748166675Srrs SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id); 2749166675Srrs 2750163953Srrs /* delete the key from the right place */ 2751166675Srrs if (stcb) { 2752163953Srrs if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) 2753163953Srrs error = EINVAL; 2754163953Srrs SCTP_TCB_UNLOCK(stcb); 2755163953Srrs } else { 2756163953Srrs SCTP_INP_WLOCK(inp); 2757163953Srrs if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) 2758163953Srrs error = EINVAL; 2759163953Srrs SCTP_INP_WUNLOCK(inp); 2760163953Srrs } 2761163953Srrs break; 2762163953Srrs } 2763163953Srrs 2764163953Srrs case SCTP_RESET_STREAMS: 2765163953Srrs { 2766163953Srrs struct sctp_stream_reset *strrst; 2767163953Srrs uint8_t send_in = 0, send_tsn = 0, send_out = 0; 2768163953Srrs int i; 2769163953Srrs 2770166675Srrs SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_stream_reset, optsize); 2771166675Srrs SCTP_FIND_STCB(inp, stcb, strrst->strrst_assoc_id); 2772163953Srrs 2773163953Srrs if (stcb == NULL) { 2774163953Srrs error = ENOENT; 2775163953Srrs break; 2776163953Srrs } 2777163953Srrs if (stcb->asoc.peer_supports_strreset == 0) { 2778163953Srrs /* 2779163953Srrs * Peer does not support it, we return 2780163953Srrs * protocol not supported since this is true 2781163953Srrs * for this feature and this peer, not the 2782163953Srrs * socket request in general. 2783163953Srrs */ 2784163953Srrs error = EPROTONOSUPPORT; 2785163953Srrs SCTP_TCB_UNLOCK(stcb); 2786163953Srrs break; 2787163953Srrs } 2788163953Srrs if (stcb->asoc.stream_reset_outstanding) { 2789163953Srrs error = EALREADY; 2790163953Srrs SCTP_TCB_UNLOCK(stcb); 2791163953Srrs break; 2792163953Srrs } 2793163953Srrs if (strrst->strrst_flags == SCTP_RESET_LOCAL_RECV) { 2794163953Srrs send_in = 1; 2795163953Srrs } else if (strrst->strrst_flags == SCTP_RESET_LOCAL_SEND) { 2796163953Srrs send_out = 1; 2797163953Srrs } else if (strrst->strrst_flags == SCTP_RESET_BOTH) { 2798163953Srrs send_in = 1; 2799163953Srrs send_out = 1; 2800163953Srrs } else if (strrst->strrst_flags == SCTP_RESET_TSN) { 2801163953Srrs send_tsn = 1; 2802163953Srrs } else { 2803163953Srrs error = EINVAL; 2804163953Srrs SCTP_TCB_UNLOCK(stcb); 2805163953Srrs break; 2806163953Srrs } 2807163953Srrs for (i = 0; i < strrst->strrst_num_streams; i++) { 2808163953Srrs if ((send_in) && 2809163953Srrs 2810163953Srrs (strrst->strrst_list[i] > stcb->asoc.streamincnt)) { 2811163953Srrs error = EINVAL; 2812163953Srrs goto get_out; 2813163953Srrs } 2814163953Srrs if ((send_out) && 2815163953Srrs (strrst->strrst_list[i] > stcb->asoc.streamoutcnt)) { 2816163953Srrs error = EINVAL; 2817163953Srrs goto get_out; 2818163953Srrs } 2819163953Srrs } 2820163953Srrs if (error) { 2821163953Srrs get_out: 2822163953Srrs SCTP_TCB_UNLOCK(stcb); 2823163953Srrs break; 2824163953Srrs } 2825163953Srrs error = sctp_send_str_reset_req(stcb, strrst->strrst_num_streams, 2826163953Srrs strrst->strrst_list, 2827163953Srrs send_out, (stcb->asoc.str_reset_seq_in - 3), 2828163953Srrs send_in, send_tsn); 2829163953Srrs 2830163953Srrs sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ); 2831163953Srrs SCTP_TCB_UNLOCK(stcb); 2832163953Srrs } 2833163953Srrs break; 2834166675Srrs 2835163953Srrs case SCTP_CONNECT_X: 2836166675Srrs if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { 2837163953Srrs error = EINVAL; 2838163953Srrs break; 2839163953Srrs } 2840166675Srrs error = sctp_do_connect_x(so, inp, optval, optsize, p, 0); 2841163953Srrs break; 2842163953Srrs 2843163953Srrs case SCTP_CONNECT_X_DELAYED: 2844166675Srrs if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { 2845163953Srrs error = EINVAL; 2846163953Srrs break; 2847163953Srrs } 2848166675Srrs error = sctp_do_connect_x(so, inp, optval, optsize, p, 1); 2849163953Srrs break; 2850163953Srrs 2851163953Srrs case SCTP_CONNECT_X_COMPLETE: 2852163953Srrs { 2853163953Srrs struct sockaddr *sa; 2854163953Srrs struct sctp_nets *net; 2855163953Srrs 2856166675Srrs /* FIXME MT: check correct? */ 2857166675Srrs SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize); 2858166675Srrs 2859163953Srrs /* find tcb */ 2860163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 2861163953Srrs SCTP_INP_RLOCK(inp); 2862163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 2863163953Srrs if (stcb) { 2864163953Srrs SCTP_TCB_LOCK(stcb); 2865163953Srrs net = sctp_findnet(stcb, sa); 2866163953Srrs } 2867163953Srrs SCTP_INP_RUNLOCK(inp); 2868163953Srrs } else { 2869166675Srrs /* 2870166675Srrs * We increment here since 2871166675Srrs * sctp_findassociation_ep_addr() wil do a 2872166675Srrs * decrement if it finds the stcb as long as 2873166675Srrs * the locked tcb (last argument) is NOT a 2874166675Srrs * TCB.. aka NULL. 2875166675Srrs */ 2876163953Srrs SCTP_INP_INCR_REF(inp); 2877163953Srrs stcb = sctp_findassociation_ep_addr(&inp, sa, &net, NULL, NULL); 2878163953Srrs if (stcb == NULL) { 2879163953Srrs SCTP_INP_DECR_REF(inp); 2880163953Srrs } 2881163953Srrs } 2882163953Srrs 2883163953Srrs if (stcb == NULL) { 2884163953Srrs error = ENOENT; 2885163953Srrs break; 2886163953Srrs } 2887163953Srrs if (stcb->asoc.delayed_connection == 1) { 2888163953Srrs stcb->asoc.delayed_connection = 0; 2889169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 2890165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, 2891165220Srrs stcb->asoc.primary_destination, 2892165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9); 2893163953Srrs sctp_send_initiate(inp, stcb); 2894163953Srrs } else { 2895163953Srrs /* 2896163953Srrs * already expired or did not use delayed 2897163953Srrs * connectx 2898163953Srrs */ 2899163953Srrs error = EALREADY; 2900163953Srrs } 2901163953Srrs SCTP_TCB_UNLOCK(stcb); 2902163953Srrs } 2903163953Srrs break; 2904170056Srrs case SCTP_MAX_BURST: 2905163953Srrs { 2906163953Srrs uint8_t *burst; 2907163953Srrs 2908166675Srrs SCTP_CHECK_AND_CAST(burst, optval, uint8_t, optsize); 2909166675Srrs 2910163953Srrs SCTP_INP_WLOCK(inp); 2911163953Srrs if (*burst) { 2912163953Srrs inp->sctp_ep.max_burst = *burst; 2913163953Srrs } 2914163953Srrs SCTP_INP_WUNLOCK(inp); 2915163953Srrs } 2916163953Srrs break; 2917163953Srrs case SCTP_MAXSEG: 2918163953Srrs { 2919167598Srrs struct sctp_assoc_value *av; 2920163953Srrs int ovh; 2921163953Srrs 2922167598Srrs SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); 2923167598Srrs SCTP_FIND_STCB(inp, stcb, av->assoc_id); 2924166675Srrs 2925170056Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2926170056Srrs ovh = SCTP_MED_OVERHEAD; 2927170056Srrs } else { 2928170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 2929170056Srrs } 2930167598Srrs if (stcb) { 2931170056Srrs if (av->assoc_value) { 2932170056Srrs stcb->asoc.sctp_frag_point = (av->assoc_value + ovh); 2933170056Srrs } else { 2934170056Srrs stcb->asoc.sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; 2935170056Srrs } 2936167598Srrs SCTP_TCB_UNLOCK(stcb); 2937163953Srrs } else { 2938167598Srrs SCTP_INP_WLOCK(inp); 2939167598Srrs /* 2940167598Srrs * FIXME MT: I think this is not in tune 2941167598Srrs * with the API ID 2942167598Srrs */ 2943167598Srrs if (av->assoc_value) { 2944167598Srrs inp->sctp_frag_point = (av->assoc_value + ovh); 2945167598Srrs } else { 2946170056Srrs inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; 2947167598Srrs } 2948167598Srrs SCTP_INP_WUNLOCK(inp); 2949163953Srrs } 2950163953Srrs } 2951163953Srrs break; 2952163953Srrs case SCTP_EVENTS: 2953163953Srrs { 2954163953Srrs struct sctp_event_subscribe *events; 2955163953Srrs 2956166675Srrs SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize); 2957166675Srrs 2958163953Srrs SCTP_INP_WLOCK(inp); 2959163953Srrs if (events->sctp_data_io_event) { 2960163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); 2961163953Srrs } else { 2962163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); 2963163953Srrs } 2964163953Srrs 2965163953Srrs if (events->sctp_association_event) { 2966163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); 2967163953Srrs } else { 2968163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); 2969163953Srrs } 2970163953Srrs 2971163953Srrs if (events->sctp_address_event) { 2972163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); 2973163953Srrs } else { 2974163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); 2975163953Srrs } 2976163953Srrs 2977163953Srrs if (events->sctp_send_failure_event) { 2978163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 2979163953Srrs } else { 2980163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); 2981163953Srrs } 2982163953Srrs 2983163953Srrs if (events->sctp_peer_error_event) { 2984163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR); 2985163953Srrs } else { 2986163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR); 2987163953Srrs } 2988163953Srrs 2989163953Srrs if (events->sctp_shutdown_event) { 2990163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 2991163953Srrs } else { 2992163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); 2993163953Srrs } 2994163953Srrs 2995163953Srrs if (events->sctp_partial_delivery_event) { 2996163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT); 2997163953Srrs } else { 2998163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT); 2999163953Srrs } 3000163953Srrs 3001163953Srrs if (events->sctp_adaptation_layer_event) { 3002163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 3003163953Srrs } else { 3004163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); 3005163953Srrs } 3006163953Srrs 3007163953Srrs if (events->sctp_authentication_event) { 3008163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT); 3009163953Srrs } else { 3010163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT); 3011163953Srrs } 3012163953Srrs 3013163953Srrs if (events->sctp_stream_reset_events) { 3014163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 3015163953Srrs } else { 3016163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); 3017163953Srrs } 3018163953Srrs SCTP_INP_WUNLOCK(inp); 3019163953Srrs } 3020163953Srrs break; 3021163953Srrs 3022163953Srrs case SCTP_ADAPTATION_LAYER: 3023163953Srrs { 3024163953Srrs struct sctp_setadaptation *adap_bits; 3025163953Srrs 3026166675Srrs SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize); 3027163953Srrs SCTP_INP_WLOCK(inp); 3028163953Srrs inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind; 3029163953Srrs SCTP_INP_WUNLOCK(inp); 3030163953Srrs } 3031163953Srrs break; 3032166675Srrs#ifdef SCTP_DEBUG 3033163953Srrs case SCTP_SET_INITIAL_DBG_SEQ: 3034163953Srrs { 3035163953Srrs uint32_t *vvv; 3036163953Srrs 3037166675Srrs SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize); 3038163953Srrs SCTP_INP_WLOCK(inp); 3039163953Srrs inp->sctp_ep.initial_sequence_debug = *vvv; 3040163953Srrs SCTP_INP_WUNLOCK(inp); 3041163953Srrs } 3042163953Srrs break; 3043166675Srrs#endif 3044163953Srrs case SCTP_DEFAULT_SEND_PARAM: 3045163953Srrs { 3046163953Srrs struct sctp_sndrcvinfo *s_info; 3047163953Srrs 3048166675Srrs SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize); 3049166675Srrs SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); 3050163953Srrs 3051166675Srrs if (stcb) { 3052166675Srrs if (s_info->sinfo_stream <= stcb->asoc.streamoutcnt) { 3053170056Srrs memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send))); 3054163953Srrs } else { 3055166675Srrs error = EINVAL; 3056163953Srrs } 3057166675Srrs SCTP_TCB_UNLOCK(stcb); 3058166675Srrs } else { 3059166675Srrs SCTP_INP_WLOCK(inp); 3060170056Srrs memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send))); 3061166675Srrs SCTP_INP_WUNLOCK(inp); 3062163953Srrs } 3063163953Srrs } 3064163953Srrs break; 3065163953Srrs case SCTP_PEER_ADDR_PARAMS: 3066163953Srrs /* Applys to the specific association */ 3067163953Srrs { 3068163953Srrs struct sctp_paddrparams *paddrp; 3069163953Srrs struct sctp_nets *net; 3070163953Srrs 3071166675Srrs SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize); 3072166675Srrs SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); 3073163953Srrs net = NULL; 3074166675Srrs if (stcb) { 3075166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address); 3076166675Srrs } else { 3077166675Srrs /* 3078166675Srrs * We increment here since 3079166675Srrs * sctp_findassociation_ep_addr() wil do a 3080166675Srrs * decrement if it finds the stcb as long as 3081166675Srrs * the locked tcb (last argument) is NOT a 3082166675Srrs * TCB.. aka NULL. 3083166675Srrs */ 3084166675Srrs SCTP_INP_INCR_REF(inp); 3085166675Srrs stcb = sctp_findassociation_ep_addr(&inp, 3086166675Srrs (struct sockaddr *)&paddrp->spp_address, 3087166675Srrs &net, NULL, NULL); 3088163953Srrs if (stcb == NULL) { 3089166675Srrs SCTP_INP_DECR_REF(inp); 3090163953Srrs } 3091163953Srrs } 3092170056Srrs /* sanity checks */ 3093170056Srrs if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) { 3094170056Srrs if (stcb) 3095170056Srrs SCTP_TCB_UNLOCK(stcb); 3096170056Srrs return (EINVAL); 3097170056Srrs } 3098170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) { 3099170056Srrs if (stcb) 3100170056Srrs SCTP_TCB_UNLOCK(stcb); 3101170056Srrs return (EINVAL); 3102170056Srrs } 3103163953Srrs if (stcb) { 3104163953Srrs /************************TCB SPECIFIC SET ******************/ 3105163953Srrs /* 3106163953Srrs * do we change the timer for HB, we run 3107163953Srrs * only one? 3108163953Srrs */ 3109170056Srrs int ovh = 0; 3110170056Srrs 3111170056Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 3112170056Srrs ovh = SCTP_MED_OVERHEAD; 3113170056Srrs } else { 3114170056Srrs ovh = SCTP_MED_V4_OVERHEAD; 3115170056Srrs } 3116170056Srrs 3117163953Srrs if (paddrp->spp_hbinterval) 3118163953Srrs stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval; 3119163953Srrs else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) 3120163953Srrs stcb->asoc.heart_beat_delay = 0; 3121163953Srrs 3122163953Srrs /* network sets ? */ 3123163953Srrs if (net) { 3124163953Srrs /************************NET SPECIFIC SET ******************/ 3125163953Srrs if (paddrp->spp_flags & SPP_HB_DEMAND) { 3126163953Srrs /* on demand HB */ 3127169378Srrs (void)sctp_send_hb(stcb, 1, net); 3128163953Srrs } 3129163953Srrs if (paddrp->spp_flags & SPP_HB_DISABLE) { 3130163953Srrs net->dest_state |= SCTP_ADDR_NOHB; 3131163953Srrs } 3132163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 3133163953Srrs net->dest_state &= ~SCTP_ADDR_NOHB; 3134163953Srrs } 3135170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { 3136165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 3137165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 3138165220Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 3139163953Srrs } 3140163953Srrs if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) { 3141170056Srrs net->mtu = paddrp->spp_pathmtu + ovh; 3142169352Srrs if (net->mtu < stcb->asoc.smallest_mtu) { 3143169352Srrs#ifdef SCTP_PRINT_FOR_B_AND_M 3144169420Srrs SCTP_PRINTF("SCTP_PMTU_DISABLE calls sctp_pathmtu_adjustment:%d\n", 3145169352Srrs net->mtu); 3146169352Srrs#endif 3147167695Srrs sctp_pathmtu_adjustment(inp, stcb, net, net->mtu); 3148169352Srrs } 3149163953Srrs } 3150163953Srrs } 3151163953Srrs if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 3152165647Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 3153163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 3154163953Srrs } 3155163953Srrs } 3156163953Srrs if (paddrp->spp_pathmaxrxt) 3157163953Srrs net->failure_threshold = paddrp->spp_pathmaxrxt; 3158167598Srrs#ifdef INET 3159163953Srrs if (paddrp->spp_flags & SPP_IPV4_TOS) { 3160163953Srrs if (net->ro._l_addr.sin.sin_family == AF_INET) { 3161163953Srrs net->tos_flowlabel = paddrp->spp_ipv4_tos & 0x000000fc; 3162163953Srrs } 3163163953Srrs } 3164163953Srrs#endif 3165167598Srrs#ifdef INET6 3166163953Srrs if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { 3167163953Srrs if (net->ro._l_addr.sin6.sin6_family == AF_INET6) { 3168163953Srrs net->tos_flowlabel = paddrp->spp_ipv6_flowlabel; 3169163953Srrs } 3170163953Srrs } 3171163953Srrs#endif 3172163953Srrs } else { 3173163953Srrs /************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/ 3174163953Srrs if (paddrp->spp_pathmaxrxt) 3175163953Srrs stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt; 3176163953Srrs 3177163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 3178163953Srrs /* Turn back on the timer */ 3179163953Srrs stcb->asoc.hb_is_disabled = 0; 3180163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 3181163953Srrs } 3182170056Srrs if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { 3183170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3184170056Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 3185170056Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 3186170056Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); 3187170056Srrs } 3188170056Srrs if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) { 3189170056Srrs net->mtu = paddrp->spp_pathmtu + ovh; 3190170056Srrs if (net->mtu < stcb->asoc.smallest_mtu) { 3191170056Srrs#ifdef SCTP_PRINT_FOR_B_AND_M 3192170056Srrs SCTP_PRINTF("SCTP_PMTU_DISABLE calls sctp_pathmtu_adjustment:%d\n", 3193170056Srrs net->mtu); 3194170056Srrs#endif 3195170056Srrs sctp_pathmtu_adjustment(inp, stcb, net, net->mtu); 3196170056Srrs } 3197170056Srrs } 3198170056Srrs } 3199170056Srrs } 3200170056Srrs if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { 3201170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3202170056Srrs if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { 3203170056Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); 3204170056Srrs } 3205170056Srrs } 3206170056Srrs } 3207163953Srrs if (paddrp->spp_flags & SPP_HB_DISABLE) { 3208163953Srrs int cnt_of_unconf = 0; 3209163953Srrs struct sctp_nets *lnet; 3210163953Srrs 3211163953Srrs stcb->asoc.hb_is_disabled = 1; 3212163953Srrs TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 3213163953Srrs if (lnet->dest_state & SCTP_ADDR_UNCONFIRMED) { 3214163953Srrs cnt_of_unconf++; 3215163953Srrs } 3216163953Srrs } 3217163953Srrs /* 3218163953Srrs * stop the timer ONLY if we 3219163953Srrs * have no unconfirmed 3220163953Srrs * addresses 3221163953Srrs */ 3222163953Srrs if (cnt_of_unconf == 0) { 3223170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3224170056Srrs sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 3225170056Srrs SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11); 3226170056Srrs } 3227163953Srrs } 3228163953Srrs } 3229163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 3230163953Srrs /* start up the timer. */ 3231170056Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3232170056Srrs sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 3233170056Srrs } 3234163953Srrs } 3235167598Srrs#ifdef INET 3236163953Srrs if (paddrp->spp_flags & SPP_IPV4_TOS) 3237163953Srrs stcb->asoc.default_tos = paddrp->spp_ipv4_tos & 0x000000fc; 3238163953Srrs#endif 3239167598Srrs#ifdef INET6 3240163953Srrs if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) 3241163953Srrs stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel; 3242163953Srrs#endif 3243163953Srrs 3244163953Srrs } 3245163953Srrs SCTP_TCB_UNLOCK(stcb); 3246163953Srrs } else { 3247163953Srrs /************************NO TCB, SET TO default stuff ******************/ 3248163953Srrs SCTP_INP_WLOCK(inp); 3249163953Srrs /* 3250163953Srrs * For the TOS/FLOWLABEL stuff you set it 3251163953Srrs * with the options on the socket 3252163953Srrs */ 3253163953Srrs if (paddrp->spp_pathmaxrxt) { 3254163953Srrs inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt; 3255163953Srrs } 3256170056Srrs if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) 3257170056Srrs inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0; 3258170056Srrs else if (paddrp->spp_hbinterval) 3259170056Srrs inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval); 3260170056Srrs 3261163953Srrs if (paddrp->spp_flags & SPP_HB_ENABLE) { 3262163953Srrs sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 3263170056Srrs 3264163953Srrs } else if (paddrp->spp_flags & SPP_HB_DISABLE) { 3265163953Srrs sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); 3266163953Srrs } 3267163953Srrs SCTP_INP_WUNLOCK(inp); 3268163953Srrs } 3269163953Srrs } 3270163953Srrs break; 3271163953Srrs case SCTP_RTOINFO: 3272163953Srrs { 3273163953Srrs struct sctp_rtoinfo *srto; 3274169655Srrs uint32_t new_init, new_min, new_max; 3275163953Srrs 3276166675Srrs SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize); 3277166675Srrs SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); 3278166675Srrs 3279166675Srrs if (stcb) { 3280167598Srrs if (srto->srto_initial) 3281169655Srrs new_init = srto->srto_initial; 3282169655Srrs else 3283169655Srrs new_init = stcb->asoc.initial_rto; 3284167598Srrs if (srto->srto_max) 3285169655Srrs new_max = srto->srto_max; 3286169655Srrs else 3287169655Srrs new_max = stcb->asoc.maxrto; 3288167598Srrs if (srto->srto_min) 3289169655Srrs new_min = srto->srto_min; 3290169655Srrs else 3291169655Srrs new_min = stcb->asoc.minrto; 3292169655Srrs if ((new_min <= new_init) && (new_init <= new_max)) { 3293169655Srrs stcb->asoc.initial_rto = new_init; 3294169655Srrs stcb->asoc.maxrto = new_max; 3295169655Srrs stcb->asoc.minrto = new_min; 3296169655Srrs } else { 3297169655Srrs error = EDOM; 3298169655Srrs } 3299166675Srrs SCTP_TCB_UNLOCK(stcb); 3300166675Srrs } else { 3301163953Srrs SCTP_INP_WLOCK(inp); 3302167598Srrs if (srto->srto_initial) 3303169655Srrs new_init = srto->srto_initial; 3304169655Srrs else 3305169655Srrs new_init = inp->sctp_ep.initial_rto; 3306167598Srrs if (srto->srto_max) 3307169655Srrs new_max = srto->srto_max; 3308169655Srrs else 3309169655Srrs new_max = inp->sctp_ep.sctp_maxrto; 3310167598Srrs if (srto->srto_min) 3311169655Srrs new_min = srto->srto_min; 3312169655Srrs else 3313169655Srrs new_min = inp->sctp_ep.sctp_minrto; 3314169655Srrs if ((new_min <= new_init) && (new_init <= new_max)) { 3315169655Srrs inp->sctp_ep.initial_rto = new_init; 3316169655Srrs inp->sctp_ep.sctp_maxrto = new_max; 3317169655Srrs inp->sctp_ep.sctp_minrto = new_min; 3318169655Srrs } else { 3319169655Srrs error = EDOM; 3320169655Srrs } 3321163953Srrs SCTP_INP_WUNLOCK(inp); 3322163953Srrs } 3323163953Srrs } 3324163953Srrs break; 3325163953Srrs case SCTP_ASSOCINFO: 3326163953Srrs { 3327163953Srrs struct sctp_assocparams *sasoc; 3328163953Srrs 3329166675Srrs SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize); 3330166675Srrs SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); 3331166675Srrs 3332163953Srrs if (stcb) { 3333163953Srrs if (sasoc->sasoc_asocmaxrxt) 3334163953Srrs stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt; 3335163953Srrs sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets; 3336163953Srrs sasoc->sasoc_peer_rwnd = 0; 3337163953Srrs sasoc->sasoc_local_rwnd = 0; 3338170056Srrs if (sasoc->sasoc_cookie_life) { 3339170056Srrs if (sasoc->sasoc_cookie_life < 1000) 3340170056Srrs sasoc->sasoc_cookie_life = 1000; 3341169655Srrs stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); 3342167598Srrs } 3343163953Srrs SCTP_TCB_UNLOCK(stcb); 3344163953Srrs } else { 3345163953Srrs SCTP_INP_WLOCK(inp); 3346163953Srrs if (sasoc->sasoc_asocmaxrxt) 3347163953Srrs inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt; 3348163953Srrs sasoc->sasoc_number_peer_destinations = 0; 3349163953Srrs sasoc->sasoc_peer_rwnd = 0; 3350163953Srrs sasoc->sasoc_local_rwnd = 0; 3351170056Srrs if (sasoc->sasoc_cookie_life) { 3352170056Srrs if (sasoc->sasoc_cookie_life < 1000) 3353170056Srrs sasoc->sasoc_cookie_life = 1000; 3354169655Srrs inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); 3355167598Srrs } 3356163953Srrs SCTP_INP_WUNLOCK(inp); 3357163953Srrs } 3358163953Srrs } 3359163953Srrs break; 3360163953Srrs case SCTP_INITMSG: 3361163953Srrs { 3362163953Srrs struct sctp_initmsg *sinit; 3363163953Srrs 3364166675Srrs SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize); 3365163953Srrs SCTP_INP_WLOCK(inp); 3366163953Srrs if (sinit->sinit_num_ostreams) 3367163953Srrs inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams; 3368163953Srrs 3369163953Srrs if (sinit->sinit_max_instreams) 3370163953Srrs inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams; 3371163953Srrs 3372163953Srrs if (sinit->sinit_max_attempts) 3373163953Srrs inp->sctp_ep.max_init_times = sinit->sinit_max_attempts; 3374163953Srrs 3375167598Srrs if (sinit->sinit_max_init_timeo) 3376163953Srrs inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo; 3377163953Srrs SCTP_INP_WUNLOCK(inp); 3378163953Srrs } 3379163953Srrs break; 3380163953Srrs case SCTP_PRIMARY_ADDR: 3381163953Srrs { 3382163953Srrs struct sctp_setprim *spa; 3383163953Srrs struct sctp_nets *net, *lnet; 3384163953Srrs 3385166675Srrs SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize); 3386166675Srrs SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id); 3387163953Srrs 3388166675Srrs net = NULL; 3389166675Srrs if (stcb) { 3390166675Srrs net = sctp_findnet(stcb, (struct sockaddr *)&spa->ssp_addr); 3391166675Srrs } else { 3392166675Srrs /* 3393166675Srrs * We increment here since 3394166675Srrs * sctp_findassociation_ep_addr() wil do a 3395166675Srrs * decrement if it finds the stcb as long as 3396166675Srrs * the locked tcb (last argument) is NOT a 3397166675Srrs * TCB.. aka NULL. 3398166675Srrs */ 3399163953Srrs SCTP_INP_INCR_REF(inp); 3400163953Srrs stcb = sctp_findassociation_ep_addr(&inp, 3401163953Srrs (struct sockaddr *)&spa->ssp_addr, 3402163953Srrs &net, NULL, NULL); 3403163953Srrs if (stcb == NULL) { 3404163953Srrs SCTP_INP_DECR_REF(inp); 3405163953Srrs } 3406163953Srrs } 3407166675Srrs 3408166675Srrs if ((stcb) && (net)) { 3409166675Srrs if ((net != stcb->asoc.primary_destination) && 3410166675Srrs (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) { 3411166675Srrs /* Ok we need to set it */ 3412166675Srrs lnet = stcb->asoc.primary_destination; 3413166675Srrs if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) { 3414166675Srrs if (net->dest_state & SCTP_ADDR_SWITCH_PRIMARY) { 3415166675Srrs net->dest_state |= SCTP_ADDR_DOUBLE_SWITCH; 3416166675Srrs } 3417166675Srrs net->dest_state |= SCTP_ADDR_SWITCH_PRIMARY; 3418163953Srrs } 3419163953Srrs } 3420166675Srrs } else { 3421166675Srrs error = EINVAL; 3422163953Srrs } 3423166675Srrs if (stcb) { 3424166675Srrs SCTP_TCB_UNLOCK(stcb); 3425166675Srrs } 3426163953Srrs } 3427163953Srrs break; 3428167598Srrs case SCTP_SET_DYNAMIC_PRIMARY: 3429167598Srrs { 3430167598Srrs union sctp_sockstore *ss; 3431163953Srrs 3432170587Srwatson error = priv_check(curthread, 3433170587Srwatson PRIV_NETINET_RESERVEDPORT); 3434167598Srrs if (error) 3435167598Srrs break; 3436167598Srrs 3437167598Srrs SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize); 3438167598Srrs /* SUPER USER CHECK? */ 3439167598Srrs error = sctp_dynamic_set_primary(&ss->sa, vrf_id); 3440167598Srrs } 3441167598Srrs break; 3442163953Srrs case SCTP_SET_PEER_PRIMARY_ADDR: 3443163953Srrs { 3444163953Srrs struct sctp_setpeerprim *sspp; 3445163953Srrs 3446166675Srrs SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize); 3447166675Srrs SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id); 3448169208Srrs if (stcb != NULL) { 3449170056Srrs struct sctp_ifa *ifa; 3450170056Srrs 3451170056Srrs ifa = sctp_find_ifa_by_addr((struct sockaddr *)&sspp->sspp_addr, 3452170056Srrs stcb->asoc.vrf_id, 0); 3453170056Srrs if (ifa == NULL) { 3454166675Srrs error = EINVAL; 3455170056Srrs goto out_of_it; 3456166675Srrs } 3457170056Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { 3458170056Srrs /* 3459170056Srrs * Must validate the ifa found is in 3460170056Srrs * our ep 3461170056Srrs */ 3462170056Srrs struct sctp_laddr *laddr; 3463170056Srrs int found = 0; 3464170056Srrs 3465170056Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 3466170056Srrs if (laddr->ifa == NULL) { 3467170056Srrs SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n", 3468170056Srrs __FUNCTION__); 3469170056Srrs continue; 3470170056Srrs } 3471170056Srrs if (laddr->ifa == ifa) { 3472170056Srrs found = 1; 3473170056Srrs break; 3474170056Srrs } 3475170056Srrs } 3476170056Srrs if (!found) { 3477170056Srrs error = EINVAL; 3478170056Srrs goto out_of_it; 3479170056Srrs } 3480170056Srrs } 3481170056Srrs if (sctp_set_primary_ip_address_sa(stcb, 3482170056Srrs (struct sockaddr *)&sspp->sspp_addr) != 0) { 3483170056Srrs error = EINVAL; 3484170056Srrs } 3485170056Srrs out_of_it: 3486169208Srrs SCTP_TCB_UNLOCK(stcb); 3487166675Srrs } else { 3488163953Srrs error = EINVAL; 3489163953Srrs } 3490169208Srrs 3491163953Srrs } 3492163953Srrs break; 3493163953Srrs case SCTP_BINDX_ADD_ADDR: 3494163953Srrs { 3495163953Srrs struct sctp_getaddresses *addrs; 3496163953Srrs 3497170606Srrs SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, 3498170606Srrs optsize); 3499170606Srrs sctp_bindx_add_address(so, inp, addrs->addr, 3500170606Srrs addrs->sget_assoc_id, vrf_id, 3501170606Srrs &error, p); 3502163953Srrs } 3503163953Srrs break; 3504163953Srrs case SCTP_BINDX_REM_ADDR: 3505163953Srrs { 3506163953Srrs struct sctp_getaddresses *addrs; 3507163953Srrs 3508166675Srrs SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize); 3509170606Srrs sctp_bindx_delete_address(so, inp, addrs->addr, 3510170606Srrs addrs->sget_assoc_id, vrf_id, 3511170606Srrs &error); 3512163953Srrs } 3513163953Srrs break; 3514163953Srrs default: 3515163953Srrs error = ENOPROTOOPT; 3516163953Srrs break; 3517163953Srrs } /* end switch (opt) */ 3518163953Srrs return (error); 3519163953Srrs} 3520163953Srrs 3521163953Srrs 3522163953Srrsint 3523163953Srrssctp_ctloutput(struct socket *so, struct sockopt *sopt) 3524163953Srrs{ 3525166675Srrs void *optval = NULL; 3526166675Srrs size_t optsize = 0; 3527163953Srrs struct sctp_inpcb *inp; 3528166675Srrs void *p; 3529166675Srrs int error = 0; 3530163953Srrs 3531163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3532163953Srrs if (inp == 0) { 3533163953Srrs /* I made the same as TCP since we are not setup? */ 3534163953Srrs return (ECONNRESET); 3535163953Srrs } 3536163953Srrs if (sopt->sopt_level != IPPROTO_SCTP) { 3537163953Srrs /* wrong proto level... send back up to IP */ 3538163953Srrs#ifdef INET6 3539163953Srrs if (INP_CHECK_SOCKAF(so, AF_INET6)) 3540163953Srrs error = ip6_ctloutput(so, sopt); 3541163953Srrs else 3542163953Srrs#endif /* INET6 */ 3543163953Srrs error = ip_ctloutput(so, sopt); 3544163953Srrs return (error); 3545163953Srrs } 3546166675Srrs optsize = sopt->sopt_valsize; 3547166675Srrs if (optsize) { 3548170091Srrs SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT); 3549166675Srrs if (optval == NULL) { 3550163953Srrs return (ENOBUFS); 3551163953Srrs } 3552166675Srrs error = sooptcopyin(sopt, optval, optsize, optsize); 3553163953Srrs if (error) { 3554170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 3555163953Srrs goto out; 3556163953Srrs } 3557163953Srrs } 3558166675Srrs p = (void *)sopt->sopt_td; 3559163953Srrs if (sopt->sopt_dir == SOPT_SET) { 3560166675Srrs error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p); 3561163953Srrs } else if (sopt->sopt_dir == SOPT_GET) { 3562166675Srrs error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p); 3563163953Srrs } else { 3564163953Srrs error = EINVAL; 3565163953Srrs } 3566166675Srrs if ((error == 0) && (optval != NULL)) { 3567166675Srrs error = sooptcopyout(sopt, optval, optsize); 3568170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 3569166675Srrs } else if (optval != NULL) { 3570170091Srrs SCTP_FREE(optval, SCTP_M_SOCKOPT); 3571163953Srrs } 3572163953Srrsout: 3573163953Srrs return (error); 3574163953Srrs} 3575163953Srrs 3576163953Srrs 3577163953Srrsstatic int 3578163953Srrssctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p) 3579163953Srrs{ 3580163953Srrs int error = 0; 3581163953Srrs int create_lock_on = 0; 3582167598Srrs uint32_t vrf_id; 3583163953Srrs struct sctp_inpcb *inp; 3584163953Srrs struct sctp_tcb *stcb = NULL; 3585163953Srrs 3586163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3587163953Srrs if (inp == 0) { 3588163953Srrs /* I made the same as TCP since we are not setup? */ 3589163953Srrs return (ECONNRESET); 3590163953Srrs } 3591170056Srrs if (addr == NULL) 3592170056Srrs return EINVAL; 3593170056Srrs 3594170056Srrs if ((addr->sa_family == AF_INET6) && (addr->sa_len != sizeof(struct sockaddr_in6))) { 3595170056Srrs return (EINVAL); 3596170056Srrs } 3597170056Srrs if ((addr->sa_family == AF_INET) && (addr->sa_len != sizeof(struct sockaddr_in))) { 3598170056Srrs return (EINVAL); 3599170056Srrs } 3600163953Srrs SCTP_ASOC_CREATE_LOCK(inp); 3601163953Srrs create_lock_on = 1; 3602163953Srrs 3603163953Srrs SCTP_INP_INCR_REF(inp); 3604163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 3605163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 3606163953Srrs /* Should I really unlock ? */ 3607163953Srrs error = EFAULT; 3608163953Srrs goto out_now; 3609163953Srrs } 3610163953Srrs#ifdef INET6 3611163953Srrs if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && 3612163953Srrs (addr->sa_family == AF_INET6)) { 3613163953Srrs error = EINVAL; 3614163953Srrs goto out_now; 3615163953Srrs } 3616163953Srrs#endif /* INET6 */ 3617163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 3618163953Srrs SCTP_PCB_FLAGS_UNBOUND) { 3619163953Srrs /* Bind a ephemeral port */ 3620170744Srrs error = sctp_inpcb_bind(so, NULL, NULL, p); 3621163953Srrs if (error) { 3622163953Srrs goto out_now; 3623163953Srrs } 3624163953Srrs } 3625163953Srrs /* Now do we connect? */ 3626163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) { 3627163953Srrs error = EINVAL; 3628163953Srrs goto out_now; 3629163953Srrs } 3630163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 3631163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 3632163953Srrs /* We are already connected AND the TCP model */ 3633163953Srrs error = EADDRINUSE; 3634163953Srrs goto out_now; 3635163953Srrs } 3636163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 3637163953Srrs SCTP_INP_RLOCK(inp); 3638163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 3639163953Srrs SCTP_INP_RUNLOCK(inp); 3640163953Srrs } else { 3641163953Srrs /* 3642166675Srrs * We increment here since sctp_findassociation_ep_addr() 3643166675Srrs * wil do a decrement if it finds the stcb as long as the 3644166675Srrs * locked tcb (last argument) is NOT a TCB.. aka NULL. 3645163953Srrs */ 3646163953Srrs SCTP_INP_INCR_REF(inp); 3647163953Srrs stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL); 3648163953Srrs if (stcb == NULL) { 3649163953Srrs SCTP_INP_DECR_REF(inp); 3650168299Srrs } else { 3651168299Srrs SCTP_TCB_LOCK(stcb); 3652163953Srrs } 3653163953Srrs } 3654163953Srrs if (stcb != NULL) { 3655163953Srrs /* Already have or am bring up an association */ 3656163953Srrs error = EALREADY; 3657163953Srrs goto out_now; 3658163953Srrs } 3659168299Srrs vrf_id = inp->def_vrf_id; 3660163953Srrs /* We are GOOD to go */ 3661167598Srrs stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0, vrf_id); 3662163953Srrs if (stcb == NULL) { 3663163953Srrs /* Gak! no memory */ 3664167598Srrs goto out_now; 3665163953Srrs } 3666163953Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 3667163953Srrs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 3668163953Srrs /* Set the connected flag so we can queue data */ 3669163953Srrs soisconnecting(so); 3670163953Srrs } 3671163953Srrs stcb->asoc.state = SCTP_STATE_COOKIE_WAIT; 3672169378Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 3673163953Srrs 3674163953Srrs /* initialize authentication parameters for the assoc */ 3675163953Srrs sctp_initialize_auth_params(inp, stcb); 3676163953Srrs 3677163953Srrs sctp_send_initiate(inp, stcb); 3678168299Srrs SCTP_TCB_UNLOCK(stcb); 3679163953Srrsout_now: 3680169420Srrs if (create_lock_on) { 3681163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 3682169420Srrs } 3683163953Srrs SCTP_INP_DECR_REF(inp); 3684163953Srrs return error; 3685163953Srrs} 3686163953Srrs 3687163953Srrsint 3688163953Srrssctp_listen(struct socket *so, int backlog, struct thread *p) 3689163953Srrs{ 3690163953Srrs /* 3691163953Srrs * Note this module depends on the protocol processing being called 3692163953Srrs * AFTER any socket level flags and backlog are applied to the 3693163953Srrs * socket. The traditional way that the socket flags are applied is 3694163953Srrs * AFTER protocol processing. We have made a change to the 3695163953Srrs * sys/kern/uipc_socket.c module to reverse this but this MUST be in 3696163953Srrs * place if the socket API for SCTP is to work properly. 3697163953Srrs */ 3698163953Srrs 3699163953Srrs int error = 0; 3700163953Srrs struct sctp_inpcb *inp; 3701163953Srrs 3702163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3703163953Srrs if (inp == 0) { 3704163953Srrs /* I made the same as TCP since we are not setup? */ 3705163953Srrs return (ECONNRESET); 3706163953Srrs } 3707163953Srrs SCTP_INP_RLOCK(inp); 3708163953Srrs#ifdef SCTP_LOCK_LOGGING 3709170744Srrs if (sctp_logging_level & SCTP_LOCK_LOGGING_ENABLE) { 3710170744Srrs sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK); 3711170744Srrs } 3712163953Srrs#endif 3713163953Srrs SOCK_LOCK(so); 3714163953Srrs error = solisten_proto_check(so); 3715163953Srrs if (error) { 3716163953Srrs SOCK_UNLOCK(so); 3717169208Srrs SCTP_INP_RUNLOCK(inp); 3718163953Srrs return (error); 3719163953Srrs } 3720163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 3721163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 3722163953Srrs /* We are already connected AND the TCP model */ 3723163953Srrs SCTP_INP_RUNLOCK(inp); 3724163953Srrs SOCK_UNLOCK(so); 3725163953Srrs return (EADDRINUSE); 3726163953Srrs } 3727163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { 3728163953Srrs /* We must do a bind. */ 3729166675Srrs SOCK_UNLOCK(so); 3730163953Srrs SCTP_INP_RUNLOCK(inp); 3731170744Srrs if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) { 3732163953Srrs /* bind error, probably perm */ 3733163953Srrs return (error); 3734163953Srrs } 3735166675Srrs SOCK_LOCK(so); 3736163953Srrs } else { 3737163953Srrs SCTP_INP_RUNLOCK(inp); 3738163953Srrs } 3739163953Srrs /* It appears for 7.0 and on, we must always call this. */ 3740163953Srrs solisten_proto(so, backlog); 3741163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 3742163953Srrs /* remove the ACCEPTCONN flag for one-to-many sockets */ 3743163953Srrs so->so_options &= ~SO_ACCEPTCONN; 3744163953Srrs } 3745163953Srrs if (backlog == 0) { 3746163953Srrs /* turning off listen */ 3747163953Srrs so->so_options &= ~SO_ACCEPTCONN; 3748163953Srrs } 3749163953Srrs SOCK_UNLOCK(so); 3750163953Srrs return (error); 3751163953Srrs} 3752163953Srrs 3753163953Srrsstatic int sctp_defered_wakeup_cnt = 0; 3754163953Srrs 3755163953Srrsint 3756163953Srrssctp_accept(struct socket *so, struct sockaddr **addr) 3757163953Srrs{ 3758163953Srrs struct sctp_tcb *stcb; 3759163953Srrs struct sctp_inpcb *inp; 3760163953Srrs union sctp_sockstore store; 3761163953Srrs 3762163953Srrs int error; 3763163953Srrs 3764163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3765163953Srrs 3766163953Srrs if (inp == 0) { 3767163953Srrs return (ECONNRESET); 3768163953Srrs } 3769163953Srrs SCTP_INP_RLOCK(inp); 3770163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { 3771168299Srrs SCTP_INP_RUNLOCK(inp); 3772163953Srrs return (ENOTSUP); 3773163953Srrs } 3774163953Srrs if (so->so_state & SS_ISDISCONNECTED) { 3775163953Srrs SCTP_INP_RUNLOCK(inp); 3776163953Srrs return (ECONNABORTED); 3777163953Srrs } 3778163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 3779163953Srrs if (stcb == NULL) { 3780163953Srrs SCTP_INP_RUNLOCK(inp); 3781163953Srrs return (ECONNRESET); 3782163953Srrs } 3783163953Srrs SCTP_TCB_LOCK(stcb); 3784163953Srrs SCTP_INP_RUNLOCK(inp); 3785163953Srrs store = stcb->asoc.primary_destination->ro._l_addr; 3786163953Srrs SCTP_TCB_UNLOCK(stcb); 3787163953Srrs if (store.sa.sa_family == AF_INET) { 3788163953Srrs struct sockaddr_in *sin; 3789163953Srrs 3790163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 3791163953Srrs sin->sin_family = AF_INET; 3792163953Srrs sin->sin_len = sizeof(*sin); 3793163953Srrs sin->sin_port = ((struct sockaddr_in *)&store)->sin_port; 3794163953Srrs sin->sin_addr = ((struct sockaddr_in *)&store)->sin_addr; 3795163953Srrs *addr = (struct sockaddr *)sin; 3796163953Srrs } else { 3797163953Srrs struct sockaddr_in6 *sin6; 3798163953Srrs 3799163953Srrs SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); 3800163953Srrs sin6->sin6_family = AF_INET6; 3801163953Srrs sin6->sin6_len = sizeof(*sin6); 3802163953Srrs sin6->sin6_port = ((struct sockaddr_in6 *)&store)->sin6_port; 3803163953Srrs 3804163953Srrs sin6->sin6_addr = ((struct sockaddr_in6 *)&store)->sin6_addr; 3805164085Srrs if ((error = sa6_recoverscope(sin6)) != 0) { 3806164085Srrs SCTP_FREE_SONAME(sin6); 3807163953Srrs return (error); 3808164085Srrs } 3809163953Srrs *addr = (struct sockaddr *)sin6; 3810163953Srrs } 3811163953Srrs /* Wake any delayed sleep action */ 3812163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { 3813166086Srrs SCTP_INP_WLOCK(inp); 3814163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE; 3815163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) { 3816163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT; 3817166086Srrs SCTP_INP_WUNLOCK(inp); 3818163953Srrs SOCKBUF_LOCK(&inp->sctp_socket->so_snd); 3819163953Srrs if (sowriteable(inp->sctp_socket)) { 3820163953Srrs sowwakeup_locked(inp->sctp_socket); 3821163953Srrs } else { 3822163953Srrs SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd); 3823163953Srrs } 3824166086Srrs SCTP_INP_WLOCK(inp); 3825163953Srrs } 3826163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) { 3827163953Srrs inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT; 3828166086Srrs SCTP_INP_WUNLOCK(inp); 3829163953Srrs SOCKBUF_LOCK(&inp->sctp_socket->so_rcv); 3830163953Srrs if (soreadable(inp->sctp_socket)) { 3831163953Srrs sctp_defered_wakeup_cnt++; 3832163953Srrs sorwakeup_locked(inp->sctp_socket); 3833163953Srrs } else { 3834163953Srrs SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv); 3835163953Srrs } 3836166086Srrs SCTP_INP_WLOCK(inp); 3837163953Srrs } 3838166086Srrs SCTP_INP_WUNLOCK(inp); 3839163953Srrs } 3840163953Srrs return (0); 3841163953Srrs} 3842163953Srrs 3843163953Srrsint 3844163953Srrssctp_ingetaddr(struct socket *so, struct sockaddr **addr) 3845163953Srrs{ 3846163953Srrs struct sockaddr_in *sin; 3847167598Srrs uint32_t vrf_id; 3848163953Srrs struct sctp_inpcb *inp; 3849167695Srrs struct sctp_ifa *sctp_ifa; 3850163953Srrs 3851163953Srrs /* 3852163953Srrs * Do the malloc first in case it blocks. 3853163953Srrs */ 3854163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 3855163953Srrs sin->sin_family = AF_INET; 3856163953Srrs sin->sin_len = sizeof(*sin); 3857163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3858163953Srrs if (!inp) { 3859163953Srrs SCTP_FREE_SONAME(sin); 3860163953Srrs return ECONNRESET; 3861163953Srrs } 3862163953Srrs SCTP_INP_RLOCK(inp); 3863163953Srrs sin->sin_port = inp->sctp_lport; 3864163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 3865163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 3866163953Srrs struct sctp_tcb *stcb; 3867163953Srrs struct sockaddr_in *sin_a; 3868163953Srrs struct sctp_nets *net; 3869163953Srrs int fnd; 3870163953Srrs 3871163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 3872163953Srrs if (stcb == NULL) { 3873163953Srrs goto notConn; 3874163953Srrs } 3875163953Srrs fnd = 0; 3876163953Srrs sin_a = NULL; 3877163953Srrs SCTP_TCB_LOCK(stcb); 3878163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3879163953Srrs sin_a = (struct sockaddr_in *)&net->ro._l_addr; 3880164085Srrs if (sin_a == NULL) 3881164085Srrs /* this will make coverity happy */ 3882164085Srrs continue; 3883164085Srrs 3884163953Srrs if (sin_a->sin_family == AF_INET) { 3885163953Srrs fnd = 1; 3886163953Srrs break; 3887163953Srrs } 3888163953Srrs } 3889163953Srrs if ((!fnd) || (sin_a == NULL)) { 3890163953Srrs /* punt */ 3891163953Srrs SCTP_TCB_UNLOCK(stcb); 3892163953Srrs goto notConn; 3893163953Srrs } 3894168299Srrs vrf_id = inp->def_vrf_id; 3895167598Srrs sctp_ifa = sctp_source_address_selection(inp, 3896167598Srrs stcb, 3897168299Srrs (sctp_route_t *) & net->ro, 3898167598Srrs net, 0, vrf_id); 3899167598Srrs if (sctp_ifa) { 3900167598Srrs sin->sin_addr = sctp_ifa->address.sin.sin_addr; 3901167598Srrs sctp_free_ifa(sctp_ifa); 3902167598Srrs } 3903163953Srrs SCTP_TCB_UNLOCK(stcb); 3904163953Srrs } else { 3905163953Srrs /* For the bound all case you get back 0 */ 3906163953Srrs notConn: 3907163953Srrs sin->sin_addr.s_addr = 0; 3908163953Srrs } 3909163953Srrs 3910163953Srrs } else { 3911163953Srrs /* Take the first IPv4 address in the list */ 3912163953Srrs struct sctp_laddr *laddr; 3913163953Srrs int fnd = 0; 3914163953Srrs 3915163953Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 3916167598Srrs if (laddr->ifa->address.sa.sa_family == AF_INET) { 3917163953Srrs struct sockaddr_in *sin_a; 3918163953Srrs 3919167598Srrs sin_a = (struct sockaddr_in *)&laddr->ifa->address.sa; 3920163953Srrs sin->sin_addr = sin_a->sin_addr; 3921163953Srrs fnd = 1; 3922163953Srrs break; 3923163953Srrs } 3924163953Srrs } 3925163953Srrs if (!fnd) { 3926163953Srrs SCTP_FREE_SONAME(sin); 3927163953Srrs SCTP_INP_RUNLOCK(inp); 3928163953Srrs return ENOENT; 3929163953Srrs } 3930163953Srrs } 3931163953Srrs SCTP_INP_RUNLOCK(inp); 3932163953Srrs (*addr) = (struct sockaddr *)sin; 3933163953Srrs return (0); 3934163953Srrs} 3935163953Srrs 3936163953Srrsint 3937163953Srrssctp_peeraddr(struct socket *so, struct sockaddr **addr) 3938163953Srrs{ 3939163953Srrs struct sockaddr_in *sin = (struct sockaddr_in *)*addr; 3940166086Srrs int fnd; 3941163953Srrs struct sockaddr_in *sin_a; 3942163953Srrs struct sctp_inpcb *inp; 3943163953Srrs struct sctp_tcb *stcb; 3944163953Srrs struct sctp_nets *net; 3945163953Srrs 3946163953Srrs /* Do the malloc first in case it blocks. */ 3947163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3948163953Srrs if ((inp == NULL) || 3949163953Srrs ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { 3950163953Srrs /* UDP type and listeners will drop out here */ 3951163953Srrs return (ENOTCONN); 3952163953Srrs } 3953163953Srrs SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); 3954163953Srrs sin->sin_family = AF_INET; 3955163953Srrs sin->sin_len = sizeof(*sin); 3956163953Srrs 3957163953Srrs /* We must recapture incase we blocked */ 3958163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 3959163953Srrs if (!inp) { 3960163953Srrs SCTP_FREE_SONAME(sin); 3961163953Srrs return ECONNRESET; 3962163953Srrs } 3963163953Srrs SCTP_INP_RLOCK(inp); 3964163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 3965169420Srrs if (stcb) { 3966163953Srrs SCTP_TCB_LOCK(stcb); 3967169420Srrs } 3968163953Srrs SCTP_INP_RUNLOCK(inp); 3969163953Srrs if (stcb == NULL) { 3970163953Srrs SCTP_FREE_SONAME(sin); 3971163953Srrs return ECONNRESET; 3972163953Srrs } 3973163953Srrs fnd = 0; 3974163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 3975163953Srrs sin_a = (struct sockaddr_in *)&net->ro._l_addr; 3976163953Srrs if (sin_a->sin_family == AF_INET) { 3977163953Srrs fnd = 1; 3978163953Srrs sin->sin_port = stcb->rport; 3979163953Srrs sin->sin_addr = sin_a->sin_addr; 3980163953Srrs break; 3981163953Srrs } 3982163953Srrs } 3983163953Srrs SCTP_TCB_UNLOCK(stcb); 3984163953Srrs if (!fnd) { 3985163953Srrs /* No IPv4 address */ 3986163953Srrs SCTP_FREE_SONAME(sin); 3987163953Srrs return ENOENT; 3988163953Srrs } 3989163953Srrs (*addr) = (struct sockaddr *)sin; 3990163953Srrs return (0); 3991163953Srrs} 3992163953Srrs 3993163953Srrsstruct pr_usrreqs sctp_usrreqs = { 3994163953Srrs .pru_abort = sctp_abort, 3995163953Srrs .pru_accept = sctp_accept, 3996163953Srrs .pru_attach = sctp_attach, 3997163953Srrs .pru_bind = sctp_bind, 3998163953Srrs .pru_connect = sctp_connect, 3999163953Srrs .pru_control = in_control, 4000163953Srrs .pru_close = sctp_close, 4001163953Srrs .pru_detach = sctp_close, 4002163953Srrs .pru_sopoll = sopoll_generic, 4003163953Srrs .pru_disconnect = sctp_disconnect, 4004163953Srrs .pru_listen = sctp_listen, 4005163953Srrs .pru_peeraddr = sctp_peeraddr, 4006163953Srrs .pru_send = sctp_sendm, 4007163953Srrs .pru_shutdown = sctp_shutdown, 4008163953Srrs .pru_sockaddr = sctp_ingetaddr, 4009163953Srrs .pru_sosend = sctp_sosend, 4010163953Srrs .pru_soreceive = sctp_soreceive 4011163953Srrs}; 4012