summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVittorio Gambaletta <openwrt@vittgam.net>2017-03-14 14:45:15 +0100
committerFelix Fietkau <nbd@nbd.name>2017-03-22 11:42:43 +0100
commit8301e613655c2d95fa5430a1a57d92d966fdc70b (patch)
treebaa316f743028291228df92132ea5a4175888414
parent3a3564ead5e4cf2f6ff73302c1e680b5575079ec (diff)
downloadmtk-20170518-8301e613655c2d95fa5430a1a57d92d966fdc70b.zip
mtk-20170518-8301e613655c2d95fa5430a1a57d92d966fdc70b.tar.gz
mtk-20170518-8301e613655c2d95fa5430a1a57d92d966fdc70b.tar.bz2
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>
-rw-r--r--package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh32
1 files changed, 27 insertions, 5 deletions
diff --git a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
index baa023e..9ebd76b 100644
--- a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
+++ b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
@@ -411,6 +411,28 @@ mac80211_check_ap() {
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() {
json_select config
@@ -437,7 +459,7 @@ mac80211_prepare_vif() {
# It is far easier to delete and create the desired interface
case "$mode" in
adhoc)
- iw phy "$phy" interface add "$ifname" type adhoc
+ mac80211_iw_interface_add "$phy" "$ifname" adhoc || return
;;
ap)
# Hostapd will handle recreating the interface and
@@ -451,21 +473,21 @@ mac80211_prepare_vif() {
mac80211_hostapd_setup_bss "$phy" "$ifname" "$macaddr" "$type" || return
[ -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}"
}
;;
mesh)
- iw phy "$phy" interface add "$ifname" type mp
+ mac80211_iw_interface_add "$phy" "$ifname" mp || return
;;
monitor)
- iw phy "$phy" interface add "$ifname" type monitor
+ mac80211_iw_interface_add "$phy" "$ifname" monitor || return
;;
sta)
local wdsflag=
staidx="$(($staidx + 1))"
[ "$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"
iw "$ifname" set power_save "$powersave"
;;