[OpenWrt-Devel,v2,4/5] mac80211: add support for dynamically reconfiguring wifi
diff mbox series

Message ID 20191109173509.GA103319@makrotopia.org
State Accepted
Delegated to: Daniel Golle
Headers show
Series
  • [OpenWrt-Devel,v2,netifd,1/5] wireless: add ubus method for reloading configuration
Related show

Commit Message

Daniel Golle Nov. 9, 2019, 5:35 p.m. UTC
From: John Crispin <john@phrozen.org>

Change scripts to use ubus interface of hostapd/wpa_supplicant to
add/remove/modify wireless interfaces instead of (re-)starting the
services.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
v2: honour vif_enable for supplicant and bare ifaces

 .../files/lib/netifd/wireless/mac80211.sh     | 170 ++++++++++++++----
 1 file changed, 134 insertions(+), 36 deletions(-)

Patch
diff mbox series

diff --git a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
index 12af2d1d0e..5b174cded6 100644
--- a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
+++ b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
@@ -19,6 +19,11 @@  iw() {
 	command iw $@ || logger -t mac80211 "Failed command: iw $@"
 }
 
+NEWAPLIST=
+OLDAPLIST=
+NEWSPLIST=
+OLDSPLIST=
+
 drv_mac80211_init_device_config() {
 	hostapd_common_add_device_config
 
@@ -58,7 +63,7 @@  drv_mac80211_init_iface_config() {
 
 	config_add_string 'macaddr:macaddr' ifname
 
-	config_add_boolean wds powersave
+	config_add_boolean wds powersave enable
 	config_add_int maxassoc
 	config_add_int max_listen_int
 	config_add_int dtim_period
@@ -454,7 +459,7 @@  mac80211_iw_interface_add() {
 mac80211_prepare_vif() {
 	json_select config
 
-	json_get_vars ifname mode ssid wds powersave macaddr
+	json_get_vars ifname mode ssid wds powersave macaddr enable
 
 	[ -n "$ifname" ] || ifname="wlan${phy#phy}${if_idx:+-$if_idx}"
 	if_idx=$((${if_idx:-0} + 1))
@@ -490,8 +495,8 @@  mac80211_prepare_vif() {
 
 			mac80211_hostapd_setup_bss "$phy" "$ifname" "$macaddr" "$type" || return
 
+			NEWAPLIST="${NEWAPLIST}$ifname "
 			[ -n "$hostapd_ctrl" ] || {
-				mac80211_iw_interface_add "$phy" "$ifname" __ap || return
 				hostapd_ctrl="${hostapd_ctrl:-/var/run/hostapd/$ifname}"
 			}
 		;;
@@ -503,7 +508,7 @@  mac80211_prepare_vif() {
 		;;
 		sta)
 			local wdsflag=
-			staidx="$(($staidx + 1))"
+			[ "$enable" = 0 ] || staidx="$(($staidx + 1))"
 			[ "$wds" -gt 0 ] && wdsflag="4addr on"
 			mac80211_iw_interface_add "$phy" "$ifname" managed "$wdsflag" || return
 			[ "$powersave" -gt 0 ] && powersave="on" || powersave="off"
@@ -529,19 +534,62 @@  mac80211_prepare_vif() {
 }
 
 mac80211_setup_supplicant() {
+	local enable=$1
+	local add_sp=0
+	local spobj="$(ubus -S list | grep wpa_supplicant.${ifname})"
+
 	wpa_supplicant_prepare_interface "$ifname" nl80211 || return 1
+	wpa_supplicant_prepare_interface "$ifname" nl80211 || {
+		iw dev "$ifname" del
+		return 1
+	}
 	if [ "$mode" = "sta" ]; then
 		wpa_supplicant_add_network "$ifname"
 	else
 		wpa_supplicant_add_network "$ifname" "$freq" "$htmode" "$noscan"
 	fi
-	wpa_supplicant_run "$ifname" ${hostapd_ctrl:+-H $hostapd_ctrl}
+
+	NEWSPLIST="${NEWSPLIST}$ifname "
+
+	if [ "${NEWAPLIST%% *}" != "${OLDAPLIST%% *}" ]; then
+		[ "$spobj" ] && ubus call wpa_supplicant.${phy} config_del "{\"iface\":\"$ifname\"}"
+		add_sp=1
+	fi
+	[ "$enable" = 0 ] && {
+		ubus call wpa_supplicant.${phy} config_del "{\"iface\":\"$ifname\"}"
+		ip link set dev "$ifname" down
+		return 0
+	}
+	[ -z "$spobj" ] && add_sp=1
+
+	if [ "$add_sp" = "1" ]; then
+		wpa_supplicant_run "$ifname" "$hostapd_ctrl"
+	else
+		ubus call $spobj reload
+	fi
 }
 
 mac80211_setup_supplicant_noctl() {
-	wpa_supplicant_prepare_interface "$ifname" nl80211 || return 1
+	local enable=$1
+	local spobj="$(ubus -S list | grep wpa_supplicant.${ifname})"
+	wpa_supplicant_prepare_interface "$ifname" nl80211 || {
+		iw dev "$ifname" del
+		return 1
+	}
+
 	wpa_supplicant_add_network "$ifname" "$freq" "$htmode" "$noscan"
-	wpa_supplicant_run "$ifname"
+
+	NEWSPLIST="${NEWSPLIST}$ifname "
+	[ "$enable" = 0 ] && {
+		ubus call wpa_supplicant.${phy} config_del "{\"iface\":\"$ifname\"}"
+		ip link set dev "$ifname" down
+		return 0
+	}
+	if [ -z "$spobj" ]; then
+		wpa_supplicant_run "$ifname"
+	else
+		ubus call $spobj reload
+	fi
 }
 
 mac80211_setup_adhoc_htmode() {
@@ -579,12 +627,17 @@  mac80211_setup_adhoc_htmode() {
 		;;
 		*) ibss_htmode="" ;;
 	esac
-
 }
 
 mac80211_setup_adhoc() {
+	local enable=$1
 	json_get_vars bssid ssid key mcast_rate
 
+	[ "$enable" = 0 ] && {
+		ip link set dev "$ifname" down
+		return 0
+	}
+
 	keyspec=
 	[ "$auth_type" = "wep" ] && {
 		set_default key 1
@@ -623,8 +676,14 @@  mac80211_setup_adhoc() {
 }
 
 mac80211_setup_mesh() {
+	local enable=$1
 	json_get_vars ssid mesh_id mcast_rate
 
+	[ "$enable" = 0 ] && {
+		ip link set dev "$ifname" down
+		return 0
+	}
+
 	mcval=
 	[ -n "$mcast_rate" ] && wpa_supplicant_add_rate mcval "$mcast_rate"
 	[ -n "$mesh_id" ] && ssid="$mesh_id"
@@ -670,6 +729,7 @@  mac80211_setup_mesh() {
 mac80211_setup_vif() {
 	local name="$1"
 	local failed
+	local action=up
 
 	json_select data
 	json_get_vars ifname
@@ -678,13 +738,15 @@  mac80211_setup_vif() {
 	json_select config
 	json_get_vars mode
 	json_get_var vif_txpower txpower
+	json_get_var vif_enable enable 1
 
-	ip link set dev "$ifname" up || {
+	[ "$vif_enable" = 1 ] || action=down
+	logger ip link set dev "$ifname" $action
+	ip link set dev "$ifname" "$action" || {
 		wireless_setup_vif_failed IFUP_ERROR
 		json_select ..
 		return
 	}
-
 	set_default vif_txpower "$txpower"
 	[ -z "$vif_txpower" ] || iw dev "$ifname" set txpower fixed "${vif_txpower%%.*}00"
 
@@ -693,9 +755,9 @@  mac80211_setup_vif() {
 			wireless_vif_parse_encryption
 			freq="$(get_freq "$phy" "$channel")"
 			if [ "$wpa" -gt 0 -o "$auto_channel" -gt 0 ] || chan_is_dfs "$phy" "$channel"; then
-				mac80211_setup_supplicant || failed=1
+				mac80211_setup_supplicant $vif_enable || failed=1
 			else
-				mac80211_setup_mesh
+				mac80211_setup_mesh $vif_enable
 			fi
 			for var in $MP_CONFIG_INT $MP_CONFIG_BOOL $MP_CONFIG_STRING; do
 				json_get_var mp_val "$var"
@@ -707,13 +769,13 @@  mac80211_setup_vif() {
 			mac80211_setup_adhoc_htmode
 			if [ "$wpa" -gt 0 -o "$auto_channel" -gt 0 ]; then
 				freq="$(get_freq "$phy" "$channel")"
-				mac80211_setup_supplicant_noctl || failed=1
+				mac80211_setup_supplicant_noctl $vif_enable || failed=1
 			else
-				mac80211_setup_adhoc
+				mac80211_setup_adhoc $vif_enable
 			fi
 		;;
 		sta)
-			mac80211_setup_supplicant || failed=1
+			mac80211_setup_supplicant $vif_enable || failed=1
 		;;
 	esac
 
@@ -734,18 +796,26 @@  chan_is_dfs() {
 	return $!
 }
 
-mac80211_interface_cleanup() {
-	local phy="$1"
+mac80211_vap_cleanup() {
+	local service="$1"
+	local vaps="$2"
 
-	for wdev in $(list_phy_interfaces "$phy"); do
-		local wdev_phy="$(readlink /sys/class/net/${wdev}/phy80211)"
-		wdev_phy="$(basename "$wdev_phy")"
-		[ -n "$wdev_phy" -a "$wdev_phy" != "$phy" ] && continue
+	for wdev in $vaps; do
+		ubus call ${service}.${phy} config_remove "{\"iface\":\"$wdev\"}"
 		ip link set dev "$wdev" down 2>/dev/null
 		iw dev "$wdev" del
 	done
 }
 
+mac80211_interface_cleanup() {
+	local phy="$1"
+	local primary_ap=$(uci -q -P /var/state get wireless._${phy}.aplist)
+	primary_ap=${primary_ap%% *}
+
+	mac80211_vap_cleanup hostapd "${primary_ap}"
+	mac80211_vap_cleanup wpa_supplicant "$(uci -q -P /var/state get wireless._${phy}.splist)"
+}
+
 mac80211_set_noscan() {
 	hostapd_noscan=1
 }
@@ -771,8 +841,10 @@  drv_mac80211_setup() {
 		return 1
 	}
 
-	wireless_set_data phy="$phy"
-	mac80211_interface_cleanup "$phy"
+	[ -z "$(uci -q -P /var/state show wireless._${phy})" ] && {
+		uci -q -P /var/state set wireless._${phy}=phy
+		wireless_set_data phy="$phy"
+	}
 
 	# convert channel to frequency
 	[ "$auto_channel" -gt 0 ] || freq="$(get_freq "$phy" "$channel")"
@@ -822,30 +894,55 @@  drv_mac80211_setup() {
 	[ -n "$has_ap" ] && mac80211_hostapd_setup_base "$phy"
 
 	for_each_interface "sta adhoc mesh monitor" mac80211_prepare_vif
+	NEWAPLIST=
 	for_each_interface "ap" mac80211_prepare_vif
-
+	OLDAPLIST=$(uci -q -P /var/state get wireless._${phy}.aplist)
+	NEW_MD5=$(md5sum ${hostapd_conf_file})
+	OLD_MD5=$(uci -q -P /var/state get wireless._${phy}.md5)
+	if [ "${NEWAPLIST}" != "${OLDAPLIST}" ]; then
+		mac80211_vap_cleanup hostapd "${OLDAPLIST}"
+		[ -n "${NEWAPLIST}" ] && mac80211_iw_interface_add "$phy" "${NEWAPLIST%% *}" __ap || return
+	fi
+	local add_ap=0
+	local primary_ap=${NEWAPLIST%% *}
 	[ -n "$hostapd_ctrl" ] && {
-		/usr/sbin/hostapd -s -P /var/run/wifi-$phy.pid -B "$hostapd_conf_file"
+		if [ -n "$(ubus list | grep hostapd.$primary_ap)" ]; then
+			[ "${NEW_MD5}" = "${OLD_MD5}" ] || {
+				ubus call hostapd.$primary_ap reload
+			}
+		else
+			add_ap=1
+			ubus call hostapd.${phy} config_add "{\"iface\":\"$primary_ap\", \"config\":\"${hostapd_conf_file}\"}"
+		fi
 		ret="$?"
-		wireless_add_process "$(cat /var/run/wifi-$phy.pid)" "/usr/sbin/hostapd" 1
 		[ "$ret" != 0 ] && {
 			wireless_setup_failed HOSTAPD_START_FAILED
 			return
 		}
 	}
+	uci -q -P /var/state set wireless._${phy}.aplist="${NEWAPLIST}"
+	uci -q -P /var/state set wireless._${phy}.md5="${NEW_MD5}"
 
-	for_each_interface "ap sta adhoc mesh monitor" mac80211_setup_vif
+	[ "${add_ap}" = 1 ] && sleep 1
+	for_each_interface "ap" mac80211_setup_vif
 
-	wireless_set_up
-}
+	NEWSPLIST=
+	OLDSPLIST=$(uci -q -P /var/state get wireless._${phy}.splist)
+	for_each_interface "sta adhoc mesh monitor" mac80211_setup_vif
 
-list_phy_interfaces() {
-	local phy="$1"
-	if [ -d "/sys/class/ieee80211/${phy}/device/net" ]; then
-		ls "/sys/class/ieee80211/${phy}/device/net" 2>/dev/null;
-	else
-		ls "/sys/class/ieee80211/${phy}/device" 2>/dev/null | grep net: | sed -e 's,net:,,g'
-	fi
+	uci -q -P /var/state set wireless._${phy}.splist="${NEWSPLIST}"
+
+	local foundvap
+	local dropvap=""
+	for oldvap in $OLDSPLIST; do
+		foundvap=0
+		for newvap in $NEWSPLIST; do
+			[ "$oldvap" = "$newvap" ] && foundvap=1
+		done
+		[ "$foundvap" = "0" ] && dropvap="$dropvap $oldvap"
+	done
+	[ -n "$dropvap" ] && mac80211_vap_cleanup wpa_supplicant "$dropvap"
+	wireless_set_up
 }
 
 drv_mac80211_teardown() {
@@ -856,6 +953,7 @@  drv_mac80211_teardown() {
 	json_select ..
 
 	mac80211_interface_cleanup "$phy"
+	uci -q -P /var/state revert wireless._${phy}
 }
 
 add_driver mac80211