/* returns ERR_PTR values */
 static struct wireless_dev *
-__cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
+__cfg80211_wdev_from_attrs(struct cfg80211_registered_device *rdev,
+                          struct net *netns, struct nlattr **attrs)
 {
-       struct cfg80211_registered_device *rdev;
        struct wireless_dev *result = NULL;
        bool have_ifidx = attrs[NL80211_ATTR_IFINDEX];
        bool have_wdev_id = attrs[NL80211_ATTR_WDEV];
        int wiphy_idx = -1;
        int ifidx = -1;
 
-       ASSERT_RTNL();
-
        if (!have_ifidx && !have_wdev_id)
                return ERR_PTR(-EINVAL);
 
                wiphy_idx = wdev_id >> 32;
        }
 
+       if (rdev) {
+               struct wireless_dev *wdev;
+
+               lockdep_assert_held(&rdev->wiphy.mtx);
+
+               list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
+                       if (have_ifidx && wdev->netdev &&
+                           wdev->netdev->ifindex == ifidx) {
+                               result = wdev;
+                               break;
+                       }
+                       if (have_wdev_id && wdev->identifier == (u32)wdev_id) {
+                               result = wdev;
+                               break;
+                       }
+               }
+
+               return result ?: ERR_PTR(-ENODEV);
+       }
+
+       ASSERT_RTNL();
+
        list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
                struct wireless_dev *wdev;
 
                        return err;
                }
 
-               *wdev = __cfg80211_wdev_from_attrs(sock_net(cb->skb->sk),
+               rtnl_lock();
+               *wdev = __cfg80211_wdev_from_attrs(NULL, sock_net(cb->skb->sk),
                                                   attrbuf);
                kfree(attrbuf);
-               if (IS_ERR(*wdev))
+               if (IS_ERR(*wdev)) {
+                       rtnl_unlock();
                        return PTR_ERR(*wdev);
+               }
                *rdev = wiphy_to_rdev((*wdev)->wiphy);
+               mutex_lock(&(*rdev)->wiphy.mtx);
+               rtnl_unlock();
                /* 0 is the first index - add 1 to parse only once */
                cb->args[0] = (*rdev)->wiphy_idx + 1;
                cb->args[1] = (*wdev)->identifier;
        } else {
                /* subtract the 1 again here */
-               struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
+               struct wiphy *wiphy;
                struct wireless_dev *tmp;
 
-               if (!wiphy)
+               rtnl_lock();
+               wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
+               if (!wiphy) {
+                       rtnl_unlock();
                        return -ENODEV;
+               }
                *rdev = wiphy_to_rdev(wiphy);
                *wdev = NULL;
 
                        }
                }
 
-               if (!*wdev)
+               if (!*wdev) {
+                       rtnl_unlock();
                        return -ENODEV;
+               }
+               mutex_lock(&(*rdev)->wiphy.mtx);
+               rtnl_unlock();
        }
 
        return 0;
 
 static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = NULL;
        struct net_device *netdev = NULL;
        struct wireless_dev *wdev;
        int result = 0, rem_txq_params = 0;
        u8 coverage_class = 0;
        u32 txq_limit = 0, txq_memory_limit = 0, txq_quantum = 0;
 
-       ASSERT_RTNL();
-
+       rtnl_lock();
        /*
         * Try to find the wiphy and netdev. Normally this
         * function shouldn't need the netdev, but this is
        if (!netdev) {
                rdev = __cfg80211_rdev_from_attrs(genl_info_net(info),
                                                  info->attrs);
-               if (IS_ERR(rdev))
+               if (IS_ERR(rdev)) {
+                       rtnl_unlock();
                        return PTR_ERR(rdev);
+               }
                wdev = NULL;
                netdev = NULL;
                result = 0;
        } else
                wdev = netdev->ieee80211_ptr;
 
+       wiphy_lock(&rdev->wiphy);
+       rtnl_unlock();
+
        /*
         * end workaround code, by now the rdev is available
         * and locked, and wdev may or may not be NULL.
                        rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
 
        if (result)
-               return result;
+               goto out;
 
        if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) {
                struct ieee80211_txq_params txq_params;
                struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1];
 
-               if (!rdev->ops->set_txq_params)
-                       return -EOPNOTSUPP;
+               if (!rdev->ops->set_txq_params) {
+                       result = -EOPNOTSUPP;
+                       goto out;
+               }
 
-               if (!netdev)
-                       return -EINVAL;
+               if (!netdev) {
+                       result = -EINVAL;
+                       goto out;
+               }
 
                if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
-                   netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
-                       return -EINVAL;
+                   netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
+                       result = -EINVAL;
+                       goto out;
+               }
 
-               if (!netif_running(netdev))
-                       return -ENETDOWN;
+               if (!netif_running(netdev)) {
+                       result = -ENETDOWN;
+                       goto out;
+               }
 
                nla_for_each_nested(nl_txq_params,
                                    info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
                                                             txq_params_policy,
                                                             info->extack);
                        if (result)
-                               return result;
+                               goto out;
                        result = parse_txq_params(tb, &txq_params);
                        if (result)
-                               return result;
+                               goto out;
 
                        result = rdev_set_txq_params(rdev, netdev,
                                                     &txq_params);
                        if (result)
-                               return result;
+                               goto out;
                }
        }
 
                        nl80211_can_set_dev_channel(wdev) ? netdev : NULL,
                        info);
                if (result)
-                       return result;
+                       goto out;
        }
 
        if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) {
                if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER))
                        txp_wdev = NULL;
 
-               if (!rdev->ops->set_tx_power)
-                       return -EOPNOTSUPP;
+               if (!rdev->ops->set_tx_power) {
+                       result = -EOPNOTSUPP;
+                       goto out;
+               }
 
                idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING;
                type = nla_get_u32(info->attrs[idx]);
 
                if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] &&
-                   (type != NL80211_TX_POWER_AUTOMATIC))
-                       return -EINVAL;
+                   (type != NL80211_TX_POWER_AUTOMATIC)) {
+                       result = -EINVAL;
+                       goto out;
+               }
 
                if (type != NL80211_TX_POWER_AUTOMATIC) {
                        idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL;
 
                result = rdev_set_tx_power(rdev, txp_wdev, type, mbm);
                if (result)
-                       return result;
+                       goto out;
        }
 
        if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
 
                if ((!rdev->wiphy.available_antennas_tx &&
                     !rdev->wiphy.available_antennas_rx) ||
-                   !rdev->ops->set_antenna)
-                       return -EOPNOTSUPP;
+                   !rdev->ops->set_antenna) {
+                       result = -EOPNOTSUPP;
+                       goto out;
+               }
 
                tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]);
                rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]);
                /* reject antenna configurations which don't match the
                 * available antenna masks, except for the "all" mask */
                if ((~tx_ant && (tx_ant & ~rdev->wiphy.available_antennas_tx)) ||
-                   (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx)))
-                       return -EINVAL;
+                   (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx))) {
+                       result = -EINVAL;
+                       goto out;
+               }
 
                tx_ant = tx_ant & rdev->wiphy.available_antennas_tx;
                rx_ant = rx_ant & rdev->wiphy.available_antennas_rx;
 
                result = rdev_set_antenna(rdev, tx_ant, rx_ant);
                if (result)
