|
@@ -70,6 +70,94 @@ static int get_rdev_dev_by_ifindex(struct net *netns, struct nlattr **attrs,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static struct cfg80211_registered_device *
|
|
|
+__cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
|
|
|
+{
|
|
|
+ struct cfg80211_registered_device *rdev = NULL, *tmp;
|
|
|
+ struct net_device *netdev;
|
|
|
+
|
|
|
+ assert_cfg80211_lock();
|
|
|
+
|
|
|
+ if (!attrs[NL80211_ATTR_WIPHY] &&
|
|
|
+ !attrs[NL80211_ATTR_IFINDEX])
|
|
|
+ return ERR_PTR(-EINVAL);
|
|
|
+
|
|
|
+ if (attrs[NL80211_ATTR_WIPHY])
|
|
|
+ rdev = cfg80211_rdev_by_wiphy_idx(
|
|
|
+ nla_get_u32(attrs[NL80211_ATTR_WIPHY]));
|
|
|
+
|
|
|
+ if (attrs[NL80211_ATTR_IFINDEX]) {
|
|
|
+ int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
|
|
|
+ netdev = dev_get_by_index(netns, ifindex);
|
|
|
+ if (netdev) {
|
|
|
+ if (netdev->ieee80211_ptr)
|
|
|
+ tmp = wiphy_to_dev(
|
|
|
+ netdev->ieee80211_ptr->wiphy);
|
|
|
+ else
|
|
|
+ tmp = NULL;
|
|
|
+
|
|
|
+ dev_put(netdev);
|
|
|
+
|
|
|
+ /* not wireless device -- return error */
|
|
|
+ if (!tmp)
|
|
|
+ return ERR_PTR(-EINVAL);
|
|
|
+
|
|
|
+ /* mismatch -- return error */
|
|
|
+ if (rdev && tmp != rdev)
|
|
|
+ return ERR_PTR(-EINVAL);
|
|
|
+
|
|
|
+ rdev = tmp;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!rdev)
|
|
|
+ return ERR_PTR(-ENODEV);
|
|
|
+
|
|
|
+ if (netns != wiphy_net(&rdev->wiphy))
|
|
|
+ return ERR_PTR(-ENODEV);
|
|
|
+
|
|
|
+ return rdev;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * This function returns a pointer to the driver
|
|
|
+ * that the genl_info item that is passed refers to.
|
|
|
+ * If successful, it returns non-NULL and also locks
|
|
|
+ * the driver's mutex!
|
|
|
+ *
|
|
|
+ * This means that you need to call cfg80211_unlock_rdev()
|
|
|
+ * before being allowed to acquire &cfg80211_mutex!
|
|
|
+ *
|
|
|
+ * This is necessary because we need to lock the global
|
|
|
+ * mutex to get an item off the list safely, and then
|
|
|
+ * we lock the rdev mutex so it doesn't go away under us.
|
|
|
+ *
|
|
|
+ * We don't want to keep cfg80211_mutex locked
|
|
|
+ * for all the time in order to allow requests on
|
|
|
+ * other interfaces to go through at the same time.
|
|
|
+ *
|
|
|
+ * The result of this can be a PTR_ERR and hence must
|
|
|
+ * be checked with IS_ERR() for errors.
|
|
|
+ */
|
|
|
+static struct cfg80211_registered_device *
|
|
|
+cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info)
|
|
|
+{
|
|
|
+ struct cfg80211_registered_device *rdev;
|
|
|
+
|
|
|
+ mutex_lock(&cfg80211_mutex);
|
|
|
+ rdev = __cfg80211_rdev_from_attrs(netns, info->attrs);
|
|
|
+
|
|
|
+ /* if it is not an error we grab the lock on
|
|
|
+ * it to assure it won't be going away while
|
|
|
+ * we operate on it */
|
|
|
+ if (!IS_ERR(rdev))
|
|
|
+ mutex_lock(&rdev->mtx);
|
|
|
+
|
|
|
+ mutex_unlock(&cfg80211_mutex);
|
|
|
+
|
|
|
+ return rdev;
|
|
|
+}
|
|
|
+
|
|
|
/* policy for the attributes */
|
|
|
static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
|
|
|
[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
|
|
@@ -115,7 +203,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
|
|
|
[NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
|
|
|
[NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ },
|
|
|
[NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
|
|
|
- .len = IEEE80211_MAX_MESH_ID_LEN },
|
|
|
+ .len = IEEE80211_MAX_MESH_ID_LEN },
|
|
|
[NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 },
|
|
|
|
|
|
[NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 },
|
|
@@ -250,7 +338,7 @@ nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
|
|
|
|
|
|
static const struct nla_policy
|
|
|
nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
|
|
|
- [NL80211_ATTR_SCHED_SCAN_MATCH_SSID] = { .type = NLA_BINARY,
|
|
|
+ [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
|
|
|
.len = IEEE80211_MAX_SSID_LEN },
|
|
|
};
|
|
|
|
|
@@ -1334,7 +1422,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
|
|
|
}
|
|
|
|
|
|
if (!netdev) {
|
|
|
- rdev = __cfg80211_rdev_from_info(info);
|
|
|
+ rdev = __cfg80211_rdev_from_attrs(genl_info_net(info),
|
|
|
+ info->attrs);
|
|
|
if (IS_ERR(rdev)) {
|
|
|
mutex_unlock(&cfg80211_mutex);
|
|
|
return PTR_ERR(rdev);
|
|
@@ -2246,6 +2335,33 @@ static int nl80211_parse_beacon(struct genl_info *info,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
|
|
|
+ struct cfg80211_ap_settings *params)
|
|
|
+{
|
|
|
+ struct wireless_dev *wdev;
|
|
|
+ bool ret = false;
|
|
|
+
|
|
|
+ mutex_lock(&rdev->devlist_mtx);
|
|
|
+
|
|
|
+ list_for_each_entry(wdev, &rdev->netdev_list, list) {
|
|
|
+ if (wdev->iftype != NL80211_IFTYPE_AP &&
|
|
|
+ wdev->iftype != NL80211_IFTYPE_P2P_GO)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (!wdev->preset_chan)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ params->channel = wdev->preset_chan;
|
|
|
+ params->channel_type = wdev->preset_chantype;
|
|
|
+ ret = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ mutex_unlock(&rdev->devlist_mtx);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
|
|
{
|
|
|
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
|
@@ -2348,7 +2464,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
|
|
} else if (wdev->preset_chan) {
|
|
|
params.channel = wdev->preset_chan;
|
|
|
params.channel_type = wdev->preset_chantype;
|
|
|
- } else
|
|
|
+ } else if (!nl80211_get_ap_channel(rdev, ¶ms))
|
|
|
return -EINVAL;
|
|
|
|
|
|
if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, params.channel,
|
|
@@ -2356,8 +2472,11 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
|
|
return -EINVAL;
|
|
|
|
|
|
err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms);
|
|
|
- if (!err)
|
|
|
+ if (!err) {
|
|
|
+ wdev->preset_chan = params.channel;
|
|
|
+ wdev->preset_chantype = params.channel_type;
|
|
|
wdev->beacon_interval = params.beacon_interval;
|
|
|
+ }
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -3469,7 +3588,13 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
|
|
|
nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
|
|
|
cur_params.rssi_threshold) ||
|
|
|
nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE,
|
|
|
- cur_params.ht_opmode))
|
|
|
+ cur_params.ht_opmode) ||
|
|
|
+ nla_put_u32(msg, NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
|
|
|
+ cur_params.dot11MeshHWMPactivePathToRootTimeout) ||
|
|
|
+ nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
|
|
|
+ cur_params.dot11MeshHWMProotInterval) ||
|
|
|
+ nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
|
|
|
+ cur_params.dot11MeshHWMPconfirmationInterval))
|
|
|
goto nla_put_failure;
|
|
|
nla_nest_end(msg, pinfoattr);
|
|
|
genlmsg_end(msg, hdr);
|
|
@@ -3492,7 +3617,6 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
|
|
|
[NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 },
|
|
|
[NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 },
|
|
|
[NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 },
|
|
|
-
|
|
|
[NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
|
|
|
[NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 },
|
|
|
[NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 },
|
|
@@ -3504,8 +3628,11 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
|
|
|
[NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 },
|
|
|
[NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 },
|
|
|
[NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 },
|
|
|
- [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32},
|
|
|
- [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16},
|
|
|
+ [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32 },
|
|
|
+ [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 },
|
|
|
+ [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 },
|
|
|
+ [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 },
|
|
|
+ [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 },
|
|
|
};
|
|
|
|
|
|
static const struct nla_policy
|
|
@@ -3515,7 +3642,7 @@ static const struct nla_policy
|
|
|
[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
|
|
|
[NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG },
|
|
|
[NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY,
|
|
|
- .len = IEEE80211_MAX_DATA_LEN },
|
|
|
+ .len = IEEE80211_MAX_DATA_LEN },
|
|
|
[NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG },
|
|
|
};
|
|
|
|
|
@@ -3548,63 +3675,82 @@ do {\
|
|
|
|
|
|
/* Fill in the params struct */
|
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout,
|
|
|
- mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16);
|
|
|
+ mask, NL80211_MESHCONF_RETRY_TIMEOUT,
|
|
|
+ nla_get_u16);
|
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout,
|
|
|
- mask, NL80211_MESHCONF_CONFIRM_TIMEOUT, nla_get_u16);
|
|
|
+ mask, NL80211_MESHCONF_CONFIRM_TIMEOUT,
|
|
|
+ nla_get_u16);
|
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout,
|
|
|
- mask, NL80211_MESHCONF_HOLDING_TIMEOUT, nla_get_u16);
|
|
|
+ mask, NL80211_MESHCONF_HOLDING_TIMEOUT,
|
|
|
+ nla_get_u16);
|
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks,
|
|
|
- mask, NL80211_MESHCONF_MAX_PEER_LINKS, nla_get_u16);
|
|
|
+ mask, NL80211_MESHCONF_MAX_PEER_LINKS,
|
|
|
+ nla_get_u16);
|
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries,
|
|
|
- mask, NL80211_MESHCONF_MAX_RETRIES, nla_get_u8);
|
|
|
+ mask, NL80211_MESHCONF_MAX_RETRIES,
|
|
|
+ nla_get_u8);
|
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL,
|
|
|
- mask, NL80211_MESHCONF_TTL, nla_get_u8);
|
|
|
+ mask, NL80211_MESHCONF_TTL, nla_get_u8);
|
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl,
|
|
|
- mask, NL80211_MESHCONF_ELEMENT_TTL, nla_get_u8);
|
|
|
+ mask, NL80211_MESHCONF_ELEMENT_TTL,
|
|
|
+ nla_get_u8);
|
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks,
|
|
|
- mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8);
|
|
|
- FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor,
|
|
|
- mask, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
|
|
|
- nla_get_u32);
|
|
|
+ mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
|
|
|
+ nla_get_u8);
|
|
|
+ FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor, mask,
|
|
|
+ NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR,
|
|
|
+ nla_get_u32);
|
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries,
|
|
|
- mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
|
|
|
- nla_get_u8);
|
|
|
+ mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
|
|
|
+ nla_get_u8);
|
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time,
|
|
|
- mask, NL80211_MESHCONF_PATH_REFRESH_TIME, nla_get_u32);
|
|
|
+ mask, NL80211_MESHCONF_PATH_REFRESH_TIME,
|
|
|
+ nla_get_u32);
|
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout,
|
|
|
- mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
|
|
|
- nla_get_u16);
|
|
|
- FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout,
|
|
|
- mask, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
|
|
|
- nla_get_u32);
|
|
|
+ mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
|
|
|
+ nla_get_u16);
|
|
|
+ FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, mask,
|
|
|
+ NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
|
|
|
+ nla_get_u32);
|
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval,
|
|
|
- mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
|
|
|
- nla_get_u16);
|
|
|
+ mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
|
|
|
+ nla_get_u16);
|
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval,
|
|
|
- mask, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
|
|
|
- nla_get_u16);
|
|
|
- FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
|
|
|
- dot11MeshHWMPnetDiameterTraversalTime,
|
|
|
- mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
|
|
|
- nla_get_u16);
|
|
|
+ mask, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL,
|
|
|
+ nla_get_u16);
|
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
|
|
|
- dot11MeshHWMPRootMode, mask,
|
|
|
- NL80211_MESHCONF_HWMP_ROOTMODE,
|
|
|
- nla_get_u8);
|
|
|
+ dot11MeshHWMPnetDiameterTraversalTime, mask,
|
|
|
+ NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
|
|
|
+ nla_get_u16);
|
|
|
+ FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, mask,
|
|
|
+ NL80211_MESHCONF_HWMP_ROOTMODE, nla_get_u8);
|
|
|
+ FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, mask,
|
|
|
+ NL80211_MESHCONF_HWMP_RANN_INTERVAL,
|
|
|
+ nla_get_u16);
|
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
|
|
|
- dot11MeshHWMPRannInterval, mask,
|
|
|
- NL80211_MESHCONF_HWMP_RANN_INTERVAL,
|
|
|
- nla_get_u16);
|
|
|
- FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
|
|
|
- dot11MeshGateAnnouncementProtocol, mask,
|
|
|
- NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
|
|
|
- nla_get_u8);
|
|
|
+ dot11MeshGateAnnouncementProtocol, mask,
|
|
|
+ NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
|
|
|
+ nla_get_u8);
|
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding,
|
|
|
- mask, NL80211_MESHCONF_FORWARDING, nla_get_u8);
|
|
|
+ mask, NL80211_MESHCONF_FORWARDING,
|
|
|
+ nla_get_u8);
|
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold,
|
|
|
- mask, NL80211_MESHCONF_RSSI_THRESHOLD, nla_get_u32);
|
|
|
+ mask, NL80211_MESHCONF_RSSI_THRESHOLD,
|
|
|
+ nla_get_u32);
|
|
|
FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode,
|
|
|
- mask, NL80211_MESHCONF_HT_OPMODE, nla_get_u16);
|
|
|
+ mask, NL80211_MESHCONF_HT_OPMODE,
|
|
|
+ nla_get_u16);
|
|
|
+ FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout,
|
|
|
+ mask,
|
|
|
+ NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT,
|
|
|
+ nla_get_u32);
|
|
|
+ FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval,
|
|
|
+ mask, NL80211_MESHCONF_HWMP_ROOT_INTERVAL,
|
|
|
+ nla_get_u16);
|
|
|
+ FILL_IN_MESH_PARAM_IF_SET(tb, cfg,
|
|
|
+ dot11MeshHWMPconfirmationInterval, mask,
|
|
|
+ NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
|
|
|
+ nla_get_u16);
|
|
|
if (mask_out)
|
|
|
*mask_out = mask;
|
|
|
|
|
@@ -4246,7 +4392,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
|
|
|
nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
|
|
|
nla_data(attr), nla_len(attr),
|
|
|
nl80211_match_policy);
|
|
|
- ssid = tb[NL80211_ATTR_SCHED_SCAN_MATCH_SSID];
|
|
|
+ ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
|
|
|
if (ssid) {
|
|
|
if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
|
|
|
err = -EINVAL;
|
|
@@ -5114,21 +5260,18 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
|
|
|
nl80211_policy);
|
|
|
if (err)
|
|
|
return err;
|
|
|
- if (nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]) {
|
|
|
- phy_idx = nla_get_u32(
|
|
|
- nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]);
|
|
|
- } else {
|
|
|
- struct net_device *netdev;
|
|
|
|
|
|
- err = get_rdev_dev_by_ifindex(sock_net(skb->sk),
|
|
|
- nl80211_fam.attrbuf,
|
|
|
- &rdev, &netdev);
|
|
|
- if (err)
|
|
|
- return err;
|
|
|
- dev_put(netdev);
|
|
|
- phy_idx = rdev->wiphy_idx;
|
|
|
- cfg80211_unlock_rdev(rdev);
|
|
|
+ mutex_lock(&cfg80211_mutex);
|
|
|
+ rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk),
|
|
|
+ nl80211_fam.attrbuf);
|
|
|
+ if (IS_ERR(rdev)) {
|
|
|
+ mutex_unlock(&cfg80211_mutex);
|
|
|
+ return PTR_ERR(rdev);
|
|
|
}
|
|
|
+ phy_idx = rdev->wiphy_idx;
|
|
|
+ rdev = NULL;
|
|
|
+ mutex_unlock(&cfg80211_mutex);
|
|
|
+
|
|
|
if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA])
|
|
|
cb->args[1] =
|
|
|
(long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA];
|
|
@@ -6511,7 +6654,7 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
|
|
|
rtnl_lock();
|
|
|
|
|
|
if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) {
|
|
|
- rdev = cfg80211_get_dev_from_info(info);
|
|
|
+ rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
|
|
|
if (IS_ERR(rdev)) {
|
|
|
if (rtnl)
|
|
|
rtnl_unlock();
|