mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-11-01 17:08:10 +00:00
nl80211: allow using wdev identifiers to get scan results
Most dump callbacks, including the scan results one, use the netdev to identify what to do, which is incorrect for the P2P_DEVICE support, it needs to be able to get the scan result from the wdev. Change all dumps to unify the code, but ones other than scan don't really support being executed on a wdev that has no netdev. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
1b737f88dc
commit
97990a060e
1 changed files with 93 additions and 77 deletions
|
@ -447,62 +447,69 @@ nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
|
|||
[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
/* ifidx get helper */
|
||||
static int nl80211_get_ifidx(struct netlink_callback *cb)
|
||||
static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
|
||||
struct netlink_callback *cb,
|
||||
struct cfg80211_registered_device **rdev,
|
||||
struct wireless_dev **wdev)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
|
||||
nl80211_fam.attrbuf, nl80211_fam.maxattr,
|
||||
nl80211_policy);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
|
||||
return -EINVAL;
|
||||
|
||||
res = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
|
||||
if (!res)
|
||||
return -EINVAL;
|
||||
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();
|
||||
mutex_lock(&cfg80211_mutex);
|
||||
|
||||
*dev = __dev_get_by_index(sock_net(skb->sk), ifidx);
|
||||
if (!*dev) {
|
||||
err = -ENODEV;
|
||||
goto out_rtnl;
|
||||
if (!cb->args[0]) {
|
||||
err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
|
||||
nl80211_fam.attrbuf, nl80211_fam.maxattr,
|
||||
nl80211_policy);
|
||||
if (err)
|
||||
goto out_unlock;
|
||||
|
||||
*wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk),
|
||||
nl80211_fam.attrbuf);
|
||||
if (IS_ERR(*wdev)) {
|
||||
err = PTR_ERR(*wdev);
|
||||
goto out_unlock;
|
||||
}
|
||||
*rdev = wiphy_to_dev((*wdev)->wiphy);
|
||||
cb->args[0] = (*rdev)->wiphy_idx;
|
||||
cb->args[1] = (*wdev)->identifier;
|
||||
} else {
|
||||
struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0]);
|
||||
struct wireless_dev *tmp;
|
||||
|
||||
if (!wiphy) {
|
||||
err = -ENODEV;
|
||||
goto out_unlock;
|
||||
}
|
||||
*rdev = wiphy_to_dev(wiphy);
|
||||
*wdev = NULL;
|
||||
|
||||
mutex_lock(&(*rdev)->devlist_mtx);
|
||||
list_for_each_entry(tmp, &(*rdev)->wdev_list, list) {
|
||||
if (tmp->identifier == cb->args[1]) {
|
||||
*wdev = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&(*rdev)->devlist_mtx);
|
||||
|
||||
if (!*wdev) {
|
||||
err = -ENODEV;
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
*rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
|
||||
if (IS_ERR(*rdev)) {
|
||||
err = PTR_ERR(*rdev);
|
||||
goto out_rtnl;
|
||||
}
|
||||
cfg80211_lock_rdev(*rdev);
|
||||
|
||||
mutex_unlock(&cfg80211_mutex);
|
||||
return 0;
|
||||
out_rtnl:
|
||||
out_unlock:
|
||||
mutex_unlock(&cfg80211_mutex);
|
||||
rtnl_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
static void nl80211_finish_netdev_dump(struct cfg80211_registered_device *rdev)
|
||||
static void nl80211_finish_wdev_dump(struct cfg80211_registered_device *rdev)
|
||||
{
|
||||
cfg80211_unlock_rdev(rdev);
|
||||
rtnl_unlock();
|
||||
|
@ -3525,15 +3532,20 @@ static int nl80211_dump_station(struct sk_buff *skb,
|
|||
{
|
||||
struct station_info sinfo;
|
||||
struct cfg80211_registered_device *dev;
|
||||
struct net_device *netdev;
|
||||
struct wireless_dev *wdev;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
int sta_idx = cb->args[1];
|
||||
int sta_idx = cb->args[2];
|
||||
int err;
|
||||
|
||||
err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev);
|
||||
err = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!wdev->netdev) {
|
||||
err = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (!dev->ops->dump_station) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out_err;
|
||||
|
@ -3541,7 +3553,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
|
|||
|
||||
while (1) {
|
||||
memset(&sinfo, 0, sizeof(sinfo));
|
||||
err = rdev_dump_station(dev, netdev, sta_idx,
|
||||
err = rdev_dump_station(dev, wdev->netdev, sta_idx,
|
||||
mac_addr, &sinfo);
|
||||
if (err == -ENOENT)
|
||||
break;
|
||||
|
@ -3551,7 +3563,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
|
|||
if (nl80211_send_station(skb,
|
||||
NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, NLM_F_MULTI,
|
||||
dev, netdev, mac_addr,
|
||||
dev, wdev->netdev, mac_addr,
|
||||
&sinfo) < 0)
|
||||
goto out;
|
||||
|
||||
|
@ -3560,10 +3572,10 @@ static int nl80211_dump_station(struct sk_buff *skb,
|
|||
|
||||
|
||||
out:
|
||||
cb->args[1] = sta_idx;
|
||||
cb->args[2] = sta_idx;
|
||||
err = skb->len;
|
||||
out_err:
|
||||
nl80211_finish_netdev_dump(dev);
|
||||
nl80211_finish_wdev_dump(dev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -4167,13 +4179,13 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
|
|||
{
|
||||
struct mpath_info pinfo;
|
||||
struct cfg80211_registered_device *dev;
|
||||
struct net_device *netdev;
|
||||
struct wireless_dev *wdev;
|
||||
u8 dst[ETH_ALEN];
|
||||
u8 next_hop[ETH_ALEN];
|
||||
int path_idx = cb->args[1];
|
||||
int path_idx = cb->args[2];
|
||||
int err;
|
||||
|
||||
err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev);
|
||||
err = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -4182,14 +4194,14 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
|
|||
goto out_err;
|
||||
}
|
||||
|
||||
if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
|
||||
if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
err = rdev_dump_mpath(dev, netdev, path_idx, dst, next_hop,
|
||||
&pinfo);
|
||||
err = rdev_dump_mpath(dev, wdev->netdev, path_idx, dst,
|
||||
next_hop, &pinfo);
|
||||
if (err == -ENOENT)
|
||||
break;
|
||||
if (err)
|
||||
|
@ -4197,7 +4209,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
|
|||
|
||||
if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, NLM_F_MULTI,
|
||||
netdev, dst, next_hop,
|
||||
wdev->netdev, dst, next_hop,
|
||||
&pinfo) < 0)
|
||||
goto out;
|
||||
|
||||
|
@ -4206,10 +4218,10 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
|
|||
|
||||
|
||||
out:
|
||||
cb->args[1] = path_idx;
|
||||
cb->args[2] = path_idx;
|
||||
err = skb->len;
|
||||
out_err:
|
||||
nl80211_finish_netdev_dump(dev);
|
||||
nl80211_finish_wdev_dump(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -5552,9 +5564,13 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
|
|||
|
||||
genl_dump_check_consistent(cb, hdr, &nl80211_fam);
|
||||
|
||||
if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation) ||
|
||||
if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation))
|
||||
goto nla_put_failure;
|
||||
if (wdev->netdev &&
|
||||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex))
|
||||
goto nla_put_failure;
|
||||
if (nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
|
||||
goto nla_put_failure;
|
||||
|
||||
bss = nla_nest_start(msg, NL80211_ATTR_BSS);
|
||||
if (!bss)
|
||||
|
@ -5634,22 +5650,18 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
|
|||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static int nl80211_dump_scan(struct sk_buff *skb,
|
||||
struct netlink_callback *cb)
|
||||
static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev;
|
||||
struct net_device *dev;
|
||||
struct cfg80211_internal_bss *scan;
|
||||
struct wireless_dev *wdev;
|
||||
int start = cb->args[1], idx = 0;
|
||||
int start = cb->args[2], idx = 0;
|
||||
int err;
|
||||
|
||||
err = nl80211_prepare_netdev_dump(skb, cb, &rdev, &dev);
|
||||
err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
wdev = dev->ieee80211_ptr;
|
||||
|
||||
wdev_lock(wdev);
|
||||
spin_lock_bh(&rdev->bss_lock);
|
||||
cfg80211_bss_expire(rdev);
|
||||
|
@ -5670,8 +5682,8 @@ static int nl80211_dump_scan(struct sk_buff *skb,
|
|||
spin_unlock_bh(&rdev->bss_lock);
|
||||
wdev_unlock(wdev);
|
||||
|
||||
cb->args[1] = idx;
|
||||
nl80211_finish_netdev_dump(rdev);
|
||||
cb->args[2] = idx;
|
||||
nl80211_finish_wdev_dump(rdev);
|
||||
|
||||
return skb->len;
|
||||
}
|
||||
|
@ -5740,14 +5752,19 @@ static int nl80211_dump_survey(struct sk_buff *skb,
|
|||
{
|
||||
struct survey_info survey;
|
||||
struct cfg80211_registered_device *dev;
|
||||
struct net_device *netdev;
|
||||
int survey_idx = cb->args[1];
|
||||
struct wireless_dev *wdev;
|
||||
int survey_idx = cb->args[2];
|
||||
int res;
|
||||
|
||||
res = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev);
|
||||
res = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
if (!wdev->netdev) {
|
||||
res = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (!dev->ops->dump_survey) {
|
||||
res = -EOPNOTSUPP;
|
||||
goto out_err;
|
||||
|
@ -5756,7 +5773,7 @@ static int nl80211_dump_survey(struct sk_buff *skb,
|
|||
while (1) {
|
||||
struct ieee80211_channel *chan;
|
||||
|
||||
res = rdev_dump_survey(dev, netdev, survey_idx, &survey);
|
||||
res = rdev_dump_survey(dev, wdev->netdev, survey_idx, &survey);
|
||||
if (res == -ENOENT)
|
||||
break;
|
||||
if (res)
|
||||
|
@ -5778,17 +5795,16 @@ static int nl80211_dump_survey(struct sk_buff *skb,
|
|||
if (nl80211_send_survey(skb,
|
||||
NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, NLM_F_MULTI,
|
||||
netdev,
|
||||
&survey) < 0)
|
||||
wdev->netdev, &survey) < 0)
|
||||
goto out;
|
||||
survey_idx++;
|
||||
}
|
||||
|
||||
out:
|
||||
cb->args[1] = survey_idx;
|
||||
cb->args[2] = survey_idx;
|
||||
res = skb->len;
|
||||
out_err:
|
||||
nl80211_finish_netdev_dump(dev);
|
||||
nl80211_finish_wdev_dump(dev);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue