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