diff options
author | Johannes Berg <johannes.berg@intel.com> | 2019-02-07 21:44:41 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-10-17 13:40:57 -0700 |
commit | 933f4f10c9286ce577db1454abb6b50c124823f9 (patch) | |
tree | b5555dd4312d77ef4a9d8335bd574fffaad06eb3 /include | |
parent | a3cda6a020433446d5424c05326149549b7e0d64 (diff) |
cfg80211: add and use strongly typed element iteration macros
commit 0f3b07f027f87a38ebe5c436490095df762819be upstream.
Rather than always iterating elements from frames with pure
u8 pointers, add a type "struct element" that encapsulates
the id/datalen/data format of them.
Then, add the element iteration macros
* for_each_element
* for_each_element_id
* for_each_element_extid
which take, as their first 'argument', such a structure and
iterate through a given u8 array interpreting it as elements.
While at it and since we'll need it, also add
* for_each_subelement
* for_each_subelement_id
* for_each_subelement_extid
which instead of taking data/length just take an outer element
and use its data/datalen.
Also add for_each_element_completed() to determine if any of
the loops above completed, i.e. it was able to parse all of
the elements successfully and no data remained.
Use for_each_element_id() in cfg80211_find_ie_match() as the
first user of this.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/ieee80211.h | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 452c0b0d2f32..40978def5aca 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -2550,4 +2550,57 @@ static inline bool ieee80211_action_contains_tpc(struct sk_buff *skb) return true; } +struct element { + u8 id; + u8 datalen; + u8 data[]; +}; + +/* element iteration helpers */ +#define for_each_element(element, _data, _datalen) \ + for (element = (void *)(_data); \ + (u8 *)(_data) + (_datalen) - (u8 *)element >= \ + sizeof(*element) && \ + (u8 *)(_data) + (_datalen) - (u8 *)element >= \ + sizeof(*element) + element->datalen; \ + element = (void *)(element->data + element->datalen)) + +#define for_each_element_id(element, _id, data, datalen) \ + for_each_element(element, data, datalen) \ + if (element->id == (_id)) + +#define for_each_element_extid(element, extid, data, datalen) \ + for_each_element(element, data, datalen) \ + if (element->id == WLAN_EID_EXTENSION && \ + element->datalen > 0 && \ + element->data[0] == (extid)) + +#define for_each_subelement(sub, element) \ + for_each_element(sub, (element)->data, (element)->datalen) + +#define for_each_subelement_id(sub, id, element) \ + for_each_element_id(sub, id, (element)->data, (element)->datalen) + +#define for_each_subelement_extid(sub, extid, element) \ + for_each_element_extid(sub, extid, (element)->data, (element)->datalen) + +/** + * for_each_element_completed - determine if element parsing consumed all data + * @element: element pointer after for_each_element() or friends + * @data: same data pointer as passed to for_each_element() or friends + * @datalen: same data length as passed to for_each_element() or friends + * + * This function returns %true if all the data was parsed or considered + * while walking the elements. Only use this if your for_each_element() + * loop cannot be broken out of, otherwise it always returns %false. + * + * If some data was malformed, this returns %false since the last parsed + * element will not fill the whole remaining data. + */ +static inline bool for_each_element_completed(const struct element *element, + const void *data, size_t datalen) +{ + return (u8 *)element == (u8 *)data + datalen; +} + #endif /* LINUX_IEEE80211_H */ |