sctp6_usrreq.c revision 218319
1290000Sglebius/*- 2182007Sroberto * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. 3290000Sglebius * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved. 4290000Sglebius * Copyright (c) 2008-2011, by Michael Tuexen. All rights reserved. 5290000Sglebius * 6182007Sroberto * Redistribution and use in source and binary forms, with or without 7182007Sroberto * modification, are permitted provided that the following conditions are met: 8182007Sroberto * 9290000Sglebius * a) Redistributions of source code must retain the above copyright notice, 10290000Sglebius * this list of conditions and the following disclaimer. 11290000Sglebius * 12290000Sglebius * b) Redistributions in binary form must reproduce the above copyright 13290000Sglebius * notice, this list of conditions and the following disclaimer in 14290000Sglebius * the documentation and/or other materials provided with the distribution. 15290000Sglebius * 16290000Sglebius * c) Neither the name of Cisco Systems, Inc. nor the names of its 17132451Sroberto * contributors may be used to endorse or promote products derived 18290000Sglebius * from this software without specific prior written permission. 19290000Sglebius * 20182007Sroberto * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21290000Sglebius * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22290000Sglebius * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23290000Sglebius * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24290000Sglebius * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25290000Sglebius * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26290000Sglebius * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27290000Sglebius * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28290000Sglebius * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29290000Sglebius * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30182007Sroberto * THE POSSIBILITY OF SUCH DAMAGE. 31290000Sglebius */ 32290000Sglebius/* $KAME: sctp6_usrreq.c,v 1.38 2005/08/24 08:08:56 suz Exp $ */ 33290000Sglebius 34290000Sglebius#include <sys/cdefs.h> 35290000Sglebius__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_usrreq.c 218319 2011-02-05 12:12:51Z rrs $"); 36290000Sglebius 37290000Sglebius#include <netinet/sctp_os.h> 38290000Sglebius#include <sys/proc.h> 39290000Sglebius#include <netinet/sctp_pcb.h> 40290000Sglebius#include <netinet/sctp_header.h> 41182007Sroberto#include <netinet/sctp_var.h> 42290000Sglebius#if defined(INET6) 43290000Sglebius#include <netinet6/sctp6_var.h> 44290000Sglebius#endif 45290000Sglebius#include <netinet/sctp_sysctl.h> 46290000Sglebius#include <netinet/sctp_output.h> 47290000Sglebius#include <netinet/sctp_uio.h> 48290000Sglebius#include <netinet/sctp_asconf.h> 49290000Sglebius#include <netinet/sctputil.h> 50290000Sglebius#include <netinet/sctp_indata.h> 51290000Sglebius#include <netinet/sctp_timer.h> 52290000Sglebius#include <netinet/sctp_auth.h> 53290000Sglebius#include <netinet/sctp_input.h> 54290000Sglebius#include <netinet/sctp_output.h> 55290000Sglebius#include <netinet/sctp_bsd_addr.h> 56290000Sglebius#include <netinet/sctp_crc32.h> 57290000Sglebius#include <netinet/udp.h> 58290000Sglebius 59290000Sglebius#ifdef IPSEC 60290000Sglebius#include <netipsec/ipsec.h> 61290000Sglebius#if defined(INET6) 62290000Sglebius#include <netipsec/ipsec6.h> 63290000Sglebius#endif /* INET6 */ 64290000Sglebius#endif /* IPSEC */ 65290000Sglebius 66290000Sglebiusextern struct protosw inetsw[]; 67290000Sglebius 68290000Sglebiusint 69290000Sglebiussctp6_input(struct mbuf **i_pak, int *offp, int proto) 70290000Sglebius{ 71290000Sglebius struct mbuf *m; 72290000Sglebius struct ip6_hdr *ip6; 73290000Sglebius struct sctphdr *sh; 74290000Sglebius struct sctp_inpcb *in6p = NULL; 75290000Sglebius struct sctp_nets *net; 76290000Sglebius int refcount_up = 0; 77290000Sglebius uint32_t vrf_id = 0; 78290000Sglebius 79290000Sglebius#ifdef IPSEC 80290000Sglebius struct inpcb *in6p_ip; 81290000Sglebius 82290000Sglebius#endif 83290000Sglebius struct sctp_chunkhdr *ch; 84290000Sglebius int length, offset, iphlen; 85290000Sglebius uint8_t ecn_bits; 86290000Sglebius struct sctp_tcb *stcb = NULL; 87290000Sglebius int pkt_len = 0; 88290000Sglebius 89290000Sglebius#if !defined(SCTP_WITH_NO_CSUM) 90290000Sglebius uint32_t check, calc_check; 91290000Sglebius 92290000Sglebius#endif 93290000Sglebius int off = *offp; 94290000Sglebius uint16_t port = 0; 95290000Sglebius 96290000Sglebius /* get the VRF and table id's */ 97290000Sglebius if (SCTP_GET_PKT_VRFID(*i_pak, vrf_id)) { 98290000Sglebius SCTP_RELEASE_PKT(*i_pak); 99290000Sglebius return (-1); 100290000Sglebius } 101290000Sglebius m = SCTP_HEADER_TO_CHAIN(*i_pak); 102290000Sglebius pkt_len = SCTP_HEADER_LEN((*i_pak)); 103290000Sglebius 104290000Sglebius#ifdef SCTP_PACKET_LOGGING 105290000Sglebius sctp_packet_log(m, pkt_len); 106290000Sglebius#endif 107290000Sglebius ip6 = mtod(m, struct ip6_hdr *); 108290000Sglebius /* Ensure that (sctphdr + sctp_chunkhdr) in a row. */ 109290000Sglebius IP6_EXTHDR_GET(sh, struct sctphdr *, m, off, 110290000Sglebius (int)(sizeof(*sh) + sizeof(*ch))); 111290000Sglebius if (sh == NULL) { 112290000Sglebius SCTP_STAT_INCR(sctps_hdrops); 113290000Sglebius return IPPROTO_DONE; 114290000Sglebius } 115290000Sglebius ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); 116290000Sglebius iphlen = off; 117290000Sglebius offset = iphlen + sizeof(*sh) + sizeof(*ch); 118290000Sglebius SCTPDBG(SCTP_DEBUG_INPUT1, 119290000Sglebius "sctp6_input() length:%d iphlen:%d\n", pkt_len, iphlen); 120290000Sglebius 121290000Sglebius 122290000Sglebius#if defined(NFAITH) && NFAITH > 0 123290000Sglebius 124290000Sglebius if (faithprefix_p != NULL && (*faithprefix_p) (&ip6->ip6_dst)) { 125290000Sglebius /* XXX send icmp6 host/port unreach? */ 126290000Sglebius goto bad; 127290000Sglebius } 128290000Sglebius#endif /* NFAITH defined and > 0 */ 129290000Sglebius SCTP_STAT_INCR(sctps_recvpackets); 130290000Sglebius SCTP_STAT_INCR_COUNTER64(sctps_inpackets); 131290000Sglebius SCTPDBG(SCTP_DEBUG_INPUT1, "V6 input gets a packet iphlen:%d pktlen:%d\n", 132290000Sglebius iphlen, pkt_len); 133290000Sglebius if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 134290000Sglebius /* No multi-cast support in SCTP */ 135290000Sglebius goto bad; 136290000Sglebius } 137290000Sglebius /* destination port of 0 is illegal, based on RFC2960. */ 138290000Sglebius if (sh->dest_port == 0) 139290000Sglebius goto bad; 140290000Sglebius 141290000Sglebius SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, 142290000Sglebius "sctp_input(): Packet of length %d received on %s with csum_flags 0x%x.\n", 143290000Sglebius m->m_pkthdr.len, 144290000Sglebius if_name(m->m_pkthdr.rcvif), 145290000Sglebius m->m_pkthdr.csum_flags); 146290000Sglebius#if defined(SCTP_WITH_NO_CSUM) 147182007Sroberto SCTP_STAT_INCR(sctps_recvnocrc); 148290000Sglebius#else 149290000Sglebius if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) { 150290000Sglebius SCTP_STAT_INCR(sctps_recvhwcrc); 15154359Sroberto goto sctp_skip_csum; 15254359Sroberto } 153290000Sglebius check = sh->checksum; /* save incoming checksum */ 15454359Sroberto if ((check == 0) && (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback)) && 155290000Sglebius (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &ip6->ip6_dst))) { 156290000Sglebius SCTP_STAT_INCR(sctps_recvnocrc); 157290000Sglebius goto sctp_skip_csum; 158290000Sglebius } 159290000Sglebius sh->checksum = 0; /* prepare for calc */ 16054359Sroberto calc_check = sctp_calculate_cksum(m, iphlen); 161290000Sglebius SCTP_STAT_INCR(sctps_recvswcrc); 162290000Sglebius if (calc_check != check) { 163290000Sglebius SCTPDBG(SCTP_DEBUG_INPUT1, "Bad CSUM on SCTP packet calc_check:%x check:%x m:%p phlen:%d\n", 164290000Sglebius calc_check, check, m, iphlen); 165290000Sglebius stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch), 166290000Sglebius sh, ch, &in6p, &net, vrf_id); 167290000Sglebius if ((net) && (port)) { 168290000Sglebius if (net->port == 0) { 169290000Sglebius sctp_pathmtu_adjustment(in6p, stcb, net, net->mtu - sizeof(struct udphdr)); 170290000Sglebius } 171290000Sglebius net->port = port; 172290000Sglebius } 173290000Sglebius /* in6p's ref-count increased && stcb locked */ 174290000Sglebius if ((in6p) && (stcb)) { 17554359Sroberto sctp_send_packet_dropped(stcb, net, m, iphlen, 1); 176290000Sglebius sctp_chunk_output((struct sctp_inpcb *)in6p, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR, SCTP_SO_NOT_LOCKED); 177290000Sglebius } else if ((in6p != NULL) && (stcb == NULL)) { 178290000Sglebius refcount_up = 1; 179290000Sglebius } 180290000Sglebius SCTP_STAT_INCR(sctps_badsum); 181290000Sglebius SCTP_STAT_INCR_COUNTER32(sctps_checksumerrors); 182290000Sglebius goto bad; 183290000Sglebius } 184290000Sglebius sh->checksum = calc_check; 185290000Sglebius 186290000Sglebiussctp_skip_csum: 187290000Sglebius#endif 188290000Sglebius net = NULL; 189290000Sglebius /* 190290000Sglebius * Locate pcb and tcb for datagram sctp_findassociation_addr() wants 191290000Sglebius * IP/SCTP/first chunk header... 192290000Sglebius */ 193290000Sglebius stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch), 194290000Sglebius sh, ch, &in6p, &net, vrf_id); 195290000Sglebius if ((net) && (port)) { 196290000Sglebius if (net->port == 0) { 197290000Sglebius sctp_pathmtu_adjustment(in6p, stcb, net, net->mtu - sizeof(struct udphdr)); 198290000Sglebius } 199290000Sglebius net->port = port; 200290000Sglebius } 201290000Sglebius /* in6p's ref-count increased */ 202290000Sglebius if (in6p == NULL) { 203290000Sglebius struct sctp_init_chunk *init_chk, chunk_buf; 204290000Sglebius 205290000Sglebius SCTP_STAT_INCR(sctps_noport); 206290000Sglebius if (ch->chunk_type == SCTP_INITIATION) { 207290000Sglebius /* 208290000Sglebius * we do a trick here to get the INIT tag, dig in 209290000Sglebius * and get the tag from the INIT and put it in the 210290000Sglebius * common header. 211290000Sglebius */ 212290000Sglebius init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m, 213290000Sglebius iphlen + sizeof(*sh), sizeof(*init_chk), 214290000Sglebius (uint8_t *) & chunk_buf); 215290000Sglebius if (init_chk) 216290000Sglebius sh->v_tag = init_chk->init.initiate_tag; 217290000Sglebius else 218290000Sglebius sh->v_tag = 0; 219290000Sglebius } 220290000Sglebius if (ch->chunk_type == SCTP_SHUTDOWN_ACK) { 221290000Sglebius sctp_send_shutdown_complete2(m, iphlen, sh, vrf_id, port); 222290000Sglebius goto bad; 223290000Sglebius } 224290000Sglebius if (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) { 225290000Sglebius goto bad; 226290000Sglebius } 227290000Sglebius if (ch->chunk_type != SCTP_ABORT_ASSOCIATION) 228290000Sglebius sctp_send_abort(m, iphlen, sh, 0, NULL, vrf_id, port); 229290000Sglebius goto bad; 230290000Sglebius } else if (stcb == NULL) { 231290000Sglebius refcount_up = 1; 232290000Sglebius } 233290000Sglebius#ifdef IPSEC 234290000Sglebius /* 235290000Sglebius * Check AH/ESP integrity. 236290000Sglebius */ 237290000Sglebius in6p_ip = (struct inpcb *)in6p; 238290000Sglebius if (in6p_ip && (ipsec6_in_reject(m, in6p_ip))) { 239290000Sglebius/* XXX */ 240290000Sglebius MODULE_GLOBAL(ipsec6stat).in_polvio++; 241290000Sglebius goto bad; 242290000Sglebius } 243290000Sglebius#endif /* IPSEC */ 244290000Sglebius 245290000Sglebius /* 246290000Sglebius * CONTROL chunk processing 247290000Sglebius */ 248290000Sglebius offset -= sizeof(*ch); 249290000Sglebius ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff); 250290000Sglebius 251290000Sglebius /* Length now holds the total packet length payload + iphlen */ 252290000Sglebius length = ntohs(ip6->ip6_plen) + iphlen; 253290000Sglebius 254290000Sglebius /* sa_ignore NO_NULL_CHK */ 255290000Sglebius sctp_common_input_processing(&m, iphlen, offset, length, sh, ch, 256290000Sglebius in6p, stcb, net, ecn_bits, vrf_id, port); 257290000Sglebius /* inp's ref-count reduced && stcb unlocked */ 258290000Sglebius /* XXX this stuff below gets moved to appropriate parts later... */ 259290000Sglebius if (m) 260290000Sglebius sctp_m_freem(m); 261290000Sglebius if ((in6p) && refcount_up) { 262290000Sglebius /* reduce ref-count */ 263290000Sglebius SCTP_INP_WLOCK(in6p); 264290000Sglebius SCTP_INP_DECR_REF(in6p); 265290000Sglebius SCTP_INP_WUNLOCK(in6p); 266290000Sglebius } 267290000Sglebius return IPPROTO_DONE; 268290000Sglebius 269290000Sglebiusbad: 270290000Sglebius if (stcb) { 271290000Sglebius SCTP_TCB_UNLOCK(stcb); 272290000Sglebius } 273290000Sglebius if ((in6p) && refcount_up) { 274290000Sglebius /* reduce ref-count */ 275290000Sglebius SCTP_INP_WLOCK(in6p); 276290000Sglebius SCTP_INP_DECR_REF(in6p); 277290000Sglebius SCTP_INP_WUNLOCK(in6p); 278290000Sglebius } 279290000Sglebius if (m) 280290000Sglebius sctp_m_freem(m); 281290000Sglebius return IPPROTO_DONE; 282290000Sglebius} 283290000Sglebius 284290000Sglebius 285290000Sglebiusstatic void 286290000Sglebiussctp6_notify_mbuf(struct sctp_inpcb *inp, struct icmp6_hdr *icmp6, 287290000Sglebius struct sctphdr *sh, struct sctp_tcb *stcb, struct sctp_nets *net) 288290000Sglebius{ 289290000Sglebius uint32_t nxtsz; 290290000Sglebius 291290000Sglebius if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 292290000Sglebius (icmp6 == NULL) || (sh == NULL)) { 293290000Sglebius goto out; 294290000Sglebius } 295290000Sglebius /* First do we even look at it? */ 296290000Sglebius if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) 297290000Sglebius goto out; 298290000Sglebius 299290000Sglebius if (icmp6->icmp6_type != ICMP6_PACKET_TOO_BIG) { 300290000Sglebius /* not PACKET TO BIG */ 301182007Sroberto goto out; 302290000Sglebius } 303290000Sglebius /* 304182007Sroberto * ok we need to look closely. We could even get smarter and look at 305182007Sroberto * anyone that we sent to in case we get a different ICMP that tells 306182007Sroberto * us there is no way to reach a host, but for this impl, all we 307290000Sglebius * care about is MTU discovery. 308182007Sroberto */ 309290000Sglebius nxtsz = ntohl(icmp6->icmp6_mtu); 310290000Sglebius /* Stop any PMTU timer */ 311182007Sroberto sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL, SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_1); 312290000Sglebius 313290000Sglebius /* Adjust destination size limit */ 314290000Sglebius if (net->mtu > nxtsz) { 315182007Sroberto net->mtu = nxtsz; 316290000Sglebius if (net->port) { 317182007Sroberto net->mtu -= sizeof(struct udphdr); 318290000Sglebius } 319290000Sglebius } 320182007Sroberto /* now what about the ep? */ 321290000Sglebius if (stcb->asoc.smallest_mtu > nxtsz) { 322290000Sglebius struct sctp_tmit_chunk *chk; 323290000Sglebius 324290000Sglebius /* Adjust that too */ 325290000Sglebius stcb->asoc.smallest_mtu = nxtsz; 326290000Sglebius /* now off to subtract IP_DF flag if needed */ 327290000Sglebius 328290000Sglebius TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) { 329290000Sglebius if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) { 330290000Sglebius chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 331290000Sglebius } 332290000Sglebius } 333290000Sglebius TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 334290000Sglebius if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) { 335290000Sglebius /* 336290000Sglebius * For this guy we also mark for immediate 337290000Sglebius * resend since we sent to big of chunk 338290000Sglebius */ 339290000Sglebius chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 340290000Sglebius if (chk->sent != SCTP_DATAGRAM_RESEND) 341290000Sglebius stcb->asoc.sent_queue_retran_cnt++; 342290000Sglebius chk->sent = SCTP_DATAGRAM_RESEND; 343290000Sglebius chk->rec.data.doing_fast_retransmit = 0; 344290000Sglebius 345290000Sglebius chk->sent = SCTP_DATAGRAM_RESEND; 346290000Sglebius /* Clear any time so NO RTT is being done */ 347290000Sglebius chk->sent_rcv_time.tv_sec = 0; 348290000Sglebius chk->sent_rcv_time.tv_usec = 0; 349290000Sglebius stcb->asoc.total_flight -= chk->send_size; 350290000Sglebius net->flight_size -= chk->send_size; 351290000Sglebius } 352290000Sglebius } 353290000Sglebius } 354290000Sglebius sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL); 355290000Sglebiusout: 356290000Sglebius if (stcb) { 357290000Sglebius SCTP_TCB_UNLOCK(stcb); 358290000Sglebius } 359290000Sglebius} 360290000Sglebius 361290000Sglebius 362290000Sglebiusvoid 363290000Sglebiussctp6_notify(struct sctp_inpcb *inp, 364290000Sglebius struct icmp6_hdr *icmph, 365290000Sglebius struct sctphdr *sh, 366290000Sglebius struct sockaddr *to, 367290000Sglebius struct sctp_tcb *stcb, 368290000Sglebius struct sctp_nets *net) 369290000Sglebius{ 370290000Sglebius#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 371290000Sglebius struct socket *so; 372290000Sglebius 373290000Sglebius#endif 374290000Sglebius /* protection */ 375290000Sglebius int reason; 376290000Sglebius 377290000Sglebius 378290000Sglebius if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 379290000Sglebius (sh == NULL) || (to == NULL)) { 380290000Sglebius if (stcb) 381290000Sglebius SCTP_TCB_UNLOCK(stcb); 382290000Sglebius return; 383290000Sglebius } 384290000Sglebius /* First job is to verify the vtag matches what I would send */ 385290000Sglebius if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 386290000Sglebius SCTP_TCB_UNLOCK(stcb); 387290000Sglebius return; 388290000Sglebius } 389290000Sglebius if (icmph->icmp6_type != ICMP_UNREACH) { 390290000Sglebius /* We only care about unreachable */ 391290000Sglebius SCTP_TCB_UNLOCK(stcb); 392290000Sglebius return; 393290000Sglebius } 394290000Sglebius if ((icmph->icmp6_code == ICMP_UNREACH_NET) || 395290000Sglebius (icmph->icmp6_code == ICMP_UNREACH_HOST) || 396290000Sglebius (icmph->icmp6_code == ICMP_UNREACH_NET_UNKNOWN) || 397290000Sglebius (icmph->icmp6_code == ICMP_UNREACH_HOST_UNKNOWN) || 398290000Sglebius (icmph->icmp6_code == ICMP_UNREACH_ISOLATED) || 399290000Sglebius (icmph->icmp6_code == ICMP_UNREACH_NET_PROHIB) || 400290000Sglebius (icmph->icmp6_code == ICMP_UNREACH_HOST_PROHIB) || 401290000Sglebius (icmph->icmp6_code == ICMP_UNREACH_FILTER_PROHIB)) { 402290000Sglebius 403290000Sglebius /* 404290000Sglebius * Hmm reachablity problems we must examine closely. If its 405290000Sglebius * not reachable, we may have lost a network. Or if there is 406290000Sglebius * NO protocol at the other end named SCTP. well we consider 407290000Sglebius * it a OOTB abort. 408290000Sglebius */ 409290000Sglebius if (net->dest_state & SCTP_ADDR_REACHABLE) { 410290000Sglebius /* Ok that destination is NOT reachable */ 41154359Sroberto SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n", 41254359Sroberto net->error_count, 413290000Sglebius net->failure_threshold, 414290000Sglebius net); 41554359Sroberto 416290000Sglebius net->dest_state &= ~SCTP_ADDR_REACHABLE; 417290000Sglebius net->dest_state |= SCTP_ADDR_NOT_REACHABLE; 418290000Sglebius /* 419290000Sglebius * JRS 5/14/07 - If a destination is unreachable, 420182007Sroberto * the PF bit is turned off. This allows an 421290000Sglebius * unambiguous use of the PF bit for destinations 422182007Sroberto * that are reachable but potentially failed. If the 42354359Sroberto * destination is set to the unreachable state, also 424290000Sglebius * set the destination to the PF state. 42554359Sroberto */ 426290000Sglebius /* 427290000Sglebius * Add debug message here if destination is not in 428182007Sroberto * PF state. 429290000Sglebius */ 430290000Sglebius /* Stop any running T3 timers here? */ 431182007Sroberto if ((stcb->asoc.sctp_cmt_on_off > 0) && 432290000Sglebius (stcb->asoc.sctp_cmt_pf > 0)) { 433290000Sglebius net->dest_state &= ~SCTP_ADDR_PF; 434290000Sglebius SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n", 435290000Sglebius net); 436290000Sglebius } 437290000Sglebius net->error_count = net->failure_threshold + 1; 438290000Sglebius sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, 439290000Sglebius stcb, SCTP_FAILED_THRESHOLD, 440290000Sglebius (void *)net, SCTP_SO_NOT_LOCKED); 441290000Sglebius } 442290000Sglebius SCTP_TCB_UNLOCK(stcb); 443 } else if ((icmph->icmp6_code == ICMP_UNREACH_PROTOCOL) || 444 (icmph->icmp6_code == ICMP_UNREACH_PORT)) { 445 /* 446 * Here the peer is either playing tricks on us, including 447 * an address that belongs to someone who does not support 448 * SCTP OR was a userland implementation that shutdown and 449 * now is dead. In either case treat it like a OOTB abort 450 * with no TCB 451 */ 452 reason = SCTP_PEER_FAULTY; 453 sctp_abort_notification(stcb, reason, SCTP_SO_NOT_LOCKED); 454#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 455 so = SCTP_INP_SO(inp); 456 atomic_add_int(&stcb->asoc.refcnt, 1); 457 SCTP_TCB_UNLOCK(stcb); 458 SCTP_SOCKET_LOCK(so, 1); 459 SCTP_TCB_LOCK(stcb); 460 atomic_subtract_int(&stcb->asoc.refcnt, 1); 461#endif 462 (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); 463#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 464 SCTP_SOCKET_UNLOCK(so, 1); 465 /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */ 466#endif 467 /* no need to unlock here, since the TCB is gone */ 468 } else { 469 SCTP_TCB_UNLOCK(stcb); 470 } 471} 472 473 474 475void 476sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d) 477{ 478 struct sctphdr sh; 479 struct ip6ctlparam *ip6cp = NULL; 480 uint32_t vrf_id; 481 482 vrf_id = SCTP_DEFAULT_VRFID; 483 484 if (pktdst->sa_family != AF_INET6 || 485 pktdst->sa_len != sizeof(struct sockaddr_in6)) 486 return; 487 488 if ((unsigned)cmd >= PRC_NCMDS) 489 return; 490 if (PRC_IS_REDIRECT(cmd)) { 491 d = NULL; 492 } else if (inet6ctlerrmap[cmd] == 0) { 493 return; 494 } 495 /* if the parameter is from icmp6, decode it. */ 496 if (d != NULL) { 497 ip6cp = (struct ip6ctlparam *)d; 498 } else { 499 ip6cp = (struct ip6ctlparam *)NULL; 500 } 501 502 if (ip6cp) { 503 /* 504 * XXX: We assume that when IPV6 is non NULL, M and OFF are 505 * valid. 506 */ 507 /* check if we can safely examine src and dst ports */ 508 struct sctp_inpcb *inp = NULL; 509 struct sctp_tcb *stcb = NULL; 510 struct sctp_nets *net = NULL; 511 struct sockaddr_in6 final; 512 513 if (ip6cp->ip6c_m == NULL) 514 return; 515 516 bzero(&sh, sizeof(sh)); 517 bzero(&final, sizeof(final)); 518 inp = NULL; 519 net = NULL; 520 m_copydata(ip6cp->ip6c_m, ip6cp->ip6c_off, sizeof(sh), 521 (caddr_t)&sh); 522 ip6cp->ip6c_src->sin6_port = sh.src_port; 523 final.sin6_len = sizeof(final); 524 final.sin6_family = AF_INET6; 525 final.sin6_addr = ((struct sockaddr_in6 *)pktdst)->sin6_addr; 526 final.sin6_port = sh.dest_port; 527 stcb = sctp_findassociation_addr_sa((struct sockaddr *)ip6cp->ip6c_src, 528 (struct sockaddr *)&final, 529 &inp, &net, 1, vrf_id); 530 /* inp's ref-count increased && stcb locked */ 531 if (stcb != NULL && inp && (inp->sctp_socket != NULL)) { 532 if (cmd == PRC_MSGSIZE) { 533 sctp6_notify_mbuf(inp, 534 ip6cp->ip6c_icmp6, 535 &sh, 536 stcb, 537 net); 538 /* inp's ref-count reduced && stcb unlocked */ 539 } else { 540 sctp6_notify(inp, ip6cp->ip6c_icmp6, &sh, 541 (struct sockaddr *)&final, 542 stcb, net); 543 /* inp's ref-count reduced && stcb unlocked */ 544 } 545 } else { 546 if (PRC_IS_REDIRECT(cmd) && inp) { 547 in6_rtchange((struct in6pcb *)inp, 548 inet6ctlerrmap[cmd]); 549 } 550 if (inp) { 551 /* reduce inp's ref-count */ 552 SCTP_INP_WLOCK(inp); 553 SCTP_INP_DECR_REF(inp); 554 SCTP_INP_WUNLOCK(inp); 555 } 556 if (stcb) 557 SCTP_TCB_UNLOCK(stcb); 558 } 559 } 560} 561 562/* 563 * this routine can probably be collasped into the one in sctp_userreq.c 564 * since they do the same thing and now we lookup with a sockaddr 565 */ 566static int 567sctp6_getcred(SYSCTL_HANDLER_ARGS) 568{ 569 struct xucred xuc; 570 struct sockaddr_in6 addrs[2]; 571 struct sctp_inpcb *inp; 572 struct sctp_nets *net; 573 struct sctp_tcb *stcb; 574 int error; 575 uint32_t vrf_id; 576 577 vrf_id = SCTP_DEFAULT_VRFID; 578 579 error = priv_check(req->td, PRIV_NETINET_GETCRED); 580 if (error) 581 return (error); 582 583 if (req->newlen != sizeof(addrs)) { 584 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 585 return (EINVAL); 586 } 587 if (req->oldlen != sizeof(struct ucred)) { 588 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 589 return (EINVAL); 590 } 591 error = SYSCTL_IN(req, addrs, sizeof(addrs)); 592 if (error) 593 return (error); 594 595 stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[0]), 596 sin6tosa(&addrs[1]), 597 &inp, &net, 1, vrf_id); 598 if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) { 599 if ((inp != NULL) && (stcb == NULL)) { 600 /* reduce ref-count */ 601 SCTP_INP_WLOCK(inp); 602 SCTP_INP_DECR_REF(inp); 603 goto cred_can_cont; 604 } 605 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT); 606 error = ENOENT; 607 goto out; 608 } 609 SCTP_TCB_UNLOCK(stcb); 610 /* 611 * We use the write lock here, only since in the error leg we need 612 * it. If we used RLOCK, then we would have to 613 * wlock/decr/unlock/rlock. Which in theory could create a hole. 614 * Better to use higher wlock. 615 */ 616 SCTP_INP_WLOCK(inp); 617cred_can_cont: 618 error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket); 619 if (error) { 620 SCTP_INP_WUNLOCK(inp); 621 goto out; 622 } 623 cru2x(inp->sctp_socket->so_cred, &xuc); 624 SCTP_INP_WUNLOCK(inp); 625 error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); 626out: 627 return (error); 628} 629 630SYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW, 631 0, 0, 632 sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection"); 633 634 635/* This is the same as the sctp_abort() could be made common */ 636static void 637sctp6_abort(struct socket *so) 638{ 639 struct sctp_inpcb *inp; 640 uint32_t flags; 641 642 inp = (struct sctp_inpcb *)so->so_pcb; 643 if (inp == 0) { 644 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 645 return; 646 } 647sctp_must_try_again: 648 flags = inp->sctp_flags; 649#ifdef SCTP_LOG_CLOSING 650 sctp_log_closing(inp, NULL, 17); 651#endif 652 if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 653 (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 654#ifdef SCTP_LOG_CLOSING 655 sctp_log_closing(inp, NULL, 16); 656#endif 657 sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 658 SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 659 SOCK_LOCK(so); 660 SCTP_SB_CLEAR(so->so_snd); 661 /* 662 * same for the rcv ones, they are only here for the 663 * accounting/select. 664 */ 665 SCTP_SB_CLEAR(so->so_rcv); 666 /* Now null out the reference, we are completely detached. */ 667 so->so_pcb = NULL; 668 SOCK_UNLOCK(so); 669 } else { 670 flags = inp->sctp_flags; 671 if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 672 goto sctp_must_try_again; 673 } 674 } 675 return; 676} 677 678static int 679sctp6_attach(struct socket *so, int proto, struct thread *p) 680{ 681 struct in6pcb *inp6; 682 int error; 683 struct sctp_inpcb *inp; 684 uint32_t vrf_id = SCTP_DEFAULT_VRFID; 685 686 inp = (struct sctp_inpcb *)so->so_pcb; 687 if (inp != NULL) { 688 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 689 return EINVAL; 690 } 691 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 692 error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace)); 693 if (error) 694 return error; 695 } 696 error = sctp_inpcb_alloc(so, vrf_id); 697 if (error) 698 return error; 699 inp = (struct sctp_inpcb *)so->so_pcb; 700 SCTP_INP_WLOCK(inp); 701 inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6; /* I'm v6! */ 702 inp6 = (struct in6pcb *)inp; 703 704 inp6->inp_vflag |= INP_IPV6; 705 inp6->in6p_hops = -1; /* use kernel default */ 706 inp6->in6p_cksum = -1; /* just to be sure */ 707#ifdef INET 708 /* 709 * XXX: ugly!! IPv4 TTL initialization is necessary for an IPv6 710 * socket as well, because the socket may be bound to an IPv6 711 * wildcard address, which may match an IPv4-mapped IPv6 address. 712 */ 713 inp6->inp_ip_ttl = MODULE_GLOBAL(ip_defttl); 714#endif 715 /* 716 * Hmm what about the IPSEC stuff that is missing here but in 717 * sctp_attach()? 718 */ 719 SCTP_INP_WUNLOCK(inp); 720 return 0; 721} 722 723static int 724sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p) 725{ 726 struct sctp_inpcb *inp; 727 struct in6pcb *inp6; 728 int error; 729 730 inp = (struct sctp_inpcb *)so->so_pcb; 731 if (inp == 0) { 732 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 733 return EINVAL; 734 } 735 if (addr) { 736 if ((addr->sa_family == AF_INET6) && 737 (addr->sa_len != sizeof(struct sockaddr_in6))) { 738 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 739 return EINVAL; 740 } 741 if ((addr->sa_family == AF_INET) && 742 (addr->sa_len != sizeof(struct sockaddr_in))) { 743 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 744 return EINVAL; 745 } 746 } 747 inp6 = (struct in6pcb *)inp; 748 inp6->inp_vflag &= ~INP_IPV4; 749 inp6->inp_vflag |= INP_IPV6; 750 if ((addr != NULL) && (SCTP_IPV6_V6ONLY(inp6) == 0)) { 751 if (addr->sa_family == AF_INET) { 752 /* binding v4 addr to v6 socket, so reset flags */ 753 inp6->inp_vflag |= INP_IPV4; 754 inp6->inp_vflag &= ~INP_IPV6; 755 } else { 756 struct sockaddr_in6 *sin6_p; 757 758 sin6_p = (struct sockaddr_in6 *)addr; 759 760 if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) { 761 inp6->inp_vflag |= INP_IPV4; 762 } else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { 763 struct sockaddr_in sin; 764 765 in6_sin6_2_sin(&sin, sin6_p); 766 inp6->inp_vflag |= INP_IPV4; 767 inp6->inp_vflag &= ~INP_IPV6; 768 error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, NULL, p); 769 return error; 770 } 771 } 772 } else if (addr != NULL) { 773 /* IPV6_V6ONLY socket */ 774 if (addr->sa_family == AF_INET) { 775 /* can't bind v4 addr to v6 only socket! */ 776 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 777 return EINVAL; 778 } else { 779 struct sockaddr_in6 *sin6_p; 780 781 sin6_p = (struct sockaddr_in6 *)addr; 782 783 if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { 784 /* can't bind v4-mapped addrs either! */ 785 /* NOTE: we don't support SIIT */ 786 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 787 return EINVAL; 788 } 789 } 790 } 791 error = sctp_inpcb_bind(so, addr, NULL, p); 792 return error; 793} 794 795 796static void 797sctp6_close(struct socket *so) 798{ 799 sctp_close(so); 800} 801 802/* This could be made common with sctp_detach() since they are identical */ 803 804static 805int 806sctp6_disconnect(struct socket *so) 807{ 808 return (sctp_disconnect(so)); 809} 810 811 812int 813sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 814 struct mbuf *control, struct thread *p); 815 816 817static int 818sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 819 struct mbuf *control, struct thread *p) 820{ 821 struct sctp_inpcb *inp; 822 struct in6pcb *inp6; 823 824#ifdef INET 825 struct sockaddr_in6 *sin6; 826 827#endif /* INET */ 828 /* No SPL needed since sctp_output does this */ 829 830 inp = (struct sctp_inpcb *)so->so_pcb; 831 if (inp == NULL) { 832 if (control) { 833 SCTP_RELEASE_PKT(control); 834 control = NULL; 835 } 836 SCTP_RELEASE_PKT(m); 837 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 838 return EINVAL; 839 } 840 inp6 = (struct in6pcb *)inp; 841 /* 842 * For the TCP model we may get a NULL addr, if we are a connected 843 * socket thats ok. 844 */ 845 if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) && 846 (addr == NULL)) { 847 goto connected_type; 848 } 849 if (addr == NULL) { 850 SCTP_RELEASE_PKT(m); 851 if (control) { 852 SCTP_RELEASE_PKT(control); 853 control = NULL; 854 } 855 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EDESTADDRREQ); 856 return (EDESTADDRREQ); 857 } 858#ifdef INET 859 sin6 = (struct sockaddr_in6 *)addr; 860 if (SCTP_IPV6_V6ONLY(inp6)) { 861 /* 862 * if IPV6_V6ONLY flag, we discard datagrams destined to a 863 * v4 addr or v4-mapped addr 864 */ 865 if (addr->sa_family == AF_INET) { 866 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 867 return EINVAL; 868 } 869 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 870 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 871 return EINVAL; 872 } 873 } 874 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 875 if (!MODULE_GLOBAL(ip6_v6only)) { 876 struct sockaddr_in sin; 877 878 /* convert v4-mapped into v4 addr and send */ 879 in6_sin6_2_sin(&sin, sin6); 880 return sctp_sendm(so, flags, m, (struct sockaddr *)&sin, 881 control, p); 882 } else { 883 /* mapped addresses aren't enabled */ 884 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 885 return EINVAL; 886 } 887 } 888#endif /* INET */ 889connected_type: 890 /* now what about control */ 891 if (control) { 892 if (inp->control) { 893 SCTP_PRINTF("huh? control set?\n"); 894 SCTP_RELEASE_PKT(inp->control); 895 inp->control = NULL; 896 } 897 inp->control = control; 898 } 899 /* Place the data */ 900 if (inp->pkt) { 901 SCTP_BUF_NEXT(inp->pkt_last) = m; 902 inp->pkt_last = m; 903 } else { 904 inp->pkt_last = inp->pkt = m; 905 } 906 if ( 907 /* FreeBSD and MacOSX uses a flag passed */ 908 ((flags & PRUS_MORETOCOME) == 0) 909 ) { 910 /* 911 * note with the current version this code will only be used 912 * by OpenBSD, NetBSD and FreeBSD have methods for 913 * re-defining sosend() to use sctp_sosend(). One can 914 * optionaly switch back to this code (by changing back the 915 * defininitions but this is not advisable. 916 */ 917 int ret; 918 919 ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags); 920 inp->pkt = NULL; 921 inp->control = NULL; 922 return (ret); 923 } else { 924 return (0); 925 } 926} 927 928static int 929sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p) 930{ 931 uint32_t vrf_id; 932 int error = 0; 933 struct sctp_inpcb *inp; 934 struct in6pcb *inp6; 935 struct sctp_tcb *stcb; 936 937#ifdef INET 938 struct sockaddr_in6 *sin6; 939 struct sockaddr_storage ss; 940 941#endif /* INET */ 942 943 inp6 = (struct in6pcb *)so->so_pcb; 944 inp = (struct sctp_inpcb *)so->so_pcb; 945 if (inp == 0) { 946 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET); 947 return (ECONNRESET); /* I made the same as TCP since we are 948 * not setup? */ 949 } 950 if (addr == NULL) { 951 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 952 return (EINVAL); 953 } 954 if ((addr->sa_family == AF_INET6) && (addr->sa_len != sizeof(struct sockaddr_in6))) { 955 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 956 return (EINVAL); 957 } 958 if ((addr->sa_family == AF_INET) && (addr->sa_len != sizeof(struct sockaddr_in))) { 959 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 960 return (EINVAL); 961 } 962 vrf_id = inp->def_vrf_id; 963 SCTP_ASOC_CREATE_LOCK(inp); 964 SCTP_INP_RLOCK(inp); 965 if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 966 SCTP_PCB_FLAGS_UNBOUND) { 967 /* Bind a ephemeral port */ 968 SCTP_INP_RUNLOCK(inp); 969 error = sctp6_bind(so, NULL, p); 970 if (error) { 971 SCTP_ASOC_CREATE_UNLOCK(inp); 972 973 return (error); 974 } 975 SCTP_INP_RLOCK(inp); 976 } 977 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 978 (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 979 /* We are already connected AND the TCP model */ 980 SCTP_INP_RUNLOCK(inp); 981 SCTP_ASOC_CREATE_UNLOCK(inp); 982 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EADDRINUSE); 983 return (EADDRINUSE); 984 } 985#ifdef INET 986 sin6 = (struct sockaddr_in6 *)addr; 987 if (SCTP_IPV6_V6ONLY(inp6)) { 988 /* 989 * if IPV6_V6ONLY flag, ignore connections destined to a v4 990 * addr or v4-mapped addr 991 */ 992 if (addr->sa_family == AF_INET) { 993 SCTP_INP_RUNLOCK(inp); 994 SCTP_ASOC_CREATE_UNLOCK(inp); 995 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 996 return EINVAL; 997 } 998 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 999 SCTP_INP_RUNLOCK(inp); 1000 SCTP_ASOC_CREATE_UNLOCK(inp); 1001 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1002 return EINVAL; 1003 } 1004 } 1005 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 1006 if (!MODULE_GLOBAL(ip6_v6only)) { 1007 /* convert v4-mapped into v4 addr */ 1008 in6_sin6_2_sin((struct sockaddr_in *)&ss, sin6); 1009 addr = (struct sockaddr *)&ss; 1010 } else { 1011 /* mapped addresses aren't enabled */ 1012 SCTP_INP_RUNLOCK(inp); 1013 SCTP_ASOC_CREATE_UNLOCK(inp); 1014 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1015 return EINVAL; 1016 } 1017 } else 1018#endif /* INET */ 1019 addr = addr; /* for true v6 address case */ 1020 1021 /* Now do we connect? */ 1022 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 1023 stcb = LIST_FIRST(&inp->sctp_asoc_list); 1024 if (stcb) { 1025 SCTP_TCB_UNLOCK(stcb); 1026 } 1027 SCTP_INP_RUNLOCK(inp); 1028 } else { 1029 SCTP_INP_RUNLOCK(inp); 1030 SCTP_INP_WLOCK(inp); 1031 SCTP_INP_INCR_REF(inp); 1032 SCTP_INP_WUNLOCK(inp); 1033 stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL); 1034 if (stcb == NULL) { 1035 SCTP_INP_WLOCK(inp); 1036 SCTP_INP_DECR_REF(inp); 1037 SCTP_INP_WUNLOCK(inp); 1038 } 1039 } 1040 1041 if (stcb != NULL) { 1042 /* Already have or am bring up an association */ 1043 SCTP_ASOC_CREATE_UNLOCK(inp); 1044 SCTP_TCB_UNLOCK(stcb); 1045 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EALREADY); 1046 return (EALREADY); 1047 } 1048 /* We are GOOD to go */ 1049 stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p); 1050 SCTP_ASOC_CREATE_UNLOCK(inp); 1051 if (stcb == NULL) { 1052 /* Gak! no memory */ 1053 return (error); 1054 } 1055 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 1056 stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 1057 /* Set the connected flag so we can queue data */ 1058 soisconnecting(so); 1059 } 1060 stcb->asoc.state = SCTP_STATE_COOKIE_WAIT; 1061 (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 1062 1063 /* initialize authentication parameters for the assoc */ 1064 sctp_initialize_auth_params(inp, stcb); 1065 1066 sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 1067 SCTP_TCB_UNLOCK(stcb); 1068 return error; 1069} 1070 1071static int 1072sctp6_getaddr(struct socket *so, struct sockaddr **addr) 1073{ 1074 struct sockaddr_in6 *sin6; 1075 struct sctp_inpcb *inp; 1076 uint32_t vrf_id; 1077 struct sctp_ifa *sctp_ifa; 1078 1079 int error; 1080 1081 /* 1082 * Do the malloc first in case it blocks. 1083 */ 1084 SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); 1085 if (sin6 == NULL) 1086 return ENOMEM; 1087 sin6->sin6_family = AF_INET6; 1088 sin6->sin6_len = sizeof(*sin6); 1089 1090 inp = (struct sctp_inpcb *)so->so_pcb; 1091 if (inp == NULL) { 1092 SCTP_FREE_SONAME(sin6); 1093 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET); 1094 return ECONNRESET; 1095 } 1096 SCTP_INP_RLOCK(inp); 1097 sin6->sin6_port = inp->sctp_lport; 1098 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1099 /* For the bound all case you get back 0 */ 1100 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 1101 struct sctp_tcb *stcb; 1102 struct sockaddr_in6 *sin_a6; 1103 struct sctp_nets *net; 1104 int fnd; 1105 1106 stcb = LIST_FIRST(&inp->sctp_asoc_list); 1107 if (stcb == NULL) { 1108 goto notConn6; 1109 } 1110 fnd = 0; 1111 sin_a6 = NULL; 1112 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1113 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr; 1114 if (sin_a6 == NULL) 1115 /* this will make coverity happy */ 1116 continue; 1117 1118 if (sin_a6->sin6_family == AF_INET6) { 1119 fnd = 1; 1120 break; 1121 } 1122 } 1123 if ((!fnd) || (sin_a6 == NULL)) { 1124 /* punt */ 1125 goto notConn6; 1126 } 1127 vrf_id = inp->def_vrf_id; 1128 sctp_ifa = sctp_source_address_selection(inp, stcb, (sctp_route_t *) & net->ro, net, 0, vrf_id); 1129 if (sctp_ifa) { 1130 sin6->sin6_addr = sctp_ifa->address.sin6.sin6_addr; 1131 } 1132 } else { 1133 /* For the bound all case you get back 0 */ 1134 notConn6: 1135 memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr)); 1136 } 1137 } else { 1138 /* Take the first IPv6 address in the list */ 1139 struct sctp_laddr *laddr; 1140 int fnd = 0; 1141 1142 LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1143 if (laddr->ifa->address.sa.sa_family == AF_INET6) { 1144 struct sockaddr_in6 *sin_a; 1145 1146 sin_a = (struct sockaddr_in6 *)&laddr->ifa->address.sin6; 1147 sin6->sin6_addr = sin_a->sin6_addr; 1148 fnd = 1; 1149 break; 1150 } 1151 } 1152 if (!fnd) { 1153 SCTP_FREE_SONAME(sin6); 1154 SCTP_INP_RUNLOCK(inp); 1155 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT); 1156 return ENOENT; 1157 } 1158 } 1159 SCTP_INP_RUNLOCK(inp); 1160 /* Scoping things for v6 */ 1161 if ((error = sa6_recoverscope(sin6)) != 0) { 1162 SCTP_FREE_SONAME(sin6); 1163 return (error); 1164 } 1165 (*addr) = (struct sockaddr *)sin6; 1166 return (0); 1167} 1168 1169static int 1170sctp6_peeraddr(struct socket *so, struct sockaddr **addr) 1171{ 1172 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)*addr; 1173 int fnd; 1174 struct sockaddr_in6 *sin_a6; 1175 struct sctp_inpcb *inp; 1176 struct sctp_tcb *stcb; 1177 struct sctp_nets *net; 1178 1179 int error; 1180 1181 /* 1182 * Do the malloc first in case it blocks. 1183 */ 1184 inp = (struct sctp_inpcb *)so->so_pcb; 1185 if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) { 1186 /* UDP type and listeners will drop out here */ 1187 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN); 1188 return (ENOTCONN); 1189 } 1190 SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); 1191 if (sin6 == NULL) 1192 return (ENOMEM); 1193 sin6->sin6_family = AF_INET6; 1194 sin6->sin6_len = sizeof(*sin6); 1195 1196 /* We must recapture incase we blocked */ 1197 inp = (struct sctp_inpcb *)so->so_pcb; 1198 if (inp == NULL) { 1199 SCTP_FREE_SONAME(sin6); 1200 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET); 1201 return ECONNRESET; 1202 } 1203 SCTP_INP_RLOCK(inp); 1204 stcb = LIST_FIRST(&inp->sctp_asoc_list); 1205 if (stcb) { 1206 SCTP_TCB_LOCK(stcb); 1207 } 1208 SCTP_INP_RUNLOCK(inp); 1209 if (stcb == NULL) { 1210 SCTP_FREE_SONAME(sin6); 1211 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET); 1212 return ECONNRESET; 1213 } 1214 fnd = 0; 1215 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1216 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr; 1217 if (sin_a6->sin6_family == AF_INET6) { 1218 fnd = 1; 1219 sin6->sin6_port = stcb->rport; 1220 sin6->sin6_addr = sin_a6->sin6_addr; 1221 break; 1222 } 1223 } 1224 SCTP_TCB_UNLOCK(stcb); 1225 if (!fnd) { 1226 /* No IPv4 address */ 1227 SCTP_FREE_SONAME(sin6); 1228 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT); 1229 return ENOENT; 1230 } 1231 if ((error = sa6_recoverscope(sin6)) != 0) 1232 return (error); 1233 *addr = (struct sockaddr *)sin6; 1234 return (0); 1235} 1236 1237static int 1238sctp6_in6getaddr(struct socket *so, struct sockaddr **nam) 1239{ 1240 struct sockaddr *addr; 1241 struct in6pcb *inp6 = sotoin6pcb(so); 1242 int error; 1243 1244 if (inp6 == NULL) { 1245 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1246 return EINVAL; 1247 } 1248 /* allow v6 addresses precedence */ 1249 error = sctp6_getaddr(so, nam); 1250 if (error) { 1251 /* try v4 next if v6 failed */ 1252 error = sctp_ingetaddr(so, nam); 1253 if (error) { 1254 return (error); 1255 } 1256 addr = *nam; 1257 /* if I'm V6ONLY, convert it to v4-mapped */ 1258 if (SCTP_IPV6_V6ONLY(inp6)) { 1259 struct sockaddr_in6 sin6; 1260 1261 in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6); 1262 memcpy(addr, &sin6, sizeof(struct sockaddr_in6)); 1263 1264 } 1265 } 1266 return (error); 1267} 1268 1269 1270static int 1271sctp6_getpeeraddr(struct socket *so, struct sockaddr **nam) 1272{ 1273 struct sockaddr *addr = *nam; 1274 struct in6pcb *inp6 = sotoin6pcb(so); 1275 int error; 1276 1277 if (inp6 == NULL) { 1278 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1279 return EINVAL; 1280 } 1281 /* allow v6 addresses precedence */ 1282 error = sctp6_peeraddr(so, nam); 1283 if (error) { 1284 /* try v4 next if v6 failed */ 1285 error = sctp_peeraddr(so, nam); 1286 if (error) { 1287 return (error); 1288 } 1289 /* if I'm V6ONLY, convert it to v4-mapped */ 1290 if (SCTP_IPV6_V6ONLY(inp6)) { 1291 struct sockaddr_in6 sin6; 1292 1293 in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6); 1294 memcpy(addr, &sin6, sizeof(struct sockaddr_in6)); 1295 } 1296 } 1297 return error; 1298} 1299 1300struct pr_usrreqs sctp6_usrreqs = { 1301 .pru_abort = sctp6_abort, 1302 .pru_accept = sctp_accept, 1303 .pru_attach = sctp6_attach, 1304 .pru_bind = sctp6_bind, 1305 .pru_connect = sctp6_connect, 1306 .pru_control = in6_control, 1307 .pru_close = sctp6_close, 1308 .pru_detach = sctp6_close, 1309 .pru_sopoll = sopoll_generic, 1310 .pru_flush = sctp_flush, 1311 .pru_disconnect = sctp6_disconnect, 1312 .pru_listen = sctp_listen, 1313 .pru_peeraddr = sctp6_getpeeraddr, 1314 .pru_send = sctp6_send, 1315 .pru_shutdown = sctp_shutdown, 1316 .pru_sockaddr = sctp6_in6getaddr, 1317 .pru_sosend = sctp_sosend, 1318 .pru_soreceive = sctp_soreceive 1319}; 1320