mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-11-01 19:07:47 +00:00
236 lines
5.9 KiB
C
236 lines
5.9 KiB
C
#include "udevmand.h"
|
|
|
|
struct avl_tree iface_tree = AVL_TREE_INIT(iface_tree, avl_strcmp, false, NULL);
|
|
|
|
struct iface_ip {
|
|
struct list_head list;
|
|
char ip[];
|
|
};
|
|
|
|
struct iface {
|
|
struct avl_node avl;
|
|
int alive;
|
|
char name[IF_NAMESIZE];
|
|
struct rtnl_link_stats stats;
|
|
struct rtnl_link_stats stats_old;
|
|
struct list_head ipv6, ipv4;
|
|
uint8_t addr[ETH_ALEN];
|
|
};
|
|
|
|
static struct iface*
|
|
iface_find(char *name)
|
|
{
|
|
struct iface *iface = avl_find_element(&iface_tree, name, iface, avl);
|
|
|
|
if (iface) {
|
|
iface->alive = 1;
|
|
return iface;
|
|
}
|
|
iface = malloc(sizeof(*iface));
|
|
if (!iface)
|
|
return NULL;
|
|
memset(iface, 0, sizeof(*iface));
|
|
iface->alive = 1;
|
|
iface->avl.key = strcpy(iface->name, name);
|
|
INIT_LIST_HEAD(&iface->ipv4);
|
|
INIT_LIST_HEAD(&iface->ipv6);
|
|
avl_insert(&iface_tree, &iface->avl);
|
|
return iface;
|
|
}
|
|
|
|
void
|
|
iface_done(void)
|
|
{
|
|
struct iface *i, *t;
|
|
|
|
avl_for_each_element_safe(&iface_tree, i, avl, t) {
|
|
avl_delete(&iface_tree, &i->avl);
|
|
free(i);
|
|
}
|
|
}
|
|
|
|
static void
|
|
iface_get(void)
|
|
{
|
|
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
|
|
struct ifaddrs *ifaddr, *ifa;
|
|
int n;
|
|
|
|
if (getifaddrs(&ifaddr) == -1) {
|
|
ULOG_ERR("failed to getifaddrs\n");
|
|
return;
|
|
}
|
|
|
|
for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
|
|
char host[NI_MAXHOST];
|
|
struct iface *iface;
|
|
int family, s;
|
|
|
|
if (ifa->ifa_addr == NULL)
|
|
continue;
|
|
|
|
if ((ifa->ifa_flags & IFF_UP) == 0)
|
|
continue;
|
|
|
|
if (ifa->ifa_flags & IFF_LOOPBACK)
|
|
continue;
|
|
|
|
family = ifa->ifa_addr->sa_family;
|
|
|
|
iface = iface_find(ifa->ifa_name);
|
|
if (!iface)
|
|
continue;
|
|
|
|
if (family == AF_INET || family == AF_INET6) {
|
|
struct iface_ip *ip;
|
|
|
|
s = getnameinfo(ifa->ifa_addr,
|
|
(family == AF_INET) ? sizeof(struct sockaddr_in) :
|
|
sizeof(struct sockaddr_in6),
|
|
host, NI_MAXHOST,
|
|
NULL, 0, NI_NUMERICHOST);
|
|
if (s)
|
|
continue;
|
|
ip = malloc(sizeof(*ip) + strlen(host) + 1);
|
|
if (!ip)
|
|
continue;
|
|
strcpy(ip->ip, host);
|
|
if (family == AF_INET)
|
|
list_add(&ip->list, &iface->ipv4);
|
|
else
|
|
list_add(&ip->list, &iface->ipv6);
|
|
} else if (family == AF_PACKET && ifa->ifa_data != NULL) {
|
|
struct rtnl_link_stats *stats = ifa->ifa_data;
|
|
struct ifreq s;
|
|
|
|
memcpy(&iface->stats, stats, sizeof(*stats));
|
|
memset(iface->addr, 0, ETH_ALEN);
|
|
if (fd) {
|
|
strcpy(s.ifr_name, ifa->ifa_name);
|
|
if (!ioctl(fd, SIOCGIFHWADDR, &s))
|
|
memcpy(iface->addr, s.ifr_addr.sa_data, ETH_ALEN);
|
|
}
|
|
}
|
|
}
|
|
|
|
freeifaddrs(ifaddr);
|
|
if (fd)
|
|
close(fd);
|
|
}
|
|
|
|
static void
|
|
iface_flush(void)
|
|
{
|
|
struct iface *iface, *tmp;
|
|
|
|
avl_for_each_element_safe(&iface_tree, iface, avl, tmp) {
|
|
struct iface_ip *ip, *tmp;
|
|
|
|
list_for_each_entry_safe(ip, tmp, &iface->ipv4, list) {
|
|
list_del(&ip->list);
|
|
free(ip);
|
|
}
|
|
|
|
list_for_each_entry_safe(ip, tmp, &iface->ipv6, list) {
|
|
list_del(&ip->list);
|
|
free(ip);
|
|
}
|
|
if (!iface->alive) {
|
|
avl_delete(&iface_tree, &iface->avl);
|
|
free(iface);
|
|
} else {
|
|
iface->alive = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int get_counter_delta(__u32 new, __u32 old)
|
|
{
|
|
uint32_t delta;
|
|
|
|
if (new < old)
|
|
delta = UINT32_MAX - old + new;
|
|
else
|
|
delta = new - old;
|
|
|
|
|
|
return delta > 0 ? delta : 0;
|
|
}
|
|
|
|
void
|
|
iface_dump(int delta)
|
|
{
|
|
struct iface *iface;
|
|
|
|
iface_get();
|
|
|
|
blob_buf_init(&b, 0);
|
|
avl_for_each_element(&iface_tree, iface, avl) {
|
|
struct iface_ip *ip;
|
|
void *c, *d;
|
|
|
|
if (!iface->alive)
|
|
continue;
|
|
|
|
c = blobmsg_open_table(&b, interface_resolve(iface->name));
|
|
blobmsg_add_mac(&b, "hwaddr", iface->addr);
|
|
if (!list_empty(&iface->ipv4)) {
|
|
d = blobmsg_open_array(&b, "ipv4");
|
|
list_for_each_entry(ip, &iface->ipv4, list)
|
|
blobmsg_add_string(&b, NULL, ip->ip);
|
|
blobmsg_close_array(&b, d);
|
|
}
|
|
|
|
if (!list_empty(&iface->ipv4)) {
|
|
d = blobmsg_open_array(&b, "ipv6");
|
|
list_for_each_entry(ip, &iface->ipv6, list)
|
|
blobmsg_add_string(&b, NULL, ip->ip);
|
|
blobmsg_close_array(&b, d);
|
|
}
|
|
|
|
d = blobmsg_open_table(&b, "counters");
|
|
blobmsg_add_u64(&b, "rx_packets", iface->stats.rx_packets);
|
|
blobmsg_add_u64(&b, "tx_packets", iface->stats.tx_packets);
|
|
blobmsg_add_u64(&b, "rx_bytes", iface->stats.rx_bytes);
|
|
blobmsg_add_u64(&b, "tx_bytes", iface->stats.tx_bytes);
|
|
blobmsg_add_u64(&b, "rx_errors", iface->stats.rx_errors);
|
|
blobmsg_add_u64(&b, "tx_errors", iface->stats.tx_errors);
|
|
blobmsg_add_u64(&b, "rx_dropped", iface->stats.rx_dropped);
|
|
blobmsg_add_u64(&b, "tx_dropped", iface->stats.tx_dropped);
|
|
blobmsg_add_u64(&b, "multicast", iface->stats.multicast);
|
|
blobmsg_add_u64(&b, "collisions", iface->stats.collisions);
|
|
blobmsg_close_table(&b, d);
|
|
|
|
if (delta) {
|
|
d = blobmsg_open_table(&b, "deltas");
|
|
blobmsg_add_u32(&b, "rx_packets",
|
|
get_counter_delta(iface->stats.rx_packets, iface->stats_old.rx_packets));
|
|
blobmsg_add_u32(&b, "tx_packets",
|
|
get_counter_delta(iface->stats.tx_packets, iface->stats_old.tx_packets));
|
|
blobmsg_add_u32(&b, "rx_bytes",
|
|
get_counter_delta(iface->stats.rx_bytes, iface->stats_old.rx_bytes));
|
|
blobmsg_add_u32(&b, "tx_bytes",
|
|
get_counter_delta(iface->stats.tx_bytes, iface->stats_old.tx_bytes));
|
|
blobmsg_add_u32(&b, "rx_errors",
|
|
get_counter_delta(iface->stats.rx_errors, iface->stats_old.rx_errors));
|
|
blobmsg_add_u32(&b, "tx_errors",
|
|
get_counter_delta(iface->stats.tx_errors, iface->stats_old.tx_errors));
|
|
blobmsg_add_u32(&b, "rx_dropped",
|
|
get_counter_delta(iface->stats.rx_dropped, iface->stats_old.rx_dropped));
|
|
blobmsg_add_u32(&b, "tx_dropped",
|
|
get_counter_delta(iface->stats.tx_dropped, iface->stats_old.tx_dropped));
|
|
blobmsg_add_u32(&b, "multicast",
|
|
get_counter_delta(iface->stats.multicast, iface->stats_old.multicast));
|
|
blobmsg_add_u32(&b, "collisions",
|
|
get_counter_delta(iface->stats.collisions, iface->stats_old.collisions));
|
|
blobmsg_close_table(&b, d);
|
|
}
|
|
memcpy(&iface->stats_old, &iface->stats, sizeof(iface->stats));
|
|
|
|
bridge_dump_if(iface->name);
|
|
blobmsg_close_table(&b, c);
|
|
}
|
|
|
|
iface_flush();
|
|
}
|