-                       return result;
+                       goto out;
        }
 
        changed = 0;
        if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) {
                frag_threshold = nla_get_u32(
                        info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]);
-               if (frag_threshold < 256)
-                       return -EINVAL;
+               if (frag_threshold < 256) {
+                       result = -EINVAL;
+                       goto out;
+               }
 
                if (frag_threshold != (u32) -1) {
                        /*
        }
 
        if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) {
-               if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK])
-                       return -EINVAL;
+               if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK]) {
+                       result = -EINVAL;
+                       goto out;
+               }
 
                coverage_class = nla_get_u8(
                        info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]);
        }
 
        if (info->attrs[NL80211_ATTR_WIPHY_DYN_ACK]) {
-               if (!(rdev->wiphy.features & NL80211_FEATURE_ACKTO_ESTIMATION))
-                       return -EOPNOTSUPP;
+               if (!(rdev->wiphy.features & NL80211_FEATURE_ACKTO_ESTIMATION)) {
+                       result = -EOPNOTSUPP;
+                       goto out;
+               }
 
                changed |= WIPHY_PARAM_DYN_ACK;
        }
 
        if (info->attrs[NL80211_ATTR_TXQ_LIMIT]) {
                if (!wiphy_ext_feature_isset(&rdev->wiphy,
-                                            NL80211_EXT_FEATURE_TXQS))
-                       return -EOPNOTSUPP;
+                                            NL80211_EXT_FEATURE_TXQS)) {
+                       result = -EOPNOTSUPP;
+                       goto out;
+               }
                txq_limit = nla_get_u32(
                        info->attrs[NL80211_ATTR_TXQ_LIMIT]);
                changed |= WIPHY_PARAM_TXQ_LIMIT;
 
        if (info->attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT]) {
                if (!wiphy_ext_feature_isset(&rdev->wiphy,
-                                            NL80211_EXT_FEATURE_TXQS))
-                       return -EOPNOTSUPP;
+                                            NL80211_EXT_FEATURE_TXQS)) {
+                       result = -EOPNOTSUPP;
+                       goto out;
+               }
                txq_memory_limit = nla_get_u32(
                        info->attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT]);
                changed |= WIPHY_PARAM_TXQ_MEMORY_LIMIT;
 
        if (info->attrs[NL80211_ATTR_TXQ_QUANTUM]) {
                if (!wiphy_ext_feature_isset(&rdev->wiphy,
-                                            NL80211_EXT_FEATURE_TXQS))
-                       return -EOPNOTSUPP;
+                                            NL80211_EXT_FEATURE_TXQS)) {
+                       result = -EOPNOTSUPP;
+                       goto out;
+               }
                txq_quantum = nla_get_u32(
                        info->attrs[NL80211_ATTR_TXQ_QUANTUM]);
                changed |= WIPHY_PARAM_TXQ_QUANTUM;
                u8 old_coverage_class;
                u32 old_txq_limit, old_txq_memory_limit, old_txq_quantum;
 
-               if (!rdev->ops->set_wiphy_params)
-                       return -EOPNOTSUPP;
+               if (!rdev->ops->set_wiphy_params) {
+                       result = -EOPNOTSUPP;
+                       goto out;
+               }
 
                old_retry_short = rdev->wiphy.retry_short;
                old_retry_long = rdev->wiphy.retry_long;
                        rdev->wiphy.txq_limit = old_txq_limit;
                        rdev->wiphy.txq_memory_limit = old_txq_memory_limit;
                        rdev->wiphy.txq_quantum = old_txq_quantum;
-                       return result;
+                       goto out;
                }
        }
-       return 0;
+
+       result = 0;
+
+out:
+       wiphy_unlock(&rdev->wiphy);
+       return result;
 }
 
 static int nl80211_send_chandef(struct sk_buff *msg,
        if (!rdev->ops->del_virtual_intf)
                return -EOPNOTSUPP;
 
+       /*
+        * We hold RTNL, so this is safe, without RTNL opencount cannot
+        * reach 0, and thus the rdev cannot be deleted.
+        *
+        * We need to do it for the dev_close(), since that will call
+        * the netdev notifiers, and we need to acquire the mutex there
+        * but don't know if we get there from here or from some other
+        * place (e.g. "ip link set ... down").
+        */
+       mutex_unlock(&rdev->wiphy.mtx);
+
        /*
         * If we remove a wireless device without a netdev then clear
         * user_ptr[1] so that nl80211_post_doit won't dereference it
         */
        if (!wdev->netdev)
                info->user_ptr[1] = NULL;
+       else
+               dev_close(wdev->netdev);
+
+       mutex_lock(&rdev->wiphy.mtx);
 
        return rdev_del_virtual_intf(rdev, wdev);
 }
        int sta_idx = cb->args[2];
        int err;
 
-       rtnl_lock();
        err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
        if (err)
-               goto out_err;
+               return err;
+       /* nl80211_prepare_wdev_dump acquired it in the successful case */
+       __acquire(&rdev->wiphy.mtx);
 
        if (!wdev->netdev) {
                err = -EINVAL;
        cb->args[2] = sta_idx;
        err = skb->len;
  out_err:
-       rtnl_unlock();
+       wiphy_unlock(&rdev->wiphy);
 
        return err;
 }
        int path_idx = cb->args[2];
        int err;
 
