Skip to content

Commit fbd05e4

Browse files
lucacoelhojmberg-intel
authored andcommitted
cfg80211: add helper to find an IE that matches a byte-array
There are a few places where an IE that matches not only the EID, but also other bytes inside the element, needs to be found. To simplify that and reduce the amount of similar code, implement a new helper function to match the EID and an extra array of bytes. Additionally, simplify cfg80211_find_vendor_ie() by using the new match function. Signed-off-by: Luca Coelho <luciano.coelho@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
1 parent b59abfb commit fbd05e4

File tree

2 files changed

+59
-32
lines changed

2 files changed

+59
-32
lines changed

include/net/cfg80211.h

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3946,6 +3946,34 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
39463946
unsigned int cfg80211_classify8021d(struct sk_buff *skb,
39473947
struct cfg80211_qos_map *qos_map);
39483948

3949+
/**
3950+
* cfg80211_find_ie_match - match information element and byte array in data
3951+
*
3952+
* @eid: element ID
3953+
* @ies: data consisting of IEs
3954+
* @len: length of data
3955+
* @match: byte array to match
3956+
* @match_len: number of bytes in the match array
3957+
* @match_offset: offset in the IE where the byte array should match.
3958+
* If match_len is zero, this must also be set to zero.
3959+
* Otherwise this must be set to 2 or more, because the first
3960+
* byte is the element id, which is already compared to eid, and
3961+
* the second byte is the IE length.
3962+
*
3963+
* Return: %NULL if the element ID could not be found or if
3964+
* the element is invalid (claims to be longer than the given
3965+
* data) or if the byte array doesn't match, or a pointer to the first
3966+
* byte of the requested element, that is the byte containing the
3967+
* element ID.
3968+
*
3969+
* Note: There are no checks on the element length other than
3970+
* having to fit into the given data and being large enough for the
3971+
* byte array to match.
3972+
*/
3973+
const u8 *cfg80211_find_ie_match(u8 eid, const u8 *ies, int len,
3974+
const u8 *match, int match_len,
3975+
int match_offset);
3976+
39493977
/**
39503978
* cfg80211_find_ie - find information element in data
39513979
*
@@ -3961,7 +3989,10 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb,
39613989
* Note: There are no checks on the element length other than
39623990
* having to fit into the given data.
39633991
*/
3964-
const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len);
3992+
static inline const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
3993+
{
3994+
return cfg80211_find_ie_match(eid, ies, len, NULL, 0, 0);
3995+
}
39653996

39663997
/**
39673998
* cfg80211_find_vendor_ie - find vendor specific information element in data

net/wireless/scan.c

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -352,52 +352,48 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *rdev)
352352
__cfg80211_bss_expire(rdev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE);
353353
}
354354

355-
const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
355+
const u8 *cfg80211_find_ie_match(u8 eid, const u8 *ies, int len,
356+
const u8 *match, int match_len,
357+
int match_offset)
356358
{
357-
while (len > 2 && ies[0] != eid) {
359+
/* match_offset can't be smaller than 2, unless match_len is
360+
* zero, in which case match_offset must be zero as well.
361+
*/
362+
if (WARN_ON((match_len && match_offset < 2) ||
363+
(!match_len && match_offset)))
364+
return NULL;
365+
366+
while (len >= 2 && len >= ies[1] + 2) {
367+
if ((ies[0] == eid) &&
368+
(ies[1] + 2 >= match_offset + match_len) &&
369+
!memcmp(ies + match_offset, match, match_len))
370+
return ies;
371+
358372
len -= ies[1] + 2;
359373
ies += ies[1] + 2;
360374
}
361-
if (len < 2)
362-
return NULL;
363-
if (len < 2 + ies[1])
364-
return NULL;
365-
return ies;
375+
376+
return NULL;
366377
}
367-
EXPORT_SYMBOL(cfg80211_find_ie);
378+
EXPORT_SYMBOL(cfg80211_find_ie_match);
368379

369380
const u8 *cfg80211_find_vendor_ie(unsigned int oui, int oui_type,
370381
const u8 *ies, int len)
371382
{
372-
struct ieee80211_vendor_ie *ie;
373-
const u8 *pos = ies, *end = ies + len;
374-
int ie_oui;
383+
const u8 *ie;
384+
u8 match[] = { oui >> 16, oui >> 8, oui, oui_type };
385+
int match_len = (oui_type < 0) ? 3 : sizeof(match);
375386

376387
if (WARN_ON(oui_type > 0xff))
377388
return NULL;
378389

379-
while (pos < end) {
380-
pos = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, pos,
381-
end - pos);
382-
if (!pos)
383-
return NULL;
384-
385-
ie = (struct ieee80211_vendor_ie *)pos;
386-
387-
/* make sure we can access ie->len */
388-
BUILD_BUG_ON(offsetof(struct ieee80211_vendor_ie, len) != 1);
390+
ie = cfg80211_find_ie_match(WLAN_EID_VENDOR_SPECIFIC, ies, len,
391+
match, match_len, 2);
389392

390-
if (ie->len < sizeof(*ie))
391-
goto cont;
393+
if (ie && (ie[1] < 4))
394+
return NULL;
392395

393-
ie_oui = ie->oui[0] << 16 | ie->oui[1] << 8 | ie->oui[2];
394-
if (ie_oui == oui &&
395-
(oui_type < 0 || ie->oui_type == oui_type))
396-
return pos;
397-
cont:
398-
pos += 2 + ie->len;
399-
}
400-
return NULL;
396+
return ie;
401397
}
402398
EXPORT_SYMBOL(cfg80211_find_vendor_ie);
403399

0 commit comments

Comments
 (0)