LCOV - code coverage report
Current view: top level - netinet - in.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 408 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 23 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: in.c,v 1.160 2018/07/11 21:18:23 nayden 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_sifaddr(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           0 : in_canforward(struct in_addr in)
     103             : {
     104             :         u_int32_t net;
     105             : 
     106           0 :         if (IN_EXPERIMENTAL(in.s_addr) || IN_MULTICAST(in.s_addr))
     107           0 :                 return (0);
     108           0 :         if (IN_CLASSA(in.s_addr)) {
     109           0 :                 net = in.s_addr & IN_CLASSA_NET;
     110           0 :                 if (net == 0 ||
     111           0 :                     net == htonl(IN_LOOPBACKNET << IN_CLASSA_NSHIFT))
     112           0 :                         return (0);
     113             :         }
     114           0 :         return (1);
     115           0 : }
     116             : 
     117             : /*
     118             :  * Trim a mask in a sockaddr
     119             :  */
     120             : void
     121           0 : in_socktrim(struct sockaddr_in *ap)
     122             : {
     123           0 :         char *cplim = (char *) &ap->sin_addr;
     124           0 :         char *cp = (char *) (&ap->sin_addr + 1);
     125             : 
     126           0 :         ap->sin_len = 0;
     127           0 :         while (--cp >= cplim)
     128           0 :                 if (*cp) {
     129           0 :                         (ap)->sin_len = cp - (char *) (ap) + 1;
     130           0 :                         break;
     131             :                 }
     132           0 : }
     133             : 
     134             : int
     135           0 : in_mask2len(struct in_addr *mask)
     136             : {
     137             :         int x, y;
     138             :         u_char *p;
     139             : 
     140           0 :         p = (u_char *)mask;
     141           0 :         for (x = 0; x < sizeof(*mask); x++) {
     142           0 :                 if (p[x] != 0xff)
     143             :                         break;
     144             :         }
     145             :         y = 0;
     146           0 :         if (x < sizeof(*mask)) {
     147           0 :                 for (y = 0; y < 8; y++) {
     148           0 :                         if ((p[x] & (0x80 >> y)) == 0)
     149             :                                 break;
     150             :                 }
     151             :         }
     152           0 :         return x * 8 + y;
     153             : }
     154             : 
     155             : void
     156           0 : in_len2mask(struct in_addr *mask, int len)
     157             : {
     158             :         int i;
     159             :         u_char *p;
     160             : 
     161           0 :         p = (u_char *)mask;
     162           0 :         bzero(mask, sizeof(*mask));
     163           0 :         for (i = 0; i < len / 8; i++)
     164           0 :                 p[i] = 0xff;
     165           0 :         if (len % 8)
     166           0 :                 p[i] = (0xff00 >> (len % 8)) & 0xff;
     167           0 : }
     168             : 
     169             : int
     170           0 : in_nam2sin(const struct mbuf *nam, struct sockaddr_in **sin)
     171             : {
     172           0 :         struct sockaddr *sa = mtod(nam, struct sockaddr *);
     173             : 
     174           0 :         if (nam->m_len < offsetof(struct sockaddr, sa_data))
     175           0 :                 return EINVAL;
     176           0 :         if (sa->sa_family != AF_INET)
     177           0 :                 return EAFNOSUPPORT;
     178           0 :         if (sa->sa_len != nam->m_len)
     179           0 :                 return EINVAL;
     180           0 :         if (sa->sa_len != sizeof(struct sockaddr_in))
     181           0 :                 return EINVAL;
     182           0 :         *sin = satosin(sa);
     183             : 
     184           0 :         return 0;
     185           0 : }
     186             : 
     187             : int
     188           0 : in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp)
     189             : {
     190             :         int privileged;
     191             :         int error;
     192             : 
     193             :         privileged = 0;
     194           0 :         if ((so->so_state & SS_PRIV) != 0)
     195           0 :                 privileged++;
     196             : 
     197           0 :         switch (cmd) {
     198             : #ifdef MROUTING
     199             :         case SIOCGETVIFCNT:
     200             :         case SIOCGETSGCNT:
     201           0 :                 error = mrt_ioctl(so, cmd, data);
     202           0 :                 break;
     203             : #endif /* MROUTING */
     204             :         default:
     205           0 :                 error = in_ioctl(cmd, data, ifp, privileged);
     206           0 :                 break;
     207             :         }
     208             : 
     209           0 :         return error;
     210             : }
     211             : 
     212             : int
     213           0 : in_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, int privileged)
     214             : {
     215           0 :         struct ifreq *ifr = (struct ifreq *)data;
     216             :         struct ifaddr *ifa;
     217             :         struct in_ifaddr *ia = NULL;
     218           0 :         struct sockaddr_in oldaddr;
     219             :         int error = 0;
     220             : 
     221           0 :         if (ifp == NULL)
     222           0 :                 return (ENXIO);
     223             : 
     224           0 :         switch (cmd) {
     225             :         case SIOCGIFADDR:
     226             :         case SIOCGIFNETMASK:
     227             :         case SIOCGIFDSTADDR:
     228             :         case SIOCGIFBRDADDR:
     229           0 :                 return in_ioctl_get(cmd, data, ifp);
     230             :         case SIOCSIFADDR:
     231           0 :                 return in_ioctl_sifaddr(cmd, data, ifp, privileged);
     232             :         case SIOCAIFADDR:
     233             :         case SIOCDIFADDR:
     234           0 :                 return in_ioctl_change_ifaddr(cmd, data, ifp, privileged);
     235             :         case SIOCSIFNETMASK:
     236             :         case SIOCSIFDSTADDR:
     237             :         case SIOCSIFBRDADDR:
     238             :                 break;
     239             :         default:
     240           0 :                 return (EOPNOTSUPP);
     241             :         }
     242             : 
     243           0 :         NET_LOCK();
     244             : 
     245           0 :         TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
     246           0 :                 if (ifa->ifa_addr->sa_family == AF_INET) {
     247           0 :                         ia = ifatoia(ifa);
     248           0 :                         break;
     249             :                 }
     250             :         }
     251             : 
     252           0 :         if (ia && satosin(&ifr->ifr_addr)->sin_addr.s_addr) {
     253           0 :                 for (; ifa != NULL; ifa = TAILQ_NEXT(ifa, ifa_list)) {
     254           0 :                         if ((ifa->ifa_addr->sa_family == AF_INET) &&
     255           0 :                             ifatoia(ifa)->ia_addr.sin_addr.s_addr ==
     256           0 :                             satosin(&ifr->ifr_addr)->sin_addr.s_addr) {
     257           0 :                                 ia = ifatoia(ifa);
     258           0 :                                 break;
     259             :                         }
     260             :                 }
     261             :         }
     262           0 :         if (ia == NULL) {
     263           0 :                 NET_UNLOCK();
     264           0 :                 return (EADDRNOTAVAIL);
     265             :         }
     266             : 
     267           0 :         switch (cmd) {
     268             :         case SIOCSIFDSTADDR:
     269           0 :                 if (!privileged) {
     270             :                         error = EPERM;
     271           0 :                         break;
     272             :                 }
     273             : 
     274           0 :                 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
     275             :                         error = EINVAL;
     276           0 :                         break;
     277             :                 }
     278           0 :                 oldaddr = ia->ia_dstaddr;
     279           0 :                 ia->ia_dstaddr = *satosin(&ifr->ifr_dstaddr);
     280           0 :                 error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (caddr_t)ia);
     281           0 :                 if (error) {
     282           0 :                         ia->ia_dstaddr = oldaddr;
     283           0 :                         break;
     284             :                 }
     285           0 :                 in_scrubhost(ia, &oldaddr);
     286           0 :                 in_addhost(ia, &ia->ia_dstaddr);
     287           0 :                 break;
     288             : 
     289             :         case SIOCSIFBRDADDR:
     290           0 :                 if (!privileged) {
     291             :                         error = EPERM;
     292           0 :                         break;
     293             :                 }
     294             : 
     295           0 :                 if ((ifp->if_flags & IFF_BROADCAST) == 0) {
     296             :                         error = EINVAL;
     297           0 :                         break;
     298             :                 }
     299           0 :                 ifa_update_broadaddr(ifp, &ia->ia_ifa, &ifr->ifr_broadaddr);
     300           0 :                 break;
     301             : 
     302             :         case SIOCSIFNETMASK:
     303           0 :                 if (!privileged) {
     304             :                         error = EPERM;
     305           0 :                         break;
     306             :                 }
     307             : 
     308           0 :                 ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr =
     309           0 :                     satosin(&ifr->ifr_addr)->sin_addr.s_addr;
     310           0 :                 break;
     311             :         }
     312             : 
     313           0 :         NET_UNLOCK();
     314           0 :         return (error);
     315           0 : }
     316             : 
     317             : int
     318           0 : in_ioctl_sifaddr(u_long cmd, caddr_t data, struct ifnet *ifp, int privileged)
     319             : {
     320           0 :         struct ifreq *ifr = (struct ifreq *)data;
     321             :         struct ifaddr *ifa;
     322             :         struct in_ifaddr *ia = NULL;
     323             :         int error = 0;
     324             :         int newifaddr;
     325             : 
     326           0 :         if (cmd != SIOCSIFADDR)
     327           0 :                 panic("%s: invalid ioctl %lu", __func__, cmd);
     328             : 
     329           0 :         if (!privileged)
     330           0 :                 return (EPERM);
     331             : 
     332           0 :         NET_LOCK();
     333             : 
     334           0 :         TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
     335           0 :                 if (ifa->ifa_addr->sa_family == AF_INET) {
     336           0 :                         ia = ifatoia(ifa);
     337           0 :                         break;
     338             :                 }
     339             :         }
     340             : 
     341           0 :         if (ia == NULL) {
     342           0 :                 ia = malloc(sizeof *ia, M_IFADDR, M_WAITOK | M_ZERO);
     343           0 :                 ia->ia_addr.sin_family = AF_INET;
     344           0 :                 ia->ia_addr.sin_len = sizeof(ia->ia_addr);
     345           0 :                 ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
     346           0 :                 ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
     347           0 :                 ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
     348           0 :                 ia->ia_sockmask.sin_len = 8;
     349           0 :                 if (ifp->if_flags & IFF_BROADCAST) {
     350           0 :                         ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
     351           0 :                         ia->ia_broadaddr.sin_family = AF_INET;
     352           0 :                 }
     353           0 :                 ia->ia_ifp = ifp;
     354             : 
     355             :                 newifaddr = 1;
     356           0 :         } else
     357             :                 newifaddr = 0;
     358             : 
     359           0 :         in_ifscrub(ifp, ia);
     360           0 :         error = in_ifinit(ifp, ia, satosin(&ifr->ifr_addr), newifaddr);
     361           0 :         if (!error)
     362           0 :                 dohooks(ifp->if_addrhooks, 0);
     363             : 
     364           0 :         NET_UNLOCK();
     365           0 :         return error;
     366           0 : }
     367             : 
     368             : int
     369           0 : in_ioctl_change_ifaddr(u_long cmd, caddr_t data, struct ifnet *ifp,
     370             :     int privileged)
     371             : {
     372             :         struct ifaddr *ifa;
     373             :         struct in_ifaddr *ia = NULL;
     374           0 :         struct in_aliasreq *ifra = (struct in_aliasreq *)data;
     375             :         int error = 0;
     376             :         int newifaddr;
     377             : 
     378           0 :         NET_LOCK();
     379             : 
     380           0 :         TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
     381           0 :                 if (ifa->ifa_addr->sa_family == AF_INET) {
     382           0 :                         ia = ifatoia(ifa);
     383           0 :                         break;
     384             :                 }
     385             :         }
     386             : 
     387           0 :         if (ifra->ifra_addr.sin_family == AF_INET) {
     388           0 :                 for (; ifa != NULL; ifa = TAILQ_NEXT(ifa, ifa_list)) {
     389           0 :                         if ((ifa->ifa_addr->sa_family == AF_INET) &&
     390           0 :                             ifatoia(ifa)->ia_addr.sin_addr.s_addr ==
     391           0 :                             ifra->ifra_addr.sin_addr.s_addr)
     392             :                                 break;
     393             :                 }
     394           0 :                 ia = ifatoia(ifa);
     395           0 :         }
     396             : 
     397           0 :         switch (cmd) {
     398             :         case SIOCAIFADDR: {
     399             :                 int needinit = 0;
     400             : 
     401           0 :                 if (!privileged) {
     402             :                         error = EPERM;
     403           0 :                         break;
     404             :                 }
     405             : 
     406           0 :                 if (ia == NULL) {
     407           0 :                         ia = malloc(sizeof *ia, M_IFADDR, M_WAITOK | M_ZERO);
     408           0 :                         ia->ia_addr.sin_family = AF_INET;
     409           0 :                         ia->ia_addr.sin_len = sizeof(ia->ia_addr);
     410           0 :                         ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
     411           0 :                         ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
     412           0 :                         ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
     413           0 :                         ia->ia_sockmask.sin_len = 8;
     414           0 :                         if (ifp->if_flags & IFF_BROADCAST) {
     415           0 :                                 ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
     416           0 :                                 ia->ia_broadaddr.sin_family = AF_INET;
     417           0 :                         }
     418           0 :                         ia->ia_ifp = ifp;
     419             : 
     420             :                         newifaddr = 1;
     421           0 :                 } else
     422             :                         newifaddr = 0;
     423             : 
     424           0 :                 if (ia->ia_addr.sin_family == AF_INET) {
     425           0 :                         if (ifra->ifra_addr.sin_len == 0)
     426           0 :                                 ifra->ifra_addr = ia->ia_addr;
     427           0 :                         else if (ifra->ifra_addr.sin_addr.s_addr !=
     428           0 :                             ia->ia_addr.sin_addr.s_addr || newifaddr)
     429           0 :                                 needinit = 1;
     430             :                 }
     431           0 :                 if (ifra->ifra_mask.sin_len) {
     432           0 :                         in_ifscrub(ifp, ia);
     433           0 :                         ia->ia_sockmask = ifra->ifra_mask;
     434           0 :                         ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr;
     435             :                         needinit = 1;
     436           0 :                 }
     437           0 :                 if ((ifp->if_flags & IFF_POINTOPOINT) &&
     438           0 :                     (ifra->ifra_dstaddr.sin_family == AF_INET)) {
     439           0 :                         in_ifscrub(ifp, ia);
     440           0 :                         ia->ia_dstaddr = ifra->ifra_dstaddr;
     441             :                         needinit  = 1;
     442           0 :                 }
     443           0 :                 if ((ifp->if_flags & IFF_BROADCAST) &&
     444           0 :                     (ifra->ifra_broadaddr.sin_family == AF_INET)) {
     445           0 :                         if (newifaddr)
     446           0 :                                 ia->ia_broadaddr = ifra->ifra_broadaddr;
     447             :                         else
     448           0 :                                 ifa_update_broadaddr(ifp, &ia->ia_ifa,
     449           0 :                                     sintosa(&ifra->ifra_broadaddr));
     450             :                 }
     451           0 :                 if (ifra->ifra_addr.sin_family == AF_INET && needinit) {
     452           0 :                         error = in_ifinit(ifp, ia, &ifra->ifra_addr, newifaddr);
     453           0 :                 }
     454           0 :                 if (error)
     455           0 :                         break;
     456           0 :                 dohooks(ifp->if_addrhooks, 0);
     457           0 :                 break;
     458             :                 }
     459             :         case SIOCDIFADDR:
     460           0 :                 if (!privileged) {
     461             :                         error = EPERM;
     462           0 :                         break;
     463             :                 }
     464             : 
     465           0 :                 if (ia == NULL) {
     466             :                         error = EADDRNOTAVAIL;
     467           0 :                         break;
     468             :                 }
     469             :                 /*
     470             :                  * Even if the individual steps were safe, shouldn't
     471             :                  * these kinds of changes happen atomically?  What
     472             :                  * should happen to a packet that was routed after
     473             :                  * the scrub but before the other steps?
     474             :                  */
     475           0 :                 in_purgeaddr(&ia->ia_ifa);
     476           0 :                 dohooks(ifp->if_addrhooks, 0);
     477           0 :                 break;
     478             : 
     479             :         default:
     480           0 :                 panic("%s: invalid ioctl %lu", __func__, cmd);
     481             :         }
     482             : 
     483           0 :         NET_UNLOCK();
     484           0 :         return (error);
     485             : }
     486             : 
     487             : int
     488           0 : in_ioctl_get(u_long cmd, caddr_t data, struct ifnet *ifp)
     489             : {
     490           0 :         struct ifreq *ifr = (struct ifreq *)data;
     491             :         struct ifaddr *ifa;
     492             :         struct in_ifaddr *ia = NULL;
     493             :         int error = 0;
     494             : 
     495           0 :         NET_RLOCK();
     496             : 
     497           0 :         TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
     498           0 :                 if (ifa->ifa_addr->sa_family == AF_INET) {
     499           0 :                         ia = ifatoia(ifa);
     500           0 :                         break;
     501             :                 }
     502             :         }
     503             : 
     504           0 :         if (ia && satosin(&ifr->ifr_addr)->sin_addr.s_addr) {
     505           0 :                 for (; ifa != NULL; ifa = TAILQ_NEXT(ifa, ifa_list)) {
     506           0 :                         if ((ifa->ifa_addr->sa_family == AF_INET) &&
     507           0 :                             ifatoia(ifa)->ia_addr.sin_addr.s_addr ==
     508           0 :                             satosin(&ifr->ifr_addr)->sin_addr.s_addr) {
     509           0 :                                 ia = ifatoia(ifa);
     510           0 :                                 break;
     511             :                         }
     512             :                 }
     513             :         }
     514           0 :         if (ia == NULL) {
     515             :                 error = EADDRNOTAVAIL;
     516           0 :                 goto err;
     517             :         }
     518             : 
     519           0 :         switch(cmd) {
     520             :         case SIOCGIFADDR:
     521           0 :                 *satosin(&ifr->ifr_addr) = ia->ia_addr;
     522           0 :                 break;
     523             : 
     524             :         case SIOCGIFBRDADDR:
     525           0 :                 if ((ifp->if_flags & IFF_BROADCAST) == 0) {
     526             :                         error = EINVAL;
     527           0 :                         break;
     528             :                 }
     529           0 :                 *satosin(&ifr->ifr_dstaddr) = ia->ia_broadaddr;
     530           0 :                 break;
     531             : 
     532             :         case SIOCGIFDSTADDR:
     533           0 :                 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
     534             :                         error = EINVAL;
     535           0 :                         break;
     536             :                 }
     537           0 :                 *satosin(&ifr->ifr_dstaddr) = ia->ia_dstaddr;
     538           0 :                 break;
     539             : 
     540             :         case SIOCGIFNETMASK:
     541           0 :                 *satosin(&ifr->ifr_addr) = ia->ia_sockmask;
     542           0 :                 break;
     543             : 
     544             :         default:
     545           0 :                 panic("%s: invalid ioctl %lu", __func__, cmd);
     546             :         }
     547             : 
     548             : err:
     549           0 :         NET_RUNLOCK();
     550           0 :         return (error);
     551             : }
     552             : 
     553             : /*
     554             :  * Delete any existing route for an interface.
     555             :  */
     556             : void
     557           0 : in_ifscrub(struct ifnet *ifp, struct in_ifaddr *ia)
     558             : {
     559           0 :         if (ISSET(ifp->if_flags, IFF_POINTOPOINT))
     560           0 :                 in_scrubhost(ia, &ia->ia_dstaddr);
     561           0 :         else if (!ISSET(ifp->if_flags, IFF_LOOPBACK))
     562           0 :                 in_remove_prefix(ia);
     563           0 : }
     564             : 
     565             : /*
     566             :  * Initialize an interface's internet address
     567             :  * and routing table entry.
     568             :  */
     569             : int
     570           0 : in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin,
     571             :     int newaddr)
     572             : {
     573           0 :         u_int32_t i = sin->sin_addr.s_addr;
     574           0 :         struct sockaddr_in oldaddr;
     575             :         int error = 0, rterror;
     576             : 
     577           0 :         NET_ASSERT_LOCKED();
     578             : 
     579             :         /*
     580             :          * Always remove the address from the tree to make sure its
     581             :          * position gets updated in case the key changes.
     582             :          */
     583           0 :         if (!newaddr) {
     584           0 :                 rt_ifa_dellocal(&ia->ia_ifa);
     585           0 :                 ifa_del(ifp, &ia->ia_ifa);
     586           0 :         }
     587           0 :         oldaddr = ia->ia_addr;
     588           0 :         ia->ia_addr = *sin;
     589             : 
     590           0 :         if (ia->ia_netmask == 0) {
     591           0 :                 if (IN_CLASSA(i))
     592           0 :                         ia->ia_netmask = IN_CLASSA_NET;
     593           0 :                 else if (IN_CLASSB(i))
     594           0 :                         ia->ia_netmask = IN_CLASSB_NET;
     595             :                 else
     596           0 :                         ia->ia_netmask = IN_CLASSC_NET;
     597           0 :                 ia->ia_sockmask.sin_addr.s_addr = ia->ia_netmask;
     598           0 :         }
     599             : 
     600             :         /*
     601             :          * Give the interface a chance to initialize
     602             :          * if this is its first address,
     603             :          * and to validate the address if necessary.
     604             :          */
     605           0 :         if ((error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
     606           0 :                 ia->ia_addr = oldaddr;
     607           0 :         }
     608             : 
     609             :         /*
     610             :          * Add the address to the local list and the global tree.  If an
     611             :          * error occured, put back the original address.
     612             :          */
     613           0 :         ifa_add(ifp, &ia->ia_ifa);
     614           0 :         rterror = rt_ifa_addlocal(&ia->ia_ifa);
     615             : 
     616           0 :         if (rterror) {
     617           0 :                 if (!newaddr)
     618           0 :                         ifa_del(ifp, &ia->ia_ifa);
     619           0 :                 if (!error)
     620           0 :                         error = rterror;
     621             :                 goto out;
     622             :         }
     623           0 :         if (error)
     624             :                 goto out;
     625             : 
     626             : 
     627           0 :         ia->ia_net = i & ia->ia_netmask;
     628           0 :         in_socktrim(&ia->ia_sockmask);
     629             :         /*
     630             :          * Add route for the network.
     631             :          */
     632           0 :         ia->ia_ifa.ifa_metric = ifp->if_metric;
     633           0 :         if (ISSET(ifp->if_flags, IFF_BROADCAST)) {
     634           0 :                 if (IN_RFC3021_SUBNET(ia->ia_netmask))
     635           0 :                         ia->ia_broadaddr.sin_addr.s_addr = 0;
     636             :                 else {
     637           0 :                         ia->ia_broadaddr.sin_addr.s_addr =
     638           0 :                             ia->ia_net | ~ia->ia_netmask;
     639             :                 }
     640             :         }
     641             : 
     642           0 :         if (ISSET(ifp->if_flags, IFF_POINTOPOINT)) {
     643             :                 /* XXX We should not even call in_ifinit() in this case. */
     644           0 :                 if (ia->ia_dstaddr.sin_family != AF_INET)
     645             :                         goto out;
     646           0 :                 error = in_addhost(ia, &ia->ia_dstaddr);
     647           0 :         } else if (!ISSET(ifp->if_flags, IFF_LOOPBACK)) {
     648           0 :                 error = in_insert_prefix(ia);
     649           0 :         }
     650             : 
     651             :         /*
     652             :          * If the interface supports multicast, join the "all hosts"
     653             :          * multicast group on that interface.
     654             :          */
     655           0 :         if ((ifp->if_flags & IFF_MULTICAST) && ia->ia_allhosts == NULL) {
     656           0 :                 struct in_addr addr;
     657             : 
     658           0 :                 addr.s_addr = INADDR_ALLHOSTS_GROUP;
     659           0 :                 ia->ia_allhosts = in_addmulti(&addr, ifp);
     660           0 :         }
     661             : 
     662             : out:
     663           0 :         if (error && newaddr)
     664           0 :                 in_purgeaddr(&ia->ia_ifa);
     665             : 
     666           0 :         return (error);
     667           0 : }
     668             : 
     669             : void
     670           0 : in_purgeaddr(struct ifaddr *ifa)
     671             : {
     672           0 :         struct ifnet *ifp = ifa->ifa_ifp;
     673           0 :         struct in_ifaddr *ia = ifatoia(ifa);
     674             :         extern int ifatrash;
     675             : 
     676           0 :         NET_ASSERT_LOCKED();
     677             : 
     678           0 :         in_ifscrub(ifp, ia);
     679             : 
     680           0 :         rt_ifa_dellocal(&ia->ia_ifa);
     681           0 :         rt_ifa_purge(&ia->ia_ifa);
     682           0 :         ifa_del(ifp, &ia->ia_ifa);
     683             : 
     684           0 :         if (ia->ia_allhosts != NULL) {
     685           0 :                 in_delmulti(ia->ia_allhosts);
     686           0 :                 ia->ia_allhosts = NULL;
     687           0 :         }
     688             : 
     689           0 :         ifatrash++;
     690           0 :         ia->ia_ifp = NULL;
     691           0 :         ifafree(&ia->ia_ifa);
     692           0 : }
     693             : 
     694             : int
     695           0 : in_addhost(struct in_ifaddr *ia, struct sockaddr_in *dst)
     696             : {
     697           0 :         return rt_ifa_add(&ia->ia_ifa, RTF_HOST, sintosa(dst));
     698             : }
     699             : 
     700             : int
     701           0 : in_scrubhost(struct in_ifaddr *ia, struct sockaddr_in *dst)
     702             : {
     703           0 :         return rt_ifa_del(&ia->ia_ifa, RTF_HOST, sintosa(dst));
     704             : }
     705             : 
     706             : /*
     707             :  * Insert the cloning and broadcast routes for this subnet.
     708             :  */
     709             : int
     710           0 : in_insert_prefix(struct in_ifaddr *ia)
     711             : {
     712           0 :         struct ifaddr *ifa = &ia->ia_ifa;
     713             :         int error;
     714             : 
     715           0 :         error = rt_ifa_add(ifa, RTF_CLONING | RTF_CONNECTED, ifa->ifa_addr);
     716           0 :         if (error)
     717           0 :                 return (error);
     718             : 
     719           0 :         if (ia->ia_broadaddr.sin_addr.s_addr != 0)
     720           0 :                 error = rt_ifa_add(ifa, RTF_HOST | RTF_BROADCAST,
     721           0 :                     ifa->ifa_broadaddr);
     722             : 
     723           0 :         return (error);
     724           0 : }
     725             : 
     726             : void
     727           0 : in_remove_prefix(struct in_ifaddr *ia)
     728             : {
     729           0 :         struct ifaddr *ifa = &ia->ia_ifa;
     730             : 
     731           0 :         rt_ifa_del(ifa, RTF_CLONING | RTF_CONNECTED, ifa->ifa_addr);
     732             : 
     733           0 :         if (ia->ia_broadaddr.sin_addr.s_addr != 0)
     734           0 :                 rt_ifa_del(ifa, RTF_HOST | RTF_BROADCAST, ifa->ifa_broadaddr);
     735           0 : }
     736             : 
     737             : /*
     738             :  * Return 1 if the address is a local broadcast address.
     739             :  */
     740             : int
     741           0 : in_broadcast(struct in_addr in, u_int rtableid)
     742             : {
     743             :         struct ifnet *ifn;
     744             :         struct ifaddr *ifa;
     745             :         u_int rdomain;
     746             : 
     747           0 :         rdomain = rtable_l2(rtableid);
     748             : 
     749             : #define ia (ifatoia(ifa))
     750           0 :         TAILQ_FOREACH(ifn, &ifnet, if_list) {
     751           0 :                 if (ifn->if_rdomain != rdomain)
     752             :                         continue;
     753           0 :                 if ((ifn->if_flags & IFF_BROADCAST) == 0)
     754             :                         continue;
     755           0 :                 TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list)
     756           0 :                         if (ifa->ifa_addr->sa_family == AF_INET &&
     757           0 :                             in.s_addr != ia->ia_addr.sin_addr.s_addr &&
     758           0 :                             in.s_addr == ia->ia_broadaddr.sin_addr.s_addr)
     759           0 :                                 return 1;
     760             :         }
     761           0 :         return (0);
     762             : #undef ia
     763           0 : }
     764             : 
     765             : /*
     766             :  * Add an address to the list of IP multicast addresses for a given interface.
     767             :  */
     768             : struct in_multi *
     769           0 : in_addmulti(struct in_addr *ap, struct ifnet *ifp)
     770             : {
     771             :         struct in_multi *inm;
     772           0 :         struct ifreq ifr;
     773             : 
     774             :         /*
     775             :          * See if address already in list.
     776             :          */
     777           0 :         IN_LOOKUP_MULTI(*ap, ifp, inm);
     778           0 :         if (inm != NULL) {
     779             :                 /*
     780             :                  * Found it; just increment the reference count.
     781             :                  */
     782           0 :                 ++inm->inm_refcnt;
     783           0 :         } else {
     784             :                 /*
     785             :                  * New address; allocate a new multicast record
     786             :                  * and link it into the interface's multicast list.
     787             :                  */
     788           0 :                 inm = malloc(sizeof(*inm), M_IPMADDR, M_NOWAIT | M_ZERO);
     789           0 :                 if (inm == NULL)
     790           0 :                         return (NULL);
     791             : 
     792           0 :                 inm->inm_sin.sin_len = sizeof(struct sockaddr_in);
     793           0 :                 inm->inm_sin.sin_family = AF_INET;
     794           0 :                 inm->inm_sin.sin_addr = *ap;
     795           0 :                 inm->inm_refcnt = 1;
     796           0 :                 inm->inm_ifidx = ifp->if_index;
     797           0 :                 inm->inm_ifma.ifma_addr = sintosa(&inm->inm_sin);
     798             : 
     799             :                 /*
     800             :                  * Ask the network driver to update its multicast reception
     801             :                  * filter appropriately for the new address.
     802             :                  */
     803           0 :                 memset(&ifr, 0, sizeof(ifr));
     804           0 :                 memcpy(&ifr.ifr_addr, &inm->inm_sin, sizeof(inm->inm_sin));
     805           0 :                 if ((*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) {
     806           0 :                         free(inm, M_IPMADDR, sizeof(*inm));
     807           0 :                         return (NULL);
     808             :                 }
     809             : 
     810           0 :                 TAILQ_INSERT_HEAD(&ifp->if_maddrlist, &inm->inm_ifma,
     811             :                     ifma_list);
     812             : 
     813             :                 /*
     814             :                  * Let IGMP know that we have joined a new IP multicast group.
     815             :                  */
     816           0 :                 igmp_joingroup(inm);
     817             :         }
     818             : 
     819           0 :         return (inm);
     820           0 : }
     821             : 
     822             : /*
     823             :  * Delete a multicast address record.
     824             :  */
     825             : void
     826           0 : in_delmulti(struct in_multi *inm)
     827             : {
     828           0 :         struct ifreq ifr;
     829             :         struct ifnet *ifp;
     830             : 
     831           0 :         NET_ASSERT_LOCKED();
     832             : 
     833           0 :         if (--inm->inm_refcnt == 0) {
     834             :                 /*
     835             :                  * No remaining claims to this record; let IGMP know that
     836             :                  * we are leaving the multicast group.
     837             :                  */
     838           0 :                 igmp_leavegroup(inm);
     839           0 :                 ifp = if_get(inm->inm_ifidx);
     840             : 
     841             :                 /*
     842             :                  * Notify the network driver to update its multicast
     843             :                  * reception filter.
     844             :                  */
     845           0 :                 if (ifp != NULL) {
     846           0 :                         memset(&ifr, 0, sizeof(ifr));
     847           0 :                         satosin(&ifr.ifr_addr)->sin_len =
     848             :                             sizeof(struct sockaddr_in);
     849           0 :                         satosin(&ifr.ifr_addr)->sin_family = AF_INET;
     850           0 :                         satosin(&ifr.ifr_addr)->sin_addr = inm->inm_addr;
     851           0 :                         (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
     852             : 
     853           0 :                         TAILQ_REMOVE(&ifp->if_maddrlist, &inm->inm_ifma,
     854             :                             ifma_list);
     855           0 :                 }
     856           0 :                 if_put(ifp);
     857             : 
     858           0 :                 free(inm, M_IPMADDR, sizeof(*inm));
     859           0 :         }
     860           0 : }
     861             : 
     862             : /*
     863             :  * Return 1 if the multicast group represented by ``ap'' has been
     864             :  * joined by interface ``ifp'', 0 otherwise.
     865             :  */
     866             : int
     867           0 : in_hasmulti(struct in_addr *ap, struct ifnet *ifp)
     868             : {
     869             :         struct in_multi *inm;
     870             :         int joined;
     871             : 
     872           0 :         IN_LOOKUP_MULTI(*ap, ifp, inm);
     873           0 :         joined = (inm != NULL);
     874             : 
     875           0 :         return (joined);
     876             : }
     877             : 
     878             : void
     879           0 : in_ifdetach(struct ifnet *ifp)
     880             : {
     881             :         struct ifaddr *ifa, *next;
     882             : 
     883             :         /* nuke any of IPv4 addresses we have */
     884           0 :         TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrlist, ifa_list, next) {
     885           0 :                 if (ifa->ifa_addr->sa_family != AF_INET)
     886             :                         continue;
     887           0 :                 in_purgeaddr(ifa);
     888           0 :                 dohooks(ifp->if_addrhooks, 0);
     889           0 :         }
     890           0 : }
     891             : 
     892             : void
     893           0 : in_prefixlen2mask(struct in_addr *maskp, int plen)
     894             : {
     895           0 :         if (plen == 0)
     896           0 :                 maskp->s_addr = 0;
     897             :         else
     898           0 :                 maskp->s_addr = htonl(0xffffffff << (32 - plen));
     899           0 : }

Generated by: LCOV version 1.13