--- /dev/null
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2012 Vincent Bernat <bernat@luffy.cx>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "lldpd.h"
+
+#include <unistd.h>
+#include <ifaddrs.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <net/bpf.h>
+#include <net/if_types.h>
+#include <net/if_mib.h>
+#include <net/if_media.h>
+#include <net/if_vlan_var.h>
+#include <net/if_bridgevar.h>
+#include <net/if_lagg.h>
+#include <net/if_dl.h>
+
+#ifndef IFDESCRSIZE
+#define IFDESCRSIZE 64
+#endif
+
+static int
+ifbsd_check_driver(struct lldpd *cfg,
+ struct ifaddrs *ifaddr,
+ struct interfaces_device *iface)
+{
+ int name[6];
+ char dname[IFNAMSIZ+1] = {};
+ size_t len = IFNAMSIZ;
+
+ name[0] = CTL_NET;
+ name[1] = PF_LINK;
+ name[2] = NETLINK_GENERIC;
+ name[3] = IFMIB_IFDATA;
+ name[4] = iface->index;
+ name[5] = IFDATA_DRIVERNAME;
+
+ if (sysctl(name, 6, dname, &len, 0, 0) == -1 || len == 0) {
+ log_info("interfaces", "unable to get driver name for %s",
+ iface->name);
+ return -1;
+ }
+ iface->driver = strdup(dname);
+ return 0;
+}
+
+static int
+ifbsd_check_wireless(struct lldpd *cfg,
+ struct ifaddrs *ifaddr,
+ struct interfaces_device *iface)
+{
+ struct ifmediareq ifmr = {};
+ strlcpy(ifmr.ifm_name, iface->name, sizeof(ifmr.ifm_name));
+ if (ioctl(cfg->g_sock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0 ||
+ IFM_TYPE(ifmr.ifm_current) != IFM_IEEE80211)
+ return 0; /* Not wireless either */
+ iface->type |= IFACE_WIRELESS_T | IFACE_PHYSICAL_T;
+ return 0;
+}
+
+static void
+ifbsd_check_bridge(struct lldpd *cfg,
+ struct interfaces_device_list *interfaces,
+ struct interfaces_device *master)
+{
+ struct ifbreq req[64];
+ struct ifbifconf bifc = {
+ .ifbic_len = sizeof(req),
+ .ifbic_req = req
+ };
+ struct ifdrv ifd = {
+ .ifd_cmd = BRDGGIFS,
+ .ifd_len = sizeof(bifc),
+ .ifd_data = &bifc
+ };
+
+ strlcpy(ifd.ifd_name, master->name, sizeof(ifd.ifd_name));
+ if (ioctl(cfg->g_sock, SIOCGDRVSPEC, (caddr_t)&ifd) < 0) {
+ log_debug("interfaces",
+ "%s is not a bridge", master->name);
+ return;
+ }
+ if (bifc.ifbic_len >= sizeof(req)) {
+ log_warnx("interfaces",
+ "%s is a bridge too big. Please, report the problem",
+ master->name);
+ return;
+ }
+ for (int i = 0; i < bifc.ifbic_len / sizeof(*req); i++) {
+ struct interfaces_device *slave =
+ interfaces_nametointerface(interfaces,
+ req[i].ifbr_ifsname);
+ if (slave == NULL) {
+ log_warnx("interfaces",
+ "%s should be bridged to %s but we don't know %s",
+ req[i].ifbr_ifsname, master->name, req[i].ifbr_ifsname);
+ continue;
+ }
+ log_debug("interfaces",
+ "%s is bridged to %s",
+ slave->name, master->name);
+ slave->upper = master;
+ }
+ master->type |= IFACE_BRIDGE_T;
+}
+
+static void
+ifbsd_check_bond(struct lldpd *cfg,
+ struct interfaces_device_list *interfaces,
+ struct interfaces_device *master)
+{
+ struct lagg_reqport rpbuf[LAGG_MAX_PORTS];
+ struct lagg_reqall ra = {
+ .ra_size = sizeof(rpbuf),
+ .ra_port = rpbuf
+ };
+ strlcpy(ra.ra_ifname, master->name, IFNAMSIZ);
+ if (ioctl(cfg->g_sock, SIOCGLAGG, (caddr_t)&ra) < 0) {
+ log_debug("interfaces",
+ "%s is not a bond", master->name);
+ return;
+ }
+
+ for (int i = 0; i < ra.ra_ports; i++) {
+ struct interfaces_device *slave;
+ slave = interfaces_nametointerface(interfaces,
+ rpbuf[i].rp_portname);
+ if (slave == NULL) {
+ log_warnx("interfaces",
+ "%s should be enslaved to %s but we don't know %s",
+ rpbuf[i].rp_portname, master->name,
+ rpbuf[i].rp_portname);
+ continue;
+ }
+ log_debug("interfaces",
+ "%s is enslaved to bond %s",
+ slave->name, master->name);
+ slave->upper = master;
+ }
+ master->type |= IFACE_BOND_T;
+}
+
+static void
+ifbsd_check_vlan(struct lldpd *cfg,
+ struct interfaces_device_list *interfaces,
+ struct interfaces_device *vlan)
+{
+ struct interfaces_device *lower;
+ struct vlanreq vreq = {};
+ struct ifreq ifr = {
+ .ifr_data = (caddr_t)&vreq
+ };
+ strlcpy(ifr.ifr_name, vlan->name, sizeof(ifr.ifr_name));
+ if (ioctl(cfg->g_sock, SIOCGETVLAN, (caddr_t)&ifr) < 0) {
+ log_debug("interfaces",
+ "%s is not a VLAN", vlan->name);
+ return;
+ }
+ if (strlen(vreq.vlr_parent) == 0) {
+ log_debug("interfaces",
+ "%s is a VLAN but has no lower interface",
+ vlan->name);
+ vlan->lower = NULL;
+ vlan->type |= IFACE_VLAN_T;
+ return;
+ }
+ lower = interfaces_nametointerface(interfaces,
+ vreq.vlr_parent);
+ if (lower == NULL) {
+ log_warnx("interfaces",
+ "%s should be a VLAN of %s but %s does not exist",
+ vlan->name, vreq.vlr_parent, vreq.vlr_parent);
+ return;
+ }
+ log_debug("interfaces",
+ "%s is VLAN %d of %s",
+ vlan->name, vreq.vlr_tag, lower->name);
+ vlan->lower = lower;
+ vlan->vlanid = vreq.vlr_tag;
+ vlan->type |= IFACE_VLAN_T;
+}
+
+static void
+ifbsd_check_physical(struct lldpd *cfg,
+ struct interfaces_device_list *interfaces,
+ struct interfaces_device *iface)
+{
+ if (iface->type & (IFACE_VLAN_T|
+ IFACE_BOND_T|IFACE_BRIDGE_T|IFACE_PHYSICAL_T))
+ return;
+
+ if (!(iface->flags & (IFF_MULTICAST|IFF_BROADCAST))) {
+ log_debug("interfaces", "skip %s: not able to do multicast nor broadcast",
+ iface->name);
+ return;
+ }
+ log_debug("interfaces",
+ "%s is a physical interface",
+ iface->name);
+ iface->type |= IFACE_PHYSICAL_T;
+}
+
+static struct interfaces_device*
+ifbsd_extract_device(struct lldpd *cfg,
+ struct ifaddrs *ifaddr)
+{
+ struct interfaces_device *iface = NULL;
+ struct sockaddr_dl *saddrdl = (struct sockaddr_dl*)ifaddr->ifa_addr;
+ if ((saddrdl->sdl_type != IFT_BRIDGE) &&
+ (saddrdl->sdl_type != IFT_L2VLAN) &&
+ (saddrdl->sdl_type != IFT_ETHER)) {
+ log_debug("interfaces", "skip %s: not an ethernet device (%d)",
+ ifaddr->ifa_name, saddrdl->sdl_type);
+ return NULL;
+ }
+ if ((iface = calloc(1, sizeof(struct interfaces_device))) == NULL) {
+ log_warn("interfaces", "unable to allocate memory for %s",
+ ifaddr->ifa_name);
+ return NULL;
+ }
+
+ iface->index = saddrdl->sdl_index;
+ iface->name = strdup(ifaddr->ifa_name);
+ iface->flags = ifaddr->ifa_flags;
+
+ /* MAC address */
+ iface->address = malloc(ETH_ALEN);
+ if (iface->address)
+ memcpy(iface->address, LLADDR(saddrdl), ETH_ALEN);
+
+ /* Grab description */
+ iface->alias = malloc(IFDESCRSIZE);
+ if (iface->alias) {
+ struct ifreq ifr = {
+ .ifr_buffer = { .buffer = iface->alias,
+ .length = IFDESCRSIZE }
+ };
+ strlcpy(ifr.ifr_name, ifaddr->ifa_name, sizeof(ifr.ifr_name));
+ if (ioctl(cfg->g_sock, SIOCGIFDESCR, (caddr_t)&ifr) < 0) {
+ free(iface->alias);
+ iface->alias = NULL;
+ }
+ }
+
+ if (ifbsd_check_driver(cfg, ifaddr, iface) == -1 ||
+ ifbsd_check_wireless(cfg, ifaddr, iface) == -1) {
+ interfaces_free_device(iface);
+ return NULL;
+ }
+
+ return iface;
+}
+
+static void
+ifbsd_extract(struct lldpd *cfg,
+ struct interfaces_device_list *interfaces,
+ struct interfaces_address_list *addresses,
+ struct ifaddrs *ifaddr)
+{
+ struct interfaces_address *address = NULL;
+ struct interfaces_device *device = NULL;
+ if (!ifaddr->ifa_name) return;
+ if (!ifaddr->ifa_addr) return;
+ if (!(ifaddr->ifa_flags & IFF_UP)) {
+ log_debug("interfaces",
+ "skip %s: down", ifaddr->ifa_name);
+ return;
+ }
+ switch (ifaddr->ifa_addr->sa_family) {
+ case AF_LINK:
+ log_debug("interfaces",
+ "grabbing information on interface %s",
+ ifaddr->ifa_name);
+ device = ifbsd_extract_device(cfg, ifaddr);
+ if (device)
+ TAILQ_INSERT_TAIL(interfaces, device, next);
+ break;
+ case AF_INET:
+ case AF_INET6:
+ log_debug("interfaces",
+ "got an IP address on %s",
+ ifaddr->ifa_name);
+ address = malloc(sizeof(struct interfaces_address));
+ if (address == NULL) {
+ log_warn("interfaces",
+ "not enough memory for a new IP address on %s",
+ ifaddr->ifa_name);
+ return;
+ }
+ address->flags = ifaddr->ifa_flags;
+ address->index = if_nametoindex(ifaddr->ifa_name);
+ memcpy(&address->address,
+ ifaddr->ifa_addr,
+ (ifaddr->ifa_addr->sa_family == AF_INET)?
+ sizeof(struct sockaddr_in):
+ sizeof(struct sockaddr_in6));
+ TAILQ_INSERT_TAIL(addresses, address, next);
+ break;
+ default:
+ log_debug("interfaces", "unhandled family %d for interface %s",
+ ifaddr->ifa_addr->sa_family,
+ ifaddr->ifa_name);
+ }
+}
+
+static void
+ifbsd_macphy(struct lldpd *cfg,
+ struct lldpd_hardware *hardware)
+{
+#ifdef ENABLE_DOT3
+ int media_list[32] = {};
+ struct ifmediareq ifmr = {
+ .ifm_ulist = media_list,
+ .ifm_count = sizeof(media_list) / sizeof(int)
+ };
+ struct lldpd_port *port = &hardware->h_lport;
+ unsigned int duplex;
+ unsigned int media;
+ int advertised_ifmedia_to_rfc3636[][3] = {
+ {IFM_10_T,
+ LLDP_DOT3_LINK_AUTONEG_10BASE_T,
+ LLDP_DOT3_LINK_AUTONEG_10BASET_FD},
+ {IFM_10_STP,
+ LLDP_DOT3_LINK_AUTONEG_10BASE_T,
+ LLDP_DOT3_LINK_AUTONEG_10BASET_FD},
+ {IFM_100_TX,
+ LLDP_DOT3_LINK_AUTONEG_100BASE_TX,
+ LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD},
+ {IFM_100_T4,
+ LLDP_DOT3_LINK_AUTONEG_100BASE_T4,
+ LLDP_DOT3_LINK_AUTONEG_100BASE_T4},
+ {IFM_100_T2,
+ LLDP_DOT3_LINK_AUTONEG_100BASE_T2,
+ LLDP_DOT3_LINK_AUTONEG_100BASE_T2FD},
+ {IFM_1000_SX,
+ LLDP_DOT3_LINK_AUTONEG_1000BASE_X,
+ LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD},
+ {IFM_1000_LX,
+ LLDP_DOT3_LINK_AUTONEG_1000BASE_X,
+ LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD},
+ {IFM_1000_CX,
+ LLDP_DOT3_LINK_AUTONEG_1000BASE_X,
+ LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD},
+ {IFM_1000_T,
+ LLDP_DOT3_LINK_AUTONEG_1000BASE_T,
+ LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD},
+ {0, 0, 0}
+ };
+ int current_ifmedia_to_rfc3636[][3] = {
+ {IFM_10_T,
+ LLDP_DOT3_MAU_10BASETHD, LLDP_DOT3_MAU_10BASETFD},
+ {IFM_10_STP,
+ LLDP_DOT3_MAU_10BASETHD, LLDP_DOT3_MAU_10BASETFD},
+ {IFM_10_2,
+ LLDP_DOT3_MAU_10BASE2, LLDP_DOT3_MAU_10BASE2},
+ {IFM_10_5,
+ LLDP_DOT3_MAU_10BASE5, LLDP_DOT3_MAU_10BASE5},
+ {IFM_100_TX,
+ LLDP_DOT3_MAU_100BASETXHD, LLDP_DOT3_MAU_100BASETXFD},
+ {IFM_100_FX,
+ LLDP_DOT3_MAU_100BASEFXHD, LLDP_DOT3_MAU_100BASEFXFD},
+ {IFM_100_T2,
+ LLDP_DOT3_MAU_100BASET2HD, LLDP_DOT3_MAU_100BASET2FD},
+ {IFM_1000_SX,
+ LLDP_DOT3_MAU_1000BASESXHD, LLDP_DOT3_MAU_1000BASESXFD},
+ {IFM_10_FL,
+ LLDP_DOT3_MAU_10BASEFLHD, LLDP_DOT3_MAU_10BASEFLFD },
+ {IFM_1000_LX,
+ LLDP_DOT3_MAU_1000BASELXHD, LLDP_DOT3_MAU_1000BASELXFD},
+ {IFM_1000_CX,
+ LLDP_DOT3_MAU_1000BASECXHD, LLDP_DOT3_MAU_1000BASECXFD},
+ {IFM_1000_T,
+ LLDP_DOT3_MAU_1000BASETHD, LLDP_DOT3_MAU_1000BASETFD },
+ {IFM_10G_LR,
+ LLDP_DOT3_MAU_10GIGBASELR, LLDP_DOT3_MAU_10GIGBASELR},
+ {IFM_10G_SR,
+ LLDP_DOT3_MAU_10GIGBASESR, LLDP_DOT3_MAU_10GIGBASESR},
+ {IFM_10G_CX4,
+ LLDP_DOT3_MAU_10GIGBASELX4, LLDP_DOT3_MAU_10GIGBASELX4},
+ {0, 0, 0}
+ };
+
+ log_debug("interfaces", "get MAC/phy for %s",
+ hardware->h_ifname);
+ strlcpy(ifmr.ifm_name, hardware->h_ifname, sizeof(ifmr.ifm_name));
+ if (ioctl(cfg->g_sock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
+ log_warn("interfaces",
+ "unable to get media information from %s",
+ hardware->h_ifname);
+ return;
+ }
+ if (IFM_TYPE(ifmr.ifm_current) != IFM_ETHER) {
+ log_warnx("interfaces",
+ "cannot get media information from %s: not an ethernet device",
+ hardware->h_ifname);
+ return;
+ }
+ if ((ifmr.ifm_status & IFM_ACTIVE) == 0) {
+ log_debug("interfaces",
+ "interface %s is now down, skip",
+ hardware->h_ifname);
+ return;
+ }
+ if (ifmr.ifm_count == 0) {
+ log_warnx("interfaces", "no media information available on %s",
+ hardware->h_ifname);
+ return;
+ }
+ port->p_macphy.autoneg_support =
+ port->p_macphy.autoneg_enabled = 0;
+ for (int m = 0; m < ifmr.ifm_count; m++) {
+ media = IFM_SUBTYPE(ifmr.ifm_ulist[m]);
+ duplex = !!(IFM_OPTIONS(ifmr.ifm_ulist[m]) &
+ IFM_FDX);
+ if (media == IFM_AUTO) {
+ port->p_macphy.autoneg_support = 1;
+ port->p_macphy.autoneg_enabled =
+ (IFM_SUBTYPE(ifmr.ifm_current) == IFM_AUTO);
+ continue;
+ }
+
+ for (int j = 0; advertised_ifmedia_to_rfc3636[j][0]; j++) {
+ if (advertised_ifmedia_to_rfc3636[j][0] == media) {
+ port->p_macphy.autoneg_advertised |=
+ advertised_ifmedia_to_rfc3636[j][1 + duplex];
+ break;
+ }
+ }
+ }
+
+ port->p_macphy.mau_type = 0;
+ media = IFM_SUBTYPE(ifmr.ifm_active);
+ duplex = !!(IFM_OPTIONS(ifmr.ifm_active) & IFM_FDX);
+ for (int j = 0; current_ifmedia_to_rfc3636[j][0]; j++) {
+ if (current_ifmedia_to_rfc3636[j][0] == media) {
+ port->p_macphy.mau_type =
+ current_ifmedia_to_rfc3636[j][1 + duplex];
+ break;
+ }
+ }
+#endif
+}
+
+struct bpf_buffer {
+ size_t len; /* Total length of the buffer */
+ char data[0]; /* Data */
+};
+
+static int
+ifbsd_phys_init(struct lldpd *cfg,
+ struct lldpd_hardware *hardware)
+{
+ struct bpf_insn filter[] = { LLDPD_FILTER_F };
+ struct ifreq ifr = {};
+ struct bpf_program fprog = {
+ .bf_insns = filter,
+ .bf_len = sizeof(filter)/sizeof(struct bpf_insn)
+ };
+ struct bpf_buffer *buffer = NULL;
+ int fd = -1, enable, required;
+
+ log_debug("interfaces", "initialize ethernet device %s",
+ hardware->h_ifname);
+ if ((fd = priv_iface_init(hardware->h_ifindex)) == -1)
+ return -1;
+ /* We got a file descriptor to /dev/bpfXXX */
+
+ /* Set buffer size */
+ required = ETHER_MAX_LEN;
+ if (ioctl(fd, BIOCSBLEN, (caddr_t)&required) < 0) {
+ log_warn("interfaces",
+ "unable to set receive buffer size for BPF on %s",
+ hardware->h_ifname);
+ goto end;
+ }
+ hardware->h_data = buffer =
+ malloc(required + sizeof(struct bpf_buffer));
+ if (buffer == NULL) {
+ log_warn("interfaces",
+ "unable to allocate buffer space for BPF on %s",
+ hardware->h_ifname);
+ goto end;
+ }
+ buffer->len = required;
+
+ /* Bind the interface to BPF device */
+ strlcpy(ifr.ifr_name, hardware->h_ifname, IFNAMSIZ);
+ if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
+ log_warn("interfaces", "failed to bind interface %s to BPF",
+ hardware->h_ifname);
+ goto end;
+ }
+
+ /* Disable buffering */
+ enable = 1;
+ if (ioctl(fd, BIOCIMMEDIATE, (caddr_t)&enable) < 0) {
+ log_warn("interfaces", "unable to disable buffering for %s",
+ hardware->h_ifname);
+ goto end;
+ }
+
+ /* Let us write the MAC address (raw packet mode) */
+ enable = 1;
+ if (ioctl(fd, BIOCSHDRCMPLT, (caddr_t)&enable) < 0) {
+ log_warn("interfaces",
+ "unable to set the `header complete` flag for %s",
+ hardware->h_ifname);
+ goto end;
+ }
+
+ /* We only want to receive incoming packets */
+ enable = BPF_D_IN;
+ if (ioctl(fd, BIOCSDIRECTION, (caddr_t)&enable) < 0) {
+ log_warn("interfaces",
+ "unable to set packet direction for BPF filter on %s",
+ hardware->h_ifname);
+ goto end;
+ }
+
+ /* Install read filter */
+ if (ioctl(fd, BIOCSETF, (caddr_t)&fprog) < 0) {
+ log_warn("interfaces", "unable to setup BPF filter for %s",
+ hardware->h_ifname);
+ goto end;
+ }
+ /* Install write filter (optional) */
+ if (ioctl(fd, BIOCSETWF, (caddr_t)&fprog) < 0) {
+ log_info("interfaces", "unable to setup write BPF filter for %s",
+ hardware->h_ifname);
+ }
+
+ /* Setup multicast */
+ interfaces_setup_multicast(cfg, hardware->h_ifname, 0);
+
+ hardware->h_sendfd = fd; /* Send */
+
+ levent_hardware_add_fd(hardware, fd); /* Receive */
+ log_debug("interfaces", "interface %s initialized (fd=%d)", hardware->h_ifname,
+ fd);
+ return 0;
+
+end:
+ if (fd >= 0) close(fd);
+ free(buffer);
+ hardware->h_data = NULL;
+ return -1;
+}
+
+/* Ethernet send/receive through BPF */
+static int
+ifbsd_eth_send(struct lldpd *cfg, struct lldpd_hardware *hardware,
+ char *buffer, size_t size)
+{
+ log_debug("interfaces", "send PDU to ethernet device %s (fd=%d)",
+ hardware->h_ifname, hardware->h_sendfd);
+ return write(hardware->h_sendfd,
+ buffer, size);
+}
+
+static int
+ifbsd_eth_recv(struct lldpd *cfg,
+ struct lldpd_hardware *hardware,
+ int fd, char *buffer, size_t size)
+{
+ int n;
+ struct bpf_buffer *bpfbuf = hardware->h_data;
+ struct bpf_hdr *bh;
+ log_debug("interfaces", "receive PDU from ethernet device %s",
+ hardware->h_ifname);
+
+ /* We assume we have only receive one packet (unbuffered mode). Dunno if
+ * this is correct. */
+ if ((n = read(fd, bpfbuf->data, bpfbuf->len)) == -1) {
+ log_warn("interfaces", "error while receiving frame on %s",
+ hardware->h_ifname);
+ hardware->h_rx_discarded_cnt++;
+ return -1;
+ }
+ bh = (struct bpf_hdr*)bpfbuf->data;
+ if (bh->bh_caplen < size)
+ size = bh->bh_caplen;
+ memcpy(buffer, bpfbuf->data + bh->bh_hdrlen, size);
+
+ return size;
+}
+
+static int
+ifbsd_eth_close(struct lldpd *cfg, struct lldpd_hardware *hardware)
+{
+ log_debug("interfaces", "close ethernet device %s",
+ hardware->h_ifname);
+ interfaces_setup_multicast(cfg, hardware->h_ifname, 1);
+ return 0;
+}
+
+static struct lldpd_ops eth_ops = {
+ .send = ifbsd_eth_send,
+ .recv = ifbsd_eth_recv,
+ .cleanup = ifbsd_eth_close,
+};
+
+void
+interfaces_update(struct lldpd *cfg)
+{
+ struct lldpd_hardware *hardware;
+ struct interfaces_device *iface;
+ struct interfaces_device_list *interfaces = NULL;
+ struct interfaces_address_list *addresses = NULL;
+ struct ifaddrs *ifaddrs = NULL, *ifaddr;
+
+ interfaces = malloc(sizeof(struct interfaces_device_list));
+ addresses = malloc(sizeof(struct interfaces_address_list));
+ if (interfaces == NULL || addresses == NULL) {
+ log_warnx("interfaces", "unable to allocate memory");
+ goto end;
+ }
+ TAILQ_INIT(interfaces);
+ TAILQ_INIT(addresses);
+ if (getifaddrs(&ifaddrs) < 0) {
+ log_warnx("interfaces", "unable to get list of interfaces");
+ goto end;
+ }
+
+ for (ifaddr = ifaddrs;
+ ifaddr != NULL;
+ ifaddr = ifaddr->ifa_next) {
+ ifbsd_extract(cfg, interfaces, addresses, ifaddr);
+ }
+ /* Link interfaces together if needed */
+ TAILQ_FOREACH(iface, interfaces, next) {
+ ifbsd_check_bridge(cfg, interfaces, iface);
+ ifbsd_check_bond(cfg, interfaces, iface);
+ ifbsd_check_vlan(cfg, interfaces, iface);
+ ifbsd_check_physical(cfg, interfaces, iface);
+ }
+
+ interfaces_helper_whitelist(cfg, interfaces);
+ interfaces_helper_physical(cfg, interfaces,
+ ð_ops, ifbsd_phys_init);
+#ifdef ENABLE_DOT1
+ interfaces_helper_vlan(cfg, interfaces);
+#endif
+ interfaces_helper_mgmt(cfg, addresses);
+ interfaces_helper_chassis(cfg, interfaces);
+
+ /* Mac/PHY */
+ TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
+ if (!hardware->h_flags) continue;
+ ifbsd_macphy(cfg, hardware);
+ }
+
+end:
+ interfaces_free_devices(interfaces);
+ interfaces_free_addresses(addresses);
+ if (ifaddrs) freeifaddrs(ifaddrs);
+ return;
+
+}