diff --git a/patches/0001-gluon-radv-filterd-use-UINT16_MAX-as-local-TQ.patch b/patches/0001-gluon-radv-filterd-use-UINT16_MAX-as-local-TQ.patch new file mode 100644 index 00000000..31ce6cde --- /dev/null +++ b/patches/0001-gluon-radv-filterd-use-UINT16_MAX-as-local-TQ.patch @@ -0,0 +1,56 @@ +From d36039abd022b2aa0f5beeb4dfdb051d1887dd69 Mon Sep 17 00:00:00 2001 +From: Grische +Date: Thu, 21 May 2026 22:21:24 +0200 +Subject: [PATCH 1/7] gluon-radv-filterd: use UINT16_MAX as local TQ + +Instead of re-using the hysteresis threshold, use UINT16_MAX as the +synthetic local-router TQ since any value larger than 255 dominates. + +Replace the remaining use with BATMAN_IV_MAX_THRESHOLD as an upper bound +to protect hysteresis threshold to be larger than 255. +--- + package/gluon-radv-filterd/src/gluon-radv-filterd.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/package/gluon-radv-filterd/src/gluon-radv-filterd.c b/package/gluon-radv-filterd/src/gluon-radv-filterd.c +index 7a777752..29d126ac 100644 +--- a/package/gluon-radv-filterd/src/gluon-radv-filterd.c ++++ b/package/gluon-radv-filterd/src/gluon-radv-filterd.c +@@ -52,8 +52,9 @@ + // max execution time of a single ebtables call in nanoseconds + #define EBTABLES_TIMEOUT 500000000 // 500ms + +-// TQ value assigned to local routers +-#define LOCAL_TQ 512 ++// BATMAN IV TQ values are 0-255; reject larger thresholds since ++// it would silently prevent the gateway from switching. ++#define BATMAN_IV_MAX_THRESHOLD 255 + + #define BUFSIZE 1500 + +@@ -267,8 +268,8 @@ static void parse_cmdline(int argc, char *argv[]) { + threshold = strtoul(optarg, &endptr, 10); + if (*endptr != '\0') + exit_errmsg("Threshold must be a number: %s", optarg); +- if (threshold >= LOCAL_TQ) +- exit_errmsg("Threshold too large: %ld (max is %d)", threshold, LOCAL_TQ); ++ if (threshold > BATMAN_IV_MAX_THRESHOLD) ++ exit_errmsg("Threshold too large: %ld (max is %d)", threshold, BATMAN_IV_MAX_THRESHOLD); + G.hysteresis_thresh = (uint16_t) threshold; + break; + case 'h': +@@ -524,9 +525,9 @@ static int parse_tt_local(struct nl_msg *msg, + if (!router) + return NL_OK; + ++ router->tq = UINT16_MAX; + DEBUG_MSG("Found router " F_MAC " in transtable_local, assigning TQ %d", +- F_MAC_VAR(router->src), LOCAL_TQ); +- router->tq = LOCAL_TQ; ++ F_MAC_VAR(router->src), router->tq); + if (router->tq > G.max_tq) + G.max_tq = router->tq; + +-- +2.43.0 + diff --git a/patches/0001-override-wired-tpo-information-for-batman_v.patch b/patches/0001-override-wired-tpo-information-for-batman_v.patch deleted file mode 100644 index 5109d7fb..00000000 --- a/patches/0001-override-wired-tpo-information-for-batman_v.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 332466f73ef43669d200cef9dfe0963f3c57ab96 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Steffen=20F=C3=B6rster?= -Date: Sat, 13 Apr 2019 19:16:38 +0200 -Subject: [PATCH 01/11] override wired tpo information for batman_v - -Co-Authored-By: Krombel ---- - .../mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo | 9 +++++++++ - 1 file changed, 9 insertions(+) - create mode 100755 package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo - -diff --git a/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -new file mode 100755 -index 00000000..7185b4a0 ---- /dev/null -+++ b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -@@ -0,0 +1,9 @@ -+#!/bin/sh -+ -+if [ -f /sys/devices/virtual/net/vx_mesh_lan/batman_adv/throughput_override ]; then echo 1000000 > /sys/devices/virtual/net/vx_mesh_lan/batman_adv/throughput_override; fi -+ -+if [ -f /sys/devices/virtual/net/vx_mesh_wan/batman_adv/throughput_override ]; then echo 1000000 > /sys/devices/virtual/net/vx_mesh_wan/batman_adv/throughput_override; fi -+ -+if [ -f /sys/devices/virtual/net/br-wan/batman_adv/throughput_override ]; then echo 1000000 > /sys/devices/virtual/net/br-wan/batman_adv/throughput_override; fi -+ -+if [ -f /sys/devices/virtual/net/mesh-vpn/batman_adv/throughput_override ]; then echo 1000000 > /sys/devices/virtual/net/mesh-vpn/batman_adv/throughput_override; fi --- -2.43.0 - diff --git a/patches/0002-treewide-add-Batman-V-support.patch b/patches/0002-treewide-add-Batman-V-support.patch new file mode 100644 index 00000000..dce605f1 --- /dev/null +++ b/patches/0002-treewide-add-Batman-V-support.patch @@ -0,0 +1,1020 @@ +From 908153f65ee448caedb167d65677da998bf90cb3 Mon Sep 17 00:00:00 2001 +From: Grische +Date: Fri, 10 Apr 2026 21:08:18 +0200 +Subject: [PATCH 2/7] treewide: add Batman V support + +--- + .../src/respondd-neighbours.c | 133 +++++++++++++----- + .../src/respondd-statistics.c | 34 ++++- + .../src/gluon-radv-filterd.c | 132 ++++++++++------- + .../luasrc/lib/gluon/status-page/mesh.lua | 2 + + .../src/neighbours-batadv.c | 80 ++++++++--- + .../gluon/status-page/view/status-page.html | 2 +- + .../javascript/status-page.js | 14 +- + .../javascript/status-page.min.js | 2 +- + package/libbatadv/src/batadv-genl.c | 102 ++++++++++++++ + package/libbatadv/src/batadv-genl.h | 16 +++ + package/libgluonutil/src/CMakeLists.txt | 2 +- + package/libgluonutil/src/libgluonutil.c | 13 ++ + package/libgluonutil/src/libgluonutil.h | 3 + + 13 files changed, 411 insertions(+), 124 deletions(-) + +diff --git a/package/gluon-mesh-batman-adv/src/respondd-neighbours.c b/package/gluon-mesh-batman-adv/src/respondd-neighbours.c +index 261d6b27..f588f005 100644 +--- a/package/gluon-mesh-batman-adv/src/respondd-neighbours.c ++++ b/package/gluon-mesh-batman-adv/src/respondd-neighbours.c +@@ -44,7 +44,8 @@ static struct json_object * ifnames2addrs(struct json_object *interfaces) { + return ret; + } + +-static const enum batadv_nl_attrs parse_orig_list_mandatory[] = { ++/* Batman IV mandatory attrs */ ++static const enum batadv_nl_attrs parse_orig_list_mandatory_batadv_iv[] = { + BATADV_ATTR_ORIG_ADDRESS, + BATADV_ATTR_NEIGH_ADDRESS, + BATADV_ATTR_TQ, +@@ -52,20 +53,58 @@ static const enum batadv_nl_attrs parse_orig_list_mandatory[] = { + BATADV_ATTR_LAST_SEEN_MSECS, + }; + +-static int parse_orig_list_netlink_cb(struct nl_msg *msg, void *arg) ++/* Batman V mandatory attrs */ ++static const enum batadv_nl_attrs parse_neigh_list_mandatory_batadv_v[] = { ++ BATADV_ATTR_NEIGH_ADDRESS, ++ BATADV_ATTR_THROUGHPUT, ++ BATADV_ATTR_HARD_IFINDEX, ++ BATADV_ATTR_LAST_SEEN_MSECS, ++}; ++ ++static int add_neighbour(struct neigh_netlink_opts *opts, struct nlattr **attrs, ++ uint8_t *mac, uint8_t tq) ++{ ++ uint32_t hardif; ++ uint32_t lastseen; ++ char ifname_buf[IF_NAMESIZE], *ifname; ++ char mac1[18]; ++ ++ hardif = nla_get_u32(attrs[BATADV_ATTR_HARD_IFINDEX]); ++ lastseen = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]); ++ ++ ifname = if_indextoname(hardif, ifname_buf); ++ if (!ifname) ++ return NL_OK; ++ ++ sprintf(mac1, "%02x:%02x:%02x:%02x:%02x:%02x", ++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); ++ ++ struct json_object *obj = json_object_new_object(); ++ if (!obj) ++ return NL_OK; ++ ++ struct json_object *interface; ++ if (!json_object_object_get_ex(opts->interfaces, ifname, &interface)) { ++ interface = json_object_new_object(); ++ json_object_object_add(opts->interfaces, ifname, interface); ++ } ++ ++ json_object_object_add(obj, "tq", json_object_new_int(tq)); ++ json_object_object_add(obj, "lastseen", json_object_new_double(lastseen / 1000.)); ++ json_object_object_add(obj, "best", json_object_new_boolean(nla_get_flag(attrs[BATADV_ATTR_FLAG_BEST]))); ++ json_object_object_add(interface, mac1, obj); ++ ++ return NL_OK; ++} ++ ++static int parse_orig_list_netlink_cb_batadv_iv(struct nl_msg *msg, void *arg) + { + struct nlattr *attrs[BATADV_ATTR_MAX+1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct batadv_nlquery_opts *query_opts = arg; + struct genlmsghdr *ghdr; +- uint8_t *orig; +- uint8_t *dest; +- uint8_t tq; +- uint32_t hardif; +- uint32_t lastseen; +- char ifname_buf[IF_NAMESIZE], *ifname; ++ uint8_t *mac; + struct neigh_netlink_opts *opts; +- char mac1[18]; + + opts = batadv_container_of(query_opts, struct neigh_netlink_opts, + query_opts); +@@ -82,42 +121,49 @@ static int parse_orig_list_netlink_cb(struct nl_msg *msg, void *arg) + genlmsg_len(ghdr), batadv_genl_policy)) + return NL_OK; + +- if (batadv_genl_missing_attrs(attrs, parse_orig_list_mandatory, +- BATADV_ARRAY_SIZE(parse_orig_list_mandatory))) ++ if (batadv_genl_missing_attrs(attrs, parse_orig_list_mandatory_batadv_iv, ++ BATADV_ARRAY_SIZE(parse_orig_list_mandatory_batadv_iv))) + return NL_OK; + +- orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); +- dest = nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]); +- tq = nla_get_u8(attrs[BATADV_ATTR_TQ]); +- hardif = nla_get_u32(attrs[BATADV_ATTR_HARD_IFINDEX]); +- lastseen = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]); +- +- if (memcmp(orig, dest, 6) != 0) ++ mac = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); ++ if (memcmp(mac, nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]), 6) != 0) + return NL_OK; + +- ifname = if_indextoname(hardif, ifname_buf); +- if (!ifname) ++ return add_neighbour(opts, attrs, mac, nla_get_u8(attrs[BATADV_ATTR_TQ])); ++} ++ ++static int parse_neigh_list_netlink_cb_batadv_v(struct nl_msg *msg, void *arg) ++{ ++ struct nlattr *attrs[BATADV_ATTR_MAX+1]; ++ struct nlmsghdr *nlh = nlmsg_hdr(msg); ++ struct batadv_nlquery_opts *query_opts = arg; ++ struct genlmsghdr *ghdr; ++ uint8_t *mac; ++ struct neigh_netlink_opts *opts; ++ ++ opts = batadv_container_of(query_opts, struct neigh_netlink_opts, ++ query_opts); ++ ++ if (!genlmsg_valid_hdr(nlh, 0)) + return NL_OK; + +- sprintf(mac1, "%02x:%02x:%02x:%02x:%02x:%02x", +- orig[0], orig[1], orig[2], orig[3], orig[4], orig[5]); ++ ghdr = nlmsg_data(nlh); + +- struct json_object *obj = json_object_new_object(); +- if (!obj) ++ if (ghdr->cmd != BATADV_CMD_GET_NEIGHBORS) + return NL_OK; + +- struct json_object *interface; +- if (!json_object_object_get_ex(opts->interfaces, ifname, &interface)) { +- interface = json_object_new_object(); +- json_object_object_add(opts->interfaces, ifname, interface); +- } ++ if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), ++ genlmsg_len(ghdr), batadv_genl_policy)) ++ return NL_OK; + +- json_object_object_add(obj, "tq", json_object_new_int(tq)); +- json_object_object_add(obj, "lastseen", json_object_new_double(lastseen / 1000.)); +- json_object_object_add(obj, "best", json_object_new_boolean(nla_get_flag(attrs[BATADV_ATTR_FLAG_BEST]))); +- json_object_object_add(interface, mac1, obj); ++ if (batadv_genl_missing_attrs(attrs, parse_neigh_list_mandatory_batadv_v, ++ BATADV_ARRAY_SIZE(parse_neigh_list_mandatory_batadv_v))) ++ return NL_OK; + +- return NL_OK; ++ mac = nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]); ++ ++ return add_neighbour(opts, attrs, mac, ++ gluonutil_get_pseudo_tq(nla_get_u32(attrs[BATADV_ATTR_THROUGHPUT]))); + } + + static struct json_object * get_batadv(void) { +@@ -127,14 +173,27 @@ static struct json_object * get_batadv(void) { + }, + }; + int ret; ++ enum batadv_algo algo; + + opts.interfaces = json_object_new_object(); + if (!opts.interfaces) + return NULL; + +- ret = batadv_genl_query("bat0", BATADV_CMD_GET_ORIGINATORS, +- parse_orig_list_netlink_cb, NLM_F_DUMP, +- &opts.query_opts); ++ if (batadv_genl_get_algo("bat0", &algo) < 0) { ++ json_object_put(opts.interfaces); ++ return NULL; ++ } ++ ++ if (algo == BATADV_ALGO_BATMAN_V) { ++ ret = batadv_genl_query("bat0", BATADV_CMD_GET_NEIGHBORS, ++ parse_neigh_list_netlink_cb_batadv_v, NLM_F_DUMP, ++ &opts.query_opts); ++ } else { ++ ret = batadv_genl_query("bat0", BATADV_CMD_GET_ORIGINATORS, ++ parse_orig_list_netlink_cb_batadv_iv, NLM_F_DUMP, ++ &opts.query_opts); ++ } ++ + if (ret < 0) { + json_object_put(opts.interfaces); + return NULL; +diff --git a/package/gluon-mesh-batman-adv/src/respondd-statistics.c b/package/gluon-mesh-batman-adv/src/respondd-statistics.c +index 28131fda..004a3b2f 100644 +--- a/package/gluon-mesh-batman-adv/src/respondd-statistics.c ++++ b/package/gluon-mesh-batman-adv/src/respondd-statistics.c +@@ -34,16 +34,23 @@ struct clients_netlink_opts { + + struct gw_netlink_opts { + struct json_object *obj; ++ enum batadv_algo algo; + struct batadv_nlquery_opts query_opts; + }; + + +-static const enum batadv_nl_attrs gateways_mandatory[] = { ++static const enum batadv_nl_attrs gateways_mandatory_batadv_iv[] = { + BATADV_ATTR_ORIG_ADDRESS, + BATADV_ATTR_ROUTER, + BATADV_ATTR_TQ, + }; + ++static const enum batadv_nl_attrs gateways_mandatory_batadv_v[] = { ++ BATADV_ATTR_ORIG_ADDRESS, ++ BATADV_ATTR_ROUTER, ++ BATADV_ATTR_THROUGHPUT, ++}; ++ + static int parse_gw_list_netlink_cb(struct nl_msg *msg, void *arg) + { + struct nlattr *attrs[BATADV_ATTR_MAX+1]; +@@ -52,7 +59,6 @@ static int parse_gw_list_netlink_cb(struct nl_msg *msg, void *arg) + struct genlmsghdr *ghdr; + uint8_t *orig; + uint8_t *router; +- uint8_t tq; + struct gw_netlink_opts *opts; + char addr[18]; + +@@ -71,22 +77,34 @@ static int parse_gw_list_netlink_cb(struct nl_msg *msg, void *arg) + genlmsg_len(ghdr), batadv_genl_policy)) + return NL_OK; + +- if (batadv_genl_missing_attrs(attrs, gateways_mandatory, +- BATADV_ARRAY_SIZE(gateways_mandatory))) +- return NL_OK; ++ if (opts->algo == BATADV_ALGO_BATMAN_V) { ++ if (batadv_genl_missing_attrs(attrs, gateways_mandatory_batadv_v, ++ BATADV_ARRAY_SIZE(gateways_mandatory_batadv_v))) ++ return NL_OK; ++ } else { ++ if (batadv_genl_missing_attrs(attrs, gateways_mandatory_batadv_iv, ++ BATADV_ARRAY_SIZE(gateways_mandatory_batadv_iv))) ++ return NL_OK; ++ } + + if (!attrs[BATADV_ATTR_FLAG_BEST]) + return NL_OK; + + orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); + router = nla_data(attrs[BATADV_ATTR_ROUTER]); +- tq = nla_get_u8(attrs[BATADV_ATTR_TQ]); + + sprintf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", + orig[0], orig[1], orig[2], orig[3], orig[4], orig[5]); + + json_object_object_add(opts->obj, "gateway", json_object_new_string(addr)); +- json_object_object_add(opts->obj, "gateway_tq", json_object_new_int(tq)); ++ ++ if (opts->algo == BATADV_ALGO_BATMAN_V) { ++ uint32_t throughput = nla_get_u32(attrs[BATADV_ATTR_THROUGHPUT]); ++ json_object_object_add(opts->obj, "gateway_throughput", json_object_new_int64(throughput)); ++ } else { ++ uint8_t tq = nla_get_u8(attrs[BATADV_ATTR_TQ]); ++ json_object_object_add(opts->obj, "gateway_tq", json_object_new_int(tq)); ++ } + + sprintf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", + router[0], router[1], router[2], router[3], router[4], router[5]); +@@ -103,6 +121,8 @@ static void add_gateway(struct json_object *obj) { + .err = 0, + }, + }; ++ if (batadv_genl_get_algo("bat0", &opts.algo) < 0) ++ return; + + batadv_genl_query("bat0", BATADV_CMD_GET_GATEWAYS, + parse_gw_list_netlink_cb, NLM_F_DUMP, +diff --git a/package/gluon-radv-filterd/src/gluon-radv-filterd.c b/package/gluon-radv-filterd/src/gluon-radv-filterd.c +index 29d126ac..55c974d5 100644 +--- a/package/gluon-radv-filterd/src/gluon-radv-filterd.c ++++ b/package/gluon-radv-filterd/src/gluon-radv-filterd.c +@@ -37,11 +37,11 @@ + + #include "mac.h" + +-// Recheck TQs after this time even if no RA was received ++// Recheck metrics after this time even if no RA was received + #define MAX_INTERVAL 60 + +-// Recheck TQs at most this often, even if new RAs were received (they won't +-// become the preferred routers until the TQs have been rechecked) ++// Recheck metrics at most this often, even if new RAs were received (they won't ++// become the preferred routers until the metrics have been rechecked) + // Also, the first update will take at least this long + #define MIN_INTERVAL 15 + +@@ -87,7 +87,7 @@ struct router { + struct ether_addr src; + struct timespec eol; + struct ether_addr originator; +- uint16_t tq; ++ uint32_t metric; + }; + + static struct global { +@@ -95,9 +95,10 @@ static struct global { + struct router *routers; + const char *mesh_iface; + const char *chain; +- uint16_t max_tq; +- uint16_t hysteresis_thresh; ++ uint32_t max_metric; ++ uint32_t hysteresis_thresh; + struct router *best_router; ++ enum batadv_algo algo; + volatile sig_atomic_t stop_daemon; + } G = { + .mesh_iface = "bat0", +@@ -167,8 +168,9 @@ static void usage(const char *msg) { + fprintf(stderr, + "Usage: %s [-m ] [-t ] -c -i \n\n" + " -m B.A.T.M.A.N. advanced mesh interface used to get metric\n" +- " information (\"TQ\") for the available gateways. Default: bat0\n" +- " -t Minimum TQ difference required to switch the gateway.\n" ++ " information (TQ or throughput) for the available gateways.\n" ++ " Default: bat0\n" ++ " -t Minimum metric difference required to switch the gateway.\n" + " Default: 0\n" + " -c ebtables chain that should be managed by the daemon. The\n" + " chain already has to exist on program invocation and should\n" +@@ -268,9 +270,7 @@ static void parse_cmdline(int argc, char *argv[]) { + threshold = strtoul(optarg, &endptr, 10); + if (*endptr != '\0') + exit_errmsg("Threshold must be a number: %s", optarg); +- if (threshold > BATMAN_IV_MAX_THRESHOLD) +- exit_errmsg("Threshold too large: %ld (max is %d)", threshold, BATMAN_IV_MAX_THRESHOLD); +- G.hysteresis_thresh = (uint16_t) threshold; ++ G.hysteresis_thresh = (uint32_t) threshold; + break; + case 'h': + usage(NULL); +@@ -432,21 +432,26 @@ static int parse_tt_global(struct nl_msg *msg, + return NL_OK; + } + ++static const enum batadv_nl_attrs originator_mandatory_batadv_iv[] = { ++ BATADV_ATTR_ORIG_ADDRESS, ++ BATADV_ATTR_TQ, ++}; ++ ++static const enum batadv_nl_attrs originator_mandatory_batadv_v[] = { ++ BATADV_ATTR_ORIG_ADDRESS, ++ BATADV_ATTR_THROUGHPUT, ++}; ++ + static int parse_originator(struct nl_msg *msg, + void *arg __attribute__((unused))) + { +- +- static const enum batadv_nl_attrs mandatory[] = { +- BATADV_ATTR_ORIG_ADDRESS, +- BATADV_ATTR_TQ, +- }; + struct nlattr *attrs[BATADV_ATTR_MAX + 1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct ether_addr mac_a; + struct genlmsghdr *ghdr; + struct router *router; + uint8_t *orig; +- uint8_t tq; ++ uint32_t metric; + + // parse netlink entry + if (!genlmsg_valid_hdr(nlh, 0)) +@@ -462,15 +467,24 @@ static int parse_originator(struct nl_msg *msg, + return NL_OK; + } + +- if (batadv_genl_missing_attrs(attrs, mandatory, ARRAY_SIZE(mandatory))) +- return NL_OK; +- +- orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); +- tq = nla_get_u8(attrs[BATADV_ATTR_TQ]); ++ if (G.algo == BATADV_ALGO_BATMAN_V) { ++ if (batadv_genl_missing_attrs(attrs, originator_mandatory_batadv_v, ++ ARRAY_SIZE(originator_mandatory_batadv_v))) ++ return NL_OK; ++ } else { ++ if (batadv_genl_missing_attrs(attrs, originator_mandatory_batadv_iv, ++ ARRAY_SIZE(originator_mandatory_batadv_iv))) ++ return NL_OK; ++ } + + if (!attrs[BATADV_ATTR_FLAG_BEST]) + return NL_OK; + ++ orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); ++ metric = (G.algo == BATADV_ALGO_BATMAN_V) ++ ? nla_get_u32(attrs[BATADV_ATTR_THROUGHPUT]) ++ : nla_get_u8(attrs[BATADV_ATTR_TQ]); ++ + MAC2ETHER(mac_a, orig); + + // update router +@@ -478,11 +492,11 @@ static int parse_originator(struct nl_msg *msg, + if (!router) + return NL_OK; + +- DEBUG_MSG("Found TQ for router " F_MAC " (originator " F_MAC "), it's %d", +- F_MAC_VAR(router->src), F_MAC_VAR(router->originator), tq); +- router->tq = tq; +- if (router->tq > G.max_tq) +- G.max_tq = router->tq; ++ DEBUG_MSG("Found metric for router " F_MAC " (originator " F_MAC "), it's %u", ++ F_MAC_VAR(router->src), F_MAC_VAR(router->originator), metric); ++ router->metric = metric; ++ if (router->metric > G.max_metric) ++ G.max_metric = router->metric; + + return NL_OK; + } +@@ -525,25 +539,25 @@ static int parse_tt_local(struct nl_msg *msg, + if (!router) + return NL_OK; + +- router->tq = UINT16_MAX; +- DEBUG_MSG("Found router " F_MAC " in transtable_local, assigning TQ %d", +- F_MAC_VAR(router->src), router->tq); +- if (router->tq > G.max_tq) +- G.max_tq = router->tq; ++ router->metric = UINT32_MAX; ++ DEBUG_MSG("Found router " F_MAC " in transtable_local, assigning metric %u", ++ F_MAC_VAR(router->src), router->metric); ++ if (router->metric > G.max_metric) ++ G.max_metric = router->metric; + + return NL_OK; + } + +-static void update_tqs(void) { ++static void update_metrics(void) { + static const struct ether_addr unspec = {}; + struct router *router; + bool update_originators = false; + struct batadv_nlquery_opts opts; + int ret; + +- // reset TQs ++ // reset metrics + foreach(router, G.routers) { +- router->tq = 0; ++ router->metric = 0; + if (ether_addr_equal(router->originator, unspec)) + update_originators = true; + } +@@ -558,8 +572,8 @@ static void update_tqs(void) { + fprintf(stderr, "Parsing of global translation table failed\n"); + } + +- // look up TQs of originators +- G.max_tq = 0; ++ // look up metrics of originators ++ G.max_metric = 0; + opts.err = 0; + ret = batadv_genl_query(G.mesh_iface, + BATADV_CMD_GET_ORIGINATORS, +@@ -567,9 +581,9 @@ static void update_tqs(void) { + if (ret < 0) + fprintf(stderr, "Parsing of originators failed\n"); + +- // if all routers have a TQ value, we don't need to check translocal ++ // if all routers have a metric value, we don't need to check translocal + foreach(router, G.routers) { +- if (router->tq == 0) ++ if (router->metric == 0) + break; + } + if (router != NULL) { +@@ -582,14 +596,14 @@ static void update_tqs(void) { + } + + foreach(router, G.routers) { +- if (router->tq == 0) { ++ if (router->metric == 0) { + if (ether_addr_equal(router->originator, unspec)) + DEBUG_MSG( + "Unable to find router " F_MAC " in transtable_{global,local}", + F_MAC_VAR(router->src)); + else + DEBUG_MSG( +- "Unable to find TQ for originator " F_MAC " (router " F_MAC ")", ++ "Unable to find metric for originator " F_MAC " (router " F_MAC ")", + F_MAC_VAR(router->originator), + F_MAC_VAR(router->src)); + } +@@ -655,11 +669,11 @@ static bool election_required(void) + if (!G.best_router) + return true; + +- /* should never happen. G.max_tq also contains G.best_router->tq */ +- if (G.max_tq < G.best_router->tq) ++ /* should never happen. G.max_metric also contains G.best_router->metric */ ++ if (G.max_metric < G.best_router->metric) + return false; + +- if ((G.max_tq - G.best_router->tq) <= G.hysteresis_thresh) ++ if ((G.max_metric - G.best_router->metric) <= G.hysteresis_thresh) + return false; + + return true; +@@ -673,29 +687,29 @@ static void update_ebtables(void) { + struct router *router; + + if (!election_required()) { +- DEBUG_MSG(F_MAC " is still good enough with TQ=%d (max_tq=%d), not executing ebtables", ++ DEBUG_MSG(F_MAC " is still good enough with metric=%u (max_metric=%u), not executing ebtables", + F_MAC_VAR(G.best_router->src), +- G.best_router->tq, +- G.max_tq); ++ G.best_router->metric, ++ G.max_metric); + return; + } + + foreach(router, G.routers) { +- if (router->tq == G.max_tq) { ++ if (router->metric == G.max_metric) { + snprintf(mac, sizeof(mac), F_MAC, F_MAC_VAR(router->src)); + break; + } + } + if (G.best_router) +- fprintf(stderr, "Switching from " F_MAC " (TQ=%d) to %s (TQ=%d)\n", ++ fprintf(stderr, "Switching from " F_MAC " (metric=%u) to %s (metric=%u)\n", + F_MAC_VAR(G.best_router->src), +- G.best_router->tq, ++ G.best_router->metric, + mac, +- G.max_tq); ++ G.max_metric); + else +- fprintf(stderr, "Switching to %s (TQ=%d)\n", ++ fprintf(stderr, "Switching to %s (metric=%u)\n", + mac, +- G.max_tq); ++ G.max_metric); + G.best_router = router; + + if (fork_execvp_timeout(&timeout, "ebtables-tiny", (const char *[]) +@@ -743,6 +757,16 @@ int main(int argc, char *argv[]) { + if (G.chain == NULL) + usage("No chain set!"); + ++ if (batadv_genl_get_algo(G.mesh_iface, &G.algo) < 0) ++ exit_errmsg("Failed to detect batman-adv routing algorithm on %s", G.mesh_iface); ++ ++ fprintf(stderr, "Using batman-adv algorithm: %s\n", ++ G.algo == BATADV_ALGO_BATMAN_V ? "BATMAN_V" : "BATMAN_IV"); ++ ++ if (G.algo == BATADV_ALGO_BATMAN_IV && G.hysteresis_thresh > BATMAN_IV_MAX_THRESHOLD) ++ exit_errmsg("Threshold too large: %u (max is %u)", ++ G.hysteresis_thresh, BATMAN_IV_MAX_THRESHOLD); ++ + G.stop_daemon = 0; + signal(SIGINT, sighandler); + signal(SIGTERM, sighandler); +@@ -780,7 +804,7 @@ int main(int argc, char *argv[]) { + next_invalidation.tv_sec += ORIGINATOR_CACHE_TTL; + } + +- update_tqs(); ++ update_metrics(); + update_ebtables(); + + next_update = now; +diff --git a/package/gluon-status-page-mesh-batman-adv/luasrc/lib/gluon/status-page/mesh.lua b/package/gluon-status-page-mesh-batman-adv/luasrc/lib/gluon/status-page/mesh.lua +index 733e6d7c..010371c8 100644 +--- a/package/gluon-status-page-mesh-batman-adv/luasrc/lib/gluon/status-page/mesh.lua ++++ b/package/gluon-status-page-mesh-batman-adv/luasrc/lib/gluon/status-page/mesh.lua +@@ -4,7 +4,9 @@ return { + -- 1) the internal identifier (JSON key) + -- 2) human-readable key (not translatable yet) + -- 3) value suffix (optional) ++ -- 4) formatter name (optional) -- key into status-page.js formats{} + attrs = { + {'tq', 'TQ', ' %'}, ++ {'tp', 'Throughput', 'bit/s', 'bitrate'}, + }, + } +diff --git a/package/gluon-status-page-mesh-batman-adv/src/neighbours-batadv.c b/package/gluon-status-page-mesh-batman-adv/src/neighbours-batadv.c +index 58e626c9..dd84200e 100644 +--- a/package/gluon-status-page-mesh-batman-adv/src/neighbours-batadv.c ++++ b/package/gluon-status-page-mesh-batman-adv/src/neighbours-batadv.c +@@ -11,10 +11,12 @@ + + struct neigh_netlink_opts { + struct json_object *obj; ++ enum batadv_algo algo; + struct batadv_nlquery_opts query_opts; + }; + +-static const enum batadv_nl_attrs parse_orig_list_mandatory[] = { ++/* Batman IV mandatory attrs */ ++static const enum batadv_nl_attrs parse_orig_list_mandatory_batadv_iv[] = { + BATADV_ATTR_ORIG_ADDRESS, + BATADV_ATTR_NEIGH_ADDRESS, + BATADV_ATTR_TQ, +@@ -22,15 +24,21 @@ static const enum batadv_nl_attrs parse_orig_list_mandatory[] = { + BATADV_ATTR_LAST_SEEN_MSECS, + }; + +-static int parse_orig_list_netlink_cb(struct nl_msg *msg, void *arg) ++/* Batman V mandatory attrs */ ++static const enum batadv_nl_attrs parse_neigh_list_mandatory_batadv_v[] = { ++ BATADV_ATTR_NEIGH_ADDRESS, ++ BATADV_ATTR_THROUGHPUT, ++ BATADV_ATTR_HARD_IFINDEX, ++ BATADV_ATTR_LAST_SEEN_MSECS, ++}; ++ ++static int parse_orig_neigh_list_netlink_cb(struct nl_msg *msg, void *arg) + { + struct nlattr *attrs[BATADV_ATTR_MAX+1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct batadv_nlquery_opts *query_opts = arg; + struct genlmsghdr *ghdr; +- uint8_t *orig; +- uint8_t *dest; +- uint8_t tq; ++ uint8_t *mac; + uint32_t hardif; + char ifname_buf[IF_NAMESIZE], *ifname; + struct neigh_netlink_opts *opts; +@@ -43,37 +51,53 @@ static int parse_orig_list_netlink_cb(struct nl_msg *msg, void *arg) + + ghdr = nlmsg_data(nlh); + +- if (ghdr->cmd != BATADV_CMD_GET_ORIGINATORS) +- return NL_OK; +- + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_genl_policy)) + return NL_OK; + +- if (batadv_genl_missing_attrs(attrs, parse_orig_list_mandatory, +- BATADV_ARRAY_SIZE(parse_orig_list_mandatory))) +- return NL_OK; ++ if (opts->algo == BATADV_ALGO_BATMAN_V) { ++ if (ghdr->cmd != BATADV_CMD_GET_NEIGHBORS) ++ return NL_OK; + +- orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); +- dest = nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]); +- tq = nla_get_u8(attrs[BATADV_ATTR_TQ]); +- hardif = nla_get_u32(attrs[BATADV_ATTR_HARD_IFINDEX]); ++ if (batadv_genl_missing_attrs(attrs, parse_neigh_list_mandatory_batadv_v, ++ BATADV_ARRAY_SIZE(parse_neigh_list_mandatory_batadv_v))) ++ return NL_OK; + +- if (memcmp(orig, dest, 6) != 0) +- return NL_OK; ++ mac = nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]); ++ } else { ++ if (ghdr->cmd != BATADV_CMD_GET_ORIGINATORS) ++ return NL_OK; ++ ++ if (batadv_genl_missing_attrs(attrs, parse_orig_list_mandatory_batadv_iv, ++ BATADV_ARRAY_SIZE(parse_orig_list_mandatory_batadv_iv))) ++ return NL_OK; ++ ++ mac = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); ++ if (memcmp(mac, nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]), 6) != 0) ++ return NL_OK; ++ } ++ ++ hardif = nla_get_u32(attrs[BATADV_ATTR_HARD_IFINDEX]); + + ifname = if_indextoname(hardif, ifname_buf); + if (!ifname) + return NL_OK; + + sprintf(mac1, "%02x:%02x:%02x:%02x:%02x:%02x", +- orig[0], orig[1], orig[2], orig[3], orig[4], orig[5]); ++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + struct json_object *neigh = json_object_new_object(); + if (!neigh) + return NL_OK; + +- json_object_object_add(neigh, "tq", json_object_new_int(tq * 100 / 255)); ++ if (opts->algo == BATADV_ALGO_BATMAN_V) { ++ json_object_object_add(neigh, "tp", ++ json_object_new_int64(nla_get_u32(attrs[BATADV_ATTR_THROUGHPUT]))); ++ } else { ++ uint8_t tq = nla_get_u8(attrs[BATADV_ATTR_TQ]); ++ json_object_object_add(neigh, "tq", json_object_new_int(tq * 100 / 255)); ++ } ++ + json_object_object_add(neigh, "ifname", json_object_new_string(ifname)); + json_object_object_add(neigh, "best", json_object_new_boolean(nla_get_flag(attrs[BATADV_ATTR_FLAG_BEST]))); + +@@ -94,9 +118,21 @@ static json_object *neighbours(void) { + if (!opts.obj) + return NULL; + +- ret = batadv_genl_query("bat0", BATADV_CMD_GET_ORIGINATORS, +- parse_orig_list_netlink_cb, NLM_F_DUMP, +- &opts.query_opts); ++ if (batadv_genl_get_algo("bat0", &opts.algo) < 0) { ++ json_object_put(opts.obj); ++ return NULL; ++ } ++ ++ if (opts.algo == BATADV_ALGO_BATMAN_V) { ++ ret = batadv_genl_query("bat0", BATADV_CMD_GET_NEIGHBORS, ++ parse_orig_neigh_list_netlink_cb, NLM_F_DUMP, ++ &opts.query_opts); ++ } else { ++ ret = batadv_genl_query("bat0", BATADV_CMD_GET_ORIGINATORS, ++ parse_orig_neigh_list_netlink_cb, NLM_F_DUMP, ++ &opts.query_opts); ++ } ++ + if (ret < 0) { + json_object_put(opts.obj); + return NULL; +diff --git a/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html b/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html +index 6b458d49..9ce21342 100644 +--- a/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html ++++ b/package/gluon-status-page/files/lib/gluon/status-page/view/status-page.html +@@ -290,7 +290,7 @@ + + <%:Node%> + <% for i, v in ipairs(mesh.attrs or {}) do %> +- ><%| v[2] %> ++ ><%| v[2] %> + <% end %> + <% if wireless then %> + dBm +diff --git a/package/gluon-status-page/javascript/status-page.js b/package/gluon-status-page/javascript/status-page.js +index 5ad207f2..d26d3172 100644 +--- a/package/gluon-status-page/javascript/status-page.js ++++ b/package/gluon-status-page/javascript/status-page.js +@@ -136,6 +136,10 @@ + }, + 'tq': function(value) { + return formatNumber(100/255 * value, 1) + '%'; ++ }, ++ // input value is in kbit/s ++ 'bitrate': function(value) { ++ return prettyPrefix([ "", "K", "M", "G", "T" ], 1000, value * 1000); + } + } + +@@ -475,6 +479,7 @@ + return; + + var suffix = attr.getAttribute('data-suffix') || ''; ++ var formatter = attr.getAttribute('data-format') || ''; + + var td = el.insertCell(); + td.textContent = '-'; +@@ -483,6 +488,7 @@ + meshAttrs[key] = { + 'td': td, + 'suffix': suffix, ++ 'formatter': formatter, + }; + } + +@@ -667,7 +673,13 @@ + 'update_mesh': function(mesh) { + Object.keys(meshAttrs).forEach(function(key) { + var attr = meshAttrs[key]; +- attr.td.textContent = mesh[key] + attr.suffix; ++ var raw = mesh[key]; ++ if (raw === undefined) ++ return; ++ var rendered = (attr.formatter && formats[attr.formatter]) ++ ? formats[attr.formatter](raw) ++ : raw; ++ attr.td.textContent = rendered + attr.suffix; + }); + + updated(); +diff --git a/package/gluon-status-page/javascript/status-page.min.js b/package/gluon-status-page/javascript/status-page.min.js +index b5b84133..5958aa65 100644 +--- a/package/gluon-status-page/javascript/status-page.min.js ++++ b/package/gluon-status-page/javascript/status-page.min.js +@@ -1 +1 @@ +-"use strict";!function(){var o=JSON.parse(document.body.getAttribute("data-translations"));function i(t,e){return t.toFixed(e).replace(/\./,o["."])}function a(t,e){e--;for(var n=t;10<=n&&0e[0]||t[1]e[1]?1:0}),(t=t[0][2])&&!/^fe80:/i.test(t)?t:void 0}return t.wireless&&((g=o.insertCell()).textContent="-",g.setAttribute("data-label",r.children[Object.keys(s).length+1].textContent),(p=o.insertCell()).textContent="-",p.setAttribute("data-label",r.children[Object.keys(s).length+2].textContent),(m=o.insertCell()).textContent="-",m.setAttribute("data-label",r.children[Object.keys(s).length+3].textContent),v=A(e),t.signalgraph.addSignal(v)),o.onmouseenter=function(){o.classList.add("highlight"),v&&(v.highlight=!0)},o.onmouseleave=function(){o.classList.remove("highlight"),v&&(v.highlight=!1)},y(),{get_hostname:function(){return u.textContent},get_addr:function(){return a},update_nodeinfo:function(t){var e,n,i,r,o;(a=x(t.network.addresses))&&("span"===u.nodeName.toLowerCase()&&(e=u,u=document.createElement("a"),e.parentNode.replaceChild(u,e)),u.href="http://["+a+"]/"),u.textContent=t.hostname,E&&t.location&&(e=E.latitude,n=E.longitude,i=t.location.latitude,t=t.location.longitude,r=Math.PI/180,o=(i*=r)-(e*=r),t=(t*=r)-(n*=r),r=Math.sin(o/2)*Math.sin(o/2)+Math.sin(t/2)*Math.sin(t/2)*Math.cos(e)*Math.cos(i),n=6372.8*(2*Math.asin(Math.sqrt(r))),p.textContent=Math.round(1e3*n)+" m"),y()},update_mesh:function(n){Object.keys(s).forEach(function(t){var e=s[t];e.td.textContent=n[t]+e.suffix}),y()},update_wifi:function(t){g.textContent=t.signal,m.textContent=Math.round(t.inactive/1e3)+" s",o.classList.toggle("inactive",200=10&&n>0;r/=10)n--;return e(t,n)}function r(t,e,r){var i=0;if(void 0===r)return"- ";for(;r>e&&i1&&(a+=t["%s days"].sprintf(r)+", "),a+=i+":",n<10&&(a+="0"),a+=n},packetsDiff:function(n,r,i){if(i>0)return a=(n-r)/i,t["%s packets/s"].sprintf(e(a,0));var a},bytesDiff:function(t,e,n){if(n>0)return i(8*((t-e)/n))+"bps"},bytes:function(t){return i(t)+"B"},neighbour:function(t){if(!t)return"";for(var e in d){var n=d[e].lookup_neigh(t);if(n){var r=document.createElement("span");r.appendChild(document.createTextNode("via "));var i=document.createElement("a");return i.href="http://["+n.get_addr()+"]/",i.textContent=n.get_hostname(),r.appendChild(i),r.appendChild(document.createTextNode(" ("+e+")")),r}}return"via "+t+" (unknown iface)"},tq:function(t){return n(100/255*t,1)+"%"},bitrate:function(t){return r(["","K","M","G","T"],1e3,1e3*t)}};function o(t,e){return e.split("/").forEach((function(e){t&&(t=t[e])})),t}function c(t,e){var n=new EventSource(t),r={};n.onmessage=function(t){var n=JSON.parse(t.data);e(n,r),r=n},n.onerror=function(){n.close(),window.setTimeout((function(){c(t,e)}),3e3)}}var u,s=document.body.getAttribute("data-node-address");try{u=JSON.parse(document.body.getAttribute("data-node-location"))}catch(t){}var l=document.querySelectorAll("[data-statistics]");c("/cgi-bin/dyn/statistics",(function(e,n){var r=e.uptime-n.uptime;l.forEach((function(t){var i=t.getAttribute("data-statistics"),c=t.getAttribute("data-format"),u=o(n,i),s=o(e,i);try{var l=a[c](s,u,r);if("object"==typeof l)t.lastChild&&t.removeChild(t.lastChild),t.appendChild(l);else t.textContent=l}catch(t){console.error(t)}}));try{!function(e){var n=document.getElementById("mesh-vpn");if(e){n.style.display="";for(var r=document.getElementById("mesh-vpn-peers");r.lastChild;)r.removeChild(r.lastChild);var i=function t(e,n){return Object.keys(n.peers||{}).forEach((function(t){e.push([t,n.peers[t]])})),Object.keys(n.groups||{}).forEach((function(r){t(e,n.groups[r])})),e}([],e);i.sort(),i.forEach((function(e){var n=document.createElement("tr"),i=document.createElement("th");i.textContent=e[0],n.appendChild(i);var o=document.createElement("td");if(e[1]&&null!=e[1].established){var c=e[1].method?", "+e[1].method:"";o.textContent=t.connected+" ("+a.time(e[1].established)+c+")"}else o.textContent=t["not connected"];n.appendChild(o),r.appendChild(n)}))}else n.style.display="none"}(e.mesh_vpn)}catch(t){console.error(t)}}));var d={};function f(t){var e=document.createElement("canvas"),n=e.getContext("2d"),r=null;return{canvas:e,highlight:!1,resize:function(t,r){var i;try{i=n.getImageData(0,0,t,r)}catch(t){}e.width=t,e.height=r,i&&n.putImageData(i,0,0)},draw:function(i,a){var o=a(r);n.clearRect(i,0,5,e.height),o&&function(e,r){n.beginPath(),n.fillStyle=t,n.arc(e,r,1.2,0,2*Math.PI,!1),n.closePath(),n.fill()}(i,o)},set:function(t){r=t}}}function h(){var t=-100,e=0,n=0,r=[],i=document.createElement("canvas");i.className="signalgraph",i.height=200;var a=i.getContext("2d");function o(t,e,n,r){return(e*t+n*(r-t))/r}function c(){i.width=i.clientWidth,r.forEach((function(t){t.resize(i.width,i.height)}))}function u(){if(0!==i.clientWidth){i.width!==i.clientWidth&&c(),a.clearRect(0,0,i.width,i.height);var u=!1;r.forEach((function(t){t.highlight&&(u=!0)})),a.save(),r.forEach((function(r){u&&(a.globalAlpha=.2),r.highlight&&(a.globalAlpha=1),r.draw(n,(function(n){return function(t,e,n,r){return(1-(t-e)/(n-e))*r}(n,t,e,i.height)})),a.drawImage(r.canvas,0,0)})),a.restore(),a.save(),a.beginPath(),a.strokeStyle="rgba(255, 180, 0, 0.15)",a.lineWidth=5,a.moveTo(n+2.5,0),a.lineTo(n+2.5,i.height),a.stroke(),function(){var n=Math.floor(i.height/40);a.save(),a.lineWidth=.5,a.strokeStyle="rgba(0, 0, 0, 0.25)",a.fillStyle="rgba(0, 0, 0, 0.5)",a.textAlign="end",a.textBaseline="bottom",a.beginPath();for(var r=0;r40&&(u(),n=(n+1)%i.width,s=e),window.requestAnimationFrame(t)})),{el:i,addSignal:function(t){r.push(t),t.resize(i.width,i.height)},removeSignal:function(t){r.splice(r.indexOf(t),1)}}}function g(t,e,n,r){var i=t.tbody.querySelector("tr"),o=t.tbody.insertRow(),c=o.insertCell();if(c.setAttribute("data-label",i.children[0].textContent),t.wireless){var l=document.createElement("span");l.textContent="⬤ ",l.style.color=n,c.appendChild(l)}var d=document.createElement("span");d.textContent=e,c.appendChild(d);var h,g,v,m,p,b={};function C(t){var e=t.getAttribute("data-key");if(e){var n=t.getAttribute("data-suffix")||"",r=t.getAttribute("data-format")||"",i=o.insertCell();i.textContent="-",i.setAttribute("data-label",t.textContent),b[e]={td:i,suffix:n,formatter:r}}}for(var y=0;ye[0]||t[1]e[1]?1:0}));var n=t[0][2];return n&&!/^fe80:/i.test(n)?n:void 0}}(t.network.addresses),e){if("span"===d.nodeName.toLowerCase()){var n=d;d=document.createElement("a"),n.parentNode.replaceChild(d,n)}d.href="http://["+e+"]/"}if(d.textContent=t.hostname,u&&t.location){var r=(i=u.latitude,a=u.longitude,o=t.location.latitude,c=t.location.longitude,l=Math.PI/180,f=(o*=l)-(i*=l),h=(c*=l)-(a*=l),v=Math.sin(f/2)*Math.sin(f/2)+Math.sin(h/2)*Math.sin(h/2)*Math.cos(i)*Math.cos(o),2*Math.asin(Math.sqrt(v))*6372.8);g.textContent=Math.round(1e3*r)+" m"}var i,a,o,c,l,f,h,v;w()},update_mesh:function(t){Object.keys(b).forEach((function(e){var n=b[e],r=t[e];if(void 0!==r){var i=n.formatter&&a[n.formatter]?a[n.formatter](r):r;n.td.textContent=i+n.suffix}})),w()},update_wifi:function(t){h.textContent=t.signal,v.textContent=Math.round(t.inactive/1e3)+" s",o.classList.toggle("inactive",t.inactive>200),m.set(t.inactive>200?null:t.signal),w()}}}function v(t,e,n){var r,i={};n&&(r=h(),t.appendChild(r.el));var a={tbody:t.querySelector("tbody"),signalgraph:r,ifname:e,wireless:n},o=!1,u={},s=[];function l(){if(!o){o=!0;var t=new EventSource("/cgi-bin/dyn/neighbours-nodeinfo?"+encodeURIComponent(e));t.addEventListener("neighbour",(function(t){try{var e=JSON.parse(t.data);(n=e,r=[],a=n.network.mesh,Object.keys(a).forEach((function(t){var e=a[t].interfaces;Object.keys(e).forEach((function(t){e[t].forEach((function(t){r.push(t)}))}))})),r).forEach((function(t){var n=i[t];if(n){delete u[t];try{n.update_nodeinfo(e)}catch(t){console.error(t)}}}))}catch(t){console.error(t)}var n,r,a}),!1),t.onerror=function(){t.close(),o=!1,Object.keys(u).forEach((function(t){u[t]>0&&(u[t]--,l())}))}}}function d(t){var e=i[t];return e||(u[t]=3,e=i[t]=g(a,t,(s[0]||(s=["#396AB1","#DA7C30","#3E9651","#CC2529","#535154","#6B4C9A","#922428","#948B3D"]),s.shift()),(function(){delete u[t],delete i[t]})),l()),e}return n&&c("/cgi-bin/dyn/stations?"+encodeURIComponent(e),(function(t){Object.keys(t).forEach((function(e){var n=t[e];d(e).update_wifi(n)}))})),{get_neigh:d,lookup_neigh:function(t){return i[t]}}}document.querySelectorAll("[data-interface]").forEach((function(t){var e=t.getAttribute("data-interface"),n=(t.getAttribute("data-interface-address"),!!t.getAttribute("data-interface-wireless"));d[e]=v(t,e,n)}));var m=document.body.getAttribute("data-mesh-provider");m&&c(m,(function(t){Object.keys(t).forEach((function(e){var n=t[e],r=d[n.ifname];r&&r.get_neigh(e).update_mesh(n)}))}))}(); +\ No newline at end of file +diff --git a/package/libbatadv/src/batadv-genl.c b/package/libbatadv/src/batadv-genl.c +index 7d421dbe..b159c034 100644 +--- a/package/libbatadv/src/batadv-genl.c ++++ b/package/libbatadv/src/batadv-genl.c +@@ -361,3 +361,105 @@ err_free_sock: + + return query_opts->err; + } ++ ++struct batadv_algoname_opts { ++ char *algoname; ++ size_t algoname_len; ++ bool found; ++ struct batadv_nlquery_opts query_opts; ++}; ++ ++static int batadv_algoname_cb(struct nl_msg *msg, void *arg) ++{ ++ struct nlattr *attrs[BATADV_ATTR_MAX + 1]; ++ struct batadv_nlquery_opts *query_opts = arg; ++ struct batadv_algoname_opts *opts; ++ struct nlmsghdr *nlh = nlmsg_hdr(msg); ++ struct genlmsghdr *ghdr; ++ ++ opts = batadv_container_of(query_opts, struct batadv_algoname_opts, ++ query_opts); ++ ++ if (!genlmsg_valid_hdr(nlh, 0)) ++ return NL_OK; ++ ++ ghdr = nlmsg_data(nlh); ++ ++ if (ghdr->cmd != BATADV_CMD_GET_MESH) ++ return NL_OK; ++ ++ if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), ++ genlmsg_len(ghdr), batadv_genl_policy)) ++ return NL_OK; ++ ++ if (!attrs[BATADV_ATTR_ALGO_NAME]) ++ return NL_OK; ++ ++ nla_strlcpy(opts->algoname, attrs[BATADV_ATTR_ALGO_NAME], ++ opts->algoname_len); ++ ++ opts->found = true; ++ return NL_OK; ++} ++ ++/** ++ * batadv_genl_get_algoname() - Query the routing algorithm name of a mesh ++ * @mesh_iface: name of the batman-adv mesh interface ++ * @algoname: buffer to store the algorithm name (e.g. "BATMAN_IV", "BATMAN_V") ++ * @algoname_len: size of @algoname buffer ++ * ++ * Return: 0 on success or negative error value otherwise ++ */ ++__attribute__ ((visibility ("default"))) ++int batadv_genl_get_algoname(const char *mesh_iface, char *algoname, ++ size_t algoname_len) ++{ ++ struct batadv_algoname_opts opts = { ++ .algoname = algoname, ++ .algoname_len = algoname_len, ++ .found = false, ++ .query_opts = { .err = 0 }, ++ }; ++ int ret; ++ ++ ret = batadv_genl_query(mesh_iface, BATADV_CMD_GET_MESH, ++ batadv_algoname_cb, 0, &opts.query_opts); ++ if (ret < 0) ++ return ret; ++ ++ if (!opts.found) ++ return -EOPNOTSUPP; ++ ++ return 0; ++} ++ ++/** ++ * batadv_genl_get_algo() - Query the routing algorithm of a mesh as enum ++ * @mesh_iface: name of the batman-adv mesh interface ++ * @algo: pointer to store the algorithm (BATADV_ALGO_BATMAN_IV or ++ * BATADV_ALGO_BATMAN_V) ++ * ++ * Return: 0 on success or negative error value otherwise ++ */ ++__attribute__ ((visibility ("default"))) ++int batadv_genl_get_algo(const char *mesh_iface, enum batadv_algo *algo) ++{ ++ char algoname[256]; ++ int ret; ++ ++ *algo = BATADV_ALGO_UNKNOWN; ++ ++ ret = batadv_genl_get_algoname(mesh_iface, algoname, sizeof(algoname)); ++ if (ret < 0) ++ return ret; ++ ++ if (strcmp(algoname, "BATMAN_IV") == 0) { ++ *algo = BATADV_ALGO_BATMAN_IV; ++ return 0; ++ } else if (strcmp(algoname, "BATMAN_V") == 0) { ++ *algo = BATADV_ALGO_BATMAN_V; ++ return 0; ++ } ++ ++ return -EINVAL; ++} +diff --git a/package/libbatadv/src/batadv-genl.h b/package/libbatadv/src/batadv-genl.h +index d9912fb6..0bef1449 100644 +--- a/package/libbatadv/src/batadv-genl.h ++++ b/package/libbatadv/src/batadv-genl.h +@@ -29,10 +29,21 @@ + #include + #include + #include ++#include + #include + + #include "batman_adv.h" + ++/* Zero-init default at slot 0: a struct field that misses ++ * batadv_genl_get_algo() trips a defined sentinel rather than ++ * silently being treated as BATMAN_IV. ++ */ ++enum batadv_algo { ++ BATADV_ALGO_UNKNOWN = 0, ++ BATADV_ALGO_BATMAN_IV, ++ BATADV_ALGO_BATMAN_V, ++}; ++ + /** + * struct batadv_nlquery_opts - internal state for batadv_genl_query() + * +@@ -97,4 +108,9 @@ int batadv_genl_query(const char *mesh_iface, enum batadv_nl_commands nl_cmd, + nl_recvmsg_msg_cb_t callback, int flags, + struct batadv_nlquery_opts *query_opts); + ++int batadv_genl_get_algoname(const char *mesh_iface, char *algoname, ++ size_t algoname_len); ++ ++int batadv_genl_get_algo(const char *mesh_iface, enum batadv_algo *algo); ++ + #endif /* _BATADV_GENL_H_ */ +diff --git a/package/libgluonutil/src/CMakeLists.txt b/package/libgluonutil/src/CMakeLists.txt +index a20ff0bd..6ff5b1c4 100644 +--- a/package/libgluonutil/src/CMakeLists.txt ++++ b/package/libgluonutil/src/CMakeLists.txt +@@ -6,7 +6,7 @@ set_property(DIRECTORY PROPERTY COMPILE_DEFINITIONS _GNU_SOURCE) + + add_library(gluonutil SHARED libgluonutil.c) + set_property(TARGET gluonutil PROPERTY COMPILE_FLAGS "-Wall -std=c99") +-target_link_libraries(gluonutil json-c uci) ++target_link_libraries(gluonutil json-c uci m) + install(TARGETS gluonutil + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib +diff --git a/package/libgluonutil/src/libgluonutil.c b/package/libgluonutil/src/libgluonutil.c +index 354f7179..ea39d2d7 100644 +--- a/package/libgluonutil/src/libgluonutil.c ++++ b/package/libgluonutil/src/libgluonutil.c +@@ -11,6 +11,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -337,3 +338,15 @@ err: + json_object_put(site); + return NULL; + } ++ ++uint8_t gluonutil_get_pseudo_tq(uint32_t throughput) { ++ return throughput >= 54000 ? 255 : ++ throughput < 417 ? 0 : ++ (uint8_t)( ++ ( ++ 1.42459274279287898080 * log2(throughput) - ++ 12.39555493934044793479 ++ ) ++ * 25.5 ++ ); ++} +diff --git a/package/libgluonutil/src/libgluonutil.h b/package/libgluonutil/src/libgluonutil.h +index 5ce9d448..69fee07d 100644 +--- a/package/libgluonutil/src/libgluonutil.h ++++ b/package/libgluonutil/src/libgluonutil.h +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + + + char * gluonutil_read_line(const char *filename); +@@ -35,4 +36,6 @@ char * gluonutil_get_domain(void); + char * gluonutil_get_primary_domain(void); + struct json_object * gluonutil_load_site_config(void); + ++uint8_t gluonutil_get_pseudo_tq(uint32_t throughput); ++ + #endif /* _LIBGLUON_LIBGLUON_H_ */ +-- +2.43.0 + diff --git a/patches/0002-wired-tpo-add-wireguard-support-to-Batman-V.patch b/patches/0002-wired-tpo-add-wireguard-support-to-Batman-V.patch deleted file mode 100644 index 49a2b453..00000000 --- a/patches/0002-wired-tpo-add-wireguard-support-to-Batman-V.patch +++ /dev/null @@ -1,25 +0,0 @@ -From bbbead73c1696398e7df49d40b4263e63012789d Mon Sep 17 00:00:00 2001 -From: Annika Wickert -Date: Mon, 31 Aug 2020 11:54:27 +0200 -Subject: [PATCH 02/11] wired tpo: add wireguard support to Batman V - ---- - .../core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -index 7185b4a0..2c488f16 100755 ---- a/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -+++ b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -@@ -4,6 +4,8 @@ if [ -f /sys/devices/virtual/net/vx_mesh_lan/batman_adv/throughput_override ]; t - - if [ -f /sys/devices/virtual/net/vx_mesh_wan/batman_adv/throughput_override ]; then echo 1000000 > /sys/devices/virtual/net/vx_mesh_wan/batman_adv/throughput_override; fi - -+if [ -f /sys/devices/virtual/net/vx_mesh_vpn/batman_adv/throughput_override ]; then echo 1000000 > /sys/devices/virtual/net/vx_mesh_vpn/batman_adv/throughput_override; fi -+ - if [ -f /sys/devices/virtual/net/br-wan/batman_adv/throughput_override ]; then echo 1000000 > /sys/devices/virtual/net/br-wan/batman_adv/throughput_override; fi - - if [ -f /sys/devices/virtual/net/mesh-vpn/batman_adv/throughput_override ]; then echo 1000000 > /sys/devices/virtual/net/mesh-vpn/batman_adv/throughput_override; fi --- -2.43.0 - diff --git a/patches/0003-Fixed-patch-for-BATMAN-throughput-override.patch b/patches/0003-Fixed-patch-for-BATMAN-throughput-override.patch deleted file mode 100644 index d5f72c6c..00000000 --- a/patches/0003-Fixed-patch-for-BATMAN-throughput-override.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 22dee5d9d33942c3a9c9272f324fd8f6ae1b84ba Mon Sep 17 00:00:00 2001 -From: Malte Wedel -Date: Thu, 14 Jan 2021 21:38:53 +0100 -Subject: [PATCH 03/11] Fixed patch for BATMAN throughput override - ---- - .../post-setup.d/40-gluon-mesh-batman-adv-wired-tpo | 13 ++++--------- - 1 file changed, 4 insertions(+), 9 deletions(-) - -diff --git a/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -index 2c488f16..647617e6 100755 ---- a/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -+++ b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -@@ -1,11 +1,6 @@ - #!/bin/sh - --if [ -f /sys/devices/virtual/net/vx_mesh_lan/batman_adv/throughput_override ]; then echo 1000000 > /sys/devices/virtual/net/vx_mesh_lan/batman_adv/throughput_override; fi -- --if [ -f /sys/devices/virtual/net/vx_mesh_wan/batman_adv/throughput_override ]; then echo 1000000 > /sys/devices/virtual/net/vx_mesh_wan/batman_adv/throughput_override; fi -- --if [ -f /sys/devices/virtual/net/vx_mesh_vpn/batman_adv/throughput_override ]; then echo 1000000 > /sys/devices/virtual/net/vx_mesh_vpn/batman_adv/throughput_override; fi -- --if [ -f /sys/devices/virtual/net/br-wan/batman_adv/throughput_override ]; then echo 1000000 > /sys/devices/virtual/net/br-wan/batman_adv/throughput_override; fi -- --if [ -f /sys/devices/virtual/net/mesh-vpn/batman_adv/throughput_override ]; then echo 1000000 > /sys/devices/virtual/net/mesh-vpn/batman_adv/throughput_override; fi -+if [ "$IFNAME" = "vx_mesh_lan" ] || [ "$IFNAME" = "vx_mesh_wan" ] || [ "$IFNAME" = "mesh-vpn" ]; then -+ sleep 1; -+ batctl hardif $IFNAME throughput_override 1000mbit; -+fi --- -2.43.0 - diff --git a/patches/0003-gluon-radv-filterd-fix-log-in-update_metrics.patch b/patches/0003-gluon-radv-filterd-fix-log-in-update_metrics.patch new file mode 100644 index 00000000..39b8cd60 --- /dev/null +++ b/patches/0003-gluon-radv-filterd-fix-log-in-update_metrics.patch @@ -0,0 +1,27 @@ +From 0ed9341462b0a7977fb29220e1aa07b4fcb18ed9 Mon Sep 17 00:00:00 2001 +From: Grische +Date: Thu, 30 Apr 2026 17:39:26 +0200 +Subject: [PATCH 3/7] gluon-radv-filterd: fix log in update_metrics + +The error message is in the local translation table query, not the global +one. +--- + package/gluon-radv-filterd/src/gluon-radv-filterd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/package/gluon-radv-filterd/src/gluon-radv-filterd.c b/package/gluon-radv-filterd/src/gluon-radv-filterd.c +index 55c974d5..4291f9eb 100644 +--- a/package/gluon-radv-filterd/src/gluon-radv-filterd.c ++++ b/package/gluon-radv-filterd/src/gluon-radv-filterd.c +@@ -592,7 +592,7 @@ static void update_metrics(void) { + BATADV_CMD_GET_TRANSTABLE_LOCAL, + parse_tt_local, NLM_F_DUMP, &opts); + if (ret < 0) +- fprintf(stderr, "Parsing of global translation table failed\n"); ++ fprintf(stderr, "Parsing of local translation table failed\n"); + } + + foreach(router, G.routers) { +-- +2.43.0 + diff --git a/patches/0004-Increase-delay-before-batctl-throughput_override.patch b/patches/0004-Increase-delay-before-batctl-throughput_override.patch deleted file mode 100644 index 88700135..00000000 --- a/patches/0004-Increase-delay-before-batctl-throughput_override.patch +++ /dev/null @@ -1,24 +0,0 @@ -From b88d9746dd60b331c1c019664e8620e7173024e1 Mon Sep 17 00:00:00 2001 -From: goligo -Date: Tue, 8 Jun 2021 17:25:45 +0200 -Subject: [PATCH 04/11] Increase delay before batctl throughput_override - ---- - .../core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -index 647617e6..38f0b6de 100755 ---- a/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -+++ b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -@@ -1,6 +1,6 @@ - #!/bin/sh - - if [ "$IFNAME" = "vx_mesh_lan" ] || [ "$IFNAME" = "vx_mesh_wan" ] || [ "$IFNAME" = "mesh-vpn" ]; then -- sleep 1; -+ sleep 3; - batctl hardif $IFNAME throughput_override 1000mbit; - fi --- -2.43.0 - diff --git a/patches/0004-gluon-mesh-batman-adv-emit-raw-throughput-for-Batman.patch b/patches/0004-gluon-mesh-batman-adv-emit-raw-throughput-for-Batman.patch new file mode 100644 index 00000000..ccecb8e3 --- /dev/null +++ b/patches/0004-gluon-mesh-batman-adv-emit-raw-throughput-for-Batman.patch @@ -0,0 +1,112 @@ +From 56d0860741ad5e183f00edfd6b412fc393491e90 Mon Sep 17 00:00:00 2001 +From: Grische +Date: Wed, 15 Apr 2026 08:55:05 +0200 +Subject: [PATCH 4/7] gluon-mesh-batman-adv: emit raw throughput for Batman V + neighbours + +Each routing algorithm now emits its native link-quality metric in its +own JSON field: tq (uint8, 0-255) for Batman IV; throughput (uint32, +kbps) for Batman V. Each neighbour link carries exactly one of the two. + +This matches the pattern in respondd-statistics.c (gateway_tq vs +gateway_throughput) and removes the need to fake a TQ value from +throughput via gluonutil_get_pseudo_tq(). + +Note: the status-page pipeline (neighbours-batadv.c) keeps emitting +"tp" as a pre-formatted display string (e.g. "123M"); only the respondd +neighbours output gains the raw numeric "throughput" here for machine +consumers (yanic, meshviewer). + +add_neighbour() now takes a metric name plus a caller-allocated +json_object value and owns that value, json_object_put()-ing it on the +two early-return paths (ifname lookup fail, inner object alloc fail). +The IV and V callbacks pass the appropriate (name, value) pair. + +Throughput is wrapped with json_object_new_int64 to avoid int32 +truncation of the uint32 source; gateway_throughput in +respondd-statistics.c still uses json_object_new_int and can be widened +in a follow-up. + +The libgluonutil include is no longer needed in this file. + +Co-Authored-By: Claude Opus 4.6 (1M context) +--- + .../src/respondd-neighbours.c | 20 +++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +diff --git a/package/gluon-mesh-batman-adv/src/respondd-neighbours.c b/package/gluon-mesh-batman-adv/src/respondd-neighbours.c +index f588f005..3b8ecd52 100644 +--- a/package/gluon-mesh-batman-adv/src/respondd-neighbours.c ++++ b/package/gluon-mesh-batman-adv/src/respondd-neighbours.c +@@ -4,7 +4,6 @@ + #include "respondd-common.h" + + #include +-#include + + #include + +@@ -62,7 +61,7 @@ static const enum batadv_nl_attrs parse_neigh_list_mandatory_batadv_v[] = { + }; + + static int add_neighbour(struct neigh_netlink_opts *opts, struct nlattr **attrs, +- uint8_t *mac, uint8_t tq) ++ uint8_t *mac, const char *metric_name, struct json_object *metric_value) + { + uint32_t hardif; + uint32_t lastseen; +@@ -73,15 +72,19 @@ static int add_neighbour(struct neigh_netlink_opts *opts, struct nlattr **attrs, + lastseen = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]); + + ifname = if_indextoname(hardif, ifname_buf); +- if (!ifname) ++ if (!ifname) { ++ json_object_put(metric_value); + return NL_OK; ++ } + + sprintf(mac1, "%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + struct json_object *obj = json_object_new_object(); +- if (!obj) ++ if (!obj) { ++ json_object_put(metric_value); + return NL_OK; ++ } + + struct json_object *interface; + if (!json_object_object_get_ex(opts->interfaces, ifname, &interface)) { +@@ -89,7 +92,7 @@ static int add_neighbour(struct neigh_netlink_opts *opts, struct nlattr **attrs, + json_object_object_add(opts->interfaces, ifname, interface); + } + +- json_object_object_add(obj, "tq", json_object_new_int(tq)); ++ json_object_object_add(obj, metric_name, metric_value); + json_object_object_add(obj, "lastseen", json_object_new_double(lastseen / 1000.)); + json_object_object_add(obj, "best", json_object_new_boolean(nla_get_flag(attrs[BATADV_ATTR_FLAG_BEST]))); + json_object_object_add(interface, mac1, obj); +@@ -129,7 +132,8 @@ static int parse_orig_list_netlink_cb_batadv_iv(struct nl_msg *msg, void *arg) + if (memcmp(mac, nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]), 6) != 0) + return NL_OK; + +- return add_neighbour(opts, attrs, mac, nla_get_u8(attrs[BATADV_ATTR_TQ])); ++ return add_neighbour(opts, attrs, mac, "tq", ++ json_object_new_int(nla_get_u8(attrs[BATADV_ATTR_TQ]))); + } + + static int parse_neigh_list_netlink_cb_batadv_v(struct nl_msg *msg, void *arg) +@@ -162,8 +166,8 @@ static int parse_neigh_list_netlink_cb_batadv_v(struct nl_msg *msg, void *arg) + + mac = nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]); + +- return add_neighbour(opts, attrs, mac, +- gluonutil_get_pseudo_tq(nla_get_u32(attrs[BATADV_ATTR_THROUGHPUT]))); ++ return add_neighbour(opts, attrs, mac, "throughput", ++ json_object_new_int64(nla_get_u32(attrs[BATADV_ATTR_THROUGHPUT]))); + } + + static struct json_object * get_batadv(void) { +-- +2.43.0 + diff --git a/patches/0005-Fix-throughput-override-for-new-interface-vx_mesh_ot.patch b/patches/0005-Fix-throughput-override-for-new-interface-vx_mesh_ot.patch deleted file mode 100644 index a5e0c77a..00000000 --- a/patches/0005-Fix-throughput-override-for-new-interface-vx_mesh_ot.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 3dd16d8e4f93d6f3af0a13b17a226f9bbd6b127b Mon Sep 17 00:00:00 2001 -From: Malte Wedel -Date: Wed, 6 Apr 2022 18:23:54 +0200 -Subject: [PATCH 05/11] Fix throughput override for new interface vx_mesh_other - -The VX mesh interface for Mesh-On-LAN and Mesh-On-WAN has been renamed -in the latest branch. This change fixes the throughput override, which -makes BATMAN prefer the wired connections over the wireless connections. ---- - .../core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -index 38f0b6de..eb1336d0 100755 ---- a/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -+++ b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -@@ -1,6 +1,6 @@ - #!/bin/sh - --if [ "$IFNAME" = "vx_mesh_lan" ] || [ "$IFNAME" = "vx_mesh_wan" ] || [ "$IFNAME" = "mesh-vpn" ]; then -+if [ "$IFNAME" = "vx_mesh_other" ] || [ "$IFNAME" = "mesh-vpn" ]; then - sleep 3; - batctl hardif $IFNAME throughput_override 1000mbit; - fi --- -2.43.0 - diff --git a/patches/0005-libgluonutil-remove-unused-gluonutil_get_pseudo_tq.patch b/patches/0005-libgluonutil-remove-unused-gluonutil_get_pseudo_tq.patch new file mode 100644 index 00000000..96b92912 --- /dev/null +++ b/patches/0005-libgluonutil-remove-unused-gluonutil_get_pseudo_tq.patch @@ -0,0 +1,73 @@ +From b062d5acf8790218558dd45291c225d0f0b0f17c Mon Sep 17 00:00:00 2001 +From: Grische +Date: Wed, 15 Apr 2026 08:55:38 +0200 +Subject: [PATCH 5/7] libgluonutil: remove unused gluonutil_get_pseudo_tq + +The function synthesised a fake Batman IV TQ from a Batman V throughput +value via a log formula. Its only caller in the tree was respondd- +neighbours.c, which now emits the raw throughput field directly. + +Drop the function, the include it required, and the -lm +linkage it forced on every libgluonutil consumer. + +Co-Authored-By: Claude Opus 4.6 (1M context) +--- + package/libgluonutil/src/CMakeLists.txt | 2 +- + package/libgluonutil/src/libgluonutil.c | 12 ------------ + package/libgluonutil/src/libgluonutil.h | 2 -- + 3 files changed, 1 insertion(+), 15 deletions(-) + +diff --git a/package/libgluonutil/src/CMakeLists.txt b/package/libgluonutil/src/CMakeLists.txt +index 6ff5b1c4..a20ff0bd 100644 +--- a/package/libgluonutil/src/CMakeLists.txt ++++ b/package/libgluonutil/src/CMakeLists.txt +@@ -6,7 +6,7 @@ set_property(DIRECTORY PROPERTY COMPILE_DEFINITIONS _GNU_SOURCE) + + add_library(gluonutil SHARED libgluonutil.c) + set_property(TARGET gluonutil PROPERTY COMPILE_FLAGS "-Wall -std=c99") +-target_link_libraries(gluonutil json-c uci m) ++target_link_libraries(gluonutil json-c uci) + install(TARGETS gluonutil + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib +diff --git a/package/libgluonutil/src/libgluonutil.c b/package/libgluonutil/src/libgluonutil.c +index ea39d2d7..86079585 100644 +--- a/package/libgluonutil/src/libgluonutil.c ++++ b/package/libgluonutil/src/libgluonutil.c +@@ -11,7 +11,6 @@ + + #include + #include +-#include + #include + #include + #include +@@ -339,14 +338,3 @@ err: + return NULL; + } + +-uint8_t gluonutil_get_pseudo_tq(uint32_t throughput) { +- return throughput >= 54000 ? 255 : +- throughput < 417 ? 0 : +- (uint8_t)( +- ( +- 1.42459274279287898080 * log2(throughput) - +- 12.39555493934044793479 +- ) +- * 25.5 +- ); +-} +diff --git a/package/libgluonutil/src/libgluonutil.h b/package/libgluonutil/src/libgluonutil.h +index 69fee07d..9391dbbd 100644 +--- a/package/libgluonutil/src/libgluonutil.h ++++ b/package/libgluonutil/src/libgluonutil.h +@@ -36,6 +36,4 @@ char * gluonutil_get_domain(void); + char * gluonutil_get_primary_domain(void); + struct json_object * gluonutil_load_site_config(void); + +-uint8_t gluonutil_get_pseudo_tq(uint32_t throughput); +- + #endif /* _LIBGLUON_LIBGLUON_H_ */ +-- +2.43.0 + diff --git a/patches/0006-Fix-TPO-for-vx_mesh_uplink.patch b/patches/0006-Fix-TPO-for-vx_mesh_uplink.patch deleted file mode 100644 index c2cd5d4a..00000000 --- a/patches/0006-Fix-TPO-for-vx_mesh_uplink.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 438a03ba1aadbcdad031cfc5acd38904720ab324 Mon Sep 17 00:00:00 2001 -From: goligo -Date: Tue, 15 Nov 2022 16:27:38 +0100 -Subject: [PATCH 06/11] Fix TPO for vx_mesh_uplink - -Gluon v2022.1.1 uses a new interface called vx_mesh_uplink, which was -not yet handled correctly in our BATMAN V Patch. ---- - .../core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -index eb1336d0..95e66831 100755 ---- a/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -+++ b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -@@ -1,6 +1,6 @@ - #!/bin/sh - --if [ "$IFNAME" = "vx_mesh_other" ] || [ "$IFNAME" = "mesh-vpn" ]; then -+if [ "$IFNAME" = "vx_mesh_uplink" ] || [ "$IFNAME" = "vx_mesh_other" ] || [ "$IFNAME" = "mesh-vpn" ]; then - sleep 3; - batctl hardif $IFNAME throughput_override 1000mbit; - fi --- -2.43.0 - diff --git a/patches/0006-gluon-status-page-mesh-batman-adv-show-only-the-acti.patch b/patches/0006-gluon-status-page-mesh-batman-adv-show-only-the-acti.patch new file mode 100644 index 00000000..027f0d6d --- /dev/null +++ b/patches/0006-gluon-status-page-mesh-batman-adv-show-only-the-acti.patch @@ -0,0 +1,68 @@ +From 9176b6cca46f8e0ce3c027532b1f16a2c928e735 Mon Sep 17 00:00:00 2001 +From: Grische +Date: Wed, 15 Apr 2026 17:39:35 +0200 +Subject: [PATCH 6/7] gluon-status-page-mesh-batman-adv: show only the active + algorithm's metric column +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +A given Gluon build runs exactly one batman-adv routing algorithm +(mesh.batman_adv.routing_algo in site config). Showing both TQ and TP +columns on the status page always leaves one permanently blank and +confuses users. Emit only the relevant attr tuple: + +- BATMAN_V → TP (throughput) +- BATMAN_IV → TQ (link quality) + +The value is read from gluon.site at render time (mesh.lua is loaded +fresh per request), so it tracks the authoritative site config that +also drives gluon_bat0.sh and the kernel. check_site already +guarantees the field is one of {'BATMAN_IV', 'BATMAN_V'}. + +No JS or HTML template change: status-page.html iterates mesh.attrs +dynamically, and the minified JS builds per-key cells from the +rendered headers, so shrinking the list works +transparently. The Monitoring panel's separate "Gateway (TQ: ...)" +line is unrelated (batman-adv reports gateway TQ for both algos) and +stays unchanged. + +Co-Authored-By: Claude Opus 4.6 (1M context) +--- + .../luasrc/lib/gluon/status-page/mesh.lua | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/package/gluon-status-page-mesh-batman-adv/luasrc/lib/gluon/status-page/mesh.lua b/package/gluon-status-page-mesh-batman-adv/luasrc/lib/gluon/status-page/mesh.lua +index 010371c8..4795891b 100644 +--- a/package/gluon-status-page-mesh-batman-adv/luasrc/lib/gluon/status-page/mesh.lua ++++ b/package/gluon-status-page-mesh-batman-adv/luasrc/lib/gluon/status-page/mesh.lua +@@ -1,3 +1,16 @@ ++local site = require 'gluon.site' ++ ++local attrs ++if site.mesh.batman_adv.routing_algo() == 'BATMAN_V' then ++ attrs = { ++ {'tp', 'Throughput', 'bit/s', 'bitrate'}, ++ } ++else ++ attrs = { ++ {'tq', 'TQ', ' %'}, ++ } ++end ++ + return { + provider = '/cgi-bin/dyn/neighbours-batadv', + -- List of mesh-specific attributes, each a tuple of +@@ -5,8 +18,5 @@ return { + -- 2) human-readable key (not translatable yet) + -- 3) value suffix (optional) + -- 4) formatter name (optional) -- key into status-page.js formats{} +- attrs = { +- {'tq', 'TQ', ' %'}, +- {'tp', 'Throughput', 'bit/s', 'bitrate'}, +- }, ++ attrs = attrs, + } +-- +2.43.0 + diff --git a/patches/0007-Revert-fixup-treewide-add-Batman-V-support.patch b/patches/0007-Revert-fixup-treewide-add-Batman-V-support.patch new file mode 100644 index 00000000..9eabc275 --- /dev/null +++ b/patches/0007-Revert-fixup-treewide-add-Batman-V-support.patch @@ -0,0 +1,30 @@ +From be7a291bd7b995ffa511630a1489e2849f281ce6 Mon Sep 17 00:00:00 2001 +From: Grische +Date: Fri, 17 Apr 2026 22:42:43 +0200 +Subject: [PATCH 7/7] Revert "fixup! treewide: add Batman V support" + +This reverts commit 3a7b9859f22cbe3ace33aa2c60220143e8079118. +--- + .../post-setup.d/40-gluon-mesh-batman-adv-wired-tpo | 10 ++++++++++ + 1 file changed, 10 insertions(+) + create mode 100755 package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo + +diff --git a/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo +new file mode 100755 +index 00000000..0fd50612 +--- /dev/null ++++ b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo +@@ -0,0 +1,10 @@ ++#!/bin/sh ++ ++# throughput_override is only relevant for Batman V ++algo=$(batctl routing_algo 2>/dev/null) ++[ "$algo" = "BATMAN_V" ] || exit 0 ++ ++if [ "$IFNAME" = "vx_mesh_uplink" ] || [ "$IFNAME" = "vx_mesh_other" ] || [ "$IFNAME" = "mesh-vpn" ]; then ++ sleep 3 ++ batctl hardif "${IFNAME}" throughput_override 1000mbit ++fi +-- +2.43.0 + diff --git a/patches/0007-Use-gluon-radv-filterd-patched-for-BATMAN-V.patch b/patches/0007-Use-gluon-radv-filterd-patched-for-BATMAN-V.patch deleted file mode 100644 index d6aabcc8..00000000 --- a/patches/0007-Use-gluon-radv-filterd-patched-for-BATMAN-V.patch +++ /dev/null @@ -1,275 +0,0 @@ -From ecb3cecc45f36584bd741a79de0c993149e53b32 Mon Sep 17 00:00:00 2001 -From: Grische -Date: Mon, 28 Oct 2024 13:12:00 +0100 -Subject: [PATCH 07/11] Use gluon-radv-filterd patched for BATMAN V -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Patched gluon-radv-filterd to use throughput instead of tq and changed -site configuration to use it instead of ffmuc-simple-radv-filter - -Co-Authored-By: Steffen Förster -Co-Authored-By: Malte Wedel ---- - .../src/gluon-radv-filterd.c | 96 +++++++++---------- - 1 file changed, 48 insertions(+), 48 deletions(-) - -diff --git a/package/gluon-radv-filterd/src/gluon-radv-filterd.c b/package/gluon-radv-filterd/src/gluon-radv-filterd.c -index 7a777752..5a45b294 100644 ---- a/package/gluon-radv-filterd/src/gluon-radv-filterd.c -+++ b/package/gluon-radv-filterd/src/gluon-radv-filterd.c -@@ -37,11 +37,11 @@ - - #include "mac.h" - --// Recheck TQs after this time even if no RA was received -+// Recheck THROUGHPUTs after this time even if no RA was received - #define MAX_INTERVAL 60 - --// Recheck TQs at most this often, even if new RAs were received (they won't --// become the preferred routers until the TQs have been rechecked) -+// Recheck THROUGHPUTs at most this often, even if new RAs were received (they won't -+// become the preferred routers until the THROUGHPUTs have been rechecked) - // Also, the first update will take at least this long - #define MIN_INTERVAL 15 - -@@ -52,8 +52,8 @@ - // max execution time of a single ebtables call in nanoseconds - #define EBTABLES_TIMEOUT 500000000 // 500ms - --// TQ value assigned to local routers --#define LOCAL_TQ 512 -+// THROUGHPUT value assigned to local routers -+#define LOCAL_THROUGHPUT 10000000 - - #define BUFSIZE 1500 - -@@ -86,7 +86,7 @@ struct router { - struct ether_addr src; - struct timespec eol; - struct ether_addr originator; -- uint16_t tq; -+ uint32_t throughput; - }; - - static struct global { -@@ -94,8 +94,8 @@ static struct global { - struct router *routers; - const char *mesh_iface; - const char *chain; -- uint16_t max_tq; -- uint16_t hysteresis_thresh; -+ uint32_t max_throughput; -+ uint32_t hysteresis_thresh; - struct router *best_router; - volatile sig_atomic_t stop_daemon; - } G = { -@@ -166,8 +166,8 @@ static void usage(const char *msg) { - fprintf(stderr, - "Usage: %s [-m ] [-t ] -c -i \n\n" - " -m B.A.T.M.A.N. advanced mesh interface used to get metric\n" -- " information (\"TQ\") for the available gateways. Default: bat0\n" -- " -t Minimum TQ difference required to switch the gateway.\n" -+ " information (\"THROUGHPUT\") for the available gateways. Default: bat0\n" -+ " -t Minimum THROUGHPUT difference required to switch the gateway.\n" - " Default: 0\n" - " -c ebtables chain that should be managed by the daemon. The\n" - " chain already has to exist on program invocation and should\n" -@@ -267,9 +267,9 @@ static void parse_cmdline(int argc, char *argv[]) { - threshold = strtoul(optarg, &endptr, 10); - if (*endptr != '\0') - exit_errmsg("Threshold must be a number: %s", optarg); -- if (threshold >= LOCAL_TQ) -- exit_errmsg("Threshold too large: %ld (max is %d)", threshold, LOCAL_TQ); -- G.hysteresis_thresh = (uint16_t) threshold; -+ if (threshold >= LOCAL_THROUGHPUT) -+ exit_errmsg("Threshold too large: %ld (max is %d)", threshold, LOCAL_THROUGHPUT); -+ G.hysteresis_thresh = (uint32_t) threshold; - break; - case 'h': - usage(NULL); -@@ -437,7 +437,7 @@ static int parse_originator(struct nl_msg *msg, - - static const enum batadv_nl_attrs mandatory[] = { - BATADV_ATTR_ORIG_ADDRESS, -- BATADV_ATTR_TQ, -+ BATADV_ATTR_THROUGHPUT, - }; - struct nlattr *attrs[BATADV_ATTR_MAX + 1]; - struct nlmsghdr *nlh = nlmsg_hdr(msg); -@@ -445,7 +445,7 @@ static int parse_originator(struct nl_msg *msg, - struct genlmsghdr *ghdr; - struct router *router; - uint8_t *orig; -- uint8_t tq; -+ uint32_t throughput; - - // parse netlink entry - if (!genlmsg_valid_hdr(nlh, 0)) -@@ -465,7 +465,7 @@ static int parse_originator(struct nl_msg *msg, - return NL_OK; - - orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); -- tq = nla_get_u8(attrs[BATADV_ATTR_TQ]); -+ throughput = nla_get_u32(attrs[BATADV_ATTR_THROUGHPUT]); - - if (!attrs[BATADV_ATTR_FLAG_BEST]) - return NL_OK; -@@ -477,11 +477,11 @@ static int parse_originator(struct nl_msg *msg, - if (!router) - return NL_OK; - -- DEBUG_MSG("Found TQ for router " F_MAC " (originator " F_MAC "), it's %d", -- F_MAC_VAR(router->src), F_MAC_VAR(router->originator), tq); -- router->tq = tq; -- if (router->tq > G.max_tq) -- G.max_tq = router->tq; -+ DEBUG_MSG("Found THROUGHPUT for router " F_MAC " (originator " F_MAC "), it's %d", -+ F_MAC_VAR(router->src), F_MAC_VAR(router->originator), throughput); -+ router->throughput = throughput; -+ if (router->throughput > G.max_throughput) -+ G.max_throughput = router->throughput; - - return NL_OK; - } -@@ -524,25 +524,25 @@ static int parse_tt_local(struct nl_msg *msg, - if (!router) - return NL_OK; - -- DEBUG_MSG("Found router " F_MAC " in transtable_local, assigning TQ %d", -- F_MAC_VAR(router->src), LOCAL_TQ); -- router->tq = LOCAL_TQ; -- if (router->tq > G.max_tq) -- G.max_tq = router->tq; -+ DEBUG_MSG("Found router " F_MAC " in transtable_local, assigning THROUGHPUT %d", -+ F_MAC_VAR(router->src), LOCAL_THROUGHPUT); -+ router->throughput = LOCAL_THROUGHPUT; -+ if (router->throughput > G.max_throughput) -+ G.max_throughput = router->throughput; - - return NL_OK; - } - --static void update_tqs(void) { -+static void update_throughputs(void) { - static const struct ether_addr unspec = {}; - struct router *router; - bool update_originators = false; - struct batadv_nlquery_opts opts; - int ret; - -- // reset TQs -+ // reset THROUGHPUTs - foreach(router, G.routers) { -- router->tq = 0; -+ router->throughput = 0; - if (ether_addr_equal(router->originator, unspec)) - update_originators = true; - } -@@ -557,8 +557,8 @@ static void update_tqs(void) { - fprintf(stderr, "Parsing of global translation table failed\n"); - } - -- // look up TQs of originators -- G.max_tq = 0; -+ // look up THROUGHPUTs of originators -+ G.max_throughput = 0; - opts.err = 0; - ret = batadv_genl_query(G.mesh_iface, - BATADV_CMD_GET_ORIGINATORS, -@@ -566,9 +566,9 @@ static void update_tqs(void) { - if (ret < 0) - fprintf(stderr, "Parsing of originators failed\n"); - -- // if all routers have a TQ value, we don't need to check translocal -+ // if all routers have a THROUGHPUT value, we don't need to check translocal - foreach(router, G.routers) { -- if (router->tq == 0) -+ if (router->throughput == 0) - break; - } - if (router != NULL) { -@@ -581,14 +581,14 @@ static void update_tqs(void) { - } - - foreach(router, G.routers) { -- if (router->tq == 0) { -+ if (router->throughput == 0) { - if (ether_addr_equal(router->originator, unspec)) - DEBUG_MSG( - "Unable to find router " F_MAC " in transtable_{global,local}", - F_MAC_VAR(router->src)); - else - DEBUG_MSG( -- "Unable to find TQ for originator " F_MAC " (router " F_MAC ")", -+ "Unable to find THROUGHPUT for originator " F_MAC " (router " F_MAC ")", - F_MAC_VAR(router->originator), - F_MAC_VAR(router->src)); - } -@@ -654,11 +654,11 @@ static bool election_required(void) - if (!G.best_router) - return true; - -- /* should never happen. G.max_tq also contains G.best_router->tq */ -- if (G.max_tq < G.best_router->tq) -+ /* should never happen. G.max_throughput also contains G.best_router->throughput */ -+ if (G.max_throughput < G.best_router->throughput) - return false; - -- if ((G.max_tq - G.best_router->tq) <= G.hysteresis_thresh) -+ if ((G.max_throughput - G.best_router->throughput) <= G.hysteresis_thresh) - return false; - - return true; -@@ -672,29 +672,29 @@ static void update_ebtables(void) { - struct router *router; - - if (!election_required()) { -- DEBUG_MSG(F_MAC " is still good enough with TQ=%d (max_tq=%d), not executing ebtables", -+ DEBUG_MSG(F_MAC " is still good enough with THROUGHPUT=%d (max_throughput=%d), not executing ebtables", - F_MAC_VAR(G.best_router->src), -- G.best_router->tq, -- G.max_tq); -+ G.best_router->throughput, -+ G.max_throughput); - return; - } - - foreach(router, G.routers) { -- if (router->tq == G.max_tq) { -+ if (router->throughput == G.max_throughput) { - snprintf(mac, sizeof(mac), F_MAC, F_MAC_VAR(router->src)); - break; - } - } - if (G.best_router) -- fprintf(stderr, "Switching from " F_MAC " (TQ=%d) to %s (TQ=%d)\n", -+ fprintf(stderr, "Switching from " F_MAC " (THROUGHPUT=%d) to %s (THROUGHPUT=%d)\n", - F_MAC_VAR(G.best_router->src), -- G.best_router->tq, -+ G.best_router->throughput, - mac, -- G.max_tq); -+ G.max_throughput); - else -- fprintf(stderr, "Switching to %s (TQ=%d)\n", -+ fprintf(stderr, "Switching to %s (THROUGHPUT=%d)\n", - mac, -- G.max_tq); -+ G.max_throughput); - G.best_router = router; - - if (fork_execvp_timeout(&timeout, "ebtables-tiny", (const char *[]) -@@ -779,7 +779,7 @@ int main(int argc, char *argv[]) { - next_invalidation.tv_sec += ORIGINATOR_CACHE_TTL; - } - -- update_tqs(); -+ update_throughputs(); - update_ebtables(); - - next_update = now; --- -2.43.0 - diff --git a/patches/0008-respondd-implement-neighbor-info-for-batman_v.patch b/patches/0008-respondd-implement-neighbor-info-for-batman_v.patch deleted file mode 100644 index b1f1c6f2..00000000 --- a/patches/0008-respondd-implement-neighbor-info-for-batman_v.patch +++ /dev/null @@ -1,389 +0,0 @@ -From 2c6190303d8e9a43eccb1f7239ee4debf661e541 Mon Sep 17 00:00:00 2001 -From: Grische -Date: Mon, 28 Oct 2024 13:12:21 +0100 -Subject: [PATCH 08/11] respondd: implement neighbor info for batman_v -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -- add patches to fix BATMAN_V support (from ff chemnitz) for new segments -- Update patches -- Fix respondd patch -- Update to gluon 2020.1.3 -- Adapted BATMAN V respondd patch - Due to changes in libgluonutil.c/h the patch was rejected. - -Co-Authored-By: Steffen Förster -Co-Authored-By: Krombel -Co-Authored-By: Annika Wickert -Co-Authored-By: Malte Wedel ---- - .../src/respondd-neighbours.c | 35 ++++---- - .../src/gluon-radv-filterd.c | 86 ++++++++++--------- - package/libgluonutil/src/libgluonutil.c | 12 +++ - package/libgluonutil/src/libgluonutil.h | 2 + - 4 files changed, 74 insertions(+), 61 deletions(-) - -diff --git a/package/gluon-mesh-batman-adv/src/respondd-neighbours.c b/package/gluon-mesh-batman-adv/src/respondd-neighbours.c -index 261d6b27..2950d1ec 100644 ---- a/package/gluon-mesh-batman-adv/src/respondd-neighbours.c -+++ b/package/gluon-mesh-batman-adv/src/respondd-neighbours.c -@@ -44,22 +44,21 @@ static struct json_object * ifnames2addrs(struct json_object *interfaces) { - return ret; - } - --static const enum batadv_nl_attrs parse_orig_list_mandatory[] = { -- BATADV_ATTR_ORIG_ADDRESS, -+static const enum batadv_nl_attrs parse_neigh_list_mandatory[] = { - BATADV_ATTR_NEIGH_ADDRESS, -- BATADV_ATTR_TQ, -+ BATADV_ATTR_THROUGHPUT, - BATADV_ATTR_HARD_IFINDEX, - BATADV_ATTR_LAST_SEEN_MSECS, - }; - --static int parse_orig_list_netlink_cb(struct nl_msg *msg, void *arg) -+static int parse_neigh_list_netlink_cb(struct nl_msg *msg, void *arg) - { - struct nlattr *attrs[BATADV_ATTR_MAX+1]; - struct nlmsghdr *nlh = nlmsg_hdr(msg); - struct batadv_nlquery_opts *query_opts = arg; - struct genlmsghdr *ghdr; -- uint8_t *orig; -- uint8_t *dest; -+ uint8_t *neigh; -+ uint32_t throughput; - uint8_t tq; - uint32_t hardif; - uint32_t lastseen; -@@ -75,32 +74,28 @@ static int parse_orig_list_netlink_cb(struct nl_msg *msg, void *arg) - - ghdr = nlmsg_data(nlh); - -- if (ghdr->cmd != BATADV_CMD_GET_ORIGINATORS) -+ if (ghdr->cmd != BATADV_CMD_GET_NEIGHBORS) - return NL_OK; - - if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), - genlmsg_len(ghdr), batadv_genl_policy)) - return NL_OK; - -- if (batadv_genl_missing_attrs(attrs, parse_orig_list_mandatory, -- BATADV_ARRAY_SIZE(parse_orig_list_mandatory))) -+ if (batadv_genl_missing_attrs(attrs, parse_neigh_list_mandatory, -+ BATADV_ARRAY_SIZE(parse_neigh_list_mandatory))) - return NL_OK; - -- orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); -- dest = nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]); -- tq = nla_get_u8(attrs[BATADV_ATTR_TQ]); -+ neigh = nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]); -+ throughput = nla_get_u32(attrs[BATADV_ATTR_THROUGHPUT]); - hardif = nla_get_u32(attrs[BATADV_ATTR_HARD_IFINDEX]); - lastseen = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]); - -- if (memcmp(orig, dest, 6) != 0) -- return NL_OK; -- - ifname = if_indextoname(hardif, ifname_buf); - if (!ifname) - return NL_OK; - - sprintf(mac1, "%02x:%02x:%02x:%02x:%02x:%02x", -- orig[0], orig[1], orig[2], orig[3], orig[4], orig[5]); -+ neigh[0], neigh[1], neigh[2], neigh[3], neigh[4], neigh[5]); - - struct json_object *obj = json_object_new_object(); - if (!obj) -@@ -112,6 +107,8 @@ static int parse_orig_list_netlink_cb(struct nl_msg *msg, void *arg) - json_object_object_add(opts->interfaces, ifname, interface); - } - -+ tq = gluonutil_get_pseudo_tq(throughput); -+ - json_object_object_add(obj, "tq", json_object_new_int(tq)); - json_object_object_add(obj, "lastseen", json_object_new_double(lastseen / 1000.)); - json_object_object_add(obj, "best", json_object_new_boolean(nla_get_flag(attrs[BATADV_ATTR_FLAG_BEST]))); -@@ -132,9 +129,9 @@ static struct json_object * get_batadv(void) { - if (!opts.interfaces) - return NULL; - -- ret = batadv_genl_query("bat0", BATADV_CMD_GET_ORIGINATORS, -- parse_orig_list_netlink_cb, NLM_F_DUMP, -- &opts.query_opts); -+ ret = batadv_genl_query("bat0", BATADV_CMD_GET_NEIGHBORS, -+ parse_neigh_list_netlink_cb, NLM_F_DUMP, -+ &opts.query_opts); - if (ret < 0) { - json_object_put(opts.interfaces); - return NULL; -diff --git a/package/gluon-radv-filterd/src/gluon-radv-filterd.c b/package/gluon-radv-filterd/src/gluon-radv-filterd.c -index 5a45b294..cda5f62d 100644 ---- a/package/gluon-radv-filterd/src/gluon-radv-filterd.c -+++ b/package/gluon-radv-filterd/src/gluon-radv-filterd.c -@@ -86,7 +86,7 @@ struct router { - struct ether_addr src; - struct timespec eol; - struct ether_addr originator; -- uint32_t throughput; -+ uint32_t throughput; - }; - - static struct global { -@@ -94,8 +94,8 @@ static struct global { - struct router *routers; - const char *mesh_iface; - const char *chain; -- uint32_t max_throughput; -- uint32_t hysteresis_thresh; -+ uint32_t max_throughput; -+ uint32_t hysteresis_thresh; - struct router *best_router; - volatile sig_atomic_t stop_daemon; - } G = { -@@ -166,8 +166,8 @@ static void usage(const char *msg) { - fprintf(stderr, - "Usage: %s [-m ] [-t ] -c -i \n\n" - " -m B.A.T.M.A.N. advanced mesh interface used to get metric\n" -- " information (\"THROUGHPUT\") for the available gateways. Default: bat0\n" -- " -t Minimum THROUGHPUT difference required to switch the gateway.\n" -+ " information (\"THROUGHPUT\") for the available gateways. Default: bat0\n" -+ " -t Minimum THROUGHPUT difference required to switch the gateway.\n" - " Default: 0\n" - " -c ebtables chain that should be managed by the daemon. The\n" - " chain already has to exist on program invocation and should\n" -@@ -267,9 +267,9 @@ static void parse_cmdline(int argc, char *argv[]) { - threshold = strtoul(optarg, &endptr, 10); - if (*endptr != '\0') - exit_errmsg("Threshold must be a number: %s", optarg); -- if (threshold >= LOCAL_THROUGHPUT) -- exit_errmsg("Threshold too large: %ld (max is %d)", threshold, LOCAL_THROUGHPUT); -- G.hysteresis_thresh = (uint32_t) threshold; -+ if (threshold >= LOCAL_THROUGHPUT) -+ exit_errmsg("Threshold too large: %ld (max is %d)", threshold, LOCAL_THROUGHPUT); -+ G.hysteresis_thresh = (uint32_t)threshold; - break; - case 'h': - usage(NULL); -@@ -437,7 +437,7 @@ static int parse_originator(struct nl_msg *msg, - - static const enum batadv_nl_attrs mandatory[] = { - BATADV_ATTR_ORIG_ADDRESS, -- BATADV_ATTR_THROUGHPUT, -+ BATADV_ATTR_THROUGHPUT, - }; - struct nlattr *attrs[BATADV_ATTR_MAX + 1]; - struct nlmsghdr *nlh = nlmsg_hdr(msg); -@@ -445,7 +445,7 @@ static int parse_originator(struct nl_msg *msg, - struct genlmsghdr *ghdr; - struct router *router; - uint8_t *orig; -- uint32_t throughput; -+ uint32_t throughput; - - // parse netlink entry - if (!genlmsg_valid_hdr(nlh, 0)) -@@ -465,7 +465,7 @@ static int parse_originator(struct nl_msg *msg, - return NL_OK; - - orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); -- throughput = nla_get_u32(attrs[BATADV_ATTR_THROUGHPUT]); -+ throughput = nla_get_u32(attrs[BATADV_ATTR_THROUGHPUT]); - - if (!attrs[BATADV_ATTR_FLAG_BEST]) - return NL_OK; -@@ -477,11 +477,11 @@ static int parse_originator(struct nl_msg *msg, - if (!router) - return NL_OK; - -- DEBUG_MSG("Found THROUGHPUT for router " F_MAC " (originator " F_MAC "), it's %d", -- F_MAC_VAR(router->src), F_MAC_VAR(router->originator), throughput); -- router->throughput = throughput; -- if (router->throughput > G.max_throughput) -- G.max_throughput = router->throughput; -+ DEBUG_MSG("Found THROUGHPUT for router " F_MAC " (originator " F_MAC "), it's %d", -+ F_MAC_VAR(router->src), F_MAC_VAR(router->originator), throughput); -+ router->throughput = throughput; -+ if (router->throughput > G.max_throughput) -+ G.max_throughput = router->throughput; - - return NL_OK; - } -@@ -524,11 +524,11 @@ static int parse_tt_local(struct nl_msg *msg, - if (!router) - return NL_OK; - -- DEBUG_MSG("Found router " F_MAC " in transtable_local, assigning THROUGHPUT %d", -- F_MAC_VAR(router->src), LOCAL_THROUGHPUT); -- router->throughput = LOCAL_THROUGHPUT; -- if (router->throughput > G.max_throughput) -- G.max_throughput = router->throughput; -+ DEBUG_MSG("Found router " F_MAC " in transtable_local, assigning THROUGHPUT %d", -+ F_MAC_VAR(router->src), LOCAL_THROUGHPUT); -+ router->throughput = LOCAL_THROUGHPUT; -+ if (router->throughput > G.max_throughput) -+ G.max_throughput = router->throughput; - - return NL_OK; - } -@@ -540,9 +540,9 @@ static void update_throughputs(void) { - struct batadv_nlquery_opts opts; - int ret; - -- // reset THROUGHPUTs -+ // reset THROUGHPUTs - foreach(router, G.routers) { -- router->throughput = 0; -+ router->throughput = 0; - if (ether_addr_equal(router->originator, unspec)) - update_originators = true; - } -@@ -557,8 +557,8 @@ static void update_throughputs(void) { - fprintf(stderr, "Parsing of global translation table failed\n"); - } - -- // look up THROUGHPUTs of originators -- G.max_throughput = 0; -+ // look up THROUGHPUTs of originators -+ G.max_throughput = 0; - opts.err = 0; - ret = batadv_genl_query(G.mesh_iface, - BATADV_CMD_GET_ORIGINATORS, -@@ -566,9 +566,9 @@ static void update_throughputs(void) { - if (ret < 0) - fprintf(stderr, "Parsing of originators failed\n"); - -- // if all routers have a THROUGHPUT value, we don't need to check translocal -+ // if all routers have a THROUGHPUT value, we don't need to check translocal - foreach(router, G.routers) { -- if (router->throughput == 0) -+ if (router->throughput == 0) - break; - } - if (router != NULL) { -@@ -581,14 +581,15 @@ static void update_throughputs(void) { - } - - foreach(router, G.routers) { -- if (router->throughput == 0) { -+ if (router->throughput == 0) -+ { - if (ether_addr_equal(router->originator, unspec)) - DEBUG_MSG( - "Unable to find router " F_MAC " in transtable_{global,local}", - F_MAC_VAR(router->src)); - else - DEBUG_MSG( -- "Unable to find THROUGHPUT for originator " F_MAC " (router " F_MAC ")", -+ "Unable to find THROUGHPUT for originator " F_MAC " (router " F_MAC ")", - F_MAC_VAR(router->originator), - F_MAC_VAR(router->src)); - } -@@ -654,11 +655,11 @@ static bool election_required(void) - if (!G.best_router) - return true; - -- /* should never happen. G.max_throughput also contains G.best_router->throughput */ -- if (G.max_throughput < G.best_router->throughput) -+ /* should never happen. G.max_throughput also contains G.best_router->throughput */ -+ if (G.max_throughput < G.best_router->throughput) - return false; - -- if ((G.max_throughput - G.best_router->throughput) <= G.hysteresis_thresh) -+ if ((G.max_throughput - G.best_router->throughput) <= G.hysteresis_thresh) - return false; - - return true; -@@ -672,29 +673,30 @@ static void update_ebtables(void) { - struct router *router; - - if (!election_required()) { -- DEBUG_MSG(F_MAC " is still good enough with THROUGHPUT=%d (max_throughput=%d), not executing ebtables", -+ DEBUG_MSG(F_MAC " is still good enough with THROUGHPUT=%d (max_throughput=%d), not executing ebtables", - F_MAC_VAR(G.best_router->src), -- G.best_router->throughput, -- G.max_throughput); -+ G.best_router->throughput, -+ G.max_throughput); - return; - } - - foreach(router, G.routers) { -- if (router->throughput == G.max_throughput) { -+ if (router->throughput == G.max_throughput) -+ { - snprintf(mac, sizeof(mac), F_MAC, F_MAC_VAR(router->src)); - break; - } - } - if (G.best_router) -- fprintf(stderr, "Switching from " F_MAC " (THROUGHPUT=%d) to %s (THROUGHPUT=%d)\n", -+ fprintf(stderr, "Switching from " F_MAC " (THROUGHPUT=%d) to %s (THROUGHPUT=%d)\n", - F_MAC_VAR(G.best_router->src), -- G.best_router->throughput, -+ G.best_router->throughput, - mac, -- G.max_throughput); -+ G.max_throughput); - else -- fprintf(stderr, "Switching to %s (THROUGHPUT=%d)\n", -+ fprintf(stderr, "Switching to %s (THROUGHPUT=%d)\n", - mac, -- G.max_throughput); -+ G.max_throughput); - G.best_router = router; - - if (fork_execvp_timeout(&timeout, "ebtables-tiny", (const char *[]) -@@ -779,7 +781,7 @@ int main(int argc, char *argv[]) { - next_invalidation.tv_sec += ORIGINATOR_CACHE_TTL; - } - -- update_throughputs(); -+ update_throughputs(); - update_ebtables(); - - next_update = now; -diff --git a/package/libgluonutil/src/libgluonutil.c b/package/libgluonutil/src/libgluonutil.c -index 354f7179..c0d61273 100644 ---- a/package/libgluonutil/src/libgluonutil.c -+++ b/package/libgluonutil/src/libgluonutil.c -@@ -17,6 +17,7 @@ - #include - #include - #include -+#include - - /** - * Merges two JSON objects -@@ -304,6 +305,17 @@ char * gluonutil_get_primary_domain(void) { - return strdup(primary_domain_code); - } - -+uint8_t gluonutil_get_pseudo_tq(uint32_t throughput) { -+ return throughput >= 54000 ? 255 : -+ throughput < 417 ? 0 : -+ (uint8_t)( -+ ( -+ 1.42459274279287898080 * log2(throughput) - -+ 12.39555493934044793479 -+ ) -+ * 25.5 -+ ); -+} - - struct json_object * gluonutil_load_site_config(void) { - char *domain_code = NULL; -diff --git a/package/libgluonutil/src/libgluonutil.h b/package/libgluonutil/src/libgluonutil.h -index 5ce9d448..1f72bcf7 100644 ---- a/package/libgluonutil/src/libgluonutil.h -+++ b/package/libgluonutil/src/libgluonutil.h -@@ -35,4 +35,6 @@ char * gluonutil_get_domain(void); - char * gluonutil_get_primary_domain(void); - struct json_object * gluonutil_load_site_config(void); - -+uint8_t gluonutil_get_pseudo_tq(uint32_t throughput); -+ - #endif /* _LIBGLUON_LIBGLUON_H_ */ --- -2.43.0 - diff --git a/patches/0009-Fix-issue-with-introduction-of-batman-TQ-propery-in-.patch b/patches/0009-Fix-issue-with-introduction-of-batman-TQ-propery-in-.patch deleted file mode 100644 index d4f27af0..00000000 --- a/patches/0009-Fix-issue-with-introduction-of-batman-TQ-propery-in-.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 70e9081d87fa7bce6b2b34a682d07f8866269a15 Mon Sep 17 00:00:00 2001 -From: Grische -Date: Mon, 28 Oct 2024 13:12:39 +0100 -Subject: [PATCH 09/11] Fix issue with introduction of batman TQ propery in - respondd -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Gluon introduced adding the TQ property of batman to the gateway -information. As we do use BATMAN V, where a TQ property no longer -exists, gateway information was dropped completely from respondd content -and our status page. - -This change fixes this, by using the THROUGHPUT propery instead. - -Co-Authored-By: Steffen Förster -Co-Authored-By: Malte Wedel ---- - package/gluon-mesh-batman-adv/src/respondd-statistics.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/package/gluon-mesh-batman-adv/src/respondd-statistics.c b/package/gluon-mesh-batman-adv/src/respondd-statistics.c -index 28131fda..2fee70de 100644 ---- a/package/gluon-mesh-batman-adv/src/respondd-statistics.c -+++ b/package/gluon-mesh-batman-adv/src/respondd-statistics.c -@@ -41,7 +41,7 @@ struct gw_netlink_opts { - static const enum batadv_nl_attrs gateways_mandatory[] = { - BATADV_ATTR_ORIG_ADDRESS, - BATADV_ATTR_ROUTER, -- BATADV_ATTR_TQ, -+ BATADV_ATTR_THROUGHPUT, - }; - - static int parse_gw_list_netlink_cb(struct nl_msg *msg, void *arg) -@@ -52,7 +52,7 @@ static int parse_gw_list_netlink_cb(struct nl_msg *msg, void *arg) - struct genlmsghdr *ghdr; - uint8_t *orig; - uint8_t *router; -- uint8_t tq; -+ uint32_t throughput; - struct gw_netlink_opts *opts; - char addr[18]; - -@@ -80,13 +80,13 @@ static int parse_gw_list_netlink_cb(struct nl_msg *msg, void *arg) - - orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); - router = nla_data(attrs[BATADV_ATTR_ROUTER]); -- tq = nla_get_u8(attrs[BATADV_ATTR_TQ]); -+ throughput = nla_get_u32(attrs[BATADV_ATTR_THROUGHPUT]); - - sprintf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", - orig[0], orig[1], orig[2], orig[3], orig[4], orig[5]); - - json_object_object_add(opts->obj, "gateway", json_object_new_string(addr)); -- json_object_object_add(opts->obj, "gateway_tq", json_object_new_int(tq)); -+ json_object_object_add(opts->obj, "gateway_throughput", json_object_new_int(throughput)); - - sprintf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", - router[0], router[1], router[2], router[3], router[4], router[5]); --- -2.43.0 - diff --git a/patches/0010-status-page-implement-neighbor-info-for-batman_v.patch b/patches/0010-status-page-implement-neighbor-info-for-batman_v.patch deleted file mode 100644 index 06a1d324..00000000 --- a/patches/0010-status-page-implement-neighbor-info-for-batman_v.patch +++ /dev/null @@ -1,148 +0,0 @@ -From b4e510dca9b8758f448c0184bdb3bbc32c436480 Mon Sep 17 00:00:00 2001 -From: Grische -Date: Mon, 28 Oct 2024 13:12:59 +0100 -Subject: [PATCH 10/11] status page: implement neighbor info for batman_v -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -- add patches to fix BATMAN_V support (from ff chemnitz) for new segments -- Update patches - -Co-Authored-By: Steffen Förster -Co-Authored-By: Krombel ---- - .../luasrc/lib/gluon/status-page/mesh.lua | 2 +- - .../src/neighbours-batadv.c | 57 ++++++++++--------- - 2 files changed, 32 insertions(+), 27 deletions(-) - -diff --git a/package/gluon-status-page-mesh-batman-adv/luasrc/lib/gluon/status-page/mesh.lua b/package/gluon-status-page-mesh-batman-adv/luasrc/lib/gluon/status-page/mesh.lua -index 733e6d7c..e512bbe9 100644 ---- a/package/gluon-status-page-mesh-batman-adv/luasrc/lib/gluon/status-page/mesh.lua -+++ b/package/gluon-status-page-mesh-batman-adv/luasrc/lib/gluon/status-page/mesh.lua -@@ -5,6 +5,6 @@ return { - -- 2) human-readable key (not translatable yet) - -- 3) value suffix (optional) - attrs = { -- {'tq', 'TQ', ' %'}, -+ {'tp', 'bit/s', ''}, - }, - } -diff --git a/package/gluon-status-page-mesh-batman-adv/src/neighbours-batadv.c b/package/gluon-status-page-mesh-batman-adv/src/neighbours-batadv.c -index 58e626c9..b13469b8 100644 ---- a/package/gluon-status-page-mesh-batman-adv/src/neighbours-batadv.c -+++ b/package/gluon-status-page-mesh-batman-adv/src/neighbours-batadv.c -@@ -14,27 +14,28 @@ struct neigh_netlink_opts { - struct batadv_nlquery_opts query_opts; - }; - --static const enum batadv_nl_attrs parse_orig_list_mandatory[] = { -- BATADV_ATTR_ORIG_ADDRESS, -+static const enum batadv_nl_attrs parse_neigh_list_mandatory[] = { - BATADV_ATTR_NEIGH_ADDRESS, -- BATADV_ATTR_TQ, -+ BATADV_ATTR_THROUGHPUT, - BATADV_ATTR_HARD_IFINDEX, - BATADV_ATTR_LAST_SEEN_MSECS, - }; - --static int parse_orig_list_netlink_cb(struct nl_msg *msg, void *arg) -+static int parse_neigh_list_netlink_cb(struct nl_msg *msg, void *arg) - { - struct nlattr *attrs[BATADV_ATTR_MAX+1]; - struct nlmsghdr *nlh = nlmsg_hdr(msg); - struct batadv_nlquery_opts *query_opts = arg; - struct genlmsghdr *ghdr; -- uint8_t *orig; -- uint8_t *dest; -- uint8_t tq; -+ uint8_t *neigh; -+ uint32_t throughput; - uint32_t hardif; - char ifname_buf[IF_NAMESIZE], *ifname; - struct neigh_netlink_opts *opts; - char mac1[18]; -+ char tp_str[5]; -+ const char tp_units[] = {'k', 'M', 'G', 'T', '?'}; -+ int tp_unit; - - opts = batadv_container_of(query_opts, struct neigh_netlink_opts, query_opts); - -@@ -43,41 +44,45 @@ static int parse_orig_list_netlink_cb(struct nl_msg *msg, void *arg) - - ghdr = nlmsg_data(nlh); - -- if (ghdr->cmd != BATADV_CMD_GET_ORIGINATORS) -+ if (ghdr->cmd != BATADV_CMD_GET_NEIGHBORS) - return NL_OK; - - if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), - genlmsg_len(ghdr), batadv_genl_policy)) - return NL_OK; - -- if (batadv_genl_missing_attrs(attrs, parse_orig_list_mandatory, -- BATADV_ARRAY_SIZE(parse_orig_list_mandatory))) -+ if (batadv_genl_missing_attrs(attrs, parse_neigh_list_mandatory, -+ BATADV_ARRAY_SIZE(parse_neigh_list_mandatory))) - return NL_OK; - -- orig = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); -- dest = nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]); -- tq = nla_get_u8(attrs[BATADV_ATTR_TQ]); -+ neigh = nla_data(attrs[BATADV_ATTR_NEIGH_ADDRESS]); -+ throughput = nla_get_u32(attrs[BATADV_ATTR_THROUGHPUT]); - hardif = nla_get_u32(attrs[BATADV_ATTR_HARD_IFINDEX]); - -- if (memcmp(orig, dest, 6) != 0) -- return NL_OK; -- - ifname = if_indextoname(hardif, ifname_buf); - if (!ifname) - return NL_OK; - - sprintf(mac1, "%02x:%02x:%02x:%02x:%02x:%02x", -- orig[0], orig[1], orig[2], orig[3], orig[4], orig[5]); -+ neigh[0], neigh[1], neigh[2], neigh[3], neigh[4], neigh[5]); - -- struct json_object *neigh = json_object_new_object(); -- if (!neigh) -+ struct json_object *obj = json_object_new_object(); -+ if (!obj) - return NL_OK; - -- json_object_object_add(neigh, "tq", json_object_new_int(tq * 100 / 255)); -- json_object_object_add(neigh, "ifname", json_object_new_string(ifname)); -- json_object_object_add(neigh, "best", json_object_new_boolean(nla_get_flag(attrs[BATADV_ATTR_FLAG_BEST]))); -+ for (tp_unit = 0; tp_unit < 4; tp_unit++) -+ { -+ if (throughput < 1000) -+ break; -+ throughput /= 1000; -+ } -+ sprintf(tp_str, "%3u%c", throughput, tp_units[tp_unit]); -+ -+ json_object_object_add(obj, "tp", json_object_new_string(tp_str)); -+ json_object_object_add(obj, "ifname", json_object_new_string(ifname)); -+ json_object_object_add(obj, "best", json_object_new_boolean(nla_get_flag(attrs[BATADV_ATTR_FLAG_BEST]))); - -- json_object_object_add(opts->obj, mac1, neigh); -+ json_object_object_add(opts->obj, mac1, obj); - - return NL_OK; - } -@@ -94,9 +99,9 @@ static json_object *neighbours(void) { - if (!opts.obj) - return NULL; - -- ret = batadv_genl_query("bat0", BATADV_CMD_GET_ORIGINATORS, -- parse_orig_list_netlink_cb, NLM_F_DUMP, -- &opts.query_opts); -+ ret = batadv_genl_query("bat0", BATADV_CMD_GET_NEIGHBORS, -+ parse_neigh_list_netlink_cb, NLM_F_DUMP, -+ &opts.query_opts); - if (ret < 0) { - json_object_put(opts.obj); - return NULL; --- -2.43.0 - diff --git a/patches/0011-wired-tpo-for-BatmanV-fix-shellcheck-error-SC2086.patch b/patches/0011-wired-tpo-for-BatmanV-fix-shellcheck-error-SC2086.patch deleted file mode 100644 index 86f36837..00000000 --- a/patches/0011-wired-tpo-for-BatmanV-fix-shellcheck-error-SC2086.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 1b35624253d82b2c3b85576c4127e21e21e0ee5f Mon Sep 17 00:00:00 2001 -From: Grische -Date: Thu, 31 Oct 2024 15:34:18 +0100 -Subject: [PATCH 11/11] wired-tpo for BatmanV: fix shellcheck error SC2086 - ---- - .../core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -index 95e66831..caecb3dc 100755 ---- a/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -+++ b/package/gluon-mesh-batman-adv/files/lib/gluon/core/mesh/post-setup.d/40-gluon-mesh-batman-adv-wired-tpo -@@ -2,5 +2,5 @@ - - if [ "$IFNAME" = "vx_mesh_uplink" ] || [ "$IFNAME" = "vx_mesh_other" ] || [ "$IFNAME" = "mesh-vpn" ]; then - sleep 3; -- batctl hardif $IFNAME throughput_override 1000mbit; -+ batctl hardif "${IFNAME}" throughput_override 1000mbit; - fi --- -2.43.0 -