hostapd: move mac address allocation from mac80211.sh to wdev.uc
authorFelix Fietkau <nbd@nbd.name>
Wed, 6 Sep 2023 14:58:09 +0000 (16:58 +0200)
committerFelix Fietkau <nbd@nbd.name>
Wed, 13 Sep 2023 10:37:44 +0000 (12:37 +0200)
Preparation for upcoming hostapd reload improvements

Signed-off-by: Felix Fietkau <nbd@nbd.name>
package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
package/network/services/hostapd/files/common.uc
package/network/services/hostapd/files/wdev.uc

index 3b88af46795970633acd14c1434c1c3e44380183..1d7f733cadfbfebf95d66b04b1e50207d7395abd 100644 (file)
@@ -533,47 +533,7 @@ mac80211_generate_mac() {
        local phy="$1"
        local id="${macidx:-0}"
 
-       local ref="$(cat /sys/class/ieee80211/${phy}/macaddress)"
-       local mask="$(cat /sys/class/ieee80211/${phy}/address_mask)"
-
-       [ "$mask" = "00:00:00:00:00:00" ] && {
-               mask="ff:ff:ff:ff:ff:ff";
-
-               [ "$(wc -l < /sys/class/ieee80211/${phy}/addresses)" -gt $id ] && {
-                       addr="$(mac80211_get_addr "$phy" "$id")"
-                       [ -n "$addr" ] && {
-                               echo "$addr"
-                               return
-                       }
-               }
-       }
-
-       local oIFS="$IFS"; IFS=":"; set -- $mask; IFS="$oIFS"
-
-       local mask1=$1
-       local mask6=$6
-
-       local oIFS="$IFS"; IFS=":"; set -- $ref; IFS="$oIFS"
-
-       macidx=$(($id + 1))
-       [ "$((0x$mask1))" -gt 0 ] && {
-               b1="0x$1"
-               [ "$id" -gt 0 ] && \
-                       b1=$(($b1 ^ ((($id - !($b1 & 2)) << 2)) | 0x2))
-               printf "%02x:%s:%s:%s:%s:%s" $b1 $2 $3 $4 $5 $6
-               return
-       }
-
-       [ "$((0x$mask6))" -lt 255 ] && {
-               printf "%s:%s:%s:%s:%s:%02x" $1 $2 $3 $4 $5 $(( 0x$6 ^ $id ))
-               return
-       }
-
-       off2=$(( (0x$6 + $id) / 0x100 ))
-       printf "%s:%s:%s:%s:%02x:%02x" \
-               $1 $2 $3 $4 \
-               $(( (0x$5 + $off2) % 0x100 )) \
-               $(( (0x$6 + $id) % 0x100 ))
+       wdev_tool "$phy" get_macaddr id=$id
 }
 
 get_board_phy_name() (
@@ -1070,7 +1030,7 @@ mac80211_reset_config() {
        hostapd_conf_file="/var/run/hostapd-$phy.conf"
        ubus call hostapd config_set '{ "phy": "'"$phy"'", "config": "", "prev_config": "'"$hostapd_conf_file"'" }' > /dev/null
        ubus call wpa_supplicant config_set '{ "phy": "'"$phy"'", "config": [] }' > /dev/null
-       wdev_tool "$phy" '{}'
+       wdev_tool "$phy" set_config '{}'
 }
 
 drv_mac80211_setup() {
@@ -1174,7 +1134,7 @@ drv_mac80211_setup() {
        [ -x /usr/sbin/wpa_supplicant ] && wpa_supplicant_start "$phy"
 
        json_set_namespace wdev_uc prev
-       wdev_tool "$phy" "$(json_dump)" $active_ifnames
+       wdev_tool "$phy" set_config "$(json_dump)" $active_ifnames
        json_set_namespace "$prev"
 
        for_each_interface "ap sta adhoc mesh monitor" mac80211_set_vif_txpower
index 74c07855c958487cee27956ff8f6191e095781fa..f37804c8c6ec5678dbc8d50a3a572cd0999ed79e 100644 (file)
@@ -94,6 +94,88 @@ function wdev_create(phy, name, data)
        return null;
 }
 
+function phy_sysfs_file(phy, name)
+{
+       return trim(readfile(`/sys/class/ieee80211/${phy}/${name}`));
+}
+
+function macaddr_split(str)
+{
+       return map(split(str, ":"), (val) => hex(val));
+}
+
+function macaddr_join(addr)
+{
+       return join(":", map(addr, (val) => sprintf("%02x", val)));
+}
+
+function wdev_generate_macaddr(phy, data)
+{
+       let idx = int(data.id ?? 0);
+       let mbssid = int(data.mbssid ?? 0) > 0;
+       let num_global = int(data.num_global ?? 1);
+       let use_global = !mbssid && idx < num_global;
+
+       let base_addr = phy_sysfs_file(phy, "macaddress");
+       if (!base_addr)
+               return null;
+
+       if (!idx && !mbssid)
+               return base_addr;
+
+       let base_mask = phy_sysfs_file(phy, "address_mask");
+       if (!base_mask)
+               return null;
+
+       if (base_mask == "00:00:00:00:00:00" && idx >= num_global) {
+               let addrs = split(phy_sysfs_file(phy, "addresses"), "\n");
+
+               if (idx < length(addrs))
+                       return addrs[idx];
+
+               base_mask = "ff:ff:ff:ff:ff:ff";
+       }
+
+       let addr = macaddr_split(base_addr);
+       let mask = macaddr_split(base_mask);
+       let type;
+
+       if (mbssid)
+               type = "b5";
+       else if (use_global)
+               type = "add";
+       else if (mask[0] > 0)
+               type = "b1";
+       else if (mask[5] < 0xff)
+               type = "b5";
+       else
+               type = "add";
+
+       switch (type) {
+       case "b1":
+               if (!(addr[0] & 2))
+                       idx--;
+               addr[0] |= 2;
+               addr[0] ^= idx << 2;
+               break;
+       case "b5":
+               if (mbssid)
+                       addr[0] |= 2;
+               addr[5] ^= idx;
+               break;
+       default:
+               for (let i = 5; i > 0; i--) {
+                       addr[i] += idx;
+                       if (addr[i] < 256)
+                               break;
+                       addr[i] %= 256;
+               }
+               break;
+       }
+
+       return macaddr_join(addr);
+}
+
 const vlist_proto = {
        update: function(values, arg) {
                let data = this.data;
@@ -165,4 +247,4 @@ function vlist_new(cb) {
                }, vlist_proto);
 }
 
-export { wdev_remove, wdev_create, is_equal, vlist_new, phy_is_fullmac };
+export { wdev_remove, wdev_create, wdev_generate_macaddr, is_equal, vlist_new, phy_is_fullmac };
index 78037a9d27131b58a41422b86c6f4b01e9536a6c..8db245cdb7330bed2f5a5052bc836d8b49a1a0cd 100644 (file)
@@ -1,11 +1,11 @@
 #!/usr/bin/env ucode
 'use strict';
-import { vlist_new, is_equal, wdev_create, wdev_remove } from "/usr/share/hostap/common.uc";
+import { vlist_new, is_equal, wdev_create, wdev_remove, wdev_generate_macaddr } from "/usr/share/hostap/common.uc";
 import { readfile, writefile, basename, readlink, glob } from "fs";
 
 let keep_devices = {};
 let phy = shift(ARGV);
-let new_config = shift(ARGV);
+
 const mesh_params = [
        "mesh_retry_timeout", "mesh_confirm_timeout", "mesh_holding_timeout", "mesh_max_peer_links",
        "mesh_max_retries", "mesh_ttl", "mesh_element_ttl", "mesh_hwmp_max_preq_retries",
@@ -114,43 +114,79 @@ function add_existing(phy, config)
        }
 }
 
+function usage()
+{
+       warn(`Usage: ${basename(sourcepath())} <phy> <command> [<arguments>]
 
-let statefile = `/var/run/wdev-${phy}.json`;
-
-for (let dev in ARGV)
-       keep_devices[dev] = true;
-
-if (!phy || !new_config) {
-       warn(`Usage: ${basename(sourcepath())} <phy> <config> [<device]...]\n`);
+Commands:
+       set_config <config> [<device]...] - set phy configuration
+       get_macaddr <id>                  - get phy MAC address for vif index <id>
+`);
        exit(1);
 }
 
