usteer2: add new package

Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
John Crispin
2022-10-10 09:59:55 +02:00
parent 4c4cb58027
commit bea3d2c4f8
18 changed files with 1076 additions and 3 deletions

View File

@@ -4,10 +4,9 @@ PKG_NAME:=ucentral-schema
PKG_RELEASE:=1
PKG_SOURCE_URL=https://github.com/Telecominfraproject/wlan-ucentral-schema.git
PKG_MIRROR_HASH:=89fd7dcbd965e3acccc39744a4e9a1dc7e41fd97facfa1638190f90604e7734b
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2022-05-29
PKG_SOURCE_VERSION:=8d4384baedc0e48b1d1554d419ed217bb3aa0de5
PKG_SOURCE_VERSION:=9877d3014b11b98eede5ea694e5566873b740ee3
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
PKG_LICENSE:=BSD-3-Clause

View File

@@ -0,0 +1,89 @@
{
"uuid": 2,
"radios": [
{
"band": "2G",
"country": "CA",
"channel-mode": "HE",
"channel-width": 80,
"channel": 32
}
],
"interfaces": [
{
"name": "WAN",
"role": "upstream",
"services": [ "lldp" ],
"ethernet": [
{
"select-ports": [
"WAN*"
]
}
],
"ipv4": {
"addressing": "dynamic"
},
"ssids": [
{
"name": "OpenWifi",
"wifi-bands": [
"2G"
],
"bss-mode": "ap",
"encryption": {
"proto": "psk2",
"key": "OpenWifi",
"ieee80211w": "optional"
},
"quality-thresholds" : {
"probe-request-rssi": -35,
"assoctiation-request-rssi": -35,
"client-kick-rssi": -45,
"client-kick-ban-time": 60
}
}
]
},
{
"name": "LAN",
"role": "downstream",
"services": [ "ssh", "lldp" ],
"ethernet": [
{
"select-ports": [
"LAN*"
]
}
],
"ipv4": {
"addressing": "static",
"subnet": "192.168.1.1/24",
"dhcp": {
"lease-first": 10,
"lease-count": 100,
"lease-time": "6h"
}
}
}
],
"metrics": {
"statistics": {
"interval": 120,
"types": [ "ssids", "lldp", "clients" ]
},
"health": {
"interval": 120
}
},
"services": {
"lldp": {
"describe": "uCentral",
"location": "universe"
},
"ssh": {
"port": 22
}
}
}

View File

@@ -0,0 +1,34 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=ucrun
PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=https://github.com/ucentral-io/ucrun.git
PKG_MIRROR_HASH:=52aeece27348611197ae5f4b96b3bdf1b5d028ae4ae284806b216d502300d07a
PKG_SOURCE_DATE:=2022-02-19
PKG_SOURCE_VERSION:=5be6abebc4ae6057b47a5b3f0799d5ff01bc60c3
CMAKE_INSTALL:=1
PKG_LICENSE:=GPL-2.0-only
PKG_LICENSE_FILES:=GPL
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
define Package/ucrun
SECTION:=utils
CATEGORY:=Utilities
DEPENDS:=+libubox +ucode +ucode-mod-uci +ucode-mod-ubus +ucode-mod-fs
TITLE:=uCode main-loop daemon
endef
define Package/ucrun/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/ucrun $(1)/usr/bin
endef
$(eval $(call BuildPackage,ucrun))

View File

