Browse Source

utils: add simple ubus query support

Some wireless runtime parameters are not available via nl80211, e.g.
the effective Mesh ID so we need to fetch those from ubus state info.

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Jo-Philipp Wich 5 years ago
parent
commit
d991fe5481
3 changed files with 98 additions and 1 deletions
  1. 1 1
      Makefile
  2. 4 0
      include/iwinfo/utils.h
  3. 93 0
      iwinfo_utils.c

+ 1 - 1
Makefile

@@ -1,6 +1,6 @@
 IWINFO_BACKENDS    = $(BACKENDS)
 IWINFO_CFLAGS      = $(CFLAGS) -std=gnu99 -fstrict-aliasing -Iinclude
-IWINFO_LDFLAGS     = -luci -lubox
+IWINFO_LDFLAGS     = -luci -lubox -lubus
 
 IWINFO_LIB         = libiwinfo.so
 IWINFO_LIB_LDFLAGS = $(LDFLAGS) -shared

+ 4 - 0
include/iwinfo/utils.h

@@ -22,6 +22,7 @@
 #include <sys/socket.h>
 #include <net/if.h>
 #include <uci.h>
+#include <libubus.h>
 
 #include "iwinfo.h"
 
@@ -58,4 +59,7 @@ void iwinfo_parse_rsn(struct iwinfo_crypto_entry *c, uint8_t *data, uint8_t len,
 struct uci_section *iwinfo_uci_get_radio(const char *name, const char *type);
 void iwinfo_uci_free(void);
 
+int iwinfo_ubus_query(const char *ifname, const char *field,
+                      char *buf, size_t len);
+
 #endif

+ 93 - 0
iwinfo_utils.c

@@ -404,3 +404,96 @@ void iwinfo_uci_free(void)
 	uci_free_context(uci_ctx);
 	uci_ctx = NULL;
 }
+
+
+struct iwinfo_ubus_query_state {
+	const char *ifname;
+	const char *field;
+	size_t len;
+	char *buf;
+};
+
+static void iwinfo_ubus_query_cb(struct ubus_request *req, int type,
+                                 struct blob_attr *msg)
+{
+	struct iwinfo_ubus_query_state *st = req->priv;
+
+	struct blobmsg_policy pol1[2] = {
+		{ "ifname",  BLOBMSG_TYPE_STRING },
+		{ "config",  BLOBMSG_TYPE_TABLE }
+	};
+
+	struct blobmsg_policy pol2 = { st->field, BLOBMSG_TYPE_STRING };
+	struct blob_attr *cur, *cur2, *cur3, *cfg[2], *res;
+	int rem, rem2, rem3;
+
+	blobmsg_for_each_attr(cur, msg, rem) {
+		if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE)
+			continue;
+
+		blobmsg_for_each_attr(cur2, cur, rem2) {
+			if (blobmsg_type(cur2) != BLOBMSG_TYPE_ARRAY)
+				continue;
+
+			if (strcmp(blobmsg_name(cur2), "interfaces"))
+				continue;
+
+			blobmsg_for_each_attr(cur3, cur2, rem3) {
+				blobmsg_parse(pol1, sizeof(pol1) / sizeof(pol1[0]), cfg,
+				              blobmsg_data(cur3), blobmsg_len(cur3));
+
+				if (!cfg[0] || !cfg[1] ||
+				    strcmp(blobmsg_get_string(cfg[0]), st->ifname))
+					continue;
+
+				blobmsg_parse(&pol2, 1, &res,
+				              blobmsg_data(cfg[1]), blobmsg_len(cfg[1]));
+
+				if (!res)
+					continue;
+
+				strncpy(st->buf, blobmsg_get_string(res), st->len);
+				return;
+			}
+		}
+	}
+}
+
+int iwinfo_ubus_query(const char *ifname, const char *field,
+                      char *buf, size_t len)
+{
+	struct iwinfo_ubus_query_state st = {
+		.ifname = ifname,
+		.field = field,
+		.buf = buf,
+		.len = len
+	};
+
+	struct ubus_context *ctx = NULL;
+	struct blob_buf b = { };
+	int rv = -1;
+	uint32_t id;
+
+	blob_buf_init(&b, 0);
+
+	ctx = ubus_connect(NULL);
+
+	if (!ctx)
+		goto out;
+
+	if (ubus_lookup_id(ctx, "network.wireless", &id))
+		goto out;
+
+	if (ubus_invoke(ctx, id, "status", b.head, iwinfo_ubus_query_cb, &st, 250))
+		goto out;
+
+	rv = 0;
+
+out:
+	if (ctx)
+		ubus_free(ctx);
+
+	blob_buf_free(&b);
+
+	return rv;
+}