-if (!readfile(`/sys/class/ieee80211/${phy}/index`)) {
-       warn(`PHY ${phy} does not exist\n`);
-       exit(1);
-}
+const commands = {
+       set_config: function(args) {
+               let statefile = `/var/run/wdev-${phy}.json`;
 
-new_config = json(new_config);
-if (!new_config) {
-       warn("Invalid configuration\n");
-       exit(1);
-}
+               let new_config = shift(args);
+               for (let dev in ARGV)
+                       keep_devices[dev] = true;
+
+               if (!new_config)
+                       usage();
+
+               new_config = json(new_config);
+               if (!new_config) {
+                       warn("Invalid configuration\n");
+                       exit(1);
+               }
 
-let old_config = readfile(statefile);
-if (old_config)
-       old_config = json(old_config);
+               let old_config = readfile(statefile);
+               if (old_config)
+                       old_config = json(old_config);
 
-let config = vlist_new(iface_cb);
-if (type(old_config) == "object")
-       config.data = old_config;
+               let config = vlist_new(iface_cb);
+               if (type(old_config) == "object")
+                       config.data = old_config;
 
-add_existing(phy, config.data);
-add_ifname(config.data);
-drop_inactive(config.data);
+               add_existing(phy, config.data);
+               add_ifname(config.data);
+               drop_inactive(config.data);
 
-add_ifname(new_config);
-config.update(new_config);
+               add_ifname(new_config);
+               config.update(new_config);
+
+               drop_inactive(config.data);
+               delete_ifname(config.data);
+               writefile(statefile, sprintf("%J", config.data));
+       },
+       get_macaddr: function(args) {
+               let data = {};
+
+               for (let arg in args) {
+                       arg = split(arg, "=", 2);
+                       data[arg[0]] = arg[1];
+               }
+
+               let macaddr = wdev_generate_macaddr(phy, data);
+               if (!macaddr) {
+                       warn(`Could not get MAC address for phy ${phy}\n`);
+                       exit(1);
+               }
+
+               print(macaddr + "\n");
+       },
+};
+
+let command = shift(ARGV);
+
+if (!phy || !command | !commands[command])
+       usage();
+
+if (!readfile(`/sys/class/ieee80211/${phy}/index`)) {
+       warn(`PHY ${phy} does not exist\n`);
+       exit(1);
+}
 
-drop_inactive(config.data);
-delete_ifname(config.data);
-writefile(statefile, sprintf("%J", config.data));
+commands[command](ARGV);