miniupnp/miniupnpd/bsd/getifstats.c
Thomas Bernard 5a3a670e89 miniupnpd/bsd/getifstats.c: fix for DragonFly BSD
struct ifnet is private to kernel code and is hidden from the userland
code unless you define a macro _KERNEL_STRUCTURES.  Although other people
argue that it should be exposed as it is on other BSDs, that's the way
it is on DragonFly BSD.

Thanks to YONETANI Tomokazu for DragonFly BSD patches
2014-03-19 12:25:52 +01:00

137 lines
3.2 KiB
C

/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* author: Ryan Wagoner and Thomas Bernard
* (c) 2006 Ryan Wagoner
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#if defined(__FreeBSD__) || defined(__DragonFly__)
#ifdef __DragonFly__
#define _KERNEL_STRUCTURES
#endif
#include <net/if_var.h>
#endif
#if defined(__DragonFly__)
#include <net/pf/pfvar.h>
#else
#include <net/pfvar.h>
#endif
#include <kvm.h>
#include <fcntl.h>
#include <nlist.h>
#include <sys/queue.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include "../getifstats.h"
#include "../config.h"
static struct nlist list[] = {
{"_ifnet", 0, 0, 0, 0},
{NULL,0, 0, 0, 0}
};
int
getifstats(const char * ifname, struct ifdata * data)
{
#if defined(__FreeBSD__) || defined(__DragonFly__)
struct ifnethead ifh;
#elif defined(__OpenBSD__) || defined(__NetBSD__)
struct ifnet_head ifh;
#else
#error "Dont know if I should use struct ifnethead or struct ifnet_head"
#endif
struct ifnet ifc;
struct ifnet *ifp;
kvm_t *kd;
ssize_t n;
char errstr[_POSIX2_LINE_MAX];
#ifdef ENABLE_GETIFSTATS_CACHING
static time_t cache_timestamp = 0;
static struct ifdata cache_data;
time_t current_time;
#endif
if(!data)
return -1;
data->baudrate = 4200000;
data->opackets = 0;
data->ipackets = 0;
data->obytes = 0;
data->ibytes = 0;
if(!ifname || ifname[0]=='\0')
return -1;
#ifdef ENABLE_GETIFSTATS_CACHING
current_time = time(NULL);
if(current_time == ((time_t)-1)) {
syslog(LOG_ERR, "getifstats() : time() error : %m");
} else {
if(current_time < cache_timestamp + GETIFSTATS_CACHING_DURATION) {
memcpy(data, &cache_data, sizeof(struct ifdata));
return 0;
}
}
#endif
/*kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);*/
kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errstr);
if(!kd)
{
syslog (LOG_ERR, "getifstats() : kvm_open(): %s", errstr);
return -1;
}
if(kvm_nlist(kd, list) < 0)
{
syslog(LOG_ERR, "getifstats() : kvm_nlist(): FAILED");
goto error;
}
if(!list[0].n_value)
{
syslog(LOG_ERR, "getifstats() : n_value(): FAILED");
goto error;
}
n = kvm_read(kd, list[0].n_value, &ifh, sizeof(ifh));
if(n<0)
{
syslog(LOG_ERR, "getifstats() : kvm_read(head): %s", kvm_geterr(kd));
goto error;
}
for(ifp = TAILQ_FIRST(&ifh); ifp; ifp = TAILQ_NEXT(&ifc, if_list))
{
n = kvm_read(kd, (u_long)ifp, &ifc, sizeof(ifc));
if(n<0)
{
syslog(LOG_ERR, "getifstats() : kvm_read(element): %s", kvm_geterr(kd));
goto error;
}
if(strcmp(ifname, ifc.if_xname) == 0)
{
/* found the right interface */
data->opackets = ifc.if_data.ifi_opackets;
data->ipackets = ifc.if_data.ifi_ipackets;
data->obytes = ifc.if_data.ifi_obytes;
data->ibytes = ifc.if_data.ifi_ibytes;
data->baudrate = ifc.if_data.ifi_baudrate;
kvm_close(kd);
#ifdef ENABLE_GETIFSTATS_CACHING
if(current_time!=((time_t)-1)) {
cache_timestamp = current_time;
memcpy(&cache_data, data, sizeof(struct ifdata));
}
#endif
return 0; /* ok */
}
}
error:
kvm_close(kd);
return -1; /* not found or error */
}