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;
|
bool destroy_on_close;
|
||||||
struct work_struct destroy_work;
|
struct work_struct destroy_work;
|
||||||
u32 portid;
|
u32 portid;
|
||||||
|
char alpha2[2];
|
||||||
|
const struct ieee80211_regdomain *regd;
|
||||||
|
|
||||||
struct ieee80211_channel *tmp_chan;
|
struct ieee80211_channel *tmp_chan;
|
||||||
struct delayed_work roc_done;
|
struct delayed_work roc_done;
|
||||||
|
@ -2420,6 +2422,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
||||||
if (param->reg_strict)
|
if (param->reg_strict)
|
||||||
hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
|
hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
|
||||||
if (param->regd) {
|
if (param->regd) {
|
||||||
|
data->regd = param->regd;
|
||||||
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
|
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
|
||||||
wiphy_apply_custom_regulatory(hw->wiphy, param->regd);
|
wiphy_apply_custom_regulatory(hw->wiphy, param->regd);
|
||||||
/* give the regulatory workqueue a chance to run */
|
/* 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);
|
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);
|
regulatory_hint(hw->wiphy, param->reg_alpha2);
|
||||||
|
}
|
||||||
|
|
||||||
data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir);
|
data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir);
|
||||||
debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps);
|
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);
|
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)
|
static void mac80211_hwsim_free(void)
|
||||||
{
|
{
|
||||||
struct mac80211_hwsim_data *data;
|
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;
|
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 */
|
/* Generic Netlink operations array */
|
||||||
static const struct genl_ops hwsim_ops[] = {
|
static const struct genl_ops hwsim_ops[] = {
|
||||||
{
|
{
|
||||||
|
@ -2853,6 +2968,12 @@ static const struct genl_ops hwsim_ops[] = {
|
||||||
.doit = hwsim_del_radio_nl,
|
.doit = hwsim_del_radio_nl,
|
||||||
.flags = GENL_ADMIN_PERM,
|
.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)
|
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
|
* returns the radio ID (>= 0) or negative on errors, if successful
|
||||||
* then multicast the result
|
* then multicast the result
|
||||||
* @HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted
|
* @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
|
* @__HWSIM_CMD_MAX: enum limit
|
||||||
*/
|
*/
|
||||||
enum {
|
enum {
|
||||||
|
@ -78,6 +80,7 @@ enum {
|
||||||
HWSIM_CMD_TX_INFO_FRAME,
|
HWSIM_CMD_TX_INFO_FRAME,
|
||||||
HWSIM_CMD_NEW_RADIO,
|
HWSIM_CMD_NEW_RADIO,
|
||||||
HWSIM_CMD_DEL_RADIO,
|
HWSIM_CMD_DEL_RADIO,
|
||||||
|
HWSIM_CMD_GET_RADIO,
|
||||||
__HWSIM_CMD_MAX,
|
__HWSIM_CMD_MAX,
|
||||||
};
|
};
|
||||||
#define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1)
|
#define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1)
|
||||||
|
|
Loading…
Reference in New Issue