]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - net/wireless/nl80211.c
Merge branch 'master' into csb1725
[mv-sheeva.git] / net / wireless / nl80211.c
index 37902a54e9c154fb8dbed3e1d996d8a198bdc17b..4e78e3f26798378bad69630679565b1909bfb370 100644 (file)
 #include "nl80211.h"
 #include "reg.h"
 
+static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
+                           struct genl_info *info);
+static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb,
+                             struct genl_info *info);
+
 /* the netlink family */
 static struct genl_family nl80211_fam = {
        .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */
@@ -31,6 +36,8 @@ static struct genl_family nl80211_fam = {
        .version = 1,           /* no particular meaning now */
        .maxattr = NL80211_ATTR_MAX,
        .netnsok = true,
+       .pre_doit = nl80211_pre_doit,
+       .post_doit = nl80211_post_doit,
 };
 
 /* internal helper: get rdev and dev */
@@ -86,6 +93,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
        [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
        [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
+       [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 },
 
        [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
        [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
@@ -136,6 +144,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
                .len = sizeof(struct nl80211_sta_flag_update),
        },
        [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG },
+       [NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 },
+       [NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG },
        [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG },
        [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
        [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
@@ -156,9 +166,10 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
 
        [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
        [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 },
+       [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 },
 };
 
-/* policy for the attributes */
+/* policy for the key attributes */
 static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
        [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
        [NL80211_KEY_IDX] = { .type = NLA_U8 },
@@ -166,6 +177,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
        [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
        [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
        [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
+       [NL80211_KEY_TYPE] = { .type = NLA_U32 },
 };
 
 /* ifidx get helper */
@@ -188,6 +200,47 @@ static int nl80211_get_ifidx(struct netlink_callback *cb)
        return res;
 }
 
+static int nl80211_prepare_netdev_dump(struct sk_buff *skb,
+                                      struct netlink_callback *cb,
+                                      struct cfg80211_registered_device **rdev,
+                                      struct net_device **dev)
+{
+       int ifidx = cb->args[0];
+       int err;
+
+       if (!ifidx)
+               ifidx = nl80211_get_ifidx(cb);
+       if (ifidx < 0)
+               return ifidx;
+
+       cb->args[0] = ifidx;
+
+       rtnl_lock();
+
+       *dev = __dev_get_by_index(sock_net(skb->sk), ifidx);
+       if (!*dev) {
+               err = -ENODEV;
+               goto out_rtnl;
+       }
+
+       *rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
+       if (IS_ERR(*rdev)) {
+               err = PTR_ERR(*rdev);
+               goto out_rtnl;
+       }
+
+       return 0;
+ out_rtnl:
+       rtnl_unlock();
+       return err;
+}
+
+static void nl80211_finish_netdev_dump(struct cfg80211_registered_device *rdev)
+{
+       cfg80211_unlock_rdev(rdev);
+       rtnl_unlock();
+}
+
 /* IE validation */
 static bool is_valid_ie_attr(const struct nlattr *attr)
 {
@@ -255,6 +308,7 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
 struct key_parse {
        struct key_params p;
        int idx;
+       int type;
        bool def, defmgmt;
 };
 
@@ -285,6 +339,12 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
        if (tb[NL80211_KEY_CIPHER])
                k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]);
 
+       if (tb[NL80211_KEY_TYPE]) {
+               k->type = nla_get_u32(tb[NL80211_KEY_TYPE]);
+               if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
+                       return -EINVAL;
+       }
+
        return 0;
 }
 
@@ -309,6 +369,12 @@ static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
        k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
        k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];
 
+       if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
+               k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
+               if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
+                       return -EINVAL;
+       }
+
        return 0;
 }
 
@@ -318,6 +384,7 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
 
        memset(k, 0, sizeof(*k));
        k->idx = -1;
+       k->type = -1;
 
        if (info->attrs[NL80211_ATTR_KEY])
                err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k);
@@ -382,7 +449,7 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
                } else if (parse.defmgmt)
                        goto error;
                err = cfg80211_validate_key_settings(rdev, &parse.p,
-                                                    parse.idx, NULL);
+                                                    parse.idx, false, NULL);
                if (err)
                        goto error;
                result->params[parse.idx].cipher = parse.p.cipher;
@@ -401,18 +468,17 @@ static int nl80211_key_allowed(struct wireless_dev *wdev)
 {
        ASSERT_WDEV_LOCK(wdev);
 
-       if (!netif_running(wdev->netdev))
-               return -ENETDOWN;
-
        switch (wdev->iftype) {
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_AP_VLAN:
+       case NL80211_IFTYPE_P2P_GO:
                break;
        case NL80211_IFTYPE_ADHOC:
                if (!wdev->current_bss)
                        return -ENOLINK;
                break;
        case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_P2P_CLIENT:
                if (wdev->sme_state != CFG80211_SME_CONNECTED)
                        return -ENOLINK;
                break;
@@ -437,6 +503,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        struct ieee80211_rate *rate;
        int i;
        u16 ifmodes = dev->wiphy.interface_modes;
+       const struct ieee80211_txrx_stypes *mgmt_stypes =
+                               dev->wiphy.mgmt_stypes;
 
        hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
        if (!hdr)
@@ -464,6 +532,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
                    dev->wiphy.max_scan_ie_len);
 
+       if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN);
+
        NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES,
                sizeof(u32) * dev->wiphy.n_cipher_suites,
                dev->wiphy.cipher_suites);
@@ -471,6 +542,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
                   dev->wiphy.max_num_pmkids);
 
+       if (dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE);
+
        nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
        if (!nl_modes)
                goto nla_put_failure;
@@ -587,12 +661,13 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        CMD(flush_pmksa, FLUSH_PMKSA);
        CMD(remain_on_channel, REMAIN_ON_CHANNEL);
        CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
-       CMD(action, ACTION);
+       CMD(mgmt_tx, FRAME);
        if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
                i++;
                NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
        }
        CMD(set_channel, SET_CHANNEL);
+       CMD(set_wds_peer, SET_WDS_PEER);
 
 #undef CMD
 
@@ -608,6 +683,55 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 
        nla_nest_end(msg, nl_cmds);
 
+       if (mgmt_stypes) {
+               u16 stypes;
+               struct nlattr *nl_ftypes, *nl_ifs;
+               enum nl80211_iftype ift;
+
+               nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES);
+               if (!nl_ifs)
+                       goto nla_put_failure;
+
+               for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
+                       nl_ftypes = nla_nest_start(msg, ift);
+                       if (!nl_ftypes)
+                               goto nla_put_failure;
+                       i = 0;
+                       stypes = mgmt_stypes[ift].tx;
+                       while (stypes) {
+                               if (stypes & 1)
+                                       NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE,
+                                                   (i << 4) | IEEE80211_FTYPE_MGMT);
+                               stypes >>= 1;
+                               i++;
+                       }
+                       nla_nest_end(msg, nl_ftypes);
+               }
+
+               nla_nest_end(msg, nl_ifs);
+
+               nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES);
+               if (!nl_ifs)
+                       goto nla_put_failure;
+
+               for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
+                       nl_ftypes = nla_nest_start(msg, ift);
+                       if (!nl_ftypes)
+                               goto nla_put_failure;
+                       i = 0;
+                       stypes = mgmt_stypes[ift].rx;
+                       while (stypes) {
+                               if (stypes & 1)
+                                       NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE,
+                                                   (i << 4) | IEEE80211_FTYPE_MGMT);
+                               stypes >>= 1;
+                               i++;
+                       }
+                       nla_nest_end(msg, nl_ftypes);
+               }
+               nla_nest_end(msg, nl_ifs);
+       }
+
        return genlmsg_end(msg, hdr);
 
  nla_put_failure:
@@ -644,28 +768,18 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
 static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
 {
        struct sk_buff *msg;
-       struct cfg80211_registered_device *dev;
-
-       dev = cfg80211_get_dev_from_info(info);
-       if (IS_ERR(dev))
-               return PTR_ERR(dev);
+       struct cfg80211_registered_device *dev = info->user_ptr[0];
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
        if (!msg)
-               goto out_err;
-
-       if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0)
-               goto out_free;
+               return -ENOMEM;
 
-       cfg80211_unlock_rdev(dev);
+       if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) {
+               nlmsg_free(msg);
+               return -ENOBUFS;
+       }
 
        return genlmsg_reply(msg, info);
-
- out_free:
-       nlmsg_free(msg);
- out_err:
-       cfg80211_unlock_rdev(dev);
-       return -ENOBUFS;
 }
 
 static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = {
@@ -709,7 +823,8 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
                wdev->iftype == NL80211_IFTYPE_AP ||
                wdev->iftype == NL80211_IFTYPE_WDS ||
                wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
-               wdev->iftype == NL80211_IFTYPE_MONITOR;
+               wdev->iftype == NL80211_IFTYPE_MONITOR ||
+               wdev->iftype == NL80211_IFTYPE_P2P_GO;
 }
 
 static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
@@ -753,38 +868,48 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
 
 static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *netdev;
-       int result;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *netdev = info->user_ptr[1];
 
-       rtnl_lock();
+       return __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info);
+}
 
-       result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev);
-       if (result)
-               goto unlock;
+static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       const u8 *bssid;
+
+       if (!info->attrs[NL80211_ATTR_MAC])
+               return -EINVAL;
 
-       result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info);
+       if (netif_running(dev))
+               return -EBUSY;
 
- unlock:
-       rtnl_unlock();
+       if (!rdev->ops->set_wds_peer)
+               return -EOPNOTSUPP;
 
