@@ -101,6 +101,45 @@ enum elem_id_ext {
EID_EXT_HE_CAPABILITY = 35,
};
+struct ieee80211_elems {
+ const __u8 *ie_start;
+ size_t total_length;
+
+ __u8 seen[32];
+ __u8 seen_ext[32];
+
+ const __u8 *ies[NUM_IES];
+ const __u8 *ies_ext[NUM_IES];
+
+ /* payload lengths of each ie */
+ __u8 lengths[NUM_IES];
+ __u8 lengths_ext[NUM_IES];
+};
+
+static inline void set_seen(struct ieee80211_elems *elems,
+ const uint8_t type)
+{
+ elems->seen[type / 8] |= 1 << (type % 8);
+}
+
+static inline void set_seen_ext(struct ieee80211_elems *elems,
+ const uint8_t type)
+{
+ elems->seen_ext[type / 8] |= 1 << (type % 8);
+}
+
+static inline int was_seen(struct ieee80211_elems *elems,
+ const uint8_t type)
+{
+ return elems->seen[type / 8] & (1 << (type % 8));
+}
+
+static inline int was_seen_ext(struct ieee80211_elems *elems,
+ const uint8_t type)
+{
+ return elems->seen_ext[type / 8] & (1 << (type % 8));
+}
+
#define SUITE(oui, id) (((oui) << 8) | (id))
/* cipher suite selectors */
@@ -1782,6 +1782,12 @@ struct ie_print {
uint8_t flags;
};
+struct element {
+ __u8 id;
+ __u8 datalen;
+ __u8 data[];
+} __attribute__ ((packed));
+
static void print_ie(const struct ie_print *p, const uint8_t type, uint8_t len,
const uint8_t *data,
const struct print_ies_data *ie_buffer)
@@ -2332,7 +2338,7 @@ static const struct ie_print wfa_printers[] = {
[28] = { "OWE Transition Mode", print_wifi_owe_tarns, 7, 255, BIT(PRINT_SCAN), },
};
-static void print_vendor(unsigned char len, unsigned char *data,
+static void print_vendor(unsigned char len, const unsigned char *data,
bool unknown, enum print_ie_type ptype)
{
int i;
@@ -2402,31 +2408,88 @@ static const struct ie_print ext_printers[] = {
[EID_EXT_HE_CAPABILITY] = { "HE capabilities", print_he_capa, 21, 54, BIT(PRINT_SCAN), },
};
-static void print_extension(unsigned char len, unsigned char *ie,
- bool unknown, enum print_ie_type ptype)
+
+static void print_extension(bool unknown, struct ieee80211_elems *elems,
+ enum print_ie_type ptype)
{
- unsigned char tag;
+ unsigned i;
- if (len < 1) {
- printf("\tExtension IE: <empty>\n");
+ if (elems == NULL)
return;
+
+ for (i = 0; i < NUM_IES; i++) {
+ if (!was_seen_ext(elems, i))
+ continue;
+
+ if (elems->lengths_ext[i] < 1) {
+ printf("\tExtension IE %u: <empty>\n", i);
+ continue;
+ }
+
+ if (i < ARRAY_SIZE(ext_printers) &&
+ ext_printers[i].name &&
+ ext_printers[i].flags & BIT(ptype) &&
+ elems->lengths_ext[i] > 0) {
+ print_ie(&ext_printers[i], i, elems->lengths_ext[i] - 1,
+ elems->ies_ext[i], NULL);
+ } else if (unknown) {
+ int j;
+
+ printf("\tUnknown Extension ID (%d):", i);
+ for (j = 1; j < elems->lengths_ext[i]; j++)
+ printf(" %.2x", elems->ies_ext[i][j]);
+ printf("\n");
+ }
}
+}
- tag = ie[0];
- if (tag < ARRAY_SIZE(ext_printers) && ext_printers[tag].name &&
- ext_printers[tag].flags & BIT(ptype)) {
- print_ie(&ext_printers[tag], tag, len - 1, ie + 1, NULL);
+static void parse_ie_ext(const struct element *elem,
+ struct ieee80211_elems *elems)
+{
+ const uint8_t type = elem->data[0];
+ const uint8_t *data = elem->data + 1;
+
+ if (!elem->datalen)
return;
- }
- if (unknown) {
- int i;
+ set_seen_ext(elems, type);
- printf("\tUnknown Extension ID (%d):", ie[0]);
- for (i = 1; i < len; i++)
- printf(" %.2x", ie[i]);
- printf("\n");
+ elems->lengths_ext[type] = elem->datalen;
+
+ if (elem->datalen)
+ elems->ies_ext[type] = data;
+}
+
+static int parse_ies(unsigned char *ie, int ielen, bool unknown,
+ struct ieee80211_elems *elems)
+{
+ const struct element *elem;
+
+ if (ie == NULL || ielen < 0 || elems == NULL)
+ return 1;
+
+ elems->ie_start = ie;
+ elems->total_length = ielen;
+
+ elem = (const struct element *)ie;
+ while (ielen >= 2 && ielen - 2 > elem->datalen) {
+ uint8_t id = elem->id;
+ uint8_t elen = elem->datalen;
+ const uint8_t *data = elem->data;
+
+ set_seen(elems, id);
+
+ if (id == EID_EXTENSION) {
+ parse_ie_ext(elem, elems);
+ } else if (elen) {
+ elems->lengths[id] = elen;
+ elems->ies[id] = data;
+ }
+
+ ielen -= elem->datalen + 2;
+ elem = (const struct element *)(elem->data + elem->datalen);
}
+ return 0;
}
void print_ies(unsigned char *ie, int ielen, bool unknown,
@@ -2435,31 +2498,36 @@ void print_ies(unsigned char *ie, int ielen, bool unknown,
struct print_ies_data ie_buffer = {
.ie = ie,
.ielen = ielen };
+ struct ieee80211_elems elems = { };
+ unsigned i;
- if (ie == NULL || ielen < 0)
+ if (parse_ies(ie, ielen, unknown, &elems))
return;
- while (ielen >= 2 && ielen - 2 >= ie[1]) {
- if (ie[0] < ARRAY_SIZE(ieprinters) &&
- ieprinters[ie[0]].name &&
- ieprinters[ie[0]].flags & BIT(ptype) &&
- ie[1] > 0) {
- print_ie(&ieprinters[ie[0]],
- ie[0], ie[1], ie + 2, &ie_buffer);
- } else if (ie[0] == 221 /* vendor */) {
- print_vendor(ie[1], ie + 2, unknown, ptype);
- } else if (ie[0] == 255 /* extension */) {
- print_extension(ie[1], ie + 2, unknown, ptype);
+ for (i = 0; i < NUM_IES; i++) {
+ if (!was_seen(&elems, i))
+ continue;
+
+ if (i < ARRAY_SIZE(ieprinters) &&
+ ieprinters[i].name &&
+ ieprinters[i].flags & BIT(ptype) &&
+ elems.lengths[i] > 0) {
+ print_ie(&ieprinters[i], i, elems.lengths[i],
+ elems.ies[i], &ie_buffer);
+ }
+ else if (i == EID_VENDOR) {
+ print_vendor(elems.lengths[i], elems.ies[i],
+ unknown, ptype);
+ } else if (i == EID_EXTENSION) {
+ print_extension(unknown, &elems, ptype);
} else if (unknown) {
- int i;
+ int j;
- printf("\tUnknown IE (%d):", ie[0]);
- for (i=0; i<ie[1]; i++)
- printf(" %.2x", ie[2+i]);
+ printf("\tUnknown IE (%d):", i);
+ for (j = 0; j < elems.lengths[i]; j++)
+ printf(" %.2x", elems.ies[i][j]);
printf("\n");
}
- ielen -= ie[1] + 2;
- ie += ie[1] + 2;
}
}
Since some ies require references to other ies, this introduces the infrastructure to prevent double parsing the ie buffer by caching the ie data rather than reading it in-place. Signed-off-by: Dylan Eskew <dylan.eskew@candelatech.com> --- ieee80211.h | 39 +++++++++++++++ scan.c | 138 +++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 142 insertions(+), 35 deletions(-)