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 2019-10-30 16:58:19 +01:00 committed by Daniel Golle
parent 60fb4c92b6
commit a5bc9787d4
2 changed files with 135 additions and 37 deletions

View File

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

View File

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