-       rtnl_lock();
        err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
        if (err)
-               goto out_err;
+               return err;
+       /* nl80211_prepare_wdev_dump acquired it in the successful case */
+       __acquire(&rdev->wiphy.mtx);
 
        if (!rdev->ops->dump_mpath) {
                err = -EOPNOTSUPP;
        cb->args[2] = path_idx;
        err = skb->len;
  out_err:
-       rtnl_unlock();
+       wiphy_unlock(&rdev->wiphy);
        return err;
 }
 
        int path_idx = cb->args[2];
        int err;
 
-       rtnl_lock();
        err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
        if (err)
-               goto out_err;
+               return err;
+       /* nl80211_prepare_wdev_dump acquired it in the successful case */
+       __acquire(&rdev->wiphy.mtx);
 
        if (!rdev->ops->dump_mpp) {
                err = -EOPNOTSUPP;
        cb->args[2] = path_idx;
        err = skb->len;
  out_err:
-       rtnl_unlock();
+       wiphy_unlock(&rdev->wiphy);
        return err;
 }
 
        if (!hdr)
                goto put_failure;
 
+       rtnl_lock();
+
        if (info->attrs[NL80211_ATTR_WIPHY]) {
                bool self_managed;
 
                rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
                if (IS_ERR(rdev)) {
                        nlmsg_free(msg);
+                       rtnl_unlock();
                        return PTR_ERR(rdev);
                }
 
                /* a self-managed-reg device must have a private regdom */
                if (WARN_ON(!regdom && self_managed)) {
                        nlmsg_free(msg);
+                       rtnl_unlock();
                        return -EINVAL;
                }
 
        rcu_read_unlock();
 
        genlmsg_end(msg, hdr);
+       rtnl_unlock();
        return genlmsg_reply(msg, info);
 
 nla_put_failure_rcu:
        rcu_read_unlock();
 nla_put_failure:
+       rtnl_unlock();
 put_failure:
        nlmsg_free(msg);
        return -EMSGSIZE;
                        return -EINVAL;
        }
 
-       if (!reg_is_valid_request(alpha2))
-               return -EINVAL;
+       rtnl_lock();
+       if (!reg_is_valid_request(alpha2)) {
+               r = -EINVAL;
+               goto out;
+       }
 
        rd = kzalloc(struct_size(rd, reg_rules, num_rules), GFP_KERNEL);
-       if (!rd)
-               return -ENOMEM;
+       if (!rd) {
+               r = -ENOMEM;
+               goto out;
+       }
 
        rd->n_reg_rules = num_rules;
        rd->alpha2[0] = alpha2[0];
                }
        }
 
+       r = set_regdom(rd, REGD_SOURCE_CRDA);
        /* set_regdom takes ownership of rd */
-       return set_regdom(rd, REGD_SOURCE_CRDA);
+       rd = NULL;
  bad_reg:
        kfree(rd);
+ out:
+       rtnl_unlock();
        return r;
 }
 #endif /* CONFIG_CFG80211_CRDA_SUPPORT */
        struct net_device *dev = info->user_ptr[1];
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_csa_settings params;
-       /* csa_attrs is defined static to avoid waste of stack size - this
-        * function is called under RTNL lock, so this should not be a problem.
-        */
-       static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
+       struct nlattr **csa_attrs = NULL;
        int err;
        bool need_new_beacon = false;
        bool need_handle_dfs_flag = true;
        if (err)
                return err;
 
+       csa_attrs = kcalloc(NL80211_ATTR_MAX + 1, sizeof(*csa_attrs),
+                           GFP_KERNEL);
+       if (!csa_attrs)
+               return -ENOMEM;
+
        err = nla_parse_nested_deprecated(csa_attrs, NL80211_ATTR_MAX,
                                          info->attrs[NL80211_ATTR_CSA_IES],
                                          nl80211_policy, info->extack);
        if (err)
-               return err;
+               goto free;
 
        err = nl80211_parse_beacon(rdev, csa_attrs, ¶ms.beacon_csa);
        if (err)
-               return err;
+               goto free;
 
-       if (!csa_attrs[NL80211_ATTR_CNTDWN_OFFS_BEACON])
-               return -EINVAL;
+       if (!csa_attrs[NL80211_ATTR_CNTDWN_OFFS_BEACON]) {
+               err = -EINVAL;
+               goto free;
+       }
 
        len = nla_len(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_BEACON]);
-       if (!len || (len % sizeof(u16)))
-               return -EINVAL;
+       if (!len || (len % sizeof(u16))) {
+               err = -EINVAL;
+               goto free;
+       }
 
        params.n_counter_offsets_beacon = len / sizeof(u16);
        if (rdev->wiphy.max_num_csa_counters &&
            (params.n_counter_offsets_beacon >
-            rdev->wiphy.max_num_csa_counters))
-               return -EINVAL;
+            rdev->wiphy.max_num_csa_counters)) {
+               err = -EINVAL;
+               goto free;
+       }
 
        params.counter_offsets_beacon =
                nla_data(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_BEACON]);
        for (i = 0; i < params.n_counter_offsets_beacon; i++) {
                u16 offset = params.counter_offsets_beacon[i];
 
-               if (offset >= params.beacon_csa.tail_len)
-                       return -EINVAL;
+               if (offset >= params.beacon_csa.tail_len) {
+                       err = -EINVAL;
+                       goto free;
+               }
 
-               if (params.beacon_csa.tail[offset] != params.count)
-                       return -EINVAL;
+               if (params.beacon_csa.tail[offset] != params.count) {
+                       err = -EINVAL;
+                       goto free;
+               }
        }
 
        if (csa_attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP]) {
                len = nla_len(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP]);
