mirror of
https://github.com/torvalds/linux.git
synced 2024-11-19 02:21:47 +00:00
mac80211-hwsim: Add HWSIM_CMD_GET_RADIO command
HWSIM_CMD_GET_RADIO returns information about a specific radio id or all of them in response to a dump. Create the netlink skb or use the one provided by the dump functionality. Use the existing attribute appending function to fill in the same attributes when creating a new hwsim radio. Save alpha2 and struct ieee80211_regdomain in the hwsim data or else they will be lost in the depths of regulatory infrastructure. Signed-off-by: Patrik Flykt <patrik.flykt@linux.intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
c449981c47
commit
93d638d49c
@ -415,6 +415,8 @@ struct mac80211_hwsim_data {
|
||||
bool destroy_on_close;
|
||||
struct work_struct destroy_work;
|
||||
u32 portid;
|
||||
char alpha2[2];
|
||||
const struct ieee80211_regdomain *regd;
|
||||
|
||||
struct ieee80211_channel *tmp_chan;
|
||||
struct delayed_work roc_done;
|
||||
@ -2420,6 +2422,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
||||
if (param->reg_strict)
|
||||
hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
|
||||
if (param->regd) {
|
||||
data->regd = param->regd;
|
||||
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
|
||||
wiphy_apply_custom_regulatory(hw->wiphy, param->regd);
|
||||
/* give the regulatory workqueue a chance to run */
|
||||
@ -2438,8 +2441,11 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
||||
|
||||
wiphy_debug(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr);
|
||||
|
||||
if (param->reg_alpha2)
|
||||
if (param->reg_alpha2) {
|
||||
data->alpha2[0] = param->reg_alpha2[0];
|
||||
data->alpha2[1] = param->reg_alpha2[1];
|
||||
regulatory_hint(hw->wiphy, param->reg_alpha2);
|
||||
}
|
||||
|
||||
data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir);
|
||||
debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps);
|
||||
@ -2518,6 +2524,44 @@ static void mac80211_hwsim_del_radio(struct mac80211_hwsim_data *data,
|
||||
ieee80211_free_hw(data->hw);
|
||||
}
|
||||
|
||||
static int mac80211_hwsim_get_radio(struct sk_buff *skb,
|
||||
struct mac80211_hwsim_data *data,
|
||||
u32 portid, u32 seq,
|
||||
struct netlink_callback *cb, int flags)
|
||||
{
|
||||
void *hdr;
|
||||
struct hwsim_new_radio_params param = { };
|
||||
int res = -EMSGSIZE;
|
||||
|
||||
hdr = genlmsg_put(skb, portid, seq, &hwsim_genl_family, flags,
|
||||
HWSIM_CMD_GET_RADIO);
|
||||
if (!hdr)
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (cb)
|
||||
genl_dump_check_consistent(cb, hdr, &hwsim_genl_family);
|
||||
|
||||
param.reg_alpha2 = data->alpha2;
|
||||
param.reg_strict = !!(data->hw->wiphy->regulatory_flags &
|
||||
REGULATORY_STRICT_REG);
|
||||
param.p2p_device = !!(data->hw->wiphy->interface_modes &
|
||||
BIT(NL80211_IFTYPE_P2P_DEVICE));
|
||||
param.use_chanctx = data->use_chanctx;
|
||||
param.regd = data->regd;
|
||||
param.channels = data->channels;
|
||||
param.hwname = wiphy_name(data->hw->wiphy);
|
||||
|
||||
res = append_radio_msg(skb, data->idx, ¶m);
|
||||
if (res < 0)
|
||||
goto out_err;
|
||||
|
||||
return genlmsg_end(skb, hdr);
|
||||
|
||||
out_err:
|
||||
genlmsg_cancel(skb, hdr);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void mac80211_hwsim_free(void)
|
||||
{
|
||||
struct mac80211_hwsim_data *data;
|
||||
@ -2823,6 +2867,77 @@ static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int hwsim_get_radio_nl(struct sk_buff *msg, struct genl_info *info)
|
||||
{
|
||||
struct mac80211_hwsim_data *data;
|
||||
struct sk_buff *skb;
|
||||
int idx, res = -ENODEV;
|
||||
|
||||
if (!info->attrs[HWSIM_ATTR_RADIO_ID])
|
||||
return -EINVAL;
|
||||
idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]);
|
||||
|
||||
spin_lock_bh(&hwsim_radio_lock);
|
||||
list_for_each_entry(data, &hwsim_radios, list) {
|
||||
if (data->idx != idx)
|
||||
continue;
|
||||
|
||||
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!skb) {
|
||||
res = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
res = mac80211_hwsim_get_radio(skb, data, info->snd_portid,
|
||||
info->snd_seq, NULL, 0);
|
||||
if (res < 0) {
|
||||
nlmsg_free(skb);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
genlmsg_reply(skb, info);
|
||||
break;
|
||||
}
|
||||
|
||||
out_err:
|
||||
spin_unlock_bh(&hwsim_radio_lock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int hwsim_dump_radio_nl(struct sk_buff *skb,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
int idx = cb->args[0];
|
||||
struct mac80211_hwsim_data *data = NULL;
|
||||
int res;
|
||||
|
||||
spin_lock_bh(&hwsim_radio_lock);
|
||||
|
||||
if (idx == hwsim_radio_idx)
|
||||
goto done;
|
||||
|
||||
list_for_each_entry(data, &hwsim_radios, list) {
|
||||
if (data->idx < idx)
|
||||
continue;
|
||||
|
||||
res = mac80211_hwsim_get_radio(skb, data,
|
||||
NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, cb,
|
||||
NLM_F_MULTI);
|
||||
if (res < 0)
|
||||
break;
|
||||
|
||||
idx = data->idx + 1;
|
||||
}
|
||||
|
||||
cb->args[0] = idx;
|
||||
|
||||
done:
|
||||
spin_unlock_bh(&hwsim_radio_lock);
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
/* Generic Netlink operations array */
|
||||
static const struct genl_ops hwsim_ops[] = {
|
||||
{
|
||||
@ -2853,6 +2968,12 @@ static const struct genl_ops hwsim_ops[] = {
|
||||
.doit = hwsim_del_radio_nl,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = HWSIM_CMD_GET_RADIO,
|
||||
.policy = hwsim_genl_policy,
|
||||
.doit = hwsim_get_radio_nl,
|
||||
.dumpit = hwsim_dump_radio_nl,
|
||||
},
|
||||
};
|
||||
|
||||
static void destroy_radio(struct work_struct *work)
|
||||
|
@ -69,6 +69,8 @@ enum hwsim_tx_control_flags {
|
||||
* returns the radio ID (>= 0) or negative on errors, if successful
|
||||
* then multicast the result
|
||||
* @HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted
|
||||
* @HWSIM_CMD_GET_RADIO: fetch information about existing radios, uses:
|
||||
* %HWSIM_ATTR_RADIO_ID
|
||||
* @__HWSIM_CMD_MAX: enum limit
|
||||
*/
|
||||
enum {
|
||||
@ -78,6 +80,7 @@ enum {
|
||||
HWSIM_CMD_TX_INFO_FRAME,
|
||||
HWSIM_CMD_NEW_RADIO,
|
||||
HWSIM_CMD_DEL_RADIO,
|
||||
HWSIM_CMD_GET_RADIO,
|
||||
__HWSIM_CMD_MAX,
|
||||
};
|
||||
#define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1)
|
||||
|
Loading…
Reference in New Issue
Block a user