From e42b0b2d48637231fdcc51ad584c1bd786c09832 Mon Sep 17 00:00:00 2001 From: Julian Kornberger Date: Mon, 18 Jul 2016 18:06:12 +0200 Subject: [PATCH 1/7] Add package gluon-airtime on ath9k: Works fine on ath10k: Does not return any data --- package/gluon-airtime/Makefile | 40 ++++++ package/gluon-airtime/src/Makefile | 22 +++ package/gluon-airtime/src/airtime-test.c | 32 +++++ package/gluon-airtime/src/airtime.c | 174 +++++++++++++++++++++++ package/gluon-airtime/src/airtime.h | 24 ++++ package/gluon-airtime/src/respondd.c | 69 +++++++++ 6 files changed, 361 insertions(+) create mode 100644 package/gluon-airtime/Makefile create mode 100644 package/gluon-airtime/src/Makefile create mode 100644 package/gluon-airtime/src/airtime-test.c create mode 100644 package/gluon-airtime/src/airtime.c create mode 100644 package/gluon-airtime/src/airtime.h create mode 100644 package/gluon-airtime/src/respondd.c diff --git a/package/gluon-airtime/Makefile b/package/gluon-airtime/Makefile new file mode 100644 index 00000000..479a419e --- /dev/null +++ b/package/gluon-airtime/Makefile @@ -0,0 +1,40 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-airtime +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) +PKG_BUILD_DEPENDS := respondd + +include $(GLUONDIR)/include/package.mk + +define Package/gluon-airtime + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Add airtime to respondd + DEPENDS:=+respondd +libnl-tiny +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +define Build/Configure +endef + + +TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include/libnl-tiny + +define Build/Compile + CFLAGS="$(TARGET_CFLAGS)" CPPFLAGS="$(TARGET_CPPFLAGS)" $(MAKE) -C $(PKG_BUILD_DIR) $(TARGET_CONFIGURE_OPTS) +endef + + +define Package/gluon-airtime/install + $(INSTALL_DIR) $(1)/lib/gluon/respondd + $(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/lib/gluon/respondd/airtime.so +endef + +$(eval $(call BuildPackage,gluon-airtime)) diff --git a/package/gluon-airtime/src/Makefile b/package/gluon-airtime/src/Makefile new file mode 100644 index 00000000..e265638f --- /dev/null +++ b/package/gluon-airtime/src/Makefile @@ -0,0 +1,22 @@ +ifeq ($(origin CC),default) +CC = gcc +endif + +# standard compliance +CFLAGS += -std=c99 + +# warnings +CFLAGS += -Wall -Wextra -Wformat=2 -Wshadow -Wpointer-arith +CFLAGS += -pedantic + +all: respondd.so + +# sudo apt install libnl-3-dev +airtime-test: airtime-test.c airtime.c airtime.h + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -fPIC -D_GNU_SOURCE -lnl-tiny -o $@ airtime.c airtime-test.c $(LDLIBS) + +respondd.so: respondd.c airtime.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -lnl-tiny -o $@ airtime.c respondd.c $(LDLIBS) + +clean: + rm -rf *.so airtime-test diff --git a/package/gluon-airtime/src/airtime-test.c b/package/gluon-airtime/src/airtime-test.c new file mode 100644 index 00000000..088a9c25 --- /dev/null +++ b/package/gluon-airtime/src/airtime-test.c @@ -0,0 +1,32 @@ +#include +#include /* sleep */ +#include "airtime.h" + +void print_result(struct airtime_result *); + +int main(int argc, char *argv[]) { + struct airtime *a; + + if (argc != 3) { + fprintf(stderr,"Usage: %s \n", argv[0]); + return 1; + } + + while (1) { + a = get_airtime(argv[1], argv[2]); + print_result(&a->radio0); + print_result(&a->radio1); + sleep(1); + } +} + +void print_result(struct airtime_result *result){ + printf("freq=%d\tnoise=%d\tbusy=%lld\tactive=%lld\trx=%lld\ttx=%lld\n", + result->frequency, + result->noise, + result->busy_time.current, + result->active_time.current, + result->rx_time.current, + result->tx_time.current + ); +} diff --git a/package/gluon-airtime/src/airtime.c b/package/gluon-airtime/src/airtime.c new file mode 100644 index 00000000..7d3fbed9 --- /dev/null +++ b/package/gluon-airtime/src/airtime.c @@ -0,0 +1,174 @@ +/* + Copyright (c) 2016, Julian Kornberger + Martin Müller + 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. +*/ + +#include +#include +#include +#include +#include +#include + +#include "airtime.h" + +static struct airtime cur_airtime = { + { .frequency = 0 }, + { .frequency = 0 }, +}; + +/* + * Excerpt from nl80211.h: + * enum nl80211_survey_info - survey information + * + * These attribute types are used with %NL80211_ATTR_SURVEY_INFO + * when getting information about a survey. + * + * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved + * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel + * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm) + * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used + * @NL80211_SURVEY_INFO_CHANNEL_TIME: amount of time (in ms) that the radio + * spent on this channel + * @NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY: amount of the time the primary + * channel was sensed busy (either due to activity or energy detect) + * @NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: amount of time the extension + * channel was sensed busy + * @NL80211_SURVEY_INFO_CHANNEL_TIME_RX: amount of time the radio spent + * receiving data + * @NL80211_SURVEY_INFO_CHANNEL_TIME_TX: amount of time the radio spent + * transmitting data + * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number + * currently defined + * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use + */ + +static int survey_airtime_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1]; + static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = { + [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 }, + [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 }, + }; + + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct airtime_result *result = (struct airtime_result *) arg; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),genlmsg_attrlen(gnlh, 0), NULL); + + if (!tb[NL80211_ATTR_SURVEY_INFO]) { + fprintf(stderr, "survey data missing!\n"); + goto abort; + } + + if(nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX, tb[NL80211_ATTR_SURVEY_INFO], survey_policy)) { + fprintf(stderr, "failed to parse nested attributes!\n"); + goto abort; + } + + // Channel active? + if(!sinfo[NL80211_SURVEY_INFO_IN_USE]){ + goto abort; + } + + uint64_t frequency = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]); + + if (frequency != result->frequency) { + // channel changed, restart at zero + result->frequency = frequency; + result->active_time.offset = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]); + result->busy_time.offset = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]); + result->rx_time.offset = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]); + result->tx_time.offset = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]); + result->active_time.current = 0; + result->busy_time.current = 0; + result->rx_time.current = 0; + result->tx_time.current = 0; + } else { + result->active_time.current = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]) - result->active_time.offset; + result->busy_time.current = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]) - result->busy_time.offset; + result->rx_time.current = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]) - result->rx_time.offset; + result->tx_time.current = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]) - result->tx_time.offset; + } + + result->noise = nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]); + +abort: + return NL_SKIP; +} + +static int get_airtime_for_interface(struct airtime_result *result, const char *interface) { + int error = 0; + int ctrl, ifx, flags; + struct nl_sock *sk = NULL; + struct nl_msg *msg = NULL; + enum nl80211_commands cmd; + +#define CHECK(x) { if (!(x)) { fprintf(stderr, "airtime.c: error on line %d\n", __LINE__); error = 1; goto out; } } + + CHECK(sk = nl_socket_alloc()); + CHECK(genl_connect(sk) >= 0); + + CHECK(ctrl = genl_ctrl_resolve(sk, NL80211_GENL_NAME)); + CHECK(nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, survey_airtime_handler, result) == 0); + CHECK(msg = nlmsg_alloc()); + + /* device does not exist */ + if (!(ifx = if_nametoindex(interface))){ + error = -1; + goto out; + } + + cmd = NL80211_CMD_GET_SURVEY; + flags = 0; + flags |= NLM_F_DUMP; + + /* TODO: check return? */ + genlmsg_put(msg, 0, 0, ctrl, 0, flags, cmd, 0); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifx); + + CHECK(nl_send_auto_complete(sk, msg) >= 0); + CHECK(nl_recvmsgs_default(sk) >= 0); + +#undef CHECK + +nla_put_failure: +out: + if (msg) + nlmsg_free(msg); + + if (sk) + nl_socket_free(sk); + + return error; +} + +struct airtime* get_airtime(const char *wifi_0_dev, const char *wifi_1_dev) { + get_airtime_for_interface(&cur_airtime.radio0, wifi_0_dev); + get_airtime_for_interface(&cur_airtime.radio1, wifi_1_dev); + + return &cur_airtime; +} diff --git a/package/gluon-airtime/src/airtime.h b/package/gluon-airtime/src/airtime.h new file mode 100644 index 00000000..4a1347c1 --- /dev/null +++ b/package/gluon-airtime/src/airtime.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +struct airtime_time { + uint64_t current; + uint64_t offset; +}; + +struct airtime_result { + uint32_t frequency; + uint8_t noise; + struct airtime_time active_time; + struct airtime_time busy_time; + struct airtime_time rx_time; + struct airtime_time tx_time; +}; + +struct airtime { + struct airtime_result radio0; + struct airtime_result radio1; +}; + +struct airtime* get_airtime(const char *radio0, const char *radio1); diff --git a/package/gluon-airtime/src/respondd.c b/package/gluon-airtime/src/respondd.c new file mode 100644 index 00000000..0f62afd9 --- /dev/null +++ b/package/gluon-airtime/src/respondd.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include + +#include "airtime.h" + +static const char const *wifi_0_dev = "client0"; +static const char const *wifi_1_dev = "client1"; + +void fill_airtime_json(struct airtime_result *air, struct json_object* wireless){ + struct json_object *result = NULL, *obj = NULL; + + obj = json_object_new_object(); + if(!obj) + goto error; +#define JSON_ADD_INT64(value,key) {result = json_object_new_int64(value); json_object_object_add(obj,key,result);} + result = json_object_new_int(air->frequency); + if(!result) + goto error; + json_object_object_add(obj,"frequency",result); + + JSON_ADD_INT64(air->active_time.current,"active") + JSON_ADD_INT64(air->busy_time.current,"busy") + JSON_ADD_INT64(air->rx_time.current,"rx") + JSON_ADD_INT64(air->tx_time.current,"tx") + + result = json_object_new_int(air->noise); + json_object_object_add(obj,"noise",result); + +error: + if(air->frequency >= 2400 && air->frequency < 2500) + json_object_object_add(wireless, "airtime24", obj); + else if (air->frequency >= 5000 && air->frequency < 6000) + json_object_object_add(wireless, "airtime5", obj); +} + +static struct json_object *respondd_provider_statistics(void) { + struct airtime *airtime = NULL; + struct json_object *result = NULL, *wireless = NULL; + + airtime = get_airtime(wifi_0_dev, wifi_1_dev); + if (!airtime) + return NULL; + + result = json_object_new_object(); + if (!result) + return NULL; + + wireless = json_object_new_object(); + if (!wireless){ + json_object_put(result); + return NULL; + } + + if (airtime->radio0.frequency) + fill_airtime_json(&airtime->radio0, wireless); + + if (airtime->radio1.frequency) + fill_airtime_json(&airtime->radio1, wireless); + + json_object_object_add(result, "wireless", wireless); + return result; +} + +const struct respondd_provider_info respondd_providers[] = { + {"statistics", respondd_provider_statistics}, + {0, 0}, +}; From 196e8f7c4e470b15e0eb89bc33dae1c905d8913a Mon Sep 17 00:00:00 2001 From: Jan-Philipp Litza Date: Sun, 4 Dec 2016 18:30:58 +0100 Subject: [PATCH 2/7] gluon-airtime: Improve code style, remove offset/current construction --- package/gluon-airtime/src/airtime-test.c | 18 ++++------- package/gluon-airtime/src/airtime.c | 41 ++++++------------------ package/gluon-airtime/src/airtime.h | 13 +++----- package/gluon-airtime/src/respondd.c | 36 ++++++++------------- 4 files changed, 34 insertions(+), 74 deletions(-) diff --git a/package/gluon-airtime/src/airtime-test.c b/package/gluon-airtime/src/airtime-test.c index 088a9c25..85773f9e 100644 --- a/package/gluon-airtime/src/airtime-test.c +++ b/package/gluon-airtime/src/airtime-test.c @@ -1,5 +1,4 @@ #include -#include /* sleep */ #include "airtime.h" void print_result(struct airtime_result *); @@ -12,21 +11,18 @@ int main(int argc, char *argv[]) { return 1; } - while (1) { - a = get_airtime(argv[1], argv[2]); - print_result(&a->radio0); - print_result(&a->radio1); - sleep(1); - } + a = get_airtime(argv[1], argv[2]); + print_result(&a->radio0); + print_result(&a->radio1); } void print_result(struct airtime_result *result){ printf("freq=%d\tnoise=%d\tbusy=%lld\tactive=%lld\trx=%lld\ttx=%lld\n", result->frequency, result->noise, - result->busy_time.current, - result->active_time.current, - result->rx_time.current, - result->tx_time.current + result->busy_time, + result->active_time, + result->rx_time, + result->tx_time ); } diff --git a/package/gluon-airtime/src/airtime.c b/package/gluon-airtime/src/airtime.c index 7d3fbed9..108d6d56 100644 --- a/package/gluon-airtime/src/airtime.c +++ b/package/gluon-airtime/src/airtime.c @@ -64,8 +64,7 @@ static struct airtime cur_airtime = { * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use */ -static int survey_airtime_handler(struct nl_msg *msg, void *arg) -{ +static int survey_airtime_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1]; static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = { @@ -76,7 +75,7 @@ static int survey_airtime_handler(struct nl_msg *msg, void *arg) struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct airtime_result *result = (struct airtime_result *) arg; - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),genlmsg_attrlen(gnlh, 0), NULL); + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (!tb[NL80211_ATTR_SURVEY_INFO]) { fprintf(stderr, "survey data missing!\n"); @@ -93,27 +92,12 @@ static int survey_airtime_handler(struct nl_msg *msg, void *arg) goto abort; } - uint64_t frequency = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]); - - if (frequency != result->frequency) { - // channel changed, restart at zero - result->frequency = frequency; - result->active_time.offset = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]); - result->busy_time.offset = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]); - result->rx_time.offset = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]); - result->tx_time.offset = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]); - result->active_time.current = 0; - result->busy_time.current = 0; - result->rx_time.current = 0; - result->tx_time.current = 0; - } else { - result->active_time.current = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]) - result->active_time.offset; - result->busy_time.current = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]) - result->busy_time.offset; - result->rx_time.current = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]) - result->rx_time.offset; - result->tx_time.current = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]) - result->tx_time.offset; - } - - result->noise = nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]); + result->frequency = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]); + result->active_time = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]); + result->busy_time = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]); + result->rx_time = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]); + result->tx_time = nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]); + result->noise = nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]); abort: return NL_SKIP; @@ -121,10 +105,9 @@ abort: static int get_airtime_for_interface(struct airtime_result *result, const char *interface) { int error = 0; - int ctrl, ifx, flags; + int ctrl, ifx; struct nl_sock *sk = NULL; struct nl_msg *msg = NULL; - enum nl80211_commands cmd; #define CHECK(x) { if (!(x)) { fprintf(stderr, "airtime.c: error on line %d\n", __LINE__); error = 1; goto out; } } @@ -141,12 +124,8 @@ static int get_airtime_for_interface(struct airtime_result *result, const char * goto out; } - cmd = NL80211_CMD_GET_SURVEY; - flags = 0; - flags |= NLM_F_DUMP; - /* TODO: check return? */ - genlmsg_put(msg, 0, 0, ctrl, 0, flags, cmd, 0); + genlmsg_put(msg, 0, 0, ctrl, 0, NLM_F_DUMP, NL80211_CMD_GET_SURVEY, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifx); diff --git a/package/gluon-airtime/src/airtime.h b/package/gluon-airtime/src/airtime.h index 4a1347c1..c0c8bb93 100644 --- a/package/gluon-airtime/src/airtime.h +++ b/package/gluon-airtime/src/airtime.h @@ -2,18 +2,13 @@ #include -struct airtime_time { - uint64_t current; - uint64_t offset; -}; - struct airtime_result { + uint64_t active_time; + uint64_t busy_time; + uint64_t rx_time; + uint64_t tx_time; uint32_t frequency; uint8_t noise; - struct airtime_time active_time; - struct airtime_time busy_time; - struct airtime_time rx_time; - struct airtime_time tx_time; }; struct airtime { diff --git a/package/gluon-airtime/src/respondd.c b/package/gluon-airtime/src/respondd.c index 0f62afd9..cc4c0497 100644 --- a/package/gluon-airtime/src/respondd.c +++ b/package/gluon-airtime/src/respondd.c @@ -8,36 +8,26 @@ static const char const *wifi_0_dev = "client0"; static const char const *wifi_1_dev = "client1"; -void fill_airtime_json(struct airtime_result *air, struct json_object* wireless){ - struct json_object *result = NULL, *obj = NULL; +void fill_airtime_json(struct airtime_result *air, struct json_object *wireless) { + struct json_object *obj = NULL; obj = json_object_new_object(); if(!obj) - goto error; -#define JSON_ADD_INT64(value,key) {result = json_object_new_int64(value); json_object_object_add(obj,key,result);} - result = json_object_new_int(air->frequency); - if(!result) - goto error; - json_object_object_add(obj,"frequency",result); + return; - JSON_ADD_INT64(air->active_time.current,"active") - JSON_ADD_INT64(air->busy_time.current,"busy") - JSON_ADD_INT64(air->rx_time.current,"rx") - JSON_ADD_INT64(air->tx_time.current,"tx") + json_object_object_add(obj, "frequency", json_object_new_int(air->frequency)); + json_object_object_add(obj, "active", json_object_new_int64(air->active_time)); + json_object_object_add(obj, "busy", json_object_new_int64(air->busy_time)); + json_object_object_add(obj, "rx", json_object_new_int64(air->rx_time)); + json_object_object_add(obj, "tx", json_object_new_int64(air->tx_time)); + json_object_object_add(obj, "noise", json_object_new_int(air->noise)); - result = json_object_new_int(air->noise); - json_object_object_add(obj,"noise",result); - -error: - if(air->frequency >= 2400 && air->frequency < 2500) - json_object_object_add(wireless, "airtime24", obj); - else if (air->frequency >= 5000 && air->frequency < 6000) - json_object_object_add(wireless, "airtime5", obj); + json_object_array_add(wireless, obj); } static struct json_object *respondd_provider_statistics(void) { struct airtime *airtime = NULL; - struct json_object *result = NULL, *wireless = NULL; + struct json_object *result, *wireless; airtime = get_airtime(wifi_0_dev, wifi_1_dev); if (!airtime) @@ -47,8 +37,8 @@ static struct json_object *respondd_provider_statistics(void) { if (!result) return NULL; - wireless = json_object_new_object(); - if (!wireless){ + wireless = json_object_new_array(); + if (!wireless) { json_object_put(result); return NULL; } From 97b82af2462a1d78580d257d4f09f80483d84f22 Mon Sep 17 00:00:00 2001 From: Jan-Philipp Litza Date: Sun, 4 Dec 2016 19:50:44 +0100 Subject: [PATCH 3/7] gluon-airtime: Improve Makefile Remove redundant mention of source files --- package/gluon-airtime/src/Makefile | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/package/gluon-airtime/src/Makefile b/package/gluon-airtime/src/Makefile index e265638f..025c98db 100644 --- a/package/gluon-airtime/src/Makefile +++ b/package/gluon-airtime/src/Makefile @@ -11,12 +11,14 @@ CFLAGS += -pedantic all: respondd.so -# sudo apt install libnl-3-dev -airtime-test: airtime-test.c airtime.c airtime.h - $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -fPIC -D_GNU_SOURCE -lnl-tiny -o $@ airtime.c airtime-test.c $(LDLIBS) +%.c: %.h -respondd.so: respondd.c airtime.c - $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -lnl-tiny -o $@ airtime.c respondd.c $(LDLIBS) +# sudo apt install libnl-3-dev +airtime-test: airtime.c airtime-test.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -fPIC -D_GNU_SOURCE -lnl-tiny -o $@ $^ $(LDLIBS) + +respondd.so: airtime.c respondd.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -lnl-tiny -o $@ $^ $(LDLIBS) clean: rm -rf *.so airtime-test From 4322d8323cc41f1175ab5724b64b803a8997c495 Mon Sep 17 00:00:00 2001 From: Jan-Philipp Litza Date: Sun, 4 Dec 2016 19:51:41 +0100 Subject: [PATCH 4/7] gluon-airtime: Autodetect interfaces --- package/gluon-airtime/src/Makefile | 4 +- package/gluon-airtime/src/airtime-test.c | 20 ++++--- package/gluon-airtime/src/airtime.c | 22 +------- package/gluon-airtime/src/airtime.h | 7 +-- package/gluon-airtime/src/ifaces.c | 66 ++++++++++++++++++++++++ package/gluon-airtime/src/ifaces.h | 9 ++++ package/gluon-airtime/src/respondd.c | 25 +++++---- 7 files changed, 104 insertions(+), 49 deletions(-) create mode 100644 package/gluon-airtime/src/ifaces.c create mode 100644 package/gluon-airtime/src/ifaces.h diff --git a/package/gluon-airtime/src/Makefile b/package/gluon-airtime/src/Makefile index 025c98db..1a6c0ed0 100644 --- a/package/gluon-airtime/src/Makefile +++ b/package/gluon-airtime/src/Makefile @@ -14,10 +14,10 @@ all: respondd.so %.c: %.h # sudo apt install libnl-3-dev -airtime-test: airtime.c airtime-test.c +airtime-test: airtime.c ifaces.c airtime-test.c $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -fPIC -D_GNU_SOURCE -lnl-tiny -o $@ $^ $(LDLIBS) -respondd.so: airtime.c respondd.c +respondd.so: airtime.c ifaces.c respondd.c $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -lnl-tiny -o $@ $^ $(LDLIBS) clean: diff --git a/package/gluon-airtime/src/airtime-test.c b/package/gluon-airtime/src/airtime-test.c index 85773f9e..a82861f1 100644 --- a/package/gluon-airtime/src/airtime-test.c +++ b/package/gluon-airtime/src/airtime-test.c @@ -1,19 +1,23 @@ #include +#include #include "airtime.h" +#include "ifaces.h" void print_result(struct airtime_result *); int main(int argc, char *argv[]) { - struct airtime *a; + struct airtime_result a; + struct iface_list *ifaces; + void *freeptr; - if (argc != 3) { - fprintf(stderr,"Usage: %s \n", argv[0]); - return 1; + ifaces = get_ifaces(); + while (ifaces != NULL) { + get_airtime(&a, ifaces->ifx); + print_result(&a); + freeptr = ifaces; + ifaces = ifaces->next; + free(freeptr); } - - a = get_airtime(argv[1], argv[2]); - print_result(&a->radio0); - print_result(&a->radio1); } void print_result(struct airtime_result *result){ diff --git a/package/gluon-airtime/src/airtime.c b/package/gluon-airtime/src/airtime.c index 108d6d56..e8c18427 100644 --- a/package/gluon-airtime/src/airtime.c +++ b/package/gluon-airtime/src/airtime.c @@ -33,11 +33,6 @@ #include "airtime.h" -static struct airtime cur_airtime = { - { .frequency = 0 }, - { .frequency = 0 }, -}; - /* * Excerpt from nl80211.h: * enum nl80211_survey_info - survey information @@ -103,9 +98,9 @@ abort: return NL_SKIP; } -static int get_airtime_for_interface(struct airtime_result *result, const char *interface) { +int get_airtime(struct airtime_result *result, int ifx) { int error = 0; - int ctrl, ifx; + int ctrl; struct nl_sock *sk = NULL; struct nl_msg *msg = NULL; @@ -118,12 +113,6 @@ static int get_airtime_for_interface(struct airtime_result *result, const char * CHECK(nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, survey_airtime_handler, result) == 0); CHECK(msg = nlmsg_alloc()); - /* device does not exist */ - if (!(ifx = if_nametoindex(interface))){ - error = -1; - goto out; - } - /* TODO: check return? */ genlmsg_put(msg, 0, 0, ctrl, 0, NLM_F_DUMP, NL80211_CMD_GET_SURVEY, 0); @@ -144,10 +133,3 @@ out: return error; } - -struct airtime* get_airtime(const char *wifi_0_dev, const char *wifi_1_dev) { - get_airtime_for_interface(&cur_airtime.radio0, wifi_0_dev); - get_airtime_for_interface(&cur_airtime.radio1, wifi_1_dev); - - return &cur_airtime; -} diff --git a/package/gluon-airtime/src/airtime.h b/package/gluon-airtime/src/airtime.h index c0c8bb93..c7c5fbb9 100644 --- a/package/gluon-airtime/src/airtime.h +++ b/package/gluon-airtime/src/airtime.h @@ -11,9 +11,4 @@ struct airtime_result { uint8_t noise; }; -struct airtime { - struct airtime_result radio0; - struct airtime_result radio1; -}; - -struct airtime* get_airtime(const char *radio0, const char *radio1); +int get_airtime(struct airtime_result *result, int ifx); diff --git a/package/gluon-airtime/src/ifaces.c b/package/gluon-airtime/src/ifaces.c new file mode 100644 index 00000000..cbb9ff18 --- /dev/null +++ b/package/gluon-airtime/src/ifaces.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "ifaces.h" + +static int iface_dump_handler(struct nl_msg *msg, struct iface_list **arg) { + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + int wiphy; + struct iface_list **last_next; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + + wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]); + for (last_next = arg; *last_next != NULL; last_next = &(*last_next)->next) { + if ((*last_next)->wiphy == wiphy) + goto abort; + } + *last_next = malloc(sizeof(**last_next)); + (*last_next)->next = NULL; + (*last_next)->ifx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); + (*last_next)->wiphy = wiphy; + +abort: + return NL_SKIP; +} + +struct iface_list *get_ifaces() { + int ctrl; + struct nl_sock *sk = NULL; + struct nl_msg *msg = NULL; + struct iface_list *ifaces = NULL; + +#define CHECK(x) { if (!(x)) { fprintf(stderr, "airtime.c: error on line %d\n", __LINE__); goto out; } } + + CHECK(sk = nl_socket_alloc()); + CHECK(genl_connect(sk) >= 0); + + CHECK(ctrl = genl_ctrl_resolve(sk, NL80211_GENL_NAME)); + CHECK(nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, (nl_recvmsg_msg_cb_t) iface_dump_handler, &ifaces) == 0); + CHECK(msg = nlmsg_alloc()); + + /* TODO: check return? */ + genlmsg_put(msg, 0, 0, ctrl, 0, NLM_F_DUMP, NL80211_CMD_GET_INTERFACE, 0); + + CHECK(nl_send_auto_complete(sk, msg) >= 0); + CHECK(nl_recvmsgs_default(sk) >= 0); + +#undef CHECK + + return ifaces; + +out: + if (msg) + nlmsg_free(msg); + + if (sk) + nl_socket_free(sk); + + return NULL; +} diff --git a/package/gluon-airtime/src/ifaces.h b/package/gluon-airtime/src/ifaces.h new file mode 100644 index 00000000..ea13ee34 --- /dev/null +++ b/package/gluon-airtime/src/ifaces.h @@ -0,0 +1,9 @@ +#pragma once + +struct iface_list { + int ifx; + int wiphy; + struct iface_list *next; +}; + +struct iface_list *get_ifaces(); diff --git a/package/gluon-airtime/src/respondd.c b/package/gluon-airtime/src/respondd.c index cc4c0497..d4c0a511 100644 --- a/package/gluon-airtime/src/respondd.c +++ b/package/gluon-airtime/src/respondd.c @@ -4,9 +4,7 @@ #include #include "airtime.h" - -static const char const *wifi_0_dev = "client0"; -static const char const *wifi_1_dev = "client1"; +#include "ifaces.h" void fill_airtime_json(struct airtime_result *air, struct json_object *wireless) { struct json_object *obj = NULL; @@ -26,12 +24,10 @@ void fill_airtime_json(struct airtime_result *air, struct json_object *wireless) } static struct json_object *respondd_provider_statistics(void) { - struct airtime *airtime = NULL; + struct airtime_result airtime; struct json_object *result, *wireless; - - airtime = get_airtime(wifi_0_dev, wifi_1_dev); - if (!airtime) - return NULL; + struct iface_list *ifaces; + void *freeptr; result = json_object_new_object(); if (!result) @@ -43,11 +39,14 @@ static struct json_object *respondd_provider_statistics(void) { return NULL; } - if (airtime->radio0.frequency) - fill_airtime_json(&airtime->radio0, wireless); - - if (airtime->radio1.frequency) - fill_airtime_json(&airtime->radio1, wireless); + ifaces = get_ifaces(); + while (ifaces != NULL) { + get_airtime(&airtime, ifaces->ifx); + fill_airtime_json(&airtime, wireless); + freeptr = ifaces; + ifaces = ifaces->next; + free(freeptr); + } json_object_object_add(result, "wireless", wireless); return result; From 5ba752f6b1a3a36723fa471a063ccb1279981c9d Mon Sep 17 00:00:00 2001 From: Jan-Philipp Litza Date: Thu, 8 Dec 2016 20:00:37 +0100 Subject: [PATCH 5/7] gluon-airtime: Fix memory leak and uninitialized struct --- package/gluon-airtime/src/ifaces.c | 4 +--- package/gluon-airtime/src/respondd.c | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/package/gluon-airtime/src/ifaces.c b/package/gluon-airtime/src/ifaces.c index cbb9ff18..f9d0514d 100644 --- a/package/gluon-airtime/src/ifaces.c +++ b/package/gluon-airtime/src/ifaces.c @@ -53,8 +53,6 @@ struct iface_list *get_ifaces() { #undef CHECK - return ifaces; - out: if (msg) nlmsg_free(msg); @@ -62,5 +60,5 @@ out: if (sk) nl_socket_free(sk); - return NULL; + return ifaces; } diff --git a/package/gluon-airtime/src/respondd.c b/package/gluon-airtime/src/respondd.c index d4c0a511..0de1f49d 100644 --- a/package/gluon-airtime/src/respondd.c +++ b/package/gluon-airtime/src/respondd.c @@ -24,7 +24,7 @@ void fill_airtime_json(struct airtime_result *air, struct json_object *wireless) } static struct json_object *respondd_provider_statistics(void) { - struct airtime_result airtime; + struct airtime_result airtime = {}; struct json_object *result, *wireless; struct iface_list *ifaces; void *freeptr; From 91280367882b637ab80d684377f8dab9a71a0f73 Mon Sep 17 00:00:00 2001 From: Jan-Philipp Litza Date: Thu, 8 Dec 2016 20:01:43 +0100 Subject: [PATCH 6/7] gluon-airtime: Add myself to the copyright notice --- package/gluon-airtime/src/airtime.c | 1 + 1 file changed, 1 insertion(+) diff --git a/package/gluon-airtime/src/airtime.c b/package/gluon-airtime/src/airtime.c index e8c18427..bd859926 100644 --- a/package/gluon-airtime/src/airtime.c +++ b/package/gluon-airtime/src/airtime.c @@ -1,6 +1,7 @@ /* Copyright (c) 2016, Julian Kornberger Martin Müller + Jan-Philipp Litza All rights reserved. Redistribution and use in source and binary forms, with or without From fbe2d717692f1dca35af4e7b39e5f1886a7ed6ec Mon Sep 17 00:00:00 2001 From: Jan-Philipp Litza Date: Thu, 8 Dec 2016 20:05:26 +0100 Subject: [PATCH 7/7] gluon-airtime: Add readme --- package/gluon-airtime/README.md | 36 +++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 package/gluon-airtime/README.md diff --git a/package/gluon-airtime/README.md b/package/gluon-airtime/README.md new file mode 100644 index 00000000..eb82b0cf --- /dev/null +++ b/package/gluon-airtime/README.md @@ -0,0 +1,36 @@ +This module adds a respondd airtime usage statistics provider. +The format is the following: + +```json +{ + "statistics": { + "wireless": [ + { + "frequency": 5220, + "active": 366561161, + "busy": 46496566, + "rx": 808415, + "tx": 41711344, + "noise": 162 + }, + { + "frequency": 2437, + "active": 366649704, + "busy": 205221222, + "rx": 108121446, + "tx": 85453679, + "noise": 161 + } + ] + } +} +``` + +The numbers `active`, `busy`, `rx` and `tx` are times in milliseconds, where +`busy`, `rx` and `tx` have to be interpreted by taking the quotient with +`active`. + +The motivation for having a list with the frequency as a value in the objects +instead of having an object with the frequency as keys is that multiple wifi +devices might be present, in which case the same frequency can appear multiple +times (because the statistics are reported once for every phy).