-               if (!len || (len % sizeof(u16)))
-                       return -EINVAL;
+               if (!len || (len % sizeof(u16))) {
+                       err = -EINVAL;
+                       goto free;
+               }
 
                params.n_counter_offsets_presp = len / sizeof(u16);
                if (rdev->wiphy.max_num_csa_counters &&
                    (params.n_counter_offsets_presp >
-                    rdev->wiphy.max_num_csa_counters))
-                       return -EINVAL;
+                    rdev->wiphy.max_num_csa_counters)) {
+                       err = -EINVAL;
+                       goto free;
+               }
 
                params.counter_offsets_presp =
                        nla_data(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP]);
                for (i = 0; i < params.n_counter_offsets_presp; i++) {
                        u16 offset = params.counter_offsets_presp[i];
 
-                       if (offset >= params.beacon_csa.probe_resp_len)
-                               return -EINVAL;
+                       if (offset >= params.beacon_csa.probe_resp_len) {
+                               err = -EINVAL;
+                               goto free;
+                       }
 
                        if (params.beacon_csa.probe_resp[offset] !=
-                           params.count)
-                               return -EINVAL;
+                           params.count) {
+                               err = -EINVAL;
+                               goto free;
+                       }
                }
        }
 
 skip_beacons:
        err = nl80211_parse_chandef(rdev, info, ¶ms.chandef);
        if (err)
-               return err;
+               goto free;
 
        if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, ¶ms.chandef,
-                                          wdev->iftype))
-               return -EINVAL;
+                                          wdev->iftype)) {
+               err = -EINVAL;
+               goto free;
+       }
 
        err = cfg80211_chandef_dfs_required(wdev->wiphy,
                                            ¶ms.chandef,
                                            wdev->iftype);
        if (err < 0)
-               return err;
+               goto free;
 
        if (err > 0) {
                params.radar_required = true;
                if (need_handle_dfs_flag &&
                    !nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS])) {
-                       return -EINVAL;
+                       err = -EINVAL;
+                       goto free;
                }
        }
 
        err = rdev_channel_switch(rdev, dev, ¶ms);
        wdev_unlock(wdev);
 
+free:
+       kfree(csa_attrs);
        return err;
 }
 
        int start = cb->args[2], idx = 0;
        int err;
 
-       rtnl_lock();
        err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
-       if (err) {
-               rtnl_unlock();
+       if (err)
                return err;
-       }
+       /* nl80211_prepare_wdev_dump acquired it in the successful case */
+       __acquire(&rdev->wiphy.mtx);
 
        wdev_lock(wdev);
        spin_lock_bh(&rdev->bss_lock);
        wdev_unlock(wdev);
 
        cb->args[2] = idx;
-       rtnl_unlock();
+       wiphy_unlock(&rdev->wiphy);
 
        return skb->len;
 }
        if (!attrbuf)
                return -ENOMEM;
 
-       rtnl_lock();
        res = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
-       if (res)
-               goto out_err;
+       if (res) {
+               kfree(attrbuf);
+               return res;
+       }
+       /* nl80211_prepare_wdev_dump acquired it in the successful case */
+       __acquire(&rdev->wiphy.mtx);
 
        /* prepare_wdev_dump parsed the attributes */
        radio_stats = attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
        res = skb->len;
  out_err:
        kfree(attrbuf);
-       rtnl_unlock();
+       wiphy_unlock(&rdev->wiphy);
        return res;
 }
 
 static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
-       struct wireless_dev *wdev =
-               __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
+       struct wireless_dev *wdev;
        int err;
 
+       lockdep_assert_held(&rdev->wiphy.mtx);
+
+       wdev = __cfg80211_wdev_from_attrs(rdev, genl_info_net(info),
+                                         info->attrs);
+
        if (!rdev->ops->testmode_cmd)
                return -EOPNOTSUPP;
 
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct wireless_dev *wdev =
-               __cfg80211_wdev_from_attrs(genl_info_net(info), info->attrs);
+               __cfg80211_wdev_from_attrs(rdev, genl_info_net(info),
+                                          info->attrs);
        int i, err;
        u32 vid, subcmd;
 
                goto out;
        }
 
-       *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), attrbuf);
+       *wdev = __cfg80211_wdev_from_attrs(NULL, sock_net(skb->sk), attrbuf);
        if (IS_ERR(*wdev))
                *wdev = NULL;
 
 static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
                            struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = NULL;
        struct wireless_dev *wdev;
        struct net_device *dev;
-       bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL;
-
-       if (rtnl)
-               rtnl_lock();
 
+       rtnl_lock();
        if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
                rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
                if (IS_ERR(rdev)) {
-                       if (rtnl)
-                               rtnl_unlock();
+                       rtnl_unlock();
                        return PTR_ERR(rdev);
                }
                info->user_ptr[0] = rdev;
        } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV ||
                   ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
-               ASSERT_RTNL();
-
-               wdev = __cfg80211_wdev_from_attrs(genl_info_net(info),
+               wdev = __cfg80211_wdev_from_attrs(NULL, genl_info_net(info),
                                                  info->attrs);
                if (IS_ERR(wdev)) {
-                       if (rtnl)
-                               rtnl_unlock();
+                       rtnl_unlock();
                        return PTR_ERR(wdev);
                }
 
 
                if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
                        if (!dev) {
-                               if (rtnl)
-                                       rtnl_unlock();
+                               rtnl_unlock();
                                return -EINVAL;
                        }
 
 
                if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
                    !wdev_running(wdev)) {
-                       if (rtnl)
-                               rtnl_unlock();
+                       rtnl_unlock();
                        return -ENETDOWN;
                }
 
                info->user_ptr[0] = rdev;
        }
 
+       if (rdev) {
+               wiphy_lock(&rdev->wiphy);
+               /* we keep the mutex locked until post_doit */
+               __release(&rdev->wiphy.mtx);
+       }
+       if (!(ops->internal_flags & NL80211_FLAG_NEED_RTNL))
+               rtnl_unlock();
+
        return 0;
 }
 
                }
        }
 
+       if (info->user_ptr[0]) {
+               struct cfg80211_registered_device *rdev = info->user_ptr[0];
+
+               /* we kept the mutex locked since pre_doit */
+               __acquire(&rdev->wiphy.mtx);
+               wiphy_unlock(&rdev->wiphy);
+       }
+
        if (ops->internal_flags & NL80211_FLAG_NEED_RTNL)
                rtnl_unlock();
 
                .dumpit = nl80211_dump_wiphy,
                .done = nl80211_dump_wiphy_done,
                /* can be retrieved by unprivileged users */
-               .internal_flags = NL80211_FLAG_NEED_WIPHY |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY,
        },
 };
 
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_set_wiphy,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_GET_INTERFACE,
                .doit = nl80211_get_interface,
                .dumpit = nl80211_dump_interface,
                /* can be retrieved by unprivileged users */