-       return result;
+       if (wdev->iftype != NL80211_IFTYPE_WDS)
+               return -EOPNOTSUPP;
+
+       bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+       return rdev->ops->set_wds_peer(wdev->wiphy, dev, bssid);
 }
 
+
 static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev;
        struct net_device *netdev = NULL;
        struct wireless_dev *wdev;
-       int result, rem_txq_params = 0;
+       int result = 0, rem_txq_params = 0;
        struct nlattr *nl_txq_params;
        u32 changed;
        u8 retry_short = 0, retry_long = 0;
        u32 frag_threshold = 0, rts_threshold = 0;
        u8 coverage_class = 0;
 
-       rtnl_lock();
-
        /*
         * Try to find the wiphy and netdev. Normally this
         * function shouldn't need the netdev, but this is
@@ -811,8 +936,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                rdev = __cfg80211_rdev_from_info(info);
                if (IS_ERR(rdev)) {
                        mutex_unlock(&cfg80211_mutex);
-                       result = PTR_ERR(rdev);
-                       goto unlock;
+                       return PTR_ERR(rdev);
                }
                wdev = NULL;
                netdev = NULL;
@@ -994,8 +1118,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
        mutex_unlock(&rdev->mtx);
        if (netdev)
                dev_put(netdev);
- unlock:
-       rtnl_unlock();
        return result;
 }
 
@@ -1075,33 +1197,20 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
 static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
 {
        struct sk_buff *msg;
-       struct cfg80211_registered_device *dev;
-       struct net_device *netdev;
-       int err;
-
-       err = get_rdev_dev_by_info_ifindex(info, &dev, &netdev);
-       if (err)
-               return err;
+       struct cfg80211_registered_device *dev = info->user_ptr[0];
+       struct net_device *netdev = info->user_ptr[1];
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
        if (!msg)
-               goto out_err;
+               return -ENOMEM;
 
        if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0,
-                              dev, netdev) < 0)
-               goto out_free;
-
-       dev_put(netdev);
-       cfg80211_unlock_rdev(dev);
+                              dev, netdev) < 0) {
+               nlmsg_free(msg);
+               return -ENOBUFS;
+       }
 
        return genlmsg_reply(msg, info);
-
- out_free:
-       nlmsg_free(msg);
- out_err:
-       dev_put(netdev);
-       cfg80211_unlock_rdev(dev);
-       return -ENOBUFS;
 }
 
 static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
@@ -1161,39 +1270,29 @@ static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
 
 static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct vif_params params;
        int err;
        enum nl80211_iftype otype, ntype;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        u32 _flags, *flags = NULL;
        bool change = false;
 
        memset(&params, 0, sizeof(params));
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
        otype = ntype = dev->ieee80211_ptr->iftype;
 
        if (info->attrs[NL80211_ATTR_IFTYPE]) {
                ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
                if (otype != ntype)
                        change = true;
-               if (ntype > NL80211_IFTYPE_MAX) {
-                       err = -EINVAL;
-                       goto unlock;
-               }
+               if (ntype > NL80211_IFTYPE_MAX)
+                       return -EINVAL;
        }
 
        if (info->attrs[NL80211_ATTR_MESH_ID]) {
-               if (ntype != NL80211_IFTYPE_MESH_POINT) {
-                       err = -EINVAL;
-                       goto unlock;
-               }
+               if (ntype != NL80211_IFTYPE_MESH_POINT)
+                       return -EINVAL;
                params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
                params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
                change = true;
@@ -1204,20 +1303,18 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
                change = true;
                err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
                if (err)
-                       goto unlock;
+                       return err;
        } else {
                params.use_4addr = -1;
        }
 
        if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
-               if (ntype != NL80211_IFTYPE_MONITOR) {
-                       err = -EINVAL;
-                       goto unlock;
-               }
+               if (ntype != NL80211_IFTYPE_MONITOR)
+                       return -EINVAL;
                err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
                                          &_flags);
                if (err)
-                       goto unlock;
+                       return err;
 
                flags = &_flags;
                change = true;
@@ -1231,17 +1328,12 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
        if (!err && params.use_4addr != -1)
                dev->ieee80211_ptr->use_4addr = params.use_4addr;
 
- unlock:
-       dev_put(dev);
-       cfg80211_unlock_rdev(rdev);
- unlock_rtnl:
-       rtnl_unlock();
        return err;
 }
 
 static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct vif_params params;
        int err;
        enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
@@ -1258,19 +1350,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
                        return -EINVAL;
        }
 
-       rtnl_lock();
-
-       rdev = cfg80211_get_dev_from_info(info);
-       if (IS_ERR(rdev)) {
-               err = PTR_ERR(rdev);
-               goto unlock_rtnl;
-       }
-
        if (!rdev->ops->add_virtual_intf ||
-           !(rdev->wiphy.interface_modes & (1 << type))) {
-               err = -EOPNOTSUPP;
-               goto unlock;
-       }
+           !(rdev->wiphy.interface_modes & (1 << type)))
+               return -EOPNOTSUPP;
 
        if (type == NL80211_IFTYPE_MESH_POINT &&
            info->attrs[NL80211_ATTR_MESH_ID]) {
@@ -1282,7 +1364,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
                params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
                err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
                if (err)
-                       goto unlock;
+                       return err;
        }
 
        err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
@@ -1292,38 +1374,18 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
                nla_data(info->attrs[NL80211_ATTR_IFNAME]),
                type, err ? NULL : &flags, &params);
 
- unlock:
-       cfg80211_unlock_rdev(rdev);
- unlock_rtnl:
-       rtnl_unlock();
        return err;
 }
 
 static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
-
-       rtnl_lock();
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
 
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->del_virtual_intf) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       err = rdev->ops->del_virtual_intf(&rdev->wiphy, dev);
+       if (!rdev->ops->del_virtual_intf)
+               return -EOPNOTSUPP;
 
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- unlock_rtnl:
-       rtnl_unlock();
-       return err;
+       return rdev->ops->del_virtual_intf(&rdev->wiphy, dev);
 }
 
 struct get_key_cookie {
@@ -1376,11 +1438,12 @@ static void get_key_callback(void *c, struct key_params *params)
 
 static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        int err;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        u8 key_idx = 0;
-       u8 *mac_addr = NULL;
+       const u8 *mac_addr = NULL;
+       bool pairwise;
        struct get_key_cookie cookie = {
                .error = 0,
        };
@@ -1396,30 +1459,28 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_MAC])
                mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->get_key) {
-               err = -EOPNOTSUPP;
-               goto out;
+       pairwise = !!mac_addr;
+       if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
+               u32 kt = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
+               if (kt >= NUM_NL80211_KEYTYPES)
+                       return -EINVAL;
+               if (kt != NL80211_KEYTYPE_GROUP &&
+                   kt != NL80211_KEYTYPE_PAIRWISE)
+                       return -EINVAL;
+               pairwise = kt == NL80211_KEYTYPE_PAIRWISE;
        }
 
+       if (!rdev->ops->get_key)
+               return -EOPNOTSUPP;
+
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg) {
-               err = -ENOMEM;
-               goto out;
-       }
+       if (!msg)
+               return -ENOMEM;
 
        hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
                             NL80211_CMD_NEW_KEY);
-
-       if (IS_ERR(hdr)) {
-               err = PTR_ERR(hdr);
-               goto free_msg;
-       }
+       if (IS_ERR(hdr))
+               return PTR_ERR(hdr);
 
        cookie.msg = msg;
        cookie.idx = key_idx;
@@ -1429,8 +1490,12 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
        if (mac_addr)
                NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
 
-       err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, mac_addr,
-                               &cookie, get_key_callback);
+       if (pairwise && mac_addr &&
+           !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
+               return -ENOENT;
+
+       err = rdev->ops->get_key(&rdev->wiphy, dev, key_idx, pairwise,
+                                mac_addr, &cookie, get_key_callback);
 
        if (err)
                goto free_msg;
@@ -1439,28 +1504,21 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
                goto nla_put_failure;
 
        genlmsg_end(msg, hdr);
-       err = genlmsg_reply(msg, info);
-       goto out;
+       return genlmsg_reply(msg, info);
 
  nla_put_failure:
        err = -ENOBUFS;
  free_msg:
        nlmsg_free(msg);
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- unlock_rtnl:
-       rtnl_unlock();
-
        return err;
 }
 
 static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct key_parse key;
        int err;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        int (*func)(struct wiphy *wiphy, struct net_device *netdev,
                    u8 key_index);
 
@@ -1475,21 +1533,13 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
        if (!key.def && !key.defmgmt)
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
        if (key.def)
                func = rdev->ops->set_default_key;
        else
                func = rdev->ops->set_default_mgmt_key;
 
-       if (!func) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!func)
+               return -EOPNOTSUPP;
 
        wdev_lock(dev->ieee80211_ptr);
        err = nl80211_key_allowed(dev->ieee80211_ptr);
@@ -1506,23 +1556,16 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
 #endif
        wdev_unlock(dev->ieee80211_ptr);
 
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-
- unlock_rtnl:
-       rtnl_unlock();
-
        return err;
 }
 
 static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        int err;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        struct key_parse key;
-       u8 *mac_addr = NULL;
+       const u8 *mac_addr = NULL;
 
        err = nl80211_parse_key(info, &key);
        if (err)
@@ -1534,43 +1577,42 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_MAC])
                mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       rtnl_lock();
+       if (key.type == -1) {
+               if (mac_addr)
+                       key.type = NL80211_KEYTYPE_PAIRWISE;
+               else
+                       key.type = NL80211_KEYTYPE_GROUP;
+       }
 
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
+       /* for now */
+       if (key.type != NL80211_KEYTYPE_PAIRWISE &&
+           key.type != NL80211_KEYTYPE_GROUP)
+               return -EINVAL;
 
