1 /* Physical and virtual interface API
2 *
3 * Copyright (C) 2001-2005 Carsten Schill <carsten@cschill.de>
4 * Copyright (C) 2006-2009 Julien BLACHE <jb@jblache.org>
5 * Copyright (C) 2009 Todd Hayton <todd.hayton@gmail.com>
6 * Copyright (C) 2009-2011 Micha Lenk <micha@debian.org>
7 * Copyright (C) 2011-2013 Joachim Nilsson <troglobit@gmail.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <netinet/in.h>
27 #include <ifaddrs.h>
28 #include "mclab.h"
29
30 static unsigned int num_ifaces = 0;
31 static struct iface *iface_list = NULL;
32
33 /**
34 * iface_init - Setup vector of active interfaces
35 *
36 * Builds up a vector with active system interfaces. Must be called
37 * before any other interface functions in this module!
38 */
iface_init(void)39 void iface_init(void)
40 {
41 int family;
42 struct iface *iface;
43 struct ifaddrs *ifaddr, *ifa;
44
45 num_ifaces = 0;
46
47 if (iface_list)
48 free(iface_list);
49
50 iface_list = calloc(MAX_IF, sizeof(struct iface));
51 if (!iface_list) {
52 smclog(LOG_ERR, "Failed allocating space for interfaces: %m");
53 exit(255);
54 }
55
56 if (getifaddrs(&ifaddr) == -1) {
57 smclog(LOG_ERR, "Failed retrieving interface addresses: %m");
58 exit(255);
59 }
60
61 for (ifa = ifaddr; ifa && num_ifaces < MAX_IF; ifa = ifa->ifa_next) {
62 /* Check if already added? */
63 if (iface_find_by_name(ifa->ifa_name))
64 continue;
65
66 /* Copy data from interface iterator 'ifa' */
67 iface = &iface_list[num_ifaces++];
68 strncpy(iface->name, ifa->ifa_name, IFNAMSIZ);
69 iface->name[IFNAMSIZ] = 0;
70
71 /*
72 * Only copy interface address if inteface has one. On
73 * Linux we can enumerate VIFs using ifindex, useful for
74 * DHCP interfaces w/o any address yet. Other UNIX
75 * systems will fail on the MRT_ADD_VIF ioctl. if the
76 * kernel cannot find a matching interface.
77 */
78 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET)
79 iface->inaddr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
80 iface->flags = ifa->ifa_flags;
81 iface->ifindex = if_nametoindex(iface->name);
82 iface->vif = -1;
83 iface->mif = -1;
84 iface->threshold = DEFAULT_THRESHOLD;
85 }
86 freeifaddrs(ifaddr);
87 }
88
89 /**
90 * iface_find_by_name - Find an interface by name
91 * @ifname: Interface name
92 *
93 * Returns:
94 * Pointer to a @struct iface of the matching interface, or %NULL if no
95 * interface exists, or is up. If more than one interface exists, chose
96 * the interface that corresponds to a virtual interface.
97 */
iface_find_by_name(const char * ifname)98 struct iface *iface_find_by_name(const char *ifname)
99 {
100 unsigned int i;
101 struct iface *iface;
102 struct iface *candidate = NULL;
103
104 if (!ifname)
105 return NULL;
106
107 for (i = 0; i < num_ifaces; i++) {
108 iface = &iface_list[i];
109 if (!strcmp(ifname, iface->name)) {
110 if (iface->vif >= 0)
111 return iface;
112 candidate = iface;
113 }
114 }
115
116 return candidate;
117 }
118
119 /**
120 * iface_find_by_vif - Find by virtual interface index
121 * @vif: Virtual multicast interface index
122 *
123 * Returns:
124 * Pointer to a @struct iface of the requested interface, or %NULL if no
125 * interface matching @vif exists.
126 */
iface_find_by_vif(int vif)127 struct iface *iface_find_by_vif(int vif)
128 {
129 size_t i;
130
131 for (i = 0; i < num_ifaces; i++) {
132 struct iface *iface = &iface_list[i];
133
134 if (iface->vif >= 0 && iface->vif == vif)
135 return iface;
136 }
137
138 return NULL;
139 }
140
141 /**
142 * iface_find_by_index - Find by kernel interface index
143 * @ifindex: Kernel interface index
144 *
145 * Returns:
146 * Pointer to a @struct iface of the requested interface, or %NULL if no
147 * interface @ifindex exists.
148 */
iface_find_by_index(unsigned int ifindex)149 struct iface *iface_find_by_index(unsigned int ifindex)
150 {
151 if (ifindex >= num_ifaces)
152 return NULL;
153
154 return &iface_list[ifindex];
155 }
156
157
158 /**
159 * iface_get_vif - Get virtual interface index for an interface (IPv4)
160 * @iface: Pointer to a @struct iface interface
161 *
162 * Returns:
163 * The virtual interface index if the interface is known and registered
164 * with the kernel, or -1 if no virtual interface exists.
165 */
iface_get_vif(struct iface * iface)166 int iface_get_vif(struct iface *iface)
167 {
168 if (!iface)
169 return -1;
170
171 return iface->vif;
172 }
173
174 /**
175 * iface_get_mif - Get virtual interface index for an interface (IPv6)
176 * @iface: Pointer to a @struct iface interface
177 *
178 * Returns:
179 * The virtual interface index if the interface is known and registered
180 * with the kernel, or -1 if no virtual interface exists.
181 */
iface_get_mif(struct iface * iface)182 int iface_get_mif(struct iface *iface __attribute__ ((unused)))
183 {
184 #ifndef HAVE_IPV6_MULTICAST_ROUTING
185 return -1;
186 #else
187 if (!iface)
188 return -1;
189
190 return iface->mif;
191 #endif /* HAVE_IPV6_MULTICAST_ROUTING */
192 }
193
194 /**
195 * iface_get_vif_by_name - Get virtual interface index by interface name (IPv4)
196 * @ifname: Interface name
197 *
198 * Returns:
199 * The virtual interface index if the interface is known and registered
200 * with the kernel, or -1 if no virtual interface by that name is found.
201 */
iface_get_vif_by_name(const char * ifname)202 int iface_get_vif_by_name(const char *ifname)
203 {
204 int vif;
205 struct iface *iface;
206
207 iface = iface_find_by_name(ifname);
208 if (!iface)
209 return -1;
210
211 vif = iface_get_vif(iface);
212 if (vif < 0)
213 return -1;
214
215 return vif;
216 }
217
218 /**
219 * iface_get_mif_by_name - Get virtual interface index by interface name (IPv6)
220 * @ifname: Interface name
221 *
222 * Returns:
223 * The virtual interface index if the interface is known and registered
224 * with the kernel, or -1 if no virtual interface by that name is found.
225 */
iface_get_mif_by_name(const char * ifname)226 int iface_get_mif_by_name(const char *ifname)
227 {
228 int vif;
229 struct iface *iface;
230
231 iface = iface_find_by_name(ifname);
232 if (!iface)
233 return -1;
234
235 vif = iface_get_mif(iface);
236 if (vif < 0)
237 return -1;
238
239 return vif;
240 }
241
242 /**
243 * Local Variables:
244 * version-control: t
245 * indent-tabs-mode: t
246 * c-file-style: "linux"
247 * End:
248 */
249