]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/daemon/netlink.c
b1ea76cbf327f096fb7985491b735143ef7128ff
[thirdparty/lldpd.git] / src / daemon / netlink.c
1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3 * Copyright (c) 2012 Vincent Bernat <bernat@luffy.cx>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 /* Grabbing interfaces information with netlink only. */
19
20 #include "lldpd.h"
21
22 #include <errno.h>
23 #include <sys/socket.h>
24 #include <netdb.h>
25 #include <net/if_arp.h>
26 #include <linux/netlink.h>
27 #include <linux/rtnetlink.h>
28
29 #define NETLINK_BUFFER 4096
30
31 struct netlink_req {
32 struct nlmsghdr hdr;
33 struct rtgenmsg gen;
34 };
35
36 struct lldpd_netlink {
37 int nl_socket;
38 /* Cache */
39 struct interfaces_device_list *devices;
40 struct interfaces_address_list *addresses;
41 };
42
43 /**
44 * Connect to netlink.
45 *
46 * Open a Netlink socket and connect to it.
47 *
48 * @param protocol Which protocol to use (eg NETLINK_ROUTE).
49 * @param groups Which groups we want to subscribe to
50 * @return The opened socket or -1 on error.
51 */
52 static int
53 netlink_connect(int protocol, unsigned groups)
54 {
55 int s;
56 struct sockaddr_nl local = {
57 .nl_family = AF_NETLINK,
58 .nl_pid = getpid(),
59 .nl_groups = groups
60 };
61
62 /* Open Netlink socket */
63 log_debug("netlink", "opening netlink socket");
64 s = socket(AF_NETLINK, SOCK_RAW, protocol);
65 if (s == -1) {
66 log_warn("netlink", "unable to open netlink socket");
67 return -1;
68 }
69 if (groups && bind(s, (struct sockaddr *)&local, sizeof(struct sockaddr_nl)) < 0) {
70 log_warn("netlink", "unable to bind netlink socket");
71 close(s);
72 return -1;
73 }
74 return s;
75 }
76
77 /**
78 * Send a netlink message.
79 *
80 * The type of the message can be chosen as well the route family. The
81 * mesage will always be NLM_F_REQUEST | NLM_F_DUMP.
82 *
83 * @param s the netlink socket
84 * @param type the request type (eg RTM_GETLINK)
85 * @param family the rt family (eg AF_PACKET)
86 * @return 0 on success, -1 otherwise
87 */
88 static int
89 netlink_send(int s, int type, int family, int seq)
90 {
91 struct netlink_req req = {
92 .hdr = {
93 .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
94 .nlmsg_type = type,
95 .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
96 .nlmsg_seq = seq,
97 .nlmsg_pid = getpid() },
98 .gen = { .rtgen_family = family }
99 };
100 struct iovec iov = {
101 .iov_base = &req,
102 .iov_len = req.hdr.nlmsg_len
103 };
104 struct sockaddr_nl peer = { .nl_family = AF_NETLINK };
105 struct msghdr rtnl_msg = {
106 .msg_iov = &iov,
107 .msg_iovlen = 1,
108 .msg_name = &peer,
109 .msg_namelen = sizeof(struct sockaddr_nl)
110 };
111
112 /* Send netlink message. This is synchronous but we are guaranteed
113 * to not block. */
114 log_debug("netlink", "sending netlink message");
115 if (sendmsg(s, (struct msghdr *)&rtnl_msg, 0) == -1) {
116 log_warn("netlink", "unable to send netlink message");
117 return -1;
118 }
119
120 return 0;
121 }
122
123 static void
124 netlink_parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
125 {
126 while (RTA_OK(rta, len)) {
127 if ((rta->rta_type <= max) && (!tb[rta->rta_type]))
128 tb[rta->rta_type] = rta;
129 rta = RTA_NEXT(rta,len);
130 }
131 }
132
133 /**
134 * Parse a `linkinfo` attributes.
135 *
136 * @param iff where to put the result
137 * @param rta linkinfo attribute
138 * @param len length of attributes
139 */
140 static void
141 netlink_parse_linkinfo(struct interfaces_device *iff, struct rtattr *rta, int len)
142 {
143 struct rtattr *link_info_attrs[IFLA_INFO_MAX+1] = {};
144 char *kind = NULL;
145
146 netlink_parse_rtattr(link_info_attrs, IFLA_INFO_MAX, rta, len);
147
148 if (link_info_attrs[IFLA_INFO_KIND]) {
149 kind = strdup(RTA_DATA(link_info_attrs[IFLA_INFO_KIND]));
150 if (kind) {
151 if (!strcmp(kind, "vlan")) {
152 log_debug("netlink", "interface %s is a VLAN",
153 iff->name);
154 iff->type |= IFACE_VLAN_T;
155 } else if (!strcmp(kind, "bridge")) {
156 log_debug("netlink", "interface %s is a bridge",
157 iff->name);
158 iff->type |= IFACE_BRIDGE_T;
159 } else if (!strcmp(kind, "bond")) {
160 log_debug("netlink", "interface %s is a bond",
161 iff->name);
162 iff->type |= IFACE_BOND_T;
163 }
164 }
165 }
166
167 if (kind && !strcmp(kind, "vlan") && link_info_attrs[IFLA_INFO_DATA]) {
168 struct rtattr *vlan_link_info_data_attrs[IFLA_VLAN_MAX+1] = {};
169 netlink_parse_rtattr(vlan_link_info_data_attrs, IFLA_VLAN_MAX,
170 RTA_DATA(link_info_attrs[IFLA_INFO_DATA]),
171 RTA_PAYLOAD(link_info_attrs[IFLA_INFO_DATA]));
172
173 if (vlan_link_info_data_attrs[IFLA_VLAN_ID]) {
174 iff->vlanid = *(uint16_t *)RTA_DATA(vlan_link_info_data_attrs[IFLA_VLAN_ID]);
175 log_debug("netlink", "VLAN ID for interface %s is %d",
176 iff->name, iff->vlanid);
177 }
178 }
179
180 free(kind);
181 }
182
183 /**
184 * Parse a `link` netlink message.
185 *
186 * @param msg message to be parsed
187 * @param iff where to put the result
188 * return 0 if the interface is worth it, -1 otherwise
189 */
190 static int
191 netlink_parse_link(struct nlmsghdr *msg,
192 struct interfaces_device *iff)
193 {
194 struct ifinfomsg *ifi;
195 struct rtattr *attribute;
196 int len;
197 ifi = NLMSG_DATA(msg);
198 len = msg->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
199
200 if (ifi->ifi_type != ARPHRD_ETHER) {
201 log_debug("netlink", "skip non Ethernet interface at index %d",
202 ifi->ifi_index);
203 return -1;
204 }
205
206 iff->index = ifi->ifi_index;
207 iff->flags = ifi->ifi_flags;
208 iff->lower_idx = -1;
209 iff->upper_idx = -1;
210
211 for (attribute = IFLA_RTA(ifi);
212 RTA_OK(attribute, len);
213 attribute = RTA_NEXT(attribute, len)) {
214 switch(attribute->rta_type) {
215 case IFLA_IFNAME:
216 /* Interface name */
217 iff->name = strdup(RTA_DATA(attribute));
218 break;
219 case IFLA_IFALIAS:
220 /* Interface alias */
221 iff->alias = strdup(RTA_DATA(attribute));
222 break;
223 case IFLA_ADDRESS:
224 /* Interface MAC address */
225 iff->address = malloc(RTA_PAYLOAD(attribute));
226 if (iff->address)
227 memcpy(iff->address, RTA_DATA(attribute), RTA_PAYLOAD(attribute));
228 break;
229 case IFLA_LINK:
230 /* Index of "lower" interface */
231 iff->lower_idx = *(int*)RTA_DATA(attribute);
232 log_debug("netlink", "attribute IFLA_LINK for %s: %d",
233 iff->name ? iff->name : "(unknown)", iff->lower_idx);
234 break;
235 case IFLA_LINK_NETNSID:
236 /* Is the lower interface into another namesapce? */
237 iff->lower_idx = -1;
238 log_debug("netlink", "attribute IFLA_LINK_NETNSID received for %s",
239 iff->name ? iff->name : "(unknown)");
240 break;
241 case IFLA_MASTER:
242 /* Index of master interface */
243 iff->upper_idx = *(int*)RTA_DATA(attribute);
244 break;
245 case IFLA_MTU:
246 /* Maximum Transmission Unit */
247 iff->mtu = *(int*)RTA_DATA(attribute);
248 break;
249 case IFLA_LINKINFO:
250 netlink_parse_linkinfo(iff, RTA_DATA(attribute), RTA_PAYLOAD(attribute));
251 break;
252 default:
253 log_debug("netlink", "unhandled link attribute type %d for iface %s",
254 attribute->rta_type, iff->name ? iff->name : "(unknown)");
255 break;
256 }
257 }
258 if (!iff->name || !iff->address) {
259 log_info("netlink", "interface %d does not have a name or an address, skip",
260 iff->index);
261 return -1;
262 }
263
264 log_debug("netlink", "parsed link %d (%s, flags: %d)",
265 iff->index, iff->name, iff->flags);
266 return 0;
267 }
268
269 /**
270 * Parse a `address` netlink message.
271 *
272 * @param msg message to be parsed
273 * @param ifa where to put the result
274 * return 0 if the address is worth it, -1 otherwise
275 */
276 static int
277 netlink_parse_address(struct nlmsghdr *msg,
278 struct interfaces_address *ifa)
279 {
280 struct ifaddrmsg *ifi;
281 struct rtattr *attribute;
282 int len;
283 ifi = NLMSG_DATA(msg);
284 len = msg->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg));
285
286 ifa->index = ifi->ifa_index;
287 ifa->flags = ifi->ifa_flags;
288 switch (ifi->ifa_family) {
289 case AF_INET:
290 case AF_INET6: break;
291 default:
292 log_debug("netlink", "got a non IP address on if %d (family: %d)",
293 ifa->index, ifi->ifa_family);
294 return -1;
295 }
296
297 for (attribute = IFA_RTA(ifi);
298 RTA_OK(attribute, len);
299 attribute = RTA_NEXT(attribute, len)) {
300 switch(attribute->rta_type) {
301 case IFA_ADDRESS:
302 /* Address */
303 if (ifi->ifa_family == AF_INET) {
304 struct sockaddr_in ip;
305 memset(&ip, 0, sizeof(struct sockaddr_in));
306 ip.sin_family = AF_INET;
307 memcpy(&ip.sin_addr, RTA_DATA(attribute),
308 sizeof(struct in_addr));
309 memcpy(&ifa->address, &ip, sizeof(struct sockaddr_in));
310 } else {
311 struct sockaddr_in6 ip6;
312 memset(&ip6, 0, sizeof(struct sockaddr_in6));
313 ip6.sin6_family = AF_INET6;
314 memcpy(&ip6.sin6_addr, RTA_DATA(attribute),
315 sizeof(struct in6_addr));
316 memcpy(&ifa->address, &ip6, sizeof(struct sockaddr_in6));
317 }
318 break;
319 default:
320 log_debug("netlink", "unhandled address attribute type %d for iface %d",
321 attribute->rta_type, ifa->index);
322 break;
323 }
324 }
325 if (ifa->address.ss_family == AF_UNSPEC) {
326 log_debug("netlink", "no IP for interface %d",
327 ifa->index);
328 return -1;
329 }
330 return 0;
331 }
332
333 /**
334 * Merge an old interface with a new one.
335 *
336 * Some properties may be absent in the new interface that should be copied over
337 * from the old one.
338 */
339 void
340 netlink_merge(struct interfaces_device *old, struct interfaces_device *new)
341 {
342 if (new->alias == NULL) {
343 new->alias = old->alias;
344 old->alias = NULL;
345 }
346 if (new->address == NULL) {
347 new->address = old->address;
348 old->address = NULL;
349 }
350 if (new->mtu == 0)
351 new->mtu = old->mtu;
352 if (new->type == 0)
353 new->type = old->type;
354 if (new->vlanid == 0)
355 new->vlanid = old->vlanid;
356
357 /* It's not possible for lower link to change */
358 new->lower_idx = old->lower_idx;
359 }
360
361 /**
362 * Receive netlink answer from the kernel.
363 *
364 * @param s the netlink socket
365 * @param ifs list to store interface list or NULL if we don't
366 * @param ifas list to store address list or NULL if we don't
367 * @return 0 on success, -1 on error
368 */
369 static int
370 netlink_recv(int s,
371 struct interfaces_device_list *ifs,
372 struct interfaces_address_list *ifas)
373 {
374 int end = 0, ret = 0;
375 int flags = MSG_PEEK | MSG_TRUNC;
376 struct iovec iov;
377 int link_update = 0;
378
379 struct interfaces_device *ifdold;
380 struct interfaces_device *ifdnew;
381 struct interfaces_address *ifaold;
382 struct interfaces_address *ifanew;
383 char addr[INET6_ADDRSTRLEN + 1];
384
385 iov.iov_len = NETLINK_BUFFER;
386 iov.iov_base = malloc(iov.iov_len);
387 if (!iov.iov_base) {
388 log_warn("netlink", "not enough memory");
389 return -1;
390 }
391
392 while (!end) {
393 ssize_t len;
394 struct nlmsghdr *msg;
395 struct sockaddr_nl peer = { .nl_family = AF_NETLINK };
396 struct msghdr rtnl_reply = {
397 .msg_iov = &iov,
398 .msg_iovlen = 1,
399 .msg_name = &peer,
400 .msg_namelen = sizeof(struct sockaddr_nl)
401 };
402
403 retry:
404 len = recvmsg(s, &rtnl_reply, flags);
405 if (len == -1) {
406 if (errno == EAGAIN || errno == EWOULDBLOCK) {
407 log_debug("netlink", "should have received something, but didn't");
408 ret = 0;
409 goto out;
410 }
411 log_warn("netlink", "unable to receive netlink answer");
412 ret = -1;
413 goto out;
414 }
415 if (!len) {
416 ret = 0;
417 goto out;
418 }
419
420 if (iov.iov_len < len || (rtnl_reply.msg_flags & MSG_TRUNC)) {
421 void *tmp;
422
423 /* Provided buffer is not large enough, enlarge it
424 * to size of len (which should be total length of the message)
425 * and try again. */
426 iov.iov_len = len;
427 tmp = realloc(iov.iov_base, iov.iov_len);
428 if (!tmp) {
429 log_warn("netlink", "not enough memory");
430 ret = -1;
431 goto out;
432 }
433 log_debug("netlink", "enlarge message size to %zu bytes", len);
434 iov.iov_base = tmp;
435 flags = 0;
436 goto retry;
437 }
438
439 if (flags != 0) {
440 /* Buffer is big enough, do the actual reading */
441 flags = 0;
442 goto retry;
443 }
444
445 for (msg = (struct nlmsghdr*)(void*)(iov.iov_base);
446 NLMSG_OK(msg, len);
447 msg = NLMSG_NEXT(msg, len)) {
448 if (!(msg->nlmsg_flags & NLM_F_MULTI))
449 end = 1;
450 switch (msg->nlmsg_type) {
451 case NLMSG_DONE:
452 log_debug("netlink", "received done message");
453 end = 1;
454 break;
455 case RTM_NEWLINK:
456 case RTM_DELLINK:
457 if (!ifs) break;
458 log_debug("netlink", "received link information");
459 ifdnew = calloc(1, sizeof(struct interfaces_device));
460 if (ifdnew == NULL) {
461 log_warn("netlink", "not enough memory for another interface, give up what we have");
462 goto end;
463 }
464 if (netlink_parse_link(msg, ifdnew) == 0) {
465 /* We need to find if we already have this interface */
466 TAILQ_FOREACH(ifdold, ifs, next) {
467 if (ifdold->index == ifdnew->index) break;
468 }
469 if (msg->nlmsg_type == RTM_NEWLINK) {
470 if (ifdold == NULL) {
471 log_debug("netlink", "interface %s is new",
472 ifdnew->name);
473 TAILQ_INSERT_TAIL(ifs, ifdnew, next);
474 } else {
475 log_debug("netlink", "interface %s/%s is updated",
476 ifdold->name, ifdnew->name);
477 netlink_merge(ifdold, ifdnew);
478 TAILQ_INSERT_AFTER(ifs, ifdold, ifdnew, next);
479 TAILQ_REMOVE(ifs, ifdold, next);
480 interfaces_free_device(ifdold);
481 }
482 } else {
483 if (ifdold == NULL) {
484 log_warnx("netlink",
485 "removal request for %s, but no knowledge of it",
486 ifdnew->name);
487 } else {
488 log_debug("netlink", "interface %s is to be removed",
489 ifdold->name);
490 TAILQ_REMOVE(ifs, ifdold, next);
491 interfaces_free_device(ifdold);
492 }
493 interfaces_free_device(ifdnew);
494 }
495 link_update = 1;
496 } else {
497 interfaces_free_device(ifdnew);
498 }
499 break;
500 case RTM_NEWADDR:
501 case RTM_DELADDR:
502 if (!ifas) break;
503 log_debug("netlink", "received address information");
504 ifanew = calloc(1, sizeof(struct interfaces_address));
505 if (ifanew == NULL) {
506 log_warn("netlink", "not enough memory for another address, give what we have");
507 goto end;
508 }
509 if (netlink_parse_address(msg, ifanew) == 0) {
510 TAILQ_FOREACH(ifaold, ifas, next) {
511 if ((ifaold->index == ifanew->index) &&
512 !memcmp(&ifaold->address, &ifanew->address,
513 sizeof(ifaold->address))) continue;
514 }
515 if (getnameinfo((struct sockaddr *)&ifanew->address,
516 sizeof(ifanew->address),
517 addr, sizeof(addr),
518 NULL, 0, NI_NUMERICHOST) != 0) {
519 strlcpy(addr, "(unknown)", sizeof(addr));
520 }
521
522 if (msg->nlmsg_type == RTM_NEWADDR) {
523 if (ifaold == NULL) {
524 log_debug("netlink", "new address %s%%%d",
525 addr, ifanew->index);
526 TAILQ_INSERT_TAIL(ifas, ifanew, next);
527 } else {
528 log_debug("netlink", "updated address %s%%%d",
529 addr, ifaold->index);
530 TAILQ_INSERT_AFTER(ifas, ifaold, ifanew, next);
531 TAILQ_REMOVE(ifas, ifaold, next);
532 interfaces_free_address(ifaold);
533 }
534 } else {
535 if (ifaold == NULL) {
536 log_info("netlink",
537 "removal request for address of %s%%%d, but no knowledge of it",
538 addr, ifanew->index);
539 } else {
540 log_debug("netlink", "address %s%%%d is to be removed",
541 addr, ifaold->index);
542 TAILQ_REMOVE(ifas, ifaold, next);
543 interfaces_free_address(ifaold);
544 }
545 interfaces_free_address(ifanew);
546 }
547 } else {
548 interfaces_free_address(ifanew);
549 }
550 break;
551 default:
552 log_debug("netlink",
553 "received unhandled message type %d (len: %d)",
554 msg->nlmsg_type, msg->nlmsg_len);
555 }
556 }
557 flags = MSG_PEEK | MSG_TRUNC;
558 }
559 end:
560 if (link_update) {
561 /* Fill out lower/upper */
562 struct interfaces_device *iface1, *iface2;
563 TAILQ_FOREACH(iface1, ifs, next) {
564 if (iface1->upper_idx != -1 && iface1->upper_idx != iface1->index) {
565 TAILQ_FOREACH(iface2, ifs, next) {
566 if (iface1->upper_idx == iface2->index) {
567 log_debug("netlink",
568 "upper interface for %s is %s",
569 iface1->name, iface2->name);
570 iface1->upper = iface2;
571 break;
572 }
573 }
574 if (iface2 == NULL)
575 iface1->upper = NULL;
576 } else {
577 iface1->upper = NULL;
578 }
579 if (iface1->lower_idx != -1 && iface1->lower_idx != iface1->index) {
580 TAILQ_FOREACH(iface2, ifs, next) {
581 if (iface1->lower_idx == iface2->index) {
582 /* Workaround a bug introduced
583 * in Linux 4.1: a pair of veth
584 * will be lower interface of
585 * each other. Do not modify
586 * index as if one of them is
587 * updated, we will loose the
588 * information about the
589 * loop. */
590 if (iface2->lower_idx == iface1->index) {
591 iface1->lower = NULL;
592 log_debug("netlink",
593 "link loop detected between %s and %s",
594 iface1->name, iface2->name);
595 } else {
596 log_debug("netlink",
597 "lower interface for %s is %s",
598 iface1->name, iface2->name);
599 iface1->lower = iface2;
600 }
601 break;
602 }
603 if (iface2 == NULL)
604 iface1->lower = NULL;
605 }
606 } else {
607 iface1->lower = NULL;
608 }
609 }
610 }
611
612 out:
613 free(iov.iov_base);
614 return ret;
615 }
616
617 static int
618 netlink_group_mask(int group)
619 {
620 return group ? (1 << (group - 1)) : 0;
621 }
622
623 /**
624 * Subscribe to link changes.
625 *
626 * @return The socket we should listen to for changes.
627 */
628 int
629 netlink_subscribe_changes()
630 {
631 unsigned int groups;
632
633 log_debug("netlink", "listening on interface changes");
634
635 groups = netlink_group_mask(RTNLGRP_LINK) |
636 netlink_group_mask(RTNLGRP_IPV4_IFADDR) |
637 netlink_group_mask(RTNLGRP_IPV6_IFADDR);
638
639 return netlink_connect(NETLINK_ROUTE, groups);
640 }
641
642 /**
643 * Receive changes from netlink */
644 static void
645 netlink_change_cb(struct lldpd *cfg)
646 {
647 if (cfg->g_netlink == NULL)
648 return;
649 netlink_recv(cfg->g_netlink->nl_socket,
650 cfg->g_netlink->devices,
651 cfg->g_netlink->addresses);
652 }
653
654 /**
655 * Initialize netlink subsystem.
656 *
657 * This can be called several times but will have effect only the first time.
658 *
659 * @return 0 on success, -1 otherwise
660 */
661 static int
662 netlink_initialize(struct lldpd *cfg)
663 {
664 if (cfg->g_netlink) return 0;
665
666 log_debug("netlink", "initialize netlink subsystem");
667 if ((cfg->g_netlink = calloc(sizeof(struct lldpd_netlink), 1)) == NULL) {
668 log_warn("netlink", "unable to allocate memory for netlink subsystem");
669 goto end;
670 }
671
672 /* Connect to netlink (by requesting to get notified on updates) and
673 * request updated information right now */
674 int s = cfg->g_netlink->nl_socket = netlink_subscribe_changes();
675
676 struct interfaces_address_list *ifaddrs = cfg->g_netlink->addresses =
677 malloc(sizeof(struct interfaces_address_list));
678 if (ifaddrs == NULL) {
679 log_warn("netlink", "not enough memory for address list");
680 goto end;
681 }
682 TAILQ_INIT(ifaddrs);
683
684 struct interfaces_device_list *ifs = cfg->g_netlink->devices =
685 malloc(sizeof(struct interfaces_device_list));
686 if (ifs == NULL) {
687 log_warn("netlink", "not enough memory for interface list");
688 goto end;
689 }
690 TAILQ_INIT(ifs);
691
692 if (netlink_send(s, RTM_GETADDR, AF_UNSPEC, 1) == -1)
693 goto end;
694 netlink_recv(s, NULL, ifaddrs);
695 if (netlink_send(s, RTM_GETLINK, AF_PACKET, 2) == -1)
696 goto end;
697 netlink_recv(s, ifs, NULL);
698
699 /* Listen to any future change */
700 cfg->g_iface_cb = netlink_change_cb;
701 if (levent_iface_subscribe(cfg, s) == -1) {
702 goto end;
703 }
704
705 return 0;
706 end:
707 netlink_cleanup(cfg);
708 return -1;
709 }
710
711 /**
712 * Cleanup netlink subsystem.
713 */
714 void
715 netlink_cleanup(struct lldpd *cfg)
716 {
717 if (cfg->g_netlink == NULL) return;
718 if (cfg->g_netlink->nl_socket != -1)
719 close(cfg->g_netlink->nl_socket);
720 interfaces_free_devices(cfg->g_netlink->devices);
721 interfaces_free_addresses(cfg->g_netlink->addresses);
722
723 free(cfg->g_netlink);
724 cfg->g_netlink = NULL;
725 }
726
727 /**
728 * Receive the list of interfaces.
729 *
730 * @return a list of interfaces.
731 */
732 struct interfaces_device_list*
733 netlink_get_interfaces(struct lldpd *cfg)
734 {
735 if (netlink_initialize(cfg) == -1) return NULL;
736 struct interfaces_device *ifd;
737 TAILQ_FOREACH(ifd, cfg->g_netlink->devices, next) {
738 ifd->ignore = 0;
739 }
740 return cfg->g_netlink->devices;
741 }
742
743 /**
744 * Receive the list of addresses.
745 *
746 * @return a list of addresses.
747 */
748 struct interfaces_address_list*
749 netlink_get_addresses(struct lldpd *cfg)
750 {
751 if (netlink_initialize(cfg) == -1) return NULL;
752 return cfg->g_netlink->addresses;
753 }