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

View File

@ -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"
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
}
[ -z "$(uci -q -P /var/state show wireless._${phy})" ] && {
uci -q -P /var/state set wireless._${phy}=phy
wireless_set_data phy="$phy"
mac80211_interface_cleanup "$phy"
}
# convert channel to frequency
[ "$auto_channel" -gt 0 ] || freq="$(get_freq "$phy" "$channel")"
@ -822,32 +894,57 @@ 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
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
}
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() {
wireless_process_kill_all
@ -856,6 +953,7 @@ drv_mac80211_teardown() {
json_select ..
mac80211_interface_cleanup "$phy"
uci -q -P /var/state revert wireless._${phy}
}
add_driver mac80211