sctp6_usrreq.c revision 185694
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/* $KAME: sctp6_usrreq.c,v 1.38 2005/08/24 08:08:56 suz Exp $ */ 31174510Sobrien 32163954Srrs#include <sys/cdefs.h> 33163953Srrs__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_usrreq.c 185694 2008-12-06 13:19:54Z rrs $"); 34163953Srrs 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> 40168709Srrs#if defined(INET6) 41168709Srrs#include <netinet6/sctp6_var.h> 42168709Srrs#endif 43167598Srrs#include <netinet/sctp_sysctl.h> 44163953Srrs#include <netinet/sctp_output.h> 45166086Srrs#include <netinet/sctp_uio.h> 46163953Srrs#include <netinet/sctp_asconf.h> 47166086Srrs#include <netinet/sctputil.h> 48166086Srrs#include <netinet/sctp_indata.h> 49166086Srrs#include <netinet/sctp_timer.h> 50166086Srrs#include <netinet/sctp_auth.h> 51168709Srrs#include <netinet/sctp_input.h> 52168709Srrs#include <netinet/sctp_output.h> 53170091Srrs#include <netinet/sctp_bsd_addr.h> 54179783Srrs#include <netinet/udp.h> 55163953Srrs 56171167Sgnn#ifdef IPSEC 57171133Sgnn#include <netipsec/ipsec.h> 58171133Sgnn#if defined(INET6) 59171133Sgnn#include <netipsec/ipsec6.h> 60171440Srrs#endif /* INET6 */ 61171440Srrs#endif /* IPSEC */ 62163953Srrs 63163953Srrsextern struct protosw inetsw[]; 64163953Srrs 65163953Srrsint 66171259Sdelphijsctp6_input(struct mbuf **i_pak, int *offp, int proto) 67163953Srrs{ 68165647Srrs struct mbuf *m; 69163953Srrs struct ip6_hdr *ip6; 70163953Srrs struct sctphdr *sh; 71163953Srrs struct sctp_inpcb *in6p = NULL; 72163953Srrs struct sctp_nets *net; 73163953Srrs int refcount_up = 0; 74169352Srrs uint32_t check, calc_check; 75170181Srrs uint32_t vrf_id = 0; 76163953Srrs struct inpcb *in6p_ip; 77163953Srrs struct sctp_chunkhdr *ch; 78163953Srrs int length, mlen, offset, iphlen; 79168299Srrs uint8_t ecn_bits; 80163953Srrs struct sctp_tcb *stcb = NULL; 81170056Srrs int pkt_len = 0; 82163953Srrs int off = *offp; 83179783Srrs uint16_t port = 0; 84163953Srrs 85169352Srrs /* get the VRF and table id's */ 86169352Srrs if (SCTP_GET_PKT_VRFID(*i_pak, vrf_id)) { 87169352Srrs SCTP_RELEASE_PKT(*i_pak); 88169352Srrs return (-1); 89169352Srrs } 90168709Srrs m = SCTP_HEADER_TO_CHAIN(*i_pak); 91170056Srrs pkt_len = SCTP_HEADER_LEN((*i_pak)); 92165647Srrs 93170091Srrs#ifdef SCTP_PACKET_LOGGING 94170091Srrs sctp_packet_log(m, pkt_len); 95170091Srrs#endif 96163953Srrs ip6 = mtod(m, struct ip6_hdr *); 97163953Srrs /* Ensure that (sctphdr + sctp_chunkhdr) in a row. */ 98170056Srrs IP6_EXTHDR_GET(sh, struct sctphdr *, m, off, 99170056Srrs (int)(sizeof(*sh) + sizeof(*ch))); 100163953Srrs if (sh == NULL) { 101163953Srrs SCTP_STAT_INCR(sctps_hdrops); 102163953Srrs return IPPROTO_DONE; 103163953Srrs } 104163953Srrs ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); 105163953Srrs iphlen = off; 106163953Srrs offset = iphlen + sizeof(*sh) + sizeof(*ch); 107170859Srrs SCTPDBG(SCTP_DEBUG_INPUT1, 108170859Srrs "sctp6_input() length:%d iphlen:%d\n", pkt_len, iphlen); 109163953Srrs 110170859Srrs 111163953Srrs#if defined(NFAITH) && NFAITH > 0 112163953Srrs 113163953Srrs if (faithprefix_p != NULL && (*faithprefix_p) (&ip6->ip6_dst)) { 114163953Srrs /* XXX send icmp6 host/port unreach? */ 115163953Srrs goto bad; 116163953Srrs } 117163953Srrs#endif /* NFAITH defined and > 0 */ 118163953Srrs SCTP_STAT_INCR(sctps_recvpackets); 119163953Srrs SCTP_STAT_INCR_COUNTER64(sctps_inpackets); 120169420Srrs SCTPDBG(SCTP_DEBUG_INPUT1, "V6 input gets a packet iphlen:%d pktlen:%d\n", 121170056Srrs iphlen, pkt_len); 122163953Srrs if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 123163953Srrs /* No multi-cast support in SCTP */ 124163953Srrs goto bad; 125163953Srrs } 126163953Srrs /* destination port of 0 is illegal, based on RFC2960. */ 127163953Srrs if (sh->dest_port == 0) 128163953Srrs goto bad; 129171990Srrs check = sh->checksum; /* save incoming checksum */ 130179783Srrs if ((check == 0) && (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback)) && 131171990Srrs (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &ip6->ip6_dst))) { 132171990Srrs goto sctp_skip_csum; 133171990Srrs } 134171990Srrs sh->checksum = 0; /* prepare for calc */ 135171990Srrs calc_check = sctp_calculate_sum(m, &mlen, iphlen); 136171990Srrs if (calc_check != check) { 137171990Srrs SCTPDBG(SCTP_DEBUG_INPUT1, "Bad CSUM on SCTP packet calc_check:%x check:%x m:%p mlen:%d iphlen:%d\n", 138171990Srrs calc_check, check, m, mlen, iphlen); 139171990Srrs stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch), 140171990Srrs sh, ch, &in6p, &net, vrf_id); 141179783Srrs if ((net) && (port)) { 142179783Srrs if (net->port == 0) { 143179783Srrs sctp_pathmtu_adjustment(in6p, stcb, net, net->mtu - sizeof(struct udphdr)); 144179783Srrs } 145179783Srrs net->port = port; 146179783Srrs } 147171990Srrs /* in6p's ref-count increased && stcb locked */ 148171990Srrs if ((in6p) && (stcb)) { 149171990Srrs sctp_send_packet_dropped(stcb, net, m, iphlen, 1); 150172090Srrs sctp_chunk_output((struct sctp_inpcb *)in6p, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR, SCTP_SO_NOT_LOCKED); 151171990Srrs } else if ((in6p != NULL) && (stcb == NULL)) { 152171990Srrs refcount_up = 1; 153163953Srrs } 154171990Srrs SCTP_STAT_INCR(sctps_badsum); 155171990Srrs SCTP_STAT_INCR_COUNTER32(sctps_checksumerrors); 156171990Srrs goto bad; 157165647Srrs } 158171990Srrs sh->checksum = calc_check; 159171990Srrs 160163953Srrssctp_skip_csum: 161163953Srrs net = NULL; 162163953Srrs /* 163163953Srrs * Locate pcb and tcb for datagram sctp_findassociation_addr() wants 164163953Srrs * IP/SCTP/first chunk header... 165163953Srrs */ 166163953Srrs stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch), 167168299Srrs sh, ch, &in6p, &net, vrf_id); 168179783Srrs if ((net) && (port)) { 169179783Srrs if (net->port == 0) { 170179783Srrs sctp_pathmtu_adjustment(in6p, stcb, net, net->mtu - sizeof(struct udphdr)); 171179783Srrs } 172179783Srrs net->port = port; 173179783Srrs } 174163953Srrs /* in6p's ref-count increased */ 175163953Srrs if (in6p == NULL) { 176163953Srrs struct sctp_init_chunk *init_chk, chunk_buf; 177163953Srrs 178163953Srrs SCTP_STAT_INCR(sctps_noport); 179163953Srrs if (ch->chunk_type == SCTP_INITIATION) { 180163953Srrs /* 181163953Srrs * we do a trick here to get the INIT tag, dig in 182163953Srrs * and get the tag from the INIT and put it in the 183163953Srrs * common header. 184163953Srrs */ 185163953Srrs init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m, 186163953Srrs iphlen + sizeof(*sh), sizeof(*init_chk), 187168299Srrs (uint8_t *) & chunk_buf); 188169420Srrs if (init_chk) 189169420Srrs sh->v_tag = init_chk->init.initiate_tag; 190169420Srrs else 191169420Srrs sh->v_tag = 0; 192163953Srrs } 193165220Srrs if (ch->chunk_type == SCTP_SHUTDOWN_ACK) { 194179783Srrs sctp_send_shutdown_complete2(m, iphlen, sh, vrf_id, port); 195165220Srrs goto bad; 196165220Srrs } 197165220Srrs if (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) { 198165220Srrs goto bad; 199165220Srrs } 200165220Srrs if (ch->chunk_type != SCTP_ABORT_ASSOCIATION) 201179783Srrs sctp_send_abort(m, iphlen, sh, 0, NULL, vrf_id, port); 202163953Srrs goto bad; 203163953Srrs } else if (stcb == NULL) { 204163953Srrs refcount_up = 1; 205163953Srrs } 206163953Srrs in6p_ip = (struct inpcb *)in6p; 207171167Sgnn#ifdef IPSEC 208163953Srrs /* 209163953Srrs * Check AH/ESP integrity. 210163953Srrs */ 211163996Srrs if (in6p_ip && (ipsec6_in_reject(m, in6p_ip))) { 212163953Srrs/* XXX */ 213180387Srrs MODULE_GLOBAL(MOD_IPSEC, ipsec6stat).in_polvio++; 214163953Srrs goto bad; 215163996Srrs } 216171440Srrs#endif /* IPSEC */ 217163953Srrs 218163953Srrs /* 219163953Srrs * CONTROL chunk processing 220163953Srrs */ 221163953Srrs offset -= sizeof(*ch); 222163953Srrs ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff); 223165647Srrs 224165647Srrs /* Length now holds the total packet length payload + iphlen */ 225165647Srrs length = ntohs(ip6->ip6_plen) + iphlen; 226165647Srrs 227169655Srrs /* sa_ignore NO_NULL_CHK */ 228169378Srrs sctp_common_input_processing(&m, iphlen, offset, length, sh, ch, 229179783Srrs in6p, stcb, net, ecn_bits, vrf_id, port); 230163953Srrs /* inp's ref-count reduced && stcb unlocked */ 231163953Srrs /* XXX this stuff below gets moved to appropriate parts later... */ 232163953Srrs if (m) 233169352Srrs sctp_m_freem(m); 234163953Srrs if ((in6p) && refcount_up) { 235163953Srrs /* reduce ref-count */ 236163953Srrs SCTP_INP_WLOCK(in6p); 237163953Srrs SCTP_INP_DECR_REF(in6p); 238163953Srrs SCTP_INP_WUNLOCK(in6p); 239163953Srrs } 240163953Srrs return IPPROTO_DONE; 241163953Srrs 242163953Srrsbad: 243169420Srrs if (stcb) { 244163953Srrs SCTP_TCB_UNLOCK(stcb); 245169420Srrs } 246163953Srrs if ((in6p) && refcount_up) { 247163953Srrs /* reduce ref-count */ 248163953Srrs SCTP_INP_WLOCK(in6p); 249163953Srrs SCTP_INP_DECR_REF(in6p); 250163953Srrs SCTP_INP_WUNLOCK(in6p); 251163953Srrs } 252163953Srrs if (m) 253169352Srrs sctp_m_freem(m); 254163953Srrs return IPPROTO_DONE; 255163953Srrs} 256163953Srrs 257163953Srrs 258163953Srrsstatic void 259171259Sdelphijsctp6_notify_mbuf(struct sctp_inpcb *inp, struct icmp6_hdr *icmp6, 260171259Sdelphij struct sctphdr *sh, struct sctp_tcb *stcb, struct sctp_nets *net) 261163953Srrs{ 262168299Srrs uint32_t nxtsz; 263163953Srrs 264163953Srrs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 265163953Srrs (icmp6 == NULL) || (sh == NULL)) { 266163953Srrs goto out; 267163953Srrs } 268163953Srrs /* First do we even look at it? */ 269163953Srrs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) 270163953Srrs goto out; 271163953Srrs 272163953Srrs if (icmp6->icmp6_type != ICMP6_PACKET_TOO_BIG) { 273163953Srrs /* not PACKET TO BIG */ 274163953Srrs goto out; 275163953Srrs } 276163953Srrs /* 277163953Srrs * ok we need to look closely. We could even get smarter and look at 278163953Srrs * anyone that we sent to in case we get a different ICMP that tells 279163953Srrs * us there is no way to reach a host, but for this impl, all we 280163953Srrs * care about is MTU discovery. 281163953Srrs */ 282163953Srrs nxtsz = ntohl(icmp6->icmp6_mtu); 283163953Srrs /* Stop any PMTU timer */ 284165220Srrs sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL, SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_1); 285163953Srrs 286163953Srrs /* Adjust destination size limit */ 287163953Srrs if (net->mtu > nxtsz) { 288163953Srrs net->mtu = nxtsz; 289185694Srrs if (net->port) { 290185694Srrs net->mtu -= sizeof(struct udphdr); 291185694Srrs } 292163953Srrs } 293163953Srrs /* now what about the ep? */ 294163953Srrs if (stcb->asoc.smallest_mtu > nxtsz) { 295163953Srrs struct sctp_tmit_chunk *chk; 296163953Srrs 297163953Srrs /* Adjust that too */ 298163953Srrs stcb->asoc.smallest_mtu = nxtsz; 299163953Srrs /* now off to subtract IP_DF flag if needed */ 300163953Srrs 301163953Srrs TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) { 302168299Srrs if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) { 303163953Srrs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 304163953Srrs } 305163953Srrs } 306163953Srrs TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 307168299Srrs if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) { 308163953Srrs /* 309163953Srrs * For this guy we also mark for immediate 310163953Srrs * resend since we sent to big of chunk 311163953Srrs */ 312163953Srrs chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 313163953Srrs if (chk->sent != SCTP_DATAGRAM_RESEND) 314163953Srrs stcb->asoc.sent_queue_retran_cnt++; 315163953Srrs chk->sent = SCTP_DATAGRAM_RESEND; 316163953Srrs chk->rec.data.doing_fast_retransmit = 0; 317163953Srrs 318163953Srrs chk->sent = SCTP_DATAGRAM_RESEND; 319163953Srrs /* Clear any time so NO RTT is being done */ 320163953Srrs chk->sent_rcv_time.tv_sec = 0; 321163953Srrs chk->sent_rcv_time.tv_usec = 0; 322163953Srrs stcb->asoc.total_flight -= chk->send_size; 323163953Srrs net->flight_size -= chk->send_size; 324163953Srrs } 325163953Srrs } 326163953Srrs } 327163953Srrs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL); 328163953Srrsout: 329169420Srrs if (stcb) { 330163953Srrs SCTP_TCB_UNLOCK(stcb); 331169420Srrs } 332163953Srrs} 333163953Srrs 334163953Srrs 335172156Srrsvoid 336172091Srrssctp6_notify(struct sctp_inpcb *inp, 337172091Srrs struct icmp6_hdr *icmph, 338172091Srrs struct sctphdr *sh, 339172091Srrs struct sockaddr *to, 340172091Srrs struct sctp_tcb *stcb, 341172091Srrs struct sctp_nets *net) 342172091Srrs{ 343172091Srrs#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 344172091Srrs struct socket *so; 345172091Srrs 346172091Srrs#endif 347172091Srrs /* protection */ 348172091Srrs int reason; 349172091Srrs 350172091Srrs 351172091Srrs if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 352172091Srrs (sh == NULL) || (to == NULL)) { 353172091Srrs if (stcb) 354172091Srrs SCTP_TCB_UNLOCK(stcb); 355172091Srrs return; 356172091Srrs } 357172091Srrs /* First job is to verify the vtag matches what I would send */ 358172091Srrs if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 359172091Srrs SCTP_TCB_UNLOCK(stcb); 360172091Srrs return; 361172091Srrs } 362172091Srrs if (icmph->icmp6_type != ICMP_UNREACH) { 363172091Srrs /* We only care about unreachable */ 364172091Srrs SCTP_TCB_UNLOCK(stcb); 365172091Srrs return; 366172091Srrs } 367172091Srrs if ((icmph->icmp6_code == ICMP_UNREACH_NET) || 368172091Srrs (icmph->icmp6_code == ICMP_UNREACH_HOST) || 369172091Srrs (icmph->icmp6_code == ICMP_UNREACH_NET_UNKNOWN) || 370172091Srrs (icmph->icmp6_code == ICMP_UNREACH_HOST_UNKNOWN) || 371172091Srrs (icmph->icmp6_code == ICMP_UNREACH_ISOLATED) || 372172091Srrs (icmph->icmp6_code == ICMP_UNREACH_NET_PROHIB) || 373172091Srrs (icmph->icmp6_code == ICMP_UNREACH_HOST_PROHIB) || 374172091Srrs (icmph->icmp6_code == ICMP_UNREACH_FILTER_PROHIB)) { 375172091Srrs 376172091Srrs /* 377172091Srrs * Hmm reachablity problems we must examine closely. If its 378172091Srrs * not reachable, we may have lost a network. Or if there is 379172091Srrs * NO protocol at the other end named SCTP. well we consider 380172091Srrs * it a OOTB abort. 381172091Srrs */ 382172091Srrs if (net->dest_state & SCTP_ADDR_REACHABLE) { 383172091Srrs /* Ok that destination is NOT reachable */ 384172091Srrs SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n", 385172091Srrs net->error_count, 386172091Srrs net->failure_threshold, 387172091Srrs net); 388172091Srrs 389172091Srrs net->dest_state &= ~SCTP_ADDR_REACHABLE; 390172091Srrs net->dest_state |= SCTP_ADDR_NOT_REACHABLE; 391172091Srrs /* 392172091Srrs * JRS 5/14/07 - If a destination is unreachable, 393172091Srrs * the PF bit is turned off. This allows an 394172091Srrs * unambiguous use of the PF bit for destinations 395172091Srrs * that are reachable but potentially failed. If the 396172091Srrs * destination is set to the unreachable state, also 397172091Srrs * set the destination to the PF state. 398172091Srrs */ 399172091Srrs /* 400172091Srrs * Add debug message here if destination is not in 401172091Srrs * PF state. 402172091Srrs */ 403172091Srrs /* Stop any running T3 timers here? */ 404179783Srrs if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_pf)) { 405172091Srrs net->dest_state &= ~SCTP_ADDR_PF; 406172091Srrs SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n", 407172091Srrs net); 408172091Srrs } 409172091Srrs net->error_count = net->failure_threshold + 1; 410172091Srrs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, 411172091Srrs stcb, SCTP_FAILED_THRESHOLD, 412172091Srrs (void *)net, SCTP_SO_NOT_LOCKED); 413172091Srrs } 414172091Srrs SCTP_TCB_UNLOCK(stcb); 415172091Srrs } else if ((icmph->icmp6_code == ICMP_UNREACH_PROTOCOL) || 416172091Srrs (icmph->icmp6_code == ICMP_UNREACH_PORT)) { 417172091Srrs /* 418172091Srrs * Here the peer is either playing tricks on us, including 419172091Srrs * an address that belongs to someone who does not support 420172091Srrs * SCTP OR was a userland implementation that shutdown and 421172091Srrs * now is dead. In either case treat it like a OOTB abort 422172091Srrs * with no TCB 423172091Srrs */ 424172091Srrs reason = SCTP_PEER_FAULTY; 425172091Srrs sctp_abort_notification(stcb, reason, SCTP_SO_NOT_LOCKED); 426172091Srrs#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 427172091Srrs so = SCTP_INP_SO(inp); 428172091Srrs atomic_add_int(&stcb->asoc.refcnt, 1); 429172091Srrs SCTP_TCB_UNLOCK(stcb); 430172091Srrs SCTP_SOCKET_LOCK(so, 1); 431172091Srrs SCTP_TCB_LOCK(stcb); 432172091Srrs atomic_subtract_int(&stcb->asoc.refcnt, 1); 433172091Srrs#endif 434172091Srrs (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); 435172091Srrs#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 436172091Srrs SCTP_SOCKET_UNLOCK(so, 1); 437172091Srrs /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */ 438172091Srrs#endif 439172091Srrs /* no need to unlock here, since the TCB is gone */ 440172091Srrs } else { 441172091Srrs SCTP_TCB_UNLOCK(stcb); 442172091Srrs } 443172091Srrs} 444172091Srrs 445172091Srrs 446172091Srrs 447163953Srrsvoid 448171259Sdelphijsctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d) 449163953Srrs{ 450163953Srrs struct sctphdr sh; 451163953Srrs struct ip6ctlparam *ip6cp = NULL; 452167598Srrs uint32_t vrf_id; 453163953Srrs 454167598Srrs vrf_id = SCTP_DEFAULT_VRFID; 455167598Srrs 456163953Srrs if (pktdst->sa_family != AF_INET6 || 457163953Srrs pktdst->sa_len != sizeof(struct sockaddr_in6)) 458163953Srrs return; 459163953Srrs 460163953Srrs if ((unsigned)cmd >= PRC_NCMDS) 461163953Srrs return; 462163953Srrs if (PRC_IS_REDIRECT(cmd)) { 463163953Srrs d = NULL; 464163953Srrs } else if (inet6ctlerrmap[cmd] == 0) { 465163953Srrs return; 466163953Srrs } 467163953Srrs /* if the parameter is from icmp6, decode it. */ 468163953Srrs if (d != NULL) { 469163953Srrs ip6cp = (struct ip6ctlparam *)d; 470163953Srrs } else { 471163953Srrs ip6cp = (struct ip6ctlparam *)NULL; 472163953Srrs } 473163953Srrs 474163953Srrs if (ip6cp) { 475163953Srrs /* 476163953Srrs * XXX: We assume that when IPV6 is non NULL, M and OFF are 477163953Srrs * valid. 478163953Srrs */ 479163953Srrs /* check if we can safely examine src and dst ports */ 480163953Srrs struct sctp_inpcb *inp = NULL; 481163953Srrs struct sctp_tcb *stcb = NULL; 482163953Srrs struct sctp_nets *net = NULL; 483163953Srrs struct sockaddr_in6 final; 484163953Srrs 485165647Srrs if (ip6cp->ip6c_m == NULL) 486163953Srrs return; 487163953Srrs 488163953Srrs bzero(&sh, sizeof(sh)); 489163953Srrs bzero(&final, sizeof(final)); 490163953Srrs inp = NULL; 491163953Srrs net = NULL; 492163953Srrs m_copydata(ip6cp->ip6c_m, ip6cp->ip6c_off, sizeof(sh), 493163953Srrs (caddr_t)&sh); 494163953Srrs ip6cp->ip6c_src->sin6_port = sh.src_port; 495163953Srrs final.sin6_len = sizeof(final); 496163953Srrs final.sin6_family = AF_INET6; 497163953Srrs final.sin6_addr = ((struct sockaddr_in6 *)pktdst)->sin6_addr; 498163953Srrs final.sin6_port = sh.dest_port; 499163953Srrs stcb = sctp_findassociation_addr_sa((struct sockaddr *)ip6cp->ip6c_src, 500163953Srrs (struct sockaddr *)&final, 501167598Srrs &inp, &net, 1, vrf_id); 502163953Srrs /* inp's ref-count increased && stcb locked */ 503163953Srrs if (stcb != NULL && inp && (inp->sctp_socket != NULL)) { 504163953Srrs if (cmd == PRC_MSGSIZE) { 505163953Srrs sctp6_notify_mbuf(inp, 506163953Srrs ip6cp->ip6c_icmp6, 507163953Srrs &sh, 508163953Srrs stcb, 509163953Srrs net); 510163953Srrs /* inp's ref-count reduced && stcb unlocked */ 511163953Srrs } else { 512172091Srrs sctp6_notify(inp, ip6cp->ip6c_icmp6, &sh, 513163953Srrs (struct sockaddr *)&final, 514163953Srrs stcb, net); 515163953Srrs /* inp's ref-count reduced && stcb unlocked */ 516163953Srrs } 517163953Srrs } else { 518163953Srrs if (PRC_IS_REDIRECT(cmd) && inp) { 519163953Srrs in6_rtchange((struct in6pcb *)inp, 520163953Srrs inet6ctlerrmap[cmd]); 521163953Srrs } 522163953Srrs if (inp) { 523163953Srrs /* reduce inp's ref-count */ 524163953Srrs SCTP_INP_WLOCK(inp); 525163953Srrs SCTP_INP_DECR_REF(inp); 526163953Srrs SCTP_INP_WUNLOCK(inp); 527163953Srrs } 528163953Srrs if (stcb) 529163953Srrs SCTP_TCB_UNLOCK(stcb); 530163953Srrs } 531163953Srrs } 532163953Srrs} 533163953Srrs 534163953Srrs/* 535163953Srrs * this routine can probably be collasped into the one in sctp_userreq.c 536163953Srrs * since they do the same thing and now we lookup with a sockaddr 537163953Srrs */ 538163953Srrsstatic int 539163953Srrssctp6_getcred(SYSCTL_HANDLER_ARGS) 540163953Srrs{ 541164085Srrs struct xucred xuc; 542163953Srrs struct sockaddr_in6 addrs[2]; 543163953Srrs struct sctp_inpcb *inp; 544163953Srrs struct sctp_nets *net; 545163953Srrs struct sctp_tcb *stcb; 546164085Srrs int error; 547167598Srrs uint32_t vrf_id; 548163953Srrs 549167598Srrs vrf_id = SCTP_DEFAULT_VRFID; 550167598Srrs 551170587Srwatson error = priv_check(req->td, PRIV_NETINET_GETCRED); 552163953Srrs if (error) 553163953Srrs return (error); 554163953Srrs 555171943Srrs if (req->newlen != sizeof(addrs)) { 556171943Srrs SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 557163953Srrs return (EINVAL); 558171943Srrs } 559171943Srrs if (req->oldlen != sizeof(struct ucred)) { 560171943Srrs SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 561163953Srrs return (EINVAL); 562171943Srrs } 563163953Srrs error = SYSCTL_IN(req, addrs, sizeof(addrs)); 564163953Srrs if (error) 565163953Srrs return (error); 566163953Srrs 567163953Srrs stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[0]), 568163953Srrs sin6tosa(&addrs[1]), 569167598Srrs &inp, &net, 1, vrf_id); 570163953Srrs if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) { 571164085Srrs if ((inp != NULL) && (stcb == NULL)) { 572164085Srrs /* reduce ref-count */ 573163953Srrs SCTP_INP_WLOCK(inp); 574163953Srrs SCTP_INP_DECR_REF(inp); 575164085Srrs goto cred_can_cont; 576163953Srrs } 577171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT); 578164085Srrs error = ENOENT; 579163953Srrs goto out; 580163953Srrs } 581163953Srrs SCTP_TCB_UNLOCK(stcb); 582164085Srrs /* 583164085Srrs * We use the write lock here, only since in the error leg we need 584164085Srrs * it. If we used RLOCK, then we would have to 585164085Srrs * wlock/decr/unlock/rlock. Which in theory could create a hole. 586164085Srrs * Better to use higher wlock. 587164085Srrs */ 588164085Srrs SCTP_INP_WLOCK(inp); 589164085Srrscred_can_cont: 590164085Srrs error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket); 591164085Srrs if (error) { 592164085Srrs SCTP_INP_WUNLOCK(inp); 593164085Srrs goto out; 594164085Srrs } 595164085Srrs cru2x(inp->sctp_socket->so_cred, &xuc); 596164085Srrs SCTP_INP_WUNLOCK(inp); 597164085Srrs error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); 598163953Srrsout: 599163953Srrs return (error); 600163953Srrs} 601163953Srrs 602163953SrrsSYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW, 603163953Srrs 0, 0, 604163953Srrs sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection"); 605163953Srrs 606163953Srrs 607163953Srrs/* This is the same as the sctp_abort() could be made common */ 608163953Srrsstatic void 609163953Srrssctp6_abort(struct socket *so) 610163953Srrs{ 611163953Srrs struct sctp_inpcb *inp; 612163953Srrs uint32_t flags; 613163953Srrs 614163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 615172091Srrs if (inp == 0) { 616172091Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 617163953Srrs return; 618172091Srrs } 619163953Srrssctp_must_try_again: 620163953Srrs flags = inp->sctp_flags; 621163953Srrs#ifdef SCTP_LOG_CLOSING 622163953Srrs sctp_log_closing(inp, NULL, 17); 623163953Srrs#endif 624163953Srrs if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 625163953Srrs (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 626163953Srrs#ifdef SCTP_LOG_CLOSING 627163953Srrs sctp_log_closing(inp, NULL, 16); 628163953Srrs#endif 629169380Srrs sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 630169380Srrs SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 631163953Srrs SOCK_LOCK(so); 632167695Srrs SCTP_SB_CLEAR(so->so_snd); 633163953Srrs /* 634163953Srrs * same for the rcv ones, they are only here for the 635163953Srrs * accounting/select. 636163953Srrs */ 637167695Srrs SCTP_SB_CLEAR(so->so_rcv); 638167695Srrs /* Now null out the reference, we are completely detached. */ 639163953Srrs so->so_pcb = NULL; 640163953Srrs SOCK_UNLOCK(so); 641163953Srrs } else { 642163953Srrs flags = inp->sctp_flags; 643163953Srrs if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 644163953Srrs goto sctp_must_try_again; 645163953Srrs } 646163953Srrs } 647163953Srrs return; 648163953Srrs} 649163953Srrs 650163953Srrsstatic int 651163953Srrssctp6_attach(struct socket *so, int proto, struct thread *p) 652163953Srrs{ 653163953Srrs struct in6pcb *inp6; 654166086Srrs int error; 655163953Srrs struct sctp_inpcb *inp; 656170205Srrs uint32_t vrf_id = SCTP_DEFAULT_VRFID; 657163953Srrs 658163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 659171943Srrs if (inp != NULL) { 660171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 661163953Srrs return EINVAL; 662171943Srrs } 663163953Srrs if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 664179783Srrs error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace)); 665163953Srrs if (error) 666163953Srrs return error; 667163953Srrs } 668170205Srrs error = sctp_inpcb_alloc(so, vrf_id); 669163953Srrs if (error) 670163953Srrs return error; 671163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 672170205Srrs SCTP_INP_WLOCK(inp); 673163953Srrs inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6; /* I'm v6! */ 674163953Srrs inp6 = (struct in6pcb *)inp; 675163953Srrs 676163953Srrs inp6->inp_vflag |= INP_IPV6; 677163953Srrs inp6->in6p_hops = -1; /* use kernel default */ 678163953Srrs inp6->in6p_cksum = -1; /* just to be sure */ 679163953Srrs#ifdef INET 680163953Srrs /* 681163953Srrs * XXX: ugly!! IPv4 TTL initialization is necessary for an IPv6 682163953Srrs * socket as well, because the socket may be bound to an IPv6 683163953Srrs * wildcard address, which may match an IPv4-mapped IPv6 address. 684163953Srrs */ 685180387Srrs inp6->inp_ip_ttl = MODULE_GLOBAL(MOD_INET, ip_defttl); 686163953Srrs#endif 687163953Srrs /* 688163953Srrs * Hmm what about the IPSEC stuff that is missing here but in 689163953Srrs * sctp_attach()? 690163953Srrs */ 691170205Srrs SCTP_INP_WUNLOCK(inp); 692163953Srrs return 0; 693163953Srrs} 694163953Srrs 695163953Srrsstatic int 696163953Srrssctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p) 697163953Srrs{ 698163953Srrs struct sctp_inpcb *inp; 699163953Srrs struct in6pcb *inp6; 700166086Srrs int error; 701163953Srrs 702163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 703171943Srrs if (inp == 0) { 704171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 705163953Srrs return EINVAL; 706171943Srrs } 707170056Srrs if (addr) { 708170056Srrs if ((addr->sa_family == AF_INET6) && 709170056Srrs (addr->sa_len != sizeof(struct sockaddr_in6))) { 710171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 711170056Srrs return EINVAL; 712170056Srrs } 713170056Srrs if ((addr->sa_family == AF_INET) && 714170056Srrs (addr->sa_len != sizeof(struct sockaddr_in))) { 715171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 716170056Srrs return EINVAL; 717170056Srrs } 718170056Srrs } 719163953Srrs inp6 = (struct in6pcb *)inp; 720163953Srrs inp6->inp_vflag &= ~INP_IPV4; 721163953Srrs inp6->inp_vflag |= INP_IPV6; 722166023Srrs if ((addr != NULL) && (SCTP_IPV6_V6ONLY(inp6) == 0)) { 723163953Srrs if (addr->sa_family == AF_INET) { 724163953Srrs /* binding v4 addr to v6 socket, so reset flags */ 725163953Srrs inp6->inp_vflag |= INP_IPV4; 726163953Srrs inp6->inp_vflag &= ~INP_IPV6; 727163953Srrs } else { 728163953Srrs struct sockaddr_in6 *sin6_p; 729163953Srrs 730163953Srrs sin6_p = (struct sockaddr_in6 *)addr; 731163953Srrs 732163953Srrs if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) { 733163953Srrs inp6->inp_vflag |= INP_IPV4; 734163953Srrs } else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { 735163953Srrs struct sockaddr_in sin; 736163953Srrs 737163953Srrs in6_sin6_2_sin(&sin, sin6_p); 738163953Srrs inp6->inp_vflag |= INP_IPV4; 739163953Srrs inp6->inp_vflag &= ~INP_IPV6; 740171572Srrs error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, NULL, p); 741163953Srrs return error; 742163953Srrs } 743163953Srrs } 744163953Srrs } else if (addr != NULL) { 745163953Srrs /* IPV6_V6ONLY socket */ 746163953Srrs if (addr->sa_family == AF_INET) { 747163953Srrs /* can't bind v4 addr to v6 only socket! */ 748171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 749163953Srrs return EINVAL; 750163953Srrs } else { 751163953Srrs struct sockaddr_in6 *sin6_p; 752163953Srrs 753163953Srrs sin6_p = (struct sockaddr_in6 *)addr; 754163953Srrs 755172091Srrs if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { 756163953Srrs /* can't bind v4-mapped addrs either! */ 757163953Srrs /* NOTE: we don't support SIIT */ 758171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 759172091Srrs return EINVAL; 760172091Srrs } 761163953Srrs } 762163953Srrs } 763171572Srrs error = sctp_inpcb_bind(so, addr, NULL, p); 764163953Srrs return error; 765163953Srrs} 766163953Srrs 767163953Srrs 768163953Srrsstatic void 769163953Srrssctp6_close(struct socket *so) 770163953Srrs{ 771171990Srrs sctp_close(so); 772163953Srrs} 773163953Srrs 774167598Srrs/* This could be made common with sctp_detach() since they are identical */ 775163953Srrs 776168709Srrsstatic 777168709Srrsint 778163953Srrssctp6_disconnect(struct socket *so) 779163953Srrs{ 780171990Srrs return (sctp_disconnect(so)); 781163953Srrs} 782163953Srrs 783168709Srrs 784163953Srrsint 785163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 786163953Srrs struct mbuf *control, struct thread *p); 787163953Srrs 788163953Srrs 789163953Srrsstatic int 790163953Srrssctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 791163953Srrs struct mbuf *control, struct thread *p) 792163953Srrs{ 793163953Srrs struct sctp_inpcb *inp; 794163953Srrs struct inpcb *in_inp; 795163953Srrs struct in6pcb *inp6; 796163953Srrs 797163953Srrs#ifdef INET 798163953Srrs struct sockaddr_in6 *sin6; 799163953Srrs 800163953Srrs#endif /* INET */ 801163953Srrs /* No SPL needed since sctp_output does this */ 802163953Srrs 803163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 804163953Srrs if (inp == NULL) { 805163953Srrs if (control) { 806169352Srrs SCTP_RELEASE_PKT(control); 807163953Srrs control = NULL; 808163953Srrs } 809169352Srrs SCTP_RELEASE_PKT(m); 810171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 811163953Srrs return EINVAL; 812163953Srrs } 813163953Srrs in_inp = (struct inpcb *)inp; 814163953Srrs inp6 = (struct in6pcb *)inp; 815163953Srrs /* 816163953Srrs * For the TCP model we may get a NULL addr, if we are a connected 817163953Srrs * socket thats ok. 818163953Srrs */ 819163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) && 820163953Srrs (addr == NULL)) { 821163953Srrs goto connected_type; 822163953Srrs } 823163953Srrs if (addr == NULL) { 824169352Srrs SCTP_RELEASE_PKT(m); 825163953Srrs if (control) { 826169352Srrs SCTP_RELEASE_PKT(control); 827163953Srrs control = NULL; 828163953Srrs } 829171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EDESTADDRREQ); 830163953Srrs return (EDESTADDRREQ); 831163953Srrs } 832163953Srrs#ifdef INET 833163953Srrs sin6 = (struct sockaddr_in6 *)addr; 834166023Srrs if (SCTP_IPV6_V6ONLY(inp6)) { 835163953Srrs /* 836163953Srrs * if IPV6_V6ONLY flag, we discard datagrams destined to a 837163953Srrs * v4 addr or v4-mapped addr 838163953Srrs */ 839163953Srrs if (addr->sa_family == AF_INET) { 840171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 841163953Srrs return EINVAL; 842163953Srrs } 843163953Srrs if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 844171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 845163953Srrs return EINVAL; 846163953Srrs } 847163953Srrs } 848163953Srrs if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 849180387Srrs if (!MODULE_GLOBAL(MOD_INET6, ip6_v6only)) { 850163953Srrs struct sockaddr_in sin; 851163953Srrs 852163953Srrs /* convert v4-mapped into v4 addr and send */ 853163953Srrs in6_sin6_2_sin(&sin, sin6); 854163953Srrs return sctp_sendm(so, flags, m, (struct sockaddr *)&sin, 855163953Srrs control, p); 856163953Srrs } else { 857163953Srrs /* mapped addresses aren't enabled */ 858171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 859163953Srrs return EINVAL; 860163953Srrs } 861163953Srrs } 862163953Srrs#endif /* INET */ 863163953Srrsconnected_type: 864163953Srrs /* now what about control */ 865163953Srrs if (control) { 866163953Srrs if (inp->control) { 867169420Srrs SCTP_PRINTF("huh? control set?\n"); 868169352Srrs SCTP_RELEASE_PKT(inp->control); 869163953Srrs inp->control = NULL; 870163953Srrs } 871163953Srrs inp->control = control; 872163953Srrs } 873163953Srrs /* Place the data */ 874163953Srrs if (inp->pkt) { 875165647Srrs SCTP_BUF_NEXT(inp->pkt_last) = m; 876163953Srrs inp->pkt_last = m; 877163953Srrs } else { 878163953Srrs inp->pkt_last = inp->pkt = m; 879163953Srrs } 880163953Srrs if ( 881163953Srrs /* FreeBSD and MacOSX uses a flag passed */ 882163953Srrs ((flags & PRUS_MORETOCOME) == 0) 883163953Srrs ) { 884163953Srrs /* 885163953Srrs * note with the current version this code will only be used 886163953Srrs * by OpenBSD, NetBSD and FreeBSD have methods for 887163953Srrs * re-defining sosend() to use sctp_sosend(). One can 888163953Srrs * optionaly switch back to this code (by changing back the 889163953Srrs * defininitions but this is not advisable. 890163953Srrs */ 891163953Srrs int ret; 892163953Srrs 893163953Srrs ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags); 894163953Srrs inp->pkt = NULL; 895163953Srrs inp->control = NULL; 896163953Srrs return (ret); 897163953Srrs } else { 898163953Srrs return (0); 899163953Srrs } 900163953Srrs} 901163953Srrs 902163953Srrsstatic int 903163953Srrssctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p) 904163953Srrs{ 905167598Srrs uint32_t vrf_id; 906163953Srrs int error = 0; 907163953Srrs struct sctp_inpcb *inp; 908163953Srrs struct in6pcb *inp6; 909163953Srrs struct sctp_tcb *stcb; 910163953Srrs 911163953Srrs#ifdef INET 912163953Srrs struct sockaddr_in6 *sin6; 913163953Srrs struct sockaddr_storage ss; 914163953Srrs 915163953Srrs#endif /* INET */ 916163953Srrs 917163953Srrs inp6 = (struct in6pcb *)so->so_pcb; 918163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 919163953Srrs if (inp == 0) { 920171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET); 921163953Srrs return (ECONNRESET); /* I made the same as TCP since we are 922163953Srrs * not setup? */ 923163953Srrs } 924170056Srrs if (addr == NULL) { 925171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 926170056Srrs return (EINVAL); 927170056Srrs } 928170056Srrs if ((addr->sa_family == AF_INET6) && (addr->sa_len != sizeof(struct sockaddr_in6))) { 929171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 930170056Srrs return (EINVAL); 931170056Srrs } 932170056Srrs if ((addr->sa_family == AF_INET) && (addr->sa_len != sizeof(struct sockaddr_in))) { 933171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 934170056Srrs return (EINVAL); 935170056Srrs } 936168299Srrs vrf_id = inp->def_vrf_id; 937163953Srrs SCTP_ASOC_CREATE_LOCK(inp); 938163953Srrs SCTP_INP_RLOCK(inp); 939163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 940163953Srrs SCTP_PCB_FLAGS_UNBOUND) { 941163953Srrs /* Bind a ephemeral port */ 942163953Srrs SCTP_INP_RUNLOCK(inp); 943163953Srrs error = sctp6_bind(so, NULL, p); 944163953Srrs if (error) { 945163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 946163953Srrs 947163953Srrs return (error); 948163953Srrs } 949163953Srrs SCTP_INP_RLOCK(inp); 950163953Srrs } 951163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 952163953Srrs (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 953163953Srrs /* We are already connected AND the TCP model */ 954163953Srrs SCTP_INP_RUNLOCK(inp); 955163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 956171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EADDRINUSE); 957163953Srrs return (EADDRINUSE); 958163953Srrs } 959163953Srrs#ifdef INET 960163953Srrs sin6 = (struct sockaddr_in6 *)addr; 961166023Srrs if (SCTP_IPV6_V6ONLY(inp6)) { 962163953Srrs /* 963163953Srrs * if IPV6_V6ONLY flag, ignore connections destined to a v4 964163953Srrs * addr or v4-mapped addr 965163953Srrs */ 966163953Srrs if (addr->sa_family == AF_INET) { 967163953Srrs SCTP_INP_RUNLOCK(inp); 968163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 969171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 970163953Srrs return EINVAL; 971163953Srrs } 972163953Srrs if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 973163953Srrs SCTP_INP_RUNLOCK(inp); 974163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 975171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 976163953Srrs return EINVAL; 977163953Srrs } 978163953Srrs } 979163953Srrs if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 980180387Srrs if (!MODULE_GLOBAL(MOD_INET6, ip6_v6only)) { 981163953Srrs /* convert v4-mapped into v4 addr */ 982163953Srrs in6_sin6_2_sin((struct sockaddr_in *)&ss, sin6); 983163953Srrs addr = (struct sockaddr *)&ss; 984163953Srrs } else { 985163953Srrs /* mapped addresses aren't enabled */ 986163953Srrs SCTP_INP_RUNLOCK(inp); 987163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 988171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 989163953Srrs return EINVAL; 990163953Srrs } 991163953Srrs } else 992163953Srrs#endif /* INET */ 993163953Srrs addr = addr; /* for true v6 address case */ 994163953Srrs 995163953Srrs /* Now do we connect? */ 996163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 997163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 998169420Srrs if (stcb) { 999163953Srrs SCTP_TCB_UNLOCK(stcb); 1000169420Srrs } 1001163953Srrs SCTP_INP_RUNLOCK(inp); 1002163953Srrs } else { 1003163953Srrs SCTP_INP_RUNLOCK(inp); 1004163953Srrs SCTP_INP_WLOCK(inp); 1005163953Srrs SCTP_INP_INCR_REF(inp); 1006163953Srrs SCTP_INP_WUNLOCK(inp); 1007163953Srrs stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL); 1008163953Srrs if (stcb == NULL) { 1009163953Srrs SCTP_INP_WLOCK(inp); 1010163953Srrs SCTP_INP_DECR_REF(inp); 1011163953Srrs SCTP_INP_WUNLOCK(inp); 1012163953Srrs } 1013163953Srrs } 1014163953Srrs 1015163953Srrs if (stcb != NULL) { 1016163953Srrs /* Already have or am bring up an association */ 1017163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1018163953Srrs SCTP_TCB_UNLOCK(stcb); 1019171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EALREADY); 1020163953Srrs return (EALREADY); 1021163953Srrs } 1022163953Srrs /* We are GOOD to go */ 1023171531Srrs stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0, vrf_id, p); 1024163953Srrs SCTP_ASOC_CREATE_UNLOCK(inp); 1025163953Srrs if (stcb == NULL) { 1026163953Srrs /* Gak! no memory */ 1027163953Srrs return (error); 1028163953Srrs } 1029163953Srrs if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 1030163953Srrs stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 1031163953Srrs /* Set the connected flag so we can queue data */ 1032163953Srrs soisconnecting(so); 1033163953Srrs } 1034163953Srrs stcb->asoc.state = SCTP_STATE_COOKIE_WAIT; 1035169420Srrs (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 1036163953Srrs 1037163953Srrs /* initialize authentication parameters for the assoc */ 1038163953Srrs sctp_initialize_auth_params(inp, stcb); 1039163953Srrs 1040172090Srrs sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 1041163953Srrs SCTP_TCB_UNLOCK(stcb); 1042163953Srrs return error; 1043163953Srrs} 1044163953Srrs 1045163953Srrsstatic int 1046163953Srrssctp6_getaddr(struct socket *so, struct sockaddr **addr) 1047163953Srrs{ 1048163953Srrs struct sockaddr_in6 *sin6; 1049163953Srrs struct sctp_inpcb *inp; 1050167598Srrs uint32_t vrf_id; 1051167598Srrs struct sctp_ifa *sctp_ifa; 1052163953Srrs 1053163953Srrs int error; 1054163953Srrs 1055163953Srrs /* 1056163953Srrs * Do the malloc first in case it blocks. 1057163953Srrs */ 1058163953Srrs SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); 1059163953Srrs sin6->sin6_family = AF_INET6; 1060163953Srrs sin6->sin6_len = sizeof(*sin6); 1061163953Srrs 1062163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 1063163953Srrs if (inp == NULL) { 1064163953Srrs SCTP_FREE_SONAME(sin6); 1065171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET); 1066163953Srrs return ECONNRESET; 1067163953Srrs } 1068163953Srrs SCTP_INP_RLOCK(inp); 1069163953Srrs sin6->sin6_port = inp->sctp_lport; 1070163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1071163953Srrs /* For the bound all case you get back 0 */ 1072163953Srrs if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 1073163953Srrs struct sctp_tcb *stcb; 1074163953Srrs struct sockaddr_in6 *sin_a6; 1075163953Srrs struct sctp_nets *net; 1076163953Srrs int fnd; 1077163953Srrs 1078163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 1079163953Srrs if (stcb == NULL) { 1080163953Srrs goto notConn6; 1081163953Srrs } 1082163953Srrs fnd = 0; 1083163953Srrs sin_a6 = NULL; 1084163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1085163953Srrs sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr; 1086164085Srrs if (sin_a6 == NULL) 1087164085Srrs /* this will make coverity happy */ 1088164085Srrs continue; 1089164085Srrs 1090163953Srrs if (sin_a6->sin6_family == AF_INET6) { 1091163953Srrs fnd = 1; 1092163953Srrs break; 1093163953Srrs } 1094163953Srrs } 1095163953Srrs if ((!fnd) || (sin_a6 == NULL)) { 1096163953Srrs /* punt */ 1097163953Srrs goto notConn6; 1098163953Srrs } 1099168299Srrs vrf_id = inp->def_vrf_id; 1100168299Srrs sctp_ifa = sctp_source_address_selection(inp, stcb, (sctp_route_t *) & net->ro, net, 0, vrf_id); 1101167598Srrs if (sctp_ifa) { 1102167598Srrs sin6->sin6_addr = sctp_ifa->address.sin6.sin6_addr; 1103167598Srrs } 1104163953Srrs } else { 1105163953Srrs /* For the bound all case you get back 0 */ 1106163953Srrs notConn6: 1107163953Srrs memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr)); 1108163953Srrs } 1109163953Srrs } else { 1110163953Srrs /* Take the first IPv6 address in the list */ 1111163953Srrs struct sctp_laddr *laddr; 1112163953Srrs int fnd = 0; 1113163953Srrs 1114163953Srrs LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1115167598Srrs if (laddr->ifa->address.sa.sa_family == AF_INET6) { 1116163953Srrs struct sockaddr_in6 *sin_a; 1117163953Srrs 1118167598Srrs sin_a = (struct sockaddr_in6 *)&laddr->ifa->address.sin6; 1119163953Srrs sin6->sin6_addr = sin_a->sin6_addr; 1120163953Srrs fnd = 1; 1121163953Srrs break; 1122163953Srrs } 1123163953Srrs } 1124163953Srrs if (!fnd) { 1125163953Srrs SCTP_FREE_SONAME(sin6); 1126163953Srrs SCTP_INP_RUNLOCK(inp); 1127171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT); 1128163953Srrs return ENOENT; 1129163953Srrs } 1130163953Srrs } 1131163953Srrs SCTP_INP_RUNLOCK(inp); 1132163953Srrs /* Scoping things for v6 */ 1133164085Srrs if ((error = sa6_recoverscope(sin6)) != 0) { 1134164085Srrs SCTP_FREE_SONAME(sin6); 1135163953Srrs return (error); 1136164085Srrs } 1137163953Srrs (*addr) = (struct sockaddr *)sin6; 1138163953Srrs return (0); 1139163953Srrs} 1140163953Srrs 1141163953Srrsstatic int 1142163953Srrssctp6_peeraddr(struct socket *so, struct sockaddr **addr) 1143163953Srrs{ 1144163953Srrs struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)*addr; 1145163953Srrs int fnd; 1146163953Srrs struct sockaddr_in6 *sin_a6; 1147163953Srrs struct sctp_inpcb *inp; 1148163953Srrs struct sctp_tcb *stcb; 1149163953Srrs struct sctp_nets *net; 1150163953Srrs 1151163953Srrs int error; 1152163953Srrs 1153163953Srrs /* 1154163953Srrs * Do the malloc first in case it blocks. 1155163953Srrs */ 1156163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 1157163953Srrs if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) { 1158163953Srrs /* UDP type and listeners will drop out here */ 1159171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN); 1160163953Srrs return (ENOTCONN); 1161163953Srrs } 1162163953Srrs SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); 1163163953Srrs sin6->sin6_family = AF_INET6; 1164163953Srrs sin6->sin6_len = sizeof(*sin6); 1165163953Srrs 1166163953Srrs /* We must recapture incase we blocked */ 1167163953Srrs inp = (struct sctp_inpcb *)so->so_pcb; 1168163953Srrs if (inp == NULL) { 1169163953Srrs SCTP_FREE_SONAME(sin6); 1170171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET); 1171163953Srrs return ECONNRESET; 1172163953Srrs } 1173163953Srrs SCTP_INP_RLOCK(inp); 1174163953Srrs stcb = LIST_FIRST(&inp->sctp_asoc_list); 1175169420Srrs if (stcb) { 1176163953Srrs SCTP_TCB_LOCK(stcb); 1177169420Srrs } 1178163953Srrs SCTP_INP_RUNLOCK(inp); 1179163953Srrs if (stcb == NULL) { 1180163953Srrs SCTP_FREE_SONAME(sin6); 1181171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET); 1182163953Srrs return ECONNRESET; 1183163953Srrs } 1184163953Srrs fnd = 0; 1185163953Srrs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1186163953Srrs sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr; 1187163953Srrs if (sin_a6->sin6_family == AF_INET6) { 1188163953Srrs fnd = 1; 1189163953Srrs sin6->sin6_port = stcb->rport; 1190163953Srrs sin6->sin6_addr = sin_a6->sin6_addr; 1191163953Srrs break; 1192163953Srrs } 1193163953Srrs } 1194163953Srrs SCTP_TCB_UNLOCK(stcb); 1195163953Srrs if (!fnd) { 1196163953Srrs /* No IPv4 address */ 1197163953Srrs SCTP_FREE_SONAME(sin6); 1198171943Srrs SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT); 1199163953Srrs return ENOENT; 1200163953Srrs } 1201163953Srrs if ((error = sa6_recoverscope(sin6)) != 0) 1202163953Srrs return (error); 1203163953Srrs *addr = (struct sockaddr *)sin6; 1204163953Srrs return (0); 1205163953Srrs} 1206163953Srrs 1207163953Srrsstatic int 1208163953Srrssctp6_in6getaddr(struct socket *so, struct sockaddr **nam) 1209163953Srrs{ 1210163953Srrs struct sockaddr *addr; 1211163953Srrs struct in6pcb *inp6 = sotoin6pcb(so); 1212166086Srrs int error; 1213163953Srrs 1214171943Srrs if (inp6 == NULL) { 1215171943Srrs SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1216163953Srrs return EINVAL; 1217171943Srrs } 1218163953Srrs /* allow v6 addresses precedence */ 1219163953Srrs error = sctp6_getaddr(so, nam); 1220163953Srrs if (error) { 1221163953Srrs /* try v4 next if v6 failed */ 1222163953Srrs error = sctp_ingetaddr(so, nam); 1223163953Srrs if (error) { 1224163953Srrs return (error); 1225163953Srrs } 1226163953Srrs addr = *nam; 1227163953Srrs /* if I'm V6ONLY, convert it to v4-mapped */ 1228166023Srrs if (SCTP_IPV6_V6ONLY(inp6)) { 1229163953Srrs struct sockaddr_in6 sin6; 1230163953Srrs 1231163953Srrs in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6); 1232163953Srrs memcpy(addr, &sin6, sizeof(struct sockaddr_in6)); 1233168709Srrs 1234163953Srrs } 1235163953Srrs } 1236163953Srrs return (error); 1237163953Srrs} 1238163953Srrs 1239163953Srrs 1240163953Srrsstatic int 1241163953Srrssctp6_getpeeraddr(struct socket *so, struct sockaddr **nam) 1242163953Srrs{ 1243163953Srrs struct sockaddr *addr = *nam; 1244163953Srrs struct in6pcb *inp6 = sotoin6pcb(so); 1245166086Srrs int error; 1246163953Srrs 1247171943Srrs if (inp6 == NULL) { 1248171943Srrs SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1249163953Srrs return EINVAL; 1250171943Srrs } 1251163953Srrs /* allow v6 addresses precedence */ 1252163953Srrs error = sctp6_peeraddr(so, nam); 1253163953Srrs if (error) { 1254163953Srrs /* try v4 next if v6 failed */ 1255163953Srrs error = sctp_peeraddr(so, nam); 1256163953Srrs if (error) { 1257163953Srrs return (error); 1258163953Srrs } 1259163953Srrs /* if I'm V6ONLY, convert it to v4-mapped */ 1260166023Srrs if (SCTP_IPV6_V6ONLY(inp6)) { 1261163953Srrs struct sockaddr_in6 sin6; 1262163953Srrs 1263163953Srrs in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6); 1264163953Srrs memcpy(addr, &sin6, sizeof(struct sockaddr_in6)); 1265163953Srrs } 1266163953Srrs } 1267163953Srrs return error; 1268163953Srrs} 1269163953Srrs 1270163953Srrsstruct pr_usrreqs sctp6_usrreqs = { 1271163953Srrs .pru_abort = sctp6_abort, 1272163953Srrs .pru_accept = sctp_accept, 1273163953Srrs .pru_attach = sctp6_attach, 1274163953Srrs .pru_bind = sctp6_bind, 1275163953Srrs .pru_connect = sctp6_connect, 1276163953Srrs .pru_control = in6_control, 1277163953Srrs .pru_close = sctp6_close, 1278163953Srrs .pru_detach = sctp6_close, 1279163953Srrs .pru_sopoll = sopoll_generic, 1280178201Srrs .pru_flush = sctp_flush, 1281163953Srrs .pru_disconnect = sctp6_disconnect, 1282163953Srrs .pru_listen = sctp_listen, 1283163953Srrs .pru_peeraddr = sctp6_getpeeraddr, 1284163953Srrs .pru_send = sctp6_send, 1285163953Srrs .pru_shutdown = sctp_shutdown, 1286163953Srrs .pru_sockaddr = sctp6_in6getaddr, 1287163953Srrs .pru_sosend = sctp_sosend, 1288163953Srrs .pru_soreceive = sctp_soreceive 1289163953Srrs}; 1290