diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 4741d71ead21..4cdd75449d73 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5299,6 +5299,8 @@ static inline void wiphy_unlock(struct wiphy *wiphy) * @wiphy: pointer to hardware description * @iftype: interface type * @registered: is this wdev already registered with cfg80211 + * @registering: indicates we're doing registration under wiphy lock + * for the notifier * @list: (private) Used to collect the interfaces * @netdev: (private) Used to reference back to the netdev, may be %NULL * @identifier: (private) Identifier used in nl80211 to identify this @@ -5382,7 +5384,7 @@ struct wireless_dev { struct mutex mtx; - bool use_4addr, is_running, registered; + bool use_4addr, is_running, registered, registering; u8 address[ETH_ALEN] __aligned(sizeof(u16)); diff --git a/net/wireless/core.c b/net/wireless/core.c index 200cd9f5fd5f..a2785379df6e 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -334,6 +334,7 @@ void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev) struct wireless_dev *wdev, *tmp; ASSERT_RTNL(); + lockdep_assert_wiphy(&rdev->wiphy); list_for_each_entry_safe(wdev, tmp, &rdev->wiphy.wdev_list, list) { if (wdev->nl_owner_dead) @@ -349,7 +350,9 @@ static void cfg80211_destroy_iface_wk(struct work_struct *work) destroy_work); rtnl_lock(); + wiphy_lock(&rdev->wiphy); cfg80211_destroy_ifaces(rdev); + wiphy_unlock(&rdev->wiphy); rtnl_unlock(); } @@ -1343,6 +1346,7 @@ int cfg80211_register_netdevice(struct net_device *dev) /* we'll take care of this */ wdev->registered = true; + wdev->registering = true; ret = register_netdevice(dev); if (ret) goto out; @@ -1358,6 +1362,7 @@ int cfg80211_register_netdevice(struct net_device *dev) cfg80211_register_wdev(rdev, wdev); ret = 0; out: + wdev->registering = false; if (ret) wdev->registered = false; return ret; @@ -1400,7 +1405,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, * It is possible to get NETDEV_UNREGISTER multiple times, * so check wdev->registered. */ - if (wdev->registered) { + if (wdev->registered && !wdev->registering) { wiphy_lock(&rdev->wiphy); _cfg80211_unregister_wdev(wdev, false); wiphy_unlock(&rdev->wiphy); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e5e9d889f00f..3b45a9593e71 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3220,7 +3220,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) wdev = netdev->ieee80211_ptr; wiphy_lock(&rdev->wiphy); - rtnl_unlock(); /* * end workaround code, by now the rdev is available @@ -3230,6 +3229,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_WIPHY_NAME]) result = cfg80211_dev_rename( rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); + rtnl_unlock(); if (result) goto out; diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 2e35cb78221e..a8320dc59af7 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -39,6 +39,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, struct cfg80211_registered_device *rdev; struct vif_params vifparams; enum nl80211_iftype type; + int ret; rdev = wiphy_to_rdev(wdev->wiphy); @@ -61,7 +62,11 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, memset(&vifparams, 0, sizeof(vifparams)); - return cfg80211_change_iface(rdev, dev, type, &vifparams); + wiphy_lock(wdev->wiphy); + ret = cfg80211_change_iface(rdev, dev, type, &vifparams); + wiphy_unlock(wdev->wiphy); + + return ret; } EXPORT_WEXT_HANDLER(cfg80211_wext_siwmode); @@ -650,6 +655,7 @@ static int cfg80211_wext_siwencodeext(struct net_device *dev, bool remove = false; struct key_params params; u32 cipher; + int ret; if (wdev->iftype != NL80211_IFTYPE_STATION && wdev->iftype != NL80211_IFTYPE_ADHOC) @@ -721,12 +727,16 @@ static int cfg80211_wext_siwencodeext(struct net_device *dev, params.seq_len = 6; } - return cfg80211_set_encryption( + wiphy_lock(wdev->wiphy); + ret = cfg80211_set_encryption( rdev, dev, !(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY), addr, remove, ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, idx, ¶ms); + wiphy_unlock(wdev->wiphy); + + return ret; } static int cfg80211_wext_giwencode(struct net_device *dev,