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/in.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: in.c,v 1.179 2022/12/06 22:19:39 mvs Exp $    */
    2 /*      $NetBSD: in.c,v 1.26 1996/02/13 23:41:39 christos Exp $ */
    3 
    4 /*
    5  * Copyright (C) 2001 WIDE Project.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of the project nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * Copyright (c) 1982, 1986, 1991, 1993
   34  *      The Regents of the University of California.  All rights reserved.
   35  *
   36  * Redistribution and use in source and binary forms, with or without
   37  * modification, are permitted provided that the following conditions
   38  * are met:
   39  * 1. Redistributions of source code must retain the above copyright
   40  *    notice, this list of conditions and the following disclaimer.
   41  * 2. Redistributions in binary form must reproduce the above copyright
   42  *    notice, this list of conditions and the following disclaimer in the
   43  *    documentation and/or other materials provided with the distribution.
   44  * 3. Neither the name of the University nor the names of its contributors
   45  *    may be used to endorse or promote products derived from this software
   46  *    without specific prior written permission.
   47  *
   48  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   58  * SUCH DAMAGE.
   59  *
   60  *      @(#)in.c        8.2 (Berkeley) 11/15/93
   61  */
   62 
   63 #include <sys/param.h>
   64 #include <sys/systm.h>
   65 #include <sys/ioctl.h>
   66 #include <sys/malloc.h>
   67 #include <sys/socket.h>
   68 #include <sys/socketvar.h>
   69 
   70 #include <net/if.h>
   71 #include <net/if_var.h>
   72 #include <net/route.h>
   73 
   74 #include <netinet/in.h>
   75 #include <netinet/in_var.h>
   76 #include <netinet/igmp_var.h>
   77 
   78 #ifdef MROUTING
   79 #include <netinet/ip_mroute.h>
   80 #endif
   81 
   82 #include "ether.h"
   83 
   84 
   85 void in_socktrim(struct sockaddr_in *);
   86 
   87 int in_ioctl_set_ifaddr(u_long, caddr_t, struct ifnet *, int);
   88 int in_ioctl_change_ifaddr(u_long, caddr_t, struct ifnet *, int);
   89 int in_ioctl_get(u_long, caddr_t, struct ifnet *);
   90 void in_purgeaddr(struct ifaddr *);
   91 int in_addhost(struct in_ifaddr *, struct sockaddr_in *);
   92 int in_scrubhost(struct in_ifaddr *, struct sockaddr_in *);
   93 int in_insert_prefix(struct in_ifaddr *);
   94 void in_remove_prefix(struct in_ifaddr *);
   95 
   96 /*
   97  * Determine whether an IP address is in a reserved set of addresses
   98  * that may not be forwarded, or whether datagrams to that destination
   99  * may be forwarded.
  100  */
  101 int
  102 in_canforward(struct in_addr in)
  103 {
  104         u_int32_t net;
  105 
  106         if (IN_MULTICAST(in.s_addr))
  107                 return (0);
  108         if (IN_CLASSA(in.s_addr)) {
  109                 net = in.s_addr & IN_CLASSA_NET;
  110                 if (net == 0 ||
  111                     net == htonl(IN_LOOPBACKNET << IN_CLASSA_NSHIFT))
  112                         return (0);
  113         }
  114         return (1);
  115 }
  116 
  117 /*
  118  * Trim a mask in a sockaddr
  119  */
  120 void
  121 in_socktrim(struct sockaddr_in *ap)
  122 {
  123         char *cplim = (char *) &ap->sin_addr;
  124         char *cp = (char *) (&ap->sin_addr + 1);
  125 
  126         ap->sin_len = 0;
  127         while (--cp >= cplim)
  128                 if (*cp) {
  129                         (ap)->sin_len = cp - (char *) (ap) + 1;
  130                         break;
  131                 }
  132 }
  133 
  134 int
  135 in_mask2len(struct in_addr *mask)
  136 {
  137         int x, y;
  138         u_char *p;
  139 
  140         p = (u_char *)mask;
  141         for (x = 0; x < sizeof(*mask); x++) {
  142                 if (p[x] != 0xff)
  143                         break;
  144         }
  145         y = 0;
  146         if (x < sizeof(*mask)) {
  147                 for (y = 0; y < 8; y++) {
  148                         if ((p[x] & (0x80 >> y)) == 0)
  149                                 break;
  150                 }
  151         }
  152         return x * 8 + y;
  153 }
  154 
  155 void
  156 in_len2mask(struct in_addr *mask, int len)
  157 {
  158         int i;
  159         u_char *p;
  160 
  161         p = (u_char *)mask;
  162         bzero(mask, sizeof(*mask));
  163         for (i = 0; i < len / 8; i++)
  164                 p[i] = 0xff;
  165         if (len % 8)
  166                 p[i] = (0xff00 >> (len % 8)) & 0xff;
  167 }
  168 
  169 int
  170 in_nam2sin(const struct mbuf *nam, struct sockaddr_in **sin)
  171 {
  172         struct sockaddr *sa = mtod(nam, struct sockaddr *);
  173 
  174         if (nam->m_len < offsetof(struct sockaddr, sa_data))
  175                 return EINVAL;
  176         if (sa->sa_family != AF_INET)
  177                 return EAFNOSUPPORT;
  178         if (sa->sa_len != nam->m_len)
  179                 return EINVAL;
  180         if (sa->sa_len != sizeof(struct sockaddr_in))
  181                 return EINVAL;
  182         *sin = satosin(sa);
  183 
  184         return 0;
  185 }
  186 
  187 int
  188 in_sa2sin(struct sockaddr *sa, struct sockaddr_in **sin)
  189 {
  190         if (sa->sa_family != AF_INET)
  191                 return EAFNOSUPPORT;
  192         if (sa->sa_len != sizeof(struct sockaddr_in))
  193                 return EINVAL;
  194         *sin = satosin(sa);
  195 
  196         return 0;
  197 }
  198 
  199 int
  200 in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp)
  201 {
  202         int privileged;
  203         int error;
  204 
  205         privileged = 0;
  206         if ((so->so_state & SS_PRIV) != 0)
  207                 privileged++;
  208 
  209         switch (cmd) {
  210 #ifdef MROUTING
  211         case SIOCGETVIFCNT:
  212         case SIOCGETSGCNT:
  213                 KERNEL_LOCK();
  214                 error = mrt_ioctl(so, cmd, data);
  215                 KERNEL_UNLOCK();
  216                 break;
  217 #endif /* MROUTING */
  218         default:
  219                 KERNEL_LOCK();
  220                 error = in_ioctl(cmd, data, ifp, privileged);
  221                 KERNEL_UNLOCK();
  222                 break;
  223         }
  224 
  225         return error;
  226 }
  227 
  228 int
  229 in_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, int privileged)
  230 {
  231         struct ifreq *ifr = (struct ifreq *)data;
  232         struct ifaddr *ifa;
  233         struct in_ifaddr *ia = NULL;
  234         struct sockaddr_in *sin = NULL, oldaddr;
  235         int error = 0;
  236 
  237         if (ifp == NULL)
  238                 return (ENXIO);
  239 
  240         switch (cmd) {
  241         case SIOCGIFADDR:
  242         case SIOCGIFNETMASK:
  243         case SIOCGIFDSTADDR:
  244         case SIOCGIFBRDADDR:
  245                 return in_ioctl_get(cmd, data, ifp);
  246         case SIOCSIFADDR:
  247                 return in_ioctl_set_ifaddr(cmd, data, ifp, privileged);
  248         case SIOCAIFADDR:
  249         case SIOCDIFADDR:
  250                 return in_ioctl_change_ifaddr(cmd, data, ifp, privileged);
  251         case SIOCSIFNETMASK:
  252         case SIOCSIFDSTADDR:
  253         case SIOCSIFBRDADDR:
  254                 break;
  255         default:
  256                 return (EOPNOTSUPP);
  257         }
  258 
  259         if (ifr->ifr_addr.sa_family == AF_INET) {
  260                 error = in_sa2sin(&ifr->ifr_addr, &sin);
  261                 if (error)
  262                         return (error);
  263         }
  264 
  265         NET_LOCK();
  266 
  267         TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
  268                 if (ifa->ifa_addr->sa_family != AF_INET)
  269                         continue;
  270                 /* find first address or exact match */
  271                 if (ia == NULL)
  272                         ia = ifatoia(ifa);
  273                 if (sin == NULL || sin->sin_addr.s_addr == INADDR_ANY)
  274                         break;
  275                 if (ifatoia(ifa)->ia_addr.sin_addr.s_addr ==
  276                     sin->sin_addr.s_addr) {
  277                         ia = ifatoia(ifa);
  278                         break;
  279                 }
  280         }
  281         if (ia == NULL) {
  282                 error = EADDRNOTAVAIL;
  283                 goto err;
  284         }
  285 
  286         switch (cmd) {
  287         case SIOCSIFDSTADDR:
  288                 if (!privileged) {
  289                         error = EPERM;
  290                         break;
  291                 }
  292 
  293                 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
  294                         error = EINVAL;
  295                         break;
  296                 }
  297                 error = in_sa2sin(&ifr->ifr_dstaddr, &sin);
  298                 if (error)
  299                         break;
  300                 oldaddr = ia->ia_dstaddr;
  301                 ia->ia_dstaddr = *sin;
  302                 error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (caddr_t)ia);
  303                 if (error) {
  304                         ia->ia_dstaddr = oldaddr;
  305                         break;
  306                 }
  307                 in_scrubhost(ia, &oldaddr);
  308                 in_addhost(ia, &ia->ia_dstaddr);
  309                 break;
  310 
  311         case SIOCSIFBRDADDR:
  312                 if (!privileged) {
  313                         error = EPERM;
  314                         break;
  315                 }
  316 
  317                 if ((ifp->if_flags & IFF_BROADCAST) == 0) {
  318                         error = EINVAL;
  319                         break;
  320                 }
  321                 error = in_sa2sin(&ifr->ifr_broadaddr, &sin);
  322                 if (error)
  323                         break;
  324                 ifa_update_broadaddr(ifp, &ia->ia_ifa, sintosa(sin));
  325                 break;
  326 
  327         case SIOCSIFNETMASK:
  328                 if (!privileged) {
  329                         error = EPERM;
  330                         break;
  331                 }
  332 
  333                 if (ifr->ifr_addr.sa_len < 8) {
  334                         error = EINVAL;
  335                         break;
  336                 }
  337                 /* do not check inet family or strict len */
  338                 sin = satosin(&ifr->ifr_addr);
  339                 if (ntohl(sin->sin_addr.s_addr) &
  340                     (~ntohl(sin->sin_addr.s_addr) >> 1)) {
  341                         /* non-contiguous netmask */
  342                         error = EINVAL;
  343                         break;
  344                 }
  345                 ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr =
  346                     sin->sin_addr.s_addr;
  347                 break;
  348         }
  349 err:
  350         NET_UNLOCK();
  351         return (error);
  352 }
  353 
  354 int
  355 in_ioctl_set_ifaddr(u_long cmd, caddr_t data, struct ifnet *ifp,
  356     int privileged)
  357 {
  358         struct ifreq *ifr = (struct ifreq *)data;
  359         struct ifaddr *ifa;
  360         struct in_ifaddr *ia = NULL;
  361         struct sockaddr_in *sin;
  362         int error = 0;
  363         int newifaddr;
  364 
  365         if (cmd != SIOCSIFADDR)
  366                 panic("%s: invalid ioctl %lu", __func__, cmd);
  367 
  368         if (!privileged)
  369                 return (EPERM);
  370 
  371         error = in_sa2sin(&ifr->ifr_addr, &sin);
  372         if (error)
  373                 return (error);
  374 
  375         NET_LOCK();
  376 
  377         TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
  378                 if (ifa->ifa_addr->sa_family != AF_INET)
  379                         continue;
  380                 /* find first address */
  381                 ia = ifatoia(ifa);
  382                 break;
  383         }
  384         if (ia == NULL) {
  385                 ia = malloc(sizeof *ia, M_IFADDR, M_WAITOK | M_ZERO);
  386                 refcnt_init_trace(&ia->ia_ifa.ifa_refcnt, DT_REFCNT_IDX_IFADDR);
  387                 ia->ia_addr.sin_family = AF_INET;
  388                 ia->ia_addr.sin_len = sizeof(ia->ia_addr);
  389                 ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
  390                 ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
  391                 ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
  392                 ia->ia_sockmask.sin_len = 8;
  393                 if (ifp->if_flags & IFF_BROADCAST) {
  394                         ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
  395                         ia->ia_broadaddr.sin_family = AF_INET;
  396                 }
  397                 ia->ia_ifp = ifp;
  398 
  399                 newifaddr = 1;
  400         } else
  401                 newifaddr = 0;
  402 
  403         in_ifscrub(ifp, ia);
  404         error = in_ifinit(ifp, ia, sin, newifaddr);
  405         if (!error)
  406                 if_addrhooks_run(ifp);
  407 
  408         NET_UNLOCK();
  409         return error;
  410 }
  411 
  412 int
  413 in_ioctl_change_ifaddr(u_long cmd, caddr_t data, struct ifnet *ifp,
  414     int privileged)
  415 {
  416         struct ifaddr *ifa;
  417         struct in_ifaddr *ia = NULL;
  418         struct in_aliasreq *ifra = (struct in_aliasreq *)data;
  419         struct sockaddr_in *sin = NULL, *dstsin = NULL, *broadsin = NULL;
  420         struct sockaddr_in *masksin = NULL;
  421         int error = 0;
  422         int newifaddr;
  423 
  424         if (ifra->ifra_addr.sin_family == AF_INET) {
  425                 error = in_sa2sin(sintosa(&ifra->ifra_addr), &sin);
  426                 if (error)
  427                         return (error);
  428         }
  429 
  430         NET_LOCK();
  431 
  432         TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
  433                 if (ifa->ifa_addr->sa_family != AF_INET)
  434                         continue;
  435                 /* find first address, if no exact match wanted */
  436                 if (sin == NULL || sin->sin_addr.s_addr ==
  437                     ifatoia(ifa)->ia_addr.sin_addr.s_addr) {
  438                         ia = ifatoia(ifa);
  439                         break;
  440                 }
  441         }
  442 
  443         switch (cmd) {
  444         case SIOCAIFADDR: {
  445                 int needinit = 0;
  446 
  447                 if (!privileged) {
  448                         error = EPERM;
  449                         break;
  450                 }
  451 
  452                 if (ifra->ifra_mask.sin_len) {
  453                         if (ifra->ifra_mask.sin_len < 8) {
  454                                 error = EINVAL;
  455                                 break;
  456                         }
  457                         /* do not check inet family or strict len */
  458                         masksin = &ifra->ifra_mask;
  459                         if (ntohl(masksin->sin_addr.s_addr) &
  460                             (~ntohl(masksin->sin_addr.s_addr) >> 1)) {
  461                                 /* non-contiguous netmask */
  462                                 error = EINVAL;
  463                                 break;
  464                         }
  465                 }
  466                 if ((ifp->if_flags & IFF_POINTOPOINT) &&
  467                     ifra->ifra_dstaddr.sin_family == AF_INET) {
  468                         error = in_sa2sin(sintosa(&ifra->ifra_dstaddr),
  469                             &dstsin);
  470                         if (error)
  471                                 break;
  472                 }
  473                 if ((ifp->if_flags & IFF_BROADCAST) &&
  474                     ifra->ifra_broadaddr.sin_family == AF_INET) {
  475                         error = in_sa2sin(sintosa(&ifra->ifra_broadaddr),
  476                             &broadsin);
  477                         if (error)
  478                                 break;
  479                 }
  480 
  481                 if (ia == NULL) {
  482                         ia = malloc(sizeof *ia, M_IFADDR, M_WAITOK | M_ZERO);
  483                         refcnt_init_trace(&ia->ia_ifa.ifa_refcnt,
  484                             DT_REFCNT_IDX_IFADDR);
  485                         ia->ia_addr.sin_family = AF_INET;
  486                         ia->ia_addr.sin_len = sizeof(ia->ia_addr);
  487                         ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
  488                         ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
  489                         ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
  490                         ia->ia_sockmask.sin_len = 8;
  491                         if (ifp->if_flags & IFF_BROADCAST) {
  492                                 ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
  493                                 ia->ia_broadaddr.sin_family = AF_INET;
  494                         }
  495                         ia->ia_ifp = ifp;
  496 
  497                         newifaddr = 1;
  498                 } else
  499                         newifaddr = 0;
  500 
  501                 if (sin == NULL) {
  502                         sin = &ia->ia_addr;
  503                 } else if (newifaddr ||
  504                     sin->sin_addr.s_addr != ia->ia_addr.sin_addr.s_addr) {
  505                         needinit = 1;
  506                 }
  507                 if (masksin != NULL) {
  508                         in_ifscrub(ifp, ia);
  509                         ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr =
  510                             masksin->sin_addr.s_addr;
  511                         needinit = 1;
  512                 }
  513                 if (dstsin != NULL) {
  514                         in_ifscrub(ifp, ia);
  515                         ia->ia_dstaddr = *dstsin;
  516                         needinit = 1;
  517                 }
  518                 if (broadsin != NULL) {
  519                         if (newifaddr)
  520                                 ia->ia_broadaddr = *broadsin;
  521                         else
  522                                 ifa_update_broadaddr(ifp, &ia->ia_ifa,
  523                                     sintosa(broadsin));
  524                 }
  525                 if (needinit) {
  526                         error = in_ifinit(ifp, ia, sin, newifaddr);
  527                         if (error)
  528                                 break;
  529                 }
  530                 if_addrhooks_run(ifp);
  531                 break;
  532             }
  533         case SIOCDIFADDR:
  534                 if (!privileged) {
  535                         error = EPERM;
  536                         break;
  537                 }
  538 
  539                 if (ia == NULL) {
  540                         error = EADDRNOTAVAIL;
  541                         break;
  542                 }
  543                 /*
  544                  * Even if the individual steps were safe, shouldn't
  545                  * these kinds of changes happen atomically?  What
  546                  * should happen to a packet that was routed after
  547                  * the scrub but before the other steps?
  548                  */
  549                 in_purgeaddr(&ia->ia_ifa);
  550                 if_addrhooks_run(ifp);
  551                 break;
  552 
  553         default:
  554                 panic("%s: invalid ioctl %lu", __func__, cmd);
  555         }
  556 
  557         NET_UNLOCK();
  558         return (error);
  559 }
  560 
  561 int
  562 in_ioctl_get(u_long cmd, caddr_t data, struct ifnet *ifp)
  563 {
  564         struct ifreq *ifr = (struct ifreq *)data;
  565         struct ifaddr *ifa;
  566         struct in_ifaddr *ia = NULL;
  567         struct sockaddr *sa;
  568         struct sockaddr_in *sin = NULL;
  569         int error = 0;
  570 
  571         sa = &ifr->ifr_addr;
  572         if (sa->sa_family == AF_INET) {
  573                 sa->sa_len = sizeof(struct sockaddr_in);
  574                 error = in_sa2sin(sa, &sin);
  575                 if (error)
  576                         return (error);
  577         }
  578 
  579         NET_LOCK_SHARED();
  580 
  581         TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
  582                 if (ifa->ifa_addr->sa_family != AF_INET)
  583                         continue;
  584                 /* find first address or exact match */
  585                 if (ia == NULL)
  586                         ia = ifatoia(ifa);
  587                 if (sin == NULL || sin->sin_addr.s_addr == INADDR_ANY)
  588                         break;
  589                 if (ifatoia(ifa)->ia_addr.sin_addr.s_addr ==
  590                     sin->sin_addr.s_addr) {
  591                         ia = ifatoia(ifa);
  592                         break;
  593                 }
  594         }
  595         if (ia == NULL) {
  596                 error = EADDRNOTAVAIL;
  597                 goto err;
  598         }
  599 
  600         switch(cmd) {
  601         case SIOCGIFADDR:
  602                 *satosin(&ifr->ifr_addr) = ia->ia_addr;
  603                 break;
  604 
  605         case SIOCGIFBRDADDR:
  606                 if ((ifp->if_flags & IFF_BROADCAST) == 0) {
  607                         error = EINVAL;
  608                         break;
  609                 }
  610                 *satosin(&ifr->ifr_dstaddr) = ia->ia_broadaddr;
  611                 break;
  612 
  613         case SIOCGIFDSTADDR:
  614                 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
  615                         error = EINVAL;
  616                         break;
  617                 }
  618                 *satosin(&ifr->ifr_dstaddr) = ia->ia_dstaddr;
  619                 break;
  620 
  621         case SIOCGIFNETMASK:
  622                 *satosin(&ifr->ifr_addr) = ia->ia_sockmask;
  623                 break;
  624 
  625         default:
  626                 panic("%s: invalid ioctl %lu", __func__, cmd);
  627         }
  628 
  629 err:
  630         NET_UNLOCK_SHARED();
  631         return (error);
  632 }
  633 
  634 /*
  635  * Delete any existing route for an interface.
  636  */
  637 void
  638 in_ifscrub(struct ifnet *ifp, struct in_ifaddr *ia)
  639 {
  640         if (ISSET(ifp->if_flags, IFF_POINTOPOINT))
  641                 in_scrubhost(ia, &ia->ia_dstaddr);
  642         else if (!ISSET(ifp->if_flags, IFF_LOOPBACK))
  643                 in_remove_prefix(ia);
  644 }
  645 
  646 /*
  647  * Initialize an interface's internet address
  648  * and routing table entry.
  649  */
  650 int
  651 in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin,
  652     int newaddr)
  653 {
  654         u_int32_t i = sin->sin_addr.s_addr;
  655         struct sockaddr_in oldaddr;
  656         int error = 0, rterror;
  657 
  658         NET_ASSERT_LOCKED();
  659 
  660         /*
  661          * Always remove the address from the tree to make sure its
  662          * position gets updated in case the key changes.
  663          */
  664         if (!newaddr) {
  665                 rt_ifa_dellocal(&ia->ia_ifa);
  666                 ifa_del(ifp, &ia->ia_ifa);
  667         }
  668         oldaddr = ia->ia_addr;
  669         ia->ia_addr = *sin;
  670 
  671         if (ia->ia_netmask == 0) {
  672                 if (IN_CLASSA(i))
  673                         ia->ia_netmask = IN_CLASSA_NET;
  674                 else if (IN_CLASSB(i))
  675                         ia->ia_netmask = IN_CLASSB_NET;
  676                 else
  677                         ia->ia_netmask = IN_CLASSC_NET;
  678                 ia->ia_sockmask.sin_addr.s_addr = ia->ia_netmask;
  679         }
  680 
  681         /*
  682          * Give the interface a chance to initialize
  683          * if this is its first address,
  684          * and to validate the address if necessary.
  685          */
  686         if ((error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
  687                 ia->ia_addr = oldaddr;
  688         }
  689 
  690         /*
  691          * Add the address to the local list and the global tree.  If an
  692          * error occurred, put back the original address.
  693          */
  694         ifa_add(ifp, &ia->ia_ifa);
  695         rterror = rt_ifa_addlocal(&ia->ia_ifa);
  696 
  697         if (rterror) {
  698                 if (!newaddr)
  699                         ifa_del(ifp, &ia->ia_ifa);
  700                 if (!error)
  701                         error = rterror;
  702                 goto out;
  703         }
  704         if (error)
  705                 goto out;
  706 
  707 
  708         ia->ia_net = i & ia->ia_netmask;
  709         in_socktrim(&ia->ia_sockmask);
  710         /*
  711          * Add route for the network.
  712          */
  713         ia->ia_ifa.ifa_metric = ifp->if_metric;
  714         if (ISSET(ifp->if_flags, IFF_BROADCAST)) {
  715                 if (IN_RFC3021_SUBNET(ia->ia_netmask))
  716                         ia->ia_broadaddr.sin_addr.s_addr = 0;
  717                 else {
  718                         ia->ia_broadaddr.sin_addr.s_addr =
  719                             ia->ia_net | ~ia->ia_netmask;
  720                 }
  721         }
  722 
  723         if (ISSET(ifp->if_flags, IFF_POINTOPOINT)) {
  724                 /* XXX We should not even call in_ifinit() in this case. */
  725                 if (ia->ia_dstaddr.sin_family != AF_INET)
  726                         goto out;
  727                 error = in_addhost(ia, &ia->ia_dstaddr);
  728         } else if (!ISSET(ifp->if_flags, IFF_LOOPBACK)) {
  729                 error = in_insert_prefix(ia);
  730         }
  731 
  732         /*
  733          * If the interface supports multicast, join the "all hosts"
  734          * multicast group on that interface.
  735          */
  736         if ((ifp->if_flags & IFF_MULTICAST) && ia->ia_allhosts == NULL) {
  737                 struct in_addr addr;
  738 
  739                 addr.s_addr = INADDR_ALLHOSTS_GROUP;
  740                 ia->ia_allhosts = in_addmulti(&addr, ifp);
  741         }
  742 
  743 out:
  744         if (error && newaddr)
  745                 in_purgeaddr(&ia->ia_ifa);
  746 
  747         return (error);
  748 }
  749 
  750 void
  751 in_purgeaddr(struct ifaddr *ifa)
  752 {
  753         struct ifnet *ifp = ifa->ifa_ifp;
  754         struct in_ifaddr *ia = ifatoia(ifa);
  755 
  756         NET_ASSERT_LOCKED();
  757 
  758         in_ifscrub(ifp, ia);
  759 
  760         rt_ifa_dellocal(&ia->ia_ifa);
  761         rt_ifa_purge(&ia->ia_ifa);
  762         ifa_del(ifp, &ia->ia_ifa);
  763 
  764         if (ia->ia_allhosts != NULL) {
  765                 in_delmulti(ia->ia_allhosts);
  766                 ia->ia_allhosts = NULL;
  767         }
  768 
  769         ia->ia_ifp = NULL;
  770         ifafree(&ia->ia_ifa);
  771 }
  772 
  773 int
  774 in_addhost(struct in_ifaddr *ia, struct sockaddr_in *dst)
  775 {
  776         return rt_ifa_add(&ia->ia_ifa, RTF_HOST | RTF_MPATH,
  777             sintosa(dst), ia->ia_ifa.ifa_ifp->if_rdomain);
  778 }
  779 
  780 int
  781 in_scrubhost(struct in_ifaddr *ia, struct sockaddr_in *dst)
  782 {
  783         return rt_ifa_del(&ia->ia_ifa, RTF_HOST,
  784             sintosa(dst), ia->ia_ifa.ifa_ifp->if_rdomain);
  785 }
  786 
  787 /*
  788  * Insert the cloning and broadcast routes for this subnet.
  789  */
  790 int
  791 in_insert_prefix(struct in_ifaddr *ia)
  792 {
  793         struct ifaddr *ifa = &ia->ia_ifa;
  794         int error;
  795 
  796         error = rt_ifa_add(ifa, RTF_CLONING | RTF_CONNECTED | RTF_MPATH,
  797             ifa->ifa_addr, ifa->ifa_ifp->if_rdomain);
  798         if (error)
  799                 return (error);
  800 
  801         if (ia->ia_broadaddr.sin_addr.s_addr != 0) {
  802                 error = rt_ifa_add(ifa, RTF_HOST | RTF_BROADCAST | RTF_MPATH,
  803                     ifa->ifa_broadaddr, ifa->ifa_ifp->if_rdomain);
  804         }
  805 
  806         return (error);
  807 }
  808 
  809 void
  810 in_remove_prefix(struct in_ifaddr *ia)
  811 {
  812         struct ifaddr *ifa = &ia->ia_ifa;
  813 
  814         rt_ifa_del(ifa, RTF_CLONING | RTF_CONNECTED,
  815             ifa->ifa_addr, ifa->ifa_ifp->if_rdomain);
  816 
  817         if (ia->ia_broadaddr.sin_addr.s_addr != 0) {
  818                 rt_ifa_del(ifa, RTF_HOST | RTF_BROADCAST,
  819                     ifa->ifa_broadaddr, ifa->ifa_ifp->if_rdomain);
  820         }
  821 }
  822 
  823 /*
  824  * Return 1 if the address is a local broadcast address.
  825  */
  826 int
  827 in_broadcast(struct in_addr in, u_int rtableid)
  828 {
  829         struct ifnet *ifn;
  830         struct ifaddr *ifa;
  831         u_int rdomain;
  832 
  833         rdomain = rtable_l2(rtableid);
  834 
  835 #define ia (ifatoia(ifa))
  836         TAILQ_FOREACH(ifn, &ifnetlist, if_list) {
  837                 if (ifn->if_rdomain != rdomain)
  838                         continue;
  839                 if ((ifn->if_flags & IFF_BROADCAST) == 0)
  840                         continue;
  841                 TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list)
  842                         if (ifa->ifa_addr->sa_family == AF_INET &&
  843                             in.s_addr != ia->ia_addr.sin_addr.s_addr &&
  844                             in.s_addr == ia->ia_broadaddr.sin_addr.s_addr)
  845                                 return 1;
  846         }
  847         return (0);
  848 #undef ia
  849 }
  850 
  851 /*
  852  * Add an address to the list of IP multicast addresses for a given interface.
  853  */
  854 struct in_multi *
  855 in_addmulti(struct in_addr *ap, struct ifnet *ifp)
  856 {
  857         struct in_multi *inm;
  858         struct ifreq ifr;
  859 
  860         /*
  861          * See if address already in list.
  862          */
  863         IN_LOOKUP_MULTI(*ap, ifp, inm);
  864         if (inm != NULL) {
  865                 /*
  866                  * Found it; just increment the reference count.
  867                  */
  868                 ++inm->inm_refcnt;
  869         } else {
  870                 /*
  871                  * New address; allocate a new multicast record
  872                  * and link it into the interface's multicast list.
  873                  */
  874                 inm = malloc(sizeof(*inm), M_IPMADDR, M_WAITOK | M_ZERO);
  875                 inm->inm_sin.sin_len = sizeof(struct sockaddr_in);
  876                 inm->inm_sin.sin_family = AF_INET;
  877                 inm->inm_sin.sin_addr = *ap;
  878                 inm->inm_refcnt = 1;
  879                 inm->inm_ifidx = ifp->if_index;
  880                 inm->inm_ifma.ifma_addr = sintosa(&inm->inm_sin);
  881 
  882                 /*
  883                  * Ask the network driver to update its multicast reception
  884                  * filter appropriately for the new address.
  885                  */
  886                 memset(&ifr, 0, sizeof(ifr));
  887                 memcpy(&ifr.ifr_addr, &inm->inm_sin, sizeof(inm->inm_sin));
  888                 KERNEL_LOCK();
  889                 if ((*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) {
  890                         KERNEL_UNLOCK();
  891                         free(inm, M_IPMADDR, sizeof(*inm));
  892                         return (NULL);
  893                 }
  894                 KERNEL_UNLOCK();
  895 
  896                 TAILQ_INSERT_HEAD(&ifp->if_maddrlist, &inm->inm_ifma,
  897                     ifma_list);
  898 
  899                 /*
  900                  * Let IGMP know that we have joined a new IP multicast group.
  901                  */
  902                 igmp_joingroup(inm, ifp);
  903         }
  904 
  905         return (inm);
  906 }
  907 
  908 /*
  909  * Delete a multicast address record.
  910  */
  911 void
  912 in_delmulti(struct in_multi *inm)
  913 {
  914         struct ifreq ifr;
  915         struct ifnet *ifp;
  916 
  917         NET_ASSERT_LOCKED();
  918 
  919         if (--inm->inm_refcnt != 0)
  920                 return;
  921 
  922         ifp = if_get(inm->inm_ifidx);
  923         if (ifp != NULL) {
  924                 /*
  925                  * No remaining claims to this record; let IGMP know that
  926                  * we are leaving the multicast group.
  927                  */
  928                 igmp_leavegroup(inm, ifp);
  929 
  930                 /*
  931                  * Notify the network driver to update its multicast
  932                  * reception filter.
  933                  */
  934                 memset(&ifr, 0, sizeof(ifr));
  935                 satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
  936                 satosin(&ifr.ifr_addr)->sin_family = AF_INET;
  937                 satosin(&ifr.ifr_addr)->sin_addr = inm->inm_addr;
  938                 KERNEL_LOCK();
  939                 (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
  940                 KERNEL_UNLOCK();
  941 
  942                 TAILQ_REMOVE(&ifp->if_maddrlist, &inm->inm_ifma, ifma_list);
  943         }
  944         if_put(ifp);
  945 
  946         free(inm, M_IPMADDR, sizeof(*inm));
  947 }
  948 
  949 /*
  950  * Return 1 if the multicast group represented by ``ap'' has been
  951  * joined by interface ``ifp'', 0 otherwise.
  952  */
  953 int
  954 in_hasmulti(struct in_addr *ap, struct ifnet *ifp)
  955 {
  956         struct in_multi *inm;
  957         int joined;
  958 
  959         IN_LOOKUP_MULTI(*ap, ifp, inm);
  960         joined = (inm != NULL);
  961 
  962         return (joined);
  963 }
  964 
  965 void
  966 in_ifdetach(struct ifnet *ifp)
  967 {
  968         struct ifaddr *ifa, *next;
  969 
  970         /* nuke any of IPv4 addresses we have */
  971         TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrlist, ifa_list, next) {
  972                 if (ifa->ifa_addr->sa_family != AF_INET)
  973                         continue;
  974                 in_purgeaddr(ifa);
  975                 if_addrhooks_run(ifp);
  976         }
  977 
  978         if (ifp->if_xflags & IFXF_AUTOCONF4)
  979                 ifp->if_xflags &= ~IFXF_AUTOCONF4;
  980 }
  981 
  982 void
  983 in_prefixlen2mask(struct in_addr *maskp, int plen)
  984 {
  985         if (plen == 0)
  986                 maskp->s_addr = 0;
  987         else
  988                 maskp->s_addr = htonl(0xffffffff << (32 - plen));
  989 }

Cache object: 88eb0be17beb06d164f6b9e7d26701ec


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