-       if (!rdev->ops->add_key) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->add_key)
+               return -EOPNOTSUPP;
 
-       if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) {
-               err = -EINVAL;
-               goto out;
-       }
+       if (cfg80211_validate_key_settings(rdev, &key.p, key.idx,
+                                          key.type == NL80211_KEYTYPE_PAIRWISE,
+                                          mac_addr))
+               return -EINVAL;
 
        wdev_lock(dev->ieee80211_ptr);
        err = nl80211_key_allowed(dev->ieee80211_ptr);
        if (!err)
                err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx,
+                                        key.type == NL80211_KEYTYPE_PAIRWISE,
                                         mac_addr, &key.p);
        wdev_unlock(dev->ieee80211_ptr);
 
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- unlock_rtnl:
-       rtnl_unlock();
-
        return err;
 }
 
 static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        int err;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        u8 *mac_addr = NULL;
        struct key_parse key;
 
@@ -1581,21 +1623,32 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_MAC])
                mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       rtnl_lock();
+       if (key.type == -1) {
+               if (mac_addr)
+                       key.type = NL80211_KEYTYPE_PAIRWISE;
+               else
+                       key.type = NL80211_KEYTYPE_GROUP;
+       }
 
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
+       /* for now */
+       if (key.type != NL80211_KEYTYPE_PAIRWISE &&
+           key.type != NL80211_KEYTYPE_GROUP)
+               return -EINVAL;
 
-       if (!rdev->ops->del_key) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->del_key)
+               return -EOPNOTSUPP;
 
        wdev_lock(dev->ieee80211_ptr);
        err = nl80211_key_allowed(dev->ieee80211_ptr);
+
+       if (key.type == NL80211_KEYTYPE_PAIRWISE && mac_addr &&
+           !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
+               err = -ENOENT;
+
        if (!err)
-               err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
+               err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx,
+                                        key.type == NL80211_KEYTYPE_PAIRWISE,
+                                        mac_addr);
 
 #ifdef CONFIG_CFG80211_WEXT
        if (!err) {
@@ -1607,13 +1660,6 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
 #endif
        wdev_unlock(dev->ieee80211_ptr);
 
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-
- unlock_rtnl:
-       rtnl_unlock();
-
        return err;
 }
 
@@ -1621,35 +1667,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
 {
         int (*call)(struct wiphy *wiphy, struct net_device *dev,
                    struct beacon_parameters *info);
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct beacon_parameters params;
        int haveinfo = 0;
 
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]))
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EOPNOTSUPP;
 
        switch (info->genlhdr->cmd) {
        case NL80211_CMD_NEW_BEACON:
                /* these are required for NEW_BEACON */
                if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
                    !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
-                   !info->attrs[NL80211_ATTR_BEACON_HEAD]) {
-                       err = -EINVAL;
-                       goto out;
-               }
+                   !info->attrs[NL80211_ATTR_BEACON_HEAD])
+                       return -EINVAL;
 
                call = rdev->ops->add_beacon;
                break;
@@ -1658,14 +1694,11 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
                break;
        default:
                WARN_ON(1);
-               err = -EOPNOTSUPP;
-               goto out;
+               return -EOPNOTSUPP;
        }
 
-       if (!call) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!call)
+               return -EOPNOTSUPP;
 
        memset(&params, 0, sizeof(params));
 
@@ -1695,52 +1728,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
                haveinfo = 1;
        }
 
-       if (!haveinfo) {
-               err = -EINVAL;
-               goto out;
-       }
-
-       err = call(&rdev->wiphy, dev, &params);
-
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- unlock_rtnl:
-       rtnl_unlock();
+       if (!haveinfo)
+               return -EINVAL;
 
-       return err;
+       return call(&rdev->wiphy, dev, &params);
 }
 
 static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
-
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->del_beacon) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
 
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-       err = rdev->ops->del_beacon(&rdev->wiphy, dev);
+       if (!rdev->ops->del_beacon)
+               return -EOPNOTSUPP;
 
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- unlock_rtnl:
-       rtnl_unlock();
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EOPNOTSUPP;
 
-       return err;
+       return rdev->ops->del_beacon(&rdev->wiphy, dev);
 }
 
 static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
@@ -1861,6 +1867,12 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
        if (sinfo->filled & STATION_INFO_TX_PACKETS)
                NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS,
                            sinfo->tx_packets);
+       if (sinfo->filled & STATION_INFO_TX_RETRIES)
+               NLA_PUT_U32(msg, NL80211_STA_INFO_TX_RETRIES,
+                           sinfo->tx_retries);
+       if (sinfo->filled & STATION_INFO_TX_FAILED)
+               NLA_PUT_U32(msg, NL80211_STA_INFO_TX_FAILED,
+                           sinfo->tx_failed);
        nla_nest_end(msg, sinfoattr);
 
        return genlmsg_end(msg, hdr);
@@ -1877,28 +1889,12 @@ static int nl80211_dump_station(struct sk_buff *skb,
        struct cfg80211_registered_device *dev;
        struct net_device *netdev;
        u8 mac_addr[ETH_ALEN];
-       int ifidx = cb->args[0];
        int sta_idx = cb->args[1];
        int err;
 
-       if (!ifidx)
-               ifidx = nl80211_get_ifidx(cb);
-       if (ifidx < 0)
-               return ifidx;
-
-       rtnl_lock();
-
-       netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
-       if (!netdev) {
-               err = -ENODEV;
-               goto out_rtnl;
-       }
-
-       dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
-       if (IS_ERR(dev)) {
-               err = PTR_ERR(dev);
-               goto out_rtnl;
-       }
+       err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev);
+       if (err)
+               return err;
 
        if (!dev->ops->dump_station) {
                err = -EOPNOTSUPP;
@@ -1928,21 +1924,19 @@ static int nl80211_dump_station(struct sk_buff *skb,
        cb->args[1] = sta_idx;
        err = skb->len;
  out_err:
-       cfg80211_unlock_rdev(dev);
- out_rtnl:
-       rtnl_unlock();
+       nl80211_finish_netdev_dump(dev);
 
        return err;
 }
 
 static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct station_info sinfo;
        struct sk_buff *msg;
        u8 *mac_addr = NULL;
+       int err;
 
        memset(&sinfo, 0, sizeof(sinfo));
 
@@ -1951,41 +1945,24 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
 
        mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
-       if (!rdev->ops->get_station) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->get_station)
+               return -EOPNOTSUPP;
 
        err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo);
        if (err)
-               goto out;
+               return err;
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
        if (!msg)
-               goto out;
+               return -ENOMEM;
 
        if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0,
-                                dev, mac_addr, &sinfo) < 0)
-               goto out_free;
-
-       err = genlmsg_reply(msg, info);
-       goto out;
-
- out_free:
-       nlmsg_free(msg);
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
+                                dev, mac_addr, &sinfo) < 0) {
+               nlmsg_free(msg);
+               return -ENOBUFS;
+       }
 
-       return err;
+       return genlmsg_reply(msg, info);
 }
 
 /*
@@ -2015,9 +1992,9 @@ static int get_vlan(struct genl_info *info,
 
 static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        int err;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        struct station_parameters params;
        u8 *mac_addr = NULL;
 
@@ -2055,12 +2032,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
                params.plink_action =
                    nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
        err = get_vlan(info, rdev, &params.vlan);
        if (err)
                goto out;
@@ -2071,10 +2042,12 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
        switch (dev->ieee80211_ptr->iftype) {
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_AP_VLAN:
+       case NL80211_IFTYPE_P2P_GO:
                /* disallow mesh-specific things */
                if (params.plink_action)
                        err = -EINVAL;
                break;
+       case NL80211_IFTYPE_P2P_CLIENT:
        case NL80211_IFTYPE_STATION:
                /* disallow everything but AUTHORIZED flag */
                if (params.plink_action)
@@ -2120,19 +2093,15 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
  out:
        if (params.vlan)
                dev_put(params.vlan);
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
 
        return err;
 }
 
 static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        int err;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        struct station_parameters params;
        u8 *mac_addr = NULL;
 
@@ -2169,17 +2138,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
        if (parse_station_flags(info, &params))
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) {
-               err = -EINVAL;
-               goto out;
-       }
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EINVAL;
 
        err = get_vlan(info, rdev, &params.vlan);
        if (err)
@@ -2193,61 +2155,33 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
-
        err = rdev->ops->add_station(&rdev->wiphy, dev, mac_addr, &params);
 
  out:
        if (params.vlan)
                dev_put(params.vlan);
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
-
        return err;
 }
 
 static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        u8 *mac_addr = NULL;
 
        if (info->attrs[NL80211_ATTR_MAC])
                mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
-               err = -EINVAL;
-               goto out;
-       }
-
-       if (!rdev->ops->del_station) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       err = rdev->ops->del_station(&rdev->wiphy, dev, mac_addr);
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EINVAL;
 
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
+       if (!rdev->ops->del_station)
+               return -EOPNOTSUPP;
 
-       return err;
+       return rdev->ops->del_station(&rdev->wiphy, dev, mac_addr);
 }
 
 static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq,