-               .internal_flags = NL80211_FLAG_NEED_WDEV |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WDEV,
        },
        {
                .cmd = NL80211_CMD_SET_INTERFACE,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_get_key,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_SET_KEY,
                .doit = nl80211_set_key,
                .flags = GENL_UNS_ADMIN_PERM,
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL |
                                  NL80211_FLAG_CLEAR_SKB,
        },
        {
                .doit = nl80211_new_key,
                .flags = GENL_UNS_ADMIN_PERM,
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL |
                                  NL80211_FLAG_CLEAR_SKB,
        },
        {
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_del_key,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_SET_BEACON,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .flags = GENL_UNS_ADMIN_PERM,
                .doit = nl80211_set_beacon,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_START_AP,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .flags = GENL_UNS_ADMIN_PERM,
                .doit = nl80211_start_ap,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_STOP_AP,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .flags = GENL_UNS_ADMIN_PERM,
                .doit = nl80211_stop_ap,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_GET_STATION,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_get_station,
                .dumpit = nl80211_dump_station,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV,
        },
        {
                .cmd = NL80211_CMD_SET_STATION,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_set_station,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_NEW_STATION,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_new_station,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_DEL_STATION,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_del_station,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_GET_MPATH,
                .doit = nl80211_get_mpath,
                .dumpit = nl80211_dump_mpath,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_GET_MPP,
                .doit = nl80211_get_mpp,
                .dumpit = nl80211_dump_mpp,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_SET_MPATH,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_set_mpath,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_NEW_MPATH,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_new_mpath,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_DEL_MPATH,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_del_mpath,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_SET_BSS,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_set_bss,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_GET_REG,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_get_reg_do,
                .dumpit = nl80211_get_reg_dump,
-               .internal_flags = NL80211_FLAG_NEED_RTNL,
+               .internal_flags = 0,
                /* can be retrieved by unprivileged users */
        },
 #ifdef CONFIG_CFG80211_CRDA_SUPPORT
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_set_reg,
                .flags = GENL_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_RTNL,
