From: Felix Fietkau Date: Fri, 27 Jun 2025 20:42:30 +0000 (+0200) Subject: wifi-scripts: ucode: add MLO interface support X-Git-Url: http://git.openwrt.org/?a=commitdiff_plain;h=217c31542330ad47907fb153d3232a15833698b1;p=openwrt%2Fopenwrt.git wifi-scripts: ucode: add MLO interface support MLO can be enabled by configuring a wifi-iface section with multiple radios, like this: config wifi-iface list radio 'radio0' list radio 'radio1' option mlo '1' option ssid 'OpenWrt' option mode 'ap' option network 'lan' ... Signed-off-by: Felix Fietkau --- diff --git a/package/network/config/wifi-scripts/files-ucode/lib/netifd/wireless/mac80211.sh b/package/network/config/wifi-scripts/files-ucode/lib/netifd/wireless/mac80211.sh index 249c7a4596..8ef2dd9b2b 100755 --- a/package/network/config/wifi-scripts/files-ucode/lib/netifd/wireless/mac80211.sh +++ b/package/network/config/wifi-scripts/files-ucode/lib/netifd/wireless/mac80211.sh @@ -157,9 +157,39 @@ function config_add_mesh_params(config, data) { 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'); @@ -200,6 +230,7 @@ function setup() { } switch (mode) { + case 'link': case 'ap': has_ap = true; // fallthrough @@ -210,7 +241,8 @@ function setup() { 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); - netifd.set_vif(k, v.config.ifname); + if (mode != "link") + netifd.set_vif(k, v.config.ifname); break; } @@ -277,6 +309,9 @@ function setup() { function teardown() { let data = json(ARGV[3]); + if (ARGV[2] == "#mlo") + return 0; + if (!data.data?.phy) { log('Bug: PHY is undefined for device'); return 1; diff --git a/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/ap.uc b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/ap.uc index 47049f30bb..62e3ec0afb 100644 --- a/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/ap.uc +++ b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/ap.uc @@ -488,6 +488,12 @@ export function generate(interface, data, config, vlans, stas, phy_features) { for (let raw in config.hostapd_options) append_raw(raw); + if (config.mode == 'link') { + append_raw('mld_ap=1'); + if (data.config.radio != null) + append_raw('mld_link_id=' + data.config.radio); + } + if (config.default_macaddr) append_raw('#default_macaddr'); }; diff --git a/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/hostapd.uc b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/hostapd.uc index cc174cda50..a31b2955eb 100644 --- a/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/hostapd.uc +++ b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/hostapd.uc @@ -548,7 +548,7 @@ export function setup(data) { append('\n#macaddr_base', data.config.macaddr_base); for (let k, interface in data.interfaces) { - if (interface.config.mode != 'ap') + if (interface.config.mode != 'ap' && interface.config.mode != 'link') continue; interface.config.network_bridge = interface.bridge; diff --git a/package/network/config/wifi-scripts/files/lib/netifd/wireless.uc b/package/network/config/wifi-scripts/files/lib/netifd/wireless.uc index de67bd5d94..b63ec239c7 100644 --- a/package/network/config/wifi-scripts/files/lib/netifd/wireless.uc +++ b/package/network/config/wifi-scripts/files/lib/netifd/wireless.uc @@ -108,6 +108,7 @@ function config_init(uci) let mlo_vif = parse_bool(data.mlo); 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 ]; for (let dev_name in dev_names) { @@ -120,8 +121,11 @@ function config_init(uci) continue; let config = parse_attribute_list(data, handler.iface); - if (mlo_vif && dev_name != wdev.mlo_name) - config.mode = "link"; + if (mlo_vif) + if (dev_name == wdev.mlo_name) + config.radio_config = radio_config; + else + config.mode = "link"; config.radios = radios; let vif = { diff --git a/package/network/config/wifi-scripts/files/usr/share/hostap/common.uc b/package/network/config/wifi-scripts/files/usr/share/hostap/common.uc index caab14bcab..f801c4940c 100644 --- a/package/network/config/wifi-scripts/files/usr/share/hostap/common.uc +++ b/package/network/config/wifi-scripts/files/usr/share/hostap/common.uc @@ -101,7 +101,9 @@ function wdev_create(phy, name, data) req["4addr"] = data["4addr"]; if (data.macaddr) req.mac = data.macaddr; - if (data.radio != null && data.radio >= 0) + if (data.radio_mask > 0) + req.vif_radio_mask = data.radio_mask; + else if (data.radio != null && data.radio >= 0) req.vif_radio_mask = 1 << data.radio; nl80211.error();