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/udp6_usrreq.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $KAME: udp6_usrreq.c,v 1.27 2001/05/21 05:45:10 jinmei Exp $    */
    2 /*      $KAME: udp6_output.c,v 1.31 2001/05/21 16:39:15 jinmei Exp $    */
    3 
    4 /*-
    5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. Neither the name of the project nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  */
   32 
   33 /*-
   34  * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
   35  *      The Regents of the University of California.
   36  * All rights reserved.
   37  *
   38  * Redistribution and use in source and binary forms, with or without
   39  * modification, are permitted provided that the following conditions
   40  * are met:
   41  * 1. Redistributions of source code must retain the above copyright
   42  *    notice, this list of conditions and the following disclaimer.
   43  * 2. Redistributions in binary form must reproduce the above copyright
   44  *    notice, this list of conditions and the following disclaimer in the
   45  *    documentation and/or other materials provided with the distribution.
   46  * 4. Neither the name of the University nor the names of its contributors
   47  *    may be used to endorse or promote products derived from this software
   48  *    without specific prior written permission.
   49  *
   50  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   60  * SUCH DAMAGE.
   61  *
   62  *      @(#)udp_usrreq.c        8.6 (Berkeley) 5/23/95
   63  * $FreeBSD$
   64  */
   65 
   66 #include "opt_inet.h"
   67 #include "opt_inet6.h"
   68 #include "opt_ipsec.h"
   69 #include "opt_mac.h"
   70 
   71 #include <sys/param.h>
   72 #include <sys/kernel.h>
   73 #include <sys/lock.h>
   74 #include <sys/mbuf.h>
   75 #include <sys/priv.h>
   76 #include <sys/proc.h>
   77 #include <sys/protosw.h>
   78 #include <sys/signalvar.h>
   79 #include <sys/socket.h>
   80 #include <sys/socketvar.h>
   81 #include <sys/sx.h>
   82 #include <sys/sysctl.h>
   83 #include <sys/syslog.h>
   84 #include <sys/systm.h>
   85 
   86 #include <net/if.h>
   87 #include <net/if_types.h>
   88 #include <net/route.h>
   89 
   90 #include <netinet/in.h>
   91 #include <netinet/in_pcb.h>
   92 #include <netinet/in_systm.h>
   93 #include <netinet/in_var.h>
   94 #include <netinet/ip.h>
   95 #include <netinet/ip_icmp.h>
   96 #include <netinet/ip6.h>
   97 #include <netinet/icmp_var.h>
   98 #include <netinet/icmp6.h>
   99 #include <netinet/ip_var.h>
  100 #include <netinet/udp.h>
  101 #include <netinet/udp_var.h>
  102 #include <netinet6/ip6protosw.h>
  103 #include <netinet6/ip6_var.h>
  104 #include <netinet6/in6_pcb.h>
  105 #include <netinet6/udp6_var.h>
  106 #include <netinet6/scope6_var.h>
  107 
  108 #ifdef IPSEC
  109 #include <netipsec/ipsec.h>
  110 #include <netipsec/ipsec6.h>
  111 #endif /* IPSEC */
  112 
  113 #include <security/mac/mac_framework.h>
  114 
  115 /*
  116  * UDP protocol implementation.
  117  * Per RFC 768, August, 1980.
  118  */
  119 
  120 extern struct protosw   inetsw[];
  121 static void             udp6_detach(struct socket *so);
  122 
  123 static void
  124 udp6_append(struct inpcb *inp, struct mbuf *n, int off,
  125     struct sockaddr_in6 *fromsa)
  126 {
  127         struct socket *so;
  128         struct mbuf *opts;
  129 
  130         INP_LOCK_ASSERT(inp);
  131 
  132 #ifdef IPSEC
  133         /* Check AH/ESP integrity. */
  134         if (ipsec6_in_reject(n, inp)) {
  135                 m_freem(n);
  136                 ipsec6stat.in_polvio++;
  137                 return;
  138         }
  139 #endif /* IPSEC */
  140 #ifdef MAC
  141         if (mac_check_inpcb_deliver(inp, n) != 0) {
  142                 m_freem(n);
  143                 return;
  144         }
  145 #endif
  146         opts = NULL;
  147         if (inp->in6p_flags & IN6P_CONTROLOPTS ||
  148             inp->inp_socket->so_options & SO_TIMESTAMP)
  149                 ip6_savecontrol(inp, n, &opts);
  150         m_adj(n, off + sizeof(struct udphdr));
  151 
  152         so = inp->inp_socket;
  153         SOCKBUF_LOCK(&so->so_rcv);
  154         if (sbappendaddr_locked(&so->so_rcv, (struct sockaddr *)fromsa, n,
  155             opts) == 0) {
  156                 SOCKBUF_UNLOCK(&so->so_rcv);
  157                 m_freem(n);
  158                 if (opts)
  159                         m_freem(opts);
  160                 udpstat.udps_fullsock++;
  161         } else
  162                 sorwakeup_locked(so);
  163 }
  164 
  165 int
  166 udp6_input(struct mbuf **mp, int *offp, int proto)
  167 {
  168         struct mbuf *m = *mp;
  169         struct ip6_hdr *ip6;
  170         struct udphdr *uh;
  171         struct inpcb *inp;
  172         int off = *offp;
  173         int plen, ulen;
  174         struct sockaddr_in6 fromsa;
  175 
  176         ip6 = mtod(m, struct ip6_hdr *);
  177 
  178         if (faithprefix_p != NULL && (*faithprefix_p)(&ip6->ip6_dst)) {
  179                 /* XXX send icmp6 host/port unreach? */
  180                 m_freem(m);
  181                 return (IPPROTO_DONE);
  182         }
  183 
  184 #ifndef PULLDOWN_TEST
  185         IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE);
  186         ip6 = mtod(m, struct ip6_hdr *);
  187         uh = (struct udphdr *)((caddr_t)ip6 + off);
  188 #else
  189         IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(*uh));
  190         if (!uh)
  191                 return (IPPROTO_DONE);
  192 #endif
  193 
  194         udpstat.udps_ipackets++;
  195 
  196         /*
  197          * Destination port of 0 is illegal, based on RFC768.
  198          */
  199         if (uh->uh_dport == 0)
  200                 goto badunlocked;
  201 
  202         plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6);
  203         ulen = ntohs((u_short)uh->uh_ulen);
  204 
  205         if (plen != ulen) {
  206                 udpstat.udps_badlen++;
  207                 goto badunlocked;
  208         }
  209 
  210         /*
  211          * Checksum extended UDP header and data.
  212          */
  213         if (uh->uh_sum == 0) {
  214                 udpstat.udps_nosum++;
  215                 goto badunlocked;
  216         }
  217         if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) {
  218                 udpstat.udps_badsum++;
  219                 goto badunlocked;
  220         }
  221 
  222         /*
  223          * Construct sockaddr format source address.
  224          */
  225         init_sin6(&fromsa, m);
  226         fromsa.sin6_port = uh->uh_sport;
  227 
  228         INP_INFO_RLOCK(&udbinfo);
  229         if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
  230                 struct inpcb *last;
  231 
  232                 /*
  233                  * In the event that laddr should be set to the link-local
  234                  * address (this happens in RIPng), the multicast address
  235                  * specified in the received packet will not match laddr.  To
  236                  * handle this situation, matching is relaxed if the
  237                  * receiving interface is the same as one specified in the
  238                  * socket and if the destination multicast address matches
  239                  * one of the multicast groups specified in the socket.
  240                  */
  241 
  242                 /*
  243                  * KAME note: traditionally we dropped udpiphdr from mbuf
  244                  * here.  We need udphdr for IPsec processing so we do that
  245                  * later.
  246                  */
  247                 last = NULL;
  248                 LIST_FOREACH(inp, &udb, inp_list) {
  249                         if ((inp->inp_vflag & INP_IPV6) == 0)
  250                                 continue;
  251                         if (inp->in6p_lport != uh->uh_dport)
  252                                 continue;
  253                         /*
  254                          * XXX: Do not check source port of incoming datagram
  255                          * unless inp_connect() has been called to bind the
  256                          * fport part of the 4-tuple; the source could be
  257                          * trying to talk to us with an ephemeral port.
  258                          */
  259                         if (inp->inp_fport != 0 &&
  260                             inp->inp_fport != uh->uh_sport)
  261                                 continue;
  262                         if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
  263                                 if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr,
  264                                                         &ip6->ip6_dst))
  265                                         continue;
  266                         }
  267                         if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
  268                                 if (!IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr,
  269                                                         &ip6->ip6_src) ||
  270                                     inp->in6p_fport != uh->uh_sport)
  271                                         continue;
  272                         }
  273 
  274                         if (last != NULL) {
  275                                 struct mbuf *n;
  276 
  277                                 if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
  278                                         INP_LOCK(last);
  279                                         udp6_append(last, n, off, &fromsa);
  280                                         INP_UNLOCK(last);
  281                                 }
  282                         }
  283                         last = inp;
  284                         /*
  285                          * Don't look for additional matches if this one does
  286                          * not have either the SO_REUSEPORT or SO_REUSEADDR
  287                          * socket options set.  This heuristic avoids
  288                          * searching through all pcbs in the common case of a
  289                          * non-shared port.  It assumes that an application
  290                          * will never clear these options after setting them.
  291                          */
  292                         if ((last->inp_socket->so_options &
  293                              (SO_REUSEPORT|SO_REUSEADDR)) == 0)
  294                                 break;
  295                 }
  296 
  297                 if (last == NULL) {
  298                         /*
  299                          * No matching pcb found; discard datagram.  (No need
  300                          * to send an ICMP Port Unreachable for a broadcast
  301                          * or multicast datgram.)
  302                          */
  303                         udpstat.udps_noport++;
  304                         udpstat.udps_noportmcast++;
  305                         goto badheadlocked;
  306                 }
  307                 INP_LOCK(last);
  308                 udp6_append(last, m, off, &fromsa);
  309                 INP_UNLOCK(last);
  310                 INP_INFO_RUNLOCK(&udbinfo);
  311                 return (IPPROTO_DONE);
  312         }
  313         /*
  314          * Locate pcb for datagram.
  315          */
  316         inp = in6_pcblookup_hash(&udbinfo, &ip6->ip6_src, uh->uh_sport,
  317             &ip6->ip6_dst, uh->uh_dport, 1, m->m_pkthdr.rcvif);
  318         if (inp == NULL) {
  319                 if (udp_log_in_vain) {
  320                         char ip6bufs[INET6_ADDRSTRLEN];
  321                         char ip6bufd[INET6_ADDRSTRLEN];
  322 
  323                         log(LOG_INFO,
  324                             "Connection attempt to UDP [%s]:%d from [%s]:%d\n",
  325                             ip6_sprintf(ip6bufd, &ip6->ip6_dst),
  326                             ntohs(uh->uh_dport),
  327                             ip6_sprintf(ip6bufs, &ip6->ip6_src),
  328                             ntohs(uh->uh_sport));
  329                 }
  330                 udpstat.udps_noport++;
  331                 if (m->m_flags & M_MCAST) {
  332                         printf("UDP6: M_MCAST is set in a unicast packet.\n");
  333                         udpstat.udps_noportmcast++;
  334                         goto badheadlocked;
  335                 }
  336                 INP_INFO_RUNLOCK(&udbinfo);
  337                 if (udp_blackhole)
  338                         goto badunlocked;
  339                 if (badport_bandlim(BANDLIM_ICMP6_UNREACH) < 0)
  340                         goto badunlocked;
  341                 icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
  342                 return (IPPROTO_DONE);
  343         }
  344         INP_LOCK(inp);
  345         udp6_append(inp, m, off, &fromsa);
  346         INP_UNLOCK(inp);
  347         INP_INFO_RUNLOCK(&udbinfo);
  348         return (IPPROTO_DONE);
  349 
  350 badheadlocked:
  351         INP_INFO_RUNLOCK(&udbinfo);
  352 badunlocked:
  353         if (m)
  354                 m_freem(m);
  355         return (IPPROTO_DONE);
  356 }
  357 
  358 void
  359 udp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
  360 {
  361         struct udphdr uh;
  362         struct ip6_hdr *ip6;
  363         struct mbuf *m;
  364         int off = 0;
  365         struct ip6ctlparam *ip6cp = NULL;
  366         const struct sockaddr_in6 *sa6_src = NULL;
  367         void *cmdarg;
  368         struct inpcb *(*notify) __P((struct inpcb *, int)) = udp_notify;
  369         struct udp_portonly {
  370                 u_int16_t uh_sport;
  371                 u_int16_t uh_dport;
  372         } *uhp;
  373 
  374         if (sa->sa_family != AF_INET6 ||
  375             sa->sa_len != sizeof(struct sockaddr_in6))
  376                 return;
  377 
  378         if ((unsigned)cmd >= PRC_NCMDS)
  379                 return;
  380         if (PRC_IS_REDIRECT(cmd))
  381                 notify = in6_rtchange, d = NULL;
  382         else if (cmd == PRC_HOSTDEAD)
  383                 d = NULL;
  384         else if (inet6ctlerrmap[cmd] == 0)
  385                 return;
  386 
  387         /* if the parameter is from icmp6, decode it. */
  388         if (d != NULL) {
  389                 ip6cp = (struct ip6ctlparam *)d;
  390                 m = ip6cp->ip6c_m;
  391                 ip6 = ip6cp->ip6c_ip6;
  392                 off = ip6cp->ip6c_off;
  393                 cmdarg = ip6cp->ip6c_cmdarg;
  394                 sa6_src = ip6cp->ip6c_src;
  395         } else {
  396                 m = NULL;
  397                 ip6 = NULL;
  398                 cmdarg = NULL;
  399                 sa6_src = &sa6_any;
  400         }
  401 
  402         if (ip6) {
  403                 /*
  404                  * XXX: We assume that when IPV6 is non NULL,
  405                  * M and OFF are valid.
  406                  */
  407 
  408                 /* Check if we can safely examine src and dst ports. */
  409                 if (m->m_pkthdr.len < off + sizeof(*uhp))
  410                         return;
  411 
  412                 bzero(&uh, sizeof(uh));
  413                 m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh);
  414 
  415                 (void) in6_pcbnotify(&udbinfo, sa, uh.uh_dport,
  416                     (struct sockaddr *)ip6cp->ip6c_src, uh.uh_sport, cmd,
  417                     cmdarg, notify);
  418         } else
  419                 (void) in6_pcbnotify(&udbinfo, sa, 0,
  420                     (const struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify);
  421 }
  422 
  423 static int
  424 udp6_getcred(SYSCTL_HANDLER_ARGS)
  425 {
  426         struct xucred xuc;
  427         struct sockaddr_in6 addrs[2];
  428         struct inpcb *inp;
  429         int error;
  430 
  431         error = priv_check(req->td, PRIV_NETINET_GETCRED);
  432         if (error)
  433                 return (error);
  434 
  435         if (req->newlen != sizeof(addrs))
  436                 return (EINVAL);
  437         if (req->oldlen != sizeof(struct xucred))
  438                 return (EINVAL);
  439         error = SYSCTL_IN(req, addrs, sizeof(addrs));
  440         if (error)
  441                 return (error);
  442         if ((error = sa6_embedscope(&addrs[0], ip6_use_defzone)) != 0 ||
  443             (error = sa6_embedscope(&addrs[1], ip6_use_defzone)) != 0) {
  444                 return (error);
  445         }
  446         INP_INFO_RLOCK(&udbinfo);
  447         inp = in6_pcblookup_hash(&udbinfo, &addrs[1].sin6_addr,
  448             addrs[1].sin6_port, &addrs[0].sin6_addr, addrs[0].sin6_port, 1,
  449             NULL);
  450         if (inp == NULL) {
  451                 INP_INFO_RUNLOCK(&udbinfo);
  452                 return (ENOENT);
  453         }
  454         INP_LOCK(inp);
  455         if (inp->inp_socket == NULL) {
  456                 error = ENOENT;
  457                 goto out;
  458         }
  459         error = cr_canseesocket(req->td->td_ucred, inp->inp_socket);
  460         if (error)
  461                 goto out;
  462         cru2x(inp->inp_socket->so_cred, &xuc);
  463 out:
  464         INP_UNLOCK(inp);
  465         INP_INFO_RUNLOCK(&udbinfo);
  466         if (error == 0)
  467                 error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
  468         return (error);
  469 }
  470 
  471 SYSCTL_PROC(_net_inet6_udp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW, 0,
  472     0, udp6_getcred, "S,xucred", "Get the xucred of a UDP6 connection");
  473 
  474 static int
  475 udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
  476     struct mbuf *control, struct thread *td)
  477 {
  478         u_int32_t ulen = m->m_pkthdr.len;
  479         u_int32_t plen = sizeof(struct udphdr) + ulen;
  480         struct ip6_hdr *ip6;
  481         struct udphdr *udp6;
  482         struct in6_addr *laddr, *faddr;
  483         struct sockaddr_in6 *sin6 = NULL;
  484         struct ifnet *oifp = NULL;
  485         int scope_ambiguous = 0;
  486         u_short fport;
  487         int error = 0;
  488         struct ip6_pktopts *optp, opt;
  489         int priv;
  490         int af = AF_INET6, hlen = sizeof(struct ip6_hdr);
  491         int flags;
  492         struct sockaddr_in6 tmp;
  493 
  494         INP_LOCK_ASSERT(inp);
  495 
  496         priv = 0;
  497         if (td && !suser(td))
  498                 priv = 1;
  499 
  500         if (addr6) {
  501                 /* addr6 has been validated in udp6_send(). */
  502                 sin6 = (struct sockaddr_in6 *)addr6;
  503 
  504                 /* protect *sin6 from overwrites */
  505                 tmp = *sin6;
  506                 sin6 = &tmp;
  507 
  508                 /*
  509                  * Application should provide a proper zone ID or the use of
  510                  * default zone IDs should be enabled.  Unfortunately, some
  511                  * applications do not behave as it should, so we need a
  512                  * workaround.  Even if an appropriate ID is not determined,
  513                  * we'll see if we can determine the outgoing interface.  If we
  514                  * can, determine the zone ID based on the interface below.
  515                  */
  516                 if (sin6->sin6_scope_id == 0 && !ip6_use_defzone)
  517                         scope_ambiguous = 1;
  518                 if ((error = sa6_embedscope(sin6, ip6_use_defzone)) != 0)
  519                         return (error);
  520         }
  521 
  522         if (control) {
  523                 if ((error = ip6_setpktopts(control, &opt,
  524                     inp->in6p_outputopts, priv, IPPROTO_UDP)) != 0)
  525                         goto release;
  526                 optp = &opt;
  527         } else
  528                 optp = inp->in6p_outputopts;
  529 
  530         if (sin6) {
  531                 faddr = &sin6->sin6_addr;
  532 
  533                 /*
  534                  * IPv4 version of udp_output calls in_pcbconnect in this case,
  535                  * which needs splnet and affects performance.
  536                  * Since we saw no essential reason for calling in_pcbconnect,
  537                  * we get rid of such kind of logic, and call in6_selectsrc
  538                  * and in6_pcbsetport in order to fill in the local address
  539                  * and the local port.
  540                  */
  541                 if (sin6->sin6_port == 0) {
  542                         error = EADDRNOTAVAIL;
  543                         goto release;
  544                 }
  545 
  546                 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
  547                         /* how about ::ffff:0.0.0.0 case? */
  548                         error = EISCONN;
  549                         goto release;
  550                 }
  551 
  552                 fport = sin6->sin6_port; /* allow 0 port */
  553 
  554                 if (IN6_IS_ADDR_V4MAPPED(faddr)) {
  555                         if ((inp->in6p_flags & IN6P_IPV6_V6ONLY)) {
  556                                 /*
  557                                  * I believe we should explicitly discard the
  558                                  * packet when mapped addresses are disabled,
  559                                  * rather than send the packet as an IPv6 one.
  560                                  * If we chose the latter approach, the packet
  561                                  * might be sent out on the wire based on the
  562                                  * default route, the situation which we'd
  563                                  * probably want to avoid.
  564                                  * (20010421 jinmei@kame.net)
  565                                  */
  566                                 error = EINVAL;
  567                                 goto release;
  568                         }
  569                         if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) &&
  570                             !IN6_IS_ADDR_V4MAPPED(&inp->in6p_laddr)) {
  571                                 /*
  572                                  * when remote addr is an IPv4-mapped address,
  573                                  * local addr should not be an IPv6 address,
  574                                  * since you cannot determine how to map IPv6
  575                                  * source address to IPv4.
  576                                  */
  577                                 error = EINVAL;
  578                                 goto release;
  579                         }
  580 
  581                         af = AF_INET;
  582                 }
  583 
  584                 if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
  585                         laddr = in6_selectsrc(sin6, optp, inp->in6p_moptions,
  586                             NULL, &inp->in6p_laddr, &oifp, &error);
  587                         if (oifp && scope_ambiguous &&
  588                             (error = in6_setscope(&sin6->sin6_addr,
  589                             oifp, NULL))) {
  590                                 goto release;
  591                         }
  592                 } else
  593                         laddr = &inp->in6p_laddr;       /* XXX */
  594                 if (laddr == NULL) {
  595                         if (error == 0)
  596                                 error = EADDRNOTAVAIL;
  597                         goto release;
  598                 }
  599                 if (inp->in6p_lport == 0 &&
  600                     (error = in6_pcbsetport(laddr, inp, td->td_ucred)) != 0)
  601                         goto release;
  602         } else {
  603                 if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
  604                         error = ENOTCONN;
  605                         goto release;
  606                 }
  607                 if (IN6_IS_ADDR_V4MAPPED(&inp->in6p_faddr)) {
  608                         if ((inp->in6p_flags & IN6P_IPV6_V6ONLY)) {
  609                                 /*
  610                                  * XXX: this case would happen when the
  611                                  * application sets the V6ONLY flag after
  612                                  * connecting the foreign address.
  613                                  * Such applications should be fixed,
  614                                  * so we bark here.
  615                                  */
  616                                 log(LOG_INFO, "udp6_output: IPV6_V6ONLY "
  617                                     "option was set for a connected socket\n");
  618                                 error = EINVAL;
  619                                 goto release;
  620                         } else
  621                                 af = AF_INET;
  622                 }
  623                 laddr = &inp->in6p_laddr;
  624                 faddr = &inp->in6p_faddr;
  625                 fport = inp->in6p_fport;
  626         }
  627 
  628         if (af == AF_INET)
  629                 hlen = sizeof(struct ip);
  630 
  631         /*
  632          * Calculate data length and get a mbuf
  633          * for UDP and IP6 headers.
  634          */
  635         M_PREPEND(m, hlen + sizeof(struct udphdr), M_DONTWAIT);
  636         if (m == 0) {
  637                 error = ENOBUFS;
  638                 goto release;
  639         }
  640 
  641         /*
  642          * Stuff checksum and output datagram.
  643          */
  644         udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen);
  645         udp6->uh_sport = inp->in6p_lport; /* lport is always set in the PCB */
  646         udp6->uh_dport = fport;
  647         if (plen <= 0xffff)
  648                 udp6->uh_ulen = htons((u_short)plen);
  649         else
  650                 udp6->uh_ulen = 0;
  651         udp6->uh_sum = 0;
  652 
  653         switch (af) {
  654         case AF_INET6:
  655                 ip6 = mtod(m, struct ip6_hdr *);
  656                 ip6->ip6_flow   = inp->in6p_flowinfo & IPV6_FLOWINFO_MASK;
  657                 ip6->ip6_vfc    &= ~IPV6_VERSION_MASK;
  658                 ip6->ip6_vfc    |= IPV6_VERSION;
  659 #if 0                           /* ip6_plen will be filled in ip6_output. */
  660                 ip6->ip6_plen   = htons((u_short)plen);
  661 #endif
  662                 ip6->ip6_nxt    = IPPROTO_UDP;
  663                 ip6->ip6_hlim   = in6_selecthlim(inp, NULL);
  664                 ip6->ip6_src    = *laddr;
  665                 ip6->ip6_dst    = *faddr;
  666 
  667                 if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP,
  668                                 sizeof(struct ip6_hdr), plen)) == 0) {
  669                         udp6->uh_sum = 0xffff;
  670                 }
  671 
  672                 flags = 0;
  673 
  674                 udpstat.udps_opackets++;
  675                 error = ip6_output(m, optp, NULL, flags, inp->in6p_moptions,
  676                     NULL, inp);
  677                 break;
  678         case AF_INET:
  679                 error = EAFNOSUPPORT;
  680                 goto release;
  681         }
  682         goto releaseopt;
  683 
  684 release:
  685         m_freem(m);
  686 
  687 releaseopt:
  688         if (control) {
  689                 ip6_clearpktopts(&opt, -1);
  690                 m_freem(control);
  691         }
  692         return (error);
  693 }
  694 
  695 static void
  696 udp6_abort(struct socket *so)
  697 {
  698         struct inpcb *inp;
  699 
  700         inp = sotoinpcb(so);
  701         KASSERT(inp != NULL, ("udp6_abort: inp == NULL"));
  702 
  703 #ifdef INET
  704         if (inp->inp_vflag & INP_IPV4) {
  705                 struct pr_usrreqs *pru;
  706 
  707                 pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
  708                 (*pru->pru_abort)(so);
  709                 return;
  710         }
  711 #endif
  712 
  713         INP_INFO_WLOCK(&udbinfo);
  714         INP_LOCK(inp);
  715         if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
  716                 in6_pcbdisconnect(inp);
  717                 inp->in6p_laddr = in6addr_any;
  718                 soisdisconnected(so);
  719         }
  720         INP_UNLOCK(inp);
  721         INP_INFO_WUNLOCK(&udbinfo);
  722 }
  723 
  724 static int
  725 udp6_attach(struct socket *so, int proto, struct thread *td)
  726 {
  727         struct inpcb *inp;
  728         int error;
  729 
  730         inp = sotoinpcb(so);
  731         KASSERT(inp == NULL, ("udp6_attach: inp != NULL"));
  732 
  733         if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
  734                 error = soreserve(so, udp_sendspace, udp_recvspace);
  735                 if (error)
  736                         return (error);
  737         }
  738         INP_INFO_WLOCK(&udbinfo);
  739         error = in_pcballoc(so, &udbinfo);
  740         if (error) {
  741                 INP_INFO_WUNLOCK(&udbinfo);
  742                 return (error);
  743         }
  744         inp = (struct inpcb *)so->so_pcb;
  745         INP_INFO_WUNLOCK(&udbinfo);
  746         inp->inp_vflag |= INP_IPV6;
  747         if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0)
  748                 inp->inp_vflag |= INP_IPV4;
  749         inp->in6p_hops = -1;    /* use kernel default */
  750         inp->in6p_cksum = -1;   /* just to be sure */
  751         /*
  752          * XXX: ugly!!
  753          * IPv4 TTL initialization is necessary for an IPv6 socket as well,
  754          * because the socket may be bound to an IPv6 wildcard address,
  755          * which may match an IPv4-mapped IPv6 address.
  756          */
  757         inp->inp_ip_ttl = ip_defttl;
  758         INP_UNLOCK(inp);
  759         return (0);
  760 }
  761 
  762 static int
  763 udp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
  764 {
  765         struct inpcb *inp;
  766         int error;
  767 
  768         inp = sotoinpcb(so);
  769         KASSERT(inp != NULL, ("udp6_bind: inp == NULL"));
  770 
  771         INP_INFO_WLOCK(&udbinfo);
  772         INP_LOCK(inp);
  773         inp->inp_vflag &= ~INP_IPV4;
  774         inp->inp_vflag |= INP_IPV6;
  775         if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
  776                 struct sockaddr_in6 *sin6_p;
  777 
  778                 sin6_p = (struct sockaddr_in6 *)nam;
  779 
  780                 if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr))
  781                         inp->inp_vflag |= INP_IPV4;
  782                 else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
  783                         struct sockaddr_in sin;
  784 
  785                         in6_sin6_2_sin(&sin, sin6_p);
  786                         inp->inp_vflag |= INP_IPV4;
  787                         inp->inp_vflag &= ~INP_IPV6;
  788                         error = in_pcbbind(inp, (struct sockaddr *)&sin,
  789                             td->td_ucred);
  790                         goto out;
  791                 }
  792         }
  793 
  794         error = in6_pcbbind(inp, nam, td->td_ucred);
  795 out:
  796         INP_UNLOCK(inp);
  797         INP_INFO_WUNLOCK(&udbinfo);
  798         return (error);
  799 }
  800 
  801 static void
  802 udp6_close(struct socket *so)
  803 {
  804         struct inpcb *inp;
  805 
  806         inp = sotoinpcb(so);
  807         KASSERT(inp != NULL, ("udp6_close: inp == NULL"));
  808 
  809 #ifdef INET
  810         if (inp->inp_vflag & INP_IPV4) {
  811                 struct pr_usrreqs *pru;
  812 
  813                 pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
  814                 (*pru->pru_disconnect)(so);
  815                 return;
  816         }
  817 #endif
  818         INP_INFO_WLOCK(&udbinfo);
  819         INP_LOCK(inp);
  820         if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
  821                 in6_pcbdisconnect(inp);
  822                 inp->in6p_laddr = in6addr_any;
  823                 soisdisconnected(so);
  824         }
  825         INP_UNLOCK(inp);
  826         INP_INFO_WUNLOCK(&udbinfo);
  827 }
  828 
  829 static int
  830 udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
  831 {
  832         struct inpcb *inp;
  833         int error;
  834 
  835         inp = sotoinpcb(so);
  836         KASSERT(inp != NULL, ("udp6_connect: inp == NULL"));
  837 
  838         INP_INFO_WLOCK(&udbinfo);
  839         INP_LOCK(inp);
  840         if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
  841                 struct sockaddr_in6 *sin6_p;
  842 
  843                 sin6_p = (struct sockaddr_in6 *)nam;
  844                 if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
  845                         struct sockaddr_in sin;
  846 
  847                         if (inp->inp_faddr.s_addr != INADDR_ANY) {
  848                                 error = EISCONN;
  849                                 goto out;
  850                         }
  851                         in6_sin6_2_sin(&sin, sin6_p);
  852                         error = in_pcbconnect(inp, (struct sockaddr *)&sin,
  853                             td->td_ucred);
  854                         if (error == 0) {
  855                                 inp->inp_vflag |= INP_IPV4;
  856                                 inp->inp_vflag &= ~INP_IPV6;
  857                                 soisconnected(so);
  858                         }
  859                         goto out;
  860                 }
  861         }
  862         if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
  863                 error = EISCONN;
  864                 goto out;
  865         }
  866         error = in6_pcbconnect(inp, nam, td->td_ucred);
  867         if (error == 0) {
  868                 if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
  869                         /* should be non mapped addr */
  870                         inp->inp_vflag &= ~INP_IPV4;
  871                         inp->inp_vflag |= INP_IPV6;
  872                 }
  873                 soisconnected(so);
  874         }
  875 out:
  876         INP_UNLOCK(inp);
  877         INP_INFO_WUNLOCK(&udbinfo);
  878         return (error);
  879 }
  880 
  881 static void
  882 udp6_detach(struct socket *so)
  883 {
  884         struct inpcb *inp;
  885 
  886         inp = sotoinpcb(so);
  887         KASSERT(inp != NULL, ("udp6_detach: inp == NULL"));
  888 
  889         INP_INFO_WLOCK(&udbinfo);
  890         INP_LOCK(inp);
  891         in6_pcbdetach(inp);
  892         in6_pcbfree(inp);
  893         INP_INFO_WUNLOCK(&udbinfo);
  894 }
  895 
  896 static int
  897 udp6_disconnect(struct socket *so)
  898 {
  899         struct inpcb *inp;
  900         int error;
  901 
  902         inp = sotoinpcb(so);
  903         KASSERT(inp != NULL, ("udp6_disconnect: inp == NULL"));
  904 
  905         INP_INFO_WLOCK(&udbinfo);
  906         INP_LOCK(inp);
  907 
  908 #ifdef INET
  909         if (inp->inp_vflag & INP_IPV4) {
  910                 struct pr_usrreqs *pru;
  911 
  912                 pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
  913                 error = (*pru->pru_disconnect)(so);
  914                 goto out;
  915         }
  916 #endif
  917 
  918         if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
  919                 error = ENOTCONN;
  920                 goto out;
  921         }
  922 
  923         in6_pcbdisconnect(inp);
  924         inp->in6p_laddr = in6addr_any;
  925         /* XXXRW: so_state locking? */
  926         so->so_state &= ~SS_ISCONNECTED;                /* XXX */
  927 out:
  928         INP_UNLOCK(inp);
  929         INP_INFO_WUNLOCK(&udbinfo);
  930         return (0);
  931 }
  932 
  933 static int
  934 udp6_send(struct socket *so, int flags, struct mbuf *m,
  935     struct sockaddr *addr, struct mbuf *control, struct thread *td)
  936 {
  937         struct inpcb *inp;
  938         int error = 0;
  939 
  940         inp = sotoinpcb(so);
  941         KASSERT(inp != NULL, ("udp6_send: inp == NULL"));
  942 
  943         INP_INFO_WLOCK(&udbinfo);
  944         INP_LOCK(inp);
  945         if (addr) {
  946                 if (addr->sa_len != sizeof(struct sockaddr_in6)) {
  947                         error = EINVAL;
  948                         goto bad;
  949                 }
  950                 if (addr->sa_family != AF_INET6) {
  951                         error = EAFNOSUPPORT;
  952                         goto bad;
  953                 }
  954         }
  955 
  956 #ifdef INET
  957         if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
  958                 int hasv4addr;
  959                 struct sockaddr_in6 *sin6 = 0;
  960 
  961                 if (addr == 0)
  962                         hasv4addr = (inp->inp_vflag & INP_IPV4);
  963                 else {
  964                         sin6 = (struct sockaddr_in6 *)addr;
  965                         hasv4addr = IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)
  966                             ? 1 : 0;
  967                 }
  968                 if (hasv4addr) {
  969                         struct pr_usrreqs *pru;
  970 
  971                         if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) &&
  972                             !IN6_IS_ADDR_V4MAPPED(&inp->in6p_laddr)) {
  973                                 /*
  974                                  * When remote addr is IPv4-mapped address,
  975                                  * local addr should not be an IPv6 address;
  976                                  * since you cannot determine how to map IPv6
  977                                  * source address to IPv4.
  978                                  */
  979                                 error = EINVAL;
  980                                 goto out;
  981                         }
  982                         if (sin6)
  983                                 in6_sin6_2_sin_in_sock(addr);
  984                         pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
  985                         error = ((*pru->pru_send)(so, flags, m, addr, control,
  986                             td));
  987                         /* addr will just be freed in sendit(). */
  988                         goto out;
  989                 }
  990         }
  991 #endif
  992 #ifdef MAC
  993         mac_create_mbuf_from_inpcb(inp, m);
  994 #endif
  995         error = udp6_output(inp, m, addr, control, td);
  996 out:
  997         INP_UNLOCK(inp);
  998         INP_INFO_WUNLOCK(&udbinfo);
  999         return (error);
 1000 
 1001 bad:
 1002         INP_UNLOCK(inp);
 1003         INP_INFO_WUNLOCK(&udbinfo);
 1004         m_freem(m);
 1005         return (error);
 1006 }
 1007 
 1008 struct pr_usrreqs udp6_usrreqs = {
 1009         .pru_abort =            udp6_abort,
 1010         .pru_attach =           udp6_attach,
 1011         .pru_bind =             udp6_bind,
 1012         .pru_connect =          udp6_connect,
 1013         .pru_control =          in6_control,
 1014         .pru_detach =           udp6_detach,
 1015         .pru_disconnect =       udp6_disconnect,
 1016         .pru_peeraddr =         in6_mapped_peeraddr,
 1017         .pru_send =             udp6_send,
 1018         .pru_shutdown =         udp_shutdown,
 1019         .pru_sockaddr =         in6_mapped_sockaddr,
 1020         .pru_sosetlabel =       in_pcbsosetlabel,
 1021         .pru_close =            udp6_close
 1022 };

Cache object: 3f9df437163b48541a658d5035e07a2f


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