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/netinet/udp_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 /*      $OpenBSD: udp_usrreq.c,v 1.305 2023/01/22 12:05:44 mvs Exp $    */
    2 /*      $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */
    3 
    4 /*
    5  * Copyright (c) 1982, 1986, 1988, 1990, 1993
    6  *      The Regents of the University of California.  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 University 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 REGENTS 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 REGENTS 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  *      @(#)COPYRIGHT   1.1 (NRL) 17 January 1995
   33  *
   34  * NRL grants permission for redistribution and use in source and binary
   35  * forms, with or without modification, of the software and documentation
   36  * created at NRL provided that the following conditions are met:
   37  *
   38  * 1. Redistributions of source code must retain the above copyright
   39  *    notice, this list of conditions and the following disclaimer.
   40  * 2. Redistributions in binary form must reproduce the above copyright
   41  *    notice, this list of conditions and the following disclaimer in the
   42  *    documentation and/or other materials provided with the distribution.
   43  * 3. All advertising materials mentioning features or use of this software
   44  *    must display the following acknowledgements:
   45  *      This product includes software developed by the University of
   46  *      California, Berkeley and its contributors.
   47  *      This product includes software developed at the Information
   48  *      Technology Division, US Naval Research Laboratory.
   49  * 4. Neither the name of the NRL nor the names of its contributors
   50  *    may be used to endorse or promote products derived from this software
   51  *    without specific prior written permission.
   52  *
   53  * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
   54  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   55  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
   56  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL NRL OR
   57  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   58  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   59  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   60  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   61  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   62  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   63  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   64  *
   65  * The views and conclusions contained in the software and documentation
   66  * are those of the authors and should not be interpreted as representing
   67  * official policies, either expressed or implied, of the US Naval
   68  * Research Laboratory (NRL).
   69  */
   70 
   71 #include <sys/param.h>
   72 #include <sys/systm.h>
   73 #include <sys/mbuf.h>
   74 #include <sys/protosw.h>
   75 #include <sys/socket.h>
   76 #include <sys/socketvar.h>
   77 #include <sys/sysctl.h>
   78 #include <sys/domain.h>
   79 
   80 #include <net/if.h>
   81 #include <net/if_var.h>
   82 #include <net/if_media.h>
   83 #include <net/route.h>
   84 
   85 #include <netinet/in.h>
   86 #include <netinet/in_var.h>
   87 #include <netinet/ip.h>
   88 #include <netinet/in_pcb.h>
   89 #include <netinet/ip_var.h>
   90 #include <netinet/ip_icmp.h>
   91 #include <netinet/udp.h>
   92 #include <netinet/udp_var.h>
   93 
   94 #ifdef IPSEC
   95 #include <netinet/ip_ipsp.h>
   96 #include <netinet/ip_esp.h>
   97 #endif
   98 
   99 #ifdef INET6
  100 #include <netinet6/in6_var.h>
  101 #include <netinet6/ip6_var.h>
  102 #include <netinet6/ip6protosw.h>
  103 #endif /* INET6 */
  104 
  105 #include "pf.h"
  106 #if NPF > 0
  107 #include <net/pfvar.h>
  108 #endif
  109 
  110 #ifdef PIPEX
  111 #include <netinet/if_ether.h>
  112 #include <net/pipex.h>
  113 #endif
  114 
  115 /*
  116  * UDP protocol implementation.
  117  * Per RFC 768, August, 1980.
  118  */
  119 int     udpcksum = 1;
  120 
  121 u_int   udp_sendspace = 9216;           /* really max datagram size */
  122 u_int   udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
  123                                         /* 40 1K datagrams */
  124 
  125 const struct pr_usrreqs udp_usrreqs = {
  126         .pru_attach     = udp_attach,
  127         .pru_detach     = udp_detach,
  128         .pru_lock       = udp_lock,
  129         .pru_unlock     = udp_unlock,
  130         .pru_bind       = udp_bind,
  131         .pru_connect    = udp_connect,
  132         .pru_disconnect = udp_disconnect,
  133         .pru_shutdown   = udp_shutdown,
  134         .pru_send       = udp_send,
  135         .pru_control    = in_control,
  136         .pru_sockaddr   = in_sockaddr,
  137         .pru_peeraddr   = in_peeraddr,
  138 };
  139 
  140 #ifdef INET6
  141 const struct pr_usrreqs udp6_usrreqs = {
  142         .pru_attach     = udp_attach,
  143         .pru_detach     = udp_detach,
  144         .pru_lock       = udp_lock,
  145         .pru_unlock     = udp_unlock,
  146         .pru_bind       = udp_bind,
  147         .pru_connect    = udp_connect,
  148         .pru_disconnect = udp_disconnect,
  149         .pru_shutdown   = udp_shutdown,
  150         .pru_send       = udp_send,
  151         .pru_control    = in6_control,
  152         .pru_sockaddr   = in6_sockaddr,
  153         .pru_peeraddr   = in6_peeraddr,
  154 };
  155 #endif
  156 
  157 const struct sysctl_bounded_args udpctl_vars[] = {
  158         { UDPCTL_CHECKSUM, &udpcksum, 0, 1 },
  159         { UDPCTL_RECVSPACE, &udp_recvspace, 0, INT_MAX },
  160         { UDPCTL_SENDSPACE, &udp_sendspace, 0, INT_MAX },
  161 };
  162 
  163 struct  inpcbtable udbtable;
  164 struct  cpumem *udpcounters;
  165 
  166 void    udp_sbappend(struct inpcb *, struct mbuf *, struct ip *,
  167             struct ip6_hdr *, int, struct udphdr *, struct sockaddr *,
  168             u_int32_t);
  169 int     udp_output(struct inpcb *, struct mbuf *, struct mbuf *, struct mbuf *);
  170 void    udp_notify(struct inpcb *, int);
  171 int     udp_sysctl_udpstat(void *, size_t *, void *);
  172 
  173 #ifndef UDB_INITIAL_HASH_SIZE
  174 #define UDB_INITIAL_HASH_SIZE   128
  175 #endif
  176 
  177 void
  178 udp_init(void)
  179 {
  180         udpcounters = counters_alloc(udps_ncounters);
  181         in_pcbinit(&udbtable, UDB_INITIAL_HASH_SIZE);
  182 }
  183 
  184 int
  185 udp_input(struct mbuf **mp, int *offp, int proto, int af)
  186 {
  187         struct mbuf *m = *mp;
  188         int iphlen = *offp;
  189         struct ip *ip = NULL;
  190         struct udphdr *uh;
  191         struct inpcb *inp = NULL;
  192         struct ip save_ip;
  193         int len;
  194         u_int16_t savesum;
  195         union {
  196                 struct sockaddr sa;
  197                 struct sockaddr_in sin;
  198 #ifdef INET6
  199                 struct sockaddr_in6 sin6;
  200 #endif /* INET6 */
  201         } srcsa, dstsa;
  202         struct ip6_hdr *ip6 = NULL;
  203         u_int32_t ipsecflowinfo = 0;
  204 
  205         udpstat_inc(udps_ipackets);
  206 
  207         IP6_EXTHDR_GET(uh, struct udphdr *, m, iphlen, sizeof(struct udphdr));
  208         if (!uh) {
  209                 udpstat_inc(udps_hdrops);
  210                 return IPPROTO_DONE;
  211         }
  212 
  213         /* Check for illegal destination port 0 */
  214         if (uh->uh_dport == 0) {
  215                 udpstat_inc(udps_noport);
  216                 goto bad;
  217         }
  218 
  219         /*
  220          * Make mbuf data length reflect UDP length.
  221          * If not enough data to reflect UDP length, drop.
  222          */
  223         len = ntohs((u_int16_t)uh->uh_ulen);
  224         switch (af) {
  225         case AF_INET:
  226                 if (m->m_pkthdr.len - iphlen != len) {
  227                         if (len > (m->m_pkthdr.len - iphlen) ||
  228                             len < sizeof(struct udphdr)) {
  229                                 udpstat_inc(udps_badlen);
  230                                 goto bad;
  231                         }
  232                         m_adj(m, len - (m->m_pkthdr.len - iphlen));
  233                 }
  234                 ip = mtod(m, struct ip *);
  235                 /*
  236                  * Save a copy of the IP header in case we want restore it
  237                  * for sending an ICMP error message in response.
  238                  */
  239                 save_ip = *ip;
  240                 break;
  241 #ifdef INET6
  242         case AF_INET6:
  243                 /* jumbograms */
  244                 if (len == 0 && m->m_pkthdr.len - iphlen > 0xffff)
  245                         len = m->m_pkthdr.len - iphlen;
  246                 if (len != m->m_pkthdr.len - iphlen) {
  247                         udpstat_inc(udps_badlen);
  248                         goto bad;
  249                 }
  250                 ip6 = mtod(m, struct ip6_hdr *);
  251                 break;
  252 #endif /* INET6 */
  253         default:
  254                 unhandled_af(af);
  255         }
  256 
  257         /*
  258          * Checksum extended UDP header and data.
  259          * from W.R.Stevens: check incoming udp cksums even if
  260          *      udpcksum is not set.
  261          */
  262         savesum = uh->uh_sum;
  263         if (uh->uh_sum == 0) {
  264                 udpstat_inc(udps_nosum);
  265 #ifdef INET6
  266                 /*
  267                  * In IPv6, the UDP checksum is ALWAYS used.
  268                  */
  269                 if (ip6)
  270                         goto bad;
  271 #endif /* INET6 */
  272         } else {
  273                 if ((m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_OK) == 0) {
  274                         if (m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_BAD) {
  275                                 udpstat_inc(udps_badsum);
  276                                 goto bad;
  277                         }
  278                         udpstat_inc(udps_inswcsum);
  279 
  280                         if (ip)
  281                                 uh->uh_sum = in4_cksum(m, IPPROTO_UDP,
  282                                     iphlen, len);
  283 #ifdef INET6
  284                         else if (ip6)
  285                                 uh->uh_sum = in6_cksum(m, IPPROTO_UDP,
  286                                     iphlen, len);
  287 #endif /* INET6 */
  288                         if (uh->uh_sum != 0) {
  289                                 udpstat_inc(udps_badsum);
  290                                 goto bad;
  291                         }
  292                 }
  293         }
  294 
  295 #ifdef IPSEC
  296         if (udpencap_enable && udpencap_port && esp_enable &&
  297 #if NPF > 0
  298             !(m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) &&
  299 #endif
  300             uh->uh_dport == htons(udpencap_port)) {
  301                 u_int32_t spi;
  302                 int skip = iphlen + sizeof(struct udphdr);
  303 
  304                 if (m->m_pkthdr.len - skip < sizeof(u_int32_t)) {
  305                         /* packet too short */
  306                         m_freem(m);
  307                         return IPPROTO_DONE;
  308                 }
  309                 m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi);
  310                 /*
  311                  * decapsulate if the SPI is not zero, otherwise pass
  312                  * to userland
  313                  */
  314                 if (spi != 0) {
  315                         int protoff;
  316 
  317                         if ((m = *mp = m_pullup(m, skip)) == NULL) {
  318                                 udpstat_inc(udps_hdrops);
  319                                 return IPPROTO_DONE;
  320                         }
  321 
  322                         /* remove the UDP header */
  323                         bcopy(mtod(m, u_char *),
  324                             mtod(m, u_char *) + sizeof(struct udphdr), iphlen);
  325                         m_adj(m, sizeof(struct udphdr));
  326                         skip -= sizeof(struct udphdr);
  327 
  328                         espstat_inc(esps_udpencin);
  329                         protoff = af == AF_INET ? offsetof(struct ip, ip_p) :
  330                             offsetof(struct ip6_hdr, ip6_nxt);
  331                         return ipsec_common_input(mp, skip, protoff,
  332                             af, IPPROTO_ESP, 1);
  333                 }
  334         }
  335 #endif /* IPSEC */
  336 
  337         switch (af) {
  338         case AF_INET:
  339                 bzero(&srcsa, sizeof(struct sockaddr_in));
  340                 srcsa.sin.sin_len = sizeof(struct sockaddr_in);
  341                 srcsa.sin.sin_family = AF_INET;
  342                 srcsa.sin.sin_port = uh->uh_sport;
  343                 srcsa.sin.sin_addr = ip->ip_src;
  344 
  345                 bzero(&dstsa, sizeof(struct sockaddr_in));
  346                 dstsa.sin.sin_len = sizeof(struct sockaddr_in);
  347                 dstsa.sin.sin_family = AF_INET;
  348                 dstsa.sin.sin_port = uh->uh_dport;
  349                 dstsa.sin.sin_addr = ip->ip_dst;
  350                 break;
  351 #ifdef INET6
  352         case AF_INET6:
  353                 bzero(&srcsa, sizeof(struct sockaddr_in6));
  354                 srcsa.sin6.sin6_len = sizeof(struct sockaddr_in6);
  355                 srcsa.sin6.sin6_family = AF_INET6;
  356                 srcsa.sin6.sin6_port = uh->uh_sport;
  357 #if 0 /*XXX inbound flowinfo */
  358                 srcsa.sin6.sin6_flowinfo = htonl(0x0fffffff) & ip6->ip6_flow;
  359 #endif
  360                 /* KAME hack: recover scopeid */
  361                 in6_recoverscope(&srcsa.sin6, &ip6->ip6_src);
  362 
  363                 bzero(&dstsa, sizeof(struct sockaddr_in6));
  364                 dstsa.sin6.sin6_len = sizeof(struct sockaddr_in6);
  365                 dstsa.sin6.sin6_family = AF_INET6;
  366                 dstsa.sin6.sin6_port = uh->uh_dport;
  367 #if 0 /*XXX inbound flowinfo */
  368                 dstsa.sin6.sin6_flowinfo = htonl(0x0fffffff) & ip6->ip6_flow;
  369 #endif
  370                 /* KAME hack: recover scopeid */
  371                 in6_recoverscope(&dstsa.sin6, &ip6->ip6_dst);
  372                 break;
  373 #endif /* INET6 */
  374         }
  375 
  376         if (m->m_flags & (M_BCAST|M_MCAST)) {
  377                 SIMPLEQ_HEAD(, inpcb) inpcblist;
  378 
  379                 /*
  380                  * Deliver a multicast or broadcast datagram to *all* sockets
  381                  * for which the local and remote addresses and ports match
  382                  * those of the incoming datagram.  This allows more than
  383                  * one process to receive multi/broadcasts on the same port.
  384                  * (This really ought to be done for unicast datagrams as
  385                  * well, but that would cause problems with existing
  386                  * applications that open both address-specific sockets and
  387                  * a wildcard socket listening to the same port -- they would
  388                  * end up receiving duplicates of every unicast datagram.
  389                  * Those applications open the multiple sockets to overcome an
  390                  * inadequacy of the UDP socket interface, but for backwards
  391                  * compatibility we avoid the problem here rather than
  392                  * fixing the interface.  Maybe 4.5BSD will remedy this?)
  393                  */
  394 
  395                 /*
  396                  * Locate pcb(s) for datagram.
  397                  * (Algorithm copied from raw_intr().)
  398                  */
  399                 SIMPLEQ_INIT(&inpcblist);
  400                 rw_enter_write(&udbtable.inpt_notify);
  401                 mtx_enter(&udbtable.inpt_mtx);
  402                 TAILQ_FOREACH(inp, &udbtable.inpt_queue, inp_queue) {
  403                         if (inp->inp_socket->so_rcv.sb_state & SS_CANTRCVMORE)
  404                                 continue;
  405 #ifdef INET6
  406                         /* don't accept it if AF does not match */
  407                         if (ip6 && !(inp->inp_flags & INP_IPV6))
  408                                 continue;
  409                         if (!ip6 && (inp->inp_flags & INP_IPV6))
  410                                 continue;
  411 #endif
  412                         if (rtable_l2(inp->inp_rtableid) !=
  413                             rtable_l2(m->m_pkthdr.ph_rtableid))
  414                                 continue;
  415                         if (inp->inp_lport != uh->uh_dport)
  416                                 continue;
  417 #ifdef INET6
  418                         if (ip6) {
  419                                 if (inp->inp_ip6_minhlim &&
  420                                     inp->inp_ip6_minhlim > ip6->ip6_hlim)
  421                                         continue;
  422                                 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6))
  423                                         if (!IN6_ARE_ADDR_EQUAL(
  424                                             &inp->inp_laddr6, &ip6->ip6_dst))
  425                                                 continue;
  426                         } else
  427 #endif /* INET6 */
  428                         {
  429                                 if (inp->inp_ip_minttl &&
  430                                     inp->inp_ip_minttl > ip->ip_ttl)
  431                                         continue;
  432 
  433                                 if (inp->inp_laddr.s_addr != INADDR_ANY) {
  434                                         if (inp->inp_laddr.s_addr !=
  435                                             ip->ip_dst.s_addr)
  436                                                 continue;
  437                                 }
  438                         }
  439 #ifdef INET6
  440                         if (ip6) {
  441                                 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
  442                                         if (!IN6_ARE_ADDR_EQUAL(
  443                                             &inp->inp_faddr6, &ip6->ip6_src) ||
  444                                             inp->inp_fport != uh->uh_sport)
  445                                                 continue;
  446                         } else
  447 #endif /* INET6 */
  448                         if (inp->inp_faddr.s_addr != INADDR_ANY) {
  449                                 if (inp->inp_faddr.s_addr !=
  450                                     ip->ip_src.s_addr ||
  451                                     inp->inp_fport != uh->uh_sport)
  452                                         continue;
  453                         }
  454 
  455                         in_pcbref(inp);
  456                         SIMPLEQ_INSERT_TAIL(&inpcblist, inp, inp_notify);
  457 
  458                         /*
  459                          * Don't look for additional matches if this one does
  460                          * not have either the SO_REUSEPORT or SO_REUSEADDR
  461                          * socket options set.  This heuristic avoids searching
  462                          * through all pcbs in the common case of a non-shared
  463                          * port.  It assumes that an application will never
  464                          * clear these options after setting them.
  465                          */
  466                         if ((inp->inp_socket->so_options & (SO_REUSEPORT |
  467                             SO_REUSEADDR)) == 0)
  468                                 break;
  469                 }
  470                 mtx_leave(&udbtable.inpt_mtx);
  471 
  472                 if (SIMPLEQ_EMPTY(&inpcblist)) {
  473                         rw_exit_write(&udbtable.inpt_notify);
  474 
  475                         /*
  476                          * No matching pcb found; discard datagram.
  477                          * (No need to send an ICMP Port Unreachable
  478                          * for a broadcast or multicast datgram.)
  479                          */
  480                         udpstat_inc(udps_noportbcast);
  481                         goto bad;
  482                 }
  483 
  484                 while ((inp = SIMPLEQ_FIRST(&inpcblist)) != NULL) {
  485                         struct mbuf *n;
  486 
  487                         SIMPLEQ_REMOVE_HEAD(&inpcblist, inp_notify);
  488                         if (SIMPLEQ_EMPTY(&inpcblist))
  489                                 n = m;
  490                         else
  491                                 n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
  492                         if (n != NULL) {
  493                                 udp_sbappend(inp, n, ip, ip6, iphlen, uh,
  494                                     &srcsa.sa, 0);
  495                         }
  496                         in_pcbunref(inp);
  497                 }
  498                 rw_exit_write(&udbtable.inpt_notify);
  499 
  500                 return IPPROTO_DONE;
  501         }
  502         /*
  503          * Locate pcb for datagram.
  504          */
  505 #if NPF > 0
  506         inp = pf_inp_lookup(m);
  507 #endif
  508         if (inp == NULL) {
  509 #ifdef INET6
  510                 if (ip6)
  511                         inp = in6_pcblookup(&udbtable, &ip6->ip6_src,
  512                             uh->uh_sport, &ip6->ip6_dst, uh->uh_dport,
  513                             m->m_pkthdr.ph_rtableid);
  514                 else
  515 #endif /* INET6 */
  516                 inp = in_pcblookup(&udbtable, ip->ip_src, uh->uh_sport,
  517                     ip->ip_dst, uh->uh_dport, m->m_pkthdr.ph_rtableid);
  518         }
  519         if (inp == NULL) {
  520                 udpstat_inc(udps_pcbhashmiss);
  521 #ifdef INET6
  522                 if (ip6) {
  523                         inp = in6_pcblookup_listen(&udbtable, &ip6->ip6_dst,
  524                             uh->uh_dport, m, m->m_pkthdr.ph_rtableid);
  525                 } else
  526 #endif /* INET6 */
  527                 inp = in_pcblookup_listen(&udbtable, ip->ip_dst,
  528                     uh->uh_dport, m, m->m_pkthdr.ph_rtableid);
  529         }
  530 
  531 #ifdef IPSEC
  532         if (ipsec_in_use) {
  533                 struct m_tag *mtag;
  534                 struct tdb_ident *tdbi;
  535                 struct tdb *tdb;
  536                 int error;
  537 
  538                 mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
  539                 if (mtag != NULL) {
  540                         tdbi = (struct tdb_ident *)(mtag + 1);
  541                         tdb = gettdb(tdbi->rdomain, tdbi->spi,
  542                             &tdbi->dst, tdbi->proto);
  543                 } else
  544                         tdb = NULL;
  545                 error = ipsp_spd_lookup(m, af, iphlen, IPSP_DIRECTION_IN,
  546                     tdb, inp, NULL, NULL);
  547                 if (error) {
  548                         udpstat_inc(udps_nosec);
  549                         tdb_unref(tdb);
  550                         goto bad;
  551                 }
  552                 /* create ipsec options, id is not modified after creation */
  553                 if (tdb && tdb->tdb_ids)
  554                         ipsecflowinfo = tdb->tdb_ids->id_flow;
  555                 tdb_unref(tdb);
  556         }
  557 #endif /*IPSEC */
  558 
  559         if (inp == NULL) {
  560                 udpstat_inc(udps_noport);
  561                 if (m->m_flags & (M_BCAST | M_MCAST)) {
  562                         udpstat_inc(udps_noportbcast);
  563                         goto bad;
  564                 }
  565 #ifdef INET6
  566                 if (ip6) {
  567                         uh->uh_sum = savesum;
  568                         icmp6_error(m, ICMP6_DST_UNREACH,
  569                             ICMP6_DST_UNREACH_NOPORT,0);
  570                 } else
  571 #endif /* INET6 */
  572                 {
  573                         *ip = save_ip;
  574                         uh->uh_sum = savesum;
  575                         icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT,
  576                             0, 0);
  577                 }
  578                 return IPPROTO_DONE;
  579         }
  580 
  581         KASSERT(sotoinpcb(inp->inp_socket) == inp);
  582         soassertlocked(inp->inp_socket);
  583 
  584 #ifdef INET6
  585         if (ip6 && inp->inp_ip6_minhlim &&
  586             inp->inp_ip6_minhlim > ip6->ip6_hlim) {
  587                 goto bad;
  588         } else
  589 #endif
  590         if (ip && inp->inp_ip_minttl &&
  591             inp->inp_ip_minttl > ip->ip_ttl) {
  592                 goto bad;
  593         }
  594 
  595 #if NPF > 0
  596         if (inp->inp_socket->so_state & SS_ISCONNECTED)
  597                 pf_inp_link(m, inp);
  598 #endif
  599 
  600 #ifdef PIPEX
  601         if (pipex_enable && inp->inp_pipex) {
  602                 struct pipex_session *session;
  603                 int off = iphlen + sizeof(struct udphdr);
  604 
  605                 if ((session = pipex_l2tp_lookup_session(m, off)) != NULL) {
  606                         m = *mp = pipex_l2tp_input(m, off, session,
  607                             ipsecflowinfo);
  608                         pipex_rele_session(session);
  609                         if (m == NULL) {
  610                                 in_pcbunref(inp);
  611                                 return IPPROTO_DONE;
  612                         }
  613                 }
  614         }
  615 #endif
  616 
  617         udp_sbappend(inp, m, ip, ip6, iphlen, uh, &srcsa.sa, ipsecflowinfo);
  618         in_pcbunref(inp);
  619         return IPPROTO_DONE;
  620 bad:
  621         m_freem(m);
  622         in_pcbunref(inp);
  623         return IPPROTO_DONE;
  624 }
  625 
  626 void
  627 udp_sbappend(struct inpcb *inp, struct mbuf *m, struct ip *ip,
  628     struct ip6_hdr *ip6, int hlen, struct udphdr *uh,
  629     struct sockaddr *srcaddr, u_int32_t ipsecflowinfo)
  630 {
  631         struct socket *so = inp->inp_socket;
  632         struct mbuf *opts = NULL;
  633 
  634         hlen += sizeof(*uh);
  635 
  636         if (inp->inp_upcall != NULL) {
  637                 m = (*inp->inp_upcall)(inp->inp_upcall_arg, m,
  638                     ip, ip6, uh, hlen);
  639                 if (m == NULL)
  640                         return;
  641         }
  642 
  643 #ifdef INET6
  644         if (ip6 && (inp->inp_flags & IN6P_CONTROLOPTS ||
  645             so->so_options & SO_TIMESTAMP))
  646                 ip6_savecontrol(inp, m, &opts);
  647 #endif /* INET6 */
  648         if (ip && (inp->inp_flags & INP_CONTROLOPTS ||
  649             so->so_options & SO_TIMESTAMP))
  650                 ip_savecontrol(inp, &opts, ip, m);
  651 #ifdef INET6
  652         if (ip6 && (inp->inp_flags & IN6P_RECVDSTPORT)) {
  653                 struct mbuf **mp = &opts;
  654 
  655                 while (*mp)
  656                         mp = &(*mp)->m_next;
  657                 *mp = sbcreatecontrol((caddr_t)&uh->uh_dport, sizeof(u_int16_t),
  658                     IPV6_RECVDSTPORT, IPPROTO_IPV6);
  659         }
  660 #endif /* INET6 */
  661         if (ip && (inp->inp_flags & INP_RECVDSTPORT)) {
  662                 struct mbuf **mp = &opts;
  663 
  664                 while (*mp)
  665                         mp = &(*mp)->m_next;
  666                 *mp = sbcreatecontrol((caddr_t)&uh->uh_dport, sizeof(u_int16_t),
  667                     IP_RECVDSTPORT, IPPROTO_IP);
  668         }
  669 #ifdef IPSEC
  670         if (ipsecflowinfo && (inp->inp_flags & INP_IPSECFLOWINFO)) {
  671                 struct mbuf **mp = &opts;
  672 
  673                 while (*mp)
  674                         mp = &(*mp)->m_next;
  675                 *mp = sbcreatecontrol((caddr_t)&ipsecflowinfo,
  676                     sizeof(u_int32_t), IP_IPSECFLOWINFO, IPPROTO_IP);
  677         }
  678 #endif
  679         m_adj(m, hlen);
  680 
  681         mtx_enter(&inp->inp_mtx);
  682         if (sbappendaddr(so, &so->so_rcv, srcaddr, m, opts) == 0) {
  683                 mtx_leave(&inp->inp_mtx);
  684                 udpstat_inc(udps_fullsock);
  685                 m_freem(m);
  686                 m_freem(opts);
  687                 return;
  688         }
  689         mtx_leave(&inp->inp_mtx);
  690 
  691         sorwakeup(so);
  692 }
  693 
  694 /*
  695  * Notify a udp user of an asynchronous error;
  696  * just wake up so that he can collect error status.
  697  */
  698 void
  699 udp_notify(struct inpcb *inp, int errno)
  700 {
  701         inp->inp_socket->so_error = errno;
  702         sorwakeup(inp->inp_socket);
  703         sowwakeup(inp->inp_socket);
  704 }
  705 
  706 #ifdef INET6
  707 void
  708 udp6_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *d)
  709 {
  710         struct udphdr uh;
  711         struct sockaddr_in6 sa6;
  712         struct ip6_hdr *ip6;
  713         struct mbuf *m;
  714         int off;
  715         void *cmdarg;
  716         struct ip6ctlparam *ip6cp = NULL;
  717         struct udp_portonly {
  718                 u_int16_t uh_sport;
  719                 u_int16_t uh_dport;
  720         } *uhp;
  721         struct inpcb *inp;
  722         void (*notify)(struct inpcb *, int) = udp_notify;
  723 
  724         if (sa == NULL)
  725                 return;
  726         if (sa->sa_family != AF_INET6 ||
  727             sa->sa_len != sizeof(struct sockaddr_in6))
  728                 return;
  729 
  730         if ((unsigned)cmd >= PRC_NCMDS)
  731                 return;
  732         if (PRC_IS_REDIRECT(cmd))
  733                 notify = in_rtchange, d = NULL;
  734         else if (cmd == PRC_HOSTDEAD)
  735                 d = NULL;
  736         else if (cmd == PRC_MSGSIZE)
  737                 ; /* special code is present, see below */
  738         else if (inet6ctlerrmap[cmd] == 0)
  739                 return;
  740 
  741         /* if the parameter is from icmp6, decode it. */
  742         if (d != NULL) {
  743                 ip6cp = (struct ip6ctlparam *)d;
  744                 m = ip6cp->ip6c_m;
  745                 ip6 = ip6cp->ip6c_ip6;
  746                 off = ip6cp->ip6c_off;
  747                 cmdarg = ip6cp->ip6c_cmdarg;
  748         } else {
  749                 m = NULL;
  750                 ip6 = NULL;
  751                 cmdarg = NULL;
  752                 /* XXX: translate addresses into internal form */
  753                 sa6 = *satosin6(sa);
  754                 if (in6_embedscope(&sa6.sin6_addr, &sa6, NULL)) {
  755                         /* should be impossible */
  756                         return;
  757                 }
  758         }
  759 
  760         if (ip6cp && ip6cp->ip6c_finaldst) {
  761                 bzero(&sa6, sizeof(sa6));
  762                 sa6.sin6_family = AF_INET6;
  763                 sa6.sin6_len = sizeof(sa6);
  764                 sa6.sin6_addr = *ip6cp->ip6c_finaldst;
  765                 /* XXX: assuming M is valid in this case */
  766                 sa6.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.ph_ifidx,
  767                     ip6cp->ip6c_finaldst);
  768                 if (in6_embedscope(ip6cp->ip6c_finaldst, &sa6, NULL)) {
  769                         /* should be impossible */
  770                         return;
  771                 }
  772         } else {
  773                 /* XXX: translate addresses into internal form */
  774                 sa6 = *satosin6(sa);
  775                 if (in6_embedscope(&sa6.sin6_addr, &sa6, NULL)) {
  776                         /* should be impossible */
  777                         return;
  778                 }
  779         }
  780 
  781         if (ip6) {
  782                 /*
  783                  * XXX: We assume that when IPV6 is non NULL,
  784                  * M and OFF are valid.
  785                  */
  786                 struct sockaddr_in6 sa6_src;
  787 
  788                 /* check if we can safely examine src and dst ports */
  789                 if (m->m_pkthdr.len < off + sizeof(*uhp))
  790                         return;
  791 
  792                 bzero(&uh, sizeof(uh));
  793                 m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh);
  794 
  795                 bzero(&sa6_src, sizeof(sa6_src));
  796                 sa6_src.sin6_family = AF_INET6;
  797                 sa6_src.sin6_len = sizeof(sa6_src);
  798                 sa6_src.sin6_addr = ip6->ip6_src;
  799                 sa6_src.sin6_scope_id = in6_addr2scopeid(m->m_pkthdr.ph_ifidx,
  800                     &ip6->ip6_src);
  801                 if (in6_embedscope(&sa6_src.sin6_addr, &sa6_src, NULL)) {
  802                         /* should be impossible */
  803                         return;
  804                 }
  805 
  806                 if (cmd == PRC_MSGSIZE) {
  807                         /*
  808                          * Check to see if we have a valid UDP socket
  809                          * corresponding to the address in the ICMPv6 message
  810                          * payload.
  811                          */
  812                         inp = in6_pcblookup(&udbtable, &sa6.sin6_addr,
  813                             uh.uh_dport, &sa6_src.sin6_addr, uh.uh_sport,
  814                             rdomain);
  815 #if 0
  816                         /*
  817                          * As the use of sendto(2) is fairly popular,
  818                          * we may want to allow non-connected pcb too.
  819                          * But it could be too weak against attacks...
  820                          * We should at least check if the local address (= s)
  821                          * is really ours.
  822                          */
  823                         if (inp == NULL) {
  824                                 inp = in6_pcblookup_listen(&udbtable,
  825                                     &sa6_src.sin6_addr, uh.uh_sport, NULL,
  826                                     rdomain))
  827                         }
  828 #endif
  829 
  830                         /*
  831                          * Depending on the value of "valid" and routing table
  832                          * size (mtudisc_{hi,lo}wat), we will:
  833                          * - recalculate the new MTU and create the
  834                          *   corresponding routing entry, or
  835                          * - ignore the MTU change notification.
  836                          */
  837                         icmp6_mtudisc_update((struct ip6ctlparam *)d,
  838                             inp != NULL);
  839                         in_pcbunref(inp);
  840 
  841                         /*
  842                          * regardless of if we called icmp6_mtudisc_update(),
  843                          * we need to call in6_pcbnotify(), to notify path
  844                          * MTU change to the userland (2292bis-02), because
  845                          * some unconnected sockets may share the same
  846                          * destination and want to know the path MTU.
  847                          */
  848                 }
  849 
  850                 in6_pcbnotify(&udbtable, &sa6, uh.uh_dport,
  851                     &sa6_src, uh.uh_sport, rdomain, cmd, cmdarg, notify);
  852         } else {
  853                 in6_pcbnotify(&udbtable, &sa6, 0,
  854                     &sa6_any, 0, rdomain, cmd, cmdarg, notify);
  855         }
  856 }
  857 #endif
  858 
  859 void
  860 udp_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *v)
  861 {
  862         struct ip *ip = v;
  863         struct udphdr *uhp;
  864         struct in_addr faddr;
  865         struct inpcb *inp;
  866         void (*notify)(struct inpcb *, int) = udp_notify;
  867         int errno;
  868 
  869         if (sa == NULL)
  870                 return;
  871         if (sa->sa_family != AF_INET ||
  872             sa->sa_len != sizeof(struct sockaddr_in))
  873                 return;
  874         faddr = satosin(sa)->sin_addr;
  875         if (faddr.s_addr == INADDR_ANY)
  876                 return;
  877 
  878         if ((unsigned)cmd >= PRC_NCMDS)
  879                 return;
  880         errno = inetctlerrmap[cmd];
  881         if (PRC_IS_REDIRECT(cmd))
  882                 notify = in_rtchange, ip = 0;
  883         else if (cmd == PRC_HOSTDEAD)
  884                 ip = 0;
  885         else if (errno == 0)
  886                 return;
  887         if (ip) {
  888                 uhp = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
  889 
  890 #ifdef IPSEC
  891                 /* PMTU discovery for udpencap */
  892                 if (cmd == PRC_MSGSIZE && ip_mtudisc && udpencap_enable &&
  893                     udpencap_port && uhp->uh_sport == htons(udpencap_port)) {
  894                         udpencap_ctlinput(cmd, sa, rdomain, v);
  895                         return;
  896                 }
  897 #endif
  898                 inp = in_pcblookup(&udbtable,
  899                     ip->ip_dst, uhp->uh_dport, ip->ip_src, uhp->uh_sport,
  900                     rdomain);
  901                 if (inp && inp->inp_socket != NULL)
  902                         notify(inp, errno);
  903                 in_pcbunref(inp);
  904         } else
  905                 in_pcbnotifyall(&udbtable, sa, rdomain, errno, notify);
  906 }
  907 
  908 int
  909 udp_output(struct inpcb *inp, struct mbuf *m, struct mbuf *addr,
  910     struct mbuf *control)
  911 {
  912         struct sockaddr_in *sin = NULL;
  913         struct udpiphdr *ui;
  914         u_int32_t ipsecflowinfo = 0;
  915         struct sockaddr_in src_sin;
  916         int len = m->m_pkthdr.len;
  917         struct in_addr laddr;
  918         int error = 0;
  919 
  920 #ifdef DIAGNOSTIC
  921         if ((inp->inp_flags & INP_IPV6) != 0)
  922                 panic("IPv6 inpcb to %s", __func__);
  923 #endif
  924 
  925         /*
  926          * Compute the packet length of the IP header, and
  927          * punt if the length looks bogus.
  928          */
  929         if ((len + sizeof(struct udpiphdr)) > IP_MAXPACKET) {
  930                 error = EMSGSIZE;
  931                 goto release;
  932         }
  933 
  934         memset(&src_sin, 0, sizeof(src_sin));
  935 
  936         if (control) {
  937                 u_int clen;
  938                 struct cmsghdr *cm;
  939                 caddr_t cmsgs;
  940 
  941                 /*
  942                  * XXX: Currently, we assume all the optional information is
  943                  * stored in a single mbuf.
  944                  */
  945                 if (control->m_next) {
  946                         error = EINVAL;
  947                         goto release;
  948                 }
  949 
  950                 clen = control->m_len;
  951                 cmsgs = mtod(control, caddr_t);
  952                 do {
  953                         if (clen < CMSG_LEN(0)) {
  954                                 error = EINVAL;
  955                                 goto release;
  956                         }
  957                         cm = (struct cmsghdr *)cmsgs;
  958                         if (cm->cmsg_len < CMSG_LEN(0) ||
  959                             CMSG_ALIGN(cm->cmsg_len) > clen) {
  960                                 error = EINVAL;
  961                                 goto release;
  962                         }
  963 #ifdef IPSEC
  964                         if ((inp->inp_flags & INP_IPSECFLOWINFO) != 0 &&
  965                             cm->cmsg_len == CMSG_LEN(sizeof(ipsecflowinfo)) &&
  966                             cm->cmsg_level == IPPROTO_IP &&
  967                             cm->cmsg_type == IP_IPSECFLOWINFO) {
  968                                 ipsecflowinfo = *(u_int32_t *)CMSG_DATA(cm);
  969                         } else
  970 #endif
  971                         if (cm->cmsg_len == CMSG_LEN(sizeof(struct in_addr)) &&
  972                             cm->cmsg_level == IPPROTO_IP &&
  973                             cm->cmsg_type == IP_SENDSRCADDR) {
  974                                 memcpy(&src_sin.sin_addr, CMSG_DATA(cm),
  975                                     sizeof(struct in_addr));
  976                                 src_sin.sin_family = AF_INET;
  977                                 src_sin.sin_len = sizeof(src_sin);
  978                                 /* no check on reuse when sin->sin_port == 0 */
  979                                 if ((error = in_pcbaddrisavail(inp, &src_sin,
  980                                     0, curproc)))
  981                                         goto release;
  982                         }
  983                         clen -= CMSG_ALIGN(cm->cmsg_len);
  984                         cmsgs += CMSG_ALIGN(cm->cmsg_len);
  985                 } while (clen);
  986         }
  987 
  988         if (addr) {
  989                 if ((error = in_nam2sin(addr, &sin)))
  990                         goto release;
  991                 if (sin->sin_port == 0) {
  992                         error = EADDRNOTAVAIL;
  993                         goto release;
  994                 }
  995                 if (inp->inp_faddr.s_addr != INADDR_ANY) {
  996                         error = EISCONN;
  997                         goto release;
  998                 }
  999                 error = in_pcbselsrc(&laddr, sin, inp);
 1000                 if (error)
 1001                         goto release;
 1002 
 1003                 if (inp->inp_lport == 0) {
 1004                         error = in_pcbbind(inp, NULL, curproc);
 1005                         if (error)
 1006                                 goto release;
 1007                 }
 1008 
 1009                 if (src_sin.sin_len > 0 &&
 1010                     src_sin.sin_addr.s_addr != INADDR_ANY &&
 1011                     src_sin.sin_addr.s_addr != inp->inp_laddr.s_addr) {
 1012                         src_sin.sin_port = inp->inp_lport;
 1013                         if (inp->inp_laddr.s_addr != INADDR_ANY &&
 1014                             (error =
 1015                             in_pcbaddrisavail(inp, &src_sin, 0, curproc)))
 1016                                 goto release;
 1017                         laddr = src_sin.sin_addr;
 1018                 }
 1019         } else {
 1020                 if (inp->inp_faddr.s_addr == INADDR_ANY) {
 1021                         error = ENOTCONN;
 1022                         goto release;
 1023                 }
 1024                 laddr = inp->inp_laddr;
 1025         }
 1026 
 1027         /*
 1028          * Calculate data length and get a mbuf
 1029          * for UDP and IP headers.
 1030          */
 1031         M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
 1032         if (m == NULL) {
 1033                 error = ENOBUFS;
 1034                 goto bail;
 1035         }
 1036 
 1037         /*
 1038          * Fill in mbuf with extended UDP header
 1039          * and addresses and length put into network format.
 1040          */
 1041         ui = mtod(m, struct udpiphdr *);
 1042         bzero(ui->ui_x1, sizeof ui->ui_x1);
 1043         ui->ui_pr = IPPROTO_UDP;
 1044         ui->ui_len = htons((u_int16_t)len + sizeof (struct udphdr));
 1045         ui->ui_src = laddr;
 1046         ui->ui_dst = sin ? sin->sin_addr : inp->inp_faddr;
 1047         ui->ui_sport = inp->inp_lport;
 1048         ui->ui_dport = sin ? sin->sin_port : inp->inp_fport;
 1049         ui->ui_ulen = ui->ui_len;
 1050         ((struct ip *)ui)->ip_len = htons(sizeof (struct udpiphdr) + len);
 1051         ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl;
 1052         ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos;
 1053         if (udpcksum)
 1054                 m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT;
 1055 
 1056         udpstat_inc(udps_opackets);
 1057 
 1058         /* force routing table */
 1059         m->m_pkthdr.ph_rtableid = inp->inp_rtableid;
 1060 
 1061 #if NPF > 0
 1062         if (inp->inp_socket->so_state & SS_ISCONNECTED)
 1063                 pf_mbuf_link_inpcb(m, inp);
 1064 #endif
 1065 
 1066         error = ip_output(m, inp->inp_options, &inp->inp_route,
 1067             (inp->inp_socket->so_options & SO_BROADCAST), inp->inp_moptions,
 1068             inp, ipsecflowinfo);
 1069 
 1070 bail:
 1071         m_freem(control);
 1072         return (error);
 1073 
 1074 release:
 1075         m_freem(m);
 1076         goto bail;
 1077 }
 1078 
 1079 int
 1080 udp_attach(struct socket *so, int proto, int wait)
 1081 {
 1082         int error;
 1083 
 1084         if (so->so_pcb != NULL)
 1085                 return EINVAL;
 1086 
 1087         if ((error = soreserve(so, udp_sendspace, udp_recvspace)))
 1088                 return error;
 1089 
 1090         NET_ASSERT_LOCKED();
 1091         if ((error = in_pcballoc(so, &udbtable, wait)))
 1092                 return error;
 1093 #ifdef INET6
 1094         if (sotoinpcb(so)->inp_flags & INP_IPV6)
 1095                 sotoinpcb(so)->inp_ipv6.ip6_hlim = ip6_defhlim;
 1096         else
 1097 #endif /* INET6 */
 1098                 sotoinpcb(so)->inp_ip.ip_ttl = ip_defttl;
 1099         return 0;
 1100 }
 1101 
 1102 int
 1103 udp_detach(struct socket *so)
 1104 {
 1105         struct inpcb *inp;
 1106 
 1107         soassertlocked(so);
 1108 
 1109         inp = sotoinpcb(so);
 1110         if (inp == NULL)
 1111                 return (EINVAL);
 1112 
 1113         in_pcbdetach(inp);
 1114         return (0);
 1115 }
 1116 
 1117 void
 1118 udp_lock(struct socket *so)
 1119 {
 1120         struct inpcb *inp = sotoinpcb(so);
 1121 
 1122         NET_ASSERT_LOCKED();
 1123         mtx_enter(&inp->inp_mtx);
 1124 }
 1125 
 1126 void
 1127 udp_unlock(struct socket *so)
 1128 {
 1129         struct inpcb *inp = sotoinpcb(so);
 1130 
 1131         NET_ASSERT_LOCKED();
 1132         mtx_leave(&inp->inp_mtx);
 1133 }
 1134 
 1135 int
 1136 udp_bind(struct socket *so, struct mbuf *addr, struct proc *p)
 1137 {
 1138         struct inpcb *inp = sotoinpcb(so);
 1139 
 1140         soassertlocked(so);
 1141         return in_pcbbind(inp, addr, p);
 1142 }
 1143 
 1144 int
 1145 udp_connect(struct socket *so, struct mbuf *addr)
 1146 {
 1147         struct inpcb *inp = sotoinpcb(so);
 1148         int error;
 1149 
 1150         soassertlocked(so);
 1151 
 1152 #ifdef INET6
 1153         if (inp->inp_flags & INP_IPV6) {
 1154                 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
 1155                         return (EISCONN);
 1156                 error = in6_pcbconnect(inp, addr);
 1157         } else
 1158 #endif /* INET6 */
 1159         {
 1160                 if (inp->inp_faddr.s_addr != INADDR_ANY)
 1161                         return (EISCONN);
 1162                 error = in_pcbconnect(inp, addr);
 1163         }
 1164 
 1165         if (error)
 1166                 return (error);
 1167 
 1168         soisconnected(so);
 1169         return (0);
 1170 }
 1171 
 1172 int
 1173 udp_disconnect(struct socket *so)
 1174 {
 1175         struct inpcb *inp = sotoinpcb(so);
 1176 
 1177         soassertlocked(so);
 1178 
 1179 #ifdef INET6
 1180         if (inp->inp_flags & INP_IPV6) {
 1181                 if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
 1182                         return (ENOTCONN);
 1183         } else
 1184 #endif /* INET6 */
 1185         {
 1186                 if (inp->inp_faddr.s_addr == INADDR_ANY)
 1187                         return (ENOTCONN);
 1188         }
 1189 
 1190 #ifdef INET6
 1191         if (inp->inp_flags & INP_IPV6)
 1192                 inp->inp_laddr6 = in6addr_any;
 1193         else
 1194 #endif /* INET6 */
 1195                 inp->inp_laddr.s_addr = INADDR_ANY;
 1196 
 1197         in_pcbdisconnect(inp);
 1198         so->so_state &= ~SS_ISCONNECTED;                /* XXX */
 1199 
 1200         return (0);
 1201 }
 1202 
 1203 int
 1204 udp_shutdown(struct socket *so)
 1205 {
 1206         soassertlocked(so);
 1207         socantsendmore(so);
 1208         return (0);
 1209 }
 1210 
 1211 int
 1212 udp_send(struct socket *so, struct mbuf *m, struct mbuf *addr,
 1213     struct mbuf *control)
 1214 {
 1215         struct inpcb *inp = sotoinpcb(so);
 1216         int error;
 1217 
 1218         soassertlocked(so);
 1219 
 1220 #ifdef PIPEX
 1221         if (inp->inp_pipex) {
 1222                 struct pipex_session *session;
 1223 
 1224                 if (addr != NULL)
 1225                         session =
 1226                             pipex_l2tp_userland_lookup_session(m,
 1227                                 mtod(addr, struct sockaddr *));
 1228                 else
 1229 #ifdef INET6
 1230                 if (inp->inp_flags & INP_IPV6)
 1231                         session =
 1232                             pipex_l2tp_userland_lookup_session_ipv6(
 1233                                 m, inp->inp_faddr6);
 1234                 else
 1235 #endif
 1236                         session =
 1237                             pipex_l2tp_userland_lookup_session_ipv4(
 1238                                 m, inp->inp_faddr);
 1239                 if (session != NULL) {
 1240                         m = pipex_l2tp_userland_output(m, session);
 1241                         pipex_rele_session(session);
 1242 
 1243                         if (m == NULL) {
 1244                                 m_freem(control);
 1245                                 return (ENOMEM);
 1246                         }
 1247                 }
 1248         }
 1249 #endif
 1250 
 1251 #ifdef INET6
 1252         if (inp->inp_flags & INP_IPV6)
 1253                 error = udp6_output(inp, m, addr, control);
 1254         else
 1255 #endif
 1256                 error = udp_output(inp, m, addr, control);
 1257 
 1258         return (error);
 1259 }
 1260 
 1261 /*
 1262  * Sysctl for udp variables.
 1263  */
 1264 int
 1265 udp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
 1266     size_t newlen)
 1267 {
 1268         int error;
 1269 
 1270         /* All sysctl names at this level are terminal. */
 1271         if (namelen != 1)
 1272                 return (ENOTDIR);
 1273 
 1274         switch (name[0]) {
 1275         case UDPCTL_BADDYNAMIC:
 1276                 NET_LOCK();
 1277                 error = sysctl_struct(oldp, oldlenp, newp, newlen,
 1278                     baddynamicports.udp, sizeof(baddynamicports.udp));
 1279                 NET_UNLOCK();
 1280                 return (error);
 1281 
 1282         case UDPCTL_ROOTONLY:
 1283                 if (newp && securelevel > 0)
 1284                         return (EPERM);
 1285                 NET_LOCK();
 1286                 error = sysctl_struct(oldp, oldlenp, newp, newlen,
 1287                     rootonlyports.udp, sizeof(rootonlyports.udp));
 1288                 NET_UNLOCK();
 1289                 return (error);
 1290 
 1291         case UDPCTL_STATS:
 1292                 if (newp != NULL)
 1293                         return (EPERM);
 1294 
 1295                 return (udp_sysctl_udpstat(oldp, oldlenp, newp));
 1296 
 1297         default:
 1298                 NET_LOCK();
 1299                 error = sysctl_bounded_arr(udpctl_vars, nitems(udpctl_vars),
 1300                     name, namelen, oldp, oldlenp, newp, newlen);
 1301                 NET_UNLOCK();
 1302                 return (error);
 1303         }
 1304         /* NOTREACHED */
 1305 }
 1306 
 1307 int
 1308 udp_sysctl_udpstat(void *oldp, size_t *oldlenp, void *newp)
 1309 {
 1310         uint64_t counters[udps_ncounters];
 1311         struct udpstat udpstat;
 1312         u_long *words = (u_long *)&udpstat;
 1313         int i;
 1314 
 1315         CTASSERT(sizeof(udpstat) == (nitems(counters) * sizeof(u_long)));
 1316         memset(&udpstat, 0, sizeof udpstat);
 1317         counters_read(udpcounters, counters, nitems(counters));
 1318 
 1319         for (i = 0; i < nitems(counters); i++)
 1320                 words[i] = (u_long)counters[i];
 1321 
 1322         return (sysctl_rdstruct(oldp, oldlenp, newp,
 1323             &udpstat, sizeof(udpstat)));
 1324 }

Cache object: 6e9be2f4a32f4ee2e0ef1a5ae405f8de


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