mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-25 02:09:42 +00:00
cfg80211: fix deadlock during reg chan check
If a P2P GO is active, the cfg80211_reg_can_beacon function will take the wdev lock, in its call to cfg80211_go_permissive_chan. But the wdev lock is already taken by the parent channel-checking function, causing a deadlock. Split the checking code into two parts. The first part will check if the wdev is active and saves the channel under the wdev lock. The second part will check actual channel validity according to type. Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com> Reviewed-by: Ilan Peer <ilan.peer@intel.com> Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
cc72f6e227
commit
20658702e0
1 changed files with 34 additions and 22 deletions
|
@ -1530,45 +1530,40 @@ static void reg_call_notifier(struct wiphy *wiphy,
|
|||
|
||||
static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
|
||||
{
|
||||
struct ieee80211_channel *ch;
|
||||
struct cfg80211_chan_def chandef;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
bool ret = true;
|
||||
enum nl80211_iftype iftype;
|
||||
|
||||
wdev_lock(wdev);
|
||||
iftype = wdev->iftype;
|
||||
|
||||
/* make sure the interface is active */
|
||||
if (!wdev->netdev || !netif_running(wdev->netdev))
|
||||
goto out;
|
||||
goto wdev_inactive_unlock;
|
||||
|
||||
switch (wdev->iftype) {
|
||||
switch (iftype) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
if (!wdev->beacon_interval)
|
||||
goto out;
|
||||
|
||||
ret = cfg80211_reg_can_beacon(wiphy,
|
||||
&wdev->chandef, wdev->iftype);
|
||||
goto wdev_inactive_unlock;
|
||||
chandef = wdev->chandef;
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
if (!wdev->ssid_len)
|
||||
goto out;
|
||||
|
||||
ret = cfg80211_reg_can_beacon(wiphy,
|
||||
&wdev->chandef, wdev->iftype);
|
||||
goto wdev_inactive_unlock;
|
||||
chandef = wdev->chandef;
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
if (!wdev->current_bss ||
|
||||
!wdev->current_bss->pub.channel)
|
||||
goto out;
|
||||
goto wdev_inactive_unlock;
|
||||
|
||||
ch = wdev->current_bss->pub.channel;
|
||||
if (rdev->ops->get_channel &&
|
||||
!rdev_get_channel(rdev, wdev, &chandef))
|
||||
ret = cfg80211_chandef_usable(wiphy, &chandef,
|
||||
IEEE80211_CHAN_DISABLED);
|
||||
else
|
||||
ret = !(ch->flags & IEEE80211_CHAN_DISABLED);
|
||||
if (!rdev->ops->get_channel ||
|
||||
rdev_get_channel(rdev, wdev, &chandef))
|
||||
cfg80211_chandef_create(&chandef,
|
||||
wdev->current_bss->pub.channel,
|
||||
NL80211_CHAN_NO_HT);
|
||||
break;
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
|
@ -1581,9 +1576,26 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
|
|||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
wdev_unlock(wdev);
|
||||
return ret;
|
||||
|
||||
switch (iftype) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
return cfg80211_reg_can_beacon(wiphy, &chandef, iftype);
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
return cfg80211_chandef_usable(wiphy, &chandef,
|
||||
IEEE80211_CHAN_DISABLED);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
wdev_inactive_unlock:
|
||||
wdev_unlock(wdev);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void reg_leave_invalid_chans(struct wiphy *wiphy)
|
||||
|
|
Loading…
Reference in a new issue