From a5bc9787d4ef89c9e2593a191b3c4cf8702b41a3 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 30 Oct 2019 16:58:19 +0100 Subject: 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 Signed-off-by: Daniel Golle --- package/kernel/mac80211/Makefile | 2 +- .../mac80211/files/lib/netifd/wireless/mac80211.sh | 170 ++++++++++++++++----- 2 files changed, 135 insertions(+), 37 deletions(-) diff --git a/package/kernel/mac80211/Makefile b/package/kernel/mac80211/Makefile index dd5d4f9456..422c0436e4 100644 --- a/package/kernel/mac80211/Makefile +++ b/package/kernel/mac80211/Makefile @@ -11,7 +11,7 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=mac80211 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_HASH:=b3baedc135b455f09f266cb77e73276ca21bceeb0f24bac2184cc4b97d09cdbf 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 -- cgit v1.2.3