mirror of
https://github.com/Telecominfraproject/ols-ucentral-schema.git
synced 2025-10-30 01:32:26 +00:00
286 lines
6.9 KiB
Ucode
286 lines
6.9 KiB
Ucode
let verbose = args?.verbose == null ? true : args.verbose;
|
|
let active = args?.active ? true : false;
|
|
let bandwidth = args?.bandwidth || 0;
|
|
let override_dfs = args?.override_dfs ? true : false;
|
|
let nl = require("nl80211");
|
|
let rtnl = require("rtnl");
|
|
let def = nl.const;
|
|
|
|
if (!ctx) {
|
|
ubus = require("ubus");
|
|
ctx = ubus.connect();
|
|
}
|
|
|
|
const SCAN_FLAG_AP = (1<<2);
|
|
const frequency_list_2g = [ 2412, 2417, 2422, 2427, 2432, 2437, 2442,
|
|
2447, 2452, 2457, 2462, 2467, 2472, 2484 ];
|
|
const frequency_list_5g = { '3': [ 5180, 5260, 5500, 5580, 5660, 5745 ],
|
|
'2': [ 5180, 5220, 5260, 5300, 5500, 5540,
|
|
5580, 5620, 5660, 5745, 5785, 5825,
|
|
5865, 5920, 5960 ],
|
|
'1': [ 5180, 5200, 5220, 5240, 5260, 5280,
|
|
5300, 5320, 5500, 5520, 5540, 5560,
|
|
5580, 5600, 5620, 5640, 5660, 5680,
|
|
5700, 5720, 5745, 5765, 5785, 5805,
|
|
5825, 5845, 5865, 5885 ],
|
|
};
|
|
const frequency_offset = { '80': 30, '40': 10 };
|
|
const frequency_width = { '80': 3, '40': 2, '20': 1 };
|
|
const IFTYPE_STATION = 2;
|
|
const IFTYPE_AP = 3;
|
|
const IFTYPE_MESH = 7;
|
|
const IFF_UP = 1;
|
|
|
|
function frequency_to_channel(freq) {
|
|
/* see 802.11-2007 17.3.8.3.2 and Annex J */
|
|
if (freq == 2484)
|
|
return 14;
|
|
else if (freq < 2484)
|
|
return (freq - 2407) / 5;
|
|
else if (freq >= 4910 && freq <= 4980)
|
|
return (freq - 4000) / 5;
|
|
else if (freq < 5935) /* DMG band lower limit */
|
|
return (freq - 5000) / 5;
|
|
else if (freq == 5935)
|
|
return 2;
|
|
else if (freq >= 5955 && freq <= 7115)
|
|
return ((freq - 5955) / 5) + 1;
|
|
else if (freq >= 58320 && freq <= 64800)
|
|
return (freq - 56160) / 2160;
|
|
return 0;
|
|
}
|
|
|
|
function iface_get(wdev) {
|
|
let params = { dev: wdev };
|
|
let res = nl.request(def.NL80211_CMD_GET_INTERFACE, wdev ? null : def.NLM_F_DUMP, wdev ? params : null);
|
|
|
|
if (res === false)
|
|
warn("Unable to lookup interface: " + nl.error() + "\n");
|
|
return res || [];
|
|
}
|
|
|
|
function iface_find(wiphy, types, ifaces) {
|
|
if (!ifaces)
|
|
ifaces = iface_get();
|
|
for (let iface in ifaces) {
|
|
if (iface.wiphy != wiphy)
|
|
continue;
|
|
if (iface.iftype in types)
|
|
return iface;
|
|
}
|
|
return;
|
|
}
|
|
|
|
function scan_trigger(wdev, frequency, width) {
|
|
let params = { dev: wdev, scan_flags: SCAN_FLAG_AP };
|
|
|
|
if (frequency && type(frequency) == 'array') {
|
|
params.scan_frequencies = frequency;
|
|
}
|
|
else if (frequency && width) {
|
|
params.wiphy_freq = frequency;
|
|
params.center_freq1 = frequency + frequency_offset[width];
|
|
params.channel_width = frequency_width[width];
|
|
}
|
|
|
|
if (active)
|
|
params.scan_ssids = [ '' ];
|
|
|
|
//printf("%.J\n", params);
|
|
let res = nl.request(def.NL80211_CMD_TRIGGER_SCAN, 0, params);
|
|
|
|
if (res === false)
|
|
die("Unable to trigger scan: " + nl.error() + "\n");
|
|
|
|
else
|
|
res = nl.waitfor([
|
|
def.NL80211_CMD_NEW_SCAN_RESULTS,
|
|
def.NL80211_CMD_SCAN_ABORTED
|
|
], (frequency && width) ? 500 : 5000);
|
|
|
|
if (!res)
|
|
warn("Netlink error while awaiting scan results: " + nl.error() + "\n");
|
|
|
|
else if (res.cmd == def.NL80211_CMD_SCAN_ABORTED)
|
|
warn("Scan aborted by kernel\n");
|
|
}
|
|
|
|
function trigger_scan_width(wdev, freqs, width) {
|
|
for (let freq in freqs)
|
|
scan_trigger(wdev, freq, width);
|
|
}
|
|
|
|
function phy_get(wdev) {
|
|
let res = nl.request(def.NL80211_CMD_GET_WIPHY, def.NLM_F_DUMP, { split_wiphy_dump: true });
|
|
|
|
if (res === false)
|
|
warn("Unable to lookup phys: " + nl.error() + "\n");
|
|
|
|
return res;
|
|
}
|
|
|
|
function phy_get_frequencies(phy) {
|
|
let freqs = [];
|
|
|
|
for (let band in phy.wiphy_bands) {
|
|
for (let freq in band?.freqs || [])
|
|
if (!freq.disabled)
|
|
push(freqs, freq.freq);
|
|
}
|
|
return freqs;
|
|
}
|
|
|
|
function phy_frequency_dfs(phy, curr) {
|
|
let freqs = [];
|
|
|
|
for (let band in phy.wiphy_bands) {
|
|
for (let freq in band?.freqs || [])
|
|
if (freq.freq == curr && freq.dfs_state >= 0)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
let phys = phy_get();
|
|
let ifaces = iface_get();
|
|
|
|
function intersect(list, filter) {
|
|
let res = [];
|
|
|
|
for (let item in list)
|
|
if (index(filter, item) >= 0)
|
|
push(res, item);
|
|
return res;
|
|
}
|
|
|
|
function wifi_scan() {
|
|
let scan = [];
|
|
|
|
for (let phy in phys) {
|
|
let iface = iface_find(phy.wiphy, [ IFTYPE_STATION, IFTYPE_AP ], ifaces);
|
|
let scan_iface = false;
|
|
if (!iface) {
|
|
warn('no valid interface found for phy' + phy.wiphy + '\n');
|
|
nl.request(def.NL80211_CMD_NEW_INTERFACE, 0, { wiphy: phy.wiphy, ifname: 'scan', iftype: IFTYPE_STATION });
|
|
nl.waitfor([ def.NL80211_CMD_NEW_INTERFACE ], 1000);
|
|
scan_iface = true;
|
|
iface = {
|
|
dev: 'scan',
|
|
channel_width: 1,
|
|
};
|
|
rtnl.request(rtnl.const.RTM_NEWLINK, 0, { dev: 'scan', flags: IFF_UP, change: 1});
|
|
sleep(1000);
|
|
}
|
|
|
|
printf("scanning on phy%d\n", phy.wiphy);
|
|
|
|
let freqs = phy_get_frequencies(phy);
|
|
if (length(intersect(freqs, frequency_list_2g)))
|
|
scan_trigger(iface.dev, frequency_list_2g);
|
|
|
|
let ch_width = iface.channel_width;
|
|
if (frequency_width[bandwith])
|
|
ch_width = frequency_width[bandwith];
|
|
let freqs_5g = intersect(freqs, frequency_list_5g[ch_width]);
|
|
if (length(freqs_5g)) {
|
|
if (override_dfs && !scan_iface && phy_frequency_dfs(phy, iface.wiphy_freq)) {
|
|
ctx.call(sprintf('hostapd.%s', iface.dev), 'switch_chan', { freq: 5180, bcn_count: 10 });
|
|
sleep(2000)
|
|
}
|
|
trigger_scan_width(iface.dev, freqs_5g, ch_width);
|
|
}
|
|
let res = nl.request(def.NL80211_CMD_GET_SCAN, def.NLM_F_DUMP, { dev: iface.dev });
|
|
for (let bss in res) {
|
|
bss = bss.bss;
|
|
let res = {
|
|
bssid: bss.bssid,
|
|
frequency: +bss.frequency,
|
|
channel: frequency_to_channel(+bss.frequency),
|
|
signal: +bss.signal_mbm / 100,
|
|
};
|
|
if (verbose) {
|
|
res.tsf = +bss.tsf;
|
|
res.last_seen = +bss.seen_ms_ago;
|
|
res.capability = +bss.capability;
|
|
res.ies = [];
|
|
}
|
|
|
|
|
|
for (let ie in bss.beacon_ies) {
|
|
switch (ie.type) {
|
|
case 0:
|
|
res.ssid = ie.data;
|
|
break;
|
|
case 114:
|
|
if (verbose)
|
|
res.meshid = ie.data;
|
|
break;
|
|
case 0x3d:
|
|
if (verbose)
|
|
res.ht_oper = b64enc(ie.data);
|
|
break;
|
|
case 0xc0:
|
|
if (verbose)
|
|
res.vht_oper = b64enc(ie.data);
|
|
break;
|
|
case 0xdd:
|
|
let oui = hexenc(substr(ie.data, 0, 3));
|
|
let type = ord(ie.data, 3);
|
|
let data = substr(ie.data, 4);
|
|
switch (oui) {
|
|
case '48d017':
|
|
res.tip_oui = true;
|
|
switch(type) {
|
|
case 1:
|
|
if (data)
|
|
res.tip_name = data;
|
|
break;
|
|
case 2:
|
|
if (data)
|
|
res.tip_serial = data;
|
|
break;
|
|
case 3:
|
|
if (data)
|
|
res.tip_network_id = data;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
if (verbose)
|
|
push(res.ies, { type: ie.type, data: b64enc(ie.data) });
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (args.periodic && !args.information_elements)
|
|
delete res.ies;
|
|
push(scan, res);
|
|
}
|
|
if (scan_iface) {
|
|
warn('removing temporary interface\n');
|
|
nl.request(def.NL80211_CMD_DEL_INTERFACE, 0, { dev: 'scan' });
|
|
}
|
|
}
|
|
printf("%.J\n", scan);
|
|
return scan;
|
|
}
|
|
|
|
let scan = wifi_scan();
|
|
|
|
if (args.periodic) {
|
|
ctx.call('ucentral', 'send', {
|
|
method: 'wifiscan',
|
|
params: { data: scan }
|
|
});
|
|
return;
|
|
}
|
|
|
|
result_json({
|
|
error: 0,
|
|
text: "Success",
|
|
resultCode: 1,
|
|
scan,
|
|
});
|