aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2019-02-07 21:44:41 +0100
committerBen Hutchings <ben@decadent.org.uk>2019-12-10 18:01:28 +0000
commit48ed745ea1ae3dc91b07a021ce3ff5ca75995551 (patch)
tree497e72ca291ef368a07fccd1d795e2a29b4f6a8b /include
parent470a2d36f614f40b7f032071cfa6662dfcc1eda4 (diff)
downloadlinux-stable-48ed745ea1ae3dc91b07a021ce3ff5ca75995551.tar.gz
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> Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'include')
-rw-r--r--include/linux/ieee80211.h53
1 files changed, 53 insertions, 0 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 75d17e15da338c..579cd731718234 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -2358,4 +2358,57 @@ static inline bool ieee80211_check_tim(const struct ieee80211_tim_ie *tim,
#define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024))
#define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x))
+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 */