Merge tag 'mac80211-next-for-davem-2019-04-26' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next

Johannes Berg says:

====================
Various updates, notably:
 * extended key ID support (from 802.11-2016)
 * per-STA TX power control support
 * mac80211 TX performance improvements
 * HE (802.11ax) updates
 * mesh link probing support
 * enhancements of multi-BSSID support (also related to HE)
 * OWE userspace processing support
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller
2019-04-26 16:05:52 -04:00
36 changed files with 1480 additions and 375 deletions
+164 -9
View File
@@ -179,12 +179,63 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev,
return true;
}
bool cfg80211_is_element_inherited(const struct element *elem,
const struct element *non_inherit_elem)
{
u8 id_len, ext_id_len, i, loop_len, id;
const u8 *list;
if (elem->id == WLAN_EID_MULTIPLE_BSSID)
return false;
if (!non_inherit_elem || non_inherit_elem->datalen < 2)
return true;
/*
* non inheritance element format is:
* ext ID (56) | IDs list len | list | extension IDs list len | list
* Both lists are optional. Both lengths are mandatory.
* This means valid length is:
* elem_len = 1 (extension ID) + 2 (list len fields) + list lengths
*/
id_len = non_inherit_elem->data[1];
if (non_inherit_elem->datalen < 3 + id_len)
return true;
ext_id_len = non_inherit_elem->data[2 + id_len];
if (non_inherit_elem->datalen < 3 + id_len + ext_id_len)
return true;
if (elem->id == WLAN_EID_EXTENSION) {
if (!ext_id_len)
return true;
loop_len = ext_id_len;
list = &non_inherit_elem->data[3 + id_len];
id = elem->data[0];
} else {
if (!id_len)
return true;
loop_len = id_len;
list = &non_inherit_elem->data[2];
id = elem->id;
}
for (i = 0; i < loop_len; i++) {
if (list[i] == id)
return false;
}
return true;
}
EXPORT_SYMBOL(cfg80211_is_element_inherited);
static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
const u8 *subelement, size_t subie_len,
u8 *new_ie, gfp_t gfp)
{
u8 *pos, *tmp;
const u8 *tmp_old, *tmp_new;
const struct element *non_inherit_elem;
u8 *sub_copy;
/* copy subelement as we need to change its content to
@@ -203,6 +254,11 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
pos += (tmp_new[1] + 2);
}
/* get non inheritance list if exists */
non_inherit_elem =
cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
sub_copy, subie_len);
/* go through IEs in ie (skip SSID) and subelement,
* merge them into new_ie
*/
@@ -223,8 +279,11 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
subie_len);
if (!tmp) {
const struct element *old_elem = (void *)tmp_old;
/* ie in old ie but not in subelement */
if (tmp_old[0] != WLAN_EID_MULTIPLE_BSSID) {
if (cfg80211_is_element_inherited(old_elem,
non_inherit_elem)) {
memcpy(pos, tmp_old, tmp_old[1] + 2);
pos += tmp_old[1] + 2;
}
@@ -268,8 +327,7 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
tmp_new = sub_copy;
while (tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP ||
tmp_new[0] == WLAN_EID_SSID ||
tmp_new[0] == WLAN_EID_MULTI_BSSID_IDX)) {
tmp_new[0] == WLAN_EID_SSID)) {
memcpy(pos, tmp_new, tmp_new[1] + 2);
pos += tmp_new[1] + 2;
}
@@ -1397,6 +1455,78 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
return &res->pub;
}
static const struct element
*cfg80211_get_profile_continuation(const u8 *ie, size_t ielen,
const struct element *mbssid_elem,
const struct element *sub_elem)
{
const u8 *mbssid_end = mbssid_elem->data + mbssid_elem->datalen;
const struct element *next_mbssid;
const struct element *next_sub;
next_mbssid = cfg80211_find_elem(WLAN_EID_MULTIPLE_BSSID,
mbssid_end,
ielen - (mbssid_end - ie));
/*
* If is is not the last subelement in current MBSSID IE or there isn't
* a next MBSSID IE - profile is complete.
*/
if ((sub_elem->data + sub_elem->datalen < mbssid_end - 1) ||
!next_mbssid)
return NULL;
/* For any length error, just return NULL */
if (next_mbssid->datalen < 4)
return NULL;
next_sub = (void *)&next_mbssid->data[1];
if (next_mbssid->data + next_mbssid->datalen <
next_sub->data + next_sub->datalen)
return NULL;
if (next_sub->id != 0 || next_sub->datalen < 2)
return NULL;
/*
* Check if the first element in the next sub element is a start
* of a new profile
*/
return next_sub->data[0] == WLAN_EID_NON_TX_BSSID_CAP ?
NULL : next_mbssid;
}
size_t cfg80211_merge_profile(const u8 *ie, size_t ielen,
const struct element *mbssid_elem,
const struct element *sub_elem,
u8 *merged_ie, size_t max_copy_len)
{
size_t copied_len = sub_elem->datalen;
const struct element *next_mbssid;
if (sub_elem->datalen > max_copy_len)
return 0;
memcpy(merged_ie, sub_elem->data, sub_elem->datalen);
while ((next_mbssid = cfg80211_get_profile_continuation(ie, ielen,
mbssid_elem,
sub_elem))) {
const struct element *next_sub = (void *)&next_mbssid->data[1];
if (copied_len + next_sub->datalen > max_copy_len)
break;
memcpy(merged_ie + copied_len, next_sub->data,
next_sub->datalen);
copied_len += next_sub->datalen;
}
return copied_len;
}
EXPORT_SYMBOL(cfg80211_merge_profile);
static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
struct cfg80211_inform_bss *data,
enum cfg80211_bss_frame_type ftype,
@@ -1410,7 +1540,8 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
const struct element *elem, *sub;
size_t new_ie_len;
u8 new_bssid[ETH_ALEN];
u8 *new_ie;
u8 *new_ie, *profile;
u64 seen_indices = 0;
u16 capability;
struct cfg80211_bss *bss;
@@ -1428,10 +1559,16 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
if (!new_ie)
return;
profile = kmalloc(ielen, gfp);
if (!profile)
goto out;
for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) {
if (elem->datalen < 4)
continue;
for_each_element(sub, elem->data + 1, elem->datalen - 1) {
u8 profile_len;
if (sub->id != 0 || sub->datalen < 4) {
/* not a valid BSS profile */
continue;
@@ -1446,16 +1583,31 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
continue;
}
memset(profile, 0, ielen);
profile_len = cfg80211_merge_profile(ie, ielen,
elem,
sub,
profile,
ielen);
/* found a Nontransmitted BSSID Profile */
mbssid_index_ie = cfg80211_find_ie
(WLAN_EID_MULTI_BSSID_IDX,
sub->data, sub->datalen);
profile, profile_len);
if (!mbssid_index_ie || mbssid_index_ie[1] < 1 ||
mbssid_index_ie[2] == 0) {
mbssid_index_ie[2] == 0 ||
mbssid_index_ie[2] > 46) {
/* No valid Multiple BSSID-Index element */
continue;
}
if (seen_indices & BIT(mbssid_index_ie[2]))
/* We don't support legacy split of a profile */
net_dbg_ratelimited("Partial info for BSSID index %d\n",
mbssid_index_ie[2]);
seen_indices |= BIT(mbssid_index_ie[2]);
non_tx_data->bssid_index = mbssid_index_ie[2];
non_tx_data->max_bssid_indicator = elem->data[0];
@@ -1464,13 +1616,14 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
non_tx_data->bssid_index,
new_bssid);
memset(new_ie, 0, IEEE80211_MAX_DATA_LEN);
new_ie_len = cfg80211_gen_new_ie(ie, ielen, sub->data,
sub->datalen, new_ie,
new_ie_len = cfg80211_gen_new_ie(ie, ielen,
profile,
profile_len, new_ie,
gfp);
if (!new_ie_len)
continue;
capability = get_unaligned_le16(sub->data + 2);
capability = get_unaligned_le16(profile + 2);
bss = cfg80211_inform_single_bss_data(wiphy, data,
ftype,
new_bssid, tsf,
@@ -1486,7 +1639,9 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
}
}
out:
kfree(new_ie);
kfree(profile);
}
struct cfg80211_bss *