1*a376eb32SXin Li /* iftable - table of network interfaces
2*a376eb32SXin Li *
3*a376eb32SXin Li * (C) 2004 by Astaro AG, written by Harald Welte <[email protected]>
4*a376eb32SXin Li * (C) 2008 by Pablo Neira Ayuso <[email protected]>
5*a376eb32SXin Li *
6*a376eb32SXin Li * This software is Free Software and licensed under GNU GPLv2.
7*a376eb32SXin Li */
8*a376eb32SXin Li
9*a376eb32SXin Li /* IFINDEX handling */
10*a376eb32SXin Li
11*a376eb32SXin Li #include <unistd.h>
12*a376eb32SXin Li #include <stdlib.h>
13*a376eb32SXin Li #include <stdio.h>
14*a376eb32SXin Li #include <string.h>
15*a376eb32SXin Li #include <sys/types.h>
16*a376eb32SXin Li #include <netinet/in.h>
17*a376eb32SXin Li #include <arpa/inet.h>
18*a376eb32SXin Li #include <errno.h>
19*a376eb32SXin Li #include <assert.h>
20*a376eb32SXin Li
21*a376eb32SXin Li #include <linux/netdevice.h>
22*a376eb32SXin Li
23*a376eb32SXin Li #include <libnfnetlink/libnfnetlink.h>
24*a376eb32SXin Li #include "rtnl.h"
25*a376eb32SXin Li #include "linux_list.h"
26*a376eb32SXin Li
27*a376eb32SXin Li struct ifindex_node {
28*a376eb32SXin Li struct list_head head;
29*a376eb32SXin Li
30*a376eb32SXin Li u_int32_t index;
31*a376eb32SXin Li u_int32_t type;
32*a376eb32SXin Li u_int32_t alen;
33*a376eb32SXin Li u_int32_t flags;
34*a376eb32SXin Li char addr[8];
35*a376eb32SXin Li char name[16];
36*a376eb32SXin Li };
37*a376eb32SXin Li
38*a376eb32SXin Li struct nlif_handle {
39*a376eb32SXin Li struct list_head ifindex_hash[16];
40*a376eb32SXin Li struct rtnl_handle *rtnl_handle;
41*a376eb32SXin Li struct rtnl_handler ifadd_handler;
42*a376eb32SXin Li struct rtnl_handler ifdel_handler;
43*a376eb32SXin Li };
44*a376eb32SXin Li
45*a376eb32SXin Li /* iftable_add - Add/Update an entry to/in the interface table
46*a376eb32SXin Li * @n: netlink message header of a RTM_NEWLINK message
47*a376eb32SXin Li * @arg: not used
48*a376eb32SXin Li *
49*a376eb32SXin Li * This function adds/updates an entry in the intrface table.
50*a376eb32SXin Li * Returns -1 on error, 1 on success.
51*a376eb32SXin Li */
iftable_add(struct nlmsghdr * n,void * arg)52*a376eb32SXin Li static int iftable_add(struct nlmsghdr *n, void *arg)
53*a376eb32SXin Li {
54*a376eb32SXin Li unsigned int hash, found = 0;
55*a376eb32SXin Li struct ifinfomsg *ifi_msg = NLMSG_DATA(n);
56*a376eb32SXin Li struct ifindex_node *this;
57*a376eb32SXin Li struct rtattr *cb[IFLA_MAX+1];
58*a376eb32SXin Li struct nlif_handle *h = arg;
59*a376eb32SXin Li
60*a376eb32SXin Li if (n->nlmsg_type != RTM_NEWLINK)
61*a376eb32SXin Li return -1;
62*a376eb32SXin Li
63*a376eb32SXin Li if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi_msg)))
64*a376eb32SXin Li return -1;
65*a376eb32SXin Li
66*a376eb32SXin Li rtnl_parse_rtattr(cb, IFLA_MAX, IFLA_RTA(ifi_msg), IFLA_PAYLOAD(n));
67*a376eb32SXin Li
68*a376eb32SXin Li if (!cb[IFLA_IFNAME])
69*a376eb32SXin Li return -1;
70*a376eb32SXin Li
71*a376eb32SXin Li hash = ifi_msg->ifi_index & 0xF;
72*a376eb32SXin Li list_for_each_entry(this, &h->ifindex_hash[hash], head) {
73*a376eb32SXin Li if (this->index == ifi_msg->ifi_index) {
74*a376eb32SXin Li found = 1;
75*a376eb32SXin Li break;
76*a376eb32SXin Li }
77*a376eb32SXin Li }
78*a376eb32SXin Li
79*a376eb32SXin Li if (!found) {
80*a376eb32SXin Li this = malloc(sizeof(*this));
81*a376eb32SXin Li if (!this)
82*a376eb32SXin Li return -1;
83*a376eb32SXin Li
84*a376eb32SXin Li this->index = ifi_msg->ifi_index;
85*a376eb32SXin Li }
86*a376eb32SXin Li
87*a376eb32SXin Li this->type = ifi_msg->ifi_type;
88*a376eb32SXin Li this->flags = ifi_msg->ifi_flags;
89*a376eb32SXin Li if (cb[IFLA_ADDRESS]) {
90*a376eb32SXin Li unsigned int alen;
91*a376eb32SXin Li this->alen = alen = RTA_PAYLOAD(cb[IFLA_ADDRESS]);
92*a376eb32SXin Li if (alen > sizeof(this->addr))
93*a376eb32SXin Li alen = sizeof(this->addr);
94*a376eb32SXin Li memcpy(this->addr, RTA_DATA(cb[IFLA_ADDRESS]), alen);
95*a376eb32SXin Li } else {
96*a376eb32SXin Li this->alen = 0;
97*a376eb32SXin Li memset(this->addr, 0, sizeof(this->addr));
98*a376eb32SXin Li }
99*a376eb32SXin Li strcpy(this->name, RTA_DATA(cb[IFLA_IFNAME]));
100*a376eb32SXin Li
101*a376eb32SXin Li if (!found)
102*a376eb32SXin Li list_add(&this->head, &h->ifindex_hash[hash]);
103*a376eb32SXin Li
104*a376eb32SXin Li return 1;
105*a376eb32SXin Li }
106*a376eb32SXin Li
107*a376eb32SXin Li /* iftable_del - Delete an entry from the interface table
108*a376eb32SXin Li * @n: netlink message header of a RTM_DELLINK nlmsg
109*a376eb32SXin Li * @arg: not used
110*a376eb32SXin Li *
111*a376eb32SXin Li * Delete an entry from the interface table.
112*a376eb32SXin Li * Returns -1 on error, 0 if no matching entry was found or 1 on success.
113*a376eb32SXin Li */
iftable_del(struct nlmsghdr * n,void * arg)114*a376eb32SXin Li static int iftable_del(struct nlmsghdr *n, void *arg)
115*a376eb32SXin Li {
116*a376eb32SXin Li struct ifinfomsg *ifi_msg = NLMSG_DATA(n);
117*a376eb32SXin Li struct rtattr *cb[IFLA_MAX+1];
118*a376eb32SXin Li struct nlif_handle *h = arg;
119*a376eb32SXin Li struct ifindex_node *this, *tmp;
120*a376eb32SXin Li unsigned int hash;
121*a376eb32SXin Li
122*a376eb32SXin Li if (n->nlmsg_type != RTM_DELLINK)
123*a376eb32SXin Li return -1;
124*a376eb32SXin Li
125*a376eb32SXin Li if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi_msg)))
126*a376eb32SXin Li return -1;
127*a376eb32SXin Li
128*a376eb32SXin Li rtnl_parse_rtattr(cb, IFLA_MAX, IFLA_RTA(ifi_msg), IFLA_PAYLOAD(n));
129*a376eb32SXin Li
130*a376eb32SXin Li hash = ifi_msg->ifi_index & 0xF;
131*a376eb32SXin Li list_for_each_entry_safe(this, tmp, &h->ifindex_hash[hash], head) {
132*a376eb32SXin Li if (this->index == ifi_msg->ifi_index) {
133*a376eb32SXin Li list_del(&this->head);
134*a376eb32SXin Li free(this);
135*a376eb32SXin Li return 1;
136*a376eb32SXin Li }
137*a376eb32SXin Li }
138*a376eb32SXin Li
139*a376eb32SXin Li return 0;
140*a376eb32SXin Li }
141*a376eb32SXin Li
142*a376eb32SXin Li /** Get the name for an ifindex
143*a376eb32SXin Li *
144*a376eb32SXin Li * \param nlif_handle A pointer to a ::nlif_handle created
145*a376eb32SXin Li * \param index ifindex to be resolved
146*a376eb32SXin Li * \param name interface name, pass a buffer of IFNAMSIZ size
147*a376eb32SXin Li * \return -1 on error, 1 on success
148*a376eb32SXin Li */
nlif_index2name(struct nlif_handle * h,unsigned int index,char * name)149*a376eb32SXin Li int nlif_index2name(struct nlif_handle *h,
150*a376eb32SXin Li unsigned int index,
151*a376eb32SXin Li char *name)
152*a376eb32SXin Li {
153*a376eb32SXin Li unsigned int hash;
154*a376eb32SXin Li struct ifindex_node *this;
155*a376eb32SXin Li
156*a376eb32SXin Li assert(h != NULL);
157*a376eb32SXin Li assert(name != NULL);
158*a376eb32SXin Li
159*a376eb32SXin Li if (index == 0) {
160*a376eb32SXin Li strcpy(name, "*");
161*a376eb32SXin Li return 1;
162*a376eb32SXin Li }
163*a376eb32SXin Li
164*a376eb32SXin Li hash = index & 0xF;
165*a376eb32SXin Li list_for_each_entry(this, &h->ifindex_hash[hash], head) {
166*a376eb32SXin Li if (this->index == index) {
167*a376eb32SXin Li strcpy(name, this->name);
168*a376eb32SXin Li return 1;
169*a376eb32SXin Li }
170*a376eb32SXin Li }
171*a376eb32SXin Li
172*a376eb32SXin Li errno = ENOENT;
173*a376eb32SXin Li return -1;
174*a376eb32SXin Li }
175*a376eb32SXin Li
176*a376eb32SXin Li /** Get the flags for an ifindex
177*a376eb32SXin Li *
178*a376eb32SXin Li * \param nlif_handle A pointer to a ::nlif_handle created
179*a376eb32SXin Li * \param index ifindex to be resolved
180*a376eb32SXin Li * \param flags pointer to variable used to store the interface flags
181*a376eb32SXin Li * \return -1 on error, 1 on success
182*a376eb32SXin Li */
nlif_get_ifflags(const struct nlif_handle * h,unsigned int index,unsigned int * flags)183*a376eb32SXin Li int nlif_get_ifflags(const struct nlif_handle *h,
184*a376eb32SXin Li unsigned int index,
185*a376eb32SXin Li unsigned int *flags)
186*a376eb32SXin Li {
187*a376eb32SXin Li unsigned int hash;
188*a376eb32SXin Li struct ifindex_node *this;
189*a376eb32SXin Li
190*a376eb32SXin Li assert(h != NULL);
191*a376eb32SXin Li assert(flags != NULL);
192*a376eb32SXin Li
193*a376eb32SXin Li if (index == 0) {
194*a376eb32SXin Li errno = ENOENT;
195*a376eb32SXin Li return -1;
196*a376eb32SXin Li }
197*a376eb32SXin Li
198*a376eb32SXin Li hash = index & 0xF;
199*a376eb32SXin Li list_for_each_entry(this, &h->ifindex_hash[hash], head) {
200*a376eb32SXin Li if (this->index == index) {
201*a376eb32SXin Li *flags = this->flags;
202*a376eb32SXin Li return 1;
203*a376eb32SXin Li }
204*a376eb32SXin Li }
205*a376eb32SXin Li errno = ENOENT;
206*a376eb32SXin Li return -1;
207*a376eb32SXin Li }
208*a376eb32SXin Li
209*a376eb32SXin Li /** Initialize interface table
210*a376eb32SXin Li *
211*a376eb32SXin Li * Initialize rtnl interface and interface table
212*a376eb32SXin Li * Call this before any nlif_* function
213*a376eb32SXin Li *
214*a376eb32SXin Li * \return file descriptor to netlink socket
215*a376eb32SXin Li */
nlif_open(void)216*a376eb32SXin Li struct nlif_handle *nlif_open(void)
217*a376eb32SXin Li {
218*a376eb32SXin Li int i;
219*a376eb32SXin Li struct nlif_handle *h;
220*a376eb32SXin Li
221*a376eb32SXin Li h = calloc(1, sizeof(struct nlif_handle));
222*a376eb32SXin Li if (h == NULL)
223*a376eb32SXin Li goto err;
224*a376eb32SXin Li
225*a376eb32SXin Li for (i=0; i<16; i++)
226*a376eb32SXin Li INIT_LIST_HEAD(&h->ifindex_hash[i]);
227*a376eb32SXin Li
228*a376eb32SXin Li h->ifadd_handler.nlmsg_type = RTM_NEWLINK;
229*a376eb32SXin Li h->ifadd_handler.handlefn = iftable_add;
230*a376eb32SXin Li h->ifadd_handler.arg = h;
231*a376eb32SXin Li h->ifdel_handler.nlmsg_type = RTM_DELLINK;
232*a376eb32SXin Li h->ifdel_handler.handlefn = iftable_del;
233*a376eb32SXin Li h->ifdel_handler.arg = h;
234*a376eb32SXin Li
235*a376eb32SXin Li h->rtnl_handle = rtnl_open();
236*a376eb32SXin Li if (h->rtnl_handle == NULL)
237*a376eb32SXin Li goto err;
238*a376eb32SXin Li
239*a376eb32SXin Li if (rtnl_handler_register(h->rtnl_handle, &h->ifadd_handler) < 0)
240*a376eb32SXin Li goto err_close;
241*a376eb32SXin Li
242*a376eb32SXin Li if (rtnl_handler_register(h->rtnl_handle, &h->ifdel_handler) < 0)
243*a376eb32SXin Li goto err_unregister;
244*a376eb32SXin Li
245*a376eb32SXin Li return h;
246*a376eb32SXin Li
247*a376eb32SXin Li err_unregister:
248*a376eb32SXin Li rtnl_handler_unregister(h->rtnl_handle, &h->ifadd_handler);
249*a376eb32SXin Li err_close:
250*a376eb32SXin Li rtnl_close(h->rtnl_handle);
251*a376eb32SXin Li free(h);
252*a376eb32SXin Li err:
253*a376eb32SXin Li return NULL;
254*a376eb32SXin Li }
255*a376eb32SXin Li
256*a376eb32SXin Li /** Destructor of interface table
257*a376eb32SXin Li *
258*a376eb32SXin Li * \param nlif_handle A pointer to a ::nlif_handle created
259*a376eb32SXin Li * via nlif_open()
260*a376eb32SXin Li */
nlif_close(struct nlif_handle * h)261*a376eb32SXin Li void nlif_close(struct nlif_handle *h)
262*a376eb32SXin Li {
263*a376eb32SXin Li int i;
264*a376eb32SXin Li struct ifindex_node *this, *tmp;
265*a376eb32SXin Li
266*a376eb32SXin Li assert(h != NULL);
267*a376eb32SXin Li
268*a376eb32SXin Li rtnl_handler_unregister(h->rtnl_handle, &h->ifadd_handler);
269*a376eb32SXin Li rtnl_handler_unregister(h->rtnl_handle, &h->ifdel_handler);
270*a376eb32SXin Li rtnl_close(h->rtnl_handle);
271*a376eb32SXin Li
272*a376eb32SXin Li for (i=0; i<16; i++) {
273*a376eb32SXin Li list_for_each_entry_safe(this, tmp, &h->ifindex_hash[i], head) {
274*a376eb32SXin Li list_del(&this->head);
275*a376eb32SXin Li free(this);
276*a376eb32SXin Li }
277*a376eb32SXin Li }
278*a376eb32SXin Li
279*a376eb32SXin Li free(h);
280*a376eb32SXin Li h = NULL; /* bugtrap */
281*a376eb32SXin Li }
282*a376eb32SXin Li
283*a376eb32SXin Li /** Receive message from netlink and update interface table
284*a376eb32SXin Li *
285*a376eb32SXin Li * \param nlif_handle A pointer to a ::nlif_handle created
286*a376eb32SXin Li * \return 0 if OK
287*a376eb32SXin Li */
nlif_catch(struct nlif_handle * h)288*a376eb32SXin Li int nlif_catch(struct nlif_handle *h)
289*a376eb32SXin Li {
290*a376eb32SXin Li assert(h != NULL);
291*a376eb32SXin Li
292*a376eb32SXin Li if (h->rtnl_handle)
293*a376eb32SXin Li return rtnl_receive(h->rtnl_handle);
294*a376eb32SXin Li
295*a376eb32SXin Li return -1;
296*a376eb32SXin Li }
297*a376eb32SXin Li
nlif_catch_multi(struct nlif_handle * h)298*a376eb32SXin Li static int nlif_catch_multi(struct nlif_handle *h)
299*a376eb32SXin Li {
300*a376eb32SXin Li assert(h != NULL);
301*a376eb32SXin Li
302*a376eb32SXin Li if (h->rtnl_handle)
303*a376eb32SXin Li return rtnl_receive_multi(h->rtnl_handle);
304*a376eb32SXin Li
305*a376eb32SXin Li return -1;
306*a376eb32SXin Li }
307*a376eb32SXin Li
308*a376eb32SXin Li /**
309*a376eb32SXin Li * nlif_query - request a dump of interfaces available in the system
310*a376eb32SXin Li * @h: pointer to a valid nlif_handler
311*a376eb32SXin Li */
nlif_query(struct nlif_handle * h)312*a376eb32SXin Li int nlif_query(struct nlif_handle *h)
313*a376eb32SXin Li {
314*a376eb32SXin Li assert(h != NULL);
315*a376eb32SXin Li
316*a376eb32SXin Li if (rtnl_dump_type(h->rtnl_handle, RTM_GETLINK) < 0)
317*a376eb32SXin Li return -1;
318*a376eb32SXin Li
319*a376eb32SXin Li return nlif_catch_multi(h);
320*a376eb32SXin Li }
321*a376eb32SXin Li
322*a376eb32SXin Li /** Returns socket descriptor for the netlink socket
323*a376eb32SXin Li *
324*a376eb32SXin Li * \param nlif_handle A pointer to a ::nlif_handle created
325*a376eb32SXin Li * \return The fd or -1 if there's an error
326*a376eb32SXin Li */
nlif_fd(struct nlif_handle * h)327*a376eb32SXin Li int nlif_fd(struct nlif_handle *h)
328*a376eb32SXin Li {
329*a376eb32SXin Li assert(h != NULL);
330*a376eb32SXin Li
331*a376eb32SXin Li if (h->rtnl_handle)
332*a376eb32SXin Li return h->rtnl_handle->rtnl_fd;
333*a376eb32SXin Li
334*a376eb32SXin Li return -1;
335*a376eb32SXin Li }
336