+               .internal_flags = 0,
        },
 #endif
        {
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_get_mesh_config,
                /* can be retrieved by unprivileged users */
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_SET_MESH_CONFIG,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_update_mesh_config,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_TRIGGER_SCAN,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_trigger_scan,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
        },
        {
                .cmd = NL80211_CMD_ABORT_SCAN,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_abort_scan,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
        },
        {
                .cmd = NL80211_CMD_GET_SCAN,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_start_sched_scan,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_STOP_SCHED_SCAN,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_stop_sched_scan,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_AUTHENTICATE,
                .doit = nl80211_authenticate,
                .flags = GENL_UNS_ADMIN_PERM,
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL |
+                                 0 |
                                  NL80211_FLAG_CLEAR_SKB,
        },
        {
                .doit = nl80211_associate,
                .flags = GENL_UNS_ADMIN_PERM,
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL |
+                                 0 |
                                  NL80211_FLAG_CLEAR_SKB,
        },
        {
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_deauthenticate,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_DISASSOCIATE,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_disassociate,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_JOIN_IBSS,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_join_ibss,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_LEAVE_IBSS,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_leave_ibss,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
 #ifdef CONFIG_NL80211_TESTMODE
        {
                .doit = nl80211_testmode_do,
                .dumpit = nl80211_testmode_dump,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_WIPHY |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY,
        },
 #endif
        {
                .doit = nl80211_connect,
                .flags = GENL_UNS_ADMIN_PERM,
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL |
+                                 0 |
                                  NL80211_FLAG_CLEAR_SKB,
        },
        {
                .doit = nl80211_update_connect_params,
                .flags = GENL_ADMIN_PERM,
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL |
+                                 0 |
                                  NL80211_FLAG_CLEAR_SKB,
        },
        {
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_disconnect,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_SET_WIPHY_NETNS,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_wiphy_netns,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_WIPHY |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY,
        },
        {
                .cmd = NL80211_CMD_GET_SURVEY,
                .doit = nl80211_setdel_pmksa,
                .flags = GENL_UNS_ADMIN_PERM,
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL |
+                                 0 |
                                  NL80211_FLAG_CLEAR_SKB,
        },
        {
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_setdel_pmksa,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_FLUSH_PMKSA,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_flush_pmksa,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_remain_on_channel,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
        },
        {
                .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_cancel_remain_on_channel,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
        },
        {
                .cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_set_tx_bitrate_mask,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV,
        },
        {
                .cmd = NL80211_CMD_REGISTER_FRAME,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_register_mgmt,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_WDEV |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WDEV,
        },
        {
                .cmd = NL80211_CMD_FRAME,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_tx_mgmt,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
        },
        {
                .cmd = NL80211_CMD_FRAME_WAIT_CANCEL,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_tx_mgmt_cancel_wait,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
        },
        {
                .cmd = NL80211_CMD_SET_POWER_SAVE,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_set_power_save,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV,
        },
        {
                .cmd = NL80211_CMD_GET_POWER_SAVE,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_get_power_save,
                /* can be retrieved by unprivileged users */
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV,
        },
        {
                .cmd = NL80211_CMD_SET_CQM,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_set_cqm,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV,
        },
        {
                .cmd = NL80211_CMD_SET_CHANNEL,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_set_channel,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV,
        },
        {
                .cmd = NL80211_CMD_JOIN_MESH,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_join_mesh,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_LEAVE_MESH,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_leave_mesh,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_JOIN_OCB,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_join_ocb,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_LEAVE_OCB,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_leave_ocb,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
 #ifdef CONFIG_PM
        {
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_get_wowlan,
                /* can be retrieved by unprivileged users */
-               .internal_flags = NL80211_FLAG_NEED_WIPHY |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY,
        },
        {
                .cmd = NL80211_CMD_SET_WOWLAN,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_set_wowlan,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_WIPHY |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY,
        },
 #endif
        {
                .doit = nl80211_set_rekey_data,
                .flags = GENL_UNS_ADMIN_PERM,
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL |
+                                 0 |
                                  NL80211_FLAG_CLEAR_SKB,
        },
        {
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_tdls_mgmt,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_TDLS_OPER,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_tdls_oper,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_UNEXPECTED_FRAME,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_register_unexpected_frame,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV,
        },
        {
                .cmd = NL80211_CMD_PROBE_CLIENT,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_probe_client,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_REGISTER_BEACONS,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_register_beacons,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_WIPHY |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY,
        },
        {
                .cmd = NL80211_CMD_SET_NOACK_MAP,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_set_noack_map,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV,
        },
        {
                .cmd = NL80211_CMD_START_P2P_DEVICE,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_nan_add_func,
                .flags = GENL_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
        },
        {
                .cmd = NL80211_CMD_DEL_NAN_FUNCTION,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_nan_del_func,
                .flags = GENL_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
        },
        {
                .cmd = NL80211_CMD_CHANGE_NAN_CONFIG,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_nan_change_config,
                .flags = GENL_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
        },
        {
                .cmd = NL80211_CMD_SET_MCAST_RATE,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_set_mcast_rate,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV,
        },
        {
                .cmd = NL80211_CMD_SET_MAC_ACL,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_set_mac_acl,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV,
        },
        {
                .cmd = NL80211_CMD_RADAR_DETECT,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_start_radar_detection,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_update_ft_ies,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_CRIT_PROTOCOL_START,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_crit_protocol_start,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
        },
        {
                .cmd = NL80211_CMD_CRIT_PROTOCOL_STOP,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_crit_protocol_stop,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
        },
        {
                .cmd = NL80211_CMD_GET_COALESCE,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_get_coalesce,
-               .internal_flags = NL80211_FLAG_NEED_WIPHY |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY,
        },
        {
                .cmd = NL80211_CMD_SET_COALESCE,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_set_coalesce,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_WIPHY |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY,
        },
        {
                .cmd = NL80211_CMD_CHANNEL_SWITCH,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_channel_switch,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_VENDOR,
                .dumpit = nl80211_vendor_cmd_dump,
                .flags = GENL_UNS_ADMIN_PERM,
                .internal_flags = NL80211_FLAG_NEED_WIPHY |
-                                 NL80211_FLAG_NEED_RTNL |
+                                 0 |
                                  NL80211_FLAG_CLEAR_SKB,
        },
        {
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_set_qos_map,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_ADD_TX_TS,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_add_tx_ts,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_DEL_TX_TS,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_del_tx_ts,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_TDLS_CHANNEL_SWITCH,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_tdls_channel_switch,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_tdls_cancel_channel_switch,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_SET_MULTICAST_TO_UNICAST,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_set_multicast_to_unicast,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV,
        },
        {
                .cmd = NL80211_CMD_SET_PMK,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_set_pmk,
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL |
+                                 0 |
                                  NL80211_FLAG_CLEAR_SKB,
        },
        {
                .cmd = NL80211_CMD_DEL_PMK,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_del_pmk,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_EXTERNAL_AUTH,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_external_auth,
                .flags = GENL_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_CONTROL_PORT_FRAME,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_tx_control_port,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_GET_FTM_RESPONDER_STATS,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_get_ftm_responder_stats,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV,
        },
        {
                .cmd = NL80211_CMD_PEER_MEASUREMENT_START,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_pmsr_start,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_WDEV_UP,
        },
        {
                .cmd = NL80211_CMD_NOTIFY_RADAR,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = nl80211_notify_radar_detection,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_UPDATE_OWE_INFO,
                .doit = nl80211_update_owe_info,
                .flags = GENL_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_PROBE_MESH_LINK,
                .doit = nl80211_probe_mesh_link,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
        },
        {
                .cmd = NL80211_CMD_SET_TID_CONFIG,
                .doit = nl80211_set_tid_config,
                .flags = GENL_UNS_ADMIN_PERM,
-               .internal_flags = NL80211_FLAG_NEED_NETDEV |
-                                 NL80211_FLAG_NEED_RTNL,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV,
        },
        {
                .cmd = NL80211_CMD_SET_SAR_SPECS,
 
  * we directly assign the wireless handlers of wireless interfaces.
  *
  * Copyright 2008-2009 Johannes Berg <johannes@sipsolutions.net>
- * Copyright (C) 2019 Intel Corporation
+ * Copyright (C) 2019-2021 Intel Corporation
  */
 
 #include <linux/export.h>
        u32 orts = wdev->wiphy->rts_threshold;
        int err;
 
-       if (rts->disabled || !rts->fixed)
+       wiphy_lock(&rdev->wiphy);
+       if (rts->disabled || !rts->fixed) {
                wdev->wiphy->rts_threshold = (u32) -1;
-       else if (rts->value < 0)
-               return -EINVAL;
-       else
+       } else if (rts->value < 0) {
+               err = -EINVAL;
+               goto out;
+       } else {
                wdev->wiphy->rts_threshold = rts->value;
+       }
 
        err = rdev_set_wiphy_params(rdev, WIPHY_PARAM_RTS_THRESHOLD);
+
        if (err)
                wdev->wiphy->rts_threshold = orts;
 
+out:
+       wiphy_unlock(&rdev->wiphy);
        return err;
 }
 EXPORT_WEXT_HANDLER(cfg80211_wext_siwrts);
        u32 ofrag = wdev->wiphy->frag_threshold;
        int err;
 
-       if (frag->disabled || !frag->fixed)
+       wiphy_lock(&rdev->wiphy);
+       if (frag->disabled || !frag->fixed) {
                wdev->wiphy->frag_threshold = (u32) -1;
-       else if (frag->value < 256)
-               return -EINVAL;
-       else {
+       } else if (frag->value < 256) {
+               err = -EINVAL;
+               goto out;
+       } else {
                /* Fragment length must be even, so strip LSB. */
                wdev->wiphy->frag_threshold = frag->value & ~0x1;
        }
        err = rdev_set_wiphy_params(rdev, WIPHY_PARAM_FRAG_THRESHOLD);
        if (err)
                wdev->wiphy->frag_threshold = ofrag;
+out:
+       wiphy_unlock(&rdev->wiphy);
 
        return err;
 }
            (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
                return -EINVAL;
 
+       wiphy_lock(&rdev->wiphy);
        if (retry->flags & IW_RETRY_LONG) {
                wdev->wiphy->retry_long = retry->value;
                changed |= WIPHY_PARAM_RETRY_LONG;
                wdev->wiphy->retry_short = oshort;
                wdev->wiphy->retry_long = olong;
        }
+       wiphy_unlock(&rdev->wiphy);
 
        return err;
 }
            !rdev->ops->set_default_key)
                return -EOPNOTSUPP;
 
+       wiphy_lock(&rdev->wiphy);
        idx = erq->flags & IW_ENCODE_INDEX;
        if (idx == 0) {
                idx = wdev->wext.default_key;
                if (idx < 0)
                        idx = 0;
-       } else if (idx < 1 || idx > 4)
-               return -EINVAL;
-       else
+       } else if (idx < 1 || idx > 4) {
+               err = -EINVAL;
+               goto out;
+       } else {
                idx--;
+       }
 
        if (erq->flags & IW_ENCODE_DISABLED)
                remove = true;
                if (!err)
                        wdev->wext.default_key = idx;
                wdev_unlock(wdev);
