]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/mrouted/config.c
This commit was generated by cvs2svn to compensate for changes in r102840,
[FreeBSD/FreeBSD.git] / usr.sbin / mrouted / config.c
1 /*
2  * The mrouted program is covered by the license in the accompanying file
3  * named "LICENSE".  Use of the mrouted program represents acceptance of
4  * the terms and conditions listed in that file.
5  *
6  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
7  * Leland Stanford Junior University.
8  *
9  *
10  * config.c,v 3.8.4.10 1998/01/06 01:57:41 fenner Exp
11  */
12
13 #ifndef lint
14 static const char rcsid[] =
15   "$FreeBSD$";
16 #endif /* not lint */
17
18 #include "defs.h"
19
20
21 struct ifconf ifc;
22
23 /*
24  * Query the kernel to find network interfaces that are multicast-capable
25  * and install them in the uvifs array.
26  */
27 void
28 config_vifs_from_kernel()
29 {
30     struct ifreq *ifrp, *ifend;
31     register struct uvif *v;
32     register vifi_t vifi;
33     int n;
34     u_int32 addr, mask, subnet;
35     int flags;
36     int num_ifreq = 32;
37
38     ifc.ifc_len = num_ifreq * sizeof(struct ifreq);
39     ifc.ifc_buf = malloc(ifc.ifc_len);
40     while (ifc.ifc_buf) {
41         if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
42             log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
43
44         /*
45          * If the buffer was large enough to hold all the addresses
46          * then break out, otherwise increase the buffer size and
47          * try again.
48          *
49          * The only way to know that we definitely had enough space
50          * is to know that there was enough space for at least one
51          * more struct ifreq. ???
52          */
53         if ((num_ifreq * sizeof(struct ifreq)) >=
54              ifc.ifc_len + sizeof(struct ifreq))
55              break;
56
57         num_ifreq *= 2;
58         ifc.ifc_len = num_ifreq * sizeof(struct ifreq);
59         ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len);
60     }
61     if (ifc.ifc_buf == NULL)
62         log(LOG_ERR, 0, "config_vifs_from_kernel: ran out of memory");
63
64     ifrp = (struct ifreq *)ifc.ifc_buf;
65     ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len);
66     /*
67      * Loop through all of the interfaces.
68      */
69     for (; ifrp < ifend; ifrp = (struct ifreq *)((char *)ifrp + n)) {
70         struct ifreq ifr;
71 #ifdef HAVE_SA_LEN
72         n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
73         if (n < sizeof(*ifrp))
74             n = sizeof(*ifrp);
75 #else
76         n = sizeof(*ifrp);
77 #endif
78         /*
79          * Ignore any interface for an address family other than IP.
80          */
81         if (ifrp->ifr_addr.sa_family != AF_INET)
82             continue;
83
84         addr = ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr;
85
86         /*
87          * Need a template to preserve address info that is
88          * used below to locate the next entry.  (Otherwise,
89          * SIOCGIFFLAGS stomps over it because the requests
90          * are returned in a union.)
91          */
92         bcopy(ifrp->ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
93
94         /*
95          * Ignore loopback interfaces and interfaces that do not support
96          * multicast.
97          */
98         if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
99             log(LOG_ERR, errno, "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
100         flags = ifr.ifr_flags;
101         if ((flags & (IFF_LOOPBACK|IFF_MULTICAST)) != IFF_MULTICAST) continue;
102
103         /*
104          * Ignore any interface whose address and mask do not define a
105          * valid subnet number, or whose address is of the form {subnet,0}
106          * or {subnet,-1}.
107          */
108         if (ioctl(udp_socket, SIOCGIFNETMASK, (char *)&ifr) < 0)
109             log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", ifr.ifr_name);
110         mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
111         subnet = addr & mask;
112         if (!inet_valid_subnet(subnet, mask) ||
113             addr == subnet ||
114             addr == (subnet | ~mask)) {
115             log(LOG_WARNING, 0,
116                 "ignoring %s, has invalid address (%s) and/or mask (%s)",
117                 ifr.ifr_name, inet_fmt(addr, s1), inet_fmt(mask, s2));
118             continue;
119         }
120
121         /*
122          * Ignore any interface that is connected to the same subnet as
123          * one already installed in the uvifs array.
124          */
125         for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
126             if (strcmp(v->uv_name, ifr.ifr_name) == 0) {
127                 log(LOG_DEBUG, 0, "skipping %s (%s on subnet %s) (alias for vif#%u?)",
128                         v->uv_name, inet_fmt(addr, s1),
129                         inet_fmts(subnet, mask, s2), vifi);
130                 break;
131             }
132             if ((addr & v->uv_subnetmask) == v->uv_subnet ||
133                 (v->uv_subnet & mask) == subnet) {
134                 log(LOG_WARNING, 0, "ignoring %s, same subnet as %s",
135                                         ifr.ifr_name, v->uv_name);
136                 break;
137             }
138         }
139         if (vifi != numvifs) continue;
140
141         /*
142          * If there is room in the uvifs array, install this interface.
143          */
144         if (numvifs == MAXVIFS) {
145             log(LOG_WARNING, 0, "too many vifs, ignoring %s", ifr.ifr_name);
146             continue;
147         }
148         v  = &uvifs[numvifs];
149         zero_vif(v, 0);
150         v->uv_lcl_addr    = addr;
151         v->uv_subnet      = subnet;
152         v->uv_subnetmask  = mask;
153         v->uv_subnetbcast = subnet | ~mask;
154         strncpy(v->uv_name, ifr.ifr_name, IFNAMSIZ);
155         v->uv_name[IFNAMSIZ-1] = '\0';
156
157         if (flags & IFF_POINTOPOINT)
158             v->uv_flags |= VIFF_REXMIT_PRUNES;
159
160         log(LOG_INFO,0,"installing %s (%s on subnet %s) as vif #%u - rate=%d",
161             v->uv_name, inet_fmt(addr, s1), inet_fmts(subnet, mask, s2),
162             numvifs, v->uv_rate_limit);
163
164         ++numvifs;
165
166         /*
167          * If the interface is not yet up, set the vifs_down flag to
168          * remind us to check again later.
169          */
170         if (!(flags & IFF_UP)) {
171             v->uv_flags |= VIFF_DOWN;
172             vifs_down = TRUE;
173         }
174     }
175 }