Skip to content

Commit 0f3b07f

Browse files
committed
cfg80211: add and use strongly typed element iteration macros
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 <[email protected]>
1 parent 341203e commit 0f3b07f

File tree

2 files changed

+59
-8
lines changed

2 files changed

+59
-8
lines changed

include/linux/ieee80211.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3243,4 +3243,57 @@ static inline bool ieee80211_action_contains_tpc(struct sk_buff *skb)
32433243
return true;
32443244
}
32453245

3246+
struct element {
3247+
u8 id;
3248+
u8 datalen;
3249+
u8 data[];
3250+
};
3251+
3252+
/* element iteration helpers */
3253+
#define for_each_element(element, _data, _datalen) \
3254+
for (element = (void *)(_data); \
3255+
(u8 *)(_data) + (_datalen) - (u8 *)element >= \
3256+
sizeof(*element) && \
3257+
(u8 *)(_data) + (_datalen) - (u8 *)element >= \
3258+
sizeof(*element) + element->datalen; \
3259+
element = (void *)(element->data + element->datalen))
3260+
3261+
#define for_each_element_id(element, _id, data, datalen) \
3262+
for_each_element(element, data, datalen) \
3263+
if (element->id == (_id))
3264+
3265+
#define for_each_element_extid(element, extid, data, datalen) \
3266+
for_each_element(element, data, datalen) \
3267+
if (element->id == WLAN_EID_EXTENSION && \
3268+
element->datalen > 0 && \
3269+
element->data[0] == (extid))
3270+
3271+
#define for_each_subelement(sub, element) \
3272+
for_each_element(sub, (element)->data, (element)->datalen)
3273+
3274+
#define for_each_subelement_id(sub, id, element) \
3275+
for_each_element_id(sub, id, (element)->data, (element)->datalen)
3276+
3277+
#define for_each_subelement_extid(sub, extid, element) \
3278+
for_each_element_extid(sub, extid, (element)->data, (element)->datalen)
3279+
3280+
/**
3281+
* for_each_element_completed - determine if element parsing consumed all data
3282+
* @element: element pointer after for_each_element() or friends
3283+
* @data: same data pointer as passed to for_each_element() or friends
3284+
* @datalen: same data length as passed to for_each_element() or friends
3285+
*
3286+
* This function returns %true if all the data was parsed or considered
3287+
* while walking the elements. Only use this if your for_each_element()
3288+
* loop cannot be broken out of, otherwise it always returns %false.
3289+
*
3290+
* If some data was malformed, this returns %false since the last parsed
3291+
* element will not fill the whole remaining data.
3292+
*/
3293+
static inline bool for_each_element_completed(const struct element *element,
3294+
const void *data, size_t datalen)
3295+
{
3296+
return (u8 *)element == (u8 *)data + datalen;
3297+
}
3298+
32463299
#endif /* LINUX_IEEE80211_H */

net/wireless/scan.c

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -484,21 +484,19 @@ const u8 *cfg80211_find_ie_match(u8 eid, const u8 *ies, int len,
484484
const u8 *match, int match_len,
485485
int match_offset)
486486
{
487+
const struct element *elem;
488+
487489
/* match_offset can't be smaller than 2, unless match_len is
488490
* zero, in which case match_offset must be zero as well.
489491
*/
490492
if (WARN_ON((match_len && match_offset < 2) ||
491493
(!match_len && match_offset)))
492494
return NULL;
493495

494-
while (len >= 2 && len >= ies[1] + 2) {
495-
if ((ies[0] == eid) &&
496-
(ies[1] + 2 >= match_offset + match_len) &&
497-
!memcmp(ies + match_offset, match, match_len))
498-
return ies;
499-
500-
len -= ies[1] + 2;
501-
ies += ies[1] + 2;
496+
for_each_element_id(elem, eid, ies, len) {
497+
if (elem->datalen >= match_offset - 2 + match_len &&
498+
!memcmp(elem->data + match_offset - 2, match, match_len))
499+
return (void *)elem;
502500
}
503501

504502
return NULL;

0 commit comments

Comments
 (0)