Commit 81830c8f authored by Johannes Berg's avatar Johannes Berg

wifi: nl80211: refactor parsing CSA offsets

The CSA offset parsing happens the same way for all of
beacon template offsets, probe response template offsets
and TX offsets (for using during probe response TX from
userspace directly).

Refactor the parsing here. There's an additional check
this introduces, which is that the number of counters in
TX offsets doesn't exceed the driver capability, but as
only two counters are used at most for anything, this is
hopefully OK.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 4f4d8be6
......@@ -10048,6 +10048,42 @@ static int nl80211_notify_radar_detection(struct sk_buff *skb,
return 0;
}
static int nl80211_parse_counter_offsets(struct cfg80211_registered_device *rdev,
const u8 *data, size_t datalen,
int first_count, struct nlattr *attr,
const u16 **offsets, unsigned int *n_offsets)
{
int i;
*n_offsets = 0;
if (!attr)
return 0;
if (!nla_len(attr) || (nla_len(attr) % sizeof(u16)))
return -EINVAL;
*n_offsets = nla_len(attr) / sizeof(u16);
if (rdev->wiphy.max_num_csa_counters &&
(*n_offsets > rdev->wiphy.max_num_csa_counters))
return -EINVAL;
*offsets = nla_data(attr);
/* sanity checks - counters should fit and be the same */
for (i = 0; i < *n_offsets; i++) {
u16 offset = (*offsets)[i];
if (offset >= datalen)
return -EINVAL;
if (first_count != -1 && data[offset] != first_count)
return -EINVAL;
}
return 0;
}
static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
......@@ -10059,7 +10095,6 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
int err;
bool need_new_beacon = false;
bool need_handle_dfs_flag = true;
int len, i;
u32 cs_count;
if (!rdev->ops->channel_switch ||
......@@ -10144,72 +10179,23 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
goto free;
}
len = nla_len(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_BEACON]);
if (!len || (len % sizeof(u16))) {
err = -EINVAL;
err = nl80211_parse_counter_offsets(rdev, params.beacon_csa.tail,
params.beacon_csa.tail_len,
params.count,
csa_attrs[NL80211_ATTR_CNTDWN_OFFS_BEACON],
&params.counter_offsets_beacon,
&params.n_counter_offsets_beacon);
if (err)
goto free;
}
params.n_counter_offsets_beacon = len / sizeof(u16);
if (rdev->wiphy.max_num_csa_counters &&
(params.n_counter_offsets_beacon >
rdev->wiphy.max_num_csa_counters)) {
err = -EINVAL;
err = nl80211_parse_counter_offsets(rdev, params.beacon_csa.probe_resp,
params.beacon_csa.probe_resp_len,
params.count,
csa_attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP],
&params.counter_offsets_presp,
&params.n_counter_offsets_presp);
if (err)
goto free;
}
params.counter_offsets_beacon =
nla_data(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_BEACON]);
/* sanity checks - counters should fit and be the same */
for (i = 0; i < params.n_counter_offsets_beacon; i++) {
u16 offset = params.counter_offsets_beacon[i];
if (offset >= params.beacon_csa.tail_len) {
err = -EINVAL;
goto free;
}
if (params.beacon_csa.tail[offset] != params.count) {
err = -EINVAL;
goto free;
}
}
if (csa_attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP]) {
len = nla_len(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP]);
if (!len || (len % sizeof(u16))) {
err = -EINVAL;
goto free;
}
params.n_counter_offsets_presp = len / sizeof(u16);
if (rdev->wiphy.max_num_csa_counters &&
(params.n_counter_offsets_presp >
rdev->wiphy.max_num_csa_counters)) {
err = -EINVAL;
goto free;
}
params.counter_offsets_presp =
nla_data(csa_attrs[NL80211_ATTR_CNTDWN_OFFS_PRESP]);
/* sanity checks - counters should fit and be the same */
for (i = 0; i < params.n_counter_offsets_presp; i++) {
u16 offset = params.counter_offsets_presp[i];
if (offset >= params.beacon_csa.probe_resp_len) {
err = -EINVAL;
goto free;
}
if (params.beacon_csa.probe_resp[offset] !=
params.count) {
err = -EINVAL;
goto free;
}
}
}
skip_beacons:
err = nl80211_parse_chandef(rdev, info, &params.chandef);
......@@ -12638,23 +12624,12 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
if (info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]) {
int len = nla_len(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
int i;
if (len % sizeof(u16))
return -EINVAL;
params.n_csa_offsets = len / sizeof(u16);
params.csa_offsets =
nla_data(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]);
/* check that all the offsets fit the frame */
for (i = 0; i < params.n_csa_offsets; i++) {
if (params.csa_offsets[i] >= params.len)
return -EINVAL;
}
}
err = nl80211_parse_counter_offsets(rdev, NULL, params.len, -1,
info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX],
&params.csa_offsets,
&params.n_csa_offsets);
if (err)
return err;
if (!params.dont_wait_for_ack) {
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment