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                 if (net->port) {
  290                         net->mtu -= sizeof(struct udphdr);
  291                 }
  292         }
  293         /* now what about the ep? */
  294         if (stcb->asoc.smallest_mtu > nxtsz) {
  295                 struct sctp_tmit_chunk *chk;
  296 
  297                 /* Adjust that too */
  298                 stcb->asoc.smallest_mtu = nxtsz;
  299                 /* now off to subtract IP_DF flag if needed */
  300 
  301                 TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
  302                         if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) {
  303                                 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
  304                         }
  305                 }
  306                 TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
  307                         if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) {
  308                                 /*
  309                                  * For this guy we also mark for immediate
  310                                  * resend since we sent to big of chunk
  311                                  */
  312                                 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
  313                                 if (chk->sent != SCTP_DATAGRAM_RESEND)
  314                                         stcb->asoc.sent_queue_retran_cnt++;
  315                                 chk->sent = SCTP_DATAGRAM_RESEND;
  316                                 chk->rec.data.doing_fast_retransmit = 0;
  317 
  318                                 chk->sent = SCTP_DATAGRAM_RESEND;
  319                                 /* Clear any time so NO RTT is being done */
  320                                 chk->sent_rcv_time.tv_sec = 0;
  321                                 chk->sent_rcv_time.tv_usec = 0;
  322                                 stcb->asoc.total_flight -= chk->send_size;
  323                                 net->flight_size -= chk->send_size;
  324                         }
  325                 }
  326         }
  327         sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL);
  328 out:
  329         if (stcb) {
  330                 SCTP_TCB_UNLOCK(stcb);
  331         }
  332 }
  333 
  334 
  335 void
  336 sctp6_notify(struct sctp_inpcb *inp,
  337     struct icmp6_hdr *icmph,
  338     struct sctphdr *sh,
  339     struct sockaddr *to,
  340     struct sctp_tcb *stcb,
  341     struct sctp_nets *net)
  342 {
  343 #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
  344         struct socket *so;
  345 
  346 #endif
  347         /* protection */
  348         int reason;
  349 
  350 
  351         if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
  352             (sh == NULL) || (to == NULL)) {
  353                 if (stcb)
  354                         SCTP_TCB_UNLOCK(stcb);
  355                 return;
  356         }
  357         /* First job is to verify the vtag matches what I would send */
  358         if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
  359                 SCTP_TCB_UNLOCK(stcb);
  360                 return;
  361         }
  362         if (icmph->icmp6_type != ICMP_UNREACH) {
  363                 /* We only care about unreachable */
  364                 SCTP_TCB_UNLOCK(stcb);
  365                 return;
  366         }
  367         if ((icmph->icmp6_code == ICMP_UNREACH_NET) ||
  368             (icmph->icmp6_code == ICMP_UNREACH_HOST) ||
  369             (icmph->icmp6_code == ICMP_UNREACH_NET_UNKNOWN) ||
  370             (icmph->icmp6_code == ICMP_UNREACH_HOST_UNKNOWN) ||
  371             (icmph->icmp6_code == ICMP_UNREACH_ISOLATED) ||
  372             (icmph->icmp6_code == ICMP_UNREACH_NET_PROHIB) ||
  373             (icmph->icmp6_code == ICMP_UNREACH_HOST_PROHIB) ||
  374             (icmph->icmp6_code == ICMP_UNREACH_FILTER_PROHIB)) {
  375 
  376                 /*
  377                  * Hmm reachablity problems we must examine closely. If its
  378                  * not reachable, we may have lost a network. Or if there is
  379                  * NO protocol at the other end named SCTP. well we consider
  380                  * it a OOTB abort.
  381                  */
  382                 if (net->dest_state & SCTP_ADDR_REACHABLE) {
  383                         /* Ok that destination is NOT reachable */
  384                         SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n",
  385                             net->error_count,
  386                             net->failure_threshold,
  387                             net);
  388 
  389                         net->dest_state &= ~SCTP_ADDR_REACHABLE;
  390                         net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
  391                         /*
  392                          * JRS 5/14/07 - If a destination is unreachable,
  393                          * the PF bit is turned off.  This allows an
  394                          * unambiguous use of the PF bit for destinations
  395                          * that are reachable but potentially failed. If the
  396                          * destination is set to the unreachable state, also
  397                          * set the destination to the PF state.
  398                          */
  399                         /*
  400                          * Add debug message here if destination is not in
  401                          * PF state.
  402                          */
  403                         /* Stop any running T3 timers here? */
  404                         if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_pf)) {
  405                                 net->dest_state &= ~SCTP_ADDR_PF;
  406                                 SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n",
  407                                     net);
  408                         }
  409                         net->error_count = net->failure_threshold + 1;
  410                         sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
  411                             stcb, SCTP_FAILED_THRESHOLD,
  412                             (void *)net, SCTP_SO_NOT_LOCKED);
  413                 }
  414                 SCTP_TCB_UNLOCK(stcb);
  415         } else if ((icmph->icmp6_code == ICMP_UNREACH_PROTOCOL) ||
  416             (icmph->icmp6_code == ICMP_UNREACH_PORT)) {
  417                 /*
  418                  * Here the peer is either playing tricks on us, including
  419                  * an address that belongs to someone who does not support
  420                  * SCTP OR was a userland implementation that shutdown and
  421                  * now is dead. In either case treat it like a OOTB abort
  422                  * with no TCB
  423                  */
  424                 reason = SCTP_PEER_FAULTY;
  425                 sctp_abort_notification(stcb, reason, SCTP_SO_NOT_LOCKED);
  426 #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
  427                 so = SCTP_INP_SO(inp);
  428                 atomic_add_int(&stcb->asoc.refcnt, 1);
  429                 SCTP_TCB_UNLOCK(stcb);
  430                 SCTP_SOCKET_LOCK(so, 1);
  431                 SCTP_TCB_LOCK(stcb);
  432                 atomic_subtract_int(&stcb->asoc.refcnt, 1);
  433 #endif
  434                 (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
  435 #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
  436                 SCTP_SOCKET_UNLOCK(so, 1);
  437                 /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */
  438 #endif
  439                 /* no need to unlock here, since the TCB is gone */
  440         } else {
  441                 SCTP_TCB_UNLOCK(stcb);
  442         }
  443 }
  444 
  445 
  446 
  447 void
  448 sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d)
  449 {
  450         struct sctphdr sh;
  451         struct ip6ctlparam *ip6cp = NULL;
  452         uint32_t vrf_id;
  453 
  454         vrf_id = SCTP_DEFAULT_VRFID;
  455 
  456         if (pktdst->sa_family != AF_INET6 ||
  457             pktdst->sa_len != sizeof(struct sockaddr_in6))
  458                 return;
  459 
  460         if ((unsigned)cmd >= PRC_NCMDS)
  461                 return;
  462         if (PRC_IS_REDIRECT(cmd)) {
  463                 d = NULL;
  464         } else if (inet6ctlerrmap[cmd] == 0) {
  465                 return;
  466         }
  467         /* if the parameter is from icmp6, decode it. */
  468         if (d != NULL) {
  469                 ip6cp = (struct ip6ctlparam *)d;
  470         } else {
  471                 ip6cp = (struct ip6ctlparam *)NULL;
  472         }
  473 
  474         if (ip6cp) {
  475                 /*
  476                  * XXX: We assume that when IPV6 is non NULL, M and OFF are
  477                  * valid.
  478                  */
  479                 /* check if we can safely examine src and dst ports */
  480                 struct sctp_inpcb *inp = NULL;
  481                 struct sctp_tcb *stcb = NULL;
  482                 struct sctp_nets *net = NULL;
  483                 struct sockaddr_in6 final;
  484 
  485                 if (ip6cp->ip6c_m == NULL)
  486                         return;
  487 
  488                 bzero(&sh, sizeof(sh));
  489                 bzero(&final, sizeof(final));
  490                 inp = NULL;
  491                 net = NULL;
  492                 m_copydata(ip6cp->ip6c_m, ip6cp->ip6c_off, sizeof(sh),
  493                     (caddr_t)&sh);
  494                 ip6cp->ip6c_src->sin6_port = sh.src_port;
  495                 final.sin6_len = sizeof(final);
  496                 final.sin6_family = AF_INET6;
  497                 final.sin6_addr = ((struct sockaddr_in6 *)pktdst)->sin6_addr;
  498                 final.sin6_port = sh.dest_port;
  499                 stcb = sctp_findassociation_addr_sa((struct sockaddr *)ip6cp->ip6c_src,
  500                     (struct sockaddr *)&final,
  501                     &inp, &net, 1, vrf_id);
  502                 /* inp's ref-count increased && stcb locked */
  503                 if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
  504                         if (cmd == PRC_MSGSIZE) {
  505                                 sctp6_notify_mbuf(inp,
  506                                     ip6cp->ip6c_icmp6,
  507                                     &sh,
  508                                     stcb,
  509                                     net);
  510                                 /* inp's ref-count reduced && stcb unlocked */
  511                         } else {
  512                                 sctp6_notify(inp, ip6cp->ip6c_icmp6, &sh,
  513                                     (struct sockaddr *)&final,
  514                                     stcb, net);
  515                                 /* inp's ref-count reduced && stcb unlocked */
  516                         }
  517                 } else {
  518                         if (PRC_IS_REDIRECT(cmd) && inp) {
  519                                 in6_rtchange((struct in6pcb *)inp,
  520                                     inet6ctlerrmap[cmd]);
  521                         }
  522                         if (inp) {
  523                                 /* reduce inp's ref-count */
  524                                 SCTP_INP_WLOCK(inp);
  525                                 SCTP_INP_DECR_REF(inp);
  526                                 SCTP_INP_WUNLOCK(inp);
  527                         }
  528                         if (stcb)
  529                                 SCTP_TCB_UNLOCK(stcb);
  530                 }
  531         }
  532 }
  533 
  534 /*
  535  * this routine can probably be collasped into the one in sctp_userreq.c
  536  * since they do the same thing and now we lookup with a sockaddr
  537  */
  538 static int
  539 sctp6_getcred(SYSCTL_HANDLER_ARGS)
  540 {
  541         struct xucred xuc;
  542         struct sockaddr_in6 addrs[2];
  543         struct sctp_inpcb *inp;
  544         struct sctp_nets *net;
  545         struct sctp_tcb *stcb;
  546         int error;
  547         uint32_t vrf_id;
  548 
  549         vrf_id = SCTP_DEFAULT_VRFID;
  550 
  551         error = priv_check(req->td, PRIV_NETINET_GETCRED);
  552         if (error)
  553                 return (error);
  554 
  555         if (req->newlen != sizeof(addrs)) {
  556                 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  557                 return (EINVAL);
  558         }
  559         if (req->oldlen != sizeof(struct ucred)) {
  560                 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  561                 return (EINVAL);
  562         }
  563         error = SYSCTL_IN(req, addrs, sizeof(addrs));
  564         if (error)
  565                 return (error);
  566 
  567         stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[0]),
  568             sin6tosa(&addrs[1]),
  569             &inp, &net, 1, vrf_id);
  570         if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
  571                 if ((inp != NULL) && (stcb == NULL)) {
  572                         /* reduce ref-count */
  573                         SCTP_INP_WLOCK(inp);
  574                         SCTP_INP_DECR_REF(inp);
  575                         goto cred_can_cont;
  576                 }
  577                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
  578                 error = ENOENT;
  579                 goto out;
  580         }
  581         SCTP_TCB_UNLOCK(stcb);
  582         /*
  583          * We use the write lock here, only since in the error leg we need
  584          * it. If we used RLOCK, then we would have to
  585          * wlock/decr/unlock/rlock. Which in theory could create a hole.
  586          * Better to use higher wlock.
  587          */
  588         SCTP_INP_WLOCK(inp);
  589 cred_can_cont:
  590         error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
  591         if (error) {
  592                 SCTP_INP_WUNLOCK(inp);
  593                 goto out;
  594         }
  595         cru2x(inp->sctp_socket->so_cred, &xuc);
  596         SCTP_INP_WUNLOCK(inp);
  597         error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
  598 out:
  599         return (error);
  600 }
  601 
  602 SYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
  603     0, 0,
  604     sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection");
  605 
  606 
  607 /* This is the same as the sctp_abort() could be made common */
  608 static void
  609 sctp6_abort(struct socket *so)
  610 {
  611         struct sctp_inpcb *inp;
  612         uint32_t flags;
  613 
  614         inp = (struct sctp_inpcb *)so->so_pcb;
  615         if (inp == 0) {
  616                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  617                 return;
  618         }
  619 sctp_must_try_again:
  620         flags = inp->sctp_flags;
  621 #ifdef SCTP_LOG_CLOSING
  622         sctp_log_closing(inp, NULL, 17);
  623 #endif
  624         if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
  625             (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
  626 #ifdef SCTP_LOG_CLOSING
  627                 sctp_log_closing(inp, NULL, 16);
  628 #endif
  629                 sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
  630                     SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
  631                 SOCK_LOCK(so);
  632                 SCTP_SB_CLEAR(so->so_snd);
  633                 /*
  634                  * same for the rcv ones, they are only here for the
  635                  * accounting/select.
  636                  */
  637                 SCTP_SB_CLEAR(so->so_rcv);
  638                 /* Now null out the reference, we are completely detached. */
  639                 so->so_pcb = NULL;
  640                 SOCK_UNLOCK(so);
  641         } else {
  642                 flags = inp->sctp_flags;
  643                 if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
  644                         goto sctp_must_try_again;
  645                 }
  646         }
  647         return;
  648 }
  649 
  650 static int
  651 sctp6_attach(struct socket *so, int proto, struct thread *p)
  652 {
  653         struct in6pcb *inp6;
  654         int error;
  655         struct sctp_inpcb *inp;
  656         uint32_t vrf_id = SCTP_DEFAULT_VRFID;
  657 
  658         inp = (struct sctp_inpcb *)so->so_pcb;
  659         if (inp != NULL) {
  660                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  661                 return EINVAL;
  662         }
  663         if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
  664                 error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace));
  665                 if (error)
  666                         return error;
  667         }
  668         error = sctp_inpcb_alloc(so, vrf_id);
  669         if (error)
  670                 return error;
  671         inp = (struct sctp_inpcb *)so->so_pcb;
  672         SCTP_INP_WLOCK(inp);
  673         inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6;     /* I'm v6! */
  674         inp6 = (struct in6pcb *)inp;
  675 
  676         inp6->inp_vflag |= INP_IPV6;
  677         inp6->in6p_hops = -1;   /* use kernel default */
  678         inp6->in6p_cksum = -1;  /* just to be sure */
  679 #ifdef INET
  680         /*
  681          * XXX: ugly!! IPv4 TTL initialization is necessary for an IPv6
  682          * socket as well, because the socket may be bound to an IPv6
  683          * wildcard address, which may match an IPv4-mapped IPv6 address.
  684          */
  685         inp6->inp_ip_ttl = MODULE_GLOBAL(MOD_INET, ip_defttl);
  686 #endif
  687         /*
  688          * Hmm what about the IPSEC stuff that is missing here but in
  689          * sctp_attach()?
  690          */
  691         SCTP_INP_WUNLOCK(inp);
  692         return 0;
  693 }
  694 
  695 static int
  696 sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
  697 {
  698         struct sctp_inpcb *inp;
  699         struct in6pcb *inp6;
  700         int error;
  701 
  702         inp = (struct sctp_inpcb *)so->so_pcb;
  703         if (inp == 0) {
  704                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  705                 return EINVAL;
  706         }
  707         if (addr) {
  708                 if ((addr->sa_family == AF_INET6) &&
  709                     (addr->sa_len != sizeof(struct sockaddr_in6))) {
  710                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  711                         return EINVAL;
  712                 }
  713                 if ((addr->sa_family == AF_INET) &&
  714                     (addr->sa_len != sizeof(struct sockaddr_in))) {
  715                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  716                         return EINVAL;
  717                 }
  718         }
  719         inp6 = (struct in6pcb *)inp;
  720         inp6->inp_vflag &= ~INP_IPV4;
  721         inp6->inp_vflag |= INP_IPV6;
  722         if ((addr != NULL) && (SCTP_IPV6_V6ONLY(inp6) == 0)) {
  723                 if (addr->sa_family == AF_INET) {
  724                         /* binding v4 addr to v6 socket, so reset flags */
  725                         inp6->inp_vflag |= INP_IPV4;
  726                         inp6->inp_vflag &= ~INP_IPV6;
  727                 } else {
  728                         struct sockaddr_in6 *sin6_p;
  729 
  730                         sin6_p = (struct sockaddr_in6 *)addr;
  731 
  732                         if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) {
  733                                 inp6->inp_vflag |= INP_IPV4;
  734                         } else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
  735                                 struct sockaddr_in sin;
  736 
  737                                 in6_sin6_2_sin(&sin, sin6_p);
  738                                 inp6->inp_vflag |= INP_IPV4;
  739                                 inp6->inp_vflag &= ~INP_IPV6;
  740                                 error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, NULL, p);
  741                                 return error;
  742                         }
  743                 }
  744         } else if (addr != NULL) {
  745                 /* IPV6_V6ONLY socket */
  746                 if (addr->sa_family == AF_INET) {
  747                         /* can't bind v4 addr to v6 only socket! */
  748                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  749                         return EINVAL;
  750                 } else {
  751                         struct sockaddr_in6 *sin6_p;
  752 
  753                         sin6_p = (struct sockaddr_in6 *)addr;
  754 
  755                         if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
  756                                 /* can't bind v4-mapped addrs either! */
  757                                 /* NOTE: we don't support SIIT */
  758                                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  759                                 return EINVAL;
  760                         }
  761                 }
  762         }
  763         error = sctp_inpcb_bind(so, addr, NULL, p);
  764         return error;
  765 }
  766 
  767 
  768 static void
  769 sctp6_close(struct socket *so)
  770 {
  771         sctp_close(so);
  772 }
  773 
  774 /* This could be made common with sctp_detach() since they are identical */
  775 
  776 static
  777 int
  778 sctp6_disconnect(struct socket *so)
  779 {
  780         return (sctp_disconnect(so));
  781 }
  782 
  783 
  784 int
  785 sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
  786     struct mbuf *control, struct thread *p);
  787 
  788 
  789 static int
  790 sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
  791     struct mbuf *control, struct thread *p)
  792 {
  793         struct sctp_inpcb *inp;
  794         struct inpcb *in_inp;
  795         struct in6pcb *inp6;
  796 
  797 #ifdef INET
  798         struct sockaddr_in6 *sin6;
  799 
  800 #endif                          /* INET */
  801         /* No SPL needed since sctp_output does this */
  802 
  803         inp = (struct sctp_inpcb *)so->so_pcb;
  804         if (inp == NULL) {
  805                 if (control) {
  806                         SCTP_RELEASE_PKT(control);
  807                         control = NULL;
  808                 }
  809                 SCTP_RELEASE_PKT(m);
  810                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  811                 return EINVAL;
  812         }
  813         in_inp = (struct inpcb *)inp;
  814         inp6 = (struct in6pcb *)inp;
  815         /*
  816          * For the TCP model we may get a NULL addr, if we are a connected
  817          * socket thats ok.
  818          */
  819         if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) &&
  820             (addr == NULL)) {
  821                 goto connected_type;
  822         }
  823         if (addr == NULL) {
  824                 SCTP_RELEASE_PKT(m);
  825                 if (control) {
  826                         SCTP_RELEASE_PKT(control);
  827                         control = NULL;
  828                 }
  829                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EDESTADDRREQ);
  830                 return (EDESTADDRREQ);
  831         }
  832 #ifdef INET
  833         sin6 = (struct sockaddr_in6 *)addr;
  834         if (SCTP_IPV6_V6ONLY(inp6)) {
  835                 /*
  836                  * if IPV6_V6ONLY flag, we discard datagrams destined to a
  837                  * v4 addr or v4-mapped addr
  838                  */
  839                 if (addr->sa_family == AF_INET) {
  840                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  841                         return EINVAL;
  842                 }
  843                 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
  844                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  845                         return EINVAL;
  846                 }
  847         }
  848         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
  849                 if (!MODULE_GLOBAL(MOD_INET6, ip6_v6only)) {
  850                         struct sockaddr_in sin;
  851 
  852                         /* convert v4-mapped into v4 addr and send */
  853                         in6_sin6_2_sin(&sin, sin6);
  854                         return sctp_sendm(so, flags, m, (struct sockaddr *)&sin,
  855                             control, p);
  856                 } else {
  857                         /* mapped addresses aren't enabled */
  858                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  859                         return EINVAL;
  860                 }
  861         }
  862 #endif                          /* INET */
  863 connected_type:
  864         /* now what about control */
  865         if (control) {
  866                 if (inp->control) {
  867                         SCTP_PRINTF("huh? control set?\n");
  868                         SCTP_RELEASE_PKT(inp->control);
  869                         inp->control = NULL;
  870                 }
  871                 inp->control = control;
  872         }
  873         /* Place the data */
  874         if (inp->pkt) {
  875                 SCTP_BUF_NEXT(inp->pkt_last) = m;
  876                 inp->pkt_last = m;
  877         } else {
  878                 inp->pkt_last = inp->pkt = m;
  879         }
  880         if (
  881         /* FreeBSD and MacOSX uses a flag passed */
  882             ((flags & PRUS_MORETOCOME) == 0)
  883             ) {
  884                 /*
  885                  * note with the current version this code will only be used
  886                  * by OpenBSD, NetBSD and FreeBSD have methods for
  887                  * re-defining sosend() to use sctp_sosend().  One can
  888                  * optionaly switch back to this code (by changing back the
  889                  * defininitions but this is not advisable.
  890                  */
  891                 int ret;
  892 
  893                 ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
  894                 inp->pkt = NULL;
  895                 inp->control = NULL;
  896                 return (ret);
  897         } else {
  898                 return (0);
  899         }
  900 }
  901 
  902 static int
  903 sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
  904 {
  905         uint32_t vrf_id;
  906         int error = 0;
  907         struct sctp_inpcb *inp;
  908         struct in6pcb *inp6;
  909         struct sctp_tcb *stcb;
  910 
  911 #ifdef INET
  912         struct sockaddr_in6 *sin6;
  913         struct sockaddr_storage ss;
  914 
  915 #endif                          /* INET */
  916 
  917         inp6 = (struct in6pcb *)so->so_pcb;
  918         inp = (struct sctp_inpcb *)so->so_pcb;
  919         if (inp == 0) {
  920                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
  921                 return (ECONNRESET);    /* I made the same as TCP since we are
  922                                          * not setup? */
  923         }
  924         if (addr == NULL) {
  925                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  926                 return (EINVAL);
  927         }
  928         if ((addr->sa_family == AF_INET6) && (addr->sa_len != sizeof(struct sockaddr_in6))) {
  929                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  930                 return (EINVAL);
  931         }
  932         if ((addr->sa_family == AF_INET) && (addr->sa_len != sizeof(struct sockaddr_in))) {
  933                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  934                 return (EINVAL);
  935         }
  936         vrf_id = inp->def_vrf_id;
  937         SCTP_ASOC_CREATE_LOCK(inp);
  938         SCTP_INP_RLOCK(inp);
  939         if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
  940             SCTP_PCB_FLAGS_UNBOUND) {
  941                 /* Bind a ephemeral port */
  942                 SCTP_INP_RUNLOCK(inp);
  943                 error = sctp6_bind(so, NULL, p);
  944                 if (error) {
  945                         SCTP_ASOC_CREATE_UNLOCK(inp);
  946 
  947                         return (error);
  948                 }
  949                 SCTP_INP_RLOCK(inp);
  950         }
  951         if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
  952             (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
  953                 /* We are already connected AND the TCP model */
  954                 SCTP_INP_RUNLOCK(inp);
  955                 SCTP_ASOC_CREATE_UNLOCK(inp);
  956                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EADDRINUSE);
  957                 return (EADDRINUSE);
  958         }
  959 #ifdef INET
  960         sin6 = (struct sockaddr_in6 *)addr;
  961         if (SCTP_IPV6_V6ONLY(inp6)) {
  962                 /*
  963                  * if IPV6_V6ONLY flag, ignore connections destined to a v4
  964                  * addr or v4-mapped addr
  965                  */
  966                 if (addr->sa_family == AF_INET) {
  967                         SCTP_INP_RUNLOCK(inp);
  968                         SCTP_ASOC_CREATE_UNLOCK(inp);
  969                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  970                         return EINVAL;
  971                 }
  972                 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
  973                         SCTP_INP_RUNLOCK(inp);
  974                         SCTP_ASOC_CREATE_UNLOCK(inp);
  975                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  976                         return EINVAL;
  977                 }
  978         }
  979         if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
  980                 if (!MODULE_GLOBAL(MOD_INET6, ip6_v6only)) {
  981                         /* convert v4-mapped into v4 addr */
  982                         in6_sin6_2_sin((struct sockaddr_in *)&ss, sin6);
  983                         addr = (struct sockaddr *)&ss;
  984                 } else {
  985                         /* mapped addresses aren't enabled */
  986                         SCTP_INP_RUNLOCK(inp);
  987                         SCTP_ASOC_CREATE_UNLOCK(inp);
  988                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
  989                         return EINVAL;
  990                 }
  991         } else
  992 #endif                          /* INET */
  993                 addr = addr;    /* for true v6 address case */
  994 
  995         /* Now do we connect? */
  996         if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
  997                 stcb = LIST_FIRST(&inp->sctp_asoc_list);
  998                 if (stcb) {
  999                         SCTP_TCB_UNLOCK(stcb);
 1000                 }
 1001                 SCTP_INP_RUNLOCK(inp);
 1002         } else {
 1003                 SCTP_INP_RUNLOCK(inp);
 1004                 SCTP_INP_WLOCK(inp);
 1005                 SCTP_INP_INCR_REF(inp);
 1006                 SCTP_INP_WUNLOCK(inp);
 1007                 stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
 1008                 if (stcb == NULL) {
 1009                         SCTP_INP_WLOCK(inp);
 1010                         SCTP_INP_DECR_REF(inp);
 1011                         SCTP_INP_WUNLOCK(inp);
 1012                 }
 1013         }
 1014 
 1015         if (stcb != NULL) {
 1016                 /* Already have or am bring up an association */
 1017                 SCTP_ASOC_CREATE_UNLOCK(inp);
 1018                 SCTP_TCB_UNLOCK(stcb);
 1019                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EALREADY);
 1020                 return (EALREADY);
 1021         }
 1022         /* We are GOOD to go */
 1023         stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0, vrf_id, p);
 1024         SCTP_ASOC_CREATE_UNLOCK(inp);
 1025         if (stcb == NULL) {
 1026                 /* Gak! no memory */
 1027                 return (error);
 1028         }
 1029         if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
 1030                 stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
 1031                 /* Set the connected flag so we can queue data */
 1032                 soisconnecting(so);
 1033         }
 1034         stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
 1035         (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
 1036 
 1037         /* initialize authentication parameters for the assoc */
 1038         sctp_initialize_auth_params(inp, stcb);
 1039 
 1040         sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
 1041         SCTP_TCB_UNLOCK(stcb);
 1042         return error;
 1043 }
 1044 
 1045 static int
 1046 sctp6_getaddr(struct socket *so, struct sockaddr **addr)
 1047 {
 1048         struct sockaddr_in6 *sin6;
 1049         struct sctp_inpcb *inp;
 1050         uint32_t vrf_id;
 1051         struct sctp_ifa *sctp_ifa;
 1052 
 1053         int error;
 1054 
 1055         /*
 1056          * Do the malloc first in case it blocks.
 1057          */
 1058         SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
 1059         sin6->sin6_family = AF_INET6;
 1060         sin6->sin6_len = sizeof(*sin6);
 1061 
 1062         inp = (struct sctp_inpcb *)so->so_pcb;
 1063         if (inp == NULL) {
 1064                 SCTP_FREE_SONAME(sin6);
 1065                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
 1066                 return ECONNRESET;
 1067         }
 1068         SCTP_INP_RLOCK(inp);
 1069         sin6->sin6_port = inp->sctp_lport;
 1070         if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
 1071                 /* For the bound all case you get back 0 */
 1072                 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
 1073                         struct sctp_tcb *stcb;
 1074                         struct sockaddr_in6 *sin_a6;
 1075                         struct sctp_nets *net;
 1076                         int fnd;
 1077 
 1078                         stcb = LIST_FIRST(&inp->sctp_asoc_list);
 1079                         if (stcb == NULL) {
 1080                                 goto notConn6;
 1081                         }
 1082                         fnd = 0;
 1083                         sin_a6 = NULL;
 1084                         TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
 1085                                 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
 1086                                 if (sin_a6 == NULL)
 1087                                         /* this will make coverity happy */
 1088                                         continue;
 1089 
 1090                                 if (sin_a6->sin6_family == AF_INET6) {
 1091                                         fnd = 1;
 1092                                         break;
 1093                                 }
 1094                         }
 1095                         if ((!fnd) || (sin_a6 == NULL)) {
 1096                                 /* punt */
 1097                                 goto notConn6;
 1098                         }
 1099                         vrf_id = inp->def_vrf_id;
 1100                         sctp_ifa = sctp_source_address_selection(inp, stcb, (sctp_route_t *) & net->ro, net, 0, vrf_id);
 1101                         if (sctp_ifa) {
 1102                                 sin6->sin6_addr = sctp_ifa->address.sin6.sin6_addr;
 1103                         }
 1104                 } else {
 1105                         /* For the bound all case you get back 0 */
 1106         notConn6:
 1107                         memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
 1108                 }
 1109         } else {
 1110                 /* Take the first IPv6 address in the list */
 1111                 struct sctp_laddr *laddr;
 1112                 int fnd = 0;
 1113 
 1114                 LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
 1115                         if (laddr->ifa->address.sa.sa_family == AF_INET6) {
 1116                                 struct sockaddr_in6 *sin_a;
 1117 
 1118                                 sin_a = (struct sockaddr_in6 *)&laddr->ifa->address.sin6;
 1119                                 sin6->sin6_addr = sin_a->sin6_addr;
 1120                                 fnd = 1;
 1121                                 break;
 1122                         }
 1123                 }
 1124                 if (!fnd) {
 1125                         SCTP_FREE_SONAME(sin6);
 1126                         SCTP_INP_RUNLOCK(inp);
 1127                         SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
 1128                         return ENOENT;
 1129                 }
 1130         }
 1131         SCTP_INP_RUNLOCK(inp);
 1132         /* Scoping things for v6 */
 1133         if ((error = sa6_recoverscope(sin6)) != 0) {
 1134                 SCTP_FREE_SONAME(sin6);
 1135                 return (error);
 1136         }
 1137         (*addr) = (struct sockaddr *)sin6;
 1138         return (0);
 1139 }
 1140 
 1141 static int
 1142 sctp6_peeraddr(struct socket *so, struct sockaddr **addr)
 1143 {
 1144         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)*addr;
 1145         int fnd;
 1146         struct sockaddr_in6 *sin_a6;
 1147         struct sctp_inpcb *inp;
 1148         struct sctp_tcb *stcb;
 1149         struct sctp_nets *net;
 1150 
 1151         int error;
 1152 
 1153         /*
 1154          * Do the malloc first in case it blocks.
 1155          */
 1156         inp = (struct sctp_inpcb *)so->so_pcb;
 1157         if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) {
 1158                 /* UDP type and listeners will drop out here */
 1159                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN);
 1160                 return (ENOTCONN);
 1161         }
 1162         SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
 1163         sin6->sin6_family = AF_INET6;
 1164         sin6->sin6_len = sizeof(*sin6);
 1165 
 1166         /* We must recapture incase we blocked */
 1167         inp = (struct sctp_inpcb *)so->so_pcb;
 1168         if (inp == NULL) {
 1169                 SCTP_FREE_SONAME(sin6);
 1170                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
 1171                 return ECONNRESET;
 1172         }
 1173         SCTP_INP_RLOCK(inp);
 1174         stcb = LIST_FIRST(&inp->sctp_asoc_list);
 1175         if (stcb) {
 1176                 SCTP_TCB_LOCK(stcb);
 1177         }
 1178         SCTP_INP_RUNLOCK(inp);
 1179         if (stcb == NULL) {
 1180                 SCTP_FREE_SONAME(sin6);
 1181                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
 1182                 return ECONNRESET;
 1183         }
 1184         fnd = 0;
 1185         TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
 1186                 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
 1187                 if (sin_a6->sin6_family == AF_INET6) {
 1188                         fnd = 1;
 1189                         sin6->sin6_port = stcb->rport;
 1190                         sin6->sin6_addr = sin_a6->sin6_addr;
 1191                         break;
 1192                 }
 1193         }
 1194         SCTP_TCB_UNLOCK(stcb);
 1195         if (!fnd) {
 1196                 /* No IPv4 address */
 1197                 SCTP_FREE_SONAME(sin6);
 1198                 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
 1199                 return ENOENT;
 1200         }
 1201         if ((error = sa6_recoverscope(sin6)) != 0)
 1202                 return (error);
 1203         *addr = (struct sockaddr *)sin6;
 1204         return (0);
 1205 }
 1206 
 1207 static int
 1208 sctp6_in6getaddr(struct socket *so, struct sockaddr **nam)
 1209 {
 1210         struct sockaddr *addr;
 1211         struct in6pcb *inp6 = sotoin6pcb(so);
 1212         int error;
 1213 
 1214         if (inp6 == NULL) {
 1215                 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
 1216                 return EINVAL;
 1217         }
 1218         /* allow v6 addresses precedence */
 1219         error = sctp6_getaddr(so, nam);
 1220         if (error) {
 1221                 /* try v4 next if v6 failed */
 1222                 error = sctp_ingetaddr(so, nam);
 1223                 if (error) {
 1224                         return (error);
 1225                 }
 1226                 addr = *nam;
 1227                 /* if I'm V6ONLY, convert it to v4-mapped */
 1228                 if (SCTP_IPV6_V6ONLY(inp6)) {
 1229                         struct sockaddr_in6 sin6;
 1230 
 1231                         in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
 1232                         memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
 1233 
 1234                 }
 1235         }
 1236         return (error);
 1237 }
 1238 
 1239 
 1240 static int
 1241 sctp6_getpeeraddr(struct socket *so, struct sockaddr **nam)
 1242 {
 1243         struct sockaddr *addr = *nam;
 1244         struct in6pcb *inp6 = sotoin6pcb(so);
 1245         int error;
 1246 
 1247         if (inp6 == NULL) {
 1248                 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
 1249                 return EINVAL;
 1250         }
 1251         /* allow v6 addresses precedence */
 1252         error = sctp6_peeraddr(so, nam);
 1253         if (error) {
 1254                 /* try v4 next if v6 failed */
 1255                 error = sctp_peeraddr(so, nam);
 1256                 if (error) {
 1257                         return (error);
 1258                 }
 1259                 /* if I'm V6ONLY, convert it to v4-mapped */
 1260                 if (SCTP_IPV6_V6ONLY(inp6)) {
 1261                         struct sockaddr_in6 sin6;
 1262 
 1263                         in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
 1264                         memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
 1265                 }
 1266         }
 1267         return error;
 1268 }
 1269 
 1270 struct pr_usrreqs sctp6_usrreqs = {
 1271         .pru_abort = sctp6_abort,
 1272         .pru_accept = sctp_accept,
 1273         .pru_attach = sctp6_attach,
 1274         .pru_bind = sctp6_bind,
 1275         .pru_connect = sctp6_connect,
 1276         .pru_control = in6_control,
 1277         .pru_close = sctp6_close,
 1278         .pru_detach = sctp6_close,
 1279         .pru_sopoll = sopoll_generic,
 1280         .pru_flush = sctp_flush,
 1281         .pru_disconnect = sctp6_disconnect,
 1282         .pru_listen = sctp_listen,
 1283         .pru_peeraddr = sctp6_getpeeraddr,
 1284         .pru_send = sctp6_send,
 1285         .pru_shutdown = sctp_shutdown,
 1286         .pru_sockaddr = sctp6_in6getaddr,
 1287         .pru_sosend = sctp_sosend,
 1288         .pru_soreceive = sctp_soreceive
 1289 };

Cache object: 2e254f4aaaaaad52dfb6b439527c4221


[ 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.