The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet6/sctp6_usrreq.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions are met:
    6  *
    7  * a) Redistributions of source code must retain the above copyright notice,
    8  *   this list of conditions and the following disclaimer.
    9  *
   10  * b) Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in
   12  *   the documentation and/or other materials provided with the distribution.
   13  *
   14  * c) Neither the name of Cisco Systems, Inc. nor the names of its
   15  *    contributors may be used to endorse or promote products derived
   16  *    from this software without specific prior written permission.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
   20  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   28  * THE POSSIBILITY OF SUCH DAMAGE.
   29  */
   30 /*      $KAME: sctp6_usrreq.c,v 1.38 2005/08/24 08:08:56 suz Exp $      */
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD$");
   34 
   35 #include <netinet/sctp_os.h>
   36 #include <sys/proc.h>
   37 #include <netinet/sctp_pcb.h>
   38 #include <netinet/sctp_header.h>
   39 #include <netinet/sctp_var.h>
   40 #if defined(INET6)
   41 #include <netinet6/sctp6_var.h>
   42 #endif
   43 #include <netinet/sctp_sysctl.h>
   44 #include <netinet/sctp_output.h>
   45 #include <netinet/sctp_uio.h>
   46 #include <netinet/sctp_asconf.h>
   47 #include <netinet/sctputil.h>
   48 #include <netinet/sctp_indata.h>
   49 #include <netinet/sctp_timer.h>
   50 #include <netinet/sctp_auth.h>
   51 #include <netinet/sctp_input.h>
   52 #include <netinet/sctp_output.h>
   53 #include <netinet/sctp_bsd_addr.h>
   54 #include <netinet/udp.h>
   55 
   56 #ifdef IPSEC
   57 #include <netipsec/ipsec.h>
   58 #if defined(INET6)
   59 #include <netipsec/ipsec6.h>
   60 #endif                          /* INET6 */
   61 #endif                          /* IPSEC */
   62 
   63 extern struct protosw inetsw[];
   64 
   65 int
   66 sctp6_input(struct mbuf **i_pak, int *offp, int proto)
   67 {
   68         struct mbuf *m;
   69         struct ip6_hdr *ip6;
   70         struct sctphdr *sh;
   71         struct sctp_inpcb *in6p = NULL;
   72         struct sctp_nets *net;
   73         int refcount_up = 0;
   74         uint32_t check, calc_check;
   75         uint32_t vrf_id = 0;
   76         struct inpcb *in6p_ip;
   77         struct sctp_chunkhdr *ch;
   78         int length, mlen, offset, iphlen;
   79         uint8_t ecn_bits;
   80         struct sctp_tcb *stcb = NULL;
   81         int pkt_len = 0;
   82         int off = *offp;
   83         uint16_t port = 0;
   84 
   85         /* get the VRF and table id's */
   86         if (SCTP_GET_PKT_VRFID(*i_pak, vrf_id)) {
   87                 SCTP_RELEASE_PKT(*i_pak);
   88                 return (-1);
   89         }
   90         m = SCTP_HEADER_TO_CHAIN(*i_pak);
   91         pkt_len = SCTP_HEADER_LEN((*i_pak));
   92 
   93 #ifdef  SCTP_PACKET_LOGGING
   94         sctp_packet_log(m, pkt_len);
   95 #endif
   96         ip6 = mtod(m, struct ip6_hdr *);
   97         /* Ensure that (sctphdr + sctp_chunkhdr) in a row. */
   98         IP6_EXTHDR_GET(sh, struct sctphdr *, m, off,
   99             (int)(sizeof(*sh) + sizeof(*ch)));
  100         if (sh == NULL) {
  101                 SCTP_STAT_INCR(sctps_hdrops);
  102                 return IPPROTO_DONE;
  103         }
  104         ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
  105         iphlen = off;
  106         offset = iphlen + sizeof(*sh) + sizeof(*ch);
  107         SCTPDBG(SCTP_DEBUG_INPUT1,
  108             "sctp6_input() length:%d iphlen:%d\n", pkt_len, iphlen);
  109 
  110 
  111 #if defined(NFAITH) && NFAITH > 0
  112 
  113         if (faithprefix_p != NULL && (*faithprefix_p) (&ip6->ip6_dst)) {
  114                 /* XXX send icmp6 host/port unreach? */
  115                 goto bad;
  116         }
  117 #endif                          /* NFAITH defined and > 0 */
  118         SCTP_STAT_INCR(sctps_recvpackets);
  119         SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
  120         SCTPDBG(SCTP_DEBUG_INPUT1, "V6 input gets a packet iphlen:%d pktlen:%d\n",
  121             iphlen, pkt_len);
  122         if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
  123                 /* No multi-cast support in SCTP */
  124                 goto bad;
  125         }
  126         /* destination port of 0 is illegal, based on RFC2960. */
  127         if (sh->dest_port == 0)
  128                 goto bad;
  129         check = sh->checksum;   /* save incoming checksum */
  130         if ((check == 0) && (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback)) &&
  131             (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &ip6->ip6_dst))) {
  132                 goto sctp_skip_csum;
  133         }
  134         sh->checksum = 0;       /* prepare for calc */
  135         calc_check = sctp_calculate_sum(m, &mlen, iphlen);
  136         if (calc_check != check) {
  137                 SCTPDBG(SCTP_DEBUG_INPUT1, "Bad CSUM on SCTP packet calc_check:%x check:%x  m:%p mlen:%d iphlen:%d\n",
  138                     calc_check, check, m, mlen, iphlen);
  139                 stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch),
  140                     sh, ch, &in6p, &net, vrf_id);
  141                 if ((net) && (port)) {
  142                         if (net->port == 0) {
  143                                 sctp_pathmtu_adjustment(in6p, stcb, net, net->mtu - sizeof(struct udphdr));
  144                         }
  145                         net->port = port;
  146                 }
  147                 /* in6p's ref-count increased && stcb locked */
  148                 if ((in6p) && (stcb)) {
  149                         sctp_send_packet_dropped(stcb, net, m, iphlen, 1);
  150                         sctp_chunk_output((struct sctp_inpcb *)in6p, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR, SCTP_SO_NOT_LOCKED);
  151                 } else if ((in6p != NULL) && (stcb == NULL)) {
  152                         refcount_up = 1;
  153                 }
  154                 SCTP_STAT_INCR(sctps_badsum);
  155                 SCTP_STAT_INCR_COUNTER32(sctps_checksumerrors);
  156                 goto bad;
  157         }
  158         sh->checksum = calc_check;
  159 
  160 sctp_skip_csum:
  161         net = NULL;
  162         /*
  163          * Locate pcb and tcb for datagram sctp_findassociation_addr() wants
  164          * IP/SCTP/first chunk header...
  165          */
  166         stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch),
  167             sh, ch, &in6p, &net, vrf_id);
  168         if ((net) && (port)) {
  169                 if (net->port == 0) {
  170                         sctp_pathmtu_adjustment(in6p, stcb, net, net->mtu - sizeof(struct udphdr));
  171                 }
  172                 net->port = port;
  173         }
  174         /* in6p's ref-count increased */
  175         if (in6p == NULL) {
  176                 struct sctp_init_chunk *init_chk, chunk_buf;
  177 
  178                 SCTP_STAT_INCR(sctps_noport);
  179                 if (ch->chunk_type == SCTP_INITIATION) {
  180                         /*
  181                          * we do a trick here to get the INIT tag, dig in
  182                          * and get the tag from the INIT and put it in the
  183                          * common header.
  184                          */
  185                         init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m,
  186                             iphlen + sizeof(*sh), sizeof(*init_chk),
  187                             (uint8_t *) & chunk_buf);
  188                         if (init_chk)
  189                                 sh->v_tag = init_chk->init.initiate_tag;
  190                         else
  191                                 sh->v_tag = 0;
  192                 }
  193                 if (ch->chunk_type == SCTP_SHUTDOWN_ACK) {
  194                         sctp_send_shutdown_complete2(m, iphlen, sh, vrf_id, port);
  195                         goto bad;
  196                 }
  197                 if (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) {
  198                         goto bad;
  199                 }
  200                 if (ch->chunk_type != SCTP_ABORT_ASSOCIATION)
  201                         sctp_send_abort(m, iphlen, sh, 0, NULL, vrf_id, port);
  202                 goto bad;
  203         } else if (stcb == NULL) {
  204                 refcount_up = 1;
  205         }
  206         in6p_ip = (struct inpcb *)in6p;
  207 #ifdef IPSEC
  208         /*
  209          * Check AH/ESP integrity.
  210          */
  211         if (in6p_ip && (ipsec6_in_reject(m, in6p_ip))) {
  212 /* XXX */
  213                 MODULE_GLOBAL(MOD_IPSEC, ipsec6stat).in_polvio++;
  214                 goto bad;
  215         }
  216 #endif                          /* IPSEC */
  217 
  218         /*
  219          * CONTROL chunk processing
  220          */
  221         offset -= sizeof(*ch);
  222         ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff);
  223 
  224         /* Length now holds the total packet length payload + iphlen */
  225         length = ntohs(ip6->ip6_plen) + iphlen;
  226 
  227         /* sa_ignore NO_NULL_CHK */
  228         sctp_common_input_processing(&m, iphlen, offset, length, sh, ch,
  229             in6p, stcb, net, ecn_bits, vrf_id, port);
  230         /* inp's ref-count reduced && stcb unlocked */
  231         /* XXX this stuff below gets moved to appropriate parts later... */
  232         if (m)
  233                 sctp_m_freem(m);
  234         if ((in6p) && refcount_up) {
  235                 /* reduce ref-count */
  236                 SCTP_INP_WLOCK(in6p);
  237                 SCTP_INP_DECR_REF(in6p);
  238                 SCTP_INP_WUNLOCK(in6p);
  239         }
  240         return IPPROTO_DONE;
  241 
  242 bad:
  243         if (stcb) {
  244                 SCTP_TCB_UNLOCK(stcb);
  245         }
  246         if ((in6p) && refcount_up) {
  247                 /* reduce ref-count */
  248                 SCTP_INP_WLOCK(in6p);
  249                 SCTP_INP_DECR_REF(in6p);
  250                 SCTP_INP_WUNLOCK(in6p);
  251         }
  252         if (m)
  253                 sctp_m_freem(m);
  254         return IPPROTO_DONE;
  255 }
  256 
  257 
  258 static void
  259 sctp6_notify_mbuf(struct sctp_inpcb *inp, struct icmp6_hdr *icmp6,
  260     struct sctphdr *sh, struct sctp_tcb *stcb, struct sctp_nets *net)
  261 {
  262         uint32_t nxtsz;
  263 
  264         if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
  265             (icmp6 == NULL) || (sh == NULL)) {
  266                 goto out;
  267         }
  268         /* First do we even look at it? */
  269         if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag))
  270                 goto out;
  271 
  272         if (icmp6->icmp6_type != ICMP6_PACKET_TOO_BIG) {
  273                 /* not PACKET TO BIG */
  274                 goto out;
  275         }
  276         /*
  277          * ok we need to look closely. We could even get smarter and look at
  278          * anyone that we sent to in case we get a different ICMP that tells
  279          * us there is no way to reach a host, but for this impl, all we
  280          * care about is MTU discovery.
  281          */
  282         nxtsz = ntohl(icmp6->icmp6_mtu);
  283         /* Stop any PMTU timer */
  284         sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL, SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_1);
  285 
  286         /* Adjust destination size limit */
  287         if (net->mtu > nxtsz) {
  288                 net->mtu = nxtsz;
  289         }
  290         /* now what about the ep? */
  291         if (stcb->asoc.smallest_mtu > nxtsz) {
  292                 struct sctp_tmit_chunk *chk;
  293 
  294                 /* Adjust that too */
  295                 stcb->asoc.smallest_mtu = nxtsz;
  296                 /* now off to subtract IP_DF flag if needed */
  297 
  298                 TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
  299                         if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) {
  300                                 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
  301                         }
  302                 }
  303                 TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
  304                         if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) {
  305                                 /*
  306                                  * For this guy we also mark for immediate
  307                                  * resend since we sent to big of chunk
  308                                  */
  309                                 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
  310                                 if (chk->sent != SCTP_DATAGRAM_RESEND)
  311                                         stcb->asoc.sent_queue_retran_cnt++;
  312                                 chk->sent = SCTP_DATAGRAM_RESEND;
  313                                 chk->rec.data.doing_fast_retransmit = 0;
  314 
  315                                 chk->sent = SCTP_DATAGRAM_RESEND;
  316                                 /* Clear any time so NO RTT is being done */
  317                                 chk->sent_rcv_time.tv_sec = 0;
  318                                 chk->sent_rcv_time.tv_usec = 0;
  319                                 stcb->asoc.total_flight -= chk->send_size;
  320                                 net->flight_size -= chk->send_size;
  321                         }
  322                 }
  323         }
  324         sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL);
  325 out:
  326         if (stcb) {
  327                 SCTP_TCB_UNLOCK(stcb);
  328         }
  329 }
  330 
  331 
  332 void
  333 sctp6_notify(struct sctp_inpcb *inp,
  334     struct icmp6_hdr *icmph,
  335     struct sctphdr *sh,
  336     struct sockaddr *to,
  337     struct sctp_tcb *stcb,
  338     struct sctp_nets *net)
  339 {
  340 #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
  341         struct socket *so;
  342 
  343 #endif
  344         /* protection */
  345         int reason;
  346 
  347 
  348         if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
  349             (sh == NULL) || (to == NULL)) {
  350                 if (stcb)
  351                         SCTP_TCB_UNLOCK(stcb);
  352                 return;
  353         }
  354         /* First job is to verify the vtag matches what I would send */
  355         if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
  356                 SCTP_TCB_UNLOCK(stcb);
  357                 return;
  358         }
  359         if (icmph->icmp6_type != ICMP_UNREACH) {
  360                 /* We only care about unreachable */
  361                 SCTP_TCB_UNLOCK(stcb);
  362                 return;
  363         }
  364         if ((icmph->icmp6_code == ICMP_UNREACH_NET) ||
  365             (icmph->icmp6_code == ICMP_UNREACH_HOST) ||
  366             (icmph->icmp6_code == ICMP_UNREACH_NET_UNKNOWN) ||
  367             (icmph->icmp6_code == ICMP_UNREACH_HOST_UNKNOWN) ||
  368             (icmph->icmp6_code == ICMP_UNREACH_ISOLATED) ||
  369             (icmph->icmp6_code == ICMP_UNREACH_NET_PROHIB) ||
  370             (icmph->icmp6_code == ICMP_UNREACH_HOST_PROHIB) ||
  371             (icmph->icmp6_code == ICMP_UNREACH_FILTER_PROHIB)) {
  372 
  373                 /*
  374                  * Hmm reachablity problems we must examine closely. If its
  375                  * not reachable, we may have lost a network. Or if there is
  376                  * NO protocol at the other end named SCTP. well we consider
  377                  * it a OOTB abort.
  378                  */
  379                 if (net->dest_state & SCTP_ADDR_REACHABLE) {
  380                         /* Ok that destination is NOT reachable */
  381                         SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n",
  382                             net->error_count,
  383                             net->failure_threshold,
  384                             net);
  385 
  386                         net->dest_state &= ~SCTP_ADDR_REACHABLE;
  387                         net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
  388                         /*
  389                          * JRS 5/14/07 - If a destination is unreachable,
  390                          * the PF bit is turned off.  This allows an
  391                          * unambiguous use of the PF bit for destinations
  392                          * that are reachable but potentially failed. If the
  393                          * destination is set to the unreachable state, also
  394                          * set the destination to the PF state.
  395                          */
  396                         /*
  397                          * Add debug message here if destination is not in
  398                          * PF state.
  399                          */
  400                         /* Stop any running T3 timers here? */
  401                         if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_pf)) {
  402                                 net->dest_state &= ~SCTP_ADDR_PF;
  403                                 SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n",
  404                                     net);
  405                         }
  406                         net->error_count = net->failure_threshold + 1;
  407                         sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
  408                             stcb, SCTP_FAILED_THRESHOLD,
  409                             (void *)net, SCTP_SO_NOT_LOCKED);
  410                 }
  411                 SCTP_TCB_UNLOCK(stcb);
  412         } else if ((icmph->icmp6_code == ICMP_UNREACH_PROTOCOL) ||
  413             (icmph->icmp6_code == ICMP_UNREACH_PORT)) {
  414                 /*
  415                  * Here the peer is either playing tricks on us, including
  416                  * an address that belongs to someone who does not support
  417                  * SCTP OR was a userland implementation that shutdown and
  418                  * now is dead. In either case treat it like a OOTB abort
  419                  * with no TCB
  420                  */
  421                 reason = SCTP_PEER_FAULTY;
  422                 sctp_abort_notification(stcb, reason, SCTP_SO_NOT_LOCKED);
  423 #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
  424                 so = SCTP_INP_SO(inp);
  425                 atomic_add_int(&stcb->asoc.refcnt, 1);
  426                 SCTP_TCB_UNLOCK(stcb);
  427                 SCTP_SOCKET_LOCK(so, 1);
  428                 SCTP_TCB_LOCK(stcb);
  429                 atomic_subtract_int(&stcb->asoc.refcnt, 1);
  430 #endif
  431                 (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
  432 #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
  433                 SCTP_SOCKET_UNLOCK(so, 1);
  434                 /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */
  435 #endif
  436                 /* no need to unlock here, since the TCB is gone */
  437         } else {
  438                 SCTP_TCB_UNLOCK(stcb);
  439         }
  440 }
  441 
  442 
  443 
  444 void
  445 sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d)
  446 {
  447         struct sctphdr sh;
  448         struct ip6ctlparam *ip6cp = NULL;
  449         uint32_t vrf_id;
  450 
  451         vrf_id = SCTP_DEFAULT_VRFID;
  452 
  453         if (pktdst->sa_family != AF_INET6 ||
  454             pktdst->sa_len != sizeof(struct sockaddr_in6))
  455                 return;
  456 
  457         if ((unsigned)cmd >= PRC_NCMDS)
  458                 return;
  459         if (PRC_IS_REDIRECT(cmd)) {
  460                 d = NULL;
  461         } else if (inet6ctlerrmap[cmd] == 0) {
  462                 return;
  463         }
  464         /* if the parameter is from icmp6, decode it. */
  465         if (d != NULL) {
  466                 ip6cp = (struct ip6ctlparam *)d;
  467         } else {
  468                 ip6cp = (struct ip6ctlparam *)NULL;
  469         }
  470 
  471         if (ip6cp) {
  472                 /*
  473                  * XXX: We assume that when IPV6 is non NULL, M and OFF are
  474                  * valid.
  475                  */
  476                 /* check if we can safely examine src and dst ports */
  477                 struct sctp_inpcb *inp = NULL;
  478                 struct sctp_tcb *stcb = NULL;
  479                 struct sctp_nets *net = NULL;
  480                 struct sockaddr_in6 final;
  481 
  482                 if (ip6cp->ip6c_m == NULL)
  483                         return;
  484 
  485                 bzero(&sh, sizeof(sh));
  486                 bzero(&final, sizeof(final));
  487                 inp = NULL;
  488                 net = NULL;
  489                 m_copydata(ip6cp->ip6c_m, ip6cp->ip6c_off, sizeof(sh),
  490                     (caddr_t)&sh);
  491                 ip6cp->ip6c_src->sin6_port = sh.src_port;
  492                 final.sin6_len = sizeof(final);
  493                 final.sin6_family = AF_INET6;
  494                 final.sin6_addr = ((struct sockaddr_in6 *)pktdst)->sin6_addr;
  495                 final.sin6_port = sh.dest_port;
  496                 stcb = sctp_findassociation_addr_sa((struct sockaddr *)ip6cp->ip6c_src,
  497                     (struct sockaddr *)&final,
  498                     &inp, &net, 1, vrf_id);
  499                 /* inp's ref-count increased && stcb locked */
  500                 if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
  501                         if (cmd == PRC_MSGSIZE) {
  502                                 sctp6_notify_mbuf(inp,
  503                                     ip6cp->ip6c_icmp6,
  504                                     &sh,
  505                                     stcb,
  506                                     net);
  507                                 /* inp's ref-count reduced && stcb unlocked */
  508                         } else {
  509                                 sctp6_notify(inp, ip6cp->ip6c_icmp6, &sh,
  510                                     (struct sockaddr *)&final,
  511                                     stcb, net);
  512                                 /* inp's ref-count reduced && stcb unlocked */
  513                         }
  514                 } else {
  515                         if (PRC_IS_REDIRECT(cmd) && inp) {
  516                                 in6_rtchange((struct in6pcb *)inp,
  517                                     inet6ctlerrmap[cmd]);
  518                         }
  519                         if (inp) {
  520                                 /* reduce inp's ref-count */
  521                                 SCTP_INP_WLOCK(inp);
  522                                 SCTP_INP_DECR_REF(inp);
  523                                 SCTP_INP_WUNLOCK(inp);
  524                         }
  525                         if (stcb)
  526                                 SCTP_TCB_UNLOCK(stcb);
  527                 }
  528         }
  529 }
  530 
  531 /*
  532  * this routine can probably be collasped into the one in sctp_userreq.c
  533  * since they do the same thing and now we lookup with a sockaddr
  534  */
  535 static int
  536 sctp6_getcred(SYSCTL_HANDLER_ARGS)
  537 {
  538         struct xucred xuc;
  539         struct sockaddr_in6 addrs[2];
  540         struct sctp_inpcb *inp;
  541         struct sctp_nets *net;
  542         struct sctp_tcb *stcb;
  543         int error;
  544         uint32_t vrf_id;
  545 
  546         vrf_id = SCTP_DEFAULT_VRFID;
  547 
  548         error = priv_check(req->td, PRIV_NETINET_GETCRED);
  549         if (error)
  550                 return (error);
  551 
  552         if (req->newlen != sizeof(addrs)) {
  553                 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  554                 return (EINVAL);
  555         }
  556         if (req->oldlen != sizeof(struct ucred)) {
  557                 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  558                 return (EINVAL);
  559         }
  560         error = SYSCTL_IN(req, addrs, sizeof(addrs));
  561         if (error)
  562                 return (error);
  563 
  564         stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[0]),
  565             sin6tosa(&addrs[1]),
  566             &inp, &net, 1, vrf_id);
  567         if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
  568                 if ((inp != NULL) && (stcb == NULL)) {
  569                         /* reduce ref-count */
  570                         SCTP_INP_WLOCK(inp);
  571                         SCTP_INP_DECR_REF(inp);
  572                         goto cred_can_cont;
  573                 }
  574                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
  575                 error = ENOENT;
  576                 goto out;
  577         }
  578         SCTP_TCB_UNLOCK(stcb);
  579         /*
  580          * We use the write lock here, only since in the error leg we need
  581          * it. If we used RLOCK, then we would have to
  582          * wlock/decr/unlock/rlock. Which in theory could create a hole.
  583          * Better to use higher wlock.
  584          */
  585         SCTP_INP_WLOCK(inp);
  586 cred_can_cont:
  587         error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
  588         if (error) {
  589                 SCTP_INP_WUNLOCK(inp);
  590                 goto out;
  591         }
  592         cru2x(inp->sctp_socket->so_cred, &xuc);
  593         SCTP_INP_WUNLOCK(inp);
  594         error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
  595 out:
  596         return (error);
  597 }
  598 
  599 SYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
  600     0, 0,
  601     sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection");
  602 
  603 
  604 /* This is the same as the sctp_abort() could be made common */
  605 static void
  606 sctp6_abort(struct socket *so)
  607 {
  608         struct sctp_inpcb *inp;
  609         uint32_t flags;
  610 
  611         inp = (struct sctp_inpcb *)so->so_pcb;
  612         if (inp == 0) {
  613                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  614                 return;
  615         }
  616 sctp_must_try_again:
  617         flags = inp->sctp_flags;
  618 #ifdef SCTP_LOG_CLOSING
  619         sctp_log_closing(inp, NULL, 17);
  620 #endif
  621         if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
  622             (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
  623 #ifdef SCTP_LOG_CLOSING
  624                 sctp_log_closing(inp, NULL, 16);
  625 #endif
  626                 sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
  627                     SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
  628                 SOCK_LOCK(so);
  629                 SCTP_SB_CLEAR(so->so_snd);
  630                 /*
  631                  * same for the rcv ones, they are only here for the
  632                  * accounting/select.
  633                  */
  634                 SCTP_SB_CLEAR(so->so_rcv);
  635                 /* Now null out the reference, we are completely detached. */
  636                 so->so_pcb = NULL;
  637                 SOCK_UNLOCK(so);
  638         } else {
  639                 flags = inp->sctp_flags;
  640                 if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
  641                         goto sctp_must_try_again;
  642                 }
  643         }
  644         return;
  645 }
  646 
  647 static int
  648 sctp6_attach(struct socket *so, int proto, struct thread *p)
  649 {
  650         struct in6pcb *inp6;
  651         int error;
  652         struct sctp_inpcb *inp;
  653         uint32_t vrf_id = SCTP_DEFAULT_VRFID;
  654 
  655         inp = (struct sctp_inpcb *)so->so_pcb;
  656         if (inp != NULL) {
  657                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  658                 return EINVAL;
  659         }
  660         if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
  661                 error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace));
  662                 if (error)
  663                         return error;
  664         }
  665         error = sctp_inpcb_alloc(so, vrf_id);
  666         if (error)
  667                 return error;
  668         inp = (struct sctp_inpcb *)so->so_pcb;
  669         SCTP_INP_WLOCK(inp);
  670         inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6;     /* I'm v6! */
  671         inp6 = (struct in6pcb *)inp;
  672 
  673         inp6->inp_vflag |= INP_IPV6;
  674         inp6->in6p_hops = -1;   /* use kernel default */
  675         inp6->in6p_cksum = -1;  /* just to be sure */
  676 #ifdef INET
  677         /*
  678          * XXX: ugly!! IPv4 TTL initialization is necessary for an IPv6
  679          * socket as well, because the socket may be bound to an IPv6
  680          * wildcard address, which may match an IPv4-mapped IPv6 address.
  681          */
  682         inp6->inp_ip_ttl = MODULE_GLOBAL(MOD_INET, ip_defttl);
  683 #endif
  684         /*
  685          * Hmm what about the IPSEC stuff that is missing here but in
  686          * sctp_attach()?
  687          */
  688         SCTP_INP_WUNLOCK(inp);
  689         return 0;
  690 }
  691 
  692 static int
  693 sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
  694 {
  695         struct sctp_inpcb *inp;
  696         struct in6pcb *inp6;
  697         int error;
  698 
  699         inp = (struct sctp_inpcb *)so->so_pcb;
  700         if (inp == 0) {
  701                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  702                 return EINVAL;
  703         }
  704         if (addr) {
  705                 if ((addr->sa_family == AF_INET6) &&
  706                     (addr->sa_len != sizeof(struct sockaddr_in6))) {
  707                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  708                         return EINVAL;
  709                 }
  710                 if ((addr->sa_family == AF_INET) &&
  711                     (addr->sa_len != sizeof(struct sockaddr_in))) {
  712                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  713                         return EINVAL;
  714                 }
  715         }
  716         inp6 = (struct in6pcb *)inp;
  717         inp6->inp_vflag &= ~INP_IPV4;
  718         inp6->inp_vflag |= INP_IPV6;
  719         if ((addr != NULL) && (SCTP_IPV6_V6ONLY(inp6) == 0)) {
  720                 if (addr->sa_family == AF_INET) {
  721                         /* binding v4 addr to v6 socket, so reset flags */
  722                         inp6->inp_vflag |= INP_IPV4;
  723                         inp6->inp_vflag &= ~INP_IPV6;
  724                 } else {
  725                         struct sockaddr_in6 *sin6_p;
  726 
  727                         sin6_p = (struct sockaddr_in6 *)addr;
  728 
  729                         if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) {
  730                                 inp6->inp_vflag |= INP_IPV4;
  731                         } else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
  732                                 struct sockaddr_in sin;
  733 
  734                                 in6_sin6_2_sin(&sin, sin6_p);
  735                                 inp6->inp_vflag |= INP_IPV4;
  736                                 inp6->inp_vflag &= ~INP_IPV6;
  737                                 error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, NULL, p);
  738                                 return error;
  739                         }
  740                 }
  741         } else if (addr != NULL) {
  742                 /* IPV6_V6ONLY socket */
  743                 if (addr->sa_family == AF_INET) {
  744                         /* can't bind v4 addr to v6 only socket! */
  745                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  746                         return EINVAL;
  747                 } else {
  748                         struct sockaddr_in6 *sin6_p;
  749 
  750                         sin6_p = (struct sockaddr_in6 *)addr;
  751 
  752                         if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
  753                                 /* can't bind v4-mapped addrs either! */
  754                                 /* NOTE: we don't support SIIT */
  755                                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  756                                 return EINVAL;
  757                         }
  758                 }
  759         }
  760         error = sctp_inpcb_bind(so, addr, NULL, p);
  761         return error;
  762 }
  763 
  764 
  765 static void
  766 sctp6_close(struct socket *so)
  767 {
  768         sctp_close(so);
  769 }
  770 
  771 /* This could be made common with sctp_detach() since they are identical */
  772 
  773 static
  774 int
  775 sctp6_disconnect(struct socket *so)
  776 {
  777         return (sctp_disconnect(so));
  778 }
  779 
  780 
  781 int
  782 sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
  783     struct mbuf *control, struct thread *p);
  784 
  785 
  786 static int
  787 sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
  788     struct mbuf *control, struct thread *p)
  789 {
  790         struct sctp_inpcb *inp;
  791         struct inpcb *in_inp;
  792         struct in6pcb *inp6;
  793 
  794 #ifdef INET
  795         struct sockaddr_in6 *sin6;
  796 
  797 #endif                          /* INET */
  798         /* No SPL needed since sctp_output does this */
  799 
  800         inp = (struct sctp_inpcb *)so->so_pcb;
  801         if (inp == NULL) {
  802                 if (control) {
  803                         SCTP_RELEASE_PKT(control);
  804                         control = NULL;
  805                 }
  806                 SCTP_RELEASE_PKT(m);
  807                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  808                 return EINVAL;
  809         }
  810         in_inp = (struct inpcb *)inp;
  811         inp6 = (struct in6pcb *)inp;
  812         /*
  813          * For the TCP model we may get a NULL addr, if we are a connected
  814          * socket thats ok.
  815          */
  816         if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) &&
  817             (addr == NULL)) {
  818                 goto connected_type;
  819         }
  820         if (addr == NULL) {
  821                 SCTP_RELEASE_PKT(m);
  822                 if (control) {
  823                         SCTP_RELEASE_PKT(control);
  824                         control = NULL;
  825                 }
  826                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EDESTADDRREQ);
  827                 return (EDESTADDRREQ);
  828         }
  829 #ifdef INET
  830         sin6 = (struct sockaddr_in6 *)addr;
  831         if (SCTP_IPV6_V6ONLY(inp6)) {
  832                 /*
  833                  * if IPV6_V6ONLY flag, we discard datagrams destined to a
  834                  * v4 addr or v4-mapped addr
  835                  */
  836                 if (addr->sa_family == AF_INET) {
  837                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  838                         return EINVAL;
  839                 }
  840                 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
  841                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  842                         return EINVAL;
  843                 }
  844         }
  845         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
  846                 if (!MODULE_GLOBAL(MOD_INET6, ip6_v6only)) {
  847                         struct sockaddr_in sin;
  848 
  849                         /* convert v4-mapped into v4 addr and send */
  850                         in6_sin6_2_sin(&sin, sin6);
  851                         return sctp_sendm(so, flags, m, (struct sockaddr *)&sin,
  852                             control, p);
  853                 } else {
  854                         /* mapped addresses aren't enabled */
  855                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  856                         return EINVAL;
  857                 }
  858         }
  859 #endif                          /* INET */
  860 connected_type:
  861         /* now what about control */
  862         if (control) {
  863                 if (inp->control) {
  864                         SCTP_PRINTF("huh? control set?\n");
  865                         SCTP_RELEASE_PKT(inp->control);
  866                         inp->control = NULL;
  867                 }
  868                 inp->control = control;
  869         }
  870         /* Place the data */
  871         if (inp->pkt) {
  872                 SCTP_BUF_NEXT(inp->pkt_last) = m;
  873                 inp->pkt_last = m;
  874         } else {
  875                 inp->pkt_last = inp->pkt = m;
  876         }
  877         if (
  878         /* FreeBSD and MacOSX uses a flag passed */
  879             ((flags & PRUS_MORETOCOME) == 0)
  880             ) {
  881                 /*
  882                  * note with the current version this code will only be used
  883                  * by OpenBSD, NetBSD and FreeBSD have methods for
  884                  * re-defining sosend() to use sctp_sosend().  One can
  885                  * optionaly switch back to this code (by changing back the
  886                  * defininitions but this is not advisable.
  887                  */
  888                 int ret;
  889 
  890                 ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
  891                 inp->pkt = NULL;
  892                 inp->control = NULL;
  893                 return (ret);
  894         } else {
  895                 return (0);
  896         }
  897 }
  898 
  899 static int
  900 sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
  901 {
  902         uint32_t vrf_id;
  903         int error = 0;
  904         struct sctp_inpcb *inp;
  905         struct in6pcb *inp6;
  906         struct sctp_tcb *stcb;
  907 
  908 #ifdef INET
  909         struct sockaddr_in6 *sin6;
  910         struct sockaddr_storage ss;
  911 
  912 #endif                          /* INET */
  913 
  914         inp6 = (struct in6pcb *)so->so_pcb;
  915         inp = (struct sctp_inpcb *)so->so_pcb;
  916         if (inp == 0) {
  917                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
  918                 return (ECONNRESET);    /* I made the same as TCP since we are
  919                                          * not setup? */
  920         }
  921         if (addr == NULL) {
  922                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  923                 return (EINVAL);
  924         }
  925         if ((addr->sa_family == AF_INET6) && (addr->sa_len != sizeof(struct sockaddr_in6))) {
  926                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  927                 return (EINVAL);
  928         }
  929         if ((addr->sa_family == AF_INET) && (addr->sa_len != sizeof(struct sockaddr_in))) {
  930                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  931                 return (EINVAL);
  932         }
  933         vrf_id = inp->def_vrf_id;
  934         SCTP_ASOC_CREATE_LOCK(inp);
  935         SCTP_INP_RLOCK(inp);
  936         if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
  937             SCTP_PCB_FLAGS_UNBOUND) {
  938                 /* Bind a ephemeral port */
  939                 SCTP_INP_RUNLOCK(inp);
  940                 error = sctp6_bind(so, NULL, p);
  941                 if (error) {
  942                         SCTP_ASOC_CREATE_UNLOCK(inp);
  943 
  944                         return (error);
  945                 }
  946                 SCTP_INP_RLOCK(inp);
  947         }
  948         if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
  949             (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
  950                 /* We are already connected AND the TCP model */
  951                 SCTP_INP_RUNLOCK(inp);
  952                 SCTP_ASOC_CREATE_UNLOCK(inp);
  953                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EADDRINUSE);
  954                 return (EADDRINUSE);
  955         }
  956 #ifdef INET
  957         sin6 = (struct sockaddr_in6 *)addr;
  958         if (SCTP_IPV6_V6ONLY(inp6)) {
  959                 /*
  960                  * if IPV6_V6ONLY flag, ignore connections destined to a v4
  961                  * addr or v4-mapped addr
  962                  */
  963                 if (addr->sa_family == AF_INET) {
  964                         SCTP_INP_RUNLOCK(inp);
  965                         SCTP_ASOC_CREATE_UNLOCK(inp);
  966                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  967                         return EINVAL;
  968                 }
  969                 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
  970                         SCTP_INP_RUNLOCK(inp);
  971                         SCTP_ASOC_CREATE_UNLOCK(inp);
  972                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  973                         return EINVAL;
  974                 }
  975         }
  976         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
  977                 if (!MODULE_GLOBAL(MOD_INET6, ip6_v6only)) {
  978                         /* convert v4-mapped into v4 addr */
  979                         in6_sin6_2_sin((struct sockaddr_in *)&ss, sin6);
  980                         addr = (struct sockaddr *)&ss;
  981                 } else {
  982                         /* mapped addresses aren't enabled */
  983                         SCTP_INP_RUNLOCK(inp);
  984                         SCTP_ASOC_CREATE_UNLOCK(inp);
  985                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  986                         return EINVAL;
  987                 }
  988         } else
  989 #endif                          /* INET */
  990                 addr = addr;    /* for true v6 address case */
  991 
  992         /* Now do we connect? */
  993         if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
  994                 stcb = LIST_FIRST(&inp->sctp_asoc_list);
  995                 if (stcb) {
  996                         SCTP_TCB_UNLOCK(stcb);
  997                 }
  998                 SCTP_INP_RUNLOCK(inp);
  999         } else {
 1000                 SCTP_INP_RUNLOCK(inp);
 1001                 SCTP_INP_WLOCK(inp);
 1002                 SCTP_INP_INCR_REF(inp);
 1003                 SCTP_INP_WUNLOCK(inp);
 1004                 stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
 1005                 if (stcb == NULL) {
 1006                         SCTP_INP_WLOCK(inp);
 1007                         SCTP_INP_DECR_REF(inp);
 1008                         SCTP_INP_WUNLOCK(inp);
 1009                 }
 1010         }
 1011 
 1012         if (stcb != NULL) {
 1013                 /* Already have or am bring up an association */
 1014                 SCTP_ASOC_CREATE_UNLOCK(inp);
 1015                 SCTP_TCB_UNLOCK(stcb);
 1016                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EALREADY);
 1017                 return (EALREADY);
 1018         }
 1019         /* We are GOOD to go */
 1020         stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0, vrf_id, p);
 1021         SCTP_ASOC_CREATE_UNLOCK(inp);
 1022         if (stcb == NULL) {
 1023                 /* Gak! no memory */
 1024                 return (error);
 1025         }
 1026         if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
 1027                 stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
 1028                 /* Set the connected flag so we can queue data */
 1029                 soisconnecting(so);
 1030         }
 1031         stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
 1032         (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
 1033 
 1034         /* initialize authentication parameters for the assoc */
 1035         sctp_initialize_auth_params(inp, stcb);
 1036 
 1037         sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
 1038         SCTP_TCB_UNLOCK(stcb);
 1039         return error;
 1040 }
 1041 
 1042 static int
 1043 sctp6_getaddr(struct socket *so, struct sockaddr **addr)
 1044 {
 1045         struct sockaddr_in6 *sin6;
 1046         struct sctp_inpcb *inp;
 1047         uint32_t vrf_id;
 1048         struct sctp_ifa *sctp_ifa;
 1049 
 1050         int error;
 1051 
 1052         /*
 1053          * Do the malloc first in case it blocks.
 1054          */
 1055         SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
 1056         sin6->sin6_family = AF_INET6;
 1057         sin6->sin6_len = sizeof(*sin6);
 1058 
 1059         inp = (struct sctp_inpcb *)so->so_pcb;
 1060         if (inp == NULL) {
 1061                 SCTP_FREE_SONAME(sin6);
 1062                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
 1063                 return ECONNRESET;
 1064         }
 1065         SCTP_INP_RLOCK(inp);
 1066         sin6->sin6_port = inp->sctp_lport;
 1067         if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
 1068                 /* For the bound all case you get back 0 */
 1069                 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
 1070                         struct sctp_tcb *stcb;
 1071                         struct sockaddr_in6 *sin_a6;
 1072                         struct sctp_nets *net;
 1073                         int fnd;
 1074 
 1075                         stcb = LIST_FIRST(&inp->sctp_asoc_list);
 1076                         if (stcb == NULL) {
 1077                                 goto notConn6;
 1078                         }
 1079                         fnd = 0;
 1080                         sin_a6 = NULL;
 1081                         TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
 1082                                 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
 1083                                 if (sin_a6 == NULL)
 1084                                         /* this will make coverity happy */
 1085                                         continue;
 1086 
 1087                                 if (sin_a6->sin6_family == AF_INET6) {
 1088                                         fnd = 1;
 1089                                         break;
 1090                                 }
 1091                         }
 1092                         if ((!fnd) || (sin_a6 == NULL)) {
 1093                                 /* punt */
 1094                                 goto notConn6;
 1095                         }
 1096                         vrf_id = inp->def_vrf_id;
 1097                         sctp_ifa = sctp_source_address_selection(inp, stcb, (sctp_route_t *) & net->ro, net, 0, vrf_id);
 1098                         if (sctp_ifa) {
 1099                                 sin6->sin6_addr = sctp_ifa->address.sin6.sin6_addr;
 1100                         }
 1101                 } else {
 1102                         /* For the bound all case you get back 0 */
 1103         notConn6:
 1104                         memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
 1105                 }
 1106         } else {
 1107                 /* Take the first IPv6 address in the list */
 1108                 struct sctp_laddr *laddr;
 1109                 int fnd = 0;
 1110 
 1111                 LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
 1112                         if (laddr->ifa->address.sa.sa_family == AF_INET6) {
 1113                                 struct sockaddr_in6 *sin_a;
 1114 
 1115                                 sin_a = (struct sockaddr_in6 *)&laddr->ifa->address.sin6;
 1116                                 sin6->sin6_addr = sin_a->sin6_addr;
 1117                                 fnd = 1;
 1118                                 break;
 1119                         }
 1120                 }
 1121                 if (!fnd) {
 1122                         SCTP_FREE_SONAME(sin6);
 1123                         SCTP_INP_RUNLOCK(inp);
 1124                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
 1125                         return ENOENT;
 1126                 }
 1127         }
 1128         SCTP_INP_RUNLOCK(inp);
 1129         /* Scoping things for v6 */
 1130         if ((error = sa6_recoverscope(sin6)) != 0) {
 1131                 SCTP_FREE_SONAME(sin6);
 1132                 return (error);
 1133         }
 1134         (*addr) = (struct sockaddr *)sin6;
 1135         return (0);
 1136 }
 1137 
 1138 static int
 1139 sctp6_peeraddr(struct socket *so, struct sockaddr **addr)
 1140 {
 1141         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)*addr;
 1142         int fnd;
 1143         struct sockaddr_in6 *sin_a6;
 1144         struct sctp_inpcb *inp;
 1145         struct sctp_tcb *stcb;
 1146         struct sctp_nets *net;
 1147 
 1148         int error;
 1149 
 1150         /*
 1151          * Do the malloc first in case it blocks.
 1152          */
 1153         inp = (struct sctp_inpcb *)so->so_pcb;
 1154         if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) {
 1155                 /* UDP type and listeners will drop out here */
 1156                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN);
 1157                 return (ENOTCONN);
 1158         }
 1159         SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
 1160         sin6->sin6_family = AF_INET6;
 1161         sin6->sin6_len = sizeof(*sin6);
 1162 
 1163         /* We must recapture incase we blocked */
 1164         inp = (struct sctp_inpcb *)so->so_pcb;
 1165         if (inp == NULL) {
 1166                 SCTP_FREE_SONAME(sin6);
 1167                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
 1168                 return ECONNRESET;
 1169         }
 1170         SCTP_INP_RLOCK(inp);
 1171         stcb = LIST_FIRST(&inp->sctp_asoc_list);
 1172         if (stcb) {
 1173                 SCTP_TCB_LOCK(stcb);
 1174         }
 1175         SCTP_INP_RUNLOCK(inp);
 1176         if (stcb == NULL) {
 1177                 SCTP_FREE_SONAME(sin6);
 1178                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
 1179                 return ECONNRESET;
 1180         }
 1181         fnd = 0;
 1182         TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
 1183                 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
 1184                 if (sin_a6->sin6_family == AF_INET6) {
 1185                         fnd = 1;
 1186                         sin6->sin6_port = stcb->rport;
 1187                         sin6->sin6_addr = sin_a6->sin6_addr;
 1188                         break;
 1189                 }
 1190         }
 1191         SCTP_TCB_UNLOCK(stcb);
 1192         if (!fnd) {
 1193                 /* No IPv4 address */
 1194                 SCTP_FREE_SONAME(sin6);
 1195                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
 1196                 return ENOENT;
 1197         }
 1198         if ((error = sa6_recoverscope(sin6)) != 0)
 1199                 return (error);
 1200         *addr = (struct sockaddr *)sin6;
 1201         return (0);
 1202 }
 1203 
 1204 static int
 1205 sctp6_in6getaddr(struct socket *so, struct sockaddr **nam)
 1206 {
 1207         struct sockaddr *addr;
 1208         struct in6pcb *inp6 = sotoin6pcb(so);
 1209         int error;
 1210 
 1211         if (inp6 == NULL) {
 1212                 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
 1213                 return EINVAL;
 1214         }
 1215         /* allow v6 addresses precedence */
 1216         error = sctp6_getaddr(so, nam);
 1217         if (error) {
 1218                 /* try v4 next if v6 failed */
 1219                 error = sctp_ingetaddr(so, nam);
 1220                 if (error) {
 1221                         return (error);
 1222                 }
 1223                 addr = *nam;
 1224                 /* if I'm V6ONLY, convert it to v4-mapped */
 1225                 if (SCTP_IPV6_V6ONLY(inp6)) {
 1226                         struct sockaddr_in6 sin6;
 1227 
 1228                         in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
 1229                         memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
 1230 
 1231                 }
 1232         }
 1233         return (error);
 1234 }
 1235 
 1236 
 1237 static int
 1238 sctp6_getpeeraddr(struct socket *so, struct sockaddr **nam)
 1239 {
 1240         struct sockaddr *addr = *nam;
 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_peeraddr(so, nam);
 1250         if (error) {
 1251                 /* try v4 next if v6 failed */
 1252                 error = sctp_peeraddr(so, nam);
 1253                 if (error) {
 1254                         return (error);
 1255                 }
 1256                 /* if I'm V6ONLY, convert it to v4-mapped */
 1257                 if (SCTP_IPV6_V6ONLY(inp6)) {
 1258                         struct sockaddr_in6 sin6;
 1259 
 1260                         in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
 1261                         memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
 1262                 }
 1263         }
 1264         return error;
 1265 }
 1266 
 1267 struct pr_usrreqs sctp6_usrreqs = {
 1268         .pru_abort = sctp6_abort,
 1269         .pru_accept = sctp_accept,
 1270         .pru_attach = sctp6_attach,
 1271         .pru_bind = sctp6_bind,
 1272         .pru_connect = sctp6_connect,
 1273         .pru_control = in6_control,
 1274         .pru_close = sctp6_close,
 1275         .pru_detach = sctp6_close,
 1276         .pru_sopoll = sopoll_generic,
 1277         .pru_flush = sctp_flush,
 1278         .pru_disconnect = sctp6_disconnect,
 1279         .pru_listen = sctp_listen,
 1280         .pru_peeraddr = sctp6_getpeeraddr,
 1281         .pru_send = sctp6_send,
 1282         .pru_shutdown = sctp_shutdown,
 1283         .pru_sockaddr = sctp6_in6getaddr,
 1284         .pru_sosend = sctp_sosend,
 1285         .pru_soreceive = sctp_soreceive
 1286 };

Cache object: 902bc459fc903de3eeb3c5d208e6425c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.