From a77d8811477c50b39f813551a092d4f66fd93962 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Thu, 11 Nov 2021 02:22:02 +0100 Subject: [PATCH] atfpolicy: add package Add a Airtime Scheduler that adjusts an UEs ATF weight based on its WMM/TID usage. Fixes: WIFI-5703 Signed-off-by: John Crispin --- feeds/ucentral/atfpolicy/Makefile | 36 ++++ feeds/ucentral/atfpolicy/files/atfpolicy.conf | 8 + feeds/ucentral/atfpolicy/files/atfpolicy.init | 57 ++++++ feeds/ucentral/atfpolicy/src/CMakeLists.txt | 15 ++ feeds/ucentral/atfpolicy/src/atf.h | 90 +++++++++ feeds/ucentral/atfpolicy/src/interface.c | 108 +++++++++++ feeds/ucentral/atfpolicy/src/main.c | 62 +++++++ feeds/ucentral/atfpolicy/src/nl80211.c | 174 ++++++++++++++++++ feeds/ucentral/atfpolicy/src/ubus.c | 164 +++++++++++++++++ profiles/ucentral-ap.yml | 1 + 10 files changed, 715 insertions(+) create mode 100644 feeds/ucentral/atfpolicy/Makefile create mode 100644 feeds/ucentral/atfpolicy/files/atfpolicy.conf create mode 100644 feeds/ucentral/atfpolicy/files/atfpolicy.init create mode 100644 feeds/ucentral/atfpolicy/src/CMakeLists.txt create mode 100644 feeds/ucentral/atfpolicy/src/atf.h create mode 100644 feeds/ucentral/atfpolicy/src/interface.c create mode 100644 feeds/ucentral/atfpolicy/src/main.c create mode 100644 feeds/ucentral/atfpolicy/src/nl80211.c create mode 100644 feeds/ucentral/atfpolicy/src/ubus.c diff --git a/feeds/ucentral/atfpolicy/Makefile b/feeds/ucentral/atfpolicy/Makefile new file mode 100644 index 000000000..d2918a5b9 --- /dev/null +++ b/feeds/ucentral/atfpolicy/Makefile @@ -0,0 +1,36 @@ +# +# Copyright (C) 2021 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=atfpolicy +PKG_VERSION:=1 + +PKG_LICENSE:=GPL-2.0 +PKG_MAINTAINER:=Felix Fietkau + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/cmake.mk + +define Package/atfpolicy + SECTION:=net + CATEGORY:=Network + TITLE:=A simple daemon for handling airtime fairness prioritization + DEPENDS:=+libubox +libubus +libnl-tiny +endef + +TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include/libnl-tiny + +define Package/atfpolicy/install + $(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/init.d $(1)/etc/config + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/atfpolicy $(1)/usr/sbin/ + $(INSTALL_BIN) ./files/atfpolicy.init $(1)/etc/init.d/atfpolicy + $(INSTALL_DATA) ./files/atfpolicy.conf $(1)/etc/config/atfpolicy +endef + +$(eval $(call BuildPackage,atfpolicy)) diff --git a/feeds/ucentral/atfpolicy/files/atfpolicy.conf b/feeds/ucentral/atfpolicy/files/atfpolicy.conf new file mode 100644 index 000000000..915b9d2a0 --- /dev/null +++ b/feeds/ucentral/atfpolicy/files/atfpolicy.conf @@ -0,0 +1,8 @@ +config defaults + option vo_queue_weight 4 + option update_pkt_threshold 100 + option bulk_percent_thresh 50 + option prio_percent_thresh 30 + option weight_normal 256 + option weight_prio 512 + option weight_bulk 128 diff --git a/feeds/ucentral/atfpolicy/files/atfpolicy.init b/feeds/ucentral/atfpolicy/files/atfpolicy.init new file mode 100644 index 000000000..498ad7118 --- /dev/null +++ b/feeds/ucentral/atfpolicy/files/atfpolicy.init @@ -0,0 +1,57 @@ +#!/bin/sh /etc/rc.common +# Copyright (c) 2021 OpenWrt.org + +START=50 + +USE_PROCD=1 +PROG=/usr/sbin/atfpolicy + +add_option() { + local type="$1" + local name="$2" + + config_get val "$cfg" "$name" + + [ -n "$val" ] && json_add_$type "$name" "$val" +} + +add_defaults() { + cfg="$1" + + json_add_boolean reset 1 + + add_option int vo_queue_weight + add_option int update_pkt_threshold + add_option int bulk_percent_thresh + add_option int prio_percent_thresh + add_option int weight_normal + add_option int weight_prio + add_option int weight_bulk +} + + +reload_service() { + json_init + + config_load atfpolicy + + config_foreach add_defaults defaults + + ubus call atfpolicy config "$(json_dump)" +} + +service_triggers() { + procd_add_reload_trigger atfpolicy +} + +start_service() { + procd_open_instance + procd_set_param command "$PROG" + procd_set_param respawn + procd_close_instance +} + +service_started() { + ubus -t 10 wait_for atfpolicy + [ $? = 0 ] && reload_service +} diff --git a/feeds/ucentral/atfpolicy/src/CMakeLists.txt b/feeds/ucentral/atfpolicy/src/CMakeLists.txt new file mode 100644 index 000000000..05cb50bbb --- /dev/null +++ b/feeds/ucentral/atfpolicy/src/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.10) + +PROJECT(atfpolicy C) + +ADD_DEFINITIONS(-Os -Wall -Wno-unknown-warning-option -Wno-array-bounds -Wno-format-truncation -Werror --std=gnu99) + +SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") + +find_library(nl NAMES nl-tiny) +ADD_EXECUTABLE(atfpolicy main.c ubus.c interface.c nl80211.c) +TARGET_LINK_LIBRARIES(atfpolicy ${nl} ubox ubus) + +INSTALL(TARGETS atfpolicy + RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} +) diff --git a/feeds/ucentral/atfpolicy/src/atf.h b/feeds/ucentral/atfpolicy/src/atf.h new file mode 100644 index 000000000..5119ba23d --- /dev/null +++ b/feeds/ucentral/atfpolicy/src/atf.h @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Felix Fietkau + */ +#ifndef __ATF_H +#define __ATF_H + +#include +#include + +#include + +#define ATF_AVG_SCALE 12 + +#define ATF_AVG_WEIGHT_FACTOR 3 +#define ATF_AVG_WEIGHT_DIV 4 + +#define MAC_ADDR_FMT "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC_ADDR_DATA(_a) \ + ((const uint8_t *)(_a))[0], \ + ((const uint8_t *)(_a))[1], \ + ((const uint8_t *)(_a))[2], \ + ((const uint8_t *)(_a))[3], \ + ((const uint8_t *)(_a))[4], \ + ((const uint8_t *)(_a))[5] + +#define D(format, ...) do { \ + if (debug_flag) \ + fprintf(stderr, "DEBUG: %s(%d) " format "\n", __func__, __LINE__, ## __VA_ARGS__); \ + } while (0) + +struct atf_config { + int voice_queue_weight; + int min_pkt_thresh; + + int bulk_percent_thresh; + int prio_percent_thresh; + + int weight_normal; + int weight_prio; + int weight_bulk; +}; + +struct atf_interface { + struct avl_node avl; + + char ifname[IFNAMSIZ + 1]; + uint32_t ubus_obj; + + struct avl_tree stations; +}; + +struct atf_stats { + uint64_t bulk, normal, prio; +}; + +struct atf_station { + struct avl_node avl; + uint8_t macaddr[6]; + bool present; + + uint8_t stats_idx; + struct atf_stats stats[2]; + + uint16_t avg_bulk; + uint16_t avg_prio; + + int weight; +}; + +extern struct atf_config config; +extern int debug_flag; + +void reset_config(void); + +struct atf_interface *atf_interface_get(const char *ifname); +void atf_interface_sta_update(struct atf_interface *iface); +struct atf_station *atf_interface_sta_get(struct atf_interface *iface, uint8_t *macaddr); +void atf_interface_sta_changed(struct atf_interface *iface, struct atf_station *sta); +void atf_interface_sta_flush(struct atf_interface *iface); +void atf_interface_update_all(void); + +int atf_ubus_init(void); +void atf_ubus_stop(void); +void atf_ubus_set_sta_weight(struct atf_interface *iface, struct atf_station *sta); + +int atf_nl80211_init(void); +int atf_nl80211_interface_update(struct atf_interface *iface); + +#endif diff --git a/feeds/ucentral/atfpolicy/src/interface.c b/feeds/ucentral/atfpolicy/src/interface.c new file mode 100644 index 000000000..638bbeb9e --- /dev/null +++ b/feeds/ucentral/atfpolicy/src/interface.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Felix Fietkau + */ +#include +#include + +#include + +#include "atf.h" + +static AVL_TREE(interfaces, avl_strcmp, false, NULL); + +#ifndef container_of_safe +#define container_of_safe(ptr, type, member) \ + (ptr ? container_of(ptr, type, member) : NULL) +#endif + +static int avl_macaddr_cmp(const void *k1, const void *k2, void *ptr) +{ + return memcmp(k1, k2, 6); +} + +void atf_interface_sta_update(struct atf_interface *iface) +{ + struct atf_station *sta; + + avl_for_each_element(&iface->stations, sta, avl) + sta->present = false; +} + +struct atf_station *atf_interface_sta_get(struct atf_interface *iface, uint8_t *macaddr) +{ + struct atf_station *sta; + + sta = avl_find_element(&iface->stations, macaddr, sta, avl); + if (sta) + goto out; + + sta = calloc(1, sizeof(*sta)); + memcpy(sta->macaddr, macaddr, sizeof(sta->macaddr)); + sta->avl.key = sta->macaddr; + sta->weight = -1; + avl_insert(&iface->stations, &sta->avl); + +out: + sta->present = true; + return sta; +} + +void atf_interface_sta_flush(struct atf_interface *iface) +{ + struct atf_station *sta, *tmp; + + avl_for_each_element_safe(&iface->stations, sta, avl, tmp) { + if (sta->present) + continue; + + avl_delete(&iface->stations, &sta->avl); + free(sta); + } +} + +void atf_interface_sta_changed(struct atf_interface *iface, struct atf_station *sta) +{ + int weight; + + if (sta->avg_prio > config.prio_percent_thresh) + weight = config.weight_prio; + else if (sta->avg_prio > config.bulk_percent_thresh) + weight = config.weight_bulk; + else + weight = config.weight_normal; + + if (sta->weight == weight) + return; + + sta->weight = weight; + atf_ubus_set_sta_weight(iface, sta); +} + +struct atf_interface *atf_interface_get(const char *ifname) +{ + struct atf_interface *iface; + + iface = avl_find_element(&interfaces, ifname, iface, avl); + if (iface) + return iface; + + if (strlen(ifname) + 1 > sizeof(iface->ifname)) + return NULL; + + iface = calloc(1, sizeof(*iface)); + strcpy(iface->ifname, ifname); + iface->avl.key = iface->ifname; + avl_init(&iface->stations, avl_macaddr_cmp, false, NULL); + avl_insert(&interfaces, &iface->avl); + + return iface; +} + +void atf_interface_update_all(void) +{ + struct atf_interface *iface, *tmp; + + avl_for_each_element_safe(&interfaces, iface, avl, tmp) + atf_nl80211_interface_update(iface); +} diff --git a/feeds/ucentral/atfpolicy/src/main.c b/feeds/ucentral/atfpolicy/src/main.c new file mode 100644 index 000000000..e295f0fe6 --- /dev/null +++ b/feeds/ucentral/atfpolicy/src/main.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Felix Fietkau + */ +#include +#include +#include + +#include + +#include "atf.h" + +struct atf_config config; +int debug_flag; + +void reset_config(void) +{ + memset(&config, 0, sizeof(config)); + + config.voice_queue_weight = 4; + config.min_pkt_thresh = 100; + + config.bulk_percent_thresh = (50 << ATF_AVG_SCALE) / 100; + config.prio_percent_thresh = (30 << ATF_AVG_SCALE) / 100; + + config.weight_normal = 256; + config.weight_bulk = 128; + config.weight_prio = 512; +} + +static void atf_update_cb(struct uloop_timeout *t) +{ + atf_interface_update_all(); + uloop_timeout_set(t, 1000); +} + +int main(int argc, char **argv) +{ + static struct uloop_timeout update_timer = { + .cb = atf_update_cb, + }; + int ch; + + while ((ch = getopt(argc, argv, "d")) != -1) { + switch (ch) { + case 'd': + debug_flag = 1; + break; + } + } + + reset_config(); + uloop_init(); + atf_ubus_init(); + atf_nl80211_init(); + atf_update_cb(&update_timer); + uloop_run(); + atf_ubus_stop(); + uloop_done(); + + return 0; +} diff --git a/feeds/ucentral/atfpolicy/src/nl80211.c b/feeds/ucentral/atfpolicy/src/nl80211.c new file mode 100644 index 000000000..c0594d2ea --- /dev/null +++ b/feeds/ucentral/atfpolicy/src/nl80211.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Felix Fietkau + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "atf.h" + +static struct unl unl; + +static void +atf_parse_tid_stats(struct atf_interface *iface, struct atf_stats *stats, + int tid, struct nlattr *attr) +{ + struct nlattr *tb[NL80211_TID_STATS_MAX + 1]; + uint64_t msdu; + + if (nla_parse_nested(tb, NL80211_TID_STATS_MAX, attr, NULL)) + return; + + if (!tb[NL80211_TID_STATS_TX_MSDU]) + return; + + msdu = nla_get_u64(tb[NL80211_TID_STATS_TX_MSDU]); + switch (tid) { + case 0: + case 3: + /* BE */ + stats->normal += msdu; + break; + case 1: + case 2: + /* BK */ + stats->bulk += msdu; + break; + case 4: + case 5: + /* VI */ + stats->prio += msdu; + break; + case 6: + case 7: + stats->prio += msdu * config.voice_queue_weight; + /* VO */ + break; + default: + break; + } +} + +static uint64_t atf_stats_total(struct atf_stats *stats) +{ + return stats->normal + stats->prio + stats->bulk; +} + +static void atf_stats_diff(struct atf_stats *dest, struct atf_stats *cur, struct atf_stats *prev) +{ + dest->normal = cur->normal - prev->normal; + dest->prio = cur->prio - prev->prio; + dest->bulk = cur->bulk - prev->bulk; +} + +static uint16_t atf_stats_avg(uint16_t avg, uint64_t cur, uint32_t total) +{ + cur <<= ATF_AVG_SCALE; + cur /= total; + + if (!avg) + return (uint16_t)cur; + + avg *= ATF_AVG_WEIGHT_FACTOR; + avg += cur * (ATF_AVG_WEIGHT_DIV - ATF_AVG_WEIGHT_FACTOR); + avg /= ATF_AVG_WEIGHT_DIV; + + if (!avg) + avg = 1; + + return avg; +} + + +static void atf_sta_update_avg(struct atf_station *sta, struct atf_stats *cur) +{ + uint64_t total = atf_stats_total(cur); + + D("sta "MAC_ADDR_FMT" total pkts: total=%d bulk=%d normal=%d prio=%d", + MAC_ADDR_DATA(sta->macaddr), (uint32_t)total, + (uint32_t)cur->bulk, (uint32_t)cur->normal, (uint32_t)cur->prio); + if (total < config.min_pkt_thresh) + return; + + sta->avg_bulk = atf_stats_avg(sta->avg_bulk, cur->bulk, total); + sta->avg_prio = atf_stats_avg(sta->avg_prio, cur->prio, total); + D("avg bulk=%d prio=%d", + (sta->avg_bulk * 100) >> ATF_AVG_SCALE, + (sta->avg_prio * 100) >> ATF_AVG_SCALE); + sta->stats_idx = !sta->stats_idx; +} + +static int +atf_sta_cb(struct nl_msg *msg, void *arg) +{ + struct atf_interface *iface = arg; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1]; + struct atf_station *sta; + struct atf_stats *stats, diff = {}; + struct nlattr *cur; + int idx = 0; + int rem; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (!tb[NL80211_ATTR_STA_INFO] || !tb[NL80211_ATTR_MAC]) + return NL_SKIP; + + if (nla_parse_nested(sinfo, NL80211_STA_INFO_MAX, + tb[NL80211_ATTR_STA_INFO], NULL)) + return NL_SKIP; + + if (!sinfo[NL80211_STA_INFO_TID_STATS]) + return NL_SKIP; + + sta = atf_interface_sta_get(iface, nla_data(tb[NL80211_ATTR_MAC])); + if (!sta) + return NL_SKIP; + + stats = &sta->stats[sta->stats_idx]; + memset(stats, 0, sizeof(*stats)); + nla_for_each_nested(cur, sinfo[NL80211_STA_INFO_TID_STATS], rem) + atf_parse_tid_stats(iface, stats, idx++, cur); + + atf_stats_diff(&diff, stats, &sta->stats[!sta->stats_idx]); + atf_sta_update_avg(sta, &diff); + atf_interface_sta_changed(iface, sta); + + return NL_SKIP; +} + +int atf_nl80211_interface_update(struct atf_interface *iface) +{ + struct nl_msg *msg; + int ifindex; + + ifindex = if_nametoindex(iface->ifname); + if (!ifindex) + return -1; + + atf_interface_sta_update(iface); + + msg = unl_genl_msg(&unl, NL80211_CMD_GET_STATION, true); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); + unl_genl_request(&unl, msg, atf_sta_cb, iface); + + atf_interface_sta_flush(iface); + + return 0; + +nla_put_failure: + nlmsg_free(msg); + return -1; +} + +int atf_nl80211_init(void) +{ + return unl_genl_init(&unl, "nl80211"); +} diff --git a/feeds/ucentral/atfpolicy/src/ubus.c b/feeds/ucentral/atfpolicy/src/ubus.c new file mode 100644 index 000000000..97a055c0b --- /dev/null +++ b/feeds/ucentral/atfpolicy/src/ubus.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 Felix Fietkau + */ +#include + +#include "atf.h" + +#define HOSTAPD_PREFIX "hostapd." + +static struct ubus_auto_conn conn; +static struct blob_buf b; + +enum { + ATF_CONFIG_RESET, + ATF_CONFIG_VO_Q_WEIGHT, + ATF_CONFIG_MIN_PKT_THRESH, + ATF_CONFIG_BULK_PERCENT_THR, + ATF_CONFIG_PRIO_PERCENT_THR, + + ATF_CONFIG_WEIGHT_NORMAL, + ATF_CONFIG_WEIGHT_PRIO, + ATF_CONFIG_WEIGHT_BULK, + __ATF_CONFIG_MAX +}; + +static const struct blobmsg_policy atf_config_policy[__ATF_CONFIG_MAX] = { + [ATF_CONFIG_VO_Q_WEIGHT] = { "vo_queue_weight", BLOBMSG_TYPE_INT32 }, + [ATF_CONFIG_MIN_PKT_THRESH] = { "update_pkt_threshold", BLOBMSG_TYPE_INT32 }, + [ATF_CONFIG_BULK_PERCENT_THR] = { "bulk_percent_thresh", BLOBMSG_TYPE_INT32 }, + [ATF_CONFIG_PRIO_PERCENT_THR] = { "prio_percent_thresh", BLOBMSG_TYPE_INT32 }, + [ATF_CONFIG_WEIGHT_NORMAL] = { "weight_normal", BLOBMSG_TYPE_INT32 }, + [ATF_CONFIG_WEIGHT_PRIO] = { "weight_prio", BLOBMSG_TYPE_INT32 }, + [ATF_CONFIG_WEIGHT_BULK] = { "weight_bulk", BLOBMSG_TYPE_INT32 }, +}; + +static int +atf_ubus_config(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__ATF_CONFIG_MAX]; + struct blob_attr *cur; + static const struct { + int id; + int *field; + } field_map[] = { + { ATF_CONFIG_VO_Q_WEIGHT, &config.voice_queue_weight }, + { ATF_CONFIG_MIN_PKT_THRESH, &config.min_pkt_thresh }, + { ATF_CONFIG_BULK_PERCENT_THR, &config.bulk_percent_thresh }, + { ATF_CONFIG_PRIO_PERCENT_THR, &config.prio_percent_thresh }, + { ATF_CONFIG_WEIGHT_NORMAL, &config.weight_normal }, + { ATF_CONFIG_WEIGHT_PRIO, &config.weight_prio }, + { ATF_CONFIG_WEIGHT_BULK, &config.weight_bulk }, + }; + bool reset = false; + int i; + + blobmsg_parse(atf_config_policy, __ATF_CONFIG_MAX, tb, + blobmsg_data(msg), blobmsg_len(msg)); + + if ((cur = tb[ATF_CONFIG_RESET]) != NULL) + reset = blobmsg_get_bool(cur); + + if (reset) + reset_config(); + + for (i = 0; i < ARRAY_SIZE(field_map); i++) { + if ((cur = tb[field_map[i].id]) != NULL) + *(field_map[i].field) = blobmsg_get_u32(cur); + } + + return 0; +} + + +static const struct ubus_method atf_methods[] = { + UBUS_METHOD("config", atf_ubus_config, atf_config_policy), +}; + +static struct ubus_object_type atf_object_type = + UBUS_OBJECT_TYPE("atfpolicy", atf_methods); + +static struct ubus_object atf_object = { + .name = "atfpolicy", + .type = &atf_object_type, + .methods = atf_methods, + .n_methods = ARRAY_SIZE(atf_methods), +}; + +static void +atf_ubus_add_interface(struct ubus_context *ctx, const char *name) +{ + struct atf_interface *iface; + + iface = atf_interface_get(name + strlen(HOSTAPD_PREFIX)); + if (!iface) + return; + + iface->ubus_obj = 0; + ubus_lookup_id(ctx, name, &iface->ubus_obj); + D("add interface %s", name + strlen(HOSTAPD_PREFIX)); +} + +static void +atf_ubus_lookup_cb(struct ubus_context *ctx, struct ubus_object_data *obj, + void *priv) +{ + if (!strncmp(obj->path, HOSTAPD_PREFIX, strlen(HOSTAPD_PREFIX))) + atf_ubus_add_interface(ctx, obj->path); +} + +void atf_ubus_set_sta_weight(struct atf_interface *iface, struct atf_station *sta) +{ + D("set sta "MAC_ADDR_FMT" weight=%d", MAC_ADDR_DATA(sta->macaddr), sta->weight); + blob_buf_init(&b, 0); + blobmsg_printf(&b, "sta", MAC_ADDR_FMT, MAC_ADDR_DATA(sta->macaddr)); + blobmsg_add_u32(&b, "weight", sta->weight); + if (ubus_invoke(&conn.ctx, iface->ubus_obj, "update_airtime", b.head, NULL, NULL, 100)) + D("set airtime weight failed"); +} + +static void +atf_ubus_event_cb(struct ubus_context *ctx, struct ubus_event_handler *ev, + const char *type, struct blob_attr *msg) +{ + static const struct blobmsg_policy policy = + { "path", BLOBMSG_TYPE_STRING }; + struct ubus_object_data obj; + struct blob_attr *attr; + + blobmsg_parse(&policy, 1, &attr, blobmsg_data(msg), blobmsg_len(msg)); + + if (!attr) + return; + + obj.path = blobmsg_get_string(attr); + atf_ubus_lookup_cb(ctx, &obj, NULL); +} + +static void +ubus_connect_handler(struct ubus_context *ctx) +{ + static struct ubus_event_handler ev = { + .cb = atf_ubus_event_cb + }; + + ubus_add_object(ctx, &atf_object); + ubus_register_event_handler(ctx, &ev, "ubus.object.add"); + ubus_lookup(ctx, "hostapd.*", atf_ubus_lookup_cb, NULL); +} + +int atf_ubus_init(void) +{ + conn.cb = ubus_connect_handler; + ubus_auto_connect(&conn); + + return 0; +} + +void atf_ubus_stop(void) +{ + ubus_auto_shutdown(&conn); +} diff --git a/profiles/ucentral-ap.yml b/profiles/ucentral-ap.yml index 1fc6091de..59f50f740 100644 --- a/profiles/ucentral-ap.yml +++ b/profiles/ucentral-ap.yml @@ -14,6 +14,7 @@ include: - qosify packages: + - atfpolicy - kmod-batman-adv - batctl-default - cJSON