206 lines
5.6 KiB
C
206 lines
5.6 KiB
C
/*
|
|
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"
|
|
#define SYSFS_BATADV "/sys/kernel/debug/batman_adv"
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
static bool batadv_file_read(const char *ifname, const char *file, const char *format, ...) {
|
|
char filename[SYSFS_PATH_MAX];
|
|
|
|
snprintf(filename, SYSFS_PATH_MAX, SYSFS_BATADV"/%s/%s", ifname, file);
|
|
|
|
va_list ap;
|
|
va_start(ap, format);
|
|
bool ret = file_readv(filename, format, ap);
|
|
va_end(ap);
|
|
|
|
return ret;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
eth_addr_t netif_mesh_get_primary_addr(const char *ifname) {
|
|
eth_addr_t ret;
|
|
uint8_t *a = ret.d;
|
|
|
|
if (!batadv_file_read(ifname, "originators", "%*[^,], MainIF/MAC: %*[^/]/%x:%x:%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]))
|
|
return ETH_ADDR_UNSPEC;
|
|
|
|
return ret;
|
|
}
|