@@ -2310,28 +2244,12 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
        struct net_device *netdev;
        u8 dst[ETH_ALEN];
        u8 next_hop[ETH_ALEN];
-       int ifidx = cb->args[0];
        int path_idx = cb->args[1];
        int err;
 
-       if (!ifidx)
-               ifidx = nl80211_get_ifidx(cb);
-       if (ifidx < 0)
-               return ifidx;
-
-       rtnl_lock();
-
-       netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
-       if (!netdev) {
-               err = -ENODEV;
-               goto out_rtnl;
-       }
-
-       dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
-       if (IS_ERR(dev)) {
-               err = PTR_ERR(dev);
-               goto out_rtnl;
-       }
+       err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev);
+       if (err)
+               return err;
 
        if (!dev->ops->dump_mpath) {
                err = -EOPNOTSUPP;
@@ -2365,18 +2283,15 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
        cb->args[1] = path_idx;
        err = skb->len;
  out_err:
-       cfg80211_unlock_rdev(dev);
- out_rtnl:
-       rtnl_unlock();
-
+       nl80211_finish_netdev_dump(dev);
        return err;
 }
 
 static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        int err;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        struct mpath_info pinfo;
        struct sk_buff *msg;
        u8 *dst = NULL;
@@ -2389,53 +2304,33 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
 
        dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
-       if (!rdev->ops->get_mpath) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->get_mpath)
+               return -EOPNOTSUPP;
 
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+               return -EOPNOTSUPP;
 
        err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo);
        if (err)
-               goto out;
+               return err;
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
        if (!msg)
-               goto out;
+               return -ENOMEM;
 
        if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0,
-                                dev, dst, next_hop, &pinfo) < 0)
-               goto out_free;
-
-       err = genlmsg_reply(msg, info);
-       goto out;
-
- out_free:
-       nlmsg_free(msg);
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
+                                dev, dst, next_hop, &pinfo) < 0) {
+               nlmsg_free(msg);
+               return -ENOBUFS;
+       }
 
-       return err;
+       return genlmsg_reply(msg, info);
 }
 
 static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        u8 *dst = NULL;
        u8 *next_hop = NULL;
 
@@ -2448,42 +2343,19 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
        dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
        next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
-       if (!rdev->ops->change_mpath) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
-
-       err = rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop);
+       if (!rdev->ops->change_mpath)
+               return -EOPNOTSUPP;
 
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+               return -EOPNOTSUPP;
 
-       return err;
+       return rdev->ops->change_mpath(&rdev->wiphy, dev, dst, next_hop);
 }
+
 static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        u8 *dst = NULL;
        u8 *next_hop = NULL;
 
@@ -2496,75 +2368,34 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
        dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
        next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
-       if (!rdev->ops->add_mpath) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
-
-       err = rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop);
+       if (!rdev->ops->add_mpath)
+               return -EOPNOTSUPP;
 
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+               return -EOPNOTSUPP;
 
-       return err;
+       return rdev->ops->add_mpath(&rdev->wiphy, dev, dst, next_hop);
 }
 
 static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        u8 *dst = NULL;
 
        if (info->attrs[NL80211_ATTR_MAC])
                dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       rtnl_lock();
+       if (!rdev->ops->del_mpath)
+               return -EOPNOTSUPP;
 
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
-       if (!rdev->ops->del_mpath) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       err = rdev->ops->del_mpath(&rdev->wiphy, dev, dst);
-
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
-
-       return err;
-}
+       return rdev->ops->del_mpath(&rdev->wiphy, dev, dst);
+}
 
 static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct bss_parameters params;
 
        memset(&params, 0, sizeof(params));
@@ -2592,31 +2423,14 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_AP_ISOLATE])
                params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]);
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
-       if (!rdev->ops->change_bss) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       err = rdev->ops->change_bss(&rdev->wiphy, dev, &params);
+       if (!rdev->ops->change_bss)
+               return -EOPNOTSUPP;
 
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EOPNOTSUPP;
 
-       return err;
+       return rdev->ops->change_bss(&rdev->wiphy, dev, &params);
 }
 
 static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
@@ -2695,37 +2509,26 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
 static int nl80211_get_mesh_params(struct sk_buff *skb,
        struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct mesh_config cur_params;
        int err;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        void *hdr;
        struct nlattr *pinfoattr;
        struct sk_buff *msg;
 
-       rtnl_lock();
-
-       /* Look up our device */
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
-       if (!rdev->ops->get_mesh_params) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->get_mesh_params)
+               return -EOPNOTSUPP;
 
        /* Get the mesh params */
        err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params);
        if (err)
-               goto out;
+               return err;
 
        /* Draw up a netlink message to send back */
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg) {
-               err = -ENOBUFS;
-               goto out;
-       }
+       if (!msg)
+               return -ENOMEM;
        hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
                             NL80211_CMD_GET_MESH_PARAMS);
        if (!hdr)
@@ -2764,21 +2567,12 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
                        cur_params.dot11MeshHWMPRootMode);
        nla_nest_end(msg, pinfoattr);
        genlmsg_end(msg, hdr);
-       err = genlmsg_reply(msg, info);
-       goto out;
+       return genlmsg_reply(msg, info);
 
  nla_put_failure:
        genlmsg_cancel(msg, hdr);
        nlmsg_free(msg);
-       err = -EMSGSIZE;
- out:
-       /* Cleanup */
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
-
-       return err;
+       return -ENOBUFS;
 }
 
 #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \
@@ -2808,10 +2602,9 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
 
 static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
 {
-       int err;
        u32 mask;
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct mesh_config cfg;
        struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
        struct nlattr *parent_attr;
@@ -2823,16 +2616,8 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
                        parent_attr, nl80211_meshconf_params_policy))
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
-       if (!rdev->ops->set_mesh_params) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->set_mesh_params)
+               return -EOPNOTSUPP;
 
        /* This makes sure that there aren't more than 32 mesh config
         * parameters (otherwise our bitfield scheme would not work.) */
@@ -2878,16 +2663,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
                        nla_get_u8);
 
        /* Apply changes */
-       err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask);
-
- out:
-       /* cleanup */
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
-
-       return err;
+       return rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask);
 }
 
 #undef FILL_IN_MESH_PARAM_IF_SET
@@ -3070,8 +2846,8 @@ static int validate_scan_freqs(struct nlattr *freqs)
 
 static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct cfg80211_scan_request *request;
        struct cfg80211_ssid *ssid;
        struct ieee80211_channel *channel;
@@ -3084,36 +2860,19 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
        wiphy = &rdev->wiphy;
 
-       if (!rdev->ops->scan) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+       if (!rdev->ops->scan)
+               return -EOPNOTSUPP;
 
-       if (rdev->scan_req) {
-               err = -EBUSY;
-               goto out;
-       }
+       if (rdev->scan_req)
+               return -EBUSY;
 
        if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
                n_channels = validate_scan_freqs(
                                info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
-               if (!n_channels) {
-                       err = -EINVAL;
-                       goto out;
-               }
+               if (!n_channels)
+                       return -EINVAL;
        } else {
                n_channels = 0;
 
@@ -3126,29 +2885,23 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
                        n_ssids++;
 
-       if (n_ssids > wiphy->max_scan_ssids) {
-               err = -EINVAL;
-               goto out;
-       }
+       if (n_ssids > wiphy->max_scan_ssids)
+               return -EINVAL;
 
        if (info->attrs[NL80211_ATTR_IE])
                ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
        else
                ie_len = 0;
 
-       if (ie_len > wiphy->max_scan_ie_len) {
-               err = -EINVAL;
-               goto out;
-       }
+       if (ie_len > wiphy->max_scan_ie_len)
+               return -EINVAL;
 
        request = kzalloc(sizeof(*request)
                        + sizeof(*ssid) * n_ssids
                        + sizeof(channel) * n_channels
                        + ie_len, GFP_KERNEL);
-       if (!request) {
-               err = -ENOMEM;
-               goto out;
-       }
+       if (!request)
+               return -ENOMEM;
 
        if (n_ssids)
                request->ssids = (void *)&request->channels[n_channels];
@@ -3236,18 +2989,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        if (!err) {
                nl80211_send_scan_start(rdev, dev);
                dev_hold(dev);
-       }
-
+       } else {
  out_free:
-       if (err) {
                rdev->scan_req = NULL;
                kfree(request);
        }
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
 
        return err;
 }
@@ -3306,6 +3052,7 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        }
 
        switch (wdev->iftype) {
+       case NL80211_IFTYPE_P2P_CLIENT:
        case NL80211_IFTYPE_STATION:
                if (intbss == wdev->current_bss)
                        NLA_PUT_U32(msg, NL80211_BSS_STATUS,
@@ -3343,25 +3090,12 @@ static int nl80211_dump_scan(struct sk_buff *skb,
        struct net_device *dev;
        struct cfg80211_internal_bss *scan;
        struct wireless_dev *wdev;
-       int ifidx = cb->args[0];
        int start = cb->args[1], idx = 0;
        int err;
 
-       if (!ifidx)
-               ifidx = nl80211_get_ifidx(cb);
-       if (ifidx < 0)
-               return ifidx;
-       cb->args[0] = ifidx;
-
-       dev = dev_get_by_index(sock_net(skb->sk), ifidx);
-       if (!dev)
-               return -ENODEV;
-
-       rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
-       if (IS_ERR(rdev)) {
-               err = PTR_ERR(rdev);
-               goto out_put_netdev;
-       }
+       err = nl80211_prepare_netdev_dump(skb, cb, &rdev, &dev);
+       if (err)
+               return err;
 
        wdev = dev->ieee80211_ptr;
 
@@ -3377,21 +3111,17 @@ static int nl80211_dump_scan(struct sk_buff *skb,
                                cb->nlh->nlmsg_seq, NLM_F_MULTI,
                                rdev, wdev, scan) < 0) {
                        idx--;
-                       goto out;
+                       break;
                }
        }
 
- out:
        spin_unlock_bh(&rdev->bss_lock);
        wdev_unlock(wdev);
 
        cb->args[1] = idx;
-       err = skb->len;
-       cfg80211_unlock_rdev(rdev);
- out_put_netdev:
-       dev_put(dev);
+       nl80211_finish_netdev_dump(rdev);
 
-       return err;
+       return skb->len;
 }
 
 static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq,
