]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/daemon/netlink.c
lldpd: fix change detection
[thirdparty/lldpd.git] / src / daemon / netlink.c
CommitLineData
e12c2365
VB
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
adbb6e54
VB
18/* Grabbing interfaces information with netlink only. */
19
e12c2365
VB
20#include "lldpd.h"
21
0fa2254b 22#include <errno.h>
e12c2365 23#include <sys/socket.h>
0fa2254b 24#include <netdb.h>
13181ede 25#include <net/if_arp.h>
0fa2254b
VB
26#include <linux/netlink.h>
27#include <linux/rtnetlink.h>
28
29#define NETLINK_BUFFER 4096
02c91f0a 30
0fa2254b
VB
31struct netlink_req {
32 struct nlmsghdr hdr;
33 struct rtgenmsg gen;
34};
13181ede
VB
35
36struct lldpd_netlink {
0fa2254b
VB
37 int nl_socket;
38 /* Cache */
39 struct interfaces_device_list *devices;
40 struct interfaces_address_list *addresses;
e12c2365
VB
41};
42
43/**
0fa2254b
VB
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.
e12c2365 51 */
0fa2254b
VB
52static int
53netlink_connect(int protocol, unsigned groups)
e12c2365 54{
0fa2254b
VB
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;
13181ede 68 }
0fa2254b
VB
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;
e12c2365
VB
75}
76
77/**
0fa2254b 78 * Send a netlink message.
e12c2365 79 *
0fa2254b
VB
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.
e12c2365 82 *
0fa2254b
VB
83 * @param s the netlink socket
84 * @param type the request type (eg RTM_GETLINK)
85 * @param family the rt family (eg AF_PACKET)
e12c2365
VB
86 * @return 0 on success, -1 otherwise
87 */
88static int
0fa2254b 89netlink_send(int s, int type, int family, int seq)
e12c2365 90{
0fa2254b
VB
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;
16eacc5b
VB
118 }
119
0fa2254b
VB
120 return 0;
121}
16eacc5b 122
0fa2254b
VB
123static void
124netlink_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);
16eacc5b 130 }
16eacc5b
VB
131}
132
e12c2365 133/**
0fa2254b
VB
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
e12c2365 139 */
0fa2254b
VB
140static void
141netlink_parse_linkinfo(struct interfaces_device *iff, struct rtattr *rta, int len)
e12c2365 142{
0fa2254b
VB
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 }
13181ede 166
0fa2254b
VB
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);
e12c2365
VB
181}
182
183/**
13181ede 184 * Parse a `link` netlink message.
e12c2365 185 *
0fa2254b
VB
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
e12c2365 189 */
0fa2254b
VB
190static int
191netlink_parse_link(struct nlmsghdr *msg,
192 struct interfaces_device *iff)
e12c2365 193{
0fa2254b
VB
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;
13181ede
VB
204 }
205
0fa2254b
VB
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 break;
233 case IFLA_MASTER:
234 /* Index of master interface */
235 iff->upper_idx = *(int*)RTA_DATA(attribute);
236 break;
237 case IFLA_TXQLEN:
238 /* Transmit queue length */
239 iff->txqueue = *(int*)RTA_DATA(attribute);
240 break;
241 case IFLA_MTU:
242 /* Maximum Transmission Unit */
243 iff->mtu = *(int*)RTA_DATA(attribute);
244 break;
245 case IFLA_LINKINFO:
246 netlink_parse_linkinfo(iff, RTA_DATA(attribute), RTA_PAYLOAD(attribute));
247 break;
248 default:
249 log_debug("netlink", "unhandled link attribute type %d for iface %s",
250 attribute->rta_type, iff->name ? iff->name : "(unknown)");
251 break;
252 }
13181ede 253 }
0fa2254b
VB
254 if (!iff->name || !iff->address) {
255 log_info("netlink", "interface %d does not have a name or an address, skip",
13181ede 256 iff->index);
0fa2254b 257 return -1;
13181ede
VB
258 }
259
0fa2254b
VB
260 log_debug("netlink", "parsed link %d (%s, flags: %d)",
261 iff->index, iff->name, iff->flags);
262 return 0;
e12c2365
VB
263}
264
265/**
13181ede 266 * Parse a `address` netlink message.
e12c2365 267 *
0fa2254b
VB
268 * @param msg message to be parsed
269 * @param ifa where to put the result
270 * return 0 if the address is worth it, -1 otherwise
e12c2365 271 */
0fa2254b
VB
272static int
273netlink_parse_address(struct nlmsghdr *msg,
274 struct interfaces_address *ifa)
e12c2365 275{
0fa2254b
VB
276 struct ifaddrmsg *ifi;
277 struct rtattr *attribute;
278 int len;
279 ifi = NLMSG_DATA(msg);
280 len = msg->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg));
281
282 ifa->index = ifi->ifa_index;
283 ifa->flags = ifi->ifa_flags;
284 switch (ifi->ifa_family) {
13181ede
VB
285 case AF_INET:
286 case AF_INET6: break;
287 default:
288 log_debug("netlink", "got a non IP address on if %d (family: %d)",
0fa2254b
VB
289 ifa->index, ifi->ifa_family);
290 return -1;
13181ede
VB
291 }
292
0fa2254b
VB
293 for (attribute = IFA_RTA(ifi);
294 RTA_OK(attribute, len);
295 attribute = RTA_NEXT(attribute, len)) {
296 switch(attribute->rta_type) {
297 case IFA_ADDRESS:
298 /* Address */
299 if (ifi->ifa_family == AF_INET) {
300 struct sockaddr_in ip;
301 memset(&ip, 0, sizeof(struct sockaddr_in));
302 ip.sin_family = AF_INET;
303 memcpy(&ip.sin_addr, RTA_DATA(attribute),
304 sizeof(struct in_addr));
305 memcpy(&ifa->address, &ip, sizeof(struct sockaddr_in));
306 } else {
307 struct sockaddr_in6 ip6;
308 memset(&ip6, 0, sizeof(struct sockaddr_in6));
309 ip6.sin6_family = AF_INET6;
310 memcpy(&ip6.sin6_addr, RTA_DATA(attribute),
311 sizeof(struct in6_addr));
312 memcpy(&ifa->address, &ip6, sizeof(struct sockaddr_in6));
313 }
314 break;
315 default:
316 log_debug("netlink", "unhandled address attribute type %d for iface %d",
317 attribute->rta_type, ifa->index);
318 break;
319 }
13181ede 320 }
0fa2254b 321 if (ifa->address.ss_family == AF_UNSPEC) {
13181ede
VB
322 log_debug("netlink", "no IP for interface %d",
323 ifa->index);
0fa2254b 324 return -1;
13181ede 325 }
0fa2254b 326 return 0;
e12c2365
VB
327}
328
329/**
0fa2254b 330 * Receive netlink answer from the kernel.
e12c2365 331 *
0fa2254b
VB
332 * @param s the netlink socket
333 * @param ifs list to store interface list or NULL if we don't
334 * @param ifas list to store address list or NULL if we don't
335 * @return 0 on success, -1 on error
e12c2365 336 */
0fa2254b
VB
337static int
338netlink_recv(int s,
339 struct interfaces_device_list *ifs,
340 struct interfaces_address_list *ifas)
e12c2365 341{
0fa2254b
VB
342 char reply[NETLINK_BUFFER] __attribute__ ((aligned));
343 int end = 0;
344 int link_update = 0;
345
346 struct interfaces_device *ifdold;
347 struct interfaces_device *ifdnew;
348 struct interfaces_address *ifaold;
349 struct interfaces_address *ifanew;
350 char addr[INET6_ADDRSTRLEN + 1];
351
352 while (!end) {
353 ssize_t len;
354 struct nlmsghdr *msg;
355 struct iovec iov = {
356 .iov_base = reply,
357 .iov_len = NETLINK_BUFFER
358 };
359 struct sockaddr_nl peer = { .nl_family = AF_NETLINK };
360 struct msghdr rtnl_reply = {
361 .msg_iov = &iov,
362 .msg_iovlen = 1,
363 .msg_name = &peer,
364 .msg_namelen = sizeof(struct sockaddr_nl)
365 };
366
367 len = recvmsg(s, &rtnl_reply, 0);
368 if (len == -1) {
369 if (errno == EAGAIN || errno == EWOULDBLOCK) {
370 log_debug("netlink", "should have received something, but didn't");
371 return 0;
372 }
373 log_warnx("netlink", "unable to receive netlink answer");
374 return -1;
375 }
376 if (!len) return 0;
377 for (msg = (struct nlmsghdr*)(void*)reply;
378 NLMSG_OK(msg, len);
379 msg = NLMSG_NEXT(msg, len)) {
380 if (!(msg->nlmsg_flags & NLM_F_MULTI))
381 end = 1;
382 switch (msg->nlmsg_type) {
383 case NLMSG_DONE:
384 log_debug("netlink", "received done message");
385 end = 1;
386 break;
387 case RTM_NEWLINK:
388 case RTM_DELLINK:
389 if (!ifs) break;
390 log_debug("netlink", "received link information");
391 ifdnew = calloc(1, sizeof(struct interfaces_device));
392 if (ifdnew == NULL) {
393 log_warn("netlink", "not enough memory for another interface, give up what we have");
394 goto end;
395 }
396 if (netlink_parse_link(msg, ifdnew) == 0) {
397 /* We need to find if we already have this interface */
398 TAILQ_FOREACH(ifdold, ifs, next) {
399 if (ifdold->index == ifdnew->index) break;
400 }
401 if (msg->nlmsg_type == RTM_NEWLINK) {
402 if (ifdold == NULL) {
403 log_debug("netlink", "interface %s is new",
404 ifdnew->name);
405 TAILQ_INSERT_TAIL(ifs, ifdnew, next);
406 } else {
407 log_debug("netlink", "interface %s/%s is updated",
408 ifdold->name, ifdnew->name);
409 TAILQ_INSERT_AFTER(ifs, ifdold, ifdnew, next);
410 TAILQ_REMOVE(ifs, ifdold, next);
411 interfaces_free_device(ifdold);
412 }
413 } else {
414 if (ifdold == NULL) {
415 log_warnx("netlink",
416 "removal request for %s, but no knowledge of it",
417 ifdnew->name);
418 } else {
419 log_debug("netlink", "interface %s is to be removed",
420 ifdold->name);
421 TAILQ_REMOVE(ifs, ifdold, next);
422 interfaces_free_device(ifdold);
423 }
424 interfaces_free_device(ifdnew);
425 }
426 link_update = 1;
427 } else {
428 interfaces_free_device(ifdnew);
429 }
430 break;
431 case RTM_NEWADDR:
432 case RTM_DELADDR:
433 if (!ifas) break;
434 log_debug("netlink", "received address information");
435 ifanew = calloc(1, sizeof(struct interfaces_address));
436 if (ifanew == NULL) {
437 log_warn("netlink", "not enough memory for another address, give what we have");
438 goto end;
439 }
440 if (netlink_parse_address(msg, ifanew) == 0) {
441 TAILQ_FOREACH(ifaold, ifas, next) {
442 if ((ifaold->index == ifanew->index) &&
443 !memcmp(&ifaold->address, &ifanew->address,
444 sizeof(ifaold->address))) continue;
445 }
446 if (getnameinfo((struct sockaddr *)&ifanew->address,
447 sizeof(ifanew->address),
448 addr, sizeof(addr),
449 NULL, 0, NI_NUMERICHOST) != 0) {
450 strlcpy(addr, "(unknown)", sizeof(addr));
451 }
13181ede 452
0fa2254b
VB
453 if (msg->nlmsg_type == RTM_NEWADDR) {
454 if (ifaold == NULL) {
455 log_debug("netlink", "new address %s%%%d",
456 addr, ifanew->index);
457 TAILQ_INSERT_TAIL(ifas, ifanew, next);
458 } else {
459 log_debug("netlink", "updated address %s%%%d",
460 addr, ifaold->index);
461 TAILQ_INSERT_AFTER(ifas, ifaold, ifanew, next);
462 TAILQ_REMOVE(ifas, ifaold, next);
463 interfaces_free_address(ifaold);
464 }
465 } else {
466 if (ifaold == NULL) {
467 log_warnx("netlink",
468 "removal request for address of %s%%%d, but no knowledge of it",
469 addr, ifanew->index);
470 } else {
471 log_debug("netlink", "address %s%%%d is to be removed",
472 addr, ifaold->index);
473 TAILQ_REMOVE(ifas, ifaold, next);
474 interfaces_free_address(ifaold);
475 }
476 interfaces_free_address(ifanew);
477 }
478 } else {
479 interfaces_free_address(ifanew);
480 }
481 break;
482 default:
483 log_debug("netlink",
484 "received unhandled message type %d (len: %d)",
485 msg->nlmsg_type, msg->nlmsg_len);
486 }
487 }
13181ede 488 }
0fa2254b
VB
489end:
490 if (link_update) {
491 /* Fill out lower/upper */
492 struct interfaces_device *iface1, *iface2;
493 TAILQ_FOREACH(iface1, ifs, next) {
494 if (iface1->upper_idx != -1 && iface1->upper_idx != iface1->index) {
495 TAILQ_FOREACH(iface2, ifs, next) {
496 if (iface1->upper_idx == iface2->index) {
497 iface1->upper = iface2;
498 break;
499 }
13181ede 500 }
0fa2254b
VB
501 } else {
502 iface1->upper = NULL;
13181ede 503 }
0fa2254b
VB
504 if (iface1->lower_idx != -1 && iface1->lower_idx != iface1->index) {
505 TAILQ_FOREACH(iface2, ifs, next) {
506 if (iface1->lower_idx == iface2->index) {
507 if (iface2->lower_idx == iface1->index) {
508 /* Workaround a bug introduced in Linux 4.1 */
509 iface2->lower_idx = iface2->index;
510 iface1->lower_idx = iface1->index;
511 } else iface1->lower = iface2;
512 break;
7d0a4975 513 }
13181ede 514 }
0fa2254b
VB
515 } else {
516 iface1->lower = NULL;
13181ede 517 }
0fa2254b 518 }
13181ede 519 }
0fa2254b
VB
520 return 0;
521}
13181ede 522
0fa2254b
VB
523static int
524netlink_group_mask(int group)
525{
526 return group ? (1 << (group - 1)) : 0;
e12c2365
VB
527}
528
529/**
0fa2254b 530 * Subscribe to link changes.
e12c2365 531 *
0fa2254b 532 * @return The socket we should listen to for changes.
e12c2365 533 */
0fa2254b
VB
534int
535netlink_subscribe_changes()
e12c2365 536{
0fa2254b
VB
537 unsigned int groups;
538
539 log_debug("netlink", "listening on interface changes");
540
541 groups = netlink_group_mask(RTNLGRP_LINK) |
542 netlink_group_mask(RTNLGRP_IPV4_IFADDR) |
543 netlink_group_mask(RTNLGRP_IPV6_IFADDR);
544
545 return netlink_connect(NETLINK_ROUTE, groups);
546}
547
548/**
549 * Receive changes from netlink */
550static void
551netlink_change_cb(struct lldpd *cfg)
552{
553 if (cfg->g_netlink == NULL)
554 return;
555 netlink_recv(cfg->g_netlink->nl_socket,
556 cfg->g_netlink->devices,
557 cfg->g_netlink->addresses);
558}
0484f180 559
0fa2254b
VB
560/**
561 * Initialize netlink subsystem.
562 *
563 * This can be called several times but will have effect only the first time.
564 *
565 * @return 0 on success, -1 otherwise
566 */
567static int
568netlink_initialize(struct lldpd *cfg)
569{
570 if (cfg->g_netlink) return 0;
aca48e4b 571
0fa2254b
VB
572 log_debug("netlink", "initialize netlink subsystem");
573 if ((cfg->g_netlink = calloc(sizeof(struct lldpd_netlink), 1)) == NULL) {
574 log_warn("netlink", "unable to allocate memory for netlink subsystem");
575 goto end;
576 }
577
578 /* Connect to netlink (by requesting to get notified on updates) and
579 * request updated information right now */
580 int s = cfg->g_netlink->nl_socket = netlink_subscribe_changes();
581
582 struct interfaces_address_list *ifaddrs = cfg->g_netlink->addresses =
583 malloc(sizeof(struct interfaces_address_list));
13181ede
VB
584 if (ifaddrs == NULL) {
585 log_warn("netlink", "not enough memory for address list");
0fa2254b 586 goto end;
13181ede
VB
587 }
588 TAILQ_INIT(ifaddrs);
589
0fa2254b
VB
590 struct interfaces_device_list *ifs = cfg->g_netlink->devices =
591 malloc(sizeof(struct interfaces_device_list));
592 if (ifs == NULL) {
593 log_warn("netlink", "not enough memory for interface list");
594 goto end;
595 }
596 TAILQ_INIT(ifs);
597
598 if (netlink_send(s, RTM_GETADDR, AF_UNSPEC, 1) == -1)
599 goto end;
600 netlink_recv(s, NULL, ifaddrs);
601 if (netlink_send(s, RTM_GETLINK, AF_PACKET, 2) == -1)
602 goto end;
603 netlink_recv(s, ifs, NULL);
604
605 /* Listen to any future change */
606 cfg->g_iface_cb = netlink_change_cb;
607 if (levent_iface_subscribe(cfg, s) == -1) {
608 goto end;
609 }
610
611 return 0;
612end:
613 netlink_cleanup(cfg);
614 return -1;
615}
616
617/**
618 * Cleanup netlink subsystem.
619 */
620void
621netlink_cleanup(struct lldpd *cfg)
622{
623 if (cfg->g_netlink == NULL) return;
624 if (cfg->g_netlink->nl_socket != -1)
625 close(cfg->g_netlink->nl_socket);
626 interfaces_free_devices(cfg->g_netlink->devices);
627 interfaces_free_addresses(cfg->g_netlink->addresses);
628
629 free(cfg->g_netlink);
630 cfg->g_netlink = NULL;
631}
632
633/**
634 * Receive the list of interfaces.
635 *
636 * @return a list of interfaces.
637 */
638struct interfaces_device_list*
639netlink_get_interfaces(struct lldpd *cfg)
640{
641 if (netlink_initialize(cfg) == -1) return NULL;
642 struct interfaces_device *ifd;
643 TAILQ_FOREACH(ifd, cfg->g_netlink->devices, next) {
644 ifd->ignore = 0;
13181ede 645 }
0fa2254b
VB
646 return cfg->g_netlink->devices;
647}
aca48e4b 648
0fa2254b
VB
649/**
650 * Receive the list of addresses.
651 *
652 * @return a list of addresses.
653 */
654struct interfaces_address_list*
655netlink_get_addresses(struct lldpd *cfg)
656{
657 if (netlink_initialize(cfg) == -1) return NULL;
658 return cfg->g_netlink->addresses;
0484f180 659}