提交 4c476991 编写于 作者: J Johannes Berg 提交者: John W. Linville

nl80211: use the new genetlink pre/post_doit hooks

This makes nl80211 use the new genetlink
pre_doit/post_doit hooks for locking and
checking the interface/wiphy index.

This significantly reduces the code size
and the likelihood of locking errors.
Signed-off-by: NJohannes Berg <johannes.berg@intel.com>
Signed-off-by: NJohn W. Linville <linville@tuxdriver.com>
上级 ff4c92d8
...@@ -23,6 +23,11 @@ ...@@ -23,6 +23,11 @@
#include "nl80211.h" #include "nl80211.h"
#include "reg.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 */ /* the netlink family */
static struct genl_family nl80211_fam = { static struct genl_family nl80211_fam = {
.id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */
...@@ -31,6 +36,8 @@ static struct genl_family nl80211_fam = { ...@@ -31,6 +36,8 @@ static struct genl_family nl80211_fam = {
.version = 1, /* no particular meaning now */ .version = 1, /* no particular meaning now */
.maxattr = NL80211_ATTR_MAX, .maxattr = NL80211_ATTR_MAX,
.netnsok = true, .netnsok = true,
.pre_doit = nl80211_pre_doit,
.post_doit = nl80211_post_doit,
}; };
/* internal helper: get rdev and dev */ /* internal helper: get rdev and dev */
...@@ -704,28 +711,18 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -704,28 +711,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) static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
{ {
struct sk_buff *msg; struct sk_buff *msg;
struct cfg80211_registered_device *dev; struct cfg80211_registered_device *dev = info->user_ptr[0];
dev = cfg80211_get_dev_from_info(info);
if (IS_ERR(dev))
return PTR_ERR(dev);
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) if (!msg)
goto out_err; return -ENOMEM;
if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0)
goto out_free;
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); 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] = { static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = {
...@@ -814,24 +811,10 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, ...@@ -814,24 +811,10 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *netdev; struct net_device *netdev = info->user_ptr[1];
int result;
rtnl_lock();
result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev);
if (result)
goto unlock_rtnl;
result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); return __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info);
dev_put(netdev);
cfg80211_unlock_rdev(rdev);
unlock_rtnl:
rtnl_unlock();
return result;
} }
static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info) static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
...@@ -893,8 +876,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) ...@@ -893,8 +876,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
u32 frag_threshold = 0, rts_threshold = 0; u32 frag_threshold = 0, rts_threshold = 0;
u8 coverage_class = 0; u8 coverage_class = 0;
rtnl_lock();
/* /*
* Try to find the wiphy and netdev. Normally this * Try to find the wiphy and netdev. Normally this
* function shouldn't need the netdev, but this is * function shouldn't need the netdev, but this is
...@@ -921,8 +902,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) ...@@ -921,8 +902,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
rdev = __cfg80211_rdev_from_info(info); rdev = __cfg80211_rdev_from_info(info);
if (IS_ERR(rdev)) { if (IS_ERR(rdev)) {
mutex_unlock(&cfg80211_mutex); mutex_unlock(&cfg80211_mutex);
result = PTR_ERR(rdev); return PTR_ERR(rdev);
goto unlock;
} }
wdev = NULL; wdev = NULL;
netdev = NULL; netdev = NULL;
...@@ -1104,8 +1084,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) ...@@ -1104,8 +1084,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
mutex_unlock(&rdev->mtx); mutex_unlock(&rdev->mtx);
if (netdev) if (netdev)
dev_put(netdev); dev_put(netdev);
unlock:
rtnl_unlock();
return result; return result;
} }
...@@ -1185,33 +1163,20 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * ...@@ -1185,33 +1163,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) static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
{ {
struct sk_buff *msg; struct sk_buff *msg;
struct cfg80211_registered_device *dev; struct cfg80211_registered_device *dev = info->user_ptr[0];
struct net_device *netdev; struct net_device *netdev = info->user_ptr[1];
int err;
err = get_rdev_dev_by_info_ifindex(info, &dev, &netdev);
if (err)
return err;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) if (!msg)
goto out_err; return -ENOMEM;
if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0,
dev, netdev) < 0) dev, netdev) < 0) {
goto out_free; nlmsg_free(msg);
return -ENOBUFS;
dev_put(netdev); }
cfg80211_unlock_rdev(dev);
return genlmsg_reply(msg, info); 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] = { static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
...@@ -1271,39 +1236,29 @@ static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev, ...@@ -1271,39 +1236,29 @@ static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) 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; struct vif_params params;
int err; int err;
enum nl80211_iftype otype, ntype; enum nl80211_iftype otype, ntype;
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
u32 _flags, *flags = NULL; u32 _flags, *flags = NULL;
bool change = false; bool change = false;
memset(&params, 0, sizeof(params)); 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; otype = ntype = dev->ieee80211_ptr->iftype;
if (info->attrs[NL80211_ATTR_IFTYPE]) { if (info->attrs[NL80211_ATTR_IFTYPE]) {
ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
if (otype != ntype) if (otype != ntype)
change = true; change = true;
if (ntype > NL80211_IFTYPE_MAX) { if (ntype > NL80211_IFTYPE_MAX)
err = -EINVAL; return -EINVAL;
goto unlock;
}
} }
if (info->attrs[NL80211_ATTR_MESH_ID]) { if (info->attrs[NL80211_ATTR_MESH_ID]) {
if (ntype != NL80211_IFTYPE_MESH_POINT) { if (ntype != NL80211_IFTYPE_MESH_POINT)
err = -EINVAL; return -EINVAL;
goto unlock;
}
params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
change = true; change = true;
...@@ -1314,20 +1269,18 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) ...@@ -1314,20 +1269,18 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
change = true; change = true;
err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype); err = nl80211_valid_4addr(rdev, dev, params.use_4addr, ntype);
if (err) if (err)
goto unlock; return err;
} else { } else {
params.use_4addr = -1; params.use_4addr = -1;
} }
if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
if (ntype != NL80211_IFTYPE_MONITOR) { if (ntype != NL80211_IFTYPE_MONITOR)
err = -EINVAL; return -EINVAL;
goto unlock;
}
err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
&_flags); &_flags);
if (err) if (err)
goto unlock; return err;
flags = &_flags; flags = &_flags;
change = true; change = true;
...@@ -1341,17 +1294,12 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) ...@@ -1341,17 +1294,12 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
if (!err && params.use_4addr != -1) if (!err && params.use_4addr != -1)
dev->ieee80211_ptr->use_4addr = params.use_4addr; dev->ieee80211_ptr->use_4addr = params.use_4addr;
unlock:
dev_put(dev);
cfg80211_unlock_rdev(rdev);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) 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; struct vif_params params;
int err; int err;
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
...@@ -1368,19 +1316,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) ...@@ -1368,19 +1316,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
return -EINVAL; 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 || if (!rdev->ops->add_virtual_intf ||
!(rdev->wiphy.interface_modes & (1 << type))) { !(rdev->wiphy.interface_modes & (1 << type)))
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto unlock;
}
if (type == NL80211_IFTYPE_MESH_POINT && if (type == NL80211_IFTYPE_MESH_POINT &&
info->attrs[NL80211_ATTR_MESH_ID]) { info->attrs[NL80211_ATTR_MESH_ID]) {
...@@ -1392,7 +1330,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) ...@@ -1392,7 +1330,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]); params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type); err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
if (err) if (err)
goto unlock; return err;
} }
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
...@@ -1402,38 +1340,18 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) ...@@ -1402,38 +1340,18 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
nla_data(info->attrs[NL80211_ATTR_IFNAME]), nla_data(info->attrs[NL80211_ATTR_IFNAME]),
type, err ? NULL : &flags, &params); type, err ? NULL : &flags, &params);
unlock:
cfg80211_unlock_rdev(rdev);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) static int nl80211_del_interface(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 = info->user_ptr[1];
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_virtual_intf) {
err = -EOPNOTSUPP;
goto out;
}
err = rdev->ops->del_virtual_intf(&rdev->wiphy, dev); if (!rdev->ops->del_virtual_intf)
return -EOPNOTSUPP;
out: return rdev->ops->del_virtual_intf(&rdev->wiphy, dev);
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err;
} }
struct get_key_cookie { struct get_key_cookie {
...@@ -1486,9 +1404,9 @@ static void get_key_callback(void *c, struct key_params *params) ...@@ -1486,9 +1404,9 @@ static void get_key_callback(void *c, struct key_params *params)
static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) 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; int err;
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
u8 key_idx = 0; u8 key_idx = 0;
u8 *mac_addr = NULL; u8 *mac_addr = NULL;
struct get_key_cookie cookie = { struct get_key_cookie cookie = {
...@@ -1506,30 +1424,17 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) ...@@ -1506,30 +1424,17 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_MAC]) if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
rtnl_lock(); if (!rdev->ops->get_key)
return -EOPNOTSUPP;
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
if (!rdev->ops->get_key) {
err = -EOPNOTSUPP;
goto out;
}
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) { if (!msg)
err = -ENOMEM; return -ENOMEM;
goto out;
}
hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
NL80211_CMD_NEW_KEY); NL80211_CMD_NEW_KEY);
if (IS_ERR(hdr))
if (IS_ERR(hdr)) { return PTR_ERR(hdr);
err = PTR_ERR(hdr);
goto free_msg;
}
cookie.msg = msg; cookie.msg = msg;
cookie.idx = key_idx; cookie.idx = key_idx;
...@@ -1549,28 +1454,21 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) ...@@ -1549,28 +1454,21 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
goto nla_put_failure; goto nla_put_failure;
genlmsg_end(msg, hdr); genlmsg_end(msg, hdr);
err = genlmsg_reply(msg, info); return genlmsg_reply(msg, info);
goto out;
nla_put_failure: nla_put_failure:
err = -ENOBUFS; err = -ENOBUFS;
free_msg: free_msg:
nlmsg_free(msg); nlmsg_free(msg);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) 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; struct key_parse key;
int err; int err;
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
int (*func)(struct wiphy *wiphy, struct net_device *netdev, int (*func)(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index); u8 key_index);
...@@ -1585,21 +1483,13 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) ...@@ -1585,21 +1483,13 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
if (!key.def && !key.defmgmt) if (!key.def && !key.defmgmt)
return -EINVAL; return -EINVAL;
rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
if (key.def) if (key.def)
func = rdev->ops->set_default_key; func = rdev->ops->set_default_key;
else else
func = rdev->ops->set_default_mgmt_key; func = rdev->ops->set_default_mgmt_key;
if (!func) { if (!func)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
wdev_lock(dev->ieee80211_ptr); wdev_lock(dev->ieee80211_ptr);
err = nl80211_key_allowed(dev->ieee80211_ptr); err = nl80211_key_allowed(dev->ieee80211_ptr);
...@@ -1616,21 +1506,14 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) ...@@ -1616,21 +1506,14 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
#endif #endif
wdev_unlock(dev->ieee80211_ptr); wdev_unlock(dev->ieee80211_ptr);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) 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; int err;
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
struct key_parse key; struct key_parse key;
u8 *mac_addr = NULL; u8 *mac_addr = NULL;
...@@ -1644,21 +1527,11 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) ...@@ -1644,21 +1527,11 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_MAC]) if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
rtnl_lock(); if (!rdev->ops->add_key)
return -EOPNOTSUPP;
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
if (!rdev->ops->add_key) {
err = -EOPNOTSUPP;
goto out;
}
if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) { if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr))
err = -EINVAL; return -EINVAL;
goto out;
}
wdev_lock(dev->ieee80211_ptr); wdev_lock(dev->ieee80211_ptr);
err = nl80211_key_allowed(dev->ieee80211_ptr); err = nl80211_key_allowed(dev->ieee80211_ptr);
...@@ -1667,20 +1540,14 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) ...@@ -1667,20 +1540,14 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
mac_addr, &key.p); mac_addr, &key.p);
wdev_unlock(dev->ieee80211_ptr); wdev_unlock(dev->ieee80211_ptr);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) 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; int err;
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
u8 *mac_addr = NULL; u8 *mac_addr = NULL;
struct key_parse key; struct key_parse key;
...@@ -1691,16 +1558,8 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) ...@@ -1691,16 +1558,8 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_MAC]) if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
rtnl_lock(); if (!rdev->ops->del_key)
return -EOPNOTSUPP;
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
if (!rdev->ops->del_key) {
err = -EOPNOTSUPP;
goto out;
}
wdev_lock(dev->ieee80211_ptr); wdev_lock(dev->ieee80211_ptr);
err = nl80211_key_allowed(dev->ieee80211_ptr); err = nl80211_key_allowed(dev->ieee80211_ptr);
...@@ -1717,13 +1576,6 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) ...@@ -1717,13 +1576,6 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
#endif #endif
wdev_unlock(dev->ieee80211_ptr); wdev_unlock(dev->ieee80211_ptr);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -1731,36 +1583,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) ...@@ -1731,36 +1583,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
{ {
int (*call)(struct wiphy *wiphy, struct net_device *dev, int (*call)(struct wiphy *wiphy, struct net_device *dev,
struct beacon_parameters *info); struct beacon_parameters *info);
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev = info->user_ptr[0];
int err; struct net_device *dev = info->user_ptr[1];
struct net_device *dev;
struct beacon_parameters params; struct beacon_parameters params;
int haveinfo = 0; int haveinfo = 0;
if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]))
return -EINVAL; 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 && if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
switch (info->genlhdr->cmd) { switch (info->genlhdr->cmd) {
case NL80211_CMD_NEW_BEACON: case NL80211_CMD_NEW_BEACON:
/* these are required for NEW_BEACON */ /* these are required for NEW_BEACON */
if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
!info->attrs[NL80211_ATTR_DTIM_PERIOD] || !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
!info->attrs[NL80211_ATTR_BEACON_HEAD]) { !info->attrs[NL80211_ATTR_BEACON_HEAD])
err = -EINVAL; return -EINVAL;
goto out;
}
call = rdev->ops->add_beacon; call = rdev->ops->add_beacon;
break; break;
...@@ -1769,14 +1610,11 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) ...@@ -1769,14 +1610,11 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
break; break;
default: default:
WARN_ON(1); WARN_ON(1);
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
} }
if (!call) { if (!call)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
memset(&params, 0, sizeof(params)); memset(&params, 0, sizeof(params));
...@@ -1806,53 +1644,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) ...@@ -1806,53 +1644,25 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
haveinfo = 1; haveinfo = 1;
} }
if (!haveinfo) { if (!haveinfo)
err = -EINVAL; return -EINVAL;
goto out;
}
err = call(&rdev->wiphy, dev, &params);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err; return call(&rdev->wiphy, dev, &params);
} }
static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) static int nl80211_del_beacon(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 = info->user_ptr[1];
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) { if (!rdev->ops->del_beacon)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
err = rdev->ops->del_beacon(&rdev->wiphy, dev);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err; return rdev->ops->del_beacon(&rdev->wiphy, dev);
} }
static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
...@@ -2049,12 +1859,12 @@ static int nl80211_dump_station(struct sk_buff *skb, ...@@ -2049,12 +1859,12 @@ static int nl80211_dump_station(struct sk_buff *skb,
static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) static int nl80211_get_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 = info->user_ptr[1];
struct net_device *dev;
struct station_info sinfo; struct station_info sinfo;
struct sk_buff *msg; struct sk_buff *msg;
u8 *mac_addr = NULL; u8 *mac_addr = NULL;
int err;
memset(&sinfo, 0, sizeof(sinfo)); memset(&sinfo, 0, sizeof(sinfo));
...@@ -2063,41 +1873,24 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) ...@@ -2063,41 +1873,24 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
rtnl_lock(); if (!rdev->ops->get_station)
return -EOPNOTSUPP;
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo);
if (err) if (err)
goto out_rtnl; return err;
if (!rdev->ops->get_station) {
err = -EOPNOTSUPP;
goto out;
}
err = rdev->ops->get_station(&rdev->wiphy, dev, mac_addr, &sinfo);
if (err)
goto out;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) if (!msg)
goto out; return -ENOMEM;
if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0,
dev, mac_addr, &sinfo) < 0) dev, mac_addr, &sinfo) < 0) {
goto out_free; nlmsg_free(msg);
return -ENOBUFS;
err = genlmsg_reply(msg, info); }
goto out;
out_free:
nlmsg_free(msg);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
return err; return genlmsg_reply(msg, info);
} }
/* /*
...@@ -2127,9 +1920,9 @@ static int get_vlan(struct genl_info *info, ...@@ -2127,9 +1920,9 @@ static int get_vlan(struct genl_info *info,
static int nl80211_set_station(struct sk_buff *skb, 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; int err;
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
struct station_parameters params; struct station_parameters params;
u8 *mac_addr = NULL; u8 *mac_addr = NULL;
...@@ -2167,12 +1960,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) ...@@ -2167,12 +1960,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
params.plink_action = params.plink_action =
nla_get_u8(info->attrs[NL80211_ATTR_STA_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); err = get_vlan(info, rdev, &params.vlan);
if (err) if (err)
goto out; goto out;
...@@ -2234,19 +2021,15 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) ...@@ -2234,19 +2021,15 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
out: out:
if (params.vlan) if (params.vlan)
dev_put(params.vlan); dev_put(params.vlan);
cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
return err; return err;
} }
static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) 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; int err;
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
struct station_parameters params; struct station_parameters params;
u8 *mac_addr = NULL; u8 *mac_addr = NULL;
...@@ -2283,18 +2066,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) ...@@ -2283,18 +2066,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
if (parse_station_flags(info, &params)) if (parse_station_flags(info, &params))
return -EINVAL; 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 && if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
err = -EINVAL; return -EINVAL;
goto out;
}
err = get_vlan(info, rdev, &params.vlan); err = get_vlan(info, rdev, &params.vlan);
if (err) if (err)
...@@ -2318,52 +2093,28 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) ...@@ -2318,52 +2093,28 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
out: out:
if (params.vlan) if (params.vlan)
dev_put(params.vlan); dev_put(params.vlan);
cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
return err; return err;
} }
static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) static int nl80211_del_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 = info->user_ptr[1];
struct net_device *dev;
u8 *mac_addr = NULL; u8 *mac_addr = NULL;
if (info->attrs[NL80211_ATTR_MAC]) if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(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 && if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
err = -EINVAL; return -EINVAL;
goto out;
}
if (!rdev->ops->del_station) {
err = -EOPNOTSUPP;
goto out;
}
err = rdev->ops->del_station(&rdev->wiphy, dev, mac_addr);
out: if (!rdev->ops->del_station)
cfg80211_unlock_rdev(rdev); return -EOPNOTSUPP;
dev_put(dev);
out_rtnl:
rtnl_unlock();
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, static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq,
...@@ -2490,9 +2241,9 @@ static int nl80211_dump_mpath(struct sk_buff *skb, ...@@ -2490,9 +2241,9 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) 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; int err;
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
struct mpath_info pinfo; struct mpath_info pinfo;
struct sk_buff *msg; struct sk_buff *msg;
u8 *dst = NULL; u8 *dst = NULL;
...@@ -2505,53 +2256,33 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) ...@@ -2505,53 +2256,33 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
dst = nla_data(info->attrs[NL80211_ATTR_MAC]); dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
rtnl_lock(); if (!rdev->ops->get_mpath)
return -EOPNOTSUPP;
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 (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo); err = rdev->ops->get_mpath(&rdev->wiphy, dev, dst, next_hop, &pinfo);
if (err) if (err)
goto out; return err;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) if (!msg)
goto out; return -ENOMEM;
if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0,
dev, dst, next_hop, &pinfo) < 0) dev, dst, next_hop, &pinfo) < 0) {
goto out_free; nlmsg_free(msg);
return -ENOBUFS;
err = genlmsg_reply(msg, info); }
goto out;
out_free:
nlmsg_free(msg);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
return err; return genlmsg_reply(msg, info);
} }
static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) static int nl80211_set_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 = info->user_ptr[1];
struct net_device *dev;
u8 *dst = NULL; u8 *dst = NULL;
u8 *next_hop = NULL; u8 *next_hop = NULL;
...@@ -2564,42 +2295,22 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) ...@@ -2564,42 +2295,22 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
dst = nla_data(info->attrs[NL80211_ATTR_MAC]); dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
rtnl_lock(); if (!rdev->ops->change_mpath)
return -EOPNOTSUPP;
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 (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
return -EOPNOTSUPP;
out: if (!netif_running(dev))
cfg80211_unlock_rdev(rdev); return -ENETDOWN;
dev_put(dev);
out_rtnl:
rtnl_unlock();
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) static int nl80211_new_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 = info->user_ptr[1];
struct net_device *dev;
u8 *dst = NULL; u8 *dst = NULL;
u8 *next_hop = NULL; u8 *next_hop = NULL;
...@@ -2612,75 +2323,37 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) ...@@ -2612,75 +2323,37 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
dst = nla_data(info->attrs[NL80211_ATTR_MAC]); dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
rtnl_lock(); if (!rdev->ops->add_mpath)
return -EOPNOTSUPP;
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 (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
return -EOPNOTSUPP;
out: if (!netif_running(dev))
cfg80211_unlock_rdev(rdev); return -ENETDOWN;
dev_put(dev);
out_rtnl:
rtnl_unlock();
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) static int nl80211_del_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 = info->user_ptr[1];
struct net_device *dev;
u8 *dst = NULL; u8 *dst = NULL;
if (info->attrs[NL80211_ATTR_MAC]) if (info->attrs[NL80211_ATTR_MAC])
dst = nla_data(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) static int nl80211_set_bss(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 = info->user_ptr[1];
struct net_device *dev;
struct bss_parameters params; struct bss_parameters params;
memset(&params, 0, sizeof(params)); memset(&params, 0, sizeof(params));
...@@ -2708,32 +2381,14 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) ...@@ -2708,32 +2381,14 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_AP_ISOLATE]) if (info->attrs[NL80211_ATTR_AP_ISOLATE])
params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]); params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]);
rtnl_lock(); if (!rdev->ops->change_bss)
return -EOPNOTSUPP;
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 && if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
err = rdev->ops->change_bss(&rdev->wiphy, dev, &params);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
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] = { static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
...@@ -2812,37 +2467,26 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) ...@@ -2812,37 +2467,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, static int nl80211_get_mesh_params(struct sk_buff *skb,
struct genl_info *info) struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct mesh_config cur_params; struct mesh_config cur_params;
int err; int err;
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
void *hdr; void *hdr;
struct nlattr *pinfoattr; struct nlattr *pinfoattr;
struct sk_buff *msg; struct sk_buff *msg;
rtnl_lock(); if (!rdev->ops->get_mesh_params)
return -EOPNOTSUPP;
/* 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;
}
/* Get the mesh params */ /* Get the mesh params */
err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params); err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params);
if (err) if (err)
goto out; return err;
/* Draw up a netlink message to send back */ /* Draw up a netlink message to send back */
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) { if (!msg)
err = -ENOBUFS; return -ENOMEM;
goto out;
}
hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
NL80211_CMD_GET_MESH_PARAMS); NL80211_CMD_GET_MESH_PARAMS);
if (!hdr) if (!hdr)
...@@ -2881,22 +2525,13 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, ...@@ -2881,22 +2525,13 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
cur_params.dot11MeshHWMPRootMode); cur_params.dot11MeshHWMPRootMode);
nla_nest_end(msg, pinfoattr); nla_nest_end(msg, pinfoattr);
genlmsg_end(msg, hdr); genlmsg_end(msg, hdr);
err = genlmsg_reply(msg, info); return genlmsg_reply(msg, info);
goto out;
nla_put_failure: nla_put_failure:
genlmsg_cancel(msg, hdr); genlmsg_cancel(msg, hdr);
nlmsg_free(msg); nlmsg_free(msg);
err = -EMSGSIZE; return -ENOBUFS;
out: }
/* Cleanup */
cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
return err;
}
#define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \
do {\ do {\
...@@ -2925,10 +2560,9 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A ...@@ -2925,10 +2560,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) static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
{ {
int err;
u32 mask; u32 mask;
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
struct mesh_config cfg; struct mesh_config cfg;
struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
struct nlattr *parent_attr; struct nlattr *parent_attr;
...@@ -2940,16 +2574,8 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) ...@@ -2940,16 +2574,8 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
parent_attr, nl80211_meshconf_params_policy)) parent_attr, nl80211_meshconf_params_policy))
return -EINVAL; return -EINVAL;
rtnl_lock(); if (!rdev->ops->set_mesh_params)
return -EOPNOTSUPP;
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;
}
/* This makes sure that there aren't more than 32 mesh config /* This makes sure that there aren't more than 32 mesh config
* parameters (otherwise our bitfield scheme would not work.) */ * parameters (otherwise our bitfield scheme would not work.) */
...@@ -2995,16 +2621,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) ...@@ -2995,16 +2621,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
nla_get_u8); nla_get_u8);
/* Apply changes */ /* Apply changes */
err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); return 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;
} }
#undef FILL_IN_MESH_PARAM_IF_SET #undef FILL_IN_MESH_PARAM_IF_SET
...@@ -3187,8 +2804,8 @@ static int validate_scan_freqs(struct nlattr *freqs) ...@@ -3187,8 +2804,8 @@ static int validate_scan_freqs(struct nlattr *freqs)
static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
struct cfg80211_scan_request *request; struct cfg80211_scan_request *request;
struct cfg80211_ssid *ssid; struct cfg80211_ssid *ssid;
struct ieee80211_channel *channel; struct ieee80211_channel *channel;
...@@ -3201,36 +2818,22 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) ...@@ -3201,36 +2818,22 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
return -EINVAL; return -EINVAL;
rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto out_rtnl;
wiphy = &rdev->wiphy; wiphy = &rdev->wiphy;
if (!rdev->ops->scan) { if (!rdev->ops->scan)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
if (!netif_running(dev)) { if (!netif_running(dev))
err = -ENETDOWN; return -ENETDOWN;
goto out;
}
if (rdev->scan_req) { if (rdev->scan_req)
err = -EBUSY; return -EBUSY;
goto out;
}
if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
n_channels = validate_scan_freqs( n_channels = validate_scan_freqs(
info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
if (!n_channels) { if (!n_channels)
err = -EINVAL; return -EINVAL;
goto out;
}
} else { } else {
n_channels = 0; n_channels = 0;
...@@ -3243,29 +2846,23 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) ...@@ -3243,29 +2846,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) nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
n_ssids++; n_ssids++;
if (n_ssids > wiphy->max_scan_ssids) { if (n_ssids > wiphy->max_scan_ssids)
err = -EINVAL; return -EINVAL;
goto out;
}
if (info->attrs[NL80211_ATTR_IE]) if (info->attrs[NL80211_ATTR_IE])
ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
else else
ie_len = 0; ie_len = 0;
if (ie_len > wiphy->max_scan_ie_len) { if (ie_len > wiphy->max_scan_ie_len)
err = -EINVAL; return -EINVAL;
goto out;
}
request = kzalloc(sizeof(*request) request = kzalloc(sizeof(*request)
+ sizeof(*ssid) * n_ssids + sizeof(*ssid) * n_ssids
+ sizeof(channel) * n_channels + sizeof(channel) * n_channels
+ ie_len, GFP_KERNEL); + ie_len, GFP_KERNEL);
if (!request) { if (!request)
err = -ENOMEM; return -ENOMEM;
goto out;
}
if (n_ssids) if (n_ssids)
request->ssids = (void *)&request->channels[n_channels]; request->ssids = (void *)&request->channels[n_channels];
...@@ -3353,18 +2950,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) ...@@ -3353,18 +2950,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
if (!err) { if (!err) {
nl80211_send_scan_start(rdev, dev); nl80211_send_scan_start(rdev, dev);
dev_hold(dev); dev_hold(dev);
} } else {
out_free: out_free:
if (err) {
rdev->scan_req = NULL; rdev->scan_req = NULL;
kfree(request); kfree(request);
} }
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -3643,8 +3233,8 @@ static bool nl80211_valid_cipher_suite(u32 cipher) ...@@ -3643,8 +3233,8 @@ static bool nl80211_valid_cipher_suite(u32 cipher)
static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
const u8 *bssid, *ssid, *ie = NULL; const u8 *bssid, *ssid, *ie = NULL;
int err, ssid_len, ie_len = 0; int err, ssid_len, ie_len = 0;
...@@ -3686,12 +3276,6 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) ...@@ -3686,12 +3276,6 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
key.p.key = NULL; key.p.key = NULL;
} }
rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
if (key.idx >= 0) { if (key.idx >= 0) {
int i; int i;
bool ok = false; bool ok = false;
...@@ -3701,35 +3285,25 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) ...@@ -3701,35 +3285,25 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
break; break;
} }
} }
if (!ok) { if (!ok)
err = -EINVAL; return -EINVAL;
goto out;
}
} }
if (!rdev->ops->auth) { if (!rdev->ops->auth)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
if (!netif_running(dev)) { if (!netif_running(dev))
err = -ENETDOWN; return -ENETDOWN;
goto out;
}
bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
chan = ieee80211_get_channel(&rdev->wiphy, chan = ieee80211_get_channel(&rdev->wiphy,
nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED))
err = -EINVAL; return -EINVAL;
goto out;
}
ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
...@@ -3740,24 +3314,15 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) ...@@ -3740,24 +3314,15 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
} }
auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
if (!nl80211_valid_auth_type(auth_type)) { if (!nl80211_valid_auth_type(auth_type))
err = -EINVAL; return -EINVAL;
goto out;
}
local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
ssid, ssid_len, ie, ie_len, ssid, ssid_len, ie, ie_len,
key.p.key, key.p.key_len, key.idx, key.p.key, key.p.key_len, key.idx,
local_state_change); local_state_change);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err;
} }
static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
...@@ -3841,8 +3406,8 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, ...@@ -3841,8 +3406,8 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
struct cfg80211_crypto_settings crypto; struct cfg80211_crypto_settings crypto;
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
...@@ -3857,36 +3422,22 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) ...@@ -3857,36 +3422,22 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
!info->attrs[NL80211_ATTR_WIPHY_FREQ]) !info->attrs[NL80211_ATTR_WIPHY_FREQ])
return -EINVAL; return -EINVAL;
rtnl_lock(); if (!rdev->ops->assoc)
return -EOPNOTSUPP;
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 && if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
if (!netif_running(dev)) { if (!netif_running(dev))
err = -ENETDOWN; return -ENETDOWN;
goto out;
}
bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
chan = ieee80211_get_channel(&rdev->wiphy, chan = ieee80211_get_channel(&rdev->wiphy,
nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED))
err = -EINVAL; return -EINVAL;
goto out;
}
ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
...@@ -3901,10 +3452,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) ...@@ -3901,10 +3452,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
if (mfp == NL80211_MFP_REQUIRED) if (mfp == NL80211_MFP_REQUIRED)
use_mfp = true; use_mfp = true;
else if (mfp != NL80211_MFP_NO) { else if (mfp != NL80211_MFP_NO)
err = -EINVAL; return -EINVAL;
goto out;
}
} }
if (info->attrs[NL80211_ATTR_PREV_BSSID]) if (info->attrs[NL80211_ATTR_PREV_BSSID])
...@@ -3916,20 +3465,15 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) ...@@ -3916,20 +3465,15 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
ssid, ssid_len, ie, ie_len, use_mfp, ssid, ssid_len, ie, ie_len, use_mfp,
&crypto); &crypto);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
const u8 *ie = NULL, *bssid; const u8 *ie = NULL, *bssid;
int err, ie_len = 0; int ie_len = 0;
u16 reason_code; u16 reason_code;
bool local_state_change; bool local_state_change;
...@@ -3942,35 +3486,22 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) ...@@ -3942,35 +3486,22 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
if (!info->attrs[NL80211_ATTR_REASON_CODE]) if (!info->attrs[NL80211_ATTR_REASON_CODE])
return -EINVAL; return -EINVAL;
rtnl_lock(); if (!rdev->ops->deauth)
return -EOPNOTSUPP;
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 && if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
if (!netif_running(dev)) { if (!netif_running(dev))
err = -ENETDOWN; return -ENETDOWN;
goto out;
}
bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
if (reason_code == 0) { if (reason_code == 0) {
/* Reason Code 0 is reserved */ /* Reason Code 0 is reserved */
err = -EINVAL; return -EINVAL;
goto out;
} }
if (info->attrs[NL80211_ATTR_IE]) { if (info->attrs[NL80211_ATTR_IE]) {
...@@ -3980,23 +3511,16 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) ...@@ -3980,23 +3511,16 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code, return cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
local_state_change); local_state_change);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err;
} }
static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
const u8 *ie = NULL, *bssid; const u8 *ie = NULL, *bssid;
int err, ie_len = 0; int ie_len = 0;
u16 reason_code; u16 reason_code;
bool local_state_change; bool local_state_change;
...@@ -4009,35 +3533,22 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) ...@@ -4009,35 +3533,22 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
if (!info->attrs[NL80211_ATTR_REASON_CODE]) if (!info->attrs[NL80211_ATTR_REASON_CODE])
return -EINVAL; return -EINVAL;
rtnl_lock(); if (!rdev->ops->disassoc)
return -EOPNOTSUPP;
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 && if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
if (!netif_running(dev)) { if (!netif_running(dev))
err = -ENETDOWN; return -ENETDOWN;
goto out;
}
bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
if (reason_code == 0) { if (reason_code == 0) {
/* Reason Code 0 is reserved */ /* Reason Code 0 is reserved */
err = -EINVAL; return -EINVAL;
goto out;
} }
if (info->attrs[NL80211_ATTR_IE]) { if (info->attrs[NL80211_ATTR_IE]) {
...@@ -4047,21 +3558,14 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) ...@@ -4047,21 +3558,14 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code, return cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
local_state_change); local_state_change);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err;
} }
static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
struct cfg80211_ibss_params ibss; struct cfg80211_ibss_params ibss;
struct wiphy *wiphy; struct wiphy *wiphy;
struct cfg80211_cached_keys *connkeys = NULL; struct cfg80211_cached_keys *connkeys = NULL;
...@@ -4086,26 +3590,14 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) ...@@ -4086,26 +3590,14 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
return -EINVAL; return -EINVAL;
} }
rtnl_lock(); if (!rdev->ops->join_ibss)
return -EOPNOTSUPP;
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) { if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
if (!netif_running(dev)) { if (!netif_running(dev))
err = -ENETDOWN; return -ENETDOWN;
goto out;
}
wiphy = &rdev->wiphy; wiphy = &rdev->wiphy;
...@@ -4123,24 +3615,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) ...@@ -4123,24 +3615,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
if (!ibss.channel || if (!ibss.channel ||
ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || ibss.channel->flags & IEEE80211_CHAN_NO_IBSS ||
ibss.channel->flags & IEEE80211_CHAN_DISABLED) { ibss.channel->flags & IEEE80211_CHAN_DISABLED)
err = -EINVAL; return -EINVAL;
goto out;
}
ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; 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]) { if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
u8 *rates = u8 *rates =
nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
...@@ -4150,10 +3630,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) ...@@ -4150,10 +3630,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
wiphy->bands[ibss.channel->band]; wiphy->bands[ibss.channel->band];
int i, j; int i, j;
if (n_rates == 0) { if (n_rates == 0)
err = -EINVAL; return -EINVAL;
goto out;
}
for (i = 0; i < n_rates; i++) { for (i = 0; i < n_rates; i++) {
int rate = (rates[i] & 0x7f) * 5; int rate = (rates[i] & 0x7f) * 5;
...@@ -4166,60 +3644,39 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) ...@@ -4166,60 +3644,39 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
break; break;
} }
} }
if (!found) { if (!found)
err = -EINVAL; return -EINVAL;
goto out;
}
} }
} }
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: err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
if (err) if (err)
kfree(connkeys); kfree(connkeys);
rtnl_unlock();
return err; return err;
} }
static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
int err;
rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
if (!rdev->ops->leave_ibss) { if (!rdev->ops->leave_ibss)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
err = -EOPNOTSUPP;
goto out;
}
if (!netif_running(dev)) { if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
err = -ENETDOWN; return -EOPNOTSUPP;
goto out;
}
err = cfg80211_leave_ibss(rdev, dev, false); if (!netif_running(dev))
return -ENETDOWN;
out: return cfg80211_leave_ibss(rdev, dev, false);
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err;
} }
#ifdef CONFIG_NL80211_TESTMODE #ifdef CONFIG_NL80211_TESTMODE
...@@ -4229,20 +3686,12 @@ static struct genl_multicast_group nl80211_testmode_mcgrp = { ...@@ -4229,20 +3686,12 @@ static struct genl_multicast_group nl80211_testmode_mcgrp = {
static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) 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; int err;
if (!info->attrs[NL80211_ATTR_TESTDATA]) if (!info->attrs[NL80211_ATTR_TESTDATA])
return -EINVAL; return -EINVAL;
rtnl_lock();
rdev = cfg80211_get_dev_from_info(info);
if (IS_ERR(rdev)) {
err = PTR_ERR(rdev);
goto unlock_rtnl;
}
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
if (rdev->ops->testmode_cmd) { if (rdev->ops->testmode_cmd) {
rdev->testmode_info = info; rdev->testmode_info = info;
...@@ -4252,10 +3701,6 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) ...@@ -4252,10 +3701,6 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
rdev->testmode_info = NULL; rdev->testmode_info = NULL;
} }
cfg80211_unlock_rdev(rdev);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -4346,8 +3791,8 @@ EXPORT_SYMBOL(cfg80211_testmode_event); ...@@ -4346,8 +3791,8 @@ EXPORT_SYMBOL(cfg80211_testmode_event);
static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
struct cfg80211_connect_params connect; struct cfg80211_connect_params connect;
struct wiphy *wiphy; struct wiphy *wiphy;
struct cfg80211_cached_keys *connkeys = NULL; struct cfg80211_cached_keys *connkeys = NULL;
...@@ -4376,22 +3821,13 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) ...@@ -4376,22 +3821,13 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
NL80211_MAX_NR_CIPHER_SUITES); NL80211_MAX_NR_CIPHER_SUITES);
if (err) if (err)
return 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 && if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
if (!netif_running(dev)) { if (!netif_running(dev))
err = -ENETDOWN; return -ENETDOWN;
goto out;
}
wiphy = &rdev->wiphy; wiphy = &rdev->wiphy;
...@@ -4410,39 +3846,27 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) ...@@ -4410,39 +3846,27 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
ieee80211_get_channel(wiphy, ieee80211_get_channel(wiphy,
nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
if (!connect.channel || if (!connect.channel ||
connect.channel->flags & IEEE80211_CHAN_DISABLED) { connect.channel->flags & IEEE80211_CHAN_DISABLED)
err = -EINVAL; return -EINVAL;
goto out;
}
} }
if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) { if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
connkeys = nl80211_parse_connkeys(rdev, connkeys = nl80211_parse_connkeys(rdev,
info->attrs[NL80211_ATTR_KEYS]); info->attrs[NL80211_ATTR_KEYS]);
if (IS_ERR(connkeys)) { if (IS_ERR(connkeys))
err = PTR_ERR(connkeys); return PTR_ERR(connkeys);
connkeys = NULL;
goto out;
}
} }
err = cfg80211_connect(rdev, dev, &connect, connkeys); err = cfg80211_connect(rdev, dev, &connect, connkeys);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
if (err) if (err)
kfree(connkeys); kfree(connkeys);
rtnl_unlock();
return err; return err;
} }
static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
int err;
u16 reason; u16 reason;
if (!info->attrs[NL80211_ATTR_REASON_CODE]) if (!info->attrs[NL80211_ATTR_REASON_CODE])
...@@ -4453,36 +3877,19 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) ...@@ -4453,36 +3877,19 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
if (reason == 0) if (reason == 0)
return -EINVAL; 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 && if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
if (!netif_running(dev)) {
err = -ENETDOWN;
goto out;
}
err = cfg80211_disconnect(rdev, dev, reason, true); if (!netif_running(dev))
return -ENETDOWN;
out: return cfg80211_disconnect(rdev, dev, reason, true);
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err;
} }
static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) 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; struct net *net;
int err; int err;
u32 pid; u32 pid;
...@@ -4492,43 +3899,26 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) ...@@ -4492,43 +3899,26 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
pid = nla_get_u32(info->attrs[NL80211_ATTR_PID]); 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); net = get_net_ns_by_pid(pid);
if (IS_ERR(net)) { if (IS_ERR(net))
err = PTR_ERR(net); return PTR_ERR(net);
goto out;
}
err = 0; err = 0;
/* check if anything to do */ /* check if anything to do */
if (net_eq(wiphy_net(&rdev->wiphy), net)) if (!net_eq(wiphy_net(&rdev->wiphy), net))
goto out_put_net; err = cfg80211_switch_netns(rdev, net);
err = cfg80211_switch_netns(rdev, net);
out_put_net:
put_net(net); put_net(net);
out:
cfg80211_unlock_rdev(rdev);
out_rtnl:
rtnl_unlock();
return err; return err;
} }
static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) 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, int (*rdev_ops)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_pmksa *pmksa) = NULL; struct cfg80211_pmksa *pmksa) = NULL;
int err; struct net_device *dev = info->user_ptr[1];
struct net_device *dev;
struct cfg80211_pmksa pmksa; struct cfg80211_pmksa pmksa;
memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
...@@ -4539,20 +3929,12 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) ...@@ -4539,20 +3929,12 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
if (!info->attrs[NL80211_ATTR_PMKID]) if (!info->attrs[NL80211_ATTR_PMKID])
return -EINVAL; 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.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
switch (info->genlhdr->cmd) { switch (info->genlhdr->cmd) {
case NL80211_CMD_SET_PMKSA: case NL80211_CMD_SET_PMKSA:
...@@ -4566,62 +3948,32 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) ...@@ -4566,62 +3948,32 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
break; break;
} }
if (!rdev_ops) { if (!rdev_ops)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
err = rdev_ops(&rdev->wiphy, dev, &pmksa);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
return err; return rdev_ops(&rdev->wiphy, dev, &pmksa);
} }
static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) static int nl80211_flush_pmksa(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 = info->user_ptr[1];
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 && if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) { dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
if (!rdev->ops->flush_pmksa) {
err = -EOPNOTSUPP;
goto out;
}
err = rdev->ops->flush_pmksa(&rdev->wiphy, dev);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
out_rtnl:
rtnl_unlock();
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, static int nl80211_remain_on_channel(struct sk_buff *skb,
struct genl_info *info) struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
struct sk_buff *msg; struct sk_buff *msg;
void *hdr; void *hdr;
...@@ -4643,21 +3995,11 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, ...@@ -4643,21 +3995,11 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
if (!duration || !msecs_to_jiffies(duration) || duration > 5000) if (!duration || !msecs_to_jiffies(duration) || duration > 5000)
return -EINVAL; return -EINVAL;
rtnl_lock(); if (!rdev->ops->remain_on_channel)
return -EOPNOTSUPP;
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)) { if (!netif_running(dev))
err = -ENETDOWN; return -ENETDOWN;
goto out;
}
if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
channel_type = nla_get_u32( channel_type = nla_get_u32(
...@@ -4665,24 +4007,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, ...@@ -4665,24 +4007,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
if (channel_type != NL80211_CHAN_NO_HT && if (channel_type != NL80211_CHAN_NO_HT &&
channel_type != NL80211_CHAN_HT20 && channel_type != NL80211_CHAN_HT20 &&
channel_type != NL80211_CHAN_HT40PLUS && channel_type != NL80211_CHAN_HT40PLUS &&
channel_type != NL80211_CHAN_HT40MINUS) { channel_type != NL80211_CHAN_HT40MINUS)
err = -EINVAL; return -EINVAL;
goto out;
}
} }
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
chan = rdev_freq_to_chan(rdev, freq, channel_type); chan = rdev_freq_to_chan(rdev, freq, channel_type);
if (chan == NULL) { if (chan == NULL)
err = -EINVAL; return -EINVAL;
goto out;
}
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) { if (!msg)
err = -ENOMEM; return -ENOMEM;
goto out;
}
hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
NL80211_CMD_REMAIN_ON_CHANNEL); NL80211_CMD_REMAIN_ON_CHANNEL);
...@@ -4701,58 +4037,35 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, ...@@ -4701,58 +4037,35 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
genlmsg_end(msg, hdr); genlmsg_end(msg, hdr);
err = genlmsg_reply(msg, info);
goto out; return genlmsg_reply(msg, info);
nla_put_failure: nla_put_failure:
err = -ENOBUFS; err = -ENOBUFS;
free_msg: free_msg:
nlmsg_free(msg); nlmsg_free(msg);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
struct genl_info *info) struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
u64 cookie; u64 cookie;
int err;
if (!info->attrs[NL80211_ATTR_COOKIE]) if (!info->attrs[NL80211_ATTR_COOKIE])
return -EINVAL; return -EINVAL;
rtnl_lock(); if (!rdev->ops->cancel_remain_on_channel)
return -EOPNOTSUPP;
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)) { if (!netif_running(dev))
err = -ENETDOWN; return -ENETDOWN;
goto out;
}
cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
err = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err;
} }
static u32 rateset_to_mask(struct ieee80211_supported_band *sband, static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
...@@ -4788,26 +4101,18 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, ...@@ -4788,26 +4101,18 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
struct genl_info *info) struct genl_info *info)
{ {
struct nlattr *tb[NL80211_TXRATE_MAX + 1]; 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; struct cfg80211_bitrate_mask mask;
int err, rem, i; int rem, i;
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
struct nlattr *tx_rates; struct nlattr *tx_rates;
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
if (info->attrs[NL80211_ATTR_TX_RATES] == NULL) if (info->attrs[NL80211_ATTR_TX_RATES] == NULL)
return -EINVAL; return -EINVAL;
rtnl_lock(); if (!rdev->ops->set_bitrate_mask)
return -EOPNOTSUPP;
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;
}
memset(&mask, 0, sizeof(mask)); memset(&mask, 0, sizeof(mask));
/* Default to all rates enabled */ /* Default to all rates enabled */
...@@ -4824,15 +4129,11 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, ...@@ -4824,15 +4129,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) nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem)
{ {
enum ieee80211_band band = nla_type(tx_rates); enum ieee80211_band band = nla_type(tx_rates);
if (band < 0 || band >= IEEE80211_NUM_BANDS) { if (band < 0 || band >= IEEE80211_NUM_BANDS)
err = -EINVAL; return -EINVAL;
goto unlock;
}
sband = rdev->wiphy.bands[band]; sband = rdev->wiphy.bands[band];
if (sband == NULL) { if (sband == NULL)
err = -EINVAL; return -EINVAL;
goto unlock;
}
nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
nla_len(tx_rates), nl80211_txattr_policy); nla_len(tx_rates), nl80211_txattr_policy);
if (tb[NL80211_TXRATE_LEGACY]) { if (tb[NL80211_TXRATE_LEGACY]) {
...@@ -4840,29 +4141,19 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, ...@@ -4840,29 +4141,19 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
sband, sband,
nla_data(tb[NL80211_TXRATE_LEGACY]), nla_data(tb[NL80211_TXRATE_LEGACY]),
nla_len(tb[NL80211_TXRATE_LEGACY])); nla_len(tb[NL80211_TXRATE_LEGACY]));
if (mask.control[band].legacy == 0) { if (mask.control[band].legacy == 0)
err = -EINVAL; return -EINVAL;
goto unlock;
}
} }
} }
err = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask); return rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask);
unlock:
dev_put(dev);
cfg80211_unlock_rdev(rdev);
unlock_rtnl:
rtnl_unlock();
return err;
} }
static int nl80211_register_mgmt(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 cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION;
int err;
if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
return -EINVAL; return -EINVAL;
...@@ -4870,44 +4161,28 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) ...@@ -4870,44 +4161,28 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_FRAME_TYPE]) if (info->attrs[NL80211_ATTR_FRAME_TYPE])
frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
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 && if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
/* not much point in registering if we can't reply */ /* not much point in registering if we can't reply */
if (!rdev->ops->mgmt_tx) { if (!rdev->ops->mgmt_tx)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
err = cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid,
frame_type, frame_type,
nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
nla_len(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_tx_mgmt(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 cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
bool channel_type_valid = false; bool channel_type_valid = false;
...@@ -4921,31 +4196,19 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) ...@@ -4921,31 +4196,19 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
!info->attrs[NL80211_ATTR_WIPHY_FREQ]) !info->attrs[NL80211_ATTR_WIPHY_FREQ])
return -EINVAL; return -EINVAL;
rtnl_lock(); if (!rdev->ops->mgmt_tx)
return -EOPNOTSUPP;
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
if (!rdev->ops->mgmt_tx) {
err = -EOPNOTSUPP;
goto out;
}
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) { dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
if (!netif_running(dev)) { if (!netif_running(dev))
err = -ENETDOWN; return -ENETDOWN;
goto out;
}
if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
channel_type = nla_get_u32( channel_type = nla_get_u32(
...@@ -4953,25 +4216,19 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) ...@@ -4953,25 +4216,19 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
if (channel_type != NL80211_CHAN_NO_HT && if (channel_type != NL80211_CHAN_NO_HT &&
channel_type != NL80211_CHAN_HT20 && channel_type != NL80211_CHAN_HT20 &&
channel_type != NL80211_CHAN_HT40PLUS && channel_type != NL80211_CHAN_HT40PLUS &&
channel_type != NL80211_CHAN_HT40MINUS) { channel_type != NL80211_CHAN_HT40MINUS)
err = -EINVAL; return -EINVAL;
goto out;
}
channel_type_valid = true; channel_type_valid = true;
} }
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
chan = rdev_freq_to_chan(rdev, freq, channel_type); chan = rdev_freq_to_chan(rdev, freq, channel_type);
if (chan == NULL) { if (chan == NULL)
err = -EINVAL; return -EINVAL;
goto out;
}
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) { if (!msg)
err = -ENOMEM; return -ENOMEM;
goto out;
}
hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
NL80211_CMD_FRAME); NL80211_CMD_FRAME);
...@@ -4991,110 +4248,72 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) ...@@ -4991,110 +4248,72 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
genlmsg_end(msg, hdr); genlmsg_end(msg, hdr);
err = genlmsg_reply(msg, info); return genlmsg_reply(msg, info);
goto out;
nla_put_failure: nla_put_failure:
err = -ENOBUFS; err = -ENOBUFS;
free_msg: free_msg:
nlmsg_free(msg); nlmsg_free(msg);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) 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 wireless_dev *wdev;
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
u8 ps_state; u8 ps_state;
bool state; bool state;
int err; int err;
if (!info->attrs[NL80211_ATTR_PS_STATE]) { if (!info->attrs[NL80211_ATTR_PS_STATE])
err = -EINVAL; return -EINVAL;
goto out;
}
ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]); ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]);
if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) { if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED)
err = -EINVAL; return -EINVAL;
goto out;
}
rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
wdev = dev->ieee80211_ptr; wdev = dev->ieee80211_ptr;
if (!rdev->ops->set_power_mgmt) { if (!rdev->ops->set_power_mgmt)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto unlock_rdev;
}
state = (ps_state == NL80211_PS_ENABLED) ? true : false; state = (ps_state == NL80211_PS_ENABLED) ? true : false;
if (state == wdev->ps) if (state == wdev->ps)
goto unlock_rdev; return 0;
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);
unlock_rtnl:
rtnl_unlock();
out: err = rdev->ops->set_power_mgmt(wdev->wiphy, dev, state,
wdev->ps_timeout);
if (!err)
wdev->ps = state;
return err; return err;
} }
static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) 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; enum nl80211_ps_state ps_state;
struct wireless_dev *wdev; struct wireless_dev *wdev;
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
struct sk_buff *msg; struct sk_buff *msg;
void *hdr; void *hdr;
int err; int err;
rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
wdev = dev->ieee80211_ptr; wdev = dev->ieee80211_ptr;
if (!rdev->ops->set_power_mgmt) { if (!rdev->ops->set_power_mgmt)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto out;
}
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) { if (!msg)
err = -ENOMEM; return -ENOMEM;
goto out;
}
hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
NL80211_CMD_GET_POWER_SAVE); NL80211_CMD_GET_POWER_SAVE);
if (!hdr) { if (!hdr) {
err = -ENOMEM; err = -ENOBUFS;
goto free_msg; goto free_msg;
} }
...@@ -5106,22 +4325,12 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) ...@@ -5106,22 +4325,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); NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state);
genlmsg_end(msg, hdr); genlmsg_end(msg, hdr);
err = genlmsg_reply(msg, info); return genlmsg_reply(msg, info);
goto out;
nla_put_failure: nla_put_failure:
err = -ENOBUFS; err = -ENOBUFS;
free_msg:
free_msg:
nlmsg_free(msg); nlmsg_free(msg);
out:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
return err; return err;
} }
...@@ -5135,43 +4344,24 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { ...@@ -5135,43 +4344,24 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = {
static int nl80211_set_cqm_rssi(struct genl_info *info, static int nl80211_set_cqm_rssi(struct genl_info *info,
s32 threshold, u32 hysteresis) s32 threshold, u32 hysteresis)
{ {
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct wireless_dev *wdev; struct wireless_dev *wdev;
struct net_device *dev; struct net_device *dev = info->user_ptr[1];
int err;
if (threshold > 0) if (threshold > 0)
return -EINVAL; return -EINVAL;
rtnl_lock();
err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
if (err)
goto unlock_rtnl;
wdev = dev->ieee80211_ptr; wdev = dev->ieee80211_ptr;
if (!rdev->ops->set_cqm_rssi_config) { if (!rdev->ops->set_cqm_rssi_config)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto unlock_rdev;
}
if (wdev->iftype != NL80211_IFTYPE_STATION && if (wdev->iftype != NL80211_IFTYPE_STATION &&
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) { wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
err = -EOPNOTSUPP; return -EOPNOTSUPP;
goto unlock_rdev;
}
err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev,
threshold, hysteresis);
unlock_rdev:
cfg80211_unlock_rdev(rdev);
dev_put(dev);
unlock_rtnl:
rtnl_unlock();
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) static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
...@@ -5205,6 +4395,54 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) ...@@ -5205,6 +4395,54 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
return err; return err;
} }
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
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;
}
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[] = { static struct genl_ops nl80211_ops[] = {
{ {
.cmd = NL80211_CMD_GET_WIPHY, .cmd = NL80211_CMD_GET_WIPHY,
...@@ -5212,12 +4450,14 @@ static struct genl_ops nl80211_ops[] = { ...@@ -5212,12 +4450,14 @@ static struct genl_ops nl80211_ops[] = {
.dumpit = nl80211_dump_wiphy, .dumpit = nl80211_dump_wiphy,
.policy = nl80211_policy, .policy = nl80211_policy,
/* can be retrieved by unprivileged users */ /* can be retrieved by unprivileged users */
.internal_flags = NL80211_FLAG_NEED_WIPHY,
}, },
{ {
.cmd = NL80211_CMD_SET_WIPHY, .cmd = NL80211_CMD_SET_WIPHY,
.doit = nl80211_set_wiphy, .doit = nl80211_set_wiphy,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_GET_INTERFACE, .cmd = NL80211_CMD_GET_INTERFACE,
...@@ -5225,90 +4465,119 @@ static struct genl_ops nl80211_ops[] = { ...@@ -5225,90 +4465,119 @@ static struct genl_ops nl80211_ops[] = {
.dumpit = nl80211_dump_interface, .dumpit = nl80211_dump_interface,
.policy = nl80211_policy, .policy = nl80211_policy,
/* can be retrieved by unprivileged users */ /* can be retrieved by unprivileged users */
.internal_flags = NL80211_FLAG_NEED_NETDEV,
}, },
{ {
.cmd = NL80211_CMD_SET_INTERFACE, .cmd = NL80211_CMD_SET_INTERFACE,
.doit = nl80211_set_interface, .doit = nl80211_set_interface,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_NEW_INTERFACE, .cmd = NL80211_CMD_NEW_INTERFACE,
.doit = nl80211_new_interface, .doit = nl80211_new_interface,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_WIPHY |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_DEL_INTERFACE, .cmd = NL80211_CMD_DEL_INTERFACE,
.doit = nl80211_del_interface, .doit = nl80211_del_interface,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_GET_KEY, .cmd = NL80211_CMD_GET_KEY,
.doit = nl80211_get_key, .doit = nl80211_get_key,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_SET_KEY, .cmd = NL80211_CMD_SET_KEY,
.doit = nl80211_set_key, .doit = nl80211_set_key,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_NEW_KEY, .cmd = NL80211_CMD_NEW_KEY,
.doit = nl80211_new_key, .doit = nl80211_new_key,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_DEL_KEY, .cmd = NL80211_CMD_DEL_KEY,
.doit = nl80211_del_key, .doit = nl80211_del_key,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_SET_BEACON, .cmd = NL80211_CMD_SET_BEACON,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.doit = nl80211_addset_beacon, .doit = nl80211_addset_beacon,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_NEW_BEACON, .cmd = NL80211_CMD_NEW_BEACON,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.doit = nl80211_addset_beacon, .doit = nl80211_addset_beacon,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_DEL_BEACON, .cmd = NL80211_CMD_DEL_BEACON,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.doit = nl80211_del_beacon, .doit = nl80211_del_beacon,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_GET_STATION, .cmd = NL80211_CMD_GET_STATION,
.doit = nl80211_get_station, .doit = nl80211_get_station,
.dumpit = nl80211_dump_station, .dumpit = nl80211_dump_station,
.policy = nl80211_policy, .policy = nl80211_policy,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_SET_STATION, .cmd = NL80211_CMD_SET_STATION,
.doit = nl80211_set_station, .doit = nl80211_set_station,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_NEW_STATION, .cmd = NL80211_CMD_NEW_STATION,
.doit = nl80211_new_station, .doit = nl80211_new_station,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_DEL_STATION, .cmd = NL80211_CMD_DEL_STATION,
.doit = nl80211_del_station, .doit = nl80211_del_station,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_GET_MPATH, .cmd = NL80211_CMD_GET_MPATH,
...@@ -5316,30 +4585,40 @@ static struct genl_ops nl80211_ops[] = { ...@@ -5316,30 +4585,40 @@ static struct genl_ops nl80211_ops[] = {
.dumpit = nl80211_dump_mpath, .dumpit = nl80211_dump_mpath,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_SET_MPATH, .cmd = NL80211_CMD_SET_MPATH,
.doit = nl80211_set_mpath, .doit = nl80211_set_mpath,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_NEW_MPATH, .cmd = NL80211_CMD_NEW_MPATH,
.doit = nl80211_new_mpath, .doit = nl80211_new_mpath,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_DEL_MPATH, .cmd = NL80211_CMD_DEL_MPATH,
.doit = nl80211_del_mpath, .doit = nl80211_del_mpath,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_SET_BSS, .cmd = NL80211_CMD_SET_BSS,
.doit = nl80211_set_bss, .doit = nl80211_set_bss,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_GET_REG, .cmd = NL80211_CMD_GET_REG,
...@@ -5364,18 +4643,24 @@ static struct genl_ops nl80211_ops[] = { ...@@ -5364,18 +4643,24 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_get_mesh_params, .doit = nl80211_get_mesh_params,
.policy = nl80211_policy, .policy = nl80211_policy,
/* can be retrieved by unprivileged users */ /* can be retrieved by unprivileged users */
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_SET_MESH_PARAMS, .cmd = NL80211_CMD_SET_MESH_PARAMS,
.doit = nl80211_set_mesh_params, .doit = nl80211_set_mesh_params,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_TRIGGER_SCAN, .cmd = NL80211_CMD_TRIGGER_SCAN,
.doit = nl80211_trigger_scan, .doit = nl80211_trigger_scan,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_GET_SCAN, .cmd = NL80211_CMD_GET_SCAN,
...@@ -5387,36 +4672,48 @@ static struct genl_ops nl80211_ops[] = { ...@@ -5387,36 +4672,48 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_authenticate, .doit = nl80211_authenticate,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_ASSOCIATE, .cmd = NL80211_CMD_ASSOCIATE,
.doit = nl80211_associate, .doit = nl80211_associate,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_DEAUTHENTICATE, .cmd = NL80211_CMD_DEAUTHENTICATE,
.doit = nl80211_deauthenticate, .doit = nl80211_deauthenticate,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_DISASSOCIATE, .cmd = NL80211_CMD_DISASSOCIATE,
.doit = nl80211_disassociate, .doit = nl80211_disassociate,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_JOIN_IBSS, .cmd = NL80211_CMD_JOIN_IBSS,
.doit = nl80211_join_ibss, .doit = nl80211_join_ibss,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_LEAVE_IBSS, .cmd = NL80211_CMD_LEAVE_IBSS,
.doit = nl80211_leave_ibss, .doit = nl80211_leave_ibss,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
#ifdef CONFIG_NL80211_TESTMODE #ifdef CONFIG_NL80211_TESTMODE
{ {
...@@ -5424,6 +4721,8 @@ static struct genl_ops nl80211_ops[] = { ...@@ -5424,6 +4721,8 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_testmode_do, .doit = nl80211_testmode_do,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_WIPHY |
NL80211_FLAG_NEED_RTNL,
}, },
#endif #endif
{ {
...@@ -5431,18 +4730,24 @@ static struct genl_ops nl80211_ops[] = { ...@@ -5431,18 +4730,24 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_connect, .doit = nl80211_connect,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_DISCONNECT, .cmd = NL80211_CMD_DISCONNECT,
.doit = nl80211_disconnect, .doit = nl80211_disconnect,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_SET_WIPHY_NETNS, .cmd = NL80211_CMD_SET_WIPHY_NETNS,
.doit = nl80211_wiphy_netns, .doit = nl80211_wiphy_netns,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_WIPHY |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_GET_SURVEY, .cmd = NL80211_CMD_GET_SURVEY,
...@@ -5454,72 +4759,96 @@ static struct genl_ops nl80211_ops[] = { ...@@ -5454,72 +4759,96 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_setdel_pmksa, .doit = nl80211_setdel_pmksa,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_DEL_PMKSA, .cmd = NL80211_CMD_DEL_PMKSA,
.doit = nl80211_setdel_pmksa, .doit = nl80211_setdel_pmksa,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_FLUSH_PMKSA, .cmd = NL80211_CMD_FLUSH_PMKSA,
.doit = nl80211_flush_pmksa, .doit = nl80211_flush_pmksa,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_REMAIN_ON_CHANNEL, .cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
.doit = nl80211_remain_on_channel, .doit = nl80211_remain_on_channel,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, .cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
.doit = nl80211_cancel_remain_on_channel, .doit = nl80211_cancel_remain_on_channel,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_SET_TX_BITRATE_MASK, .cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
.doit = nl80211_set_tx_bitrate_mask, .doit = nl80211_set_tx_bitrate_mask,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_REGISTER_FRAME, .cmd = NL80211_CMD_REGISTER_FRAME,
.doit = nl80211_register_mgmt, .doit = nl80211_register_mgmt,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_FRAME, .cmd = NL80211_CMD_FRAME,
.doit = nl80211_tx_mgmt, .doit = nl80211_tx_mgmt,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_SET_POWER_SAVE, .cmd = NL80211_CMD_SET_POWER_SAVE,
.doit = nl80211_set_power_save, .doit = nl80211_set_power_save,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_GET_POWER_SAVE, .cmd = NL80211_CMD_GET_POWER_SAVE,
.doit = nl80211_get_power_save, .doit = nl80211_get_power_save,
.policy = nl80211_policy, .policy = nl80211_policy,
/* can be retrieved by unprivileged users */ /* can be retrieved by unprivileged users */
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_SET_CQM, .cmd = NL80211_CMD_SET_CQM,
.doit = nl80211_set_cqm, .doit = nl80211_set_cqm,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_SET_CHANNEL, .cmd = NL80211_CMD_SET_CHANNEL,
.doit = nl80211_set_channel, .doit = nl80211_set_channel,
.policy = nl80211_policy, .policy = nl80211_policy,
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
}, },
{ {
.cmd = NL80211_CMD_SET_WDS_PEER, .cmd = NL80211_CMD_SET_WDS_PEER,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册