-               return err;
+               goto out;
        }
 
        memset(¶ms, 0, sizeof(params));
        params.key = keybuf;
        params.key_len = erq->length;
-       if (erq->length == 5)
+       if (erq->length == 5) {
                params.cipher = WLAN_CIPHER_SUITE_WEP40;
-       else if (erq->length == 13)
+       } else if (erq->length == 13) {
                params.cipher = WLAN_CIPHER_SUITE_WEP104;
-       else if (!remove)
-               return -EINVAL;
+       } else if (!remove) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       err = cfg80211_set_encryption(rdev, dev, false, NULL, remove,
+                                     wdev->wext.default_key == -1,
+                                     idx, ¶ms);
+out:
+       wiphy_unlock(&rdev->wiphy);
 
-       return cfg80211_set_encryption(rdev, dev, false, NULL, remove,
-                                      wdev->wext.default_key == -1,
-                                      idx, ¶ms);
+       return err;
 }
 
 static int cfg80211_wext_siwencodeext(struct net_device *dev,
        struct cfg80211_chan_def chandef = {
                .width = NL80211_CHAN_WIDTH_20_NOHT,
        };
-       int freq;
+       int freq, ret;
+
+       wiphy_lock(&rdev->wiphy);
 
        switch (wdev->iftype) {
        case NL80211_IFTYPE_STATION:
-               return cfg80211_mgd_wext_siwfreq(dev, info, wextfreq, extra);
+               ret = cfg80211_mgd_wext_siwfreq(dev, info, wextfreq, extra);
+               break;
        case NL80211_IFTYPE_ADHOC:
-               return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra);
+               ret = cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra);
+               break;
        case NL80211_IFTYPE_MONITOR:
                freq = cfg80211_wext_freq(wextfreq);
-               if (freq < 0)
-                       return freq;
-               if (freq == 0)
-                       return -EINVAL;
+               if (freq < 0) {
+                       ret = freq;
+                       break;
+               }
+               if (freq == 0) {
+                       ret = -EINVAL;
+                       break;
+               }
                chandef.center_freq1 = freq;
                chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);
-               if (!chandef.chan)
-                       return -EINVAL;
-               return cfg80211_set_monitor_channel(rdev, &chandef);
+               if (!chandef.chan) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = cfg80211_set_monitor_channel(rdev, &chandef);
+               break;
        case NL80211_IFTYPE_MESH_POINT:
                freq = cfg80211_wext_freq(wextfreq);
-               if (freq < 0)
-                       return freq;
-               if (freq == 0)
-                       return -EINVAL;
+               if (freq < 0) {
+                       ret = freq;
+                       break;
+               }
+               if (freq == 0) {
+                       ret = -EINVAL;
+                       break;
+               }
                chandef.center_freq1 = freq;
                chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);
-               if (!chandef.chan)
-                       return -EINVAL;
-               return cfg80211_set_mesh_channel(rdev, wdev, &chandef);
+               if (!chandef.chan) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = cfg80211_set_mesh_channel(rdev, wdev, &chandef);
+               break;
        default:
-               return -EOPNOTSUPP;
+               ret = -EOPNOTSUPP;
+               break;
        }
+
+       wiphy_unlock(&rdev->wiphy);
+
+       return ret;
 }
 
 static int cfg80211_wext_giwfreq(struct net_device *dev,
        struct cfg80211_chan_def chandef = {};
        int ret;
 
+       wiphy_lock(&rdev->wiphy);
        switch (wdev->iftype) {
        case NL80211_IFTYPE_STATION:
-               return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
+               ret = cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
+               break;
        case NL80211_IFTYPE_ADHOC:
-               return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
+               ret = cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
+               break;
        case NL80211_IFTYPE_MONITOR:
-               if (!rdev->ops->get_channel)
-                       return -EINVAL;
+               if (!rdev->ops->get_channel) {
+                       ret = -EINVAL;
+                       break;
+               }
 
                ret = rdev_get_channel(rdev, wdev, &chandef);
                if (ret)
-                       return ret;
+                       break;
                freq->m = chandef.chan->center_freq;
                freq->e = 6;
-               return 0;
+               ret = 0;
+               break;
        default:
-               return -EINVAL;
+               ret = -EINVAL;
+               break;
        }
+
+       wiphy_unlock(&rdev->wiphy);
+
+       return ret;
 }
 
 static int cfg80211_wext_siwtxpower(struct net_device *dev,
        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        enum nl80211_tx_power_setting type;
        int dbm = 0;
+       int ret;
 
        if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
                return -EINVAL;
                return 0;
        }
 
-       return rdev_set_tx_power(rdev, wdev, type, DBM_TO_MBM(dbm));
+       wiphy_lock(&rdev->wiphy);
+       ret = rdev_set_tx_power(rdev, wdev, type, DBM_TO_MBM(dbm));
+       wiphy_unlock(&rdev->wiphy);
+
+       return ret;
 }
 
 static int cfg80211_wext_giwtxpower(struct net_device *dev,
        if (!rdev->ops->get_tx_power)
                return -EOPNOTSUPP;
 
+       wiphy_lock(&rdev->wiphy);
        err = rdev_get_tx_power(rdev, wdev, &val);
+       wiphy_unlock(&rdev->wiphy);
        if (err)
                return err;
 
                        timeout = wrq->value / 1000;
        }
 