@@ -3421,6 +3151,23 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq,
        if (survey->filled & SURVEY_INFO_NOISE_DBM)
                NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE,
                            survey->noise);
+       if (survey->filled & SURVEY_INFO_IN_USE)
+               NLA_PUT_FLAG(msg, NL80211_SURVEY_INFO_IN_USE);
+       if (survey->filled & SURVEY_INFO_CHANNEL_TIME)
+               NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME,
+                           survey->channel_time);
+       if (survey->filled & SURVEY_INFO_CHANNEL_TIME_BUSY)
+               NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY,
+                           survey->channel_time_busy);
+       if (survey->filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY)
+               NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY,
+                           survey->channel_time_ext_busy);
+       if (survey->filled & SURVEY_INFO_CHANNEL_TIME_RX)
+               NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_RX,
+                           survey->channel_time_rx);
+       if (survey->filled & SURVEY_INFO_CHANNEL_TIME_TX)
+               NLA_PUT_U64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_TX,
+                           survey->channel_time_tx);
 
        nla_nest_end(msg, infoattr);
 
@@ -3437,29 +3184,12 @@ static int nl80211_dump_survey(struct sk_buff *skb,
        struct survey_info survey;
        struct cfg80211_registered_device *dev;
        struct net_device *netdev;
-       int ifidx = cb->args[0];
        int survey_idx = cb->args[1];
        int res;
 
-       if (!ifidx)
-               ifidx = nl80211_get_ifidx(cb);
-       if (ifidx < 0)
-               return ifidx;
-       cb->args[0] = ifidx;
-
-       rtnl_lock();
-
-       netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
-       if (!netdev) {
-               res = -ENODEV;
-               goto out_rtnl;
-       }
-
-       dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
-       if (IS_ERR(dev)) {
-               res = PTR_ERR(dev);
-               goto out_rtnl;
-       }
+       res = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev);
+       if (res)
+               return res;
 
        if (!dev->ops->dump_survey) {
                res = -EOPNOTSUPP;
@@ -3487,10 +3217,7 @@ static int nl80211_dump_survey(struct sk_buff *skb,
        cb->args[1] = survey_idx;
        res = skb->len;
  out_err:
-       cfg80211_unlock_rdev(dev);
- out_rtnl:
-       rtnl_unlock();
-
+       nl80211_finish_netdev_dump(dev);
        return res;
 }
 
@@ -3523,8 +3250,8 @@ static bool nl80211_valid_cipher_suite(u32 cipher)
 
 static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct ieee80211_channel *chan;
        const u8 *bssid, *ssid, *ie = NULL;
        int err, ssid_len, ie_len = 0;
@@ -3552,6 +3279,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
                return err;
 
        if (key.idx >= 0) {
+               if (key.type != -1 && key.type != NL80211_KEYTYPE_GROUP)
+                       return -EINVAL;
                if (!key.p.key || !key.p.key_len)
                        return -EINVAL;
                if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
@@ -3566,34 +3295,31 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
                key.p.key = NULL;
        }
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->auth) {
-               err = -EOPNOTSUPP;
-               goto out;
+       if (key.idx >= 0) {
+               int i;
+               bool ok = false;
+               for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) {
+                       if (key.p.cipher == rdev->wiphy.cipher_suites[i]) {
+                               ok = true;
+                               break;
+                       }
+               }
+               if (!ok)
+                       return -EINVAL;
        }
 
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->auth)
+               return -EOPNOTSUPP;
 
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
 
        bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
        chan = ieee80211_get_channel(&rdev->wiphy,
                nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
-       if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) {
-               err = -EINVAL;
-               goto out;
-       }
+       if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED))
+               return -EINVAL;
 
        ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
        ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
@@ -3604,27 +3330,19 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
        }
 
        auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
-       if (!nl80211_valid_auth_type(auth_type)) {
-               err = -EINVAL;
-               goto out;
-       }
+       if (!nl80211_valid_auth_type(auth_type))
+               return -EINVAL;
 
        local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
 
-       err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
-                                ssid, ssid_len, ie, ie_len,
-                                key.p.key, key.p.key_len, key.idx,
-                                local_state_change);
-
-out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-unlock_rtnl:
-       rtnl_unlock();
-       return err;
+       return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
+                                 ssid, ssid_len, ie, ie_len,
+                                 key.p.key, key.p.key_len, key.idx,
+                                 local_state_change);
 }
 
-static int nl80211_crypto_settings(struct genl_info *info,
+static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
+                                  struct genl_info *info,
                                   struct cfg80211_crypto_settings *settings,
                                   int cipher_limit)
 {
@@ -3632,6 +3350,19 @@ static int nl80211_crypto_settings(struct genl_info *info,
 
        settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
 
+       if (info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]) {
+               u16 proto;
+               proto = nla_get_u16(
+                       info->attrs[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]);
+               settings->control_port_ethertype = cpu_to_be16(proto);
+               if (!(rdev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
+                   proto != ETH_P_PAE)
+                       return -EINVAL;
+               if (info->attrs[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT])
+                       settings->control_port_no_encrypt = true;
+       } else
+               settings->control_port_ethertype = cpu_to_be16(ETH_P_PAE);
+
        if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
                void *data;
                int len, i;
@@ -3691,8 +3422,8 @@ static int nl80211_crypto_settings(struct genl_info *info,
 
 static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct cfg80211_crypto_settings crypto;
        struct ieee80211_channel *chan;
        const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
@@ -3707,35 +3438,19 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
            !info->attrs[NL80211_ATTR_WIPHY_FREQ])
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->assoc) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->assoc)
+               return -EOPNOTSUPP;
 
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
 
        bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
        chan = ieee80211_get_channel(&rdev->wiphy,
                nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
-       if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) {
-               err = -EINVAL;
-               goto out;
-       }
+       if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED))
+               return -EINVAL;
 
        ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
        ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
@@ -3750,35 +3465,28 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
                        nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
                if (mfp == NL80211_MFP_REQUIRED)
                        use_mfp = true;
-               else if (mfp != NL80211_MFP_NO) {
-                       err = -EINVAL;
-                       goto out;
-               }
+               else if (mfp != NL80211_MFP_NO)
+                       return -EINVAL;
        }
 
        if (info->attrs[NL80211_ATTR_PREV_BSSID])
                prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
 
-       err = nl80211_crypto_settings(info, &crypto, 1);
+       err = nl80211_crypto_settings(rdev, info, &crypto, 1);
        if (!err)
                err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
                                          ssid, ssid_len, ie, ie_len, use_mfp,
                                          &crypto);
 
-out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-unlock_rtnl:
-       rtnl_unlock();
        return err;
 }
 
 static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        const u8 *ie = NULL, *bssid;
-       int err, ie_len = 0;
+       int ie_len = 0;
        u16 reason_code;
        bool local_state_change;
 
@@ -3791,34 +3499,19 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
        if (!info->attrs[NL80211_ATTR_REASON_CODE])
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->deauth) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->deauth)
+               return -EOPNOTSUPP;
 
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
 
        bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
        reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
        if (reason_code == 0) {
                /* Reason Code 0 is reserved */
-               err = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
 
        if (info->attrs[NL80211_ATTR_IE]) {
@@ -3828,23 +3521,16 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
 
        local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
 
-       err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
-                                  local_state_change);
-
-out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-unlock_rtnl:
-       rtnl_unlock();
-       return err;
+       return cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
+                                   local_state_change);
 }
 
 static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        const u8 *ie = NULL, *bssid;
-       int err, ie_len = 0;
+       int ie_len = 0;
        u16 reason_code;
        bool local_state_change;
 
@@ -3857,34 +3543,19 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
        if (!info->attrs[NL80211_ATTR_REASON_CODE])
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->disassoc) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->disassoc)
+               return -EOPNOTSUPP;
 
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
 
        bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
        reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
        if (reason_code == 0) {
                /* Reason Code 0 is reserved */
-               err = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
 
        if (info->attrs[NL80211_ATTR_IE]) {
@@ -3894,21 +3565,14 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
 
        local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
 
-       err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
-                                    local_state_change);
-
-out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-unlock_rtnl:
-       rtnl_unlock();
-       return err;
+       return cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
+                                     local_state_change);
 }
 
 static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct cfg80211_ibss_params ibss;
        struct wiphy *wiphy;
        struct cfg80211_cached_keys *connkeys = NULL;
@@ -3933,26 +3597,11 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
                        return -EINVAL;
        }
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->join_ibss) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->join_ibss)
+               return -EOPNOTSUPP;
 
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
+               return -EOPNOTSUPP;
 
        wiphy = &rdev->wiphy;
 
@@ -3970,24 +3619,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
                nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
        if (!ibss.channel ||
            ibss.channel->flags & IEEE80211_CHAN_NO_IBSS ||
-           ibss.channel->flags & IEEE80211_CHAN_DISABLED) {
-               err = -EINVAL;
-               goto out;
-       }
+           ibss.channel->flags & IEEE80211_CHAN_DISABLED)
+               return -EINVAL;
 
        ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
        ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
 
-       if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
-               connkeys = nl80211_parse_connkeys(rdev,
-                                       info->attrs[NL80211_ATTR_KEYS]);
-               if (IS_ERR(connkeys)) {
-                       err = PTR_ERR(connkeys);
-                       connkeys = NULL;
-                       goto out;
-               }
-       }
-
        if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
                u8 *rates =
                        nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
@@ -3997,10 +3634,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
                        wiphy->bands[ibss.channel->band];
                int i, j;
 
-               if (n_rates == 0) {
-                       err = -EINVAL;
-                       goto out;
-               }
+               if (n_rates == 0)
+                       return -EINVAL;
 
                for (i = 0; i < n_rates; i++) {
                        int rate = (rates[i] & 0x7f) * 5;
@@ -4013,77 +3648,36 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
                                        break;
                                }
                        }
-                       if (!found) {
-                               err = -EINVAL;
-                               goto out;
-                       }
-               }
-       } else {
-               /*
-               * If no rates were explicitly configured,
-               * use the mandatory rate set for 11b or
-               * 11a for maximum compatibility.
-               */
-               struct ieee80211_supported_band *sband =
-                       wiphy->bands[ibss.channel->band];
-               int j;
-               u32 flag = ibss.channel->band == IEEE80211_BAND_5GHZ ?
-                       IEEE80211_RATE_MANDATORY_A :
-                       IEEE80211_RATE_MANDATORY_B;
-
-               for (j = 0; j < sband->n_bitrates; j++) {
-                       if (sband->bitrates[j].flags & flag)
-                               ibss.basic_rates |= BIT(j);
+                       if (!found)
+                               return -EINVAL;
                }
        }
 
-       err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
+       if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
+               connkeys = nl80211_parse_connkeys(rdev,
+                                       info->attrs[NL80211_ATTR_KEYS]);
+               if (IS_ERR(connkeys))
+                       return PTR_ERR(connkeys);
+       }
 
-out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-unlock_rtnl:
+       err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
        if (err)
                kfree(connkeys);
-       rtnl_unlock();
        return err;
 }
 
 static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
-       int err;
-
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->leave_ibss) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
 
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+       if (!rdev->ops->leave_ibss)
+               return -EOPNOTSUPP;
 
-       err = cfg80211_leave_ibss(rdev, dev, false);
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
+               return -EOPNOTSUPP;
 
-out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-unlock_rtnl:
-       rtnl_unlock();
-       return err;
+       return cfg80211_leave_ibss(rdev, dev, false);
 }
 
 #ifdef CONFIG_NL80211_TESTMODE
@@ -4093,20 +3687,12 @@ static struct genl_multicast_group nl80211_testmode_mcgrp = {
 
 static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        int err;
 
        if (!info->attrs[NL80211_ATTR_TESTDATA])
                return -EINVAL;
 
-       rtnl_lock();
-
-       rdev = cfg80211_get_dev_from_info(info);
-       if (IS_ERR(rdev)) {
-               err = PTR_ERR(rdev);
-               goto unlock_rtnl;
-       }
-
        err = -EOPNOTSUPP;
        if (rdev->ops->testmode_cmd) {
                rdev->testmode_info = info;
@@ -4116,10 +3702,6 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
                rdev->testmode_info = NULL;
        }
 
-       cfg80211_unlock_rdev(rdev);
-
- unlock_rtnl:
-       rtnl_unlock();
        return err;
 }
 
@@ -4210,8 +3792,8 @@ EXPORT_SYMBOL(cfg80211_testmode_event);
 
 static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct cfg80211_connect_params connect;
        struct wiphy *wiphy;
        struct cfg80211_cached_keys *connkeys = NULL;
@@ -4236,25 +3818,14 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
 
        connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];
 
-       err = nl80211_crypto_settings(info, &connect.crypto,
+       err = nl80211_crypto_settings(rdev, info, &connect.crypto,
                                      NL80211_MAX_NR_CIPHER_SUITES);
        if (err)
                return err;
-       rtnl_lock();
 
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
 
        wiphy = &rdev->wiphy;
 
@@ -4273,39 +3844,27 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
                        ieee80211_get_channel(wiphy,
                            nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
                if (!connect.channel ||
-                   connect.channel->flags & IEEE80211_CHAN_DISABLED) {
-                       err = -EINVAL;
-                       goto out;
-               }
+                   connect.channel->flags & IEEE80211_CHAN_DISABLED)
+                       return -EINVAL;
        }
 
        if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
                connkeys = nl80211_parse_connkeys(rdev,
                                        info->attrs[NL80211_ATTR_KEYS]);
-               if (IS_ERR(connkeys)) {
-                       err = PTR_ERR(connkeys);
-                       connkeys = NULL;
-                       goto out;
-               }
+               if (IS_ERR(connkeys))
+                       return PTR_ERR(connkeys);
        }
 
        err = cfg80211_connect(rdev, dev, &connect, connkeys);
-
-out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-unlock_rtnl:
        if (err)
                kfree(connkeys);
-       rtnl_unlock();
        return err;
 }
 
 static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
-       int err;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        u16 reason;
 
        if (!info->attrs[NL80211_ATTR_REASON_CODE])
@@ -4316,35 +3875,16 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
        if (reason == 0)
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
-
-       err = cfg80211_disconnect(rdev, dev, reason, true);
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
 
-out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-unlock_rtnl:
-       rtnl_unlock();
-       return err;
+       return cfg80211_disconnect(rdev, dev, reason, true);
 }
 
 static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct net *net;
        int err;
        u32 pid;
@@ -4354,43 +3894,26 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
 
        pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]);
 
-       rtnl_lock();
-
-       rdev = cfg80211_get_dev_from_info(info);
-       if (IS_ERR(rdev)) {
-               err = PTR_ERR(rdev);
-               goto out_rtnl;
-       }
-
        net = get_net_ns_by_pid(pid);
-       if (IS_ERR(net)) {
-               err = PTR_ERR(net);
-               goto out;
-       }
+       if (IS_ERR(net))
+               return PTR_ERR(net);
 
        err = 0;
 
        /* check if anything to do */
-       if (net_eq(wiphy_net(&rdev->wiphy), net))
-               goto out_put_net;
+       if (!net_eq(wiphy_net(&rdev->wiphy), net))
+               err = cfg80211_switch_netns(rdev, net);
 
-       err = cfg80211_switch_netns(rdev, net);
- out_put_net:
        put_net(net);
- out:
-       cfg80211_unlock_rdev(rdev);
- out_rtnl:
-       rtnl_unlock();
        return err;
 }
 
 static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev,
                        struct cfg80211_pmksa *pmksa) = NULL;
-       int err;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        struct cfg80211_pmksa pmksa;
 
        memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
@@ -4401,19 +3924,12 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
        if (!info->attrs[NL80211_ATTR_PMKID])
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
        pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
        pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
 
        switch (info->genlhdr->cmd) {
        case NL80211_CMD_SET_PMKSA:
@@ -4427,61 +3943,32 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
                break;
        }
 
-       if (!rdev_ops) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       err = rdev_ops(&rdev->wiphy, dev, &pmksa);
-
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
+       if (!rdev_ops)
+               return -EOPNOTSUPP;
 
-       return err;
+       return rdev_ops(&rdev->wiphy, dev, &pmksa);
 }
 
 static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       int err;
-       struct net_device *dev;
-
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto out_rtnl;
-
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!rdev->ops->flush_pmksa) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       err = rdev->ops->flush_pmksa(&rdev->wiphy, dev);
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
 
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- out_rtnl:
-       rtnl_unlock();
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
 
-       return err;
+       if (!rdev->ops->flush_pmksa)
+               return -EOPNOTSUPP;
 
+       return rdev->ops->flush_pmksa(&rdev->wiphy, dev);
 }
 
 static int nl80211_remain_on_channel(struct sk_buff *skb,
                                     struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct ieee80211_channel *chan;
        struct sk_buff *msg;
        void *hdr;
@@ -4503,21 +3990,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
        if (!duration || !msecs_to_jiffies(duration) || duration > 5000)
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->remain_on_channel) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+       if (!rdev->ops->remain_on_channel)
+               return -EOPNOTSUPP;
 
        if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
                channel_type = nla_get_u32(
@@ -4525,24 +3999,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
                if (channel_type != NL80211_CHAN_NO_HT &&
                    channel_type != NL80211_CHAN_HT20 &&
                    channel_type != NL80211_CHAN_HT40PLUS &&
-                   channel_type != NL80211_CHAN_HT40MINUS) {
-                       err = -EINVAL;
-                       goto out;
-               }
+                   channel_type != NL80211_CHAN_HT40MINUS)
+                       return -EINVAL;
        }
 
        freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
        chan = rdev_freq_to_chan(rdev, freq, channel_type);
-       if (chan == NULL) {
-               err = -EINVAL;
-               goto out;
-       }
+       if (chan == NULL)
+               return -EINVAL;
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg) {
-               err = -ENOMEM;
-               goto out;
-       }
+       if (!msg)
+               return -ENOMEM;
 
        hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
                             NL80211_CMD_REMAIN_ON_CHANNEL);
@@ -4561,58 +4029,32 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
        NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
 
        genlmsg_end(msg, hdr);
-       err = genlmsg_reply(msg, info);
-       goto out;
+
+       return genlmsg_reply(msg, info);
 
  nla_put_failure:
        err = -ENOBUFS;
  free_msg:
        nlmsg_free(msg);
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- unlock_rtnl:
-       rtnl_unlock();
        return err;
 }
 
 static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
                                            struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        u64 cookie;
-       int err;
 
        if (!info->attrs[NL80211_ATTR_COOKIE])
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->cancel_remain_on_channel) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+       if (!rdev->ops->cancel_remain_on_channel)
+               return -EOPNOTSUPP;
 
        cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
 
-       err = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie);
-
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- unlock_rtnl:
-       rtnl_unlock();
-       return err;
+       return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie);
 }
 
 static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
@@ -4648,26 +4090,18 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
                                       struct genl_info *info)
 {
        struct nlattr *tb[NL80211_TXRATE_MAX + 1];
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct cfg80211_bitrate_mask mask;
-       int err, rem, i;
-       struct net_device *dev;
+       int rem, i;
+       struct net_device *dev = info->user_ptr[1];
        struct nlattr *tx_rates;
        struct ieee80211_supported_band *sband;
 
        if (info->attrs[NL80211_ATTR_TX_RATES] == NULL)
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->set_bitrate_mask) {
-               err = -EOPNOTSUPP;
-               goto unlock;
-       }
+       if (!rdev->ops->set_bitrate_mask)
+               return -EOPNOTSUPP;
 
        memset(&mask, 0, sizeof(mask));
        /* Default to all rates enabled */
@@ -4684,15 +4118,11 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
        nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem)
        {
                enum ieee80211_band band = nla_type(tx_rates);
-               if (band < 0 || band >= IEEE80211_NUM_BANDS) {
-                       err = -EINVAL;
-                       goto unlock;
-               }
+               if (band < 0 || band >= IEEE80211_NUM_BANDS)
+                       return -EINVAL;
                sband = rdev->wiphy.bands[band];
-               if (sband == NULL) {
-                       err = -EINVAL;
-                       goto unlock;
-               }
+               if (sband == NULL)
+                       return -EINVAL;
                nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
                          nla_len(tx_rates), nl80211_txattr_policy);
                if (tb[NL80211_TXRATE_LEGACY]) {
@@ -4700,68 +4130,48 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
                                sband,
                                nla_data(tb[NL80211_TXRATE_LEGACY]),
                                nla_len(tb[NL80211_TXRATE_LEGACY]));
-                       if (mask.control[band].legacy == 0) {
-                               err = -EINVAL;
-                               goto unlock;
-                       }
+                       if (mask.control[band].legacy == 0)
+                               return -EINVAL;
                }
        }
 
-       err = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask);
-
- unlock:
-       dev_put(dev);
-       cfg80211_unlock_rdev(rdev);
- unlock_rtnl:
-       rtnl_unlock();
-       return err;
+       return rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask);
 }
 
-static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
-       int err;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
+       u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION;
 
        if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
                return -EINVAL;
 
-       if (nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]) < 1)
-               return -EINVAL;
-
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
+       if (info->attrs[NL80211_ATTR_FRAME_TYPE])
+               frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EOPNOTSUPP;
 
        /* not much point in registering if we can't reply */
-       if (!rdev->ops->action) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->mgmt_tx)
+               return -EOPNOTSUPP;
 
-       err = cfg80211_mlme_register_action(dev->ieee80211_ptr, info->snd_pid,
+       return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid,
+                       frame_type,
                        nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
                        nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
- unlock_rtnl:
-       rtnl_unlock();
-       return err;
 }
 
-static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
-       struct net_device *dev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
        struct ieee80211_channel *chan;
        enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
        bool channel_type_valid = false;
@@ -4775,27 +4185,16 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
            !info->attrs[NL80211_ATTR_WIPHY_FREQ])
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
-       if (!rdev->ops->action) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->mgmt_tx)
+               return -EOPNOTSUPP;
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       if (!netif_running(dev)) {
-               err = -ENETDOWN;
-               goto out;
-       }
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EOPNOTSUPP;
 
        if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
                channel_type = nla_get_u32(
@@ -4803,147 +4202,104 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
                if (channel_type != NL80211_CHAN_NO_HT &&
                    channel_type != NL80211_CHAN_HT20 &&
                    channel_type != NL80211_CHAN_HT40PLUS &&
-                   channel_type != NL80211_CHAN_HT40MINUS) {
-                       err = -EINVAL;
-                       goto out;
-               }
+                   channel_type != NL80211_CHAN_HT40MINUS)
+                       return -EINVAL;
                channel_type_valid = true;
        }
 
        freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
        chan = rdev_freq_to_chan(rdev, freq, channel_type);
-       if (chan == NULL) {
-               err = -EINVAL;
-               goto out;
-       }
+       if (chan == NULL)
+               return -EINVAL;
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg) {
-               err = -ENOMEM;
-               goto out;
-       }
+       if (!msg)
+               return -ENOMEM;
 
        hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
-                            NL80211_CMD_ACTION);
+                            NL80211_CMD_FRAME);
 
        if (IS_ERR(hdr)) {
                err = PTR_ERR(hdr);
                goto free_msg;
        }
-       err = cfg80211_mlme_action(rdev, dev, chan, channel_type,
-                                  channel_type_valid,
-                                  nla_data(info->attrs[NL80211_ATTR_FRAME]),
-                                  nla_len(info->attrs[NL80211_ATTR_FRAME]),
-                                  &cookie);
+       err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, channel_type,
+                                   channel_type_valid,
+                                   nla_data(info->attrs[NL80211_ATTR_FRAME]),
+                                   nla_len(info->attrs[NL80211_ATTR_FRAME]),
+                                   &cookie);
        if (err)
                goto free_msg;
 
        NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
 
        genlmsg_end(msg, hdr);
-       err = genlmsg_reply(msg, info);
-       goto out;
+       return genlmsg_reply(msg, info);
 
  nla_put_failure:
        err = -ENOBUFS;
  free_msg:
        nlmsg_free(msg);
- out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-unlock_rtnl:
-       rtnl_unlock();
        return err;
 }
 
 static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct wireless_dev *wdev;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        u8 ps_state;
        bool state;
        int err;
 
-       if (!info->attrs[NL80211_ATTR_PS_STATE]) {
-               err = -EINVAL;
-               goto out;
-       }
+       if (!info->attrs[NL80211_ATTR_PS_STATE])
+               return -EINVAL;
 
        ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]);
 
-       if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) {
-               err = -EINVAL;
-               goto out;
-       }
-
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rdev;
+       if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED)
+               return -EINVAL;
 
        wdev = dev->ieee80211_ptr;
 
-       if (!rdev->ops->set_power_mgmt) {
-               err = -EOPNOTSUPP;
-               goto unlock_rdev;
-       }
+       if (!rdev->ops->set_power_mgmt)
+               return -EOPNOTSUPP;
 
        state = (ps_state == NL80211_PS_ENABLED) ? true : false;
 
        if (state == wdev->ps)
-               goto unlock_rdev;
-
-       wdev->ps = state;
-
-       if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, wdev->ps,
-                                     wdev->ps_timeout))
-               /* assume this means it's off */
-               wdev->ps = false;
-
-unlock_rdev:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-       rtnl_unlock();
+               return 0;
 
-out:
+       err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, state,
+                                       wdev->ps_timeout);
+       if (!err)
+               wdev->ps = state;
        return err;
 }
 
 static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        enum nl80211_ps_state ps_state;
        struct wireless_dev *wdev;
-       struct net_device *dev;
+       struct net_device *dev = info->user_ptr[1];
        struct sk_buff *msg;
        void *hdr;
        int err;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rtnl;
-
        wdev = dev->ieee80211_ptr;
 
-       if (!rdev->ops->set_power_mgmt) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!rdev->ops->set_power_mgmt)
+               return -EOPNOTSUPP;
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg) {
-               err = -ENOMEM;
-               goto out;
-       }
+       if (!msg)
+               return -ENOMEM;
 
        hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
                             NL80211_CMD_GET_POWER_SAVE);
        if (!hdr) {
-               err = -ENOMEM;
+               err = -ENOBUFS;
                goto free_msg;
        }
 
@@ -4955,22 +4311,12 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
        NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state);
 
        genlmsg_end(msg, hdr);
-       err = genlmsg_reply(msg, info);
-       goto out;
+       return genlmsg_reply(msg, info);
 
-nla_put_failure:
+ nla_put_failure:
        err = -ENOBUFS;
-
-free_msg:
+ free_msg:
        nlmsg_free(msg);
-
-out:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-
-unlock_rtnl:
-       rtnl_unlock();
-
        return err;
 }
 
@@ -4984,41 +4330,24 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = {
 static int nl80211_set_cqm_rssi(struct genl_info *info,
                                s32 threshold, u32 hysteresis)
 {
-       struct cfg80211_registered_device *rdev;
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct wireless_dev *wdev;
-       struct net_device *dev;
-       int err;
+       struct net_device *dev = info->user_ptr[1];
 
        if (threshold > 0)
                return -EINVAL;
 
-       rtnl_lock();
-
-       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
-       if (err)
-               goto unlock_rdev;
-
        wdev = dev->ieee80211_ptr;
 
-       if (!rdev->ops->set_cqm_rssi_config) {
-               err = -EOPNOTSUPP;
-               goto unlock_rdev;
-       }
-
-       if (wdev->iftype != NL80211_IFTYPE_STATION) {
-               err = -EOPNOTSUPP;
-               goto unlock_rdev;
-       }
-
-       err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev,
-                                            threshold, hysteresis);
+       if (!rdev->ops->set_cqm_rssi_config)
+               return -EOPNOTSUPP;
 
-unlock_rdev:
-       cfg80211_unlock_rdev(rdev);
-       dev_put(dev);
-       rtnl_unlock();
+       if (wdev->iftype != NL80211_IFTYPE_STATION &&
+           wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return -EOPNOTSUPP;
 
-       return err;
+       return rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev,
+                                             threshold, hysteresis);
 }
 
 static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
@@ -5052,6 +4381,65 @@ out:
        return err;
 }
 
+#define NL80211_FLAG_NEED_WIPHY                0x01
+#define NL80211_FLAG_NEED_NETDEV       0x02
+#define NL80211_FLAG_NEED_RTNL         0x04
+#define NL80211_FLAG_CHECK_NETDEV_UP   0x08
+#define NL80211_FLAG_NEED_NETDEV_UP    (NL80211_FLAG_NEED_NETDEV |\
+                                        NL80211_FLAG_CHECK_NETDEV_UP)
+
+static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
+                           struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev;
+       struct net_device *dev;
+       int err;
+       bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL;
+
+       if (rtnl)
+               rtnl_lock();
+
+       if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
+               rdev = cfg80211_get_dev_from_info(info);
+               if (IS_ERR(rdev)) {
+                       if (rtnl)
+                               rtnl_unlock();
+                       return PTR_ERR(rdev);
+               }
+               info->user_ptr[0] = rdev;
+       } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
+               err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
+               if (err) {
+                       if (rtnl)
+                               rtnl_unlock();
+                       return err;
+               }
+               if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
+                   !netif_running(dev)) {
+                       cfg80211_unlock_rdev(rdev);
+                       dev_put(dev);
+                       if (rtnl)
+                               rtnl_unlock();
+                       return -ENETDOWN;
+               }
+               info->user_ptr[0] = rdev;
+               info->user_ptr[1] = dev;
+       }
+
+       return 0;
+}
+
+static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb,
+                             struct genl_info *info)
+{
+       if (info->user_ptr[0])
+               cfg80211_unlock_rdev(info->user_ptr[0]);
+       if (info->user_ptr[1])
+               dev_put(info->user_ptr[1]);
+       if (ops->internal_flags & NL80211_FLAG_NEED_RTNL)
+               rtnl_unlock();
+}
+
 static struct genl_ops nl80211_ops[] = {
        {
                .cmd = NL80211_CMD_GET_WIPHY,
@@ -5059,12 +4447,14 @@ static struct genl_ops nl80211_ops[] = {
                .dumpit = nl80211_dump_wiphy,
                .policy = nl80211_policy,
                /* can be retrieved by unprivileged users */
+               .internal_flags = NL80211_FLAG_NEED_WIPHY,
        },
        {
                .cmd = NL80211_CMD_SET_WIPHY,
                .doit = nl80211_set_wiphy,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_GET_INTERFACE,
@@ -5072,90 +4462,119 @@ static struct genl_ops nl80211_ops[] = {
                .dumpit = nl80211_dump_interface,
                .policy = nl80211_policy,
                /* can be retrieved by unprivileged users */
+               .internal_flags = NL80211_FLAG_NEED_NETDEV,
        },
        {
                .cmd = NL80211_CMD_SET_INTERFACE,
                .doit = nl80211_set_interface,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_NEW_INTERFACE,
                .doit = nl80211_new_interface,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_DEL_INTERFACE,
                .doit = nl80211_del_interface,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_GET_KEY,
                .doit = nl80211_get_key,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_KEY,
                .doit = nl80211_set_key,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_NEW_KEY,
                .doit = nl80211_new_key,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_DEL_KEY,
                .doit = nl80211_del_key,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_BEACON,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
                .doit = nl80211_addset_beacon,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_NEW_BEACON,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
                .doit = nl80211_addset_beacon,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_DEL_BEACON,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
                .doit = nl80211_del_beacon,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_GET_STATION,
                .doit = nl80211_get_station,
                .dumpit = nl80211_dump_station,
                .policy = nl80211_policy,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_STATION,
                .doit = nl80211_set_station,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_NEW_STATION,
                .doit = nl80211_new_station,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_DEL_STATION,
                .doit = nl80211_del_station,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_GET_MPATH,
@@ -5163,30 +4582,40 @@ static struct genl_ops nl80211_ops[] = {
                .dumpit = nl80211_dump_mpath,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_MPATH,
                .doit = nl80211_set_mpath,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_NEW_MPATH,
                .doit = nl80211_new_mpath,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_DEL_MPATH,
                .doit = nl80211_del_mpath,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_BSS,
                .doit = nl80211_set_bss,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_GET_REG,
@@ -5211,18 +4640,24 @@ static struct genl_ops nl80211_ops[] = {
                .doit = nl80211_get_mesh_params,
                .policy = nl80211_policy,
                /* can be retrieved by unprivileged users */
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_MESH_PARAMS,
                .doit = nl80211_set_mesh_params,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_TRIGGER_SCAN,
                .doit = nl80211_trigger_scan,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_GET_SCAN,
@@ -5234,36 +4669,48 @@ static struct genl_ops nl80211_ops[] = {
                .doit = nl80211_authenticate,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_ASSOCIATE,
                .doit = nl80211_associate,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_DEAUTHENTICATE,
                .doit = nl80211_deauthenticate,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_DISASSOCIATE,
                .doit = nl80211_disassociate,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_JOIN_IBSS,
                .doit = nl80211_join_ibss,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_LEAVE_IBSS,
                .doit = nl80211_leave_ibss,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
 #ifdef CONFIG_NL80211_TESTMODE
        {
@@ -5271,6 +4718,8 @@ static struct genl_ops nl80211_ops[] = {
                .doit = nl80211_testmode_do,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY |
+                                 NL80211_FLAG_NEED_RTNL,
        },
 #endif
        {
@@ -5278,18 +4727,24 @@ static struct genl_ops nl80211_ops[] = {
                .doit = nl80211_connect,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_DISCONNECT,
                .doit = nl80211_disconnect,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_WIPHY_NETNS,
                .doit = nl80211_wiphy_netns,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_GET_SURVEY,
@@ -5301,72 +4756,104 @@ static struct genl_ops nl80211_ops[] = {
                .doit = nl80211_setdel_pmksa,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_DEL_PMKSA,
                .doit = nl80211_setdel_pmksa,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_FLUSH_PMKSA,
                .doit = nl80211_flush_pmksa,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
                .doit = nl80211_remain_on_channel,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
                .doit = nl80211_cancel_remain_on_channel,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
                .doit = nl80211_set_tx_bitrate_mask,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
-               .cmd = NL80211_CMD_REGISTER_ACTION,
-               .doit = nl80211_register_action,
+               .cmd = NL80211_CMD_REGISTER_FRAME,
+               .doit = nl80211_register_mgmt,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
-               .cmd = NL80211_CMD_ACTION,
-               .doit = nl80211_action,
+               .cmd = NL80211_CMD_FRAME,
+               .doit = nl80211_tx_mgmt,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_POWER_SAVE,
                .doit = nl80211_set_power_save,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_GET_POWER_SAVE,
                .doit = nl80211_get_power_save,
                .policy = nl80211_policy,
                /* can be retrieved by unprivileged users */
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_CQM,
                .doit = nl80211_set_cqm,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
        {
                .cmd = NL80211_CMD_SET_CHANNEL,
                .doit = nl80211_set_channel,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
+       {
+               .cmd = NL80211_CMD_SET_WDS_PEER,
+               .doit = nl80211_set_wds_peer,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
        },
 };
 
@@ -6040,9 +5527,9 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
                                nl80211_mlme_mcgrp.id, gfp);
 }
 
-int nl80211_send_action(struct cfg80211_registered_device *rdev,
-                       struct net_device *netdev, u32 nlpid,
-                       int freq, const u8 *buf, size_t len, gfp_t gfp)
+int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
+                     struct net_device *netdev, u32 nlpid,
+                     int freq, const u8 *buf, size_t len, gfp_t gfp)
 {
        struct sk_buff *msg;
        void *hdr;
@@ -6052,7 +5539,7 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev,
        if (!msg)
                return -ENOMEM;
 
-       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION);
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
        if (!hdr) {
                nlmsg_free(msg);
                return -ENOMEM;
@@ -6080,10 +5567,10 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev,
        return -ENOBUFS;
 }
 
-void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
-                                  struct net_device *netdev, u64 cookie,
-                                  const u8 *buf, size_t len, bool ack,
-                                  gfp_t gfp)
+void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
+                                struct net_device *netdev, u64 cookie,
+                                const u8 *buf, size_t len, bool ack,
+                                gfp_t gfp)
 {
        struct sk_buff *msg;
        void *hdr;
@@ -6092,7 +5579,7 @@ void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
        if (!msg)
                return;
 
-       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION_TX_STATUS);
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS);
        if (!hdr) {
                nlmsg_free(msg);
                return;
@@ -6179,7 +5666,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
 
        list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list)
                list_for_each_entry_rcu(wdev, &rdev->netdev_list, list)
-                       cfg80211_mlme_unregister_actions(wdev, notify->pid);
+                       cfg80211_mlme_unregister_socket(wdev, notify->pid);
 
        rcu_read_unlock();