diff options
Diffstat (limited to 'ffd/netif.c')
-rw-r--r-- | ffd/netif.c | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/ffd/netif.c b/ffd/netif.c new file mode 100644 index 0000000..c63b19b --- /dev/null +++ b/ffd/netif.c @@ -0,0 +1,182 @@ +/* + Copyright (c) 2012, Matthias Schiffer <mschiffer@universe-factory.net> + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define _GNU_SOURCE + +#include "netif.h" +#include "util.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <linux/rtnetlink.h> + +#include <net/if.h> + +#include <sys/stat.h> +#include <sys/types.h> + + +#define SYSFS_PATH_MAX 256 +#define SYSFS_CLASS_NET "/sys/class/net" + + +static bool netif_file_read(const char *ifname, const char *file, const char *format, ...) { + char filename[SYSFS_PATH_MAX]; + + snprintf(filename, SYSFS_PATH_MAX, SYSFS_CLASS_NET"/%s/%s", ifname, file); + + va_list ap; + va_start(ap, format); + bool ret = file_readv(filename, format, ap); + va_end(ap); + + return ret; +} + +static bool netif_file_exists(const char *ifname, const char *file) { + char filename[SYSFS_PATH_MAX]; + + snprintf(filename, SYSFS_PATH_MAX, SYSFS_CLASS_NET"/%s/%s", ifname, file); + + struct stat st; + return (stat(filename, &st) == 0); +} + +bool netif_is_mesh(const char *ifname) { + return netif_file_exists(ifname, "mesh"); +} + +char* netif_get_mesh(const char *ifname) { + char *mesh = NULL; + + if (!netif_file_read(ifname, "batman_adv/mesh_iface", "%as", &mesh) || !strcmp(mesh, "none")) { + free(mesh); + return NULL; + } + + return mesh; +} + +char* netif_get_bridge(const char *ifname) { + char filename[SYSFS_PATH_MAX], filename2[SYSFS_PATH_MAX] = {0}; + + snprintf(filename, SYSFS_PATH_MAX, SYSFS_CLASS_NET"/%s/brport/bridge", ifname); + if (readlink(filename, filename2, sizeof(filename2)) < 0) + return NULL; + + return strdup(basename(filename2)); +} + +eth_addr_t netif_get_eth_addr(const char *ifname) { + eth_addr_t ret; + uint8_t *a = ret.d; + + if (!netif_file_read(ifname, "address", "%x:%x:%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5])) + return ETH_ADDR_UNSPEC; + + return ret; +} + +struct in6_addr netif_get_addr(unsigned ifindex, int scope) { + struct msg { + struct nlmsghdr nh; + struct ifaddrmsg addr; + uint8_t attrbuf[16384]; + } msg; + + memset(&msg, 0, sizeof(msg)); + + int rtnetlink_sk = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); + + msg.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); + msg.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; + msg.nh.nlmsg_type = RTM_GETADDR; + + msg.addr.ifa_family = AF_INET6; + + if(write(rtnetlink_sk, &msg, msg.nh.nlmsg_len) <= 0) { + fprintf(stderr, "error: write: %m\n"); + close(rtnetlink_sk); + return in6addr_any; + } + + int readlen = read(rtnetlink_sk, &msg, sizeof(msg)); + + if (readlen <= 0) { + fprintf(stderr, "error: read: %m\n"); + close(rtnetlink_sk); + return in6addr_any; + } + + close(rtnetlink_sk); + + struct msg *chunk; + + for (chunk = &msg; readlen > sizeof(struct nlmsghdr);) { + int len = chunk->nh.nlmsg_len - sizeof(struct nlmsghdr); + + if (len < sizeof(struct ifaddrmsg) || readlen < len) + return in6addr_any; + + if (!NLMSG_OK(&chunk->nh, readlen)) + return in6addr_any; + + if (chunk->nh.nlmsg_type == RTM_NEWADDR && chunk->addr.ifa_scope == scope && chunk->addr.ifa_index == ifindex) { + struct rtattr *rta = (struct rtattr *)IFA_RTA(&chunk->addr); + int rtattrlen = IFA_PAYLOAD(&chunk->nh); + + for (; RTA_OK(rta, rtattrlen); rta = RTA_NEXT(rta, rtattrlen)) { + if(rta->rta_type == IFA_ADDRESS && rta->rta_len == RTA_LENGTH(16)) { + struct in6_addr ret; + memcpy(ret.s6_addr, RTA_DATA(rta), 16); + return ret; + } + } + } + + readlen -= NLMSG_ALIGN(chunk->nh.nlmsg_len); + chunk = (struct msg*)((uint8_t*)chunk + NLMSG_ALIGN(chunk->nh.nlmsg_len)); + } + + return in6addr_any; +} + +void netif_foreach(netif_cb cb, void *arg) { + struct if_nameindex *ifaces = if_nameindex(); + + if (!ifaces) { + fprintf(stderr, "error: if_nameindex: %m\n"); + return; + } + + int i; + for (i = 0; ifaces[i].if_name; i++) + cb(ifaces[i].if_name, ifaces[i].if_index, arg); + + if_freenameindex(ifaces); +} |