summaryrefslogtreecommitdiffstats
path: root/ffd/netif.c
diff options
context:
space:
mode:
Diffstat (limited to 'ffd/netif.c')
-rw-r--r--ffd/netif.c182
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);
+}