[openwrt/openwrt] wifi-scripts: ucode: add MLO interface support

LEDE Commits lede-commits at lists.infradead.org
Sat Aug 2 08:44:57 PDT 2025


nbd pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/217c31542330ad47907fb153d3232a15833698b1

commit 217c31542330ad47907fb153d3232a15833698b1
Author: Felix Fietkau <nbd at nbd.name>
AuthorDate: Fri Jun 27 22:42:30 2025 +0200

    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 <nbd at nbd.name>
---
 .../files-ucode/lib/netifd/wireless/mac80211.sh    | 37 +++++++++++++++++++++-
 .../files-ucode/usr/share/ucode/wifi/ap.uc         |  6 ++++
 .../files-ucode/usr/share/ucode/wifi/hostapd.uc    |  2 +-
 .../wifi-scripts/files/lib/netifd/wireless.uc      |  8 +++--
 .../wifi-scripts/files/usr/share/hostap/common.uc  |  4 ++-
 5 files changed, 52 insertions(+), 5 deletions(-)

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();




More information about the lede-commits mailing list