@@ -0,0 +1,138 @@
From b24a5a890ccd19b0f1b50340c79c5087f08d9447 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Fri, 4 Mar 2022 15:56:30 +0100
Subject: [PATCH] ulog: add ringbuffer and log_event notification
Signed-off-by: John Crispin <john@phrozen.org>
---
ucode.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 73 insertions(+), 2 deletions(-)
diff --git a/ucode.c b/ucode.c
index cef50e2..9e0373a 100644
--- a/ucode.c
+++ b/ucode.c
@@ -31,6 +31,17 @@ static const char *exception_types[] = {
[EXCEPTION_EXIT] = "Exit"
};
+struct log_buffer {
+ struct list_head list;
+ int severity;
+ char entry[];
+};
+
+static LIST_HEAD(log_buffer);
+static int log_count;
+static int log_max = 100;
+static uc_value_t *log_event;
+
static void
ucode_handle_exception(uc_vm_t *vm, uc_exception_t *ex)
{
@@ -287,6 +298,7 @@ static uc_value_t *
uc_ulog(uc_vm_t *vm, size_t nargs, int severity)
{
uc_value_t *res;
+ char *entry;
if (!fmtfn) {
fmtfn = (uc_cfunction_t *)ucv_object_get(uc_vm_scope_get(vm), "sprintf", NULL);
@@ -300,7 +312,37 @@ uc_ulog(uc_vm_t *vm, size_t nargs, int severity)
if (!res)
return ucv_int64_new(-1);
- ulog(severity, "%s", ucv_string_get(res));
+ entry = ucv_string_get(res);
+
+ if (log_max) {
+ struct log_buffer *log = calloc(1, sizeof(*log) + strlen(entry) + 1);
+
+ strcpy(log->entry, entry);
+ log->severity = severity;
+ list_add_tail(&log->list, &log_buffer);
+
+ if (log_event) {
+ uc_value_t *event = ucv_array_new(vm);
+
+ ucv_array_push(event, ucv_int64_new(severity));
+ ucv_array_push(event, ucv_string_new(entry));
+
+ uc_vm_stack_push(vm, ucv_get(log_event));
+ uc_vm_stack_push(vm, ucv_get(event));
+ uc_vm_call(vm, false, 1);
+ }
+
+ if (log_count == log_max) {
+ struct log_buffer *first = list_first_entry(&log_buffer, struct log_buffer, list);
+
+ list_del(&first->list);
+ free(first);
+ } else {
+ log_count++;
+ }
+ }
+
+ ulog(severity, "%s", entry);
ucv_put(res);
return ucv_int64_new(0);
@@ -330,11 +372,27 @@ uc_ulog_err(uc_vm_t *vm, size_t nargs)
return uc_ulog(vm, nargs, LOG_ERR);
}
+static uc_value_t *
+uc_ulog_dump(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *log = ucv_array_new(vm);
+ struct log_buffer *iter;
+
+ list_for_each_entry(iter, &log_buffer, list) {
+ uc_value_t *entry = ucv_array_new(vm);
+ ucv_array_push(entry, ucv_int64_new(iter->severity));
+ ucv_array_push(entry, ucv_string_new(iter->entry));
+ ucv_array_push(log, entry);
+ }
+
+ return log;
+}
+
static void
ucode_init_ulog(ucrun_ctx_t *ucrun)
{
uc_value_t *ulog = ucv_object_get(ucrun->scope, "ulog", NULL);
- uc_value_t *identity, *channels;
+ uc_value_t *identity, *channels, *logsize;
int flags = 0, channel;
/* make sure the declartion is complete */
@@ -365,6 +423,18 @@ ucode_init_ulog(ucrun_ctx_t *ucrun)
flags |= ULOG_STDIO;
}
+ /* set the internal ring buffer size */
+ logsize = ucv_object_get(ulog, "channels", NULL);
+ if (ucv_type(logsize) == UC_INTEGER && ucv_int64_get(logsize))
+ log_max = ucv_int64_get(logsize);
+
+ /* find out if ucrun wants a notification when a new log entry is generated */
+ log_event = ucv_object_get(ulog, "event", NULL);
+ if (ucv_is_callable(log_event))
+ ucv_get(log_event);
+ else
+ log_event = NULL;
+
/* open the log */
ucrun->ulog_identity = strdup(ucv_string_get(identity));
ulog_open(flags, LOG_DAEMON, ucrun->ulog_identity);
@@ -404,6 +474,7 @@ ucode_init(ucrun_ctx_t *ucrun, int argc, const char **argv, int *rc)
uc_function_register(ucrun->scope, "ulog_note", uc_ulog_note);
uc_function_register(ucrun->scope, "ulog_warn", uc_ulog_warn);
uc_function_register(ucrun->scope, "ulog_err", uc_ulog_err);
+ uc_function_register(ucrun->scope, "ulog_dump", uc_ulog_dump);
/* add commandline parameters */
ARGV = ucv_array_new(&ucrun->vm);
--
2.25.1

View File

@@ -0,0 +1,27 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=usteer2
PKG_RELEASE:=1
PKG_LICENSE:=ISC
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
include $(INCLUDE_DIR)/package.mk
define Package/usteer2
SECTION:=utils
CATEGORY:=Utilities
DEPENDS:=+ucrun
TITLE:=wifi client steering
endef
define Build/Compile/Default
endef
Build/Compile = $(Build/Compile/Default)
define Package/usteer2/install
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,usteer2))

