1/* $Id: getifstats.c,v 1.6 2012/02/11 13:10:57 nanard Exp $ */
2/*
3 * MiniUPnP project
4 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
5 * (c) 2009 Jardel Weyrich
6 * This software is subject to the conditions detailed
7 * in the LICENCE file provided within the distribution
8 */
9
10#include <syslog.h>
11#include <sys/sysctl.h>
12#include <sys/types.h>
13#include <netinet/in.h>
14#include <net/if.h>
15#include <net/if_types.h>
16#include <net/route.h>
17#include <nlist.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21
22#include "../getifstats.h"
23#include "../config.h"
24
25int getifstats(const char * ifname, struct ifdata * data) {
26	int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, if_nametoindex(ifname) };
27	const size_t mib_len = sizeof(mib) / sizeof(mib[0]);
28	size_t needed;
29	char *buf, *end, *p;
30	struct if_msghdr *ifm;
31	struct if_data ifdata;
32#ifdef ENABLE_GETIFSTATS_CACHING
33	static time_t cache_timestamp = 0;
34	static struct ifdata cache_data;
35	time_t current_time;
36#endif
37
38	if (data == NULL || ifname == NULL || ifname[0] == '\0')
39		return -1; /* error */
40
41	data->baudrate = 4200000;
42	data->opackets = 0;
43	data->ipackets = 0;
44	data->obytes = 0;
45	data->ibytes = 0;
46
47#ifdef ENABLE_GETIFSTATS_CACHING
48	current_time = time(NULL);
49	if (current_time == ((time_t)-1)) {
50		syslog(LOG_ERR, "getifstats() : time() error : %m");
51	} else {
52		if (current_time < cache_timestamp + GETIFSTATS_CACHING_DURATION) {
53			memcpy(data, &cache_data, sizeof(struct ifdata));
54			return 0;
55		}
56	}
57#endif
58
59	if (sysctl(mib, mib_len, NULL, &needed, NULL, 0) == -1) {
60		syslog(LOG_ERR, "sysctl(): %m");
61		return -1;
62	}
63	buf = (char *) malloc(needed);
64	if (buf == NULL)
65		return -1; /* error */
66	if (sysctl(mib, mib_len, buf, &needed, NULL, 0) == -1) {
67		syslog(LOG_ERR, "sysctl(): %m");
68		free(buf);
69		return -1; /* error */
70	} else {
71		for (end = buf + needed, p = buf; p < end; p += ifm->ifm_msglen) {
72			ifm = (struct if_msghdr *) p;
73			if (ifm->ifm_type == RTM_IFINFO && ifm->ifm_data.ifi_type == IFT_ETHER) {
74				ifdata = ifm->ifm_data;
75				data->opackets = ifdata.ifi_opackets;
76				data->ipackets = ifdata.ifi_ipackets;
77				data->obytes = ifdata.ifi_obytes;
78				data->ibytes = ifdata.ifi_ibytes;
79				data->baudrate = ifdata.ifi_baudrate;
80				free(buf);
81#ifdef ENABLE_GETIFSTATS_CACHING
82				if (current_time!=((time_t)-1)) {
83					cache_timestamp = current_time;
84					memcpy(&cache_data, data, sizeof(struct ifdata));
85				}
86#endif
87				return 0; /* found, ok */
88			}
89		}
90	}
91	free(buf);
92	return -1; /* not found or error */
93}
94
95