Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 93d638d4 authored by Patrik Flykt's avatar Patrik Flykt Committed by Johannes Berg
Browse files

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: default avatarPatrik Flykt <patrik.flykt@linux.intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent c449981c
Loading
Loading
Loading
Loading
+122 −1
Original line number Diff line number Diff line
@@ -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, &param);
	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)
+3 −0
Original line number Diff line number Diff line
@@ -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)