|
@@ -156,6 +156,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
|
|
|
|
|
|
[NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
|
|
[NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
|
|
[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 },
|
|
[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 },
|
|
|
|
+ [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 },
|
|
};
|
|
};
|
|
|
|
|
|
/* policy for the attributes */
|
|
/* policy for the attributes */
|
|
@@ -437,6 +438,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
|
struct ieee80211_rate *rate;
|
|
struct ieee80211_rate *rate;
|
|
int i;
|
|
int i;
|
|
u16 ifmodes = dev->wiphy.interface_modes;
|
|
u16 ifmodes = dev->wiphy.interface_modes;
|
|
|
|
+ const struct ieee80211_txrx_stypes *mgmt_stypes =
|
|
|
|
+ dev->wiphy.mgmt_stypes;
|
|
|
|
|
|
hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
|
|
hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
|
|
if (!hdr)
|
|
if (!hdr)
|
|
@@ -587,7 +590,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
|
CMD(flush_pmksa, FLUSH_PMKSA);
|
|
CMD(flush_pmksa, FLUSH_PMKSA);
|
|
CMD(remain_on_channel, REMAIN_ON_CHANNEL);
|
|
CMD(remain_on_channel, REMAIN_ON_CHANNEL);
|
|
CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
|
|
CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
|
|
- CMD(action, ACTION);
|
|
|
|
|
|
+ CMD(mgmt_tx, FRAME);
|
|
if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
|
|
if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
|
|
i++;
|
|
i++;
|
|
NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
|
|
NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
|
|
@@ -608,6 +611,53 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
|
|
|
|
|
nla_nest_end(msg, nl_cmds);
|
|
nla_nest_end(msg, nl_cmds);
|
|
|
|
|
|
|
|
+ if (mgmt_stypes) {
|
|
|
|
+ u16 stypes;
|
|
|
|
+ struct nlattr *nl_ftypes, *nl_ifs;
|
|
|
|
+ enum nl80211_iftype ift;
|
|
|
|
+
|
|
|
|
+ nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES);
|
|
|
|
+ if (!nl_ifs)
|
|
|
|
+ goto nla_put_failure;
|
|
|
|
+
|
|
|
|
+ for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
|
|
|
|
+ nl_ftypes = nla_nest_start(msg, ift);
|
|
|
|
+ if (!nl_ftypes)
|
|
|
|
+ goto nla_put_failure;
|
|
|
|
+ i = 0;
|
|
|
|
+ stypes = mgmt_stypes[ift].tx;
|
|
|
|
+ while (stypes) {
|
|
|
|
+ if (stypes & 1)
|
|
|
|
+ NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE,
|
|
|
|
+ (i << 4) | IEEE80211_FTYPE_MGMT);
|
|
|
|
+ stypes >>= 1;
|
|
|
|
+ i++;
|
|
|
|
+ }
|
|
|
|
+ nla_nest_end(msg, nl_ftypes);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES);
|
|
|
|
+ if (!nl_ifs)
|
|
|
|
+ goto nla_put_failure;
|
|
|
|
+
|
|
|
|
+ for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
|
|
|
|
+ nl_ftypes = nla_nest_start(msg, ift);
|
|
|
|
+ if (!nl_ftypes)
|
|
|
|
+ goto nla_put_failure;
|
|
|
|
+ i = 0;
|
|
|
|
+ stypes = mgmt_stypes[ift].rx;
|
|
|
|
+ while (stypes) {
|
|
|
|
+ if (stypes & 1)
|
|
|
|
+ NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE,
|
|
|
|
+ (i << 4) | IEEE80211_FTYPE_MGMT);
|
|
|
|
+ stypes >>= 1;
|
|
|
|
+ i++;
|
|
|
|
+ }
|
|
|
|
+ nla_nest_end(msg, nl_ftypes);
|
|
|
|
+ }
|
|
|
|
+ nla_nest_end(msg, nl_ifs);
|
|
|
|
+ }
|
|
|
|
+
|
|
return genlmsg_end(msg, hdr);
|
|
return genlmsg_end(msg, hdr);
|
|
|
|
|
|
nla_put_failure:
|
|
nla_put_failure:
|
|
@@ -4732,17 +4782,18 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
-static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
|
|
+static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
|
|
{
|
|
{
|
|
struct cfg80211_registered_device *rdev;
|
|
struct cfg80211_registered_device *rdev;
|
|
struct net_device *dev;
|
|
struct net_device *dev;
|
|
|
|
+ u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION;
|
|
int err;
|
|
int err;
|
|
|
|
|
|
if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
|
|
if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
- if (nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]) < 1)
|
|
|
|
- return -EINVAL;
|
|
|
|
|
|
+ if (info->attrs[NL80211_ATTR_FRAME_TYPE])
|
|
|
|
+ frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
|
|
|
|
|
|
rtnl_lock();
|
|
rtnl_lock();
|
|
|
|
|
|
@@ -4757,12 +4808,13 @@ static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info)
|
|
}
|
|
}
|
|
|
|
|
|
/* not much point in registering if we can't reply */
|
|
/* not much point in registering if we can't reply */
|
|
- if (!rdev->ops->action) {
|
|
|
|
|
|
+ if (!rdev->ops->mgmt_tx) {
|
|
err = -EOPNOTSUPP;
|
|
err = -EOPNOTSUPP;
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
- err = cfg80211_mlme_register_action(dev->ieee80211_ptr, info->snd_pid,
|
|
|
|
|
|
+ err = cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid,
|
|
|
|
+ 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:
|
|
out:
|
|
@@ -4773,7 +4825,7 @@ static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info)
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
-static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
|
|
+static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
|
|
{
|
|
{
|
|
struct cfg80211_registered_device *rdev;
|
|
struct cfg80211_registered_device *rdev;
|
|
struct net_device *dev;
|
|
struct net_device *dev;
|
|
@@ -4796,7 +4848,7 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
|
|
if (err)
|
|
if (err)
|
|
goto unlock_rtnl;
|
|
goto unlock_rtnl;
|
|
|
|
|
|
- if (!rdev->ops->action) {
|
|
|
|
|
|
+ if (!rdev->ops->mgmt_tx) {
|
|
err = -EOPNOTSUPP;
|
|
err = -EOPNOTSUPP;
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
@@ -4839,17 +4891,17 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
|
|
}
|
|
}
|
|
|
|
|
|
hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
|
|
hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
|
|
- NL80211_CMD_ACTION);
|
|
|
|
|
|
+ NL80211_CMD_FRAME);
|
|
|
|
|
|
if (IS_ERR(hdr)) {
|
|
if (IS_ERR(hdr)) {
|
|
err = PTR_ERR(hdr);
|
|
err = PTR_ERR(hdr);
|
|
goto free_msg;
|
|
goto free_msg;
|
|
}
|
|
}
|
|
- err = cfg80211_mlme_action(rdev, dev, chan, channel_type,
|
|
|
|
- channel_type_valid,
|
|
|
|
- nla_data(info->attrs[NL80211_ATTR_FRAME]),
|
|
|
|
- nla_len(info->attrs[NL80211_ATTR_FRAME]),
|
|
|
|
- &cookie);
|
|
|
|
|
|
+ err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, channel_type,
|
|
|
|
+ channel_type_valid,
|
|
|
|
+ nla_data(info->attrs[NL80211_ATTR_FRAME]),
|
|
|
|
+ nla_len(info->attrs[NL80211_ATTR_FRAME]),
|
|
|
|
+ &cookie);
|
|
if (err)
|
|
if (err)
|
|
goto free_msg;
|
|
goto free_msg;
|
|
|
|
|
|
@@ -5348,14 +5400,14 @@ static struct genl_ops nl80211_ops[] = {
|
|
.flags = GENL_ADMIN_PERM,
|
|
.flags = GENL_ADMIN_PERM,
|
|
},
|
|
},
|
|
{
|
|
{
|
|
- .cmd = NL80211_CMD_REGISTER_ACTION,
|
|
|
|
- .doit = nl80211_register_action,
|
|
|
|
|
|
+ .cmd = NL80211_CMD_REGISTER_FRAME,
|
|
|
|
+ .doit = nl80211_register_mgmt,
|
|
.policy = nl80211_policy,
|
|
.policy = nl80211_policy,
|
|
.flags = GENL_ADMIN_PERM,
|
|
.flags = GENL_ADMIN_PERM,
|
|
},
|
|
},
|
|
{
|
|
{
|
|
- .cmd = NL80211_CMD_ACTION,
|
|
|
|
- .doit = nl80211_action,
|
|
|
|
|
|
+ .cmd = NL80211_CMD_FRAME,
|
|
|
|
+ .doit = nl80211_tx_mgmt,
|
|
.policy = nl80211_policy,
|
|
.policy = nl80211_policy,
|
|
.flags = GENL_ADMIN_PERM,
|
|
.flags = GENL_ADMIN_PERM,
|
|
},
|
|
},
|
|
@@ -6055,9 +6107,9 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
|
|
nl80211_mlme_mcgrp.id, gfp);
|
|
nl80211_mlme_mcgrp.id, gfp);
|
|
}
|
|
}
|
|
|
|
|
|
-int nl80211_send_action(struct cfg80211_registered_device *rdev,
|
|
|
|
- struct net_device *netdev, u32 nlpid,
|
|
|
|
- int freq, const u8 *buf, size_t len, gfp_t gfp)
|
|
|
|
|
|
+int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
|
|
|
|
+ struct net_device *netdev, u32 nlpid,
|
|
|
|
+ int freq, const u8 *buf, size_t len, gfp_t gfp)
|
|
{
|
|
{
|
|
struct sk_buff *msg;
|
|
struct sk_buff *msg;
|
|
void *hdr;
|
|
void *hdr;
|
|
@@ -6067,7 +6119,7 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev,
|
|
if (!msg)
|
|
if (!msg)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
|
|
|
|
- hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION);
|
|
|
|
|
|
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
|
|
if (!hdr) {
|
|
if (!hdr) {
|
|
nlmsg_free(msg);
|
|
nlmsg_free(msg);
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
@@ -6095,10 +6147,10 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev,
|
|
return -ENOBUFS;
|
|
return -ENOBUFS;
|
|
}
|
|
}
|
|
|
|
|
|
-void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
|
|
|
|
- struct net_device *netdev, u64 cookie,
|
|
|
|
- const u8 *buf, size_t len, bool ack,
|
|
|
|
- gfp_t gfp)
|
|
|
|
|
|
+void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
|
|
|
|
+ struct net_device *netdev, u64 cookie,
|
|
|
|
+ const u8 *buf, size_t len, bool ack,
|
|
|
|
+ gfp_t gfp)
|
|
{
|
|
{
|
|
struct sk_buff *msg;
|
|
struct sk_buff *msg;
|
|
void *hdr;
|
|
void *hdr;
|
|
@@ -6107,7 +6159,7 @@ void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
|
|
if (!msg)
|
|
if (!msg)
|
|
return;
|
|
return;
|
|
|
|
|
|
- hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION_TX_STATUS);
|
|
|
|
|
|
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS);
|
|
if (!hdr) {
|
|
if (!hdr) {
|
|
nlmsg_free(msg);
|
|
nlmsg_free(msg);
|
|
return;
|
|
return;
|
|
@@ -6194,7 +6246,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
|
|
|
|
|
|
list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list)
|
|
list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list)
|
|
list_for_each_entry_rcu(wdev, &rdev->netdev_list, list)
|
|
list_for_each_entry_rcu(wdev, &rdev->netdev_list, list)
|
|
- cfg80211_mlme_unregister_actions(wdev, notify->pid);
|
|
|
|
|
|
+ cfg80211_mlme_unregister_socket(wdev, notify->pid);
|
|
|
|
|
|
rcu_read_unlock();
|
|
rcu_read_unlock();
|
|
|
|
|