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-airtime/src/ifaces.c b/net/respondd-module-airtime/src/ifaces.c deleted file mode 100644 index 926d3e4..0000000 --- a/net/respondd-module-airtime/src/ifaces.c +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include - -#include "ifaces.h" -#include "netlink.h" - -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)); - int wiphy; - struct iface_list **last_next; - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); - - if (!tb[NL80211_ATTR_WIPHY] || !tb[NL80211_ATTR_IFINDEX]) - goto skip; - - 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 skip; - } - *last_next = malloc(sizeof(**last_next)); - if (!*last_next) - goto skip; - (*last_next)->next = NULL; - (*last_next)->ifx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); - (*last_next)->wiphy = wiphy; - -skip: - return NL_SKIP; -} - -struct iface_list *get_ifaces() { - struct iface_list *ifaces = NULL; - nl_send_dump(&iface_dump_handler, &ifaces, NL80211_CMD_GET_INTERFACE, 0); - return ifaces; -} diff --git a/net/respondd-module-airtime/src/respondd.c b/net/respondd-module-airtime/src/respondd.c deleted file mode 100644 index 4648bd4..0000000 --- a/net/respondd-module-airtime/src/respondd.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include -#include -#include - -#include "airtime.h" -#include "ifaces.h" - -static struct json_object *respondd_provider_statistics(void) { - struct json_object *result, *wireless; - struct iface_list *ifaces; - - result = json_object_new_object(); - if (!result) - return NULL; - - wireless = json_object_new_array(); - if (!wireless) { - json_object_put(result); - return NULL; - } - - ifaces = get_ifaces(); - while (ifaces != NULL) { - get_airtime(wireless, ifaces->ifx); - - void *freeptr = ifaces; - ifaces = ifaces->next; - free(freeptr); - } - - json_object_object_add(result, "wireless", wireless); - return result; -} - -const struct respondd_provider_info respondd_providers[] = { - {"statistics", respondd_provider_statistics}, - {0, 0}, -}; diff --git a/net/respondd-module-wifi/Makefile b/net/respondd-module-wifi/Makefile new file mode 100644 index 0000000..1d5a3a1 --- /dev/null +++ b/net/respondd-module-wifi/Makefile @@ -0,0 +1,40 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=respondd-module-wifi +PKG_VERSION:=1 +PKG_RELEASE:=1 + +PKG_LICENSE:=BSD-2-Clause + +PKG_BUILD_DEPENDS := respondd + +include $(INCLUDE_DIR)/package.mk + +define Package/respondd-module-wifi/Default + SECTION:=net + CATEGORY:=Network + TITLE:=Add wifi statistics to respondd + DEPENDS:=+respondd +libnl-tiny +endef + +TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include/libnl-tiny + +define Package/respondd-module-wifi + $(call Package/respondd-module-wifi/Default) +endef + +define Package/respondd-module-gluonwifi + $(call Package/respondd-module-wifi/Default) + VARIANT:=gluon + TARGET_CFLAGS += -DGLUON +endef + +define Package/respondd-module-wifi/install + $(INSTALL_DIR) $(1)/usr/lib/respondd + $(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/usr/lib/respondd/wifi.so +endef + +Package/respondd-module-gluonwifi/install = $(Package/respondd-module-wifi/install) + +$(eval $(call BuildPackage,respondd-module-wifi)) +$(eval $(call BuildPackage,respondd-module-gluonwifi)) diff --git a/net/respondd-module-airtime/README.md b/net/respondd-module-wifi/README.md similarity index 51% rename from net/respondd-module-airtime/README.md rename to net/respondd-module-wifi/README.md index eb82b0c..df05639 100644 --- a/net/respondd-module-airtime/README.md +++ b/net/respondd-module-wifi/README.md @@ -1,27 +1,61 @@ -This module adds a respondd airtime usage statistics provider. +This module adds a respondd wifi usage statistics provider. The format is the following: ```json { "statistics": { + "clients":{ + "wifi24": 3, + "wifi5": 7 + }, "wireless": [ { "frequency": 5220, + "channel_width": 40, + "txpower": 1700, "active": 366561161, "busy": 46496566, "rx": 808415, "tx": 41711344, - "noise": 162 + "noise": 162, + "clients": 5 + }, + { + "frequency": 5220, + "channel_width": 40, + "txpower": 1700, + "active": 366561161, + "busy": 46496566, + "rx": 808415, + "tx": 41711344, + "noise": 162, + "clients": 2 }, { "frequency": 2437, + "channel_width": 20, + "txpower": 2000, "active": 366649704, "busy": 205221222, "rx": 108121446, "tx": 85453679, - "noise": 161 + "noise": 161, + "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-airtime/src/Makefile b/net/respondd-module-wifi/src/Makefile similarity index 80% rename from net/respondd-module-airtime/src/Makefile rename to net/respondd-module-wifi/src/Makefile index 61f6da5..8afb817 100644 --- a/net/respondd-module-airtime/src/Makefile +++ b/net/respondd-module-wifi/src/Makefile @@ -9,7 +9,7 @@ all: respondd.so %.c: %.h -respondd.so: netlink.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-airtime/src/airtime.c b/net/respondd-module-wifi/src/airtime.c similarity index 81% rename from net/respondd-module-airtime/src/airtime.c rename to net/respondd-module-wifi/src/airtime.c index 7e27ee0..1c1288b 100644 --- a/net/respondd-module-airtime/src/airtime.c +++ b/net/respondd-module-wifi/src/airtime.c @@ -57,8 +57,7 @@ * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use */ -static const char const* msg_names[NL80211_SURVEY_INFO_MAX + 1] = { - [NL80211_SURVEY_INFO_FREQUENCY] = "frequency", +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", @@ -67,26 +66,19 @@ static const char const* msg_names[NL80211_SURVEY_INFO_MAX + 1] = { }; static int survey_airtime_handler(struct nl_msg *msg, void *arg) { - struct json_object *parent_json = (struct json_object *) arg; + struct json_object *json = (struct json_object *) arg; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); struct nlattr *survey_info = nla_find(genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NL80211_ATTR_SURVEY_INFO); if (!survey_info) { - fprintf(stderr, "respondd-module-airtime: survey data missing in netlink message\n"); - goto abort; - } - - struct json_object *freq_json = json_object_new_object(); - if (!freq_json) { - fprintf(stderr, "respondd-module-airtime: failed allocating JSON object\n"); + fputs("respondd-module-wifi: survey data missing in netlink message\n", stderr); goto abort; } // 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; @@ -96,15 +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_FREQUENCY: - case NL80211_SURVEY_INFO_CHANNEL_TIME: - req_fields++; - } - - if (!msg_names[type]) + if (!airtime_names[type]) continue; struct json_object *data_json = NULL; @@ -122,18 +106,13 @@ static int survey_airtime_handler(struct nl_msg *msg, void *arg) { data_json = json_object_new_int(nla_get_u8(nla)); break; default: - fprintf(stderr, "respondd-module-airtime: Unexpected NL attribute length: %d\n", nla_len(nla)); + fprintf(stderr, "respondd-module-wifi: Unexpected NL attribute length: %d\n", nla_len(nla)); } if (data_json) - json_object_object_add(freq_json, msg_names[type], data_json); + json_object_object_add(json, airtime_names[type], data_json); } - if (req_fields == 3) - json_object_array_add(parent_json, freq_json); - else - json_object_put(freq_json); - abort: return NL_SKIP; } diff --git a/net/respondd-module-airtime/src/airtime.h b/net/respondd-module-wifi/src/airtime.h similarity index 88% rename from net/respondd-module-airtime/src/airtime.h rename to net/respondd-module-wifi/src/airtime.h index 7adc91e..d0bc56c 100644 --- a/net/respondd-module-airtime/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.c b/net/respondd-module-wifi/src/clients.c new file mode 100644 index 0000000..f87433a --- /dev/null +++ b/net/respondd-module-wifi/src/clients.c @@ -0,0 +1,16 @@ +#include +#include + +#include "netlink.h" +#include "clients.h" + +static int station_client_handler(struct nl_msg *msg, void *arg) { + int *count = (int *) arg; + + (*count)++; + + return NL_SKIP; +} +bool get_client_counts(int *count, int ifx) { + return nl_send_dump(station_client_handler, count, NL80211_CMD_GET_STATION, ifx); +} diff --git a/net/respondd-module-wifi/src/clients.h b/net/respondd-module-wifi/src/clients.h new file mode 100644 index 0000000..d946aef --- /dev/null +++ b/net/respondd-module-wifi/src/clients.h @@ -0,0 +1,5 @@ +#pragma once + +#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 new file mode 100644 index 0000000..cd0f810 --- /dev/null +++ b/net/respondd-module-wifi/src/ifaces.c @@ -0,0 +1,65 @@ +#include +#include + +#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)); + struct iface_list **last_next; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + + if (!tb[NL80211_ATTR_WIPHY] || !tb[NL80211_ATTR_IFINDEX]) + goto skip; + + #ifdef GLUON + 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 + + // TODO fix add to head list - instatt find last item + for (last_next = arg; *last_next != NULL; last_next = &(*last_next)->next) {} + + *last_next = malloc(sizeof(**last_next)); + if (!*last_next) + goto skip; + (*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 = 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; +} + +struct iface_list *get_ifaces() { + struct iface_list *ifaces = NULL; + nl_send_dump(&iface_dump_handler, &ifaces, NL80211_CMD_GET_INTERFACE, 0); + return ifaces; +} diff --git a/net/respondd-module-airtime/src/ifaces.h b/net/respondd-module-wifi/src/ifaces.h similarity index 61% rename from net/respondd-module-airtime/src/ifaces.h rename to net/respondd-module-wifi/src/ifaces.h index e873087..fb88411 100644 --- a/net/respondd-module-airtime/src/ifaces.h +++ b/net/respondd-module-wifi/src/ifaces.h @@ -1,8 +1,15 @@ #pragma once +#include + struct iface_list { - int ifx; 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..fbbcf40 --- /dev/null +++ b/net/respondd-module-wifi/src/neighbours.c @@ -0,0 +1,86 @@ +#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) + 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); + json_object_put(neighbour); + goto abort; + } + + char mac_addr[20]; + + if (!tb[NL80211_ATTR_MAC]) { + json_object_put(neighbour); + 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)) { + json_object_put(neighbours); + 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-airtime/src/netlink.c b/net/respondd-module-wifi/src/netlink.c similarity index 83% rename from net/respondd-module-airtime/src/netlink.c rename to net/respondd-module-wifi/src/netlink.c index 2030193..b5b81d8 100644 --- a/net/respondd-module-airtime/src/netlink.c +++ b/net/respondd-module-wifi/src/netlink.c @@ -1,11 +1,18 @@ #include #include +#include #include #include #include "netlink.h" + +void mac_addr_n2a(char *mac_addr, unsigned char *arg) { + sprintf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", arg[0], arg[1], arg[2], arg[3], arg[4], arg[5]); +} + + bool nl_send_dump(nl_recvmsg_msg_cb_t cb, void *cb_arg, int cmd, uint32_t cmd_arg) { bool ok = false; int ret; @@ -14,7 +21,7 @@ bool nl_send_dump(nl_recvmsg_msg_cb_t cb, void *cb_arg, int cmd, uint32_t cmd_ar struct nl_msg *msg = NULL; -#define ERR(...) { fprintf(stderr, "respondd-module-airtime: " __VA_ARGS__); goto out; } +#define ERR(...) { fprintf(stderr, "respondd-module-wifi: " __VA_ARGS__); goto out; } sk = nl_socket_alloc(); if (!sk) diff --git a/net/respondd-module-airtime/src/netlink.h b/net/respondd-module-wifi/src/netlink.h similarity index 69% rename from net/respondd-module-airtime/src/netlink.h rename to net/respondd-module-wifi/src/netlink.h index 022765e..c8f6898 100644 --- a/net/respondd-module-airtime/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 new file mode 100644 index 0000000..212e1c0 --- /dev/null +++ b/net/respondd-module-wifi/src/respondd.c @@ -0,0 +1,128 @@ +#include +#include +#include +#include + +#include + +#include "airtime.h" +#include "clients.h" +#include "neighbours.h" +#include "ifaces.h" + +static struct json_object *respondd_provider_statistics(void) { + struct json_object *result, *wireless, *clients, *interface; + struct iface_list *ifaces; + int wifi24 = 0, wifi5 = 0, clients_count; + + result = json_object_new_object(); + if (!result) + return NULL; + + wireless = json_object_new_array(); + if (!wireless) { + json_object_put(result); + return NULL; + } + + clients = json_object_new_object(); + if (!clients) { + json_object_put(wireless); + json_object_put(result); + return NULL; + } + + ifaces = get_ifaces(); + while (ifaces != NULL) { + clients_count = 0; + get_client_counts(&clients_count, ifaces->ifx); + if(ifaces->type == NL80211_IFTYPE_AP) { + if (ifaces->frequency < 5000) + wifi24 += clients_count; + if (ifaces->frequency > 5000) + wifi5 += clients_count; + } + + //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); +next_statistics: ; + void *freeptr = ifaces; + ifaces = ifaces->next; + free(freeptr); + } + + //TODO maybe skip: if (wifi24 > 0 || wifi5 > 0) { + json_object_object_add(clients, "wifi24", json_object_new_int(wifi24)); + json_object_object_add(clients, "wifi5", json_object_new_int(wifi5)); + json_object_object_add(result, "clients", clients); + //} + + json_object_object_add(result, "wireless", wireless); + 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) { + 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)) { + json_object_put(station); + 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}, +};