1 /* -*- mode: c; c-file-style: "openbsd" -*- */
3 * Copyright (c) 2012 Vincent Bernat <bernat@luffy.cx>
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.
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.
18 /* Grabbing interfaces information with netlink only. */
23 #include <sys/socket.h>
25 #include <net/if_arp.h>
26 #include <linux/netlink.h>
27 #include <linux/rtnetlink.h>
29 #define NETLINK_BUFFER 4096
36 struct lldpd_netlink
{
38 int nl_socket_recv_size
;
40 struct interfaces_device_list
*devices
;
41 struct interfaces_address_list
*addresses
;
46 * Set netlink socket buffer size.
48 * This returns the effective size on success. If the provided value is 0, this
49 * returns the current size instead. It returns -1 on system errors and -2 if
50 * the size was not changed appropriately (when reaching the max).
53 netlink_socket_set_buffer_size(int s
, int optname
, const char *optname_str
, int bufsize
)
55 socklen_t size
= sizeof(int);
58 if (bufsize
> 0 && setsockopt(s
, SOL_SOCKET
, optname
, &bufsize
, sizeof(bufsize
)) < 0) {
59 log_warn("netlink", "unable to set %s to '%d'", optname_str
, bufsize
);
63 /* Now read them back from kernel.
64 * SO_SNDBUF & SO_RCVBUF are cap-ed at sysctl `net.core.rmem_max` &
65 * `net.core.wmem_max`. This it the easiest [probably sanest too]
66 * to validate that our socket buffers were set properly.
68 if (getsockopt(s
, SOL_SOCKET
, optname
, &got
, &size
) < 0) {
69 log_warn("netlink", "unable to get %s", optname_str
);
72 if (bufsize
> 0 && got
< bufsize
) {
73 log_warnx("netlink", "tried to set %s to '%d' "
74 "but got '%d'", optname_str
, bufsize
, got
);
84 * Open a Netlink socket and connect to it.
86 * @param protocol Which protocol to use (eg NETLINK_ROUTE).
87 * @param groups Which groups we want to subscribe to
88 * @return 0 on success, -1 otherwise
91 netlink_connect(struct lldpd
*cfg
, int protocol
, unsigned groups
)
94 struct sockaddr_nl local
= {
95 .nl_family
= AF_NETLINK
,
100 /* Open Netlink socket */
101 log_debug("netlink", "opening netlink socket");
102 s
= socket(AF_NETLINK
, SOCK_RAW
, protocol
);
104 log_warn("netlink", "unable to open netlink socket");
107 if (NETLINK_SEND_BUFSIZE
&&
108 netlink_socket_set_buffer_size(s
,
109 SO_SNDBUF
, "SO_SNDBUF", NETLINK_SEND_BUFSIZE
) == -1)
112 int rc
= netlink_socket_set_buffer_size(s
,
113 SO_RCVBUF
, "SO_RCVBUF", NETLINK_RECEIVE_BUFSIZE
);
116 case -2: cfg
->g_netlink
->nl_socket_recv_size
= 0; break;
117 default: cfg
->g_netlink
->nl_socket_recv_size
= rc
; break;
119 if (groups
&& bind(s
, (struct sockaddr
*)&local
, sizeof(struct sockaddr_nl
)) < 0) {
120 log_warn("netlink", "unable to bind netlink socket");
124 cfg
->g_netlink
->nl_socket
= s
;
129 * Send a netlink message.
131 * The type of the message can be chosen as well the route family. The
132 * mesage will always be NLM_F_REQUEST | NLM_F_DUMP.
134 * @param s the netlink socket
135 * @param type the request type (eg RTM_GETLINK)
136 * @param family the rt family (eg AF_PACKET)
137 * @return 0 on success, -1 otherwise
140 netlink_send(int s
, int type
, int family
, int seq
)
142 struct netlink_req req
= {
144 .nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtgenmsg
)),
146 .nlmsg_flags
= NLM_F_REQUEST
| NLM_F_DUMP
,
148 .nlmsg_pid
= getpid() },
149 .gen
= { .rtgen_family
= family
}
153 .iov_len
= req
.hdr
.nlmsg_len
155 struct sockaddr_nl peer
= { .nl_family
= AF_NETLINK
};
156 struct msghdr rtnl_msg
= {
160 .msg_namelen
= sizeof(struct sockaddr_nl
)
163 /* Send netlink message. This is synchronous but we are guaranteed
165 log_debug("netlink", "sending netlink message");
166 if (sendmsg(s
, (struct msghdr
*)&rtnl_msg
, 0) == -1) {
167 log_warn("netlink", "unable to send netlink message");
175 netlink_parse_rtattr(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
177 while (RTA_OK(rta
, len
)) {
178 if ((rta
->rta_type
<= max
) && (!tb
[rta
->rta_type
]))
179 tb
[rta
->rta_type
] = rta
;
180 rta
= RTA_NEXT(rta
,len
);
185 * Parse a `linkinfo` attributes.
187 * @param iff where to put the result
188 * @param rta linkinfo attribute
189 * @param len length of attributes
192 netlink_parse_linkinfo(struct interfaces_device
*iff
, struct rtattr
*rta
, int len
)
194 struct rtattr
*link_info_attrs
[IFLA_INFO_MAX
+1] = {};
197 netlink_parse_rtattr(link_info_attrs
, IFLA_INFO_MAX
, rta
, len
);
199 if (link_info_attrs
[IFLA_INFO_KIND
]) {
200 kind
= strdup(RTA_DATA(link_info_attrs
[IFLA_INFO_KIND
]));
202 if (!strcmp(kind
, "vlan")) {
203 log_debug("netlink", "interface %s is a VLAN",
205 iff
->type
|= IFACE_VLAN_T
;
206 } else if (!strcmp(kind
, "bridge")) {
207 log_debug("netlink", "interface %s is a bridge",
209 iff
->type
|= IFACE_BRIDGE_T
;
210 } else if (!strcmp(kind
, "bond")) {
211 log_debug("netlink", "interface %s is a bond",
213 iff
->type
|= IFACE_BOND_T
;
214 } else if (!strcmp(kind
, "team")) {
215 log_debug("netlink", "interface %s is a team",
217 iff
->type
|= IFACE_BOND_T
;
222 if (kind
&& !strcmp(kind
, "vlan") && link_info_attrs
[IFLA_INFO_DATA
]) {
223 struct rtattr
*vlan_link_info_data_attrs
[IFLA_VLAN_MAX
+1] = {};
224 netlink_parse_rtattr(vlan_link_info_data_attrs
, IFLA_VLAN_MAX
,
225 RTA_DATA(link_info_attrs
[IFLA_INFO_DATA
]),
226 RTA_PAYLOAD(link_info_attrs
[IFLA_INFO_DATA
]));
228 if (vlan_link_info_data_attrs
[IFLA_VLAN_ID
]) {
229 iff
->vlanid
= *(uint16_t *)RTA_DATA(vlan_link_info_data_attrs
[IFLA_VLAN_ID
]);
230 log_debug("netlink", "VLAN ID for interface %s is %d",
231 iff
->name
, iff
->vlanid
);
239 * Parse a `link` netlink message.
241 * @param msg message to be parsed
242 * @param iff where to put the result
243 * return 0 if the interface is worth it, -1 otherwise
246 netlink_parse_link(struct nlmsghdr
*msg
,
247 struct interfaces_device
*iff
)
249 struct ifinfomsg
*ifi
;
250 struct rtattr
*attribute
;
252 ifi
= NLMSG_DATA(msg
);
253 len
= msg
->nlmsg_len
- NLMSG_LENGTH(sizeof(struct ifinfomsg
));
255 if (ifi
->ifi_type
!= ARPHRD_ETHER
) {
256 log_debug("netlink", "skip non Ethernet interface at index %d",
261 iff
->index
= ifi
->ifi_index
;
262 iff
->flags
= ifi
->ifi_flags
;
266 for (attribute
= IFLA_RTA(ifi
);
267 RTA_OK(attribute
, len
);
268 attribute
= RTA_NEXT(attribute
, len
)) {
269 switch(attribute
->rta_type
) {
272 iff
->name
= strdup(RTA_DATA(attribute
));
275 /* Interface alias */
276 iff
->alias
= strdup(RTA_DATA(attribute
));
279 /* Interface MAC address */
280 iff
->address
= malloc(RTA_PAYLOAD(attribute
));
282 memcpy(iff
->address
, RTA_DATA(attribute
), RTA_PAYLOAD(attribute
));
285 /* Index of "lower" interface */
286 iff
->lower_idx
= *(int*)RTA_DATA(attribute
);
287 log_debug("netlink", "attribute IFLA_LINK for %s: %d",
288 iff
->name
? iff
->name
: "(unknown)", iff
->lower_idx
);
290 case IFLA_LINK_NETNSID
:
291 /* Is the lower interface into another namesapce? */
293 log_debug("netlink", "attribute IFLA_LINK_NETNSID received for %s",
294 iff
->name
? iff
->name
: "(unknown)");
297 /* Index of master interface */
298 iff
->upper_idx
= *(int*)RTA_DATA(attribute
);
301 /* Maximum Transmission Unit */
302 iff
->mtu
= *(int*)RTA_DATA(attribute
);
305 netlink_parse_linkinfo(iff
, RTA_DATA(attribute
), RTA_PAYLOAD(attribute
));
308 log_debug("netlink", "unhandled link attribute type %d for iface %s",
309 attribute
->rta_type
, iff
->name
? iff
->name
: "(unknown)");
313 if (!iff
->name
|| !iff
->address
) {
314 log_info("netlink", "interface %d does not have a name or an address, skip",
318 if (iff
->upper_idx
== -1) {
319 /* No upper interface, we cannot be enslaved. We need to clear
320 * the flag because the appropriate information may come later
321 * and we don't want to miss it. */
322 iff
->flags
&= ~IFF_SLAVE
;
325 if (ifi
->ifi_family
== AF_BRIDGE
&& msg
->nlmsg_type
== RTM_DELLINK
&& iff
->upper_idx
!= -1) {
326 log_debug("netlink", "removal of %s from bridge %d",
327 iff
->name
, iff
->upper_idx
);
328 msg
->nlmsg_type
= RTM_NEWLINK
;
330 } else if (ifi
->ifi_family
!= 0) {
331 log_debug("netlink", "skip non-generic message update %d at index %d",
332 ifi
->ifi_type
, ifi
->ifi_index
);
336 log_debug("netlink", "parsed link %d (%s, flags: %d)",
337 iff
->index
, iff
->name
, iff
->flags
);
342 * Parse a `address` netlink message.
344 * @param msg message to be parsed
345 * @param ifa where to put the result
346 * return 0 if the address is worth it, -1 otherwise
349 netlink_parse_address(struct nlmsghdr
*msg
,
350 struct interfaces_address
*ifa
)
352 struct ifaddrmsg
*ifi
;
353 struct rtattr
*attribute
;
355 ifi
= NLMSG_DATA(msg
);
356 len
= msg
->nlmsg_len
- NLMSG_LENGTH(sizeof(struct ifaddrmsg
));
358 ifa
->index
= ifi
->ifa_index
;
359 ifa
->flags
= ifi
->ifa_flags
;
360 switch (ifi
->ifa_family
) {
362 case AF_INET6
: break;
364 log_debug("netlink", "got a non IP address on if %d (family: %d)",
365 ifa
->index
, ifi
->ifa_family
);
369 for (attribute
= IFA_RTA(ifi
);
370 RTA_OK(attribute
, len
);
371 attribute
= RTA_NEXT(attribute
, len
)) {
372 switch(attribute
->rta_type
) {
375 if (ifi
->ifa_family
== AF_INET
) {
376 struct sockaddr_in ip
;
377 memset(&ip
, 0, sizeof(struct sockaddr_in
));
378 ip
.sin_family
= AF_INET
;
379 memcpy(&ip
.sin_addr
, RTA_DATA(attribute
),
380 sizeof(struct in_addr
));
381 memcpy(&ifa
->address
, &ip
, sizeof(struct sockaddr_in
));
383 struct sockaddr_in6 ip6
;
384 memset(&ip6
, 0, sizeof(struct sockaddr_in6
));
385 ip6
.sin6_family
= AF_INET6
;
386 memcpy(&ip6
.sin6_addr
, RTA_DATA(attribute
),
387 sizeof(struct in6_addr
));
388 memcpy(&ifa
->address
, &ip6
, sizeof(struct sockaddr_in6
));
392 log_debug("netlink", "unhandled address attribute type %d for iface %d",
393 attribute
->rta_type
, ifa
->index
);
397 if (ifa
->address
.ss_family
== AF_UNSPEC
) {
398 log_debug("netlink", "no IP for interface %d",
406 * Merge an old interface with a new one.
408 * Some properties may be absent in the new interface that should be copied over
412 netlink_merge(struct interfaces_device
*old
, struct interfaces_device
*new)
414 if (new->alias
== NULL
) {
415 new->alias
= old
->alias
;
418 if (new->address
== NULL
) {
419 new->address
= old
->address
;
425 new->type
= old
->type
;
426 if (new->vlanid
== 0)
427 new->vlanid
= old
->vlanid
;
429 /* It's not possible for lower link to change */
430 new->lower_idx
= old
->lower_idx
;
434 * Receive netlink answer from the kernel.
436 * @param ifs list to store interface list or NULL if we don't
437 * @param ifas list to store address list or NULL if we don't
438 * @return 0 on success, -1 on error
441 netlink_recv(struct lldpd
*cfg
,
442 struct interfaces_device_list
*ifs
,
443 struct interfaces_address_list
*ifas
)
445 int end
= 0, ret
= 0;
446 int flags
= MSG_PEEK
| MSG_TRUNC
;
449 int s
= cfg
->g_netlink
->nl_socket
;
451 struct interfaces_device
*ifdold
;
452 struct interfaces_device
*ifdnew
;
453 struct interfaces_address
*ifaold
;
454 struct interfaces_address
*ifanew
;
455 char addr
[INET6_ADDRSTRLEN
+ 1];
457 iov
.iov_len
= NETLINK_BUFFER
;
458 iov
.iov_base
= malloc(iov
.iov_len
);
460 log_warn("netlink", "not enough memory");
466 struct nlmsghdr
*msg
;
467 struct sockaddr_nl peer
= { .nl_family
= AF_NETLINK
};
468 struct msghdr rtnl_reply
= {
472 .msg_namelen
= sizeof(struct sockaddr_nl
)
476 len
= recvmsg(s
, &rtnl_reply
, flags
);
478 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) {
479 log_debug("netlink", "should have received something, but didn't");
483 int rsize
= cfg
->g_netlink
->nl_socket_recv_size
;
484 if (errno
== ENOBUFS
&&
485 rsize
> 0 && rsize
< NETLINK_MAX_RECEIVE_BUFSIZE
) {
486 /* Try to increase buffer size */
488 if (rsize
> NETLINK_MAX_RECEIVE_BUFSIZE
) {
489 rsize
= NETLINK_MAX_RECEIVE_BUFSIZE
;
491 int rc
= netlink_socket_set_buffer_size(s
,
492 SO_RCVBUF
, "SO_RCVBUF",
495 cfg
->g_netlink
->nl_socket_recv_size
= 0;
497 cfg
->g_netlink
->nl_socket_recv_size
= rsize
;
498 if (rc
> 0 || rc
== -2) {
500 "netlink receive buffer too small, retry with larger one (%d)",
506 log_warn("netlink", "unable to receive netlink answer");
515 if (iov
.iov_len
< len
|| (rtnl_reply
.msg_flags
& MSG_TRUNC
)) {
518 /* Provided buffer is not large enough, enlarge it
519 * to size of len (which should be total length of the message)
522 tmp
= realloc(iov
.iov_base
, iov
.iov_len
);
524 log_warn("netlink", "not enough memory");
528 log_debug("netlink", "enlarge message size to %zu bytes", len
);
535 /* Buffer is big enough, do the actual reading */
540 for (msg
= (struct nlmsghdr
*)(void*)(iov
.iov_base
);
542 msg
= NLMSG_NEXT(msg
, len
)) {
543 if (!(msg
->nlmsg_flags
& NLM_F_MULTI
))
545 switch (msg
->nlmsg_type
) {
547 log_debug("netlink", "received done message");
553 log_debug("netlink", "received link information");
554 ifdnew
= calloc(1, sizeof(struct interfaces_device
));
555 if (ifdnew
== NULL
) {
556 log_warn("netlink", "not enough memory for another interface, give up what we have");
559 if (netlink_parse_link(msg
, ifdnew
) == 0) {
560 /* We need to find if we already have this interface */
561 TAILQ_FOREACH(ifdold
, ifs
, next
) {
562 if (ifdold
->index
== ifdnew
->index
) break;
565 if (msg
->nlmsg_type
== RTM_NEWLINK
) {
566 if (ifdold
== NULL
) {
567 log_debug("netlink", "interface %s is new",
569 TAILQ_INSERT_TAIL(ifs
, ifdnew
, next
);
571 log_debug("netlink", "interface %s/%s is updated",
572 ifdold
->name
, ifdnew
->name
);
573 netlink_merge(ifdold
, ifdnew
);
574 TAILQ_INSERT_AFTER(ifs
, ifdold
, ifdnew
, next
);
575 TAILQ_REMOVE(ifs
, ifdold
, next
);
576 interfaces_free_device(ifdold
);
579 if (ifdold
== NULL
) {
581 "removal request for %s, but no knowledge of it",
584 log_debug("netlink", "interface %s is to be removed",
586 TAILQ_REMOVE(ifs
, ifdold
, next
);
587 interfaces_free_device(ifdold
);
589 interfaces_free_device(ifdnew
);
593 interfaces_free_device(ifdnew
);
599 log_debug("netlink", "received address information");
600 ifanew
= calloc(1, sizeof(struct interfaces_address
));
601 if (ifanew
== NULL
) {
602 log_warn("netlink", "not enough memory for another address, give what we have");
605 if (netlink_parse_address(msg
, ifanew
) == 0) {
606 TAILQ_FOREACH(ifaold
, ifas
, next
) {
607 if ((ifaold
->index
== ifanew
->index
) &&
608 !memcmp(&ifaold
->address
, &ifanew
->address
,
609 sizeof(ifaold
->address
))) break;
611 if (getnameinfo((struct sockaddr
*)&ifanew
->address
,
612 sizeof(ifanew
->address
),
614 NULL
, 0, NI_NUMERICHOST
) != 0) {
615 strlcpy(addr
, "(unknown)", sizeof(addr
));
618 if (msg
->nlmsg_type
== RTM_NEWADDR
) {
619 if (ifaold
== NULL
) {
620 log_debug("netlink", "new address %s%%%d",
621 addr
, ifanew
->index
);
622 TAILQ_INSERT_TAIL(ifas
, ifanew
, next
);
624 log_debug("netlink", "updated address %s%%%d",
625 addr
, ifaold
->index
);
626 TAILQ_INSERT_AFTER(ifas
, ifaold
, ifanew
, next
);
627 TAILQ_REMOVE(ifas
, ifaold
, next
);
628 interfaces_free_address(ifaold
);
631 if (ifaold
== NULL
) {
633 "removal request for address of %s%%%d, but no knowledge of it",
634 addr
, ifanew
->index
);
636 log_debug("netlink", "address %s%%%d is to be removed",
637 addr
, ifaold
->index
);
638 TAILQ_REMOVE(ifas
, ifaold
, next
);
639 interfaces_free_address(ifaold
);
641 interfaces_free_address(ifanew
);
644 interfaces_free_address(ifanew
);
649 "received unhandled message type %d (len: %d)",
650 msg
->nlmsg_type
, msg
->nlmsg_len
);
653 flags
= MSG_PEEK
| MSG_TRUNC
;
657 /* Fill out lower/upper */
658 struct interfaces_device
*iface1
, *iface2
;
659 TAILQ_FOREACH(iface1
, ifs
, next
) {
660 if (iface1
->upper_idx
!= -1 && iface1
->upper_idx
!= iface1
->index
) {
661 TAILQ_FOREACH(iface2
, ifs
, next
) {
662 if (iface1
->upper_idx
== iface2
->index
) {
664 "upper interface for %s is %s",
665 iface1
->name
, iface2
->name
);
666 iface1
->upper
= iface2
;
671 iface1
->upper
= NULL
;
673 iface1
->upper
= NULL
;
675 if (iface1
->lower_idx
!= -1 && iface1
->lower_idx
!= iface1
->index
) {
676 TAILQ_FOREACH(iface2
, ifs
, next
) {
677 if (iface1
->lower_idx
== iface2
->index
) {
678 /* Workaround a bug introduced
679 * in Linux 4.1: a pair of veth
680 * will be lower interface of
681 * each other. Do not modify
682 * index as if one of them is
683 * updated, we will loose the
684 * information about the
686 if (iface2
->lower_idx
== iface1
->index
) {
687 iface1
->lower
= NULL
;
689 "link loop detected between %s and %s",
690 iface1
->name
, iface2
->name
);
693 "lower interface for %s is %s",
694 iface1
->name
, iface2
->name
);
695 iface1
->lower
= iface2
;
700 iface1
->lower
= NULL
;
703 iface1
->lower
= NULL
;
714 netlink_group_mask(int group
)
716 return group
? (1 << (group
- 1)) : 0;
720 * Subscribe to link changes.
722 * @return 0 on success, -1 otherwise
725 netlink_subscribe_changes(struct lldpd
*cfg
)
729 log_debug("netlink", "listening on interface changes");
731 groups
= netlink_group_mask(RTNLGRP_LINK
) |
732 netlink_group_mask(RTNLGRP_IPV4_IFADDR
) |
733 netlink_group_mask(RTNLGRP_IPV6_IFADDR
);
735 return netlink_connect(cfg
, NETLINK_ROUTE
, groups
);
739 * Receive changes from netlink */
741 netlink_change_cb(struct lldpd
*cfg
)
743 if (cfg
->g_netlink
== NULL
)
746 cfg
->g_netlink
->devices
,
747 cfg
->g_netlink
->addresses
);
751 * Initialize netlink subsystem.
753 * This can be called several times but will have effect only the first time.
755 * @return 0 on success, -1 otherwise
758 netlink_initialize(struct lldpd
*cfg
)
760 if (cfg
->g_netlink
) return 0;
762 log_debug("netlink", "initialize netlink subsystem");
763 if ((cfg
->g_netlink
= calloc(sizeof(struct lldpd_netlink
), 1)) == NULL
) {
764 log_warn("netlink", "unable to allocate memory for netlink subsystem");
768 /* Connect to netlink (by requesting to get notified on updates) and
769 * request updated information right now */
770 if (netlink_subscribe_changes(cfg
) == -1)
773 struct interfaces_address_list
*ifaddrs
= cfg
->g_netlink
->addresses
=
774 malloc(sizeof(struct interfaces_address_list
));
775 if (ifaddrs
== NULL
) {
776 log_warn("netlink", "not enough memory for address list");
781 struct interfaces_device_list
*ifs
= cfg
->g_netlink
->devices
=
782 malloc(sizeof(struct interfaces_device_list
));
784 log_warn("netlink", "not enough memory for interface list");
789 if (netlink_send(cfg
->g_netlink
->nl_socket
, RTM_GETADDR
, AF_UNSPEC
, 1) == -1)
791 netlink_recv(cfg
, NULL
, ifaddrs
);
792 if (netlink_send(cfg
->g_netlink
->nl_socket
, RTM_GETLINK
, AF_PACKET
, 2) == -1)
794 netlink_recv(cfg
, ifs
, NULL
);
796 /* Listen to any future change */
797 cfg
->g_iface_cb
= netlink_change_cb
;
798 if (levent_iface_subscribe(cfg
, cfg
->g_netlink
->nl_socket
) == -1) {
804 netlink_cleanup(cfg
);
809 * Cleanup netlink subsystem.
812 netlink_cleanup(struct lldpd
*cfg
)
814 if (cfg
->g_netlink
== NULL
) return;
815 if (cfg
->g_netlink
->nl_socket
!= -1)
816 close(cfg
->g_netlink
->nl_socket
);
817 interfaces_free_devices(cfg
->g_netlink
->devices
);
818 interfaces_free_addresses(cfg
->g_netlink
->addresses
);
820 free(cfg
->g_netlink
);
821 cfg
->g_netlink
= NULL
;
825 * Receive the list of interfaces.
827 * @return a list of interfaces.
829 struct interfaces_device_list
*
830 netlink_get_interfaces(struct lldpd
*cfg
)
832 if (netlink_initialize(cfg
) == -1) return NULL
;
833 struct interfaces_device
*ifd
;
834 TAILQ_FOREACH(ifd
, cfg
->g_netlink
->devices
, next
) {
837 return cfg
->g_netlink
->devices
;
841 * Receive the list of addresses.
843 * @return a list of addresses.
845 struct interfaces_address_list
*
846 netlink_get_addresses(struct lldpd
*cfg
)
848 if (netlink_initialize(cfg
) == -1) return NULL
;
849 return cfg
->g_netlink
->addresses
;