rrmd: Update scanning for WiFi 7 devices

Update scan module to support WiFi 7 devices
which have virtual phys defined. Scanning on
the different virtual phys but on the same physical
phy isn't allowed.
Add NL CBs to notify about scanning progress.

Signed-off-by: Marek Kwaczynski <marek@shasta.cloud>
This commit is contained in:
Marek Kwaczynski
2025-03-08 23:56:18 +01:00
committed by John Crispin
parent b791a723ca
commit 52f2e31892
2 changed files with 141 additions and 9 deletions

View File

@@ -32,6 +32,17 @@ function channel_to_freq(cur_freq, channel) {
return null;
}
function freq2band(freq) {
if (freq < 2500) {
return "2G";
} else if (freq <= 5885) {
return "5G";
} else if (freq < 7115){
return "6G";
}
return "na"
}
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 });
@@ -151,6 +162,8 @@ function interfaces_subunsub(path, sub) {
interfaces[name][prop] = status[prop];
interfaces[name].config = cfg;
interfaces[name].phy = status.phy;
interfaces[name].virtual_phys = length(split(status.phy, ".")) > 1 ? true : false;
interfaces[name].band = freq2band(status?.freq);
/* ask hostapd for the local neighbourhood report data */
let rrm = global.ubus.conn.call(path, 'rrm_nr_get_own');

View File

@@ -1,7 +1,13 @@
const SCAN_FLAG_AP = (1<<2);
const PHY_SCAN_STATE_READY = 0;
const PHY_SCAN_STATE_TRIGGERED = 1;
const PHY_SCAN_STATE_STARTED = 2;
const PHY_SCAN_STATE_COMPLETED = 3;
const PHY_SCAN_STATE_BLOCKED = 4;
let phys = {};
let beacons = {};
let scan_blocked_cnt = 0;
function scan(phy, params) {
if (params.wiphy_freq) {
@@ -17,7 +23,7 @@ function scan(phy, params) {
printf("Unable to trigger scan: " + global.nl80211.error() + "\n");
else
printf('triggered scan on %s\n', params?.dev);
phys[phy].pending = true;
phys[phy].state = PHY_SCAN_STATE_TRIGGERED;
phys[phy].last = time();
}
@@ -70,21 +76,56 @@ function scan_parse(data) {
printf('%.J\n', beacons);
}
function get_scan_res(dev) {
let res = global.nl80211.request(global.nl80211.const.NL80211_CMD_GET_SCAN, global.nl80211.const.NLM_F_DUMP, { dev });
if (!res || res == false) {
ulog_err("Unable to get scan results: " + global.nl80211.error() + "\n");
return;
}
scan_parse(res);
}
function scan_timer() {
try {
let scan_trigger = false;
let cur_blocked = 0;
let last_blocked = 0;
for (let k, v in phys) {
if (v.pending && time() - v.last >= v.delay) {
let scan_pending = (v.state == PHY_SCAN_STATE_TRIGGERED || v.state == PHY_SCAN_STATE_STARTED) ? true : false;
/* It should not happen, get_scan is handled by NL CB */
if (scan_pending && time() - v.last >= v.delay) {
ulog_warn("Scanning process too long, phy state: %s\n", phys[k]);
let dev = global.local.lookup(k);
if (dev) {
let res = global.nl80211.request(global.nl80211.const.NL80211_CMD_GET_SCAN, global.nl80211.const.NLM_F_DUMP, { dev });
scan_parse(res);
}
v.pending = false;
v.state = PHY_SCAN_STATE_READY;
scan_pending = false;
v.last = time();
v.delay = 1;
}
if (!v.pending && time() - v.last >= global.config.scan_interval) {
if (!v?.channels || !v?.num_chan)
continue;
/* Running scanning parallel on virtual phys not allowed */
if (v?.virtual_phys) {
if (v?.state == PHY_SCAN_STATE_BLOCKED)
last_blocked++;
else if (scan_blocked_cnt > 0)
continue;
if (scan_trigger) {
v.state = PHY_SCAN_STATE_BLOCKED;
cur_blocked++;
continue;
} else if (v.state == PHY_SCAN_STATE_BLOCKED) {
v.state = PHY_SCAN_STATE_READY;
}
}
if (!scan_pending && time() - v.last >= global.config.scan_interval) {
let dev = global.local.lookup(k);
scan(k, {
dev,
@@ -92,8 +133,17 @@ function scan_timer() {
measurement_duration: global.config.scan_dwell_time,
});
v.state = PHY_SCAN_STATE_TRIGGERED;
scan_trigger = true;
v.curr_chan = (v.curr_chan + 1) % v.num_chan;
}
/* Shouldn't never happen */
if (scan_blocked_cnt > 0 && scan_blocked_cnt != last_blocked) {
log_warn("Mismatch in blocked phys config: %s -> %s\n", phys.blocked, last_blocked);
scan_blocked_cnt = 0;
} else {
scan_blocked_cnt = cur_blocked;
}
}
@@ -103,17 +153,79 @@ function scan_timer() {
// return 1000;
}
function get_phy_from_msg(msg) {
if (!msg?.msg)
return;
let phy = "phy" + msg.msg.wiphy;
let dev = msg.msg?.dev;
if (!dev)
dev = global.local.lookup(phy);
if (!dev)
return null;
if (global.local.interfaces[dev]?.virtual_phys)
phy = global.local.interfaces[dev].phy;
if (!phy)
return null;
return phy;
}
function nl_handle_scan_msg(msg) {
let phy = get_phy_from_msg(msg);
if (!phy)
return;
phys[phy].last = time();
phys[phy].state = PHY_SCAN_STATE_COMPLETED;
//get_scan_res(msg.msg?.dev);
}
function nl_scan_res_cb(msg) {
nl_handle_scan_msg(msg);
}
function nl_scan_abort_cb(msg) {
nl_handle_scan_msg(msg);
}
function nl_scan_start_cb(msg) {
let phy = get_phy_from_msg(msg);
if (!phy)
return;
if (!phys[phy])
return;
if (phys[phy].state != PHY_SCAN_STATE_TRIGGERED) {
ulog_warn("Skip scan results not started by scan module: %s\n", msg);
return;
}
phys[phy].state = PHY_SCAN_STATE_STARTED;
}
return {
beacons,
add_wdev: function(dev, phy) {
if (phys[phy])
return;
let p = split(phy, '.');
let virtual_phys = length(p) > 1 ? true : false;
let bands = global.phy.phys[phy]?.band;
if (!bands)
bands = [ global.local.interfaces[dev].band ];
if (!bands)
return;
let channels;
let offset = 0;
if (!global.phy.phys[phy])
return;
switch (global.phy.phys[phy].band[0]) {
switch (bands[0]) {
case '2G':
channels = global.config.channels_2g;
break;
@@ -132,8 +244,12 @@ return {
channels,
offset,
num_chan,
bands,
curr_chan: 0,
delay: 5,
virtual_phys,
delay: 25,
state: PHY_SCAN_STATE_READY,
parent_phy: p[0],
};
},
@@ -143,5 +259,8 @@ return {
init: function() {
uloop_timeout(scan_timer, 5000);
nl80211.listener(nl_scan_start_cb, [ nl80211.const.NL80211_CMD_TRIGGER_SCAN ]);
nl80211.listener(nl_scan_res_cb, [ nl80211.const.NL80211_CMD_NEW_SCAN_RESULTS ]);
nl80211.listener(nl_scan_abort_cb, [ nl80211.const.NL80211_CMD_SCAN_ABORTED ]);
},
};