+       wiphy_lock(&rdev->wiphy);
        err = rdev_set_power_mgmt(rdev, dev, ps, timeout);
+       wiphy_unlock(&rdev->wiphy);
        if (err)
                return err;
 
        struct cfg80211_bitrate_mask mask;
        u32 fixed, maxrate;
        struct ieee80211_supported_band *sband;
-       int band, ridx;
+       int band, ridx, ret;
        bool match = false;
 
        if (!rdev->ops->set_bitrate_mask)
        if (!match)
                return -EINVAL;
 
-       return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
+       wiphy_lock(&rdev->wiphy);
+       ret = rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
+       wiphy_unlock(&rdev->wiphy);
+
+       return ret;
 }
 
 static int cfg80211_wext_giwrate(struct net_device *dev,
        if (err)
                return err;
 
+       wiphy_lock(&rdev->wiphy);
        err = rdev_get_station(rdev, dev, addr, &sinfo);
+       wiphy_unlock(&rdev->wiphy);
        if (err)
                return err;
 
        static struct iw_statistics wstats;
        static struct station_info sinfo = {};
        u8 bssid[ETH_ALEN];
+       int ret;
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION)
                return NULL;
 
        memset(&sinfo, 0, sizeof(sinfo));
 
-       if (rdev_get_station(rdev, dev, bssid, &sinfo))
+       wiphy_lock(&rdev->wiphy);
+       ret = rdev_get_station(rdev, dev, bssid, &sinfo);
+       wiphy_unlock(&rdev->wiphy);
+
+       if (ret)
                return NULL;
 
        memset(&wstats, 0, sizeof(wstats));
                               struct sockaddr *ap_addr, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+       int ret;
 
+       wiphy_lock(&rdev->wiphy);
        switch (wdev->iftype) {
        case NL80211_IFTYPE_ADHOC:
-               return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
+               ret = cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
+               break;
        case NL80211_IFTYPE_STATION:
-               return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
+               ret = cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
+               break;
        default:
-               return -EOPNOTSUPP;
+               ret = -EOPNOTSUPP;
+               break;
        }
+       wiphy_unlock(&rdev->wiphy);
+
+       return ret;
 }
 
 static int cfg80211_wext_giwap(struct net_device *dev,
                               struct sockaddr *ap_addr, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+       int ret;
 
+       wiphy_lock(&rdev->wiphy);
        switch (wdev->iftype) {
        case NL80211_IFTYPE_ADHOC:
-               return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
+               ret = cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
+               break;
        case NL80211_IFTYPE_STATION:
-               return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
+               ret = cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
+               break;
        default:
-               return -EOPNOTSUPP;
+               ret = -EOPNOTSUPP;
+               break;
        }
+       wiphy_unlock(&rdev->wiphy);
+
+       return ret;
 }
 
 static int cfg80211_wext_siwessid(struct net_device *dev,
                                  struct iw_point *data, char *ssid)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+       int ret;
 
+       wiphy_lock(&rdev->wiphy);
        switch (wdev->iftype) {
        case NL80211_IFTYPE_ADHOC:
-               return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
+               ret = cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
+               break;
        case NL80211_IFTYPE_STATION:
-               return cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
+               ret = cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
+               break;
        default:
-               return -EOPNOTSUPP;
+               ret = -EOPNOTSUPP;
+               break;
        }
+       wiphy_unlock(&rdev->wiphy);
+
+       return ret;
 }
 
 static int cfg80211_wext_giwessid(struct net_device *dev,
                                  struct iw_point *data, char *ssid)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+       int ret;
 
        data->flags = 0;
        data->length = 0;
 
+       wiphy_lock(&rdev->wiphy);
        switch (wdev->iftype) {
        case NL80211_IFTYPE_ADHOC:
-               return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
+               ret = cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
+               break;
        case NL80211_IFTYPE_STATION:
-               return cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
+               ret = cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
+               break;
        default:
-               return -EOPNOTSUPP;
+               ret = -EOPNOTSUPP;
+               break;
        }
+       wiphy_unlock(&rdev->wiphy);
+
+       return ret;
 }
 
 static int cfg80211_wext_siwpmksa(struct net_device *dev,
        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
        struct cfg80211_pmksa cfg_pmksa;
        struct iw_pmksa *pmksa = (struct iw_pmksa *)extra;
+       int ret;
 
        memset(&cfg_pmksa, 0, sizeof(struct cfg80211_pmksa));
 
        cfg_pmksa.bssid = pmksa->bssid.sa_data;
        cfg_pmksa.pmkid = pmksa->pmkid;
 
+       wiphy_lock(&rdev->wiphy);
        switch (pmksa->cmd) {
        case IW_PMKSA_ADD:
-               if (!rdev->ops->set_pmksa)
-                       return -EOPNOTSUPP;
-
-               return rdev_set_pmksa(rdev, dev, &cfg_pmksa);
+               if (!rdev->ops->set_pmksa) {
+                       ret = -EOPNOTSUPP;
+                       break;
+               }
 
+               ret = rdev_set_pmksa(rdev, dev, &cfg_pmksa);
+               break;
        case IW_PMKSA_REMOVE:
-               if (!rdev->ops->del_pmksa)
-                       return -EOPNOTSUPP;
-
-               return rdev_del_pmksa(rdev, dev, &cfg_pmksa);
+               if (!rdev->ops->del_pmksa) {
+                       ret = -EOPNOTSUPP;
+                       break;
+               }
 
+               ret = rdev_del_pmksa(rdev, dev, &cfg_pmksa);
+               break;
        case IW_PMKSA_FLUSH:
-               if (!rdev->ops->flush_pmksa)
-                       return -EOPNOTSUPP;
-
-               return rdev_flush_pmksa(rdev, dev);
+               if (!rdev->ops->flush_pmksa) {
+                       ret = -EOPNOTSUPP;
+                       break;
+               }
 
+               ret = rdev_flush_pmksa(rdev, dev);
+               break;
        default:
-               return -EOPNOTSUPP;
+               ret = -EOPNOTSUPP;
+               break;
        }
+       wiphy_unlock(&rdev->wiphy);
+
+       return ret;
 }
 
 #define DEFINE_WEXT_COMPAT_STUB(func, type)                    \