diff options
Diffstat (limited to '')
-rw-r--r-- | src/daemon/interfaces-solaris.c | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/src/daemon/interfaces-solaris.c b/src/daemon/interfaces-solaris.c new file mode 100644 index 0000000..5e3ae3c --- /dev/null +++ b/src/daemon/interfaces-solaris.c @@ -0,0 +1,174 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2013 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 <sys/sockio.h> +#include <net/if_types.h> + +/* Solaris comes with libdladm which seems to be handy to get all the necessary + * information. Unfortunately, this library needs a special device file and a + * Unix socket to a daemon. This is a bit difficult to use it in a + * privilege-separated daemon. Therefore, we keep using ioctl(). This should + * also improve compatibility with older versions of Solaris. + */ + +static void +ifsolaris_extract(struct lldpd *cfg, struct interfaces_device_list *interfaces, + struct interfaces_address_list *addresses, struct lifreq *lifr) +{ + int flags = 0; + int index = 0; + struct interfaces_address *address = NULL; + struct interfaces_device *device = NULL; + + sa_family_t lifr_af = lifr->lifr_addr.ss_family; + struct lifreq lifrl = { .lifr_name = {} }; + strlcpy(lifrl.lifr_name, lifr->lifr_name, sizeof(lifrl.lifr_name)); + + /* Flags */ + if (ioctl(cfg->g_sock, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) { + log_warn("interfaces", "unable to get flags for %s", lifrl.lifr_name); + return; + } + flags = lifrl.lifr_flags; + + /* Index */ + if (ioctl(cfg->g_sock, SIOCGLIFINDEX, (caddr_t)&lifrl) < 0) { + log_warn("interfaces", "unable to get index for %s", lifrl.lifr_name); + return; + } + index = lifrl.lifr_index; + + /* Record the address */ + if ((address = malloc(sizeof(struct interfaces_address))) == NULL) { + log_warn("interfaces", "not enough memory for a new IP address on %s", + lifrl.lifr_name); + return; + } + address->flags = flags; + address->index = index; + memcpy(&address->address, &lifr->lifr_addr, + (lifr_af == AF_INET) ? sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6)); + TAILQ_INSERT_TAIL(addresses, address, next); + + /* Hardware address */ + if (ioctl(cfg->g_sock, SIOCGLIFHWADDR, (caddr_t)&lifrl) < 0) { + log_debug("interfaces", "unable to get hardware address for %s", + lifrl.lifr_name); + return; + } + struct sockaddr_dl *saddrdl = (struct sockaddr_dl *)&lifrl.lifr_addr; + if (saddrdl->sdl_type != 4) { + log_debug("interfaces", "skip %s: not an ethernet device (%d)", + lifrl.lifr_name, saddrdl->sdl_type); + return; + } + + /* Handle the interface */ + if ((device = calloc(1, sizeof(struct interfaces_device))) == NULL) { + log_warn("interfaces", "unable to allocate memory for %s", + lifrl.lifr_name); + return; + } + + device->name = strdup(lifrl.lifr_name); + device->flags = flags; + device->index = index; + device->type = IFACE_PHYSICAL_T; + device->address = malloc(ETHER_ADDR_LEN); + if (device->address) memcpy(device->address, LLADDR(saddrdl), ETHER_ADDR_LEN); + + /* MTU */ + if (ioctl(cfg->g_sock, SIOCGLIFMTU, (caddr_t)&lifrl) < 0) { + log_debug("interfaces", "unable to get MTU for %s", lifrl.lifr_name); + } else + device->mtu = lifrl.lifr_mtu; + + TAILQ_INSERT_TAIL(interfaces, device, next); +} + +extern struct lldpd_ops bpf_ops; +void +interfaces_update(struct lldpd *cfg) +{ + struct lldpd_hardware *hardware; + caddr_t buffer = NULL; + struct interfaces_device_list *interfaces; + struct interfaces_address_list *addresses; + 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); + + struct lifnum lifn = { .lifn_family = AF_UNSPEC, .lifn_flags = LIFC_ENABLED }; + if (ioctl(cfg->g_sock, SIOCGLIFNUM, &lifn) < 0) { + log_warn("interfaces", "unable to get the number of interfaces"); + goto end; + } + + size_t bufsize = lifn.lifn_count * sizeof(struct lifreq); + if ((buffer = malloc(bufsize)) == NULL) { + log_warn("interfaces", "unable to allocate buffer to get interfaces"); + goto end; + } + + struct lifconf lifc = { .lifc_family = AF_UNSPEC, + .lifc_flags = LIFC_ENABLED, + .lifc_len = bufsize, + .lifc_buf = buffer }; + if (ioctl(cfg->g_sock, SIOCGLIFCONF, (char *)&lifc) < 0) { + log_warn("interfaces", "unable to get the network interfaces"); + goto end; + } + + int num = lifc.lifc_len / sizeof(struct lifreq); + if (num > lifn.lifn_count) num = lifn.lifn_count; + log_debug("interfaces", "got %d interfaces", num); + + struct lifreq *lifrp = (struct lifreq *)buffer; + for (int n = 0; n < num; n++, lifrp++) + ifsolaris_extract(cfg, interfaces, addresses, lifrp); + + interfaces_helper_allowlist(cfg, interfaces); + interfaces_helper_physical(cfg, interfaces, &bpf_ops, ifbpf_phys_init); + interfaces_helper_mgmt(cfg, addresses, interfaces); + interfaces_helper_chassis(cfg, interfaces); + + /* Mac/PHY */ + TAILQ_FOREACH (hardware, &cfg->g_hardware, h_entries) { + if (!hardware->h_flags) continue; + /* TODO: mac/phy for Solaris */ + interfaces_helper_promisc(cfg, hardware); + } + +end: + free(buffer); + interfaces_free_devices(interfaces); + interfaces_free_addresses(addresses); +} + +void +interfaces_cleanup(struct lldpd *cfg) +{ +} |