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

Cache object: 0f81a0a4cd72ea2e8adbc768eb21babd


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