Browse Source

hostapd: move mac address allocation from mac80211.sh to wdev.uc

Preparation for upcoming hostapd reload improvements

Signed-off-by: Felix Fietkau <[email protected]>
Felix Fietkau 2 years ago
parent
commit
13c1080a3f

+ 3 - 43
package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh

@@ -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

+ 83 - 1
package/network/services/hostapd/files/common.uc

@@ -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 };

+ 68 - 32
package/network/services/hostapd/files/wdev.uc

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