mac80211: backport SAR power limit support
Needed for an upcoming mt76 update Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
parent
19228c4562
commit
890bf06cef
@ -0,0 +1,398 @@
|
|||||||
|
From: Carl Huang <cjhuang@codeaurora.org>
|
||||||
|
Date: Thu, 3 Dec 2020 05:37:26 -0500
|
||||||
|
Subject: [PATCH] nl80211: add common API to configure SAR power limitations
|
||||||
|
|
||||||
|
NL80211_CMD_SET_SAR_SPECS is added to configure SAR from
|
||||||
|
user space. NL80211_ATTR_SAR_SPEC is used to pass the SAR
|
||||||
|
power specification when used with NL80211_CMD_SET_SAR_SPECS.
|
||||||
|
|
||||||
|
Wireless driver needs to register SAR type, supported frequency
|
||||||
|
ranges to wiphy, so user space can query it. The index in
|
||||||
|
frequency range is used to specify which sub band the power
|
||||||
|
limitation applies to. The SAR type is for compatibility, so later
|
||||||
|
other SAR mechanism can be implemented without breaking the user
|
||||||
|
space SAR applications.
|
||||||
|
|
||||||
|
Normal process is user space queries the SAR capability, and
|
||||||
|
gets the index of supported frequency ranges and associates the
|
||||||
|
power limitation with this index and sends to kernel.
|
||||||
|
|
||||||
|
Here is an example of message send to kernel:
|
||||||
|
8c 00 00 00 08 00 01 00 00 00 00 00 38 00 2b 81
|
||||||
|
08 00 01 00 00 00 00 00 2c 00 02 80 14 00 00 80
|
||||||
|
08 00 02 00 00 00 00 00 08 00 01 00 38 00 00 00
|
||||||
|
14 00 01 80 08 00 02 00 01 00 00 00 08 00 01 00
|
||||||
|
48 00 00 00
|
||||||
|
|
||||||
|
NL80211_CMD_SET_SAR_SPECS: 0x8c
|
||||||
|
NL80211_ATTR_WIPHY: 0x01(phy idx is 0)
|
||||||
|
NL80211_ATTR_SAR_SPEC: 0x812b (NLA_NESTED)
|
||||||
|
NL80211_SAR_ATTR_TYPE: 0x00 (NL80211_SAR_TYPE_POWER)
|
||||||
|
NL80211_SAR_ATTR_SPECS: 0x8002 (NLA_NESTED)
|
||||||
|
freq range 0 power: 0x38 in 0.25dbm unit (14dbm)
|
||||||
|
freq range 1 power: 0x48 in 0.25dbm unit (18dbm)
|
||||||
|
|
||||||
|
Signed-off-by: Carl Huang <cjhuang@codeaurora.org>
|
||||||
|
Reviewed-by: Brian Norris <briannorris@chromium.org>
|
||||||
|
Reviewed-by: Abhishek Kumar <kuabhs@chromium.org>
|
||||||
|
Link: https://lore.kernel.org/r/20201203103728.3034-2-cjhuang@codeaurora.org
|
||||||
|
[minor edits, NLA parse cleanups]
|
||||||
|
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/include/net/cfg80211.h
|
||||||
|
+++ b/include/net/cfg80211.h
|
||||||
|
@@ -1737,6 +1737,54 @@ struct station_info {
|
||||||
|
u8 connected_to_as;
|
||||||
|
};
|
||||||
|
|
||||||
|
+/**
|
||||||
|
+ * struct cfg80211_sar_sub_specs - sub specs limit
|
||||||
|
+ * @power: power limitation in 0.25dbm
|
||||||
|
+ * @freq_range_index: index the power limitation applies to
|
||||||
|
+ */
|
||||||
|
+struct cfg80211_sar_sub_specs {
|
||||||
|
+ s32 power;
|
||||||
|
+ u32 freq_range_index;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * struct cfg80211_sar_specs - sar limit specs
|
||||||
|
+ * @type: it's set with power in 0.25dbm or other types
|
||||||
|
+ * @num_sub_specs: number of sar sub specs
|
||||||
|
+ * @sub_specs: memory to hold the sar sub specs
|
||||||
|
+ */
|
||||||
|
+struct cfg80211_sar_specs {
|
||||||
|
+ enum nl80211_sar_type type;
|
||||||
|
+ u32 num_sub_specs;
|
||||||
|
+ struct cfg80211_sar_sub_specs sub_specs[];
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * @struct cfg80211_sar_chan_ranges - sar frequency ranges
|
||||||
|
+ * @start_freq: start range edge frequency
|
||||||
|
+ * @end_freq: end range edge frequency
|
||||||
|
+ */
|
||||||
|
+struct cfg80211_sar_freq_ranges {
|
||||||
|
+ u32 start_freq;
|
||||||
|
+ u32 end_freq;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * struct cfg80211_sar_capa - sar limit capability
|
||||||
|
+ * @type: it's set via power in 0.25dbm or other types
|
||||||
|
+ * @num_freq_ranges: number of frequency ranges
|
||||||
|
+ * @freq_ranges: memory to hold the freq ranges.
|
||||||
|
+ *
|
||||||
|
+ * Note: WLAN driver may append new ranges or split an existing
|
||||||
|
+ * range to small ones and then append them.
|
||||||
|
+ */
|
||||||
|
+struct cfg80211_sar_capa {
|
||||||
|
+ enum nl80211_sar_type type;
|
||||||
|
+ u32 num_freq_ranges;
|
||||||
|
+ const struct cfg80211_sar_freq_ranges *freq_ranges;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
#if IS_ENABLED(CPTCFG_CFG80211)
|
||||||
|
/**
|
||||||
|
* cfg80211_get_station - retrieve information about a given station
|
||||||
|
@@ -4259,6 +4307,8 @@ struct cfg80211_ops {
|
||||||
|
struct cfg80211_tid_config *tid_conf);
|
||||||
|
int (*reset_tid_config)(struct wiphy *wiphy, struct net_device *dev,
|
||||||
|
const u8 *peer, u8 tids);
|
||||||
|
+ int (*set_sar_specs)(struct wiphy *wiphy,
|
||||||
|
+ struct cfg80211_sar_specs *sar);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -5030,6 +5080,8 @@ struct wiphy {
|
||||||
|
|
||||||
|
u8 max_data_retry_count;
|
||||||
|
|
||||||
|
+ const struct cfg80211_sar_capa *sar_capa;
|
||||||
|
+
|
||||||
|
char priv[] __aligned(NETDEV_ALIGN);
|
||||||
|
};
|
||||||
|
|
||||||
|
--- a/net/wireless/nl80211.c
|
||||||
|
+++ b/net/wireless/nl80211.c
|
||||||
|
@@ -405,6 +405,18 @@ nl80211_unsol_bcast_probe_resp_policy[NL
|
||||||
|
.len = IEEE80211_MAX_DATA_LEN }
|
||||||
|
};
|
||||||
|
|
||||||
|
+static const struct nla_policy
|
||||||
|
+sar_specs_policy[NL80211_SAR_ATTR_SPECS_MAX + 1] = {
|
||||||
|
+ [NL80211_SAR_ATTR_SPECS_POWER] = { .type = NLA_S32 },
|
||||||
|
+ [NL80211_SAR_ATTR_SPECS_RANGE_INDEX] = {.type = NLA_U32 },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static const struct nla_policy
|
||||||
|
+sar_policy[NL80211_SAR_ATTR_MAX + 1] = {
|
||||||
|
+ [NL80211_SAR_ATTR_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_SAR_TYPE),
|
||||||
|
+ [NL80211_SAR_ATTR_SPECS] = NLA_POLICY_NESTED_ARRAY(sar_specs_policy),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||||
|
[0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD },
|
||||||
|
[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
|
||||||
|
@@ -739,6 +751,7 @@ static const struct nla_policy nl80211_p
|
||||||
|
[NL80211_ATTR_SAE_PWE] =
|
||||||
|
NLA_POLICY_RANGE(NLA_U8, NL80211_SAE_PWE_HUNT_AND_PECK,
|
||||||
|
NL80211_SAE_PWE_BOTH),
|
||||||
|
+ [NL80211_ATTR_SAR_SPEC] = NLA_POLICY_NESTED(sar_policy),
|
||||||
|
[NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT },
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -2117,6 +2130,56 @@ fail:
|
||||||
|
return -ENOBUFS;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int
|
||||||
|
+nl80211_put_sar_specs(struct cfg80211_registered_device *rdev,
|
||||||
|
+ struct sk_buff *msg)
|
||||||
|
+{
|
||||||
|
+ struct nlattr *sar_capa, *specs, *sub_freq_range;
|
||||||
|
+ u8 num_freq_ranges;
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ if (!rdev->wiphy.sar_capa)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ num_freq_ranges = rdev->wiphy.sar_capa->num_freq_ranges;
|
||||||
|
+
|
||||||
|
+ sar_capa = nla_nest_start(msg, NL80211_ATTR_SAR_SPEC);
|
||||||
|
+ if (!sar_capa)
|
||||||
|
+ return -ENOSPC;
|
||||||
|
+
|
||||||
|
+ if (nla_put_u32(msg, NL80211_SAR_ATTR_TYPE, rdev->wiphy.sar_capa->type))
|
||||||
|
+ goto fail;
|
||||||
|
+
|
||||||
|
+ specs = nla_nest_start(msg, NL80211_SAR_ATTR_SPECS);
|
||||||
|
+ if (!specs)
|
||||||
|
+ goto fail;
|
||||||
|
+
|
||||||
|
+ /* report supported freq_ranges */
|
||||||
|
+ for (i = 0; i < num_freq_ranges; i++) {
|
||||||
|
+ sub_freq_range = nla_nest_start(msg, i + 1);
|
||||||
|
+ if (!sub_freq_range)
|
||||||
|
+ goto fail;
|
||||||
|
+
|
||||||
|
+ if (nla_put_u32(msg, NL80211_SAR_ATTR_SPECS_START_FREQ,
|
||||||
|
+ rdev->wiphy.sar_capa->freq_ranges[i].start_freq))
|
||||||
|
+ goto fail;
|
||||||
|
+
|
||||||
|
+ if (nla_put_u32(msg, NL80211_SAR_ATTR_SPECS_END_FREQ,
|
||||||
|
+ rdev->wiphy.sar_capa->freq_ranges[i].end_freq))
|
||||||
|
+ goto fail;
|
||||||
|
+
|
||||||
|
+ nla_nest_end(msg, sub_freq_range);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ nla_nest_end(msg, specs);
|
||||||
|
+ nla_nest_end(msg, sar_capa);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+fail:
|
||||||
|
+ nla_nest_cancel(msg, sar_capa);
|
||||||
|
+ return -ENOBUFS;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
struct nl80211_dump_wiphy_state {
|
||||||
|
s64 filter_wiphy;
|
||||||
|
long start;
|
||||||
|
@@ -2366,6 +2429,8 @@ static int nl80211_send_wiphy(struct cfg
|
||||||
|
CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST);
|
||||||
|
CMD(update_connect_params, UPDATE_CONNECT_PARAMS);
|
||||||
|
CMD(update_ft_ies, UPDATE_FT_IES);
|
||||||
|
+ if (rdev->wiphy.sar_capa)
|
||||||
|
+ CMD(set_sar_specs, SET_SAR_SPECS);
|
||||||
|
}
|
||||||
|
#undef CMD
|
||||||
|
|
||||||
|
@@ -2691,6 +2756,11 @@ static int nl80211_send_wiphy(struct cfg
|
||||||
|
|
||||||
|
if (nl80211_put_tid_config_support(rdev, msg))
|
||||||
|
goto nla_put_failure;
|
||||||
|
+ state->split_start++;
|
||||||
|
+ break;
|
||||||
|
+ case 16:
|
||||||
|
+ if (nl80211_put_sar_specs(rdev, msg))
|
||||||
|
+ goto nla_put_failure;
|
||||||
|
|
||||||
|
/* done */
|
||||||
|
state->split_start = 0;
|
||||||
|
@@ -14713,6 +14783,111 @@ static void nl80211_post_doit(__genl_con
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int nl80211_set_sar_sub_specs(struct cfg80211_registered_device *rdev,
|
||||||
|
+ struct cfg80211_sar_specs *sar_specs,
|
||||||
|
+ struct nlattr *spec[], int index)
|
||||||
|
+{
|
||||||
|
+ u32 range_index, i;
|
||||||
|
+
|
||||||
|
+ if (!sar_specs || !spec)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ if (!spec[NL80211_SAR_ATTR_SPECS_POWER] ||
|
||||||
|
+ !spec[NL80211_SAR_ATTR_SPECS_RANGE_INDEX])
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ range_index = nla_get_u32(spec[NL80211_SAR_ATTR_SPECS_RANGE_INDEX]);
|
||||||
|
+
|
||||||
|
+ /* check if range_index exceeds num_freq_ranges */
|
||||||
|
+ if (range_index >= rdev->wiphy.sar_capa->num_freq_ranges)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ /* check if range_index duplicates */
|
||||||
|
+ for (i = 0; i < index; i++) {
|
||||||
|
+ if (sar_specs->sub_specs[i].freq_range_index == range_index)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ sar_specs->sub_specs[index].power =
|
||||||
|
+ nla_get_s32(spec[NL80211_SAR_ATTR_SPECS_POWER]);
|
||||||
|
+
|
||||||
|
+ sar_specs->sub_specs[index].freq_range_index = range_index;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int nl80211_set_sar_specs(struct sk_buff *skb, struct genl_info *info)
|
||||||
|
+{
|
||||||
|
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||||
|
+ struct nlattr *spec[NL80211_SAR_ATTR_SPECS_MAX + 1];
|
||||||
|
+ struct nlattr *tb[NL80211_SAR_ATTR_MAX + 1];
|
||||||
|
+ struct cfg80211_sar_specs *sar_spec;
|
||||||
|
+ enum nl80211_sar_type type;
|
||||||
|
+ struct nlattr *spec_list;
|
||||||
|
+ u32 specs;
|
||||||
|
+ int rem, err;
|
||||||
|
+
|
||||||
|
+ if (!rdev->wiphy.sar_capa || !rdev->ops->set_sar_specs)
|
||||||
|
+ return -EOPNOTSUPP;
|
||||||
|
+
|
||||||
|
+ if (!info->attrs[NL80211_ATTR_SAR_SPEC])
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ nla_parse_nested(tb, NL80211_SAR_ATTR_MAX,
|
||||||
|
+ info->attrs[NL80211_ATTR_SAR_SPEC],
|
||||||
|
+ NULL, NULL);
|
||||||
|
+
|
||||||
|
+ if (!tb[NL80211_SAR_ATTR_TYPE] || !tb[NL80211_SAR_ATTR_SPECS])
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ type = nla_get_u32(tb[NL80211_SAR_ATTR_TYPE]);
|
||||||
|
+ if (type != rdev->wiphy.sar_capa->type)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ specs = 0;
|
||||||
|
+ nla_for_each_nested(spec_list, tb[NL80211_SAR_ATTR_SPECS], rem)
|
||||||
|
+ specs++;
|
||||||
|
+
|
||||||
|
+ if (specs > rdev->wiphy.sar_capa->num_freq_ranges)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ sar_spec = kzalloc(sizeof(*sar_spec) +
|
||||||
|
+ specs * sizeof(struct cfg80211_sar_sub_specs),
|
||||||
|
+ GFP_KERNEL);
|
||||||
|
+ if (!sar_spec)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+
|
||||||
|
+ sar_spec->type = type;
|
||||||
|
+ specs = 0;
|
||||||
|
+ nla_for_each_nested(spec_list, tb[NL80211_SAR_ATTR_SPECS], rem) {
|
||||||
|
+ nla_parse_nested(spec, NL80211_SAR_ATTR_SPECS_MAX,
|
||||||
|
+ spec_list, NULL, NULL);
|
||||||
|
+
|
||||||
|
+ switch (type) {
|
||||||
|
+ case NL80211_SAR_TYPE_POWER:
|
||||||
|
+ if (nl80211_set_sar_sub_specs(rdev, sar_spec,
|
||||||
|
+ spec, specs)) {
|
||||||
|
+ err = -EINVAL;
|
||||||
|
+ goto error;
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
+ err = -EINVAL;
|
||||||
|
+ goto error;
|
||||||
|
+ }
|
||||||
|
+ specs++;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ sar_spec->num_sub_specs = specs;
|
||||||
|
+
|
||||||
|
+ rdev->cur_cmd_info = info;
|
||||||
|
+ err = rdev_set_sar_specs(rdev, sar_spec);
|
||||||
|
+ rdev->cur_cmd_info = NULL;
|
||||||
|
+error:
|
||||||
|
+ kfree(sar_spec);
|
||||||
|
+ return err;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static __genl_const struct genl_ops nl80211_ops[] = {
|
||||||
|
{
|
||||||
|
.cmd = NL80211_CMD_GET_WIPHY,
|
||||||
|
@@ -15576,6 +15751,14 @@ static const struct genl_small_ops nl802
|
||||||
|
.internal_flags = NL80211_FLAG_NEED_NETDEV |
|
||||||
|
NL80211_FLAG_NEED_RTNL,
|
||||||
|
},
|
||||||
|
+ {
|
||||||
|
+ .cmd = NL80211_CMD_SET_SAR_SPECS,
|
||||||
|
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
|
||||||
|
+ .doit = nl80211_set_sar_specs,
|
||||||
|
+ .flags = GENL_UNS_ADMIN_PERM,
|
||||||
|
+ .internal_flags = NL80211_FLAG_NEED_WIPHY |
|
||||||
|
+ NL80211_FLAG_NEED_RTNL,
|
||||||
|
+ },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct genl_family nl80211_fam __genl_ro_after_init = {
|
||||||
|
--- a/net/wireless/rdev-ops.h
|
||||||
|
+++ b/net/wireless/rdev-ops.h
|
||||||
|
@@ -1356,4 +1356,16 @@ static inline int rdev_reset_tid_config(
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static inline int rdev_set_sar_specs(struct cfg80211_registered_device *rdev,
|
||||||
|
+ struct cfg80211_sar_specs *sar)
|
||||||
|
+{
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ trace_rdev_set_sar_specs(&rdev->wiphy, sar);
|
||||||
|
+ ret = rdev->ops->set_sar_specs(&rdev->wiphy, sar);
|
||||||
|
+ trace_rdev_return_int(&rdev->wiphy, ret);
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
#endif /* __CFG80211_RDEV_OPS */
|
||||||
|
--- a/net/wireless/trace.h
|
||||||
|
+++ b/net/wireless/trace.h
|
||||||
|
@@ -3551,6 +3551,25 @@ TRACE_EVENT(rdev_reset_tid_config,
|
||||||
|
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT ", tids: 0x%x",
|
||||||
|
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->tids)
|
||||||
|
);
|
||||||
|
+
|
||||||
|
+TRACE_EVENT(rdev_set_sar_specs,
|
||||||
|
+ TP_PROTO(struct wiphy *wiphy, struct cfg80211_sar_specs *sar),
|
||||||
|
+ TP_ARGS(wiphy, sar),
|
||||||
|
+ TP_STRUCT__entry(
|
||||||
|
+ WIPHY_ENTRY
|
||||||
|
+ __field(u16, type)
|
||||||
|
+ __field(u16, num)
|
||||||
|
+ ),
|
||||||
|
+ TP_fast_assign(
|
||||||
|
+ WIPHY_ASSIGN;
|
||||||
|
+ __entry->type = sar->type;
|
||||||
|
+ __entry->num = sar->num_sub_specs;
|
||||||
|
+
|
||||||
|
+ ),
|
||||||
|
+ TP_printk(WIPHY_PR_FMT ", Set type:%d, num_specs:%d",
|
||||||
|
+ WIPHY_PR_ARG, __entry->type, __entry->num)
|
||||||
|
+);
|
||||||
|
+
|
||||||
|
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
|
||||||
|
|
||||||
|
#undef TRACE_INCLUDE_PATH
|
@ -0,0 +1,51 @@
|
|||||||
|
From: Carl Huang <cjhuang@codeaurora.org>
|
||||||
|
Date: Thu, 3 Dec 2020 05:37:27 -0500
|
||||||
|
Subject: [PATCH] mac80211: add ieee80211_set_sar_specs
|
||||||
|
|
||||||
|
This change registers ieee80211_set_sar_specs to
|
||||||
|
mac80211_config_ops, so cfg80211 can call it.
|
||||||
|
|
||||||
|
Signed-off-by: Carl Huang <cjhuang@codeaurora.org>
|
||||||
|
Reviewed-by: Brian Norris <briannorris@chromium.org>
|
||||||
|
Reviewed-by: Abhishek Kumar <kuabhs@chromium.org>
|
||||||
|
Link: https://lore.kernel.org/r/20201203103728.3034-3-cjhuang@codeaurora.org
|
||||||
|
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/include/net/mac80211.h
|
||||||
|
+++ b/include/net/mac80211.h
|
||||||
|
@@ -4207,6 +4207,8 @@ struct ieee80211_ops {
|
||||||
|
struct ieee80211_vif *vif);
|
||||||
|
void (*sta_set_4addr)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
|
struct ieee80211_sta *sta, bool enabled);
|
||||||
|
+ int (*set_sar_specs)(struct ieee80211_hw *hw,
|
||||||
|
+ const struct cfg80211_sar_specs *sar);
|
||||||
|
void (*sta_set_decap_offload)(struct ieee80211_hw *hw,
|
||||||
|
struct ieee80211_vif *vif,
|
||||||
|
struct ieee80211_sta *sta, bool enabled);
|
||||||
|
--- a/net/mac80211/cfg.c
|
||||||
|
+++ b/net/mac80211/cfg.c
|
||||||
|
@@ -4136,6 +4136,17 @@ static int ieee80211_reset_tid_config(st
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int ieee80211_set_sar_specs(struct wiphy *wiphy,
|
||||||
|
+ struct cfg80211_sar_specs *sar)
|
||||||
|
+{
|
||||||
|
+ struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||||
|
+
|
||||||
|
+ if (!local->ops->set_sar_specs)
|
||||||
|
+ return -EOPNOTSUPP;
|
||||||
|
+
|
||||||
|
+ return local->ops->set_sar_specs(&local->hw, sar);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
const struct cfg80211_ops mac80211_config_ops = {
|
||||||
|
.add_virtual_intf = ieee80211_add_iface,
|
||||||
|
.del_virtual_intf = ieee80211_del_iface,
|
||||||
|
@@ -4239,4 +4250,5 @@ const struct cfg80211_ops mac80211_confi
|
||||||
|
.probe_mesh_link = ieee80211_probe_mesh_link,
|
||||||
|
.set_tid_config = ieee80211_set_tid_config,
|
||||||
|
.reset_tid_config = ieee80211_reset_tid_config,
|
||||||
|
+ .set_sar_specs = ieee80211_set_sar_specs,
|
||||||
|
};
|
@ -1,6 +1,6 @@
|
|||||||
--- a/include/net/cfg80211.h
|
--- a/include/net/cfg80211.h
|
||||||
+++ b/include/net/cfg80211.h
|
+++ b/include/net/cfg80211.h
|
||||||
@@ -3745,6 +3745,7 @@ struct mgmt_frame_regs {
|
@@ -3793,6 +3793,7 @@ struct mgmt_frame_regs {
|
||||||
* (as advertised by the nl80211 feature flag.)
|
* (as advertised by the nl80211 feature flag.)
|
||||||
* @get_tx_power: store the current TX power into the dbm variable;
|
* @get_tx_power: store the current TX power into the dbm variable;
|
||||||
* return 0 if successful
|
* return 0 if successful
|
||||||
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
* @set_wds_peer: set the WDS peer for a WDS interface
|
* @set_wds_peer: set the WDS peer for a WDS interface
|
||||||
*
|
*
|
||||||
@@ -4067,6 +4068,7 @@ struct cfg80211_ops {
|
@@ -4115,6 +4116,7 @@ struct cfg80211_ops {
|
||||||
enum nl80211_tx_power_setting type, int mbm);
|
enum nl80211_tx_power_setting type, int mbm);
|
||||||
int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
|
int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||||
int *dbm);
|
int *dbm);
|
||||||
@ -57,7 +57,7 @@
|
|||||||
__NL80211_ATTR_AFTER_LAST,
|
__NL80211_ATTR_AFTER_LAST,
|
||||||
--- a/net/mac80211/cfg.c
|
--- a/net/mac80211/cfg.c
|
||||||
+++ b/net/mac80211/cfg.c
|
+++ b/net/mac80211/cfg.c
|
||||||
@@ -2742,6 +2742,19 @@ static int ieee80211_get_tx_power(struct
|
@@ -2761,6 +2761,19 @@ static int ieee80211_get_tx_power(struct
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,7 @@
|
|||||||
static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
|
static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
|
||||||
const u8 *addr)
|
const u8 *addr)
|
||||||
{
|
{
|
||||||
@@ -4172,6 +4185,7 @@ const struct cfg80211_ops mac80211_confi
|
@@ -4202,6 +4215,7 @@ const struct cfg80211_ops mac80211_confi
|
||||||
.set_wiphy_params = ieee80211_set_wiphy_params,
|
.set_wiphy_params = ieee80211_set_wiphy_params,
|
||||||
.set_tx_power = ieee80211_set_tx_power,
|
.set_tx_power = ieee80211_set_tx_power,
|
||||||
.get_tx_power = ieee80211_get_tx_power,
|
.get_tx_power = ieee80211_get_tx_power,
|
||||||
@ -129,15 +129,15 @@
|
|||||||
local->hw.max_mtu = IEEE80211_MAX_DATA_LEN;
|
local->hw.max_mtu = IEEE80211_MAX_DATA_LEN;
|
||||||
--- a/net/wireless/nl80211.c
|
--- a/net/wireless/nl80211.c
|
||||||
+++ b/net/wireless/nl80211.c
|
+++ b/net/wireless/nl80211.c
|
||||||
@@ -740,6 +740,7 @@ static const struct nla_policy nl80211_p
|
@@ -753,6 +753,7 @@ static const struct nla_policy nl80211_p
|
||||||
NLA_POLICY_RANGE(NLA_U8, NL80211_SAE_PWE_HUNT_AND_PECK,
|
|
||||||
NL80211_SAE_PWE_BOTH),
|
NL80211_SAE_PWE_BOTH),
|
||||||
|
[NL80211_ATTR_SAR_SPEC] = NLA_POLICY_NESTED(sar_policy),
|
||||||
[NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT },
|
[NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT },
|
||||||
+ [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
|
+ [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* policy for the key attributes */
|
/* policy for the key attributes */
|
||||||
@@ -3248,6 +3249,20 @@ static int nl80211_set_wiphy(struct sk_b
|
@@ -3318,6 +3319,20 @@ static int nl80211_set_wiphy(struct sk_b
|
||||||
if (result)
|
if (result)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user