View File

@@ -0,0 +1,9 @@
config base
option station_update 1000
option station_expiry 120
config policy
option name snr
option min_snr_kick_delay 5
option kick_reason 5
option interval 1000

View File

@@ -0,0 +1,13 @@
#!/bin/sh /etc/rc.common
START=99
STOP=01
USE_PROCD=1
start_service() {
procd_open_instance
procd_set_param command /usr/bin/usteer.uc
procd_set_param respawn 3600 5 0
procd_close_instance
}

View File

@@ -0,0 +1,75 @@
#!/usr/bin/ucrun
push(REQUIRE_SEARCH_PATH, '/usr/share/usteer/*.uc');
global.ulog = {
identity: 'usteer',
channels: [ 'stdio', 'syslog' ],
};
global.ubus = {
object: 'usteer2',
connect: function() {
printf('connected to ubus\n');
},
methods: {
interfaces: {
cb: function(msg) {
return global.local.status();
}
},
stations: {
cb: function(msg) {
return global.station.list(msg);
}
},
status: {
cb: function(msg) {
return global.station.status();
}
},
command: {
cb: function(msg) {
return global.command.handle(msg);
}
},
get_beacon_request: {
cb: function(msg) {
let val = global.station.list(msg);
return val?.beacon_report || {};
}
},
policy: {
cb: function(msg) {
return global.policy.status(msg);
},
},
},
};
global.start = function() {
try {
global.uci = require('uci').cursor();
global.ubus.conn = require('ubus').connect();
for (let module in [ 'config', 'local', 'station', 'command', 'policy' ]) {
printf('loading ' + module + '\n');
global[module] = require(module);
if (exists(global[module], 'init'))
global[module].init();
}
} catch(e) {
printf('exception %s\n', e);
}
};
global.stop = function() {
ulog_info('stopping\n');
};

View File

@@ -0,0 +1,35 @@
function result(error, text, data) {
return {
error: error,
text: text || 'unknown',
...(data ? { data } : {}),
};
}
const actions = {
// ubus call usteer2 command '{"action": "kick", "mac": "1c:57:dc:37:3c:b1", "params": {"reason": 5, "ban_time": 30}}'
kick: function(msg) {
if (global.station.kick(msg.mac, msg.params?.reason, msg.params?.ban_time))
return result(1, 'station ' + msg.mac + ' is unknown');
return result(0, 'station ' + msg.mac + ' was kicked');
},
// ubus call usteer2 command '{"action": "beacon_request", "mac": "1c:57:dc:37:3c:b1", "params": {"channel": 36}}'
// ubus call usteer2 get_beacon_request '{"mac": "1c:57:dc:37:3c:b1"}'
beacon_request: function(msg) {
if (!global.station.beacon_request(msg.mac, msg.params?.channel, msg.params?.op_class, msg.param?.duration))
return result(1, 'station ' + msg.mac + ' is unknown');
return result(0, 'station ' + msg.mac + ' beacon-request sent');
},
};
return {
handle: function(msg) {
if (!actions[msg.action])
return result(1, 'unknown action ' + msg.action);
return actions[msg.action](msg);
},
};

View File

@@ -0,0 +1,10 @@
return {
station_update: 1000,
station_expiry: 120,
init: function() {
let options = uci.get_all('usteer2', '@base[-1]');
for (let key in options)
this[key] = options[key];
},
};

View File

@@ -0,0 +1,142 @@
let nl80211 = require("nl80211");
let def = nl80211.const;
let subscriber;
let state = {};
let hapd = {};
let handlers = {};
function channel_survey(dev) {
/* trigger the nl80211 call that gathers channel survey data */
let res = nl80211.request(def.NL80211_CMD_GET_SURVEY, def.NLM_F_DUMP, { dev });
if (!res) {
ulog_err(sprintf('failed to update survey for %s', dev));
return;
}
/* iterate over the result and filter out the correct channel */
for (let survey in res) {
if (survey?.survey_info?.frequency != hapd[dev].freq)
continue;
if (survey.survey_info.noise)
hapd[dev].noise = survey.survey_info.noise;
if (survey.survey_info.time && survey.survey_info.busy) {
let time = survey.survey_info.time - (state[dev].time || 0);
let busy = survey.survey_info.busy - (state[dev].busy || 0);
state[dev].time = survey.survey_info.time;
state[dev].busy = survey.survey_info.busy;
let load = (100 * busy) / time;
if (hapd[dev].load)
hapd[dev].load = 0.85 * hapd[dev].load + 0.15 * load;
else
hapd[dev].load = load;
}
}
}
function hapd_update() {
/* todo: prefilter frequency */
for (let key in state)
channel_survey(key);
return 5000;
}
function hapd_subunsub(path, sub) {
/* check if this is a hostapd instance */
let name = split(path, '.');
if (length(name) != 2 || name[0] != 'hostapd')
return;
name = name[1];
ulog_info(sprintf('%s %s\n', sub ? 'add' : 'remove', path));
/* the hostapd instance disappeared */
if (!sub) {
delete hapd[name];
delete state[name];
return;
}
/* gather initial data from hostapd */
let status = global.ubus.conn.call(path, 'get_status');
if (!status)
return;
let cfg = uci.get_all('usteer2', status.uci_section);
if (!cfg)
return;
/* subscibe to hostapd */
subscriber.subscribe(path);
/* tell hostapd to wait for a reply before answering probe requests */
//global.ubus.conn.call(path, 'notify_response', { 'notify_response': 1 });
/* tell hostapd to enable rrm/roaming */
global.ubus.conn.call(path, 'bss_mgmt_enable', { 'neighbor_report': 1, 'beacon_report': 1, 'bss_transition': 1 });
/* instantiate state */
hapd[name] = { };
state[name] = { };
for (let prop in [ 'ssid', 'bssid', 'freq', 'channel', 'op_class', 'uci_section' ])
if (status[prop])
hapd[name][prop] = status[prop];
hapd[name].config = cfg;
/* ask hostapd for the local neighbourhood report data */
let rrm = global.ubus.conn.call(path, 'rrm_nr_get_own');
if (rrm && rrm.value)
hapd[name].rrm_nr = rrm.value;
/* trigger an initial channel survey */
channel_survey(name);
}
function hapd_listener(event, msg) {
hapd_subunsub(msg.path, event == 'ubus.object.add');
}
function hapd_handle_event(req) {
/* iterate over all handlers for this event type, if 1 or more handlers replied with false, do not reply to the notification */
let reply = true;
for (let handler in handlers[req.type])
if (!handler(req.type, req.data))
reply = false;
if (!reply)
return;
req.reply();
}
return {
status: function() {
return hapd;
},
init: function() {
subscriber = global.ubus.conn.subscriber(
hapd_handle_event,
function(msg) {
// printf('2 %.J\n', msg);
});
/* register a callback that will monitor hostapd instances spawning and disappearing */
global.ubus.conn.listener('ubus.object.add', hapd_listener);
global.ubus.conn.listener('ubus.object.remove', hapd_listener);
/* iterade over all existing hostapd instances and subscribe to them */
for (let path in global.ubus.conn.list())
hapd_subunsub(path, true);
uloop_timeout(hapd_update, 5000);
},
register_handler: function(event, handler) {
/* a policy requested to be notified of action frames, register the callback */
handlers[event] ??= [];
push(handlers[event], handler);
},
};

View File

@@ -0,0 +1,36 @@
let policies = {};
return {
init: function() {
let config = global.uci.get_all('usteer2');
for (let section in config) {
if (config[section]['.type'] != 'policy' || !config[section].name)
continue;
let policy = require(`policy_${config[section].name}`);
if (type(policy) != 'object' || type(policy.init) != 'function') {
ulog_info('failed to load policy "%s"\n', config[section].name);
continue;
}
try {
policy.init(config[section]);
} catch(e) {
ulog_info('failed to initialze policy "%s"\n', config[section].name);
continue;
}
ulog_info('loaded policy "%s"\n', config[section].name);
policies[config[section].name] = policy;
}
},
status: function(msg) {
/* if no specific policies state was requested, dump the list of loaded policies */
if (msg?.name === null)
return { policies: keys(policies) };
/* check if the requested policy exists and dump its state */
if (policies[msg.name])
return policies[msg.name].status(msg);
/* return an empty dictionary */
return {};
},
};

View File

@@ -0,0 +1,91 @@
let config = {
/* how many seconds must a client be below the thershold before we kick it */
min_snr_kick_delay: 5,
/* the reson code sent when triggering the deauth (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */
kick_reason: 5,
/* the periodicity for checking client kick conditions */
interval: 1000,
};
/* counter of how often a station was kicked */
let kick_count = 0;
let foo = 0;
function snr_update() {
try {
let iface = global.local.status();
let stations = global.station.list();
let now = time();
/* iterate over all stations and kick anything that had a signal worse than the threshold for too long */
for (let addr in stations) {
let station = stations[addr];
if (!station.signal || !station.device)
continue;
let device = iface[station.device].config;
if (!device?.client_kick_rssi)
continue;
if (0) {
foo++;
if (foo > 10)
station.signal = -80;
printf(`snr check ${addr} ${station.seen} ${station.signal} ${device.client_kick_rssi}\n`);
}
printf(`${addr} ${station.signal} ${device.client_kick_rssi}\n`);
/* ignore old stations and ones that have a good signal */
if (now - station.seen > 2 || station.signal >= device.client_kick_rssi) {
station.snr_kick_timer = 0;
continue;
}
/* find out how long the station had a bad signal for */
if (!station.snr_kick_timer)
station.snr_kick_timer = now;
if (now - station.snr_kick_timer < config.min_snr_kick_delay)
continue;
printf(`${now - station.seen}\n`);
if ((now - station.seen) > 2)
return;
/* kick the station and ban it for the configured timeout */
ulog_info(`kick ${addr} as signal (${station.signal}) is too low\n`);
global.station.kick(addr, config.kick_reason, device.client_kick_ban_time);
kick_count++;
}
} catch(e) {
printf(`snr exception ${e}\n`);
}
return config.interval;
}
function probe_handler(type, data) {
/* only send a probe request if the signal is good enough */
return (data.signal > config.min_connect_snr)
}
return {
init: function(data) {
/* load config and override defaults if they were set in UCI */
for (let key in config)
if (data[key])
config[key] = +data[key];
/* register a callback that will inspect probe-requests and prevent a reply if SNR is too low */
//global.local.register_handler('probe', probe_handler);
/* register the timer that periodically checks if a client should be kicked */
uloop_timeout(snr_update, config.interval);
},
status: function(data) {
/* dump the status of this policy */
return { config, kick_count };
},
};

View File

@@ -0,0 +1,201 @@
let stations = {};
function station_add(device, addr, data, seen) {
/* only honour stations that are authenticated */
if (!data.auth || !data.assoc)
return;
/* if the station is new, add the initial entry */
if (!stations[addr]) {
ulog_info(`add station ${ addr }\n`);
/* extract the rrm bits and give them meaningful names */
let rrm = {
link_measure: !!(data.rrm[0] & 0x1),
beacon_passive_measure: !!(data.rrm[0] & 0x10),
beacon_active_measure: !!(data.rrm[0] & 0x20),
beacon_table_measure: !!(data.rrm[0] & 0x40),
statistics_measure: !!(data.rrm[1] & 0x8),
};
/* add the new station */
stations[addr] = {
rrm,
beacon_report: {},
};
}
/* update device, seen and signal data */
stations[addr].device = device;
stations[addr].seen = seen;
if (data.signal)
stations[addr].signal = data.signal;
}
function station_del(addr) {
ulog_info(`deleting ${ addr }\n`);
delete stations[addr];
}
function stations_update() {
try {
/* lets not call time() multiple times */
let seen = time();
/* iterate over all ssids and ask hapd for the list of associations */
for (let device in global.local.status()) {
let clients = global.ubus.conn.call(`hostapd.${ device}`, 'get_clients');
for (let client in clients.clients)
if (clients.clients[client].auth)
station_add(device, client, clients.clients[client], seen);
else
station_del(client);
}
/* purge all stations that have not been seen in a while */
for (let station in stations) {
if (seen - stations[station].seen <= +global.config.station_expiry)
continue;
station_del(station);
}
} catch (e) {
printf('%.J', e);
}
/* restart the timer */
return +global.config.station_update;
}
function beacon_report(type, report) {
/* make sure that the station exists */
if (!stations[report.address]) {
ulog_err(`beacon report on unknown station ${report.address}\n`);
return false;
}
/* store the report */
stations[report.address].beacon_report[report.bssid] = {
seen: time(),
channel: report.channel,
rcpi: report.rcpi,
rsni: report.rsni,
};
}
function probe_handler(type, data) {
/* track non-associated stations SNR */
stations[data.address] = {
signal: data.signal,
connected: false,
seen: time(),
};
return true;
}
function disassoc_handler(type, data) {
station_del(data.address);
return true;
}
return {
init: function() {
/* register the mgmt frame handlers */
global.local.register_handler('beacon-report', beacon_report);
//global.local.register_handler('probe', probe_handler);
global.local.register_handler('disassoc', disassoc_handler);
/* initial probe of associated stations */
uloop_timeout(stations_update, 100);
},
status: function() {
let ret = { };
let now = time();
/* get the list of our local APs */
let local = global.local.status();
/* iterate over all APs and aggregate their associations */
for (let device in local) {
/* iterate over all known stations */
for (let addr, station in stations) {
/* match for the current AP */
if (station.device != device)
continue;
/* add the station info to the return data */
ret[addr] = {
[device]: {
signal: station.signal,
rrm: station.rrm,
last_seen: now - station.seen,
},
};
if (length(station.beacon_report))
ret[addr][device].beacon_report = station.beacon_report;
}
}
return ret;
},
beacon_request: function(addr, channel, mode, op_class, duration) {
let station = stations[addr];
/* make sure that the station exists */
if (!station) {
ulog_err(`beacon request on unknown station ${addr}`);
return false;
}
/* make sure that the station supports active beacon requests */
if (!station.rrm?.beacon_active_measure) {
ulog_err(`${addr} does not support beacon requests`);
return false;
}
station.beacon_report = {};
let payload = {
addr,
channel,
mode: mode || 1,
op_class: op_class || 128,
duration: duration || 100,
};
global.ubus.conn.call(`hostapd.${station.device}`, 'rrm_beacon_req', payload);
return true;
},
kick: function(addr, reason, ban_time) {
if (!exists(stations, addr))
return -1;
let payload = {
addr,
reason: reason || 5,
deauth: 1
};
if (ban_time)
payload.ban_time = ban_time * 1000;
/* tell hostapd to kick a station via ubus */
global.ubus.conn.call(`hostapd.${stations[addr].device}`, 'del_client', payload);
return 0;
},
list: function(msg) {
if (msg?.mac)
return stations[msg.mac] || {};
return stations;
},
steer: function(addr, imminent, neighbors) {
},
};

View File

@@ -392,6 +392,8 @@ hostapd_common_add_bss_config() {
config_add_string fils_dhcp
config_add_boolean ratelimit
config_add_string uci_section
}
hostapd_set_vlan_file() {
@@ -627,7 +629,7 @@ hostapd_set_bss_options() {
airtime_bss_weight airtime_bss_limit airtime_sta_weight \
multicast_to_unicast_all proxy_arp per_sta_vif \
eap_server eap_user_file ca_cert server_cert private_key private_key_passwd server_id \
vendor_elements fils
vendor_elements fils uci_section
set_default fils 0
set_default isolate 0
@@ -1152,6 +1154,8 @@ hostapd_set_bss_options() {
append bss_conf "per_sta_vif=$per_sta_vif" "$N"
fi
[ -n "$uci_section" ] && append bss_conf "uci_section=$uci_section" "$N"
json_get_values opts hostapd_bss_options
for val in $opts; do
append bss_conf "$val" "$N"

View File

@@ -0,0 +1,51 @@
Index: hostapd-2021-02-20-59e9794c/hostapd/config_file.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/hostapd/config_file.c
+++ hostapd-2021-02-20-59e9794c/hostapd/config_file.c
@@ -2366,6 +2366,8 @@ static int hostapd_config_fill(struct ho
return 1;
}
conf->driver = driver;
+ } else if (os_strcmp(buf, "uci_section") == 0) {
+ bss->uci_section = os_strdup(pos);
} else if (os_strcmp(buf, "driver_params") == 0) {
os_free(conf->driver_params);
conf->driver_params = os_strdup(pos);
Index: hostapd-2021-02-20-59e9794c/src/ap/ap_config.h
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/ap_config.h
+++ hostapd-2021-02-20-59e9794c/src/ap/ap_config.h
@@ -279,6 +279,7 @@ struct hostapd_bss_config {
char snoop_iface[IFNAMSIZ + 1];
char vlan_bridge[IFNAMSIZ + 1];
char wds_bridge[IFNAMSIZ + 1];
+ char *uci_section;
char *config_id;
Index: hostapd-2021-02-20-59e9794c/src/ap/ubus.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/ubus.c
+++ hostapd-2021-02-20-59e9794c/src/ap/ubus.c
@@ -467,6 +467,9 @@ hostapd_bss_get_status(struct ubus_conte
hapd->iface->cac_started ? hapd->iface->dfs_cac_ms / 1000 - now.sec : 0);
blobmsg_close_table(&b, dfs_table);
+ if (hapd->conf->uci_section)
+ blobmsg_add_string(&b, "uci_section", hapd->conf->uci_section);
+
ubus_send_reply(ctx, req, b.head);
return 0;
Index: hostapd-2021-02-20-59e9794c/src/ap/ap_config.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/ap_config.c
+++ hostapd-2021-02-20-59e9794c/src/ap/ap_config.c
@@ -785,6 +785,7 @@ void hostapd_config_free_bss(struct host
os_free(conf->radius_req_attr_sqlite);
os_free(conf->rsn_preauth_interfaces);
os_free(conf->ctrl_interface);
+ os_free(conf->uci_section);
os_free(conf->config_id);
os_free(conf->ca_cert);
os_free(conf->server_cert);

View File

@@ -0,0 +1,116 @@
From 2b9306b0b87758c9ec565f8c0dbbb55e5028b7ff Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Mon, 10 Oct 2022 11:14:57 +0200
Subject: [PATCH] hostapd: add uci_section to status
Signed-off-by: John Crispin <john@phrozen.org>
---
.../network/services/hostapd/files/hostapd.sh | 6 ++-
.../hostapd/patches/901-cfg-section.patch | 51 +++++++++++++++++++
package/network/services/uhttpd/Makefile | 1 +
3 files changed, 57 insertions(+), 1 deletion(-)
create mode 100644 package/network/services/hostapd/patches/901-cfg-section.patch
diff --git a/package/network/services/hostapd/files/hostapd.sh b/package/network/services/hostapd/files/hostapd.sh
index 3ac9e7b590..c308d1d2de 100644
--- a/package/network/services/hostapd/files/hostapd.sh
+++ b/package/network/services/hostapd/files/hostapd.sh
@@ -392,6 +392,8 @@ hostapd_common_add_bss_config() {
config_add_string fils_dhcp
config_add_boolean ratelimit
+
+ config_add_string uci_section
}
hostapd_set_vlan_file() {
@@ -627,7 +629,7 @@ hostapd_set_bss_options() {
airtime_bss_weight airtime_bss_limit airtime_sta_weight \
multicast_to_unicast_all proxy_arp per_sta_vif \
eap_server eap_user_file ca_cert server_cert private_key private_key_passwd server_id \
- vendor_elements fils
+ vendor_elements fils uci_section
set_default fils 0
set_default isolate 0
@@ -1152,6 +1154,8 @@ hostapd_set_bss_options() {
append bss_conf "per_sta_vif=$per_sta_vif" "$N"
fi
+ [ -n "$uci_section" ] && append bss_conf "uci_section=$uci_section" "$N"
+
json_get_values opts hostapd_bss_options
for val in $opts; do
append bss_conf "$val" "$N"
diff --git a/package/network/services/hostapd/patches/901-cfg-section.patch b/package/network/services/hostapd/patches/901-cfg-section.patch
new file mode 100644
index 0000000000..dcfdd658fe
--- /dev/null
+++ b/package/network/services/hostapd/patches/901-cfg-section.patch
@@ -0,0 +1,51 @@
+Index: hostapd-2021-02-20-59e9794c/hostapd/config_file.c
+===================================================================
+--- hostapd-2021-02-20-59e9794c.orig/hostapd/config_file.c
++++ hostapd-2021-02-20-59e9794c/hostapd/config_file.c
+@@ -2366,6 +2366,8 @@ static int hostapd_config_fill(struct ho
+ return 1;
+ }
+ conf->driver = driver;
++ } else if (os_strcmp(buf, "uci_section") == 0) {
++ bss->uci_section = os_strdup(pos);
+ } else if (os_strcmp(buf, "driver_params") == 0) {
+ os_free(conf->driver_params);
+ conf->driver_params = os_strdup(pos);
+Index: hostapd-2021-02-20-59e9794c/src/ap/ap_config.h
+===================================================================
+--- hostapd-2021-02-20-59e9794c.orig/src/ap/ap_config.h
++++ hostapd-2021-02-20-59e9794c/src/ap/ap_config.h
+@@ -279,6 +279,7 @@ struct hostapd_bss_config {
+ char snoop_iface[IFNAMSIZ + 1];
+ char vlan_bridge[IFNAMSIZ + 1];
+ char wds_bridge[IFNAMSIZ + 1];
++ char *uci_section;
+
+ char *config_id;
+
+Index: hostapd-2021-02-20-59e9794c/src/ap/ubus.c
+===================================================================
+--- hostapd-2021-02-20-59e9794c.orig/src/ap/ubus.c
++++ hostapd-2021-02-20-59e9794c/src/ap/ubus.c
+@@ -467,6 +467,9 @@ hostapd_bss_get_status(struct ubus_conte
+ hapd->iface->cac_started ? hapd->iface->dfs_cac_ms / 1000 - now.sec : 0);
+ blobmsg_close_table(&b, dfs_table);
+
++ if (hapd->conf->uci_section)
++ blobmsg_add_string(&b, "uci_section", hapd->conf->uci_section);
++
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+Index: hostapd-2021-02-20-59e9794c/src/ap/ap_config.c
+===================================================================
+--- hostapd-2021-02-20-59e9794c.orig/src/ap/ap_config.c
++++ hostapd-2021-02-20-59e9794c/src/ap/ap_config.c
+@@ -785,6 +785,7 @@ void hostapd_config_free_bss(struct host
+ os_free(conf->radius_req_attr_sqlite);
+ os_free(conf->rsn_preauth_interfaces);
+ os_free(conf->ctrl_interface);
++ os_free(conf->uci_section);
+ os_free(conf->config_id);
+ os_free(conf->ca_cert);
+ os_free(conf->server_cert);
diff --git a/package/network/services/uhttpd/Makefile b/package/network/services/uhttpd/Makefile
index 0ae076ca8b..a3fd2a84d9 100644
--- a/package/network/services/uhttpd/Makefile
+++ b/package/network/services/uhttpd/Makefile
@@ -12,6 +12,7 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/uhttpd.git
+PKG_MIRROR_HASH:=90f737663d8495b891f0364342efb06f548a82c26ddb1595e42752f7cecdccee
PKG_SOURCE_DATE:=2022-06-01
PKG_SOURCE_VERSION:=e3395cd90bed9b7b9fc319e79528fedcc0d947fe
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
--
2.25.1

View File

@@ -43,11 +43,14 @@ packages:
- ucentral-schema
- ucentral-wifi
- ucentral-tools
- usteer2
- ucrun
- ucode
- unetd
- udhcpsnoop
- udnssnoop
- usteer
- usteer2
- ustp
- libustream-openssl
- udevmand