mac80211: add support for dynamically reconfiguring wifi
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: John Crispin <john@phrozen.org> Signed-off-by: Daniel Golle <daniel@makrotopia.org>
This commit is contained in:
		 John Crispin
					John Crispin
				
			
				
					committed by
					
						 Daniel Golle
						Daniel Golle
					
				
			
			
				
	
			
			
			 Daniel Golle
						Daniel Golle
					
				
			
						parent
						
							60fb4c92b6
						
					
				
				
					commit
					a5bc9787d4
				
			| @@ -11,7 +11,7 @@ include $(INCLUDE_DIR)/kernel.mk | |||||||
| PKG_NAME:=mac80211 | PKG_NAME:=mac80211 | ||||||
|  |  | ||||||
| PKG_VERSION:=5.4-rc2-1 | PKG_VERSION:=5.4-rc2-1 | ||||||
| PKG_RELEASE:=1 | PKG_RELEASE:=2 | ||||||
| PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.4-rc2/ | PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.4-rc2/ | ||||||
| PKG_HASH:=b3baedc135b455f09f266cb77e73276ca21bceeb0f24bac2184cc4b97d09cdbf | PKG_HASH:=b3baedc135b455f09f266cb77e73276ca21bceeb0f24bac2184cc4b97d09cdbf | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,6 +19,11 @@ iw() { | |||||||
| 	command iw $@ || logger -t mac80211 "Failed command: iw $@" | 	command iw $@ || logger -t mac80211 "Failed command: iw $@" | ||||||
| } | } | ||||||
|  |  | ||||||
|  | NEWAPLIST= | ||||||
|  | OLDAPLIST= | ||||||
|  | NEWSPLIST= | ||||||
|  | OLDSPLIST= | ||||||
|  |  | ||||||
| drv_mac80211_init_device_config() { | drv_mac80211_init_device_config() { | ||||||
| 	hostapd_common_add_device_config | 	hostapd_common_add_device_config | ||||||
|  |  | ||||||
| @@ -58,7 +63,7 @@ drv_mac80211_init_iface_config() { | |||||||
|  |  | ||||||
| 	config_add_string 'macaddr:macaddr' ifname | 	config_add_string 'macaddr:macaddr' ifname | ||||||
|  |  | ||||||
| 	config_add_boolean wds powersave | 	config_add_boolean wds powersave enable | ||||||
| 	config_add_int maxassoc | 	config_add_int maxassoc | ||||||
| 	config_add_int max_listen_int | 	config_add_int max_listen_int | ||||||
| 	config_add_int dtim_period | 	config_add_int dtim_period | ||||||
| @@ -454,7 +459,7 @@ mac80211_iw_interface_add() { | |||||||
| mac80211_prepare_vif() { | mac80211_prepare_vif() { | ||||||
| 	json_select config | 	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}" | 	[ -n "$ifname" ] || ifname="wlan${phy#phy}${if_idx:+-$if_idx}" | ||||||
| 	if_idx=$((${if_idx:-0} + 1)) | 	if_idx=$((${if_idx:-0} + 1)) | ||||||
| @@ -490,8 +495,8 @@ mac80211_prepare_vif() { | |||||||
|  |  | ||||||
| 			mac80211_hostapd_setup_bss "$phy" "$ifname" "$macaddr" "$type" || return | 			mac80211_hostapd_setup_bss "$phy" "$ifname" "$macaddr" "$type" || return | ||||||
|  |  | ||||||
|  | 			NEWAPLIST="${NEWAPLIST}$ifname " | ||||||
| 			[ -n "$hostapd_ctrl" ] || { | 			[ -n "$hostapd_ctrl" ] || { | ||||||
| 				mac80211_iw_interface_add "$phy" "$ifname" __ap || return |  | ||||||
| 				hostapd_ctrl="${hostapd_ctrl:-/var/run/hostapd/$ifname}" | 				hostapd_ctrl="${hostapd_ctrl:-/var/run/hostapd/$ifname}" | ||||||
| 			} | 			} | ||||||
| 		;; | 		;; | ||||||
| @@ -503,7 +508,7 @@ mac80211_prepare_vif() { | |||||||
| 		;; | 		;; | ||||||
| 		sta) | 		sta) | ||||||
| 			local wdsflag= | 			local wdsflag= | ||||||
| 			staidx="$(($staidx + 1))" | 			[ "$enable" = 0 ] || staidx="$(($staidx + 1))" | ||||||
| 			[ "$wds" -gt 0 ] && wdsflag="4addr on" | 			[ "$wds" -gt 0 ] && wdsflag="4addr on" | ||||||
| 			mac80211_iw_interface_add "$phy" "$ifname" managed "$wdsflag" || return | 			mac80211_iw_interface_add "$phy" "$ifname" managed "$wdsflag" || return | ||||||
| 			[ "$powersave" -gt 0 ] && powersave="on" || powersave="off" | 			[ "$powersave" -gt 0 ] && powersave="on" || powersave="off" | ||||||
| @@ -529,19 +534,62 @@ mac80211_prepare_vif() { | |||||||
| } | } | ||||||
|  |  | ||||||
| mac80211_setup_supplicant() { | 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 || return 1 | ||||||
|  | 	wpa_supplicant_prepare_interface "$ifname" nl80211 || { | ||||||
|  | 		iw dev "$ifname" del | ||||||
|  | 		return 1 | ||||||
|  | 	} | ||||||
| 	if [ "$mode" = "sta" ]; then | 	if [ "$mode" = "sta" ]; then | ||||||
| 		wpa_supplicant_add_network "$ifname" | 		wpa_supplicant_add_network "$ifname" | ||||||
| 	else | 	else | ||||||
| 		wpa_supplicant_add_network "$ifname" "$freq" "$htmode" "$noscan" | 		wpa_supplicant_add_network "$ifname" "$freq" "$htmode" "$noscan" | ||||||
| 	fi | 	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() { | 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_add_network "$ifname" "$freq" "$htmode" "$noscan" | ||||||
|  |  | ||||||
|  | 	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" | 		wpa_supplicant_run "$ifname" | ||||||
|  | 	else | ||||||
|  | 		ubus call $spobj reload | ||||||
|  | 	fi | ||||||
| } | } | ||||||
|  |  | ||||||
| mac80211_setup_adhoc_htmode() { | mac80211_setup_adhoc_htmode() { | ||||||
| @@ -579,12 +627,17 @@ mac80211_setup_adhoc_htmode() { | |||||||
| 		;; | 		;; | ||||||
| 		*) ibss_htmode="" ;; | 		*) ibss_htmode="" ;; | ||||||
| 	esac | 	esac | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| mac80211_setup_adhoc() { | mac80211_setup_adhoc() { | ||||||
|  | 	local enable=$1 | ||||||
| 	json_get_vars bssid ssid key mcast_rate | 	json_get_vars bssid ssid key mcast_rate | ||||||
|  |  | ||||||
|  | 	[ "$enable" = 0 ] && { | ||||||
|  | 		ip link set dev "$ifname" down | ||||||
|  | 		return 0 | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	keyspec= | 	keyspec= | ||||||
| 	[ "$auth_type" = "wep" ] && { | 	[ "$auth_type" = "wep" ] && { | ||||||
| 		set_default key 1 | 		set_default key 1 | ||||||
| @@ -623,8 +676,14 @@ mac80211_setup_adhoc() { | |||||||
| } | } | ||||||
|  |  | ||||||
| mac80211_setup_mesh() { | mac80211_setup_mesh() { | ||||||
|  | 	local enable=$1 | ||||||
| 	json_get_vars ssid mesh_id mcast_rate | 	json_get_vars ssid mesh_id mcast_rate | ||||||
|  |  | ||||||
|  | 	[ "$enable" = 0 ] && { | ||||||
|  | 		ip link set dev "$ifname" down | ||||||
|  | 		return 0 | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	mcval= | 	mcval= | ||||||
| 	[ -n "$mcast_rate" ] && wpa_supplicant_add_rate mcval "$mcast_rate" | 	[ -n "$mcast_rate" ] && wpa_supplicant_add_rate mcval "$mcast_rate" | ||||||
| 	[ -n "$mesh_id" ] && ssid="$mesh_id" | 	[ -n "$mesh_id" ] && ssid="$mesh_id" | ||||||
| @@ -670,6 +729,7 @@ mac80211_setup_mesh() { | |||||||
| mac80211_setup_vif() { | mac80211_setup_vif() { | ||||||
| 	local name="$1" | 	local name="$1" | ||||||
| 	local failed | 	local failed | ||||||
|  | 	local action=up | ||||||
|  |  | ||||||
| 	json_select data | 	json_select data | ||||||
| 	json_get_vars ifname | 	json_get_vars ifname | ||||||
| @@ -678,13 +738,15 @@ mac80211_setup_vif() { | |||||||
| 	json_select config | 	json_select config | ||||||
| 	json_get_vars mode | 	json_get_vars mode | ||||||
| 	json_get_var vif_txpower txpower | 	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 | 		wireless_setup_vif_failed IFUP_ERROR | ||||||
| 		json_select .. | 		json_select .. | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	set_default vif_txpower "$txpower" | 	set_default vif_txpower "$txpower" | ||||||
| 	[ -z "$vif_txpower" ] || iw dev "$ifname" set txpower fixed "${vif_txpower%%.*}00" | 	[ -z "$vif_txpower" ] || iw dev "$ifname" set txpower fixed "${vif_txpower%%.*}00" | ||||||
|  |  | ||||||
| @@ -693,9 +755,9 @@ mac80211_setup_vif() { | |||||||
| 			wireless_vif_parse_encryption | 			wireless_vif_parse_encryption | ||||||
| 			freq="$(get_freq "$phy" "$channel")" | 			freq="$(get_freq "$phy" "$channel")" | ||||||
| 			if [ "$wpa" -gt 0 -o "$auto_channel" -gt 0 ] || chan_is_dfs "$phy" "$channel"; then | 			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 | 			else | ||||||
| 				mac80211_setup_mesh | 				mac80211_setup_mesh $vif_enable | ||||||
| 			fi | 			fi | ||||||
| 			for var in $MP_CONFIG_INT $MP_CONFIG_BOOL $MP_CONFIG_STRING; do | 			for var in $MP_CONFIG_INT $MP_CONFIG_BOOL $MP_CONFIG_STRING; do | ||||||
| 				json_get_var mp_val "$var" | 				json_get_var mp_val "$var" | ||||||
| @@ -707,13 +769,13 @@ mac80211_setup_vif() { | |||||||
| 			mac80211_setup_adhoc_htmode | 			mac80211_setup_adhoc_htmode | ||||||
| 			if [ "$wpa" -gt 0 -o "$auto_channel" -gt 0 ]; then | 			if [ "$wpa" -gt 0 -o "$auto_channel" -gt 0 ]; then | ||||||
| 				freq="$(get_freq "$phy" "$channel")" | 				freq="$(get_freq "$phy" "$channel")" | ||||||
| 				mac80211_setup_supplicant_noctl || failed=1 | 				mac80211_setup_supplicant_noctl $vif_enable || failed=1 | ||||||
| 			else | 			else | ||||||
| 				mac80211_setup_adhoc | 				mac80211_setup_adhoc $vif_enable | ||||||
| 			fi | 			fi | ||||||
| 		;; | 		;; | ||||||
| 		sta) | 		sta) | ||||||
| 			mac80211_setup_supplicant || failed=1 | 			mac80211_setup_supplicant $vif_enable || failed=1 | ||||||
| 		;; | 		;; | ||||||
| 	esac | 	esac | ||||||
|  |  | ||||||
| @@ -734,18 +796,26 @@ chan_is_dfs() { | |||||||
| 	return $! | 	return $! | ||||||
| } | } | ||||||
|  |  | ||||||
| mac80211_interface_cleanup() { | mac80211_vap_cleanup() { | ||||||
| 	local phy="$1" | 	local service="$1" | ||||||
|  | 	local vaps="$2" | ||||||
|  |  | ||||||
| 	for wdev in $(list_phy_interfaces "$phy"); do | 	for wdev in $vaps; do | ||||||
| 		local wdev_phy="$(readlink /sys/class/net/${wdev}/phy80211)" | 		ubus call ${service}.${phy} config_remove "{\"iface\":\"$wdev\"}" | ||||||
| 		wdev_phy="$(basename "$wdev_phy")" |  | ||||||
| 		[ -n "$wdev_phy" -a "$wdev_phy" != "$phy" ] && continue |  | ||||||
| 		ip link set dev "$wdev" down 2>/dev/null | 		ip link set dev "$wdev" down 2>/dev/null | ||||||
| 		iw dev "$wdev" del | 		iw dev "$wdev" del | ||||||
| 	done | 	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() { | mac80211_set_noscan() { | ||||||
| 	hostapd_noscan=1 | 	hostapd_noscan=1 | ||||||
| } | } | ||||||
| @@ -771,8 +841,10 @@ drv_mac80211_setup() { | |||||||
| 		return 1 | 		return 1 | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	[ -z "$(uci -q -P /var/state show wireless._${phy})" ] && { | ||||||
|  | 		uci -q -P /var/state set wireless._${phy}=phy | ||||||
| 		wireless_set_data phy="$phy" | 		wireless_set_data phy="$phy" | ||||||
| 	mac80211_interface_cleanup "$phy" | 	} | ||||||
|  |  | ||||||
| 	# convert channel to frequency | 	# convert channel to frequency | ||||||
| 	[ "$auto_channel" -gt 0 ] || freq="$(get_freq "$phy" "$channel")" | 	[ "$auto_channel" -gt 0 ] || freq="$(get_freq "$phy" "$channel")" | ||||||
| @@ -822,32 +894,57 @@ drv_mac80211_setup() { | |||||||
| 	[ -n "$has_ap" ] && mac80211_hostapd_setup_base "$phy" | 	[ -n "$has_ap" ] && mac80211_hostapd_setup_base "$phy" | ||||||
|  |  | ||||||
| 	for_each_interface "sta adhoc mesh monitor" mac80211_prepare_vif | 	for_each_interface "sta adhoc mesh monitor" mac80211_prepare_vif | ||||||
|  | 	NEWAPLIST= | ||||||
| 	for_each_interface "ap" mac80211_prepare_vif | 	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" ] && { | 	[ -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="$?" | 		ret="$?" | ||||||
| 		wireless_add_process "$(cat /var/run/wifi-$phy.pid)" "/usr/sbin/hostapd" 1 |  | ||||||
| 		[ "$ret" != 0 ] && { | 		[ "$ret" != 0 ] && { | ||||||
| 			wireless_setup_failed HOSTAPD_START_FAILED | 			wireless_setup_failed HOSTAPD_START_FAILED | ||||||
| 			return | 			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 | ||||||
|  |  | ||||||
|  | 	NEWSPLIST= | ||||||
|  | 	OLDSPLIST=$(uci -q -P /var/state get wireless._${phy}.splist) | ||||||
|  | 	for_each_interface "sta adhoc mesh monitor" mac80211_setup_vif | ||||||
|  |  | ||||||
|  | 	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 | 	wireless_set_up | ||||||
| } | } | ||||||
|  |  | ||||||
| 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 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| drv_mac80211_teardown() { | drv_mac80211_teardown() { | ||||||
| 	wireless_process_kill_all | 	wireless_process_kill_all | ||||||
|  |  | ||||||
| @@ -856,6 +953,7 @@ drv_mac80211_teardown() { | |||||||
| 	json_select .. | 	json_select .. | ||||||
|  |  | ||||||
| 	mac80211_interface_cleanup "$phy" | 	mac80211_interface_cleanup "$phy" | ||||||
|  | 	uci -q -P /var/state revert wireless._${phy} | ||||||
| } | } | ||||||
|  |  | ||||||
| add_driver mac80211 | add_driver mac80211 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user