diff --git a/net/respondd-module-airtime/Makefile b/net/respondd-module-airtime/Makefile deleted file mode 100644 index 6a6e450..0000000 --- a/net/respondd-module-airtime/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -include $(TOPDIR)/rules.mk - -PKG_NAME:=respondd-module-airtime -PKG_VERSION:=1 -PKG_RELEASE:=2 - -PKG_LICENSE:=BSD-2-Clause - -PKG_BUILD_DEPENDS := respondd - -include $(INCLUDE_DIR)/package.mk - -define Package/respondd-module-airtime - SECTION:=net - CATEGORY:=Network - TITLE:=Add airtime to respondd - DEPENDS:=+respondd +libnl-tiny -endef - -TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include/libnl-tiny - -define Package/respondd-module-airtime/install - $(INSTALL_DIR) $(1)/usr/lib/respondd - $(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/usr/lib/respondd/airtime.so -endef - -$(eval $(call BuildPackage,respondd-module-airtime)) diff --git a/net/respondd-module-wifi/README.md b/net/respondd-module-wifi/README.md index 3a9423c..df05639 100644 --- a/net/respondd-module-wifi/README.md +++ b/net/respondd-module-wifi/README.md @@ -11,6 +11,7 @@ The format is the following: "wireless": [ { "frequency": 5220, + "channel_width": 40, "txpower": 1700, "active": 366561161, "busy": 46496566, @@ -21,6 +22,7 @@ The format is the following: }, { "frequency": 5220, + "channel_width": 40, "txpower": 1700, "active": 366561161, "busy": 46496566, @@ -31,6 +33,7 @@ The format is the following: }, { "frequency": 2437, + "channel_width": 20, "txpower": 2000, "active": 366649704, "busy": 205221222, @@ -40,6 +43,19 @@ The format is the following: "clients": 3 } ] + }, + "neighbours": { + "wifi":{ + "00:11:22:33:44:55:66":{ + "frequency": 5220, + "neighbours":{ + "33:22:33:11:22:44":{ + "signal": 191, + "inactive": 50 + } + } + } + } } } ``` diff --git a/net/respondd-module-wifi/src/Makefile b/net/respondd-module-wifi/src/Makefile index 1d07977..8afb817 100644 --- a/net/respondd-module-wifi/src/Makefile +++ b/net/respondd-module-wifi/src/Makefile @@ -9,7 +9,7 @@ all: respondd.so %.c: %.h -respondd.so: netlink.c clients.c airtime.c ifaces.c respondd.c +respondd.so: netlink.c ifaces.c airtime.c clients.c neighbours.c respondd.c $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -lnl-tiny -o $@ $^ $(LDLIBS) clean: diff --git a/net/respondd-module-wifi/src/airtime.c b/net/respondd-module-wifi/src/airtime.c index 989057a..1c1288b 100644 --- a/net/respondd-module-wifi/src/airtime.c +++ b/net/respondd-module-wifi/src/airtime.c @@ -57,7 +57,7 @@ * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use */ -static const char * msg_names[NL80211_SURVEY_INFO_MAX + 1] = { +static const char * airtime_names[NL80211_SURVEY_INFO_MAX + 1] = { [NL80211_SURVEY_INFO_CHANNEL_TIME] = "active", [NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY] = "busy", [NL80211_SURVEY_INFO_CHANNEL_TIME_RX] = "rx", @@ -79,7 +79,6 @@ static int survey_airtime_handler(struct nl_msg *msg, void *arg) { // This variable counts the number of required attributes that are // found in the message and is afterwards checked against the number of // required attributes. - unsigned int req_fields = 0; int rem; struct nlattr *nla; @@ -89,14 +88,7 @@ static int survey_airtime_handler(struct nl_msg *msg, void *arg) { if (type > NL80211_SURVEY_INFO_MAX) continue; - switch (type) { - // these are the required fields - case NL80211_SURVEY_INFO_IN_USE: - case NL80211_SURVEY_INFO_CHANNEL_TIME: - req_fields++; - } - - if (!msg_names[type]) + if (!airtime_names[type]) continue; struct json_object *data_json = NULL; @@ -118,7 +110,7 @@ static int survey_airtime_handler(struct nl_msg *msg, void *arg) { } if (data_json) - json_object_object_add(json, msg_names[type], data_json); + json_object_object_add(json, airtime_names[type], data_json); } abort: diff --git a/net/respondd-module-wifi/src/airtime.h b/net/respondd-module-wifi/src/airtime.h index 7adc91e..d0bc56c 100644 --- a/net/respondd-module-wifi/src/airtime.h +++ b/net/respondd-module-wifi/src/airtime.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include __attribute__((visibility("hidden"))) bool get_airtime(struct json_object *result, int ifx); diff --git a/net/respondd-module-wifi/src/clients.h b/net/respondd-module-wifi/src/clients.h index a3ce848..d946aef 100644 --- a/net/respondd-module-wifi/src/clients.h +++ b/net/respondd-module-wifi/src/clients.h @@ -1,6 +1,5 @@ #pragma once #include -#include __attribute__((visibility("hidden"))) bool get_client_counts(int *count, int ifx); diff --git a/net/respondd-module-wifi/src/ifaces.c b/net/respondd-module-wifi/src/ifaces.c index 7f8edc1..cd0f810 100644 --- a/net/respondd-module-wifi/src/ifaces.c +++ b/net/respondd-module-wifi/src/ifaces.c @@ -4,6 +4,19 @@ #include "ifaces.h" #include "netlink.h" + +//https://github.com/torvalds/linux/blob/master/include/uapi/linux/nl80211.h#L4031 +static const int chanwidth[NL80211_SURVEY_INFO_MAX + 1] = { + [NL80211_CHAN_WIDTH_20_NOHT] = 20, + [NL80211_CHAN_WIDTH_20] = 20, + [NL80211_CHAN_WIDTH_40] = 40, + [NL80211_CHAN_WIDTH_80] = 80, + [NL80211_CHAN_WIDTH_80P80] = 160, + [NL80211_CHAN_WIDTH_160] = 160, + [NL80211_CHAN_WIDTH_5] = 5, + [NL80211_CHAN_WIDTH_10] = 10, +}; + static int iface_dump_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); @@ -15,7 +28,7 @@ static int iface_dump_handler(struct nl_msg *msg, void *arg) { goto skip; #ifdef GLUON - if(nla_strcmp(tb[NL80211_ATTR_IFNAME], "client") == -1) + if(nla_strcmp(tb[NL80211_ATTR_IFNAME], "client") == -1 || nla_strcmp(tb[NL80211_ATTR_IFNAME], "ibss") == -1 || nla_strcmp(tb[NL80211_ATTR_IFNAME], "mesh") == -1) goto skip; #endif @@ -28,8 +41,18 @@ static int iface_dump_handler(struct nl_msg *msg, void *arg) { (*last_next)->next = NULL; (*last_next)->wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]); (*last_next)->ifx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); - (*last_next)->frequency = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); - (*last_next)->txpower = nla_get_u32(tb[NL80211_ATTR_WIPHY_TX_POWER_LEVEL]); + (*last_next)->frequency = tb[NL80211_ATTR_WIPHY_FREQ] ? nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]) : 0; + (*last_next)->txpower = tb[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] ? nla_get_u32(tb[NL80211_ATTR_WIPHY_TX_POWER_LEVEL]) : 0; + (*last_next)->type = tb[NL80211_ATTR_IFTYPE] ? nla_get_u32(tb[NL80211_ATTR_IFTYPE]) : 0; + + if(tb[NL80211_ATTR_MAC]) { + mac_addr_n2a((*last_next)->mac_addr, nla_data(tb[NL80211_ATTR_MAC])); + } + + int chanwidth_id = nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]); + + if(chanwidth[chanwidth_id]) + (*last_next)->chanwidth = tb[NL80211_ATTR_CHANNEL_WIDTH] ? chanwidth[chanwidth_id] : 0; skip: return NL_SKIP; diff --git a/net/respondd-module-wifi/src/ifaces.h b/net/respondd-module-wifi/src/ifaces.h index 5f2021d..fb88411 100644 --- a/net/respondd-module-wifi/src/ifaces.h +++ b/net/respondd-module-wifi/src/ifaces.h @@ -1,9 +1,14 @@ #pragma once +#include + struct iface_list { int wiphy; int ifx; + char mac_addr[20]; + int type; int frequency; + int chanwidth; int txpower; struct iface_list *next; }; diff --git a/net/respondd-module-wifi/src/neighbours.c b/net/respondd-module-wifi/src/neighbours.c new file mode 100644 index 0000000..f097908 --- /dev/null +++ b/net/respondd-module-wifi/src/neighbours.c @@ -0,0 +1,83 @@ +#include +#include + +#include "netlink.h" +#include "neighbours.h" + +static const char * neighbours_names[NL80211_STA_INFO_MAX + 1] = { + [NL80211_STA_INFO_SIGNAL] = "signal", + [NL80211_STA_INFO_INACTIVE_TIME] = "inactive", +}; + +static int station_neighbours_handler(struct nl_msg *msg, void *arg) { + struct json_object *neighbour, *json = (struct json_object *) arg; + + neighbour = json_object_new_object(); + if (!neighbour) { + //TODO why needed? : json_object_put(result); + goto abort; + } + + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *station_info = nla_find(genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NL80211_ATTR_STA_INFO); + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + + if (!station_info) { + fputs("respondd-module-wifi: station data missing in netlink message\n", stderr); + goto abort; + } + + char mac_addr[20]; + + if (!tb[NL80211_ATTR_MAC]) + goto abort; + mac_addr_n2a(mac_addr, nla_data(tb[NL80211_ATTR_MAC])); + + int rem; + struct nlattr *nla; + nla_for_each_nested(nla, station_info, rem) { + int type = nla_type(nla); + + if (type > NL80211_STA_INFO_MAX) + continue; + + if (!neighbours_names[type]) + continue; + + struct json_object *data_json = NULL; + switch (nla_len(nla)) { + case sizeof(uint64_t): + data_json = json_object_new_int64(nla_get_u64(nla)); + break; + case sizeof(uint32_t): + data_json = json_object_new_int(nla_get_u32(nla)); + break; + case sizeof(uint8_t): + data_json = json_object_new_int(nla_get_u8(nla)); + break; + default: + fprintf(stderr, "respondd-module-wifi: Unexpected NL attribute length: %d\n", nla_len(nla)); + } + if (data_json) + json_object_object_add(neighbour, neighbours_names[type], data_json); + } + json_object_object_add(json, mac_addr, neighbour); + +abort: + return NL_SKIP; +} + +bool get_neighbours(struct json_object *result, int ifx) { + struct json_object *neighbours; + neighbours = json_object_new_object(); + if (!neighbours) + return false; + if(!nl_send_dump(station_neighbours_handler, neighbours, NL80211_CMD_GET_STATION, ifx)) + return false; + json_object_object_add(result, "neighbours", neighbours); + return true; + +} diff --git a/net/respondd-module-wifi/src/neighbours.h b/net/respondd-module-wifi/src/neighbours.h new file mode 100644 index 0000000..28dcf49 --- /dev/null +++ b/net/respondd-module-wifi/src/neighbours.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include + +__attribute__((visibility("hidden"))) bool get_neighbours(struct json_object *result, int ifx); diff --git a/net/respondd-module-wifi/src/netlink.c b/net/respondd-module-wifi/src/netlink.c index ac707d0..3d62536 100644 --- a/net/respondd-module-wifi/src/netlink.c +++ b/net/respondd-module-wifi/src/netlink.c @@ -1,12 +1,29 @@ #include #include +#include #include #include #include "netlink.h" +void mac_addr_n2a(char *mac_addr, unsigned char *arg) { + int i, l; + + l = 0; + for (i = 0; i < ETH_ALEN ; i++) { + if (i == 0) { + sprintf(mac_addr+l, "%02x", arg[i]); + l += 2; + } else { + sprintf(mac_addr+l, ":%02x", arg[i]); + l += 3; + } + } +} + + bool nl_send_dump(nl_recvmsg_msg_cb_t cb, void *cb_arg, int cmd, uint32_t cmd_arg) { bool ok = false; int ret; diff --git a/net/respondd-module-wifi/src/netlink.h b/net/respondd-module-wifi/src/netlink.h index 022765e..c8f6898 100644 --- a/net/respondd-module-wifi/src/netlink.h +++ b/net/respondd-module-wifi/src/netlink.h @@ -4,4 +4,5 @@ #include #include +__attribute__((visibility("hidden"))) void mac_addr_n2a(char *mac_addr, unsigned char *arg); __attribute__((visibility("hidden"))) bool nl_send_dump(nl_recvmsg_msg_cb_t cb, void *cb_arg, int cmd, uint32_t cmd_arg); diff --git a/net/respondd-module-wifi/src/respondd.c b/net/respondd-module-wifi/src/respondd.c index 74a8cc3..03fe015 100644 --- a/net/respondd-module-wifi/src/respondd.c +++ b/net/respondd-module-wifi/src/respondd.c @@ -3,8 +3,11 @@ #include #include +#include + #include "airtime.h" #include "clients.h" +#include "neighbours.h" #include "ifaces.h" static struct json_object *respondd_provider_statistics(void) { @@ -31,23 +34,30 @@ static struct json_object *respondd_provider_statistics(void) { while (ifaces != NULL) { clients_count = 0; get_client_counts(&clients_count, ifaces->ifx); - if (ifaces->frequency < 5000) - wifi24 += clients_count; - if (ifaces->frequency > 5000) - wifi5 += clients_count; - - //TODO wiphy only one radio added? (no necessary on gluon - only one ap-ssid at radio) - interface = json_object_new_object(); - if (!interface) { - continue; + if(ifaces->type == NL80211_IFTYPE_AP) { + if (ifaces->frequency < 5000) + wifi24 += clients_count; + if (ifaces->frequency > 5000) + wifi5 += clients_count; } - json_object_object_add(interface, "frequency", json_object_new_int(ifaces->frequency)); - json_object_object_add(interface, "txpower", json_object_new_int(ifaces->txpower)); + + //TODO wiphy only one radio added? (not necessary on gluon - only one ap-ssid at radio) + interface = json_object_new_object(); + if (!interface) + goto next_statistics; + + if (ifaces->frequency) + json_object_object_add(interface, "frequency", json_object_new_int(ifaces->frequency)); + if (ifaces->chanwidth) + json_object_object_add(interface, "channel_width", json_object_new_int(ifaces->chanwidth)); + if (ifaces->txpower) + json_object_object_add(interface, "txpower", json_object_new_int(ifaces->txpower)); get_airtime(interface, ifaces->ifx); //TODO remove at merge radios (one wiphy radio) json_object_object_add(interface, "clients", json_object_new_int(clients_count)); - json_object_array_add(wireless, interface); + json_object_array_add(wireless, interface); +next_statistics: ; void *freeptr = ifaces; ifaces = ifaces->next; free(freeptr); @@ -63,7 +73,52 @@ static struct json_object *respondd_provider_statistics(void) { return result; } +static struct json_object *respondd_provider_neighbours(void) { + struct json_object *result, *wireless, *station; + struct iface_list *ifaces; + + result = json_object_new_object(); + if (!result) + return NULL; + + wireless = json_object_new_object(); + if (!wireless) { + //TODO why needed? : json_object_put(result); + return NULL; + } + + ifaces = get_ifaces(); + + while (ifaces != NULL) { + + if(ifaces->type != NL80211_IFTYPE_ADHOC) + goto next_neighbours; + + station = json_object_new_object(); + if (!station) + goto next_neighbours; + + if (!get_neighbours(station, ifaces->ifx)) + goto next_neighbours; + + if (ifaces->frequency) + json_object_object_add(station, "frequency", json_object_new_int(ifaces->frequency)); + + json_object_object_add(wireless, ifaces->mac_addr, station); + +next_neighbours: ; + void *freeptr = ifaces; + ifaces = ifaces->next; + free(freeptr); + } + + + json_object_object_add(result, "wifi", wireless); + return result; +} + const struct respondd_provider_info respondd_providers[] = { {"statistics", respondd_provider_statistics}, + {"neighbours", respondd_provider_neighbours}, {0, 0}, };