wireless: add MLO support to example scripts
authorFelix Fietkau <nbd@nbd.name>
Tue, 17 Jun 2025 09:16:17 +0000 (11:16 +0200)
committerFelix Fietkau <nbd@nbd.name>
Sat, 2 Aug 2025 14:44:19 +0000 (16:44 +0200)
Signed-off-by: Felix Fietkau <nbd@nbd.name>
examples/wireless-device.uc
examples/wireless.uc
examples/wireless/mac80211.sh

index f6db09c9002cf3a8c94c96f6c2f9db0b63405eec..b0faef1a0a6fd493589a7c50417b989ff65634fe 100644 (file)
@@ -12,6 +12,9 @@ const NOTIFY_CMD_SET_RETRY = 4;
 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;
@@ -59,6 +62,23 @@ function handle_link(dev, data, up)
                });
 }
 
+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;
@@ -177,6 +197,9 @@ function handler_sort_fn(a, b)
 
 function __run_next_handler_name()
 {
+       if (wdev_handler[mlo_name])
+               return mlo_name;
+
        return sort(keys(wdev_handler), handler_sort_fn)[0];
 }
 
@@ -194,6 +217,8 @@ function __run_next_handler()
        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),
@@ -409,6 +434,9 @@ function wdev_mark_up(wdev)
        if (wdev.state != "setup")
                return;
 
+       if (wdev.name == mlo_name)
+               mlo_wdev = wdev;
+
        if (wdev.config_change) {
                wdev.setup();
                return;
index d75aaca65490158089d72d163c7d0d659bb25ee5..b63ec239c71c888ffaaa016d412fb74879700266 100644 (file)
@@ -45,6 +45,7 @@ function config_init(uci)
        let handlers = {};
        let devices = {};
        let vifs = {};
+       let mlo_device;
 
        let sections = {
                device: {},
@@ -52,6 +53,7 @@ function config_init(uci)
                vlan: {},
                station: {},
        };
+       let radio_idx = {};
 
        for (let name, data in config) {
                let type = data[".type"];
@@ -64,6 +66,20 @@ function config_init(uci)
                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) {
@@ -74,6 +90,9 @@ function config_init(uci)
                if (!handler)
                        continue;
 
+               if (data.radio != null)
+                       radio_idx[name] = +data.radio;
+
                let config = parse_attribute_list(data, handler.device);
                devices[name] = {
                        name,
@@ -86,6 +105,12 @@ function config_init(uci)
 
        for (let name, data in sections.iface) {
                let dev_names = parse_array(data.device);
+               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) {
                        let dev = devices[dev_name];
                        if (!dev)
@@ -96,6 +121,12 @@ function config_init(uci)
                                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;
 
                        let vif = {
                                name, config,
@@ -266,8 +297,11 @@ function wdev_call(req, cb)
                return cb(dev);
        }
 
-       for (let name, dev in wireless.devices)
+       for (let name, dev in wireless.devices) {
+               if (name == wdev.mlo_name)
+                       continue;
                cb(dev);
+       }
 
        return 0;
 }
@@ -308,6 +342,10 @@ const ubus_obj = {
        up: {
                args: wdev_args,
                call: function(req) {
+                       let mlo_dev = wireless.devices[wdev.mlo_name];
+                       if (mlo_dev)
+                               mlo_dev.start();
+
                        return wdev_call(req, (dev) => {
                                dev.start();
                                return 0;
@@ -317,6 +355,10 @@ const ubus_obj = {
        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;
@@ -326,6 +368,10 @@ const ubus_obj = {
        reconf: {
                args: wdev_args,
                call: function(req) {
+                       let mlo_dev = wireless.devices[wdev.mlo_name];
+                       if (mlo_dev)
+                               mlo_dev.update();
+
                        return wdev_call(req, (dev) => {
                                dev.update();
                                return 0;
index 28e16f761c475ee3b6d40a830dc16b8ea1125296..8389afae2f95ddcbad4ea9fdb064f0ebbc3008e4 100755 (executable)
@@ -287,6 +287,17 @@ setup_vif() {
        vifidx=$((vifidx + 1))
 }
 
+setup_link() {
+       local name="$1"
+
+       json_select config
+       json_get_vars ifname
+       json_select ..
+
+       echo "Add link on $radio: $ifname"
+}
+
+
 drv_mac80211_cleanup() {
        echo "mac80211 cleanup"
 }
@@ -296,6 +307,7 @@ drv_mac80211_setup() {
        radio=$1
        vifidx=0
        json_dump
+       for_each_interface "link" setup_link
        for_each_interface "sta ap adhoc" setup_vif
        wireless_set_data phy=phy0
        wireless_set_up