Skip to content

Commit

Permalink
nl80211: allow using wdev identifiers to get scan results
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johannes Berg committed Apr 18, 2013
1 parent 1b737f8 commit 97990a0
Showing 1 changed file with 91 additions and 75 deletions.
166 changes: 91 additions & 75 deletions net/wireless/nl80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
int err;

res = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
if (!res)
return -EINVAL;
return res;
}
rtnl_lock();
mutex_lock(&cfg80211_mutex);

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 (!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;

if (!ifidx)
ifidx = nl80211_get_ifidx(cb);
if (ifidx < 0)
return ifidx;
*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;

cb->args[0] = ifidx;
if (!wiphy) {
err = -ENODEV;
goto out_unlock;
}
*rdev = wiphy_to_dev(wiphy);
*wdev = NULL;

rtnl_lock();
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);

*dev = __dev_get_by_index(sock_net(skb->sk), ifidx);
if (!*dev) {
err = -ENODEV;
goto out_rtnl;
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();
Expand Down Expand Up @@ -3525,23 +3532,28 @@ 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;
}

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;
Expand All @@ -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;

Expand All @@ -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;
}
Expand Down Expand Up @@ -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;

Expand All @@ -4182,22 +4194,22 @@ 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)
goto out_err;

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;

Expand All @@ -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;
}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand All @@ -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;
}

Expand Down

0 comments on commit 97990a0

Please sign in to comment.