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