config_add(config, param, data[param]);
}
-function setup_mlo(data) {
- let config = {};
- let idx = 0;
-
- for (let k, v in data.interfaces) {
- let ifname = v.config.ifname;
- if (!ifname)
- ifname = 'ap-mld' + idx++;
-
- delete v.config.ifname;
- config[ifname] = v.config;
- netifd.set_vif(k, ifname);
-
- v.config.phy = find_phy(v.config.radio_config[0], true);
- delete v.config.radio_config;
- }
-
- let ret = ubus.call('hostapd', 'mld_set', { config });
- if (type(ret) != "object")
- return netifd.setup_failed('HOSTAPD_START_FAILED');
-
- netifd.add_process('/usr/sbin/hostapd', ret.pid, true, true);
- netifd.set_up();
-
- return 0;
-}
-
function setup() {
let data = json(ARGV[3]);
- if (ARGV[2] == "#mlo")
- return setup_mlo(data);
-
data.phy = find_phy(data.config, true);
if (!data.phy) {
log('Bug: PHY is undefined for device');
}
switch (mode) {
- case 'link':
case 'ap':
has_ap = true;
for (let _, sta in v.stas)
data.config.noscan = true;
validate('iface', v.config);
iface.prepare(v.config, data.phy + data.phy_suffix, data.config.num_global_macaddr, data.config.macaddr_base);
- if (mode != "link")
- netifd.set_vif(k, v.config.ifname);
+ netifd.set_vif(k, v.config.ifname);
break;
}
const DEFAULT_RETRY = 3;
const DEFAULT_SCRIPT_TIMEOUT = 30 * 1000;
-export const mlo_name = "#mlo";
-
-let mlo_wdev;
let wdev_cur;
let wdev_handler = {};
let wdev_script_task, wdev_script_timeout;
});
}
-function wdev_mlo_fixup(config)
-{
- if (!mlo_wdev)
- return;
-
- for (let name, iface in config.interfaces) {
- let config = iface.config;
-
- if (config.mode != "link")
- continue;
-
- let mlo_config = mlo_wdev.handler_data[iface.name];
- if (mlo_config && mlo_config.ifname)
- config.ifname = mlo_config.ifname;
- }
-}
-
function wdev_config_init(wdev)
{
let data = wdev.data;
function __run_next_handler_name()
{
- if (wdev_handler[mlo_name])
- return mlo_name;
-
return sort(keys(wdev_handler), handler_sort_fn)[0];
}
let cb = wdev_cur.cb;
wdev.dbg("run " + op);
- if (name != mlo_name)
- wdev_mlo_fixup(wdev.handler_config);
wdev.handler_config.data = wdev.handler_data[wdev.name] ?? {};
wdev_script_task = netifd.process({
cb: () => run_handler_cb(wdev, cb),
if (wdev.state != "setup")
return;
- if (wdev.name == mlo_name)
- mlo_wdev = wdev;
-
if (wdev.config_change) {
wdev.setup();
return;
parse_attribute_list, parse_bool, parse_array,
TYPE_ARRAY, TYPE_STRING, TYPE_INT, TYPE_BOOL
} from "./utils.uc";
+import { find_phy } from "wifi.utils";
import * as wdev from "./wireless-device.uc";
let wireless = netifd.wireless = {
handlers: {},
devices: {},
+ mlo: {},
path: realpath(netifd.main_path + "/wireless"),
};
-function update_config(new_devices)
+function hostapd_update_mlo()
{
+ let config = {};
+
+ for (let ifname, data in wireless.mlo) {
+ if (data.mode != "ap")
+ continue;
+
+ data.phy = find_phy(data.radio_config[0], true);
+ if (!data.phy)
+ continue;
+
+ config[ifname] = data;
+ }
+
+ ubus.call({
+ object: "hostapd",
+ method: "mld_set",
+ return: "ignore",
+ data: { config },
+ });
+}
+
+function update_config(new_devices, mlo_vifs)
+{
+ wireless.mlo = mlo_vifs;
+ hostapd_update_mlo();
+
for (let name, dev in wireless.devices)
if (!new_devices[name])
dev.destroy();
let handlers = {};
let devices = {};
let vifs = {};
- let mlo_device;
+ let mlo_vifs = {};
let sections = {
device: {},
station: {},
};
let radio_idx = {};
+ let vif_idx = {};
for (let name, data in config) {
let type = data[".type"];
let list = sections[substr(type, 5)];
if (list)
list[name] = data;
-
- if (type == "wifi-iface" && parse_bool(data.mlo))
- mlo_device = true;
- }
-
- if (mlo_device) {
- devices[wdev.mlo_name] = {
- name: wdev.mlo_name,
- config: {
- type: "mac80211",
- },
- vif: [],
- };
- handlers[wdev.mlo_name] = wireless.handlers.mac80211;
}
for (let name, data in sections.device) {
let radios = map(dev_names, (v) => radio_idx[v]);
radios = filter(radios, (v) => v != null);
let radio_config = map(dev_names, (v) => devices[v].config);
- if (mlo_vif)
- dev_names = [ wdev.mlo_name, ...dev_names ];
+ let ifname;
+
for (let dev_name in dev_names) {
let dev = devices[dev_name];
if (!dev)
continue;
let config = parse_attribute_list(data, handler.iface);
- if (mlo_vif)
- if (dev_name == wdev.mlo_name)
- config.radio_config = radio_config;
- else
- config.mode = "link";
config.radios = radios;
+ if (mlo_vif && dev_name == dev_names[0]) {
+ let mlo_config = { ...config };
+
+ mlo_config.radio_config = radio_config;
+ ifname = config.ifname;
+ if (!ifname) {
+ let idx = vif_idx[config.mode] ?? 0;
+ vif_idx[config.mode] = idx + 1;
+ ifname = config.mode + "-mld" + idx;
+ }
+
+ mlo_vifs[ifname] = mlo_config;
+ }
+
+ if (ifname)
+ config.ifname = ifname;
if (dev_name != dev_names[0])
delete config.macaddr;
- if (dev_name != wdev.mlo_name && config.radio_macaddr) {
+ if (config.radio_macaddr) {
let idx = index(dev_names, dev_name);
- if (mlo_vif)
- idx--;
let macaddr = idx >= 0 ? config.radio_macaddr[idx] : null;
if (macaddr)
config.macaddr = macaddr;
}
}
- update_config(devices);
+ update_config(devices, mlo_vifs);
}
function config_start()
return cb(dev);
}
- for (let name, dev in wireless.devices) {
- if (name == wdev.mlo_name)
- continue;
+ for (let name, dev in wireless.devices)
cb(dev);
- }
return 0;
}
up: {
args: wdev_args,
call: function(req) {
- let mlo_dev = wireless.devices[wdev.mlo_name];
- if (mlo_dev)
- mlo_dev.start();
+ hostapd_update_mlo();
return wdev_call(req, (dev) => {
dev.start();
down: {
args: wdev_args,
call: function(req) {
- let mlo_dev = wireless.devices[wdev.mlo_name];
- if (mlo_dev)
- mlo_dev.config_change = true;
-
return wdev_call(req, (dev) => {
dev.stop();
return 0;
reconf: {
args: wdev_args,
call: function(req) {
- let mlo_dev = wireless.devices[wdev.mlo_name];
- if (mlo_dev)
- mlo_dev.update();
+ hostapd_update_mlo();
return wdev_call(req, (dev) => {
dev.update();
});
wireless.obj = ubus.publish("network.wireless", ubus_obj);
+wireless.listener = ubus.listener("ubus.object.add", (event, msg) => {
+ if (msg.path == "hostapd")
+ hostapd_update_mlo();
+});
return {
hotplug,