mac80211: Fix race condition leading to wifi interfaces not coming up at boot sometimes.

In the drv_mac80211_setup function, mac80211_interface_cleanup
is called to ask the kernel to delete all existing interfaces
for the phy that is being configured via netlink.

Later in the first function, mac80211_prepare_vif is called to
set up the new interfaces as required.

But sometimes, when mac80211_prepare_vif (and so the relevant
`iw phy x interface add y` command) runs, the kernel might still
be cleaning up the old interface with the same ifname. It usually
takes very few time to do that; possibly a few milliseconds of
sleep in the script after detecting this error condition could be
enough, but the busybox sh does not support sub-second sleep
intervals.

When this happens, iw obviously fails to create the new interface;
and the following message is printed in the system log, followed by
subsequent failure messages from hostapd in case this would have been
an AP interface.

Tue Mar 14 04:21:57 2017 daemon.notice netifd: radio1 (2767): command failed: Too many open files in system (-23)

This was a long-standing issue existing since at least OpenWrt Backfire,
and today I finally managed to debug and (hopefully) solve it.
It was happening very few times on most devices; but it was happening
a lot more frequently on fast platforms with multiple radios, such as
the powerpc-based dual-ath9k-radio tl-wdr4900-v1.

Signed-off-by: Vittorio Gambaletta <openwrt@vittgam.net>
(cherry picked from commit 8301e61365)
This commit is contained in:
Vittorio Gambaletta 2017-03-14 14:45:15 +01:00 committed by Jo-Philipp Wich
parent 5f03ce1213
commit 62a8252a0f

View File

@ -411,6 +411,28 @@ mac80211_check_ap() {
has_ap=1 has_ap=1
} }
mac80211_iw_interface_add() {
local phy="$1"
local ifname="$2"
local type="$3"
local wdsflag="$4"
local rc
iw phy "$phy" interface add "$ifname" type "$type" $wdsflag
rc="$?"
[ "$rc" = 233 ] && {
# Device might have just been deleted, give the kernel some time to finish cleaning it up
sleep 1
iw phy "$phy" interface add "$ifname" type "$type" $wdsflag
rc="$?"
}
[ "$rc" != 0 ] && wireless_setup_failed INTERFACE_CREATION_FAILED
return $rc
}
mac80211_prepare_vif() { mac80211_prepare_vif() {
json_select config json_select config
@ -437,7 +459,7 @@ mac80211_prepare_vif() {
# It is far easier to delete and create the desired interface # It is far easier to delete and create the desired interface
case "$mode" in case "$mode" in
adhoc) adhoc)
iw phy "$phy" interface add "$ifname" type adhoc mac80211_iw_interface_add "$phy" "$ifname" adhoc || return
;; ;;
ap) ap)
# Hostapd will handle recreating the interface and # Hostapd will handle recreating the interface and
@ -451,21 +473,21 @@ mac80211_prepare_vif() {
mac80211_hostapd_setup_bss "$phy" "$ifname" "$macaddr" "$type" || return mac80211_hostapd_setup_bss "$phy" "$ifname" "$macaddr" "$type" || return
[ -n "$hostapd_ctrl" ] || { [ -n "$hostapd_ctrl" ] || {
iw phy "$phy" interface add "$ifname" type __ap mac80211_iw_interface_add "$phy" "$ifname" __ap || return
hostapd_ctrl="${hostapd_ctrl:-/var/run/hostapd/$ifname}" hostapd_ctrl="${hostapd_ctrl:-/var/run/hostapd/$ifname}"
} }
;; ;;
mesh) mesh)
iw phy "$phy" interface add "$ifname" type mp mac80211_iw_interface_add "$phy" "$ifname" mp || return
;; ;;
monitor) monitor)
iw phy "$phy" interface add "$ifname" type monitor mac80211_iw_interface_add "$phy" "$ifname" monitor || return
;; ;;
sta) sta)
local wdsflag= local wdsflag=
staidx="$(($staidx + 1))" staidx="$(($staidx + 1))"
[ "$wds" -gt 0 ] && wdsflag="4addr on" [ "$wds" -gt 0 ] && wdsflag="4addr on"
iw phy "$phy" interface add "$ifname" type managed $wdsflag mac80211_iw_interface_add "$phy" "$ifname" managed "$wdsflag" || return
[ "$powersave" -gt 0 ] && powersave="on" || powersave="off" [ "$powersave" -gt 0 ] && powersave="on" || powersave="off"
iw "$ifname" set power_save "$powersave" iw "$ifname" set power_save "$powersave"
;; ;;