1*92022041SSam Saccone #include <net/if.h>
2*92022041SSam Saccone #include <errno.h>
3*92022041SSam Saccone #include <string.h>
4*92022041SSam Saccone #include <stdbool.h>
5*92022041SSam Saccone
6*92022041SSam Saccone #include <netlink/genl/genl.h>
7*92022041SSam Saccone #include <netlink/genl/family.h>
8*92022041SSam Saccone #include <netlink/genl/ctrl.h>
9*92022041SSam Saccone #include <netlink/msg.h>
10*92022041SSam Saccone #include <netlink/attr.h>
11*92022041SSam Saccone
12*92022041SSam Saccone #include "nl80211.h"
13*92022041SSam Saccone #include "iw.h"
14*92022041SSam Saccone
15*92022041SSam Saccone #define WLAN_CAPABILITY_ESS (1<<0)
16*92022041SSam Saccone #define WLAN_CAPABILITY_IBSS (1<<1)
17*92022041SSam Saccone #define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
18*92022041SSam Saccone #define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
19*92022041SSam Saccone #define WLAN_CAPABILITY_PRIVACY (1<<4)
20*92022041SSam Saccone #define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
21*92022041SSam Saccone #define WLAN_CAPABILITY_PBCC (1<<6)
22*92022041SSam Saccone #define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
23*92022041SSam Saccone #define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8)
24*92022041SSam Saccone #define WLAN_CAPABILITY_QOS (1<<9)
25*92022041SSam Saccone #define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
26*92022041SSam Saccone #define WLAN_CAPABILITY_APSD (1<<11)
27*92022041SSam Saccone #define WLAN_CAPABILITY_RADIO_MEASURE (1<<12)
28*92022041SSam Saccone #define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
29*92022041SSam Saccone #define WLAN_CAPABILITY_DEL_BACK (1<<14)
30*92022041SSam Saccone #define WLAN_CAPABILITY_IMM_BACK (1<<15)
31*92022041SSam Saccone /* DMG (60gHz) 802.11ad */
32*92022041SSam Saccone /* type - bits 0..1 */
33*92022041SSam Saccone #define WLAN_CAPABILITY_DMG_TYPE_MASK (3<<0)
34*92022041SSam Saccone
35*92022041SSam Saccone #define WLAN_CAPABILITY_DMG_TYPE_IBSS (1<<0) /* Tx by: STA */
36*92022041SSam Saccone #define WLAN_CAPABILITY_DMG_TYPE_PBSS (2<<0) /* Tx by: PCP */
37*92022041SSam Saccone #define WLAN_CAPABILITY_DMG_TYPE_AP (3<<0) /* Tx by: AP */
38*92022041SSam Saccone
39*92022041SSam Saccone #define WLAN_CAPABILITY_DMG_CBAP_ONLY (1<<2)
40*92022041SSam Saccone #define WLAN_CAPABILITY_DMG_CBAP_SOURCE (1<<3)
41*92022041SSam Saccone #define WLAN_CAPABILITY_DMG_PRIVACY (1<<4)
42*92022041SSam Saccone #define WLAN_CAPABILITY_DMG_ECPAC (1<<5)
43*92022041SSam Saccone
44*92022041SSam Saccone #define WLAN_CAPABILITY_DMG_SPECTRUM_MGMT (1<<8)
45*92022041SSam Saccone #define WLAN_CAPABILITY_DMG_RADIO_MEASURE (1<<12)
46*92022041SSam Saccone
47*92022041SSam Saccone static unsigned char ms_oui[3] = { 0x00, 0x50, 0xf2 };
48*92022041SSam Saccone static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
49*92022041SSam Saccone static unsigned char wfa_oui[3] = { 0x50, 0x6f, 0x9a };
50*92022041SSam Saccone
51*92022041SSam Saccone struct scan_params {
52*92022041SSam Saccone bool unknown;
53*92022041SSam Saccone enum print_ie_type type;
54*92022041SSam Saccone bool show_both_ie_sets;
55*92022041SSam Saccone };
56*92022041SSam Saccone
57*92022041SSam Saccone #define IEEE80211_COUNTRY_EXTENSION_ID 201
58*92022041SSam Saccone
59*92022041SSam Saccone union ieee80211_country_ie_triplet {
60*92022041SSam Saccone struct {
61*92022041SSam Saccone __u8 first_channel;
62*92022041SSam Saccone __u8 num_channels;
63*92022041SSam Saccone __s8 max_power;
64*92022041SSam Saccone } __attribute__ ((packed)) chans;
65*92022041SSam Saccone struct {
66*92022041SSam Saccone __u8 reg_extension_id;
67*92022041SSam Saccone __u8 reg_class;
68*92022041SSam Saccone __u8 coverage_class;
69*92022041SSam Saccone } __attribute__ ((packed)) ext;
70*92022041SSam Saccone } __attribute__ ((packed));
71*92022041SSam Saccone
parse_sched_scan(struct nl_msg * msg,int * argc,char *** argv)72*92022041SSam Saccone int parse_sched_scan(struct nl_msg *msg, int *argc, char ***argv)
73*92022041SSam Saccone {
74*92022041SSam Saccone struct nl_msg *matchset = NULL, *freqs = NULL, *ssids = NULL;
75*92022041SSam Saccone struct nl_msg *scan_plans = NULL;
76*92022041SSam Saccone struct nlattr *match = NULL, *plan = NULL;
77*92022041SSam Saccone enum {
78*92022041SSam Saccone ND_TOPLEVEL,
79*92022041SSam Saccone ND_MATCH,
80*92022041SSam Saccone ND_FREQS,
81*92022041SSam Saccone ND_ACTIVE,
82*92022041SSam Saccone ND_PLANS,
83*92022041SSam Saccone } parse_state = ND_TOPLEVEL;
84*92022041SSam Saccone int c = *argc;
85*92022041SSam Saccone char *end, **v = *argv;
86*92022041SSam Saccone int err = 0, i = 0;
87*92022041SSam Saccone unsigned int freq, interval = 0, delay = 0, iterations = 0;
88*92022041SSam Saccone bool have_matchset = false, have_freqs = false, have_ssids = false;
89*92022041SSam Saccone bool have_active = false, have_passive = false, have_plans = false;
90*92022041SSam Saccone uint32_t flags = 0;
91*92022041SSam Saccone
92*92022041SSam Saccone matchset = nlmsg_alloc();
93*92022041SSam Saccone if (!matchset) {
94*92022041SSam Saccone err = -ENOBUFS;
95*92022041SSam Saccone goto out;
96*92022041SSam Saccone }
97*92022041SSam Saccone
98*92022041SSam Saccone freqs = nlmsg_alloc();
99*92022041SSam Saccone if (!freqs) {
100*92022041SSam Saccone err = -ENOBUFS;
101*92022041SSam Saccone goto out;
102*92022041SSam Saccone }
103*92022041SSam Saccone
104*92022041SSam Saccone ssids = nlmsg_alloc();
105*92022041SSam Saccone if (!ssids) {
106*92022041SSam Saccone err = -ENOMEM;
107*92022041SSam Saccone goto out;
108*92022041SSam Saccone }
109*92022041SSam Saccone
110*92022041SSam Saccone scan_plans = nlmsg_alloc();
111*92022041SSam Saccone if (!scan_plans) {
112*92022041SSam Saccone err = -ENOBUFS;
113*92022041SSam Saccone goto out;
114*92022041SSam Saccone }
115*92022041SSam Saccone
116*92022041SSam Saccone while (c) {
117*92022041SSam Saccone switch (parse_state) {
118*92022041SSam Saccone case ND_TOPLEVEL:
119*92022041SSam Saccone if (!strcmp(v[0], "interval")) {
120*92022041SSam Saccone c--; v++;
121*92022041SSam Saccone if (c == 0) {
122*92022041SSam Saccone err = -EINVAL;
123*92022041SSam Saccone goto nla_put_failure;
124*92022041SSam Saccone }
125*92022041SSam Saccone
126*92022041SSam Saccone if (interval || have_plans) {
127*92022041SSam Saccone err = -EINVAL;
128*92022041SSam Saccone goto nla_put_failure;
129*92022041SSam Saccone }
130*92022041SSam Saccone interval = strtoul(v[0], &end, 10);
131*92022041SSam Saccone if (*end || !interval) {
132*92022041SSam Saccone err = -EINVAL;
133*92022041SSam Saccone goto nla_put_failure;
134*92022041SSam Saccone }
135*92022041SSam Saccone NLA_PUT_U32(msg,
136*92022041SSam Saccone NL80211_ATTR_SCHED_SCAN_INTERVAL,
137*92022041SSam Saccone interval);
138*92022041SSam Saccone } else if (!strcmp(v[0], "scan_plans")) {
139*92022041SSam Saccone parse_state = ND_PLANS;
140*92022041SSam Saccone if (have_plans || interval) {
141*92022041SSam Saccone err = -EINVAL;
142*92022041SSam Saccone goto nla_put_failure;
143*92022041SSam Saccone }
144*92022041SSam Saccone
145*92022041SSam Saccone have_plans = true;
146*92022041SSam Saccone i = 0;
147*92022041SSam Saccone } else if (!strcmp(v[0], "delay")) {
148*92022041SSam Saccone c--; v++;
149*92022041SSam Saccone if (c == 0) {
150*92022041SSam Saccone err = -EINVAL;
151*92022041SSam Saccone goto nla_put_failure;
152*92022041SSam Saccone }
153*92022041SSam Saccone
154*92022041SSam Saccone if (delay) {
155*92022041SSam Saccone err = -EINVAL;
156*92022041SSam Saccone goto nla_put_failure;
157*92022041SSam Saccone }
158*92022041SSam Saccone delay = strtoul(v[0], &end, 10);
159*92022041SSam Saccone if (*end) {
160*92022041SSam Saccone err = -EINVAL;
161*92022041SSam Saccone goto nla_put_failure;
162*92022041SSam Saccone }
163*92022041SSam Saccone NLA_PUT_U32(msg,
164*92022041SSam Saccone NL80211_ATTR_SCHED_SCAN_DELAY,
165*92022041SSam Saccone delay);
166*92022041SSam Saccone } else if (!strcmp(v[0], "matches")) {
167*92022041SSam Saccone parse_state = ND_MATCH;
168*92022041SSam Saccone if (have_matchset) {
169*92022041SSam Saccone err = -EINVAL;
170*92022041SSam Saccone goto nla_put_failure;
171*92022041SSam Saccone }
172*92022041SSam Saccone
173*92022041SSam Saccone i = 0;
174*92022041SSam Saccone } else if (!strcmp(v[0], "freqs")) {
175*92022041SSam Saccone parse_state = ND_FREQS;
176*92022041SSam Saccone if (have_freqs) {
177*92022041SSam Saccone err = -EINVAL;
178*92022041SSam Saccone goto nla_put_failure;
179*92022041SSam Saccone }
180*92022041SSam Saccone
181*92022041SSam Saccone have_freqs = true;
182*92022041SSam Saccone i = 0;
183*92022041SSam Saccone } else if (!strcmp(v[0], "active")) {
184*92022041SSam Saccone parse_state = ND_ACTIVE;
185*92022041SSam Saccone if (have_active || have_passive) {
186*92022041SSam Saccone err = -EINVAL;
187*92022041SSam Saccone goto nla_put_failure;
188*92022041SSam Saccone }
189*92022041SSam Saccone
190*92022041SSam Saccone have_active = true;
191*92022041SSam Saccone i = 0;
192*92022041SSam Saccone } else if (!strcmp(v[0], "passive")) {
193*92022041SSam Saccone if (have_active || have_passive) {
194*92022041SSam Saccone err = -EINVAL;
195*92022041SSam Saccone goto nla_put_failure;
196*92022041SSam Saccone }
197*92022041SSam Saccone
198*92022041SSam Saccone have_passive = true;
199*92022041SSam Saccone } else if (!strncmp(v[0], "randomise", 9) ||
200*92022041SSam Saccone !strncmp(v[0], "randomize", 9)) {
201*92022041SSam Saccone flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
202*92022041SSam Saccone err = parse_random_mac_addr(msg, v[0] + 9);
203*92022041SSam Saccone if (err)
204*92022041SSam Saccone goto nla_put_failure;
205*92022041SSam Saccone } else if (!strncmp(v[0], "coloc", 5)) {
206*92022041SSam Saccone flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ;
207*92022041SSam Saccone } else if (!strncmp(v[0], "flush", 5)) {
208*92022041SSam Saccone flags |= NL80211_SCAN_FLAG_FLUSH;
209*92022041SSam Saccone } else {
210*92022041SSam Saccone /* this element is not for us, so
211*92022041SSam Saccone * return to continue parsing.
212*92022041SSam Saccone */
213*92022041SSam Saccone goto nla_put_failure;
214*92022041SSam Saccone }
215*92022041SSam Saccone c--; v++;
216*92022041SSam Saccone
217*92022041SSam Saccone break;
218*92022041SSam Saccone case ND_MATCH:
219*92022041SSam Saccone if (!strcmp(v[0], "ssid")) {
220*92022041SSam Saccone c--; v++;
221*92022041SSam Saccone if (c == 0) {
222*92022041SSam Saccone err = -EINVAL;
223*92022041SSam Saccone goto nla_put_failure;
224*92022041SSam Saccone }
225*92022041SSam Saccone
226*92022041SSam Saccone /* TODO: for now we can only have an
227*92022041SSam Saccone * SSID in the match, so we can start
228*92022041SSam Saccone * the match nest here.
229*92022041SSam Saccone */
230*92022041SSam Saccone match = nla_nest_start(matchset, i);
231*92022041SSam Saccone if (!match) {
232*92022041SSam Saccone err = -ENOBUFS;
233*92022041SSam Saccone goto nla_put_failure;
234*92022041SSam Saccone }
235*92022041SSam Saccone
236*92022041SSam Saccone NLA_PUT(matchset,
237*92022041SSam Saccone NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
238*92022041SSam Saccone strlen(v[0]), v[0]);
239*92022041SSam Saccone nla_nest_end(matchset, match);
240*92022041SSam Saccone match = NULL;
241*92022041SSam Saccone
242*92022041SSam Saccone have_matchset = true;
243*92022041SSam Saccone i++;
244*92022041SSam Saccone c--; v++;
245*92022041SSam Saccone } else {
246*92022041SSam Saccone /* other element that cannot be part
247*92022041SSam Saccone * of a match indicates the end of the
248*92022041SSam Saccone * match. */
249*92022041SSam Saccone /* need at least one match in the matchset */
250*92022041SSam Saccone if (i == 0) {
251*92022041SSam Saccone err = -EINVAL;
252*92022041SSam Saccone goto nla_put_failure;
253*92022041SSam Saccone }
254*92022041SSam Saccone
255*92022041SSam Saccone parse_state = ND_TOPLEVEL;
256*92022041SSam Saccone }
257*92022041SSam Saccone
258*92022041SSam Saccone break;
259*92022041SSam Saccone case ND_FREQS:
260*92022041SSam Saccone freq = strtoul(v[0], &end, 10);
261*92022041SSam Saccone if (*end) {
262*92022041SSam Saccone if (i == 0) {
263*92022041SSam Saccone err = -EINVAL;
264*92022041SSam Saccone goto nla_put_failure;
265*92022041SSam Saccone }
266*92022041SSam Saccone
267*92022041SSam Saccone parse_state = ND_TOPLEVEL;
268*92022041SSam Saccone } else {
269*92022041SSam Saccone NLA_PUT_U32(freqs, i, freq);
270*92022041SSam Saccone i++;
271*92022041SSam Saccone c--; v++;
272*92022041SSam Saccone }
273*92022041SSam Saccone break;
274*92022041SSam Saccone case ND_ACTIVE:
275*92022041SSam Saccone if (!strcmp(v[0], "ssid")) {
276*92022041SSam Saccone c--; v++;
277*92022041SSam Saccone if (c == 0) {
278*92022041SSam Saccone err = -EINVAL;
279*92022041SSam Saccone goto nla_put_failure;
280*92022041SSam Saccone }
281*92022041SSam Saccone
282*92022041SSam Saccone NLA_PUT(ssids,
283*92022041SSam Saccone NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
284*92022041SSam Saccone strlen(v[0]), v[0]);
285*92022041SSam Saccone
286*92022041SSam Saccone have_ssids = true;
287*92022041SSam Saccone i++;
288*92022041SSam Saccone c--; v++;
289*92022041SSam Saccone } else {
290*92022041SSam Saccone /* other element that cannot be part
291*92022041SSam Saccone * of a match indicates the end of the
292*92022041SSam Saccone * active set. */
293*92022041SSam Saccone /* need at least one item in the set */
294*92022041SSam Saccone if (i == 0) {
295*92022041SSam Saccone err = -EINVAL;
296*92022041SSam Saccone goto nla_put_failure;
297*92022041SSam Saccone }
298*92022041SSam Saccone
299*92022041SSam Saccone parse_state = ND_TOPLEVEL;
300*92022041SSam Saccone }
301*92022041SSam Saccone break;
302*92022041SSam Saccone case ND_PLANS:
303*92022041SSam Saccone iterations = 0;
304*92022041SSam Saccone interval = strtoul(v[0], &end, 10);
305*92022041SSam Saccone if (*end) {
306*92022041SSam Saccone char *iter;
307*92022041SSam Saccone
308*92022041SSam Saccone if (*end != ':') {
309*92022041SSam Saccone err = -EINVAL;
310*92022041SSam Saccone goto nla_put_failure;
311*92022041SSam Saccone }
312*92022041SSam Saccone
313*92022041SSam Saccone iter = ++end;
314*92022041SSam Saccone iterations = strtoul(iter, &end, 10);
315*92022041SSam Saccone if (*end || !iterations) {
316*92022041SSam Saccone err = -EINVAL;
317*92022041SSam Saccone goto nla_put_failure;
318*92022041SSam Saccone }
319*92022041SSam Saccone }
320*92022041SSam Saccone
321*92022041SSam Saccone plan = nla_nest_start(scan_plans, i + 1);
322*92022041SSam Saccone if (!plan) {
323*92022041SSam Saccone err = -ENOBUFS;
324*92022041SSam Saccone goto nla_put_failure;
325*92022041SSam Saccone }
326*92022041SSam Saccone
327*92022041SSam Saccone NLA_PUT_U32(scan_plans,
328*92022041SSam Saccone NL80211_SCHED_SCAN_PLAN_INTERVAL,
329*92022041SSam Saccone interval);
330*92022041SSam Saccone
331*92022041SSam Saccone if (iterations)
332*92022041SSam Saccone NLA_PUT_U32(scan_plans,
333*92022041SSam Saccone NL80211_SCHED_SCAN_PLAN_ITERATIONS,
334*92022041SSam Saccone iterations);
335*92022041SSam Saccone else
336*92022041SSam Saccone parse_state = ND_TOPLEVEL;
337*92022041SSam Saccone
338*92022041SSam Saccone nla_nest_end(scan_plans, plan);
339*92022041SSam Saccone plan = NULL;
340*92022041SSam Saccone i++;
341*92022041SSam Saccone c--; v++;
342*92022041SSam Saccone break;
343*92022041SSam Saccone }
344*92022041SSam Saccone }
345*92022041SSam Saccone
346*92022041SSam Saccone if (!have_ssids)
347*92022041SSam Saccone NLA_PUT(ssids, 1, 0, "");
348*92022041SSam Saccone if (!have_passive)
349*92022041SSam Saccone nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
350*92022041SSam Saccone if (have_freqs)
351*92022041SSam Saccone nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
352*92022041SSam Saccone if (have_matchset)
353*92022041SSam Saccone nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH, matchset);
354*92022041SSam Saccone if (have_plans)
355*92022041SSam Saccone nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_PLANS, scan_plans);
356*92022041SSam Saccone if (flags)
357*92022041SSam Saccone NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, flags);
358*92022041SSam Saccone
359*92022041SSam Saccone nla_put_failure:
360*92022041SSam Saccone if (match)
361*92022041SSam Saccone nla_nest_end(msg, match);
362*92022041SSam Saccone out:
363*92022041SSam Saccone nlmsg_free(freqs);
364*92022041SSam Saccone nlmsg_free(matchset);
365*92022041SSam Saccone nlmsg_free(scan_plans);
366*92022041SSam Saccone nlmsg_free(ssids);
367*92022041SSam Saccone
368*92022041SSam Saccone *argc = c;
369*92022041SSam Saccone *argv = v;
370*92022041SSam Saccone return err;
371*92022041SSam Saccone }
372*92022041SSam Saccone
handle_scan(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)373*92022041SSam Saccone static int handle_scan(struct nl80211_state *state,
374*92022041SSam Saccone struct nl_msg *msg,
375*92022041SSam Saccone int argc, char **argv,
376*92022041SSam Saccone enum id_input id)
377*92022041SSam Saccone {
378*92022041SSam Saccone struct nl_msg *ssids = NULL, *freqs = NULL;
379*92022041SSam Saccone char *eptr;
380*92022041SSam Saccone int err = -ENOBUFS;
381*92022041SSam Saccone int i;
382*92022041SSam Saccone enum {
383*92022041SSam Saccone NONE,
384*92022041SSam Saccone FREQ,
385*92022041SSam Saccone IES,
386*92022041SSam Saccone SSID,
387*92022041SSam Saccone MESHID,
388*92022041SSam Saccone DURATION,
389*92022041SSam Saccone DONE,
390*92022041SSam Saccone } parse = NONE;
391*92022041SSam Saccone int freq;
392*92022041SSam Saccone unsigned int duration = 0;
393*92022041SSam Saccone bool passive = false, have_ssids = false, have_freqs = false;
394*92022041SSam Saccone bool duration_mandatory = false;
395*92022041SSam Saccone size_t ies_len = 0, meshid_len = 0;
396*92022041SSam Saccone unsigned char *ies = NULL, *meshid = NULL, *tmpies = NULL;
397*92022041SSam Saccone unsigned int flags = 0;
398*92022041SSam Saccone
399*92022041SSam Saccone ssids = nlmsg_alloc();
400*92022041SSam Saccone if (!ssids)
401*92022041SSam Saccone return -ENOMEM;
402*92022041SSam Saccone
403*92022041SSam Saccone freqs = nlmsg_alloc();
404*92022041SSam Saccone if (!freqs) {
405*92022041SSam Saccone nlmsg_free(ssids);
406*92022041SSam Saccone return -ENOMEM;
407*92022041SSam Saccone }
408*92022041SSam Saccone
409*92022041SSam Saccone for (i = 0; i < argc; i++) {
410*92022041SSam Saccone switch (parse) {
411*92022041SSam Saccone case NONE:
412*92022041SSam Saccone if (strcmp(argv[i], "freq") == 0) {
413*92022041SSam Saccone parse = FREQ;
414*92022041SSam Saccone have_freqs = true;
415*92022041SSam Saccone break;
416*92022041SSam Saccone } else if (strcmp(argv[i], "ies") == 0) {
417*92022041SSam Saccone parse = IES;
418*92022041SSam Saccone break;
419*92022041SSam Saccone } else if (strcmp(argv[i], "lowpri") == 0) {
420*92022041SSam Saccone flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
421*92022041SSam Saccone break;
422*92022041SSam Saccone } else if (strcmp(argv[i], "flush") == 0) {
423*92022041SSam Saccone flags |= NL80211_SCAN_FLAG_FLUSH;
424*92022041SSam Saccone break;
425*92022041SSam Saccone } else if (strcmp(argv[i], "ap-force") == 0) {
426*92022041SSam Saccone flags |= NL80211_SCAN_FLAG_AP;
427*92022041SSam Saccone break;
428*92022041SSam Saccone } else if (strcmp(argv[i], "coloc") == 0) {
429*92022041SSam Saccone flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ;
430*92022041SSam Saccone break;
431*92022041SSam Saccone } else if (strcmp(argv[i], "duration-mandatory") == 0) {
432*92022041SSam Saccone duration_mandatory = true;
433*92022041SSam Saccone break;
434*92022041SSam Saccone } else if (strncmp(argv[i], "randomise", 9) == 0 ||
435*92022041SSam Saccone strncmp(argv[i], "randomize", 9) == 0) {
436*92022041SSam Saccone flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
437*92022041SSam Saccone err = parse_random_mac_addr(msg, argv[i] + 9);
438*92022041SSam Saccone if (err)
439*92022041SSam Saccone goto nla_put_failure;
440*92022041SSam Saccone break;
441*92022041SSam Saccone } else if (strcmp(argv[i], "ssid") == 0) {
442*92022041SSam Saccone parse = SSID;
443*92022041SSam Saccone have_ssids = true;
444*92022041SSam Saccone break;
445*92022041SSam Saccone } else if (strcmp(argv[i], "passive") == 0) {
446*92022041SSam Saccone parse = DONE;
447*92022041SSam Saccone passive = true;
448*92022041SSam Saccone break;
449*92022041SSam Saccone } else if (strcmp(argv[i], "meshid") == 0) {
450*92022041SSam Saccone parse = MESHID;
451*92022041SSam Saccone break;
452*92022041SSam Saccone } else if (strcmp(argv[i], "duration") == 0) {
453*92022041SSam Saccone parse = DURATION;
454*92022041SSam Saccone break;
455*92022041SSam Saccone }
456*92022041SSam Saccone /* fall through - this is an error */
457*92022041SSam Saccone case DONE:
458*92022041SSam Saccone err = 1;
459*92022041SSam Saccone goto nla_put_failure;
460*92022041SSam Saccone case FREQ:
461*92022041SSam Saccone freq = strtoul(argv[i], &eptr, 10);
462*92022041SSam Saccone if (eptr != argv[i] + strlen(argv[i])) {
463*92022041SSam Saccone /* failed to parse as number -- maybe a tag? */
464*92022041SSam Saccone i--;
465*92022041SSam Saccone parse = NONE;
466*92022041SSam Saccone continue;
467*92022041SSam Saccone }
468*92022041SSam Saccone NLA_PUT_U32(freqs, i, freq);
469*92022041SSam Saccone break;
470*92022041SSam Saccone case IES:
471*92022041SSam Saccone if (ies)
472*92022041SSam Saccone free(ies);
473*92022041SSam Saccone ies = parse_hex(argv[i], &ies_len);
474*92022041SSam Saccone if (!ies)
475*92022041SSam Saccone goto nla_put_failure;
476*92022041SSam Saccone parse = NONE;
477*92022041SSam Saccone break;
478*92022041SSam Saccone case SSID:
479*92022041SSam Saccone NLA_PUT(ssids, i, strlen(argv[i]), argv[i]);
480*92022041SSam Saccone break;
481*92022041SSam Saccone case MESHID:
482*92022041SSam Saccone meshid_len = strlen(argv[i]);
483*92022041SSam Saccone meshid = (unsigned char *) malloc(meshid_len + 2);
484*92022041SSam Saccone if (!meshid)
485*92022041SSam Saccone goto nla_put_failure;
486*92022041SSam Saccone meshid[0] = 114; /* mesh element id */
487*92022041SSam Saccone meshid[1] = meshid_len;
488*92022041SSam Saccone memcpy(&meshid[2], argv[i], meshid_len);
489*92022041SSam Saccone meshid_len += 2;
490*92022041SSam Saccone parse = NONE;
491*92022041SSam Saccone break;
492*92022041SSam Saccone case DURATION:
493*92022041SSam Saccone duration = strtoul(argv[i], &eptr, 10);
494*92022041SSam Saccone parse = NONE;
495*92022041SSam Saccone break;
496*92022041SSam Saccone }
497*92022041SSam Saccone }
498*92022041SSam Saccone
499*92022041SSam Saccone if (ies || meshid) {
500*92022041SSam Saccone tmpies = (unsigned char *) malloc(ies_len + meshid_len);
501*92022041SSam Saccone if (!tmpies)
502*92022041SSam Saccone goto nla_put_failure;
503*92022041SSam Saccone if (ies)
504*92022041SSam Saccone memcpy(tmpies, ies, ies_len);
505*92022041SSam Saccone if (meshid)
506*92022041SSam Saccone memcpy(&tmpies[ies_len], meshid, meshid_len);
507*92022041SSam Saccone if (nla_put(msg, NL80211_ATTR_IE, ies_len + meshid_len, tmpies) < 0)
508*92022041SSam Saccone goto nla_put_failure;
509*92022041SSam Saccone }
510*92022041SSam Saccone
511*92022041SSam Saccone if (!have_ssids)
512*92022041SSam Saccone NLA_PUT(ssids, 1, 0, "");
513*92022041SSam Saccone if (!passive)
514*92022041SSam Saccone nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
515*92022041SSam Saccone
516*92022041SSam Saccone if (have_freqs)
517*92022041SSam Saccone nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
518*92022041SSam Saccone else
519*92022041SSam Saccone flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ;
520*92022041SSam Saccone if (flags)
521*92022041SSam Saccone NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, flags);
522*92022041SSam Saccone if (duration)
523*92022041SSam Saccone NLA_PUT_U16(msg, NL80211_ATTR_MEASUREMENT_DURATION, duration);
524*92022041SSam Saccone if (duration_mandatory) {
525*92022041SSam Saccone if (duration) {
526*92022041SSam Saccone NLA_PUT_FLAG(msg,
527*92022041SSam Saccone NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY);
528*92022041SSam Saccone } else {
529*92022041SSam Saccone err = -EINVAL;
530*92022041SSam Saccone goto nla_put_failure;
531*92022041SSam Saccone }
532*92022041SSam Saccone }
533*92022041SSam Saccone
534*92022041SSam Saccone err = 0;
535*92022041SSam Saccone nla_put_failure:
536*92022041SSam Saccone nlmsg_free(ssids);
537*92022041SSam Saccone nlmsg_free(freqs);
538*92022041SSam Saccone if (meshid)
539*92022041SSam Saccone free(meshid);
540*92022041SSam Saccone if (ies)
541*92022041SSam Saccone free(ies);
542*92022041SSam Saccone if (tmpies)
543*92022041SSam Saccone free(tmpies);
544*92022041SSam Saccone return err;
545*92022041SSam Saccone }
546*92022041SSam Saccone
tab_on_first(bool * first)547*92022041SSam Saccone static void tab_on_first(bool *first)
548*92022041SSam Saccone {
549*92022041SSam Saccone if (!*first)
550*92022041SSam Saccone printf("\t");
551*92022041SSam Saccone else
552*92022041SSam Saccone *first = false;
553*92022041SSam Saccone }
554*92022041SSam Saccone
555*92022041SSam Saccone struct print_ies_data {
556*92022041SSam Saccone unsigned char *ie;
557*92022041SSam Saccone int ielen;
558*92022041SSam Saccone };
559*92022041SSam Saccone
print_ssid(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)560*92022041SSam Saccone static void print_ssid(const uint8_t type, uint8_t len, const uint8_t *data,
561*92022041SSam Saccone const struct print_ies_data *ie_buffer)
562*92022041SSam Saccone {
563*92022041SSam Saccone printf(" ");
564*92022041SSam Saccone print_ssid_escaped(len, data);
565*92022041SSam Saccone printf("\n");
566*92022041SSam Saccone }
567*92022041SSam Saccone
568*92022041SSam Saccone #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
569*92022041SSam Saccone #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
570*92022041SSam Saccone
print_supprates(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)571*92022041SSam Saccone static void print_supprates(const uint8_t type, uint8_t len,
572*92022041SSam Saccone const uint8_t *data,
573*92022041SSam Saccone const struct print_ies_data *ie_buffer)
574*92022041SSam Saccone {
575*92022041SSam Saccone int i;
576*92022041SSam Saccone
577*92022041SSam Saccone printf(" ");
578*92022041SSam Saccone
579*92022041SSam Saccone for (i = 0; i < len; i++) {
580*92022041SSam Saccone int r = data[i] & 0x7f;
581*92022041SSam Saccone
582*92022041SSam Saccone if (r == BSS_MEMBERSHIP_SELECTOR_VHT_PHY && data[i] & 0x80)
583*92022041SSam Saccone printf("VHT");
584*92022041SSam Saccone else if (r == BSS_MEMBERSHIP_SELECTOR_HT_PHY && data[i] & 0x80)
585*92022041SSam Saccone printf("HT");
586*92022041SSam Saccone else
587*92022041SSam Saccone printf("%d.%d", r/2, 5*(r&1));
588*92022041SSam Saccone
589*92022041SSam Saccone printf("%s ", data[i] & 0x80 ? "*" : "");
590*92022041SSam Saccone }
591*92022041SSam Saccone printf("\n");
592*92022041SSam Saccone }
593*92022041SSam Saccone
print_rm_enabled_capabilities(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)594*92022041SSam Saccone static void print_rm_enabled_capabilities(const uint8_t type, uint8_t len,
595*92022041SSam Saccone const uint8_t *data,
596*92022041SSam Saccone const struct print_ies_data *ie_buffer)
597*92022041SSam Saccone {
598*92022041SSam Saccone __u64 capa = ((__u64) data[0]) |
599*92022041SSam Saccone ((__u64) data[1]) << 8 |
600*92022041SSam Saccone ((__u64) data[2]) << 16 |
601*92022041SSam Saccone ((__u64) data[3]) << 24 |
602*92022041SSam Saccone ((__u64) data[4]) << 32;
603*92022041SSam Saccone
604*92022041SSam Saccone printf("\n");
605*92022041SSam Saccone printf("\t\tCapabilities: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
606*92022041SSam Saccone data[0], data[1],
607*92022041SSam Saccone data[2], data[3],
608*92022041SSam Saccone data[4]);
609*92022041SSam Saccone
610*92022041SSam Saccone #define PRINT_RM_CAPA(_bit, _str) \
611*92022041SSam Saccone do { \
612*92022041SSam Saccone if (capa & BIT(_bit)) \
613*92022041SSam Saccone printf("\t\t\t" _str "\n"); \
614*92022041SSam Saccone } while (0)
615*92022041SSam Saccone
616*92022041SSam Saccone PRINT_RM_CAPA(0, "Link Measurement");
617*92022041SSam Saccone PRINT_RM_CAPA(1, "Neighbor Report");
618*92022041SSam Saccone PRINT_RM_CAPA(2, "Parallel Measurements");
619*92022041SSam Saccone PRINT_RM_CAPA(3, "Repeated Measurements");
620*92022041SSam Saccone PRINT_RM_CAPA(4, "Beacon Passive Measurement");
621*92022041SSam Saccone PRINT_RM_CAPA(5, "Beacon Active Measurement");
622*92022041SSam Saccone PRINT_RM_CAPA(6, "Beacon Table Measurement");
623*92022041SSam Saccone PRINT_RM_CAPA(7, "Beacon Measurement Reporting Conditions");
624*92022041SSam Saccone PRINT_RM_CAPA(8, "Frame Measurement");
625*92022041SSam Saccone PRINT_RM_CAPA(9, "Channel Load");
626*92022041SSam Saccone PRINT_RM_CAPA(10, "Noise Histogram Measurement");
627*92022041SSam Saccone PRINT_RM_CAPA(11, "Statistics Measurement");
628*92022041SSam Saccone PRINT_RM_CAPA(12, "LCI Measurement");
629*92022041SSam Saccone PRINT_RM_CAPA(13, "LCI Azimuth");
630*92022041SSam Saccone PRINT_RM_CAPA(14, "Transmit Stream/Category Measurement");
631*92022041SSam Saccone PRINT_RM_CAPA(15, "Triggered Transmit Stream/Category");
632*92022041SSam Saccone PRINT_RM_CAPA(16, "AP Channel Report");
633*92022041SSam Saccone PRINT_RM_CAPA(17, "RM MIB Capability");
634*92022041SSam Saccone
635*92022041SSam Saccone PRINT_RM_CAPA(27, "Measurement Pilot Transmission Information");
636*92022041SSam Saccone PRINT_RM_CAPA(28, "Neighbor Report TSF Offset");
637*92022041SSam Saccone PRINT_RM_CAPA(29, "RCPI Measurement");
638*92022041SSam Saccone PRINT_RM_CAPA(30, "RSNI Measurement");
639*92022041SSam Saccone PRINT_RM_CAPA(31, "BSS Average Access Delay");
640*92022041SSam Saccone PRINT_RM_CAPA(32, "BSS Available Admission");
641*92022041SSam Saccone PRINT_RM_CAPA(33, "Antenna");
642*92022041SSam Saccone PRINT_RM_CAPA(34, "FTM Range Report");
643*92022041SSam Saccone PRINT_RM_CAPA(35, "Civic Location Measurement");
644*92022041SSam Saccone
645*92022041SSam Saccone printf("\t\tNonoperating Channel Max Measurement Duration: %i\n", data[3] >> 5);
646*92022041SSam Saccone printf("\t\tMeasurement Pilot Capability: %i\n", data[4] & 7);
647*92022041SSam Saccone }
648*92022041SSam Saccone
print_ds(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)649*92022041SSam Saccone static void print_ds(const uint8_t type, uint8_t len, const uint8_t *data,
650*92022041SSam Saccone const struct print_ies_data *ie_buffer)
651*92022041SSam Saccone {
652*92022041SSam Saccone printf(" channel %d\n", data[0]);
653*92022041SSam Saccone }
654*92022041SSam Saccone
country_env_str(char environment)655*92022041SSam Saccone static const char *country_env_str(char environment)
656*92022041SSam Saccone {
657*92022041SSam Saccone switch (environment) {
658*92022041SSam Saccone case 'I':
659*92022041SSam Saccone return "Indoor only";
660*92022041SSam Saccone case 'O':
661*92022041SSam Saccone return "Outdoor only";
662*92022041SSam Saccone case ' ':
663*92022041SSam Saccone return "Indoor/Outdoor";
664*92022041SSam Saccone default:
665*92022041SSam Saccone return "bogus";
666*92022041SSam Saccone }
667*92022041SSam Saccone }
668*92022041SSam Saccone
print_country(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)669*92022041SSam Saccone static void print_country(const uint8_t type, uint8_t len, const uint8_t *data,
670*92022041SSam Saccone const struct print_ies_data *ie_buffer)
671*92022041SSam Saccone {
672*92022041SSam Saccone printf(" %.*s", 2, data);
673*92022041SSam Saccone
674*92022041SSam Saccone printf("\tEnvironment: %s\n", country_env_str(data[2]));
675*92022041SSam Saccone
676*92022041SSam Saccone data += 3;
677*92022041SSam Saccone len -= 3;
678*92022041SSam Saccone
679*92022041SSam Saccone if (len < 3) {
680*92022041SSam Saccone printf("\t\tNo country IE triplets present\n");
681*92022041SSam Saccone return;
682*92022041SSam Saccone }
683*92022041SSam Saccone
684*92022041SSam Saccone while (len >= 3) {
685*92022041SSam Saccone int end_channel;
686*92022041SSam Saccone union ieee80211_country_ie_triplet *triplet = (void *) data;
687*92022041SSam Saccone
688*92022041SSam Saccone if (triplet->ext.reg_extension_id >= IEEE80211_COUNTRY_EXTENSION_ID) {
689*92022041SSam Saccone printf("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
690*92022041SSam Saccone triplet->ext.reg_extension_id,
691*92022041SSam Saccone triplet->ext.reg_class,
692*92022041SSam Saccone triplet->ext.coverage_class,
693*92022041SSam Saccone triplet->ext.coverage_class * 450);
694*92022041SSam Saccone
695*92022041SSam Saccone data += 3;
696*92022041SSam Saccone len -= 3;
697*92022041SSam Saccone continue;
698*92022041SSam Saccone }
699*92022041SSam Saccone
700*92022041SSam Saccone /* 2 GHz */
701*92022041SSam Saccone if (triplet->chans.first_channel <= 14)
702*92022041SSam Saccone end_channel = triplet->chans.first_channel + (triplet->chans.num_channels - 1);
703*92022041SSam Saccone else
704*92022041SSam Saccone end_channel = triplet->chans.first_channel + (4 * (triplet->chans.num_channels - 1));
705*92022041SSam Saccone
706*92022041SSam Saccone printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet->chans.first_channel, end_channel, triplet->chans.max_power);
707*92022041SSam Saccone
708*92022041SSam Saccone data += 3;
709*92022041SSam Saccone len -= 3;
710*92022041SSam Saccone }
711*92022041SSam Saccone
712*92022041SSam Saccone return;
713*92022041SSam Saccone }
714*92022041SSam Saccone
print_powerconstraint(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)715*92022041SSam Saccone static void print_powerconstraint(const uint8_t type, uint8_t len,
716*92022041SSam Saccone const uint8_t *data,
717*92022041SSam Saccone const struct print_ies_data *ie_buffer)
718*92022041SSam Saccone {
719*92022041SSam Saccone printf(" %d dB\n", data[0]);
720*92022041SSam Saccone }
721*92022041SSam Saccone
print_tpcreport(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)722*92022041SSam Saccone static void print_tpcreport(const uint8_t type, uint8_t len,
723*92022041SSam Saccone const uint8_t *data,
724*92022041SSam Saccone const struct print_ies_data *ie_buffer)
725*92022041SSam Saccone {
726*92022041SSam Saccone printf(" TX power: %d dBm\n", data[0]);
727*92022041SSam Saccone /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
728*92022041SSam Saccone }
729*92022041SSam Saccone
print_erp(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)730*92022041SSam Saccone static void print_erp(const uint8_t type, uint8_t len, const uint8_t *data,
731*92022041SSam Saccone const struct print_ies_data *ie_buffer)
732*92022041SSam Saccone {
733*92022041SSam Saccone if (data[0] == 0x00)
734*92022041SSam Saccone printf(" <no flags>");
735*92022041SSam Saccone if (data[0] & 0x01)
736*92022041SSam Saccone printf(" NonERP_Present");
737*92022041SSam Saccone if (data[0] & 0x02)
738*92022041SSam Saccone printf(" Use_Protection");
739*92022041SSam Saccone if (data[0] & 0x04)
740*92022041SSam Saccone printf(" Barker_Preamble_Mode");
741*92022041SSam Saccone printf("\n");
742*92022041SSam Saccone }
743*92022041SSam Saccone
print_ap_channel_report(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)744*92022041SSam Saccone static void print_ap_channel_report(const uint8_t type, uint8_t len, const uint8_t *data,
745*92022041SSam Saccone const struct print_ies_data *ie_buffer)
746*92022041SSam Saccone {
747*92022041SSam Saccone uint8_t oper_class = data[0];
748*92022041SSam Saccone int i;
749*92022041SSam Saccone
750*92022041SSam Saccone printf("\n");
751*92022041SSam Saccone printf("\t\t * operating class: %d\n", oper_class);
752*92022041SSam Saccone printf("\t\t * channel(s):");
753*92022041SSam Saccone for (i = 1; i < len; ++i) {
754*92022041SSam Saccone printf(" %d", data[i]);
755*92022041SSam Saccone }
756*92022041SSam Saccone printf("\n");
757*92022041SSam Saccone }
758*92022041SSam Saccone
print_cipher(const uint8_t * data)759*92022041SSam Saccone static void print_cipher(const uint8_t *data)
760*92022041SSam Saccone {
761*92022041SSam Saccone if (memcmp(data, ms_oui, 3) == 0) {
762*92022041SSam Saccone switch (data[3]) {
763*92022041SSam Saccone case 0:
764*92022041SSam Saccone printf("Use group cipher suite");
765*92022041SSam Saccone break;
766*92022041SSam Saccone case 1:
767*92022041SSam Saccone printf("WEP-40");
768*92022041SSam Saccone break;
769*92022041SSam Saccone case 2:
770*92022041SSam Saccone printf("TKIP");
771*92022041SSam Saccone break;
772*92022041SSam Saccone case 4:
773*92022041SSam Saccone printf("CCMP");
774*92022041SSam Saccone break;
775*92022041SSam Saccone case 5:
776*92022041SSam Saccone printf("WEP-104");
777*92022041SSam Saccone break;
778*92022041SSam Saccone default:
779*92022041SSam Saccone printf("%.02x-%.02x-%.02x:%d",
780*92022041SSam Saccone data[0], data[1] ,data[2], data[3]);
781*92022041SSam Saccone break;
782*92022041SSam Saccone }
783*92022041SSam Saccone } else if (memcmp(data, ieee80211_oui, 3) == 0) {
784*92022041SSam Saccone switch (data[3]) {
785*92022041SSam Saccone case 0:
786*92022041SSam Saccone printf("Use group cipher suite");
787*92022041SSam Saccone break;
788*92022041SSam Saccone case 1:
789*92022041SSam Saccone printf("WEP-40");
790*92022041SSam Saccone break;
791*92022041SSam Saccone case 2:
792*92022041SSam Saccone printf("TKIP");
793*92022041SSam Saccone break;
794*92022041SSam Saccone case 4:
795*92022041SSam Saccone printf("CCMP");
796*92022041SSam Saccone break;
797*92022041SSam Saccone case 5:
798*92022041SSam Saccone printf("WEP-104");
799*92022041SSam Saccone break;
800*92022041SSam Saccone case 6:
801*92022041SSam Saccone printf("AES-128-CMAC");
802*92022041SSam Saccone break;
803*92022041SSam Saccone case 7:
804*92022041SSam Saccone printf("NO-GROUP");
805*92022041SSam Saccone break;
806*92022041SSam Saccone case 8:
807*92022041SSam Saccone printf("GCMP");
808*92022041SSam Saccone break;
809*92022041SSam Saccone default:
810*92022041SSam Saccone printf("%.02x-%.02x-%.02x:%d",
811*92022041SSam Saccone data[0], data[1] ,data[2], data[3]);
812*92022041SSam Saccone break;
813*92022041SSam Saccone }
814*92022041SSam Saccone } else
815*92022041SSam Saccone printf("%.02x-%.02x-%.02x:%d",
816*92022041SSam Saccone data[0], data[1] ,data[2], data[3]);
817*92022041SSam Saccone }
818*92022041SSam Saccone
print_auth(const uint8_t * data)819*92022041SSam Saccone static void print_auth(const uint8_t *data)
820*92022041SSam Saccone {
821*92022041SSam Saccone if (memcmp(data, ms_oui, 3) == 0) {
822*92022041SSam Saccone switch (data[3]) {
823*92022041SSam Saccone case 1:
824*92022041SSam Saccone printf("IEEE 802.1X");
825*92022041SSam Saccone break;
826*92022041SSam Saccone case 2:
827*92022041SSam Saccone printf("PSK");
828*92022041SSam Saccone break;
829*92022041SSam Saccone default:
830*92022041SSam Saccone printf("%.02x-%.02x-%.02x:%d",
831*92022041SSam Saccone data[0], data[1] ,data[2], data[3]);
832*92022041SSam Saccone break;
833*92022041SSam Saccone }
834*92022041SSam Saccone } else if (memcmp(data, ieee80211_oui, 3) == 0) {
835*92022041SSam Saccone switch (data[3]) {
836*92022041SSam Saccone case 1:
837*92022041SSam Saccone printf("IEEE 802.1X");
838*92022041SSam Saccone break;
839*92022041SSam Saccone case 2:
840*92022041SSam Saccone printf("PSK");
841*92022041SSam Saccone break;
842*92022041SSam Saccone case 3:
843*92022041SSam Saccone printf("FT/IEEE 802.1X");
844*92022041SSam Saccone break;
845*92022041SSam Saccone case 4:
846*92022041SSam Saccone printf("FT/PSK");
847*92022041SSam Saccone break;
848*92022041SSam Saccone case 5:
849*92022041SSam Saccone printf("IEEE 802.1X/SHA-256");
850*92022041SSam Saccone break;
851*92022041SSam Saccone case 6:
852*92022041SSam Saccone printf("PSK/SHA-256");
853*92022041SSam Saccone break;
854*92022041SSam Saccone case 7:
855*92022041SSam Saccone printf("TDLS/TPK");
856*92022041SSam Saccone break;
857*92022041SSam Saccone case 8:
858*92022041SSam Saccone printf("SAE");
859*92022041SSam Saccone break;
860*92022041SSam Saccone case 9:
861*92022041SSam Saccone printf("FT/SAE");
862*92022041SSam Saccone break;
863*92022041SSam Saccone case 11:
864*92022041SSam Saccone printf("IEEE 802.1X/SUITE-B");
865*92022041SSam Saccone break;
866*92022041SSam Saccone case 12:
867*92022041SSam Saccone printf("IEEE 802.1X/SUITE-B-192");
868*92022041SSam Saccone break;
869*92022041SSam Saccone case 13:
870*92022041SSam Saccone printf("FT/IEEE 802.1X/SHA-384");
871*92022041SSam Saccone break;
872*92022041SSam Saccone case 14:
873*92022041SSam Saccone printf("FILS/SHA-256");
874*92022041SSam Saccone break;
875*92022041SSam Saccone case 15:
876*92022041SSam Saccone printf("FILS/SHA-384");
877*92022041SSam Saccone break;
878*92022041SSam Saccone case 16:
879*92022041SSam Saccone printf("FT/FILS/SHA-256");
880*92022041SSam Saccone break;
881*92022041SSam Saccone case 17:
882*92022041SSam Saccone printf("FT/FILS/SHA-384");
883*92022041SSam Saccone break;
884*92022041SSam Saccone case 18:
885*92022041SSam Saccone printf("OWE");
886*92022041SSam Saccone break;
887*92022041SSam Saccone default:
888*92022041SSam Saccone printf("%.02x-%.02x-%.02x:%d",
889*92022041SSam Saccone data[0], data[1] ,data[2], data[3]);
890*92022041SSam Saccone break;
891*92022041SSam Saccone }
892*92022041SSam Saccone } else if (memcmp(data, wfa_oui, 3) == 0) {
893*92022041SSam Saccone switch (data[3]) {
894*92022041SSam Saccone case 1:
895*92022041SSam Saccone printf("OSEN");
896*92022041SSam Saccone break;
897*92022041SSam Saccone case 2:
898*92022041SSam Saccone printf("DPP");
899*92022041SSam Saccone break;
900*92022041SSam Saccone default:
901*92022041SSam Saccone printf("%.02x-%.02x-%.02x:%d",
902*92022041SSam Saccone data[0], data[1] ,data[2], data[3]);
903*92022041SSam Saccone break;
904*92022041SSam Saccone }
905*92022041SSam Saccone } else
906*92022041SSam Saccone printf("%.02x-%.02x-%.02x:%d",
907*92022041SSam Saccone data[0], data[1] ,data[2], data[3]);
908*92022041SSam Saccone }
909*92022041SSam Saccone
_print_rsn_ie(const char * defcipher,const char * defauth,uint8_t len,const uint8_t * data,int is_osen)910*92022041SSam Saccone static void _print_rsn_ie(const char *defcipher, const char *defauth,
911*92022041SSam Saccone uint8_t len, const uint8_t *data, int is_osen)
912*92022041SSam Saccone {
913*92022041SSam Saccone bool first = true;
914*92022041SSam Saccone __u16 count, capa;
915*92022041SSam Saccone int i;
916*92022041SSam Saccone
917*92022041SSam Saccone if (!is_osen) {
918*92022041SSam Saccone __u16 version;
919*92022041SSam Saccone version = data[0] + (data[1] << 8);
920*92022041SSam Saccone tab_on_first(&first);
921*92022041SSam Saccone printf("\t * Version: %d\n", version);
922*92022041SSam Saccone
923*92022041SSam Saccone data += 2;
924*92022041SSam Saccone len -= 2;
925*92022041SSam Saccone }
926*92022041SSam Saccone
927*92022041SSam Saccone if (len < 4) {
928*92022041SSam Saccone tab_on_first(&first);
929*92022041SSam Saccone printf("\t * Group cipher: %s\n", defcipher);
930*92022041SSam Saccone printf("\t * Pairwise ciphers: %s\n", defcipher);
931*92022041SSam Saccone return;
932*92022041SSam Saccone }
933*92022041SSam Saccone
934*92022041SSam Saccone tab_on_first(&first);
935*92022041SSam Saccone printf("\t * Group cipher: ");
936*92022041SSam Saccone print_cipher(data);
937*92022041SSam Saccone printf("\n");
938*92022041SSam Saccone
939*92022041SSam Saccone data += 4;
940*92022041SSam Saccone len -= 4;
941*92022041SSam Saccone
942*92022041SSam Saccone if (len < 2) {
943*92022041SSam Saccone tab_on_first(&first);
944*92022041SSam Saccone printf("\t * Pairwise ciphers: %s\n", defcipher);
945*92022041SSam Saccone return;
946*92022041SSam Saccone }
947*92022041SSam Saccone
948*92022041SSam Saccone count = data[0] | (data[1] << 8);
949*92022041SSam Saccone if (2 + (count * 4) > len)
950*92022041SSam Saccone goto invalid;
951*92022041SSam Saccone
952*92022041SSam Saccone tab_on_first(&first);
953*92022041SSam Saccone printf("\t * Pairwise ciphers:");
954*92022041SSam Saccone for (i = 0; i < count; i++) {
955*92022041SSam Saccone printf(" ");
956*92022041SSam Saccone print_cipher(data + 2 + (i * 4));
957*92022041SSam Saccone }
958*92022041SSam Saccone printf("\n");
959*92022041SSam Saccone
960*92022041SSam Saccone data += 2 + (count * 4);
961*92022041SSam Saccone len -= 2 + (count * 4);
962*92022041SSam Saccone
963*92022041SSam Saccone if (len < 2) {
964*92022041SSam Saccone tab_on_first(&first);
965*92022041SSam Saccone printf("\t * Authentication suites: %s\n", defauth);
966*92022041SSam Saccone return;
967*92022041SSam Saccone }
968*92022041SSam Saccone
969*92022041SSam Saccone count = data[0] | (data[1] << 8);
970*92022041SSam Saccone if (2 + (count * 4) > len)
971*92022041SSam Saccone goto invalid;
972*92022041SSam Saccone
973*92022041SSam Saccone tab_on_first(&first);
974*92022041SSam Saccone printf("\t * Authentication suites:");
975*92022041SSam Saccone for (i = 0; i < count; i++) {
976*92022041SSam Saccone printf(" ");
977*92022041SSam Saccone print_auth(data + 2 + (i * 4));
978*92022041SSam Saccone }
979*92022041SSam Saccone printf("\n");
980*92022041SSam Saccone
981*92022041SSam Saccone data += 2 + (count * 4);
982*92022041SSam Saccone len -= 2 + (count * 4);
983*92022041SSam Saccone
984*92022041SSam Saccone if (len >= 2) {
985*92022041SSam Saccone capa = data[0] | (data[1] << 8);
986*92022041SSam Saccone tab_on_first(&first);
987*92022041SSam Saccone printf("\t * Capabilities:");
988*92022041SSam Saccone if (capa & 0x0001)
989*92022041SSam Saccone printf(" PreAuth");
990*92022041SSam Saccone if (capa & 0x0002)
991*92022041SSam Saccone printf(" NoPairwise");
992*92022041SSam Saccone switch ((capa & 0x000c) >> 2) {
993*92022041SSam Saccone case 0:
994*92022041SSam Saccone printf(" 1-PTKSA-RC");
995*92022041SSam Saccone break;
996*92022041SSam Saccone case 1:
997*92022041SSam Saccone printf(" 2-PTKSA-RC");
998*92022041SSam Saccone break;
999*92022041SSam Saccone case 2:
1000*92022041SSam Saccone printf(" 4-PTKSA-RC");
1001*92022041SSam Saccone break;
1002*92022041SSam Saccone case 3:
1003*92022041SSam Saccone printf(" 16-PTKSA-RC");
1004*92022041SSam Saccone break;
1005*92022041SSam Saccone }
1006*92022041SSam Saccone switch ((capa & 0x0030) >> 4) {
1007*92022041SSam Saccone case 0:
1008*92022041SSam Saccone printf(" 1-GTKSA-RC");
1009*92022041SSam Saccone break;
1010*92022041SSam Saccone case 1:
1011*92022041SSam Saccone printf(" 2-GTKSA-RC");
1012*92022041SSam Saccone break;
1013*92022041SSam Saccone case 2:
1014*92022041SSam Saccone printf(" 4-GTKSA-RC");
1015*92022041SSam Saccone break;
1016*92022041SSam Saccone case 3:
1017*92022041SSam Saccone printf(" 16-GTKSA-RC");
1018*92022041SSam Saccone break;
1019*92022041SSam Saccone }
1020*92022041SSam Saccone if (capa & 0x0040)
1021*92022041SSam Saccone printf(" MFP-required");
1022*92022041SSam Saccone if (capa & 0x0080)
1023*92022041SSam Saccone printf(" MFP-capable");
1024*92022041SSam Saccone if (capa & 0x0200)
1025*92022041SSam Saccone printf(" Peerkey-enabled");
1026*92022041SSam Saccone if (capa & 0x0400)
1027*92022041SSam Saccone printf(" SPP-AMSDU-capable");
1028*92022041SSam Saccone if (capa & 0x0800)
1029*92022041SSam Saccone printf(" SPP-AMSDU-required");
1030*92022041SSam Saccone if (capa & 0x2000)
1031*92022041SSam Saccone printf(" Extended-Key-ID");
1032*92022041SSam Saccone printf(" (0x%.4x)\n", capa);
1033*92022041SSam Saccone data += 2;
1034*92022041SSam Saccone len -= 2;
1035*92022041SSam Saccone }
1036*92022041SSam Saccone
1037*92022041SSam Saccone if (len >= 2) {
1038*92022041SSam Saccone int pmkid_count = data[0] | (data[1] << 8);
1039*92022041SSam Saccone
1040*92022041SSam Saccone if (len >= 2 + 16 * pmkid_count) {
1041*92022041SSam Saccone tab_on_first(&first);
1042*92022041SSam Saccone printf("\t * %d PMKIDs\n", pmkid_count);
1043*92022041SSam Saccone /* not printing PMKID values */
1044*92022041SSam Saccone data += 2 + 16 * pmkid_count;
1045*92022041SSam Saccone len -= 2 + 16 * pmkid_count;
1046*92022041SSam Saccone } else
1047*92022041SSam Saccone goto invalid;
1048*92022041SSam Saccone }
1049*92022041SSam Saccone
1050*92022041SSam Saccone if (len >= 4) {
1051*92022041SSam Saccone tab_on_first(&first);
1052*92022041SSam Saccone printf("\t * Group mgmt cipher suite: ");
1053*92022041SSam Saccone print_cipher(data);
1054*92022041SSam Saccone printf("\n");
1055*92022041SSam Saccone data += 4;
1056*92022041SSam Saccone len -= 4;
1057*92022041SSam Saccone }
1058*92022041SSam Saccone
1059*92022041SSam Saccone invalid:
1060*92022041SSam Saccone if (len != 0) {
1061*92022041SSam Saccone printf("\t\t * bogus tail data (%d):", len);
1062*92022041SSam Saccone while (len) {
1063*92022041SSam Saccone printf(" %.2x", *data);
1064*92022041SSam Saccone data++;
1065*92022041SSam Saccone len--;
1066*92022041SSam Saccone }
1067*92022041SSam Saccone printf("\n");
1068*92022041SSam Saccone }
1069*92022041SSam Saccone }
1070*92022041SSam Saccone
print_rsn_ie(const char * defcipher,const char * defauth,uint8_t len,const uint8_t * data)1071*92022041SSam Saccone static void print_rsn_ie(const char *defcipher, const char *defauth,
1072*92022041SSam Saccone uint8_t len, const uint8_t *data)
1073*92022041SSam Saccone {
1074*92022041SSam Saccone _print_rsn_ie(defcipher, defauth, len, data, 0);
1075*92022041SSam Saccone }
1076*92022041SSam Saccone
print_osen_ie(const char * defcipher,const char * defauth,uint8_t len,const uint8_t * data)1077*92022041SSam Saccone static void print_osen_ie(const char *defcipher, const char *defauth,
1078*92022041SSam Saccone uint8_t len, const uint8_t *data)
1079*92022041SSam Saccone {
1080*92022041SSam Saccone printf("\n\t");
1081*92022041SSam Saccone _print_rsn_ie(defcipher, defauth, len, data, 1);
1082*92022041SSam Saccone }
1083*92022041SSam Saccone
print_rsn(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1084*92022041SSam Saccone static void print_rsn(const uint8_t type, uint8_t len, const uint8_t *data,
1085*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1086*92022041SSam Saccone {
1087*92022041SSam Saccone print_rsn_ie("CCMP", "IEEE 802.1X", len, data);
1088*92022041SSam Saccone }
1089*92022041SSam Saccone
print_ht_capa(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1090*92022041SSam Saccone static void print_ht_capa(const uint8_t type, uint8_t len, const uint8_t *data,
1091*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1092*92022041SSam Saccone {
1093*92022041SSam Saccone printf("\n");
1094*92022041SSam Saccone print_ht_capability(data[0] | (data[1] << 8));
1095*92022041SSam Saccone print_ampdu_length(data[2] & 3);
1096*92022041SSam Saccone print_ampdu_spacing((data[2] >> 2) & 7);
1097*92022041SSam Saccone print_ht_mcs(data + 3);
1098*92022041SSam Saccone }
1099*92022041SSam Saccone
ntype_11u(uint8_t t)1100*92022041SSam Saccone static const char* ntype_11u(uint8_t t)
1101*92022041SSam Saccone {
1102*92022041SSam Saccone switch (t) {
1103*92022041SSam Saccone case 0: return "Private";
1104*92022041SSam Saccone case 1: return "Private with Guest";
1105*92022041SSam Saccone case 2: return "Chargeable Public";
1106*92022041SSam Saccone case 3: return "Free Public";
1107*92022041SSam Saccone case 4: return "Personal Device";
1108*92022041SSam Saccone case 5: return "Emergency Services Only";
1109*92022041SSam Saccone case 14: return "Test or Experimental";
1110*92022041SSam Saccone case 15: return "Wildcard";
1111*92022041SSam Saccone default: return "Reserved";
1112*92022041SSam Saccone }
1113*92022041SSam Saccone }
1114*92022041SSam Saccone
vgroup_11u(uint8_t t)1115*92022041SSam Saccone static const char* vgroup_11u(uint8_t t)
1116*92022041SSam Saccone {
1117*92022041SSam Saccone switch (t) {
1118*92022041SSam Saccone case 0: return "Unspecified";
1119*92022041SSam Saccone case 1: return "Assembly";
1120*92022041SSam Saccone case 2: return "Business";
1121*92022041SSam Saccone case 3: return "Educational";
1122*92022041SSam Saccone case 4: return "Factory and Industrial";
1123*92022041SSam Saccone case 5: return "Institutional";
1124*92022041SSam Saccone case 6: return "Mercantile";
1125*92022041SSam Saccone case 7: return "Residential";
1126*92022041SSam Saccone case 8: return "Storage";
1127*92022041SSam Saccone case 9: return "Utility and Miscellaneous";
1128*92022041SSam Saccone case 10: return "Vehicular";
1129*92022041SSam Saccone case 11: return "Outdoor";
1130*92022041SSam Saccone default: return "Reserved";
1131*92022041SSam Saccone }
1132*92022041SSam Saccone }
1133*92022041SSam Saccone
print_interworking(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1134*92022041SSam Saccone static void print_interworking(const uint8_t type, uint8_t len,
1135*92022041SSam Saccone const uint8_t *data,
1136*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1137*92022041SSam Saccone {
1138*92022041SSam Saccone /* See Section 7.3.2.92 in the 802.11u spec. */
1139*92022041SSam Saccone printf("\n");
1140*92022041SSam Saccone if (len >= 1) {
1141*92022041SSam Saccone uint8_t ano = data[0];
1142*92022041SSam Saccone printf("\t\tNetwork Options: 0x%hx\n", (unsigned short)(ano));
1143*92022041SSam Saccone printf("\t\t\tNetwork Type: %i (%s)\n",
1144*92022041SSam Saccone (int)(ano & 0xf), ntype_11u(ano & 0xf));
1145*92022041SSam Saccone if (ano & (1<<4))
1146*92022041SSam Saccone printf("\t\t\tInternet\n");
1147*92022041SSam Saccone if (ano & (1<<5))
1148*92022041SSam Saccone printf("\t\t\tASRA\n");
1149*92022041SSam Saccone if (ano & (1<<6))
1150*92022041SSam Saccone printf("\t\t\tESR\n");
1151*92022041SSam Saccone if (ano & (1<<7))
1152*92022041SSam Saccone printf("\t\t\tUESA\n");
1153*92022041SSam Saccone }
1154*92022041SSam Saccone if ((len == 3) || (len == 9)) {
1155*92022041SSam Saccone printf("\t\tVenue Group: %i (%s)\n",
1156*92022041SSam Saccone (int)(data[1]), vgroup_11u(data[1]));
1157*92022041SSam Saccone printf("\t\tVenue Type: %i\n", (int)(data[2]));
1158*92022041SSam Saccone }
1159*92022041SSam Saccone if (len == 9)
1160*92022041SSam Saccone printf("\t\tHESSID: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
1161*92022041SSam Saccone data[3], data[4], data[5], data[6], data[7], data[8]);
1162*92022041SSam Saccone else if (len == 7)
1163*92022041SSam Saccone printf("\t\tHESSID: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
1164*92022041SSam Saccone data[1], data[2], data[3], data[4], data[5], data[6]);
1165*92022041SSam Saccone }
1166*92022041SSam Saccone
print_11u_advert(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1167*92022041SSam Saccone static void print_11u_advert(const uint8_t type, uint8_t len,
1168*92022041SSam Saccone const uint8_t *data,
1169*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1170*92022041SSam Saccone {
1171*92022041SSam Saccone /* See Section 7.3.2.93 in the 802.11u spec. */
1172*92022041SSam Saccone /* TODO: This code below does not decode private protocol IDs */
1173*92022041SSam Saccone int idx = 0;
1174*92022041SSam Saccone printf("\n");
1175*92022041SSam Saccone while (idx < (len - 1)) {
1176*92022041SSam Saccone uint8_t qri = data[idx];
1177*92022041SSam Saccone uint8_t proto_id = data[idx + 1];
1178*92022041SSam Saccone printf("\t\tQuery Response Info: 0x%hx\n", (unsigned short)(qri));
1179*92022041SSam Saccone printf("\t\t\tQuery Response Length Limit: %i\n",
1180*92022041SSam Saccone (qri & 0x7f));
1181*92022041SSam Saccone if (qri & (1<<7))
1182*92022041SSam Saccone printf("\t\t\tPAME-BI\n");
1183*92022041SSam Saccone switch(proto_id) {
1184*92022041SSam Saccone case 0:
1185*92022041SSam Saccone printf("\t\t\tANQP\n"); break;
1186*92022041SSam Saccone case 1:
1187*92022041SSam Saccone printf("\t\t\tMIH Information Service\n"); break;
1188*92022041SSam Saccone case 2:
1189*92022041SSam Saccone printf("\t\t\tMIH Command and Event Services Capability Discovery\n"); break;
1190*92022041SSam Saccone case 3:
1191*92022041SSam Saccone printf("\t\t\tEmergency Alert System (EAS)\n"); break;
1192*92022041SSam Saccone case 221:
1193*92022041SSam Saccone printf("\t\t\tVendor Specific\n"); break;
1194*92022041SSam Saccone default:
1195*92022041SSam Saccone printf("\t\t\tReserved: %i\n", proto_id); break;
1196*92022041SSam Saccone }
1197*92022041SSam Saccone idx += 2;
1198*92022041SSam Saccone }
1199*92022041SSam Saccone }
1200*92022041SSam Saccone
print_11u_rcon(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1201*92022041SSam Saccone static void print_11u_rcon(const uint8_t type, uint8_t len, const uint8_t *data,
1202*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1203*92022041SSam Saccone {
1204*92022041SSam Saccone /* See Section 7.3.2.96 in the 802.11u spec. */
1205*92022041SSam Saccone int idx = 0;
1206*92022041SSam Saccone int ln0 = data[1] & 0xf;
1207*92022041SSam Saccone int ln1 = ((data[1] & 0xf0) >> 4);
1208*92022041SSam Saccone int ln2 = 0;
1209*92022041SSam Saccone printf("\n");
1210*92022041SSam Saccone
1211*92022041SSam Saccone if (ln1)
1212*92022041SSam Saccone ln2 = len - 2 - ln0 - ln1;
1213*92022041SSam Saccone
1214*92022041SSam Saccone printf("\t\tANQP OIs: %i\n", data[0]);
1215*92022041SSam Saccone
1216*92022041SSam Saccone if (ln0 > 0) {
1217*92022041SSam Saccone printf("\t\tOI 1: ");
1218*92022041SSam Saccone if (2 + ln0 > len) {
1219*92022041SSam Saccone printf("Invalid IE length.\n");
1220*92022041SSam Saccone } else {
1221*92022041SSam Saccone for (idx = 0; idx < ln0; idx++) {
1222*92022041SSam Saccone printf("%02hhx", data[2 + idx]);
1223*92022041SSam Saccone }
1224*92022041SSam Saccone printf("\n");
1225*92022041SSam Saccone }
1226*92022041SSam Saccone }
1227*92022041SSam Saccone
1228*92022041SSam Saccone if (ln1 > 0) {
1229*92022041SSam Saccone printf("\t\tOI 2: ");
1230*92022041SSam Saccone if (2 + ln0 + ln1 > len) {
1231*92022041SSam Saccone printf("Invalid IE length.\n");
1232*92022041SSam Saccone } else {
1233*92022041SSam Saccone for (idx = 0; idx < ln1; idx++) {
1234*92022041SSam Saccone printf("%02hhx", data[2 + ln0 + idx]);
1235*92022041SSam Saccone }
1236*92022041SSam Saccone printf("\n");
1237*92022041SSam Saccone }
1238*92022041SSam Saccone }
1239*92022041SSam Saccone
1240*92022041SSam Saccone if (ln2 > 0) {
1241*92022041SSam Saccone printf("\t\tOI 3: ");
1242*92022041SSam Saccone if (2 + ln0 + ln1 + ln2 > len) {
1243*92022041SSam Saccone printf("Invalid IE length.\n");
1244*92022041SSam Saccone } else {
1245*92022041SSam Saccone for (idx = 0; idx < ln2; idx++) {
1246*92022041SSam Saccone printf("%02hhx", data[2 + ln0 + ln1 + idx]);
1247*92022041SSam Saccone }
1248*92022041SSam Saccone printf("\n");
1249*92022041SSam Saccone }
1250*92022041SSam Saccone }
1251*92022041SSam Saccone }
1252*92022041SSam Saccone
print_tx_power_envelope(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1253*92022041SSam Saccone static void print_tx_power_envelope(const uint8_t type, uint8_t len,
1254*92022041SSam Saccone const uint8_t *data,
1255*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1256*92022041SSam Saccone {
1257*92022041SSam Saccone const uint8_t local_max_tx_power_count = data[0] & 7;
1258*92022041SSam Saccone const uint8_t local_max_tx_power_unit_interp = (data[0] >> 3) & 7;
1259*92022041SSam Saccone int i;
1260*92022041SSam Saccone static const char *power_names[] = {
1261*92022041SSam Saccone "Local Maximum Transmit Power For 20 MHz",
1262*92022041SSam Saccone "Local Maximum Transmit Power For 40 MHz",
1263*92022041SSam Saccone "Local Maximum Transmit Power For 80 MHz",
1264*92022041SSam Saccone "Local Maximum Transmit Power For 160/80+80 MHz",
1265*92022041SSam Saccone };
1266*92022041SSam Saccone
1267*92022041SSam Saccone printf("\n");
1268*92022041SSam Saccone
1269*92022041SSam Saccone if (local_max_tx_power_count + 2 != len)
1270*92022041SSam Saccone return;
1271*92022041SSam Saccone if (local_max_tx_power_unit_interp != 0)
1272*92022041SSam Saccone return;
1273*92022041SSam Saccone for (i = 0; i < local_max_tx_power_count + 1; ++i) {
1274*92022041SSam Saccone int8_t power_val = ((int8_t)data[1 + i]) >> 1;
1275*92022041SSam Saccone int8_t point5 = data[1 + i] & 1;
1276*92022041SSam Saccone if (point5)
1277*92022041SSam Saccone printf("\t\t * %s: %i.5 dBm\n", power_names[i], power_val);
1278*92022041SSam Saccone else
1279*92022041SSam Saccone printf("\t\t * %s: %i dBm\n", power_names[i], power_val);
1280*92022041SSam Saccone }
1281*92022041SSam Saccone }
1282*92022041SSam Saccone
1283*92022041SSam Saccone static const char *ht_secondary_offset[4] = {
1284*92022041SSam Saccone "no secondary",
1285*92022041SSam Saccone "above",
1286*92022041SSam Saccone "[reserved!]",
1287*92022041SSam Saccone "below",
1288*92022041SSam Saccone };
1289*92022041SSam Saccone
print_ht_op(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1290*92022041SSam Saccone static void print_ht_op(const uint8_t type, uint8_t len, const uint8_t *data,
1291*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1292*92022041SSam Saccone {
1293*92022041SSam Saccone static const char *protection[4] = {
1294*92022041SSam Saccone "no",
1295*92022041SSam Saccone "nonmember",
1296*92022041SSam Saccone "20 MHz",
1297*92022041SSam Saccone "non-HT mixed",
1298*92022041SSam Saccone };
1299*92022041SSam Saccone static const char *sta_chan_width[2] = {
1300*92022041SSam Saccone "20 MHz",
1301*92022041SSam Saccone "any",
1302*92022041SSam Saccone };
1303*92022041SSam Saccone
1304*92022041SSam Saccone printf("\n");
1305*92022041SSam Saccone printf("\t\t * primary channel: %d\n", data[0]);
1306*92022041SSam Saccone printf("\t\t * secondary channel offset: %s\n",
1307*92022041SSam Saccone ht_secondary_offset[data[1] & 0x3]);
1308*92022041SSam Saccone printf("\t\t * STA channel width: %s\n", sta_chan_width[(data[1] & 0x4)>>2]);
1309*92022041SSam Saccone printf("\t\t * RIFS: %d\n", (data[1] & 0x8)>>3);
1310*92022041SSam Saccone printf("\t\t * HT protection: %s\n", protection[data[2] & 0x3]);
1311*92022041SSam Saccone printf("\t\t * non-GF present: %d\n", (data[2] & 0x4) >> 2);
1312*92022041SSam Saccone printf("\t\t * OBSS non-GF present: %d\n", (data[2] & 0x10) >> 4);
1313*92022041SSam Saccone printf("\t\t * dual beacon: %d\n", (data[4] & 0x40) >> 6);
1314*92022041SSam Saccone printf("\t\t * dual CTS protection: %d\n", (data[4] & 0x80) >> 7);
1315*92022041SSam Saccone printf("\t\t * STBC beacon: %d\n", data[5] & 0x1);
1316*92022041SSam Saccone printf("\t\t * L-SIG TXOP Prot: %d\n", (data[5] & 0x2) >> 1);
1317*92022041SSam Saccone printf("\t\t * PCO active: %d\n", (data[5] & 0x4) >> 2);
1318*92022041SSam Saccone printf("\t\t * PCO phase: %d\n", (data[5] & 0x8) >> 3);
1319*92022041SSam Saccone }
1320*92022041SSam Saccone
print_capabilities(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1321*92022041SSam Saccone static void print_capabilities(const uint8_t type, uint8_t len,
1322*92022041SSam Saccone const uint8_t *data,
1323*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1324*92022041SSam Saccone {
1325*92022041SSam Saccone int i, base, bit, si_duration = 0, max_amsdu = 0;
1326*92022041SSam Saccone bool s_psmp_support = false, is_vht_cap = false;
1327*92022041SSam Saccone unsigned char *ie = ie_buffer->ie;
1328*92022041SSam Saccone int ielen = ie_buffer->ielen;
1329*92022041SSam Saccone
1330*92022041SSam Saccone while (ielen >= 2 && ielen >= ie[1]) {
1331*92022041SSam Saccone if (ie[0] == 191) {
1332*92022041SSam Saccone is_vht_cap = true;
1333*92022041SSam Saccone break;
1334*92022041SSam Saccone }
1335*92022041SSam Saccone ielen -= ie[1] + 2;
1336*92022041SSam Saccone ie += ie[1] + 2;
1337*92022041SSam Saccone }
1338*92022041SSam Saccone
1339*92022041SSam Saccone for (i = 0; i < len; i++) {
1340*92022041SSam Saccone base = i * 8;
1341*92022041SSam Saccone
1342*92022041SSam Saccone for (bit = 0; bit < 8; bit++) {
1343*92022041SSam Saccone if (!(data[i] & (1 << bit)))
1344*92022041SSam Saccone continue;
1345*92022041SSam Saccone
1346*92022041SSam Saccone printf("\n\t\t *");
1347*92022041SSam Saccone
1348*92022041SSam Saccone #define CAPA(bit, name) case bit: printf(" " name); break
1349*92022041SSam Saccone
1350*92022041SSam Saccone /* if the capability 'cap' exists add 'val' to 'sum'
1351*92022041SSam Saccone * otherwise print 'Reserved' */
1352*92022041SSam Saccone #define ADD_BIT_VAL(bit, cap, sum, val) case (bit): do { \
1353*92022041SSam Saccone if (!(cap)) { \
1354*92022041SSam Saccone printf(" Reserved"); \
1355*92022041SSam Saccone break; \
1356*92022041SSam Saccone } \
1357*92022041SSam Saccone sum += val; \
1358*92022041SSam Saccone break; \
1359*92022041SSam Saccone } while (0)
1360*92022041SSam Saccone
1361*92022041SSam Saccone switch (bit + base) {
1362*92022041SSam Saccone CAPA(0, "HT Information Exchange Supported");
1363*92022041SSam Saccone CAPA(1, "reserved (On-demand Beacon)");
1364*92022041SSam Saccone CAPA(2, "Extended Channel Switching");
1365*92022041SSam Saccone CAPA(3, "reserved (Wave Indication)");
1366*92022041SSam Saccone CAPA(4, "PSMP Capability");
1367*92022041SSam Saccone CAPA(5, "reserved (Service Interval Granularity)");
1368*92022041SSam Saccone
1369*92022041SSam Saccone case 6:
1370*92022041SSam Saccone s_psmp_support = true;
1371*92022041SSam Saccone printf(" S-PSMP Capability");
1372*92022041SSam Saccone break;
1373*92022041SSam Saccone
1374*92022041SSam Saccone CAPA(7, "Event");
1375*92022041SSam Saccone CAPA(8, "Diagnostics");
1376*92022041SSam Saccone CAPA(9, "Multicast Diagnostics");
1377*92022041SSam Saccone CAPA(10, "Location Tracking");
1378*92022041SSam Saccone CAPA(11, "FMS");
1379*92022041SSam Saccone CAPA(12, "Proxy ARP Service");
1380*92022041SSam Saccone CAPA(13, "Collocated Interference Reporting");
1381*92022041SSam Saccone CAPA(14, "Civic Location");
1382*92022041SSam Saccone CAPA(15, "Geospatial Location");
1383*92022041SSam Saccone CAPA(16, "TFS");
1384*92022041SSam Saccone CAPA(17, "WNM-Sleep Mode");
1385*92022041SSam Saccone CAPA(18, "TIM Broadcast");
1386*92022041SSam Saccone CAPA(19, "BSS Transition");
1387*92022041SSam Saccone CAPA(20, "QoS Traffic Capability");
1388*92022041SSam Saccone CAPA(21, "AC Station Count");
1389*92022041SSam Saccone CAPA(22, "Multiple BSSID");
1390*92022041SSam Saccone CAPA(23, "Timing Measurement");
1391*92022041SSam Saccone CAPA(24, "Channel Usage");
1392*92022041SSam Saccone CAPA(25, "SSID List");
1393*92022041SSam Saccone CAPA(26, "DMS");
1394*92022041SSam Saccone CAPA(27, "UTC TSF Offset");
1395*92022041SSam Saccone CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
1396*92022041SSam Saccone CAPA(29, "TDLS Peer PSM Support");
1397*92022041SSam Saccone CAPA(30, "TDLS channel switching");
1398*92022041SSam Saccone CAPA(31, "Interworking");
1399*92022041SSam Saccone CAPA(32, "QoS Map");
1400*92022041SSam Saccone CAPA(33, "EBR");
1401*92022041SSam Saccone CAPA(34, "SSPN Interface");
1402*92022041SSam Saccone CAPA(35, "Reserved");
1403*92022041SSam Saccone CAPA(36, "MSGCF Capability");
1404*92022041SSam Saccone CAPA(37, "TDLS Support");
1405*92022041SSam Saccone CAPA(38, "TDLS Prohibited");
1406*92022041SSam Saccone CAPA(39, "TDLS Channel Switching Prohibited");
1407*92022041SSam Saccone CAPA(40, "Reject Unadmitted Frame");
1408*92022041SSam Saccone
1409*92022041SSam Saccone ADD_BIT_VAL(41, s_psmp_support, si_duration, 1);
1410*92022041SSam Saccone ADD_BIT_VAL(42, s_psmp_support, si_duration, 2);
1411*92022041SSam Saccone ADD_BIT_VAL(43, s_psmp_support, si_duration, 4);
1412*92022041SSam Saccone
1413*92022041SSam Saccone CAPA(44, "Identifier Location");
1414*92022041SSam Saccone CAPA(45, "U-APSD Coexistence");
1415*92022041SSam Saccone CAPA(46, "WNM-Notification");
1416*92022041SSam Saccone CAPA(47, "Reserved");
1417*92022041SSam Saccone CAPA(48, "UTF-8 SSID");
1418*92022041SSam Saccone CAPA(49, "QMFActivated");
1419*92022041SSam Saccone CAPA(50, "QMFReconfigurationActivated");
1420*92022041SSam Saccone CAPA(51, "Robust AV Streaming");
1421*92022041SSam Saccone CAPA(52, "Advanced GCR");
1422*92022041SSam Saccone CAPA(53, "Mesh GCR");
1423*92022041SSam Saccone CAPA(54, "SCS");
1424*92022041SSam Saccone CAPA(55, "QLoad Report");
1425*92022041SSam Saccone CAPA(56, "Alternate EDCA");
1426*92022041SSam Saccone CAPA(57, "Unprotected TXOP Negotiation");
1427*92022041SSam Saccone CAPA(58, "Protected TXOP egotiation");
1428*92022041SSam Saccone CAPA(59, "Reserved");
1429*92022041SSam Saccone CAPA(60, "Protected QLoad Report");
1430*92022041SSam Saccone CAPA(61, "TDLS Wider Bandwidth");
1431*92022041SSam Saccone CAPA(62, "Operating Mode Notification");
1432*92022041SSam Saccone
1433*92022041SSam Saccone ADD_BIT_VAL(63, is_vht_cap, max_amsdu, 1);
1434*92022041SSam Saccone ADD_BIT_VAL(64, is_vht_cap, max_amsdu, 2);
1435*92022041SSam Saccone
1436*92022041SSam Saccone CAPA(65, "Channel Schedule Management");
1437*92022041SSam Saccone CAPA(66, "Geodatabase Inband Enabling Signal");
1438*92022041SSam Saccone CAPA(67, "Network Channel Control");
1439*92022041SSam Saccone CAPA(68, "White Space Map");
1440*92022041SSam Saccone CAPA(69, "Channel Availability Query");
1441*92022041SSam Saccone CAPA(70, "FTM Responder");
1442*92022041SSam Saccone CAPA(71, "FTM Initiator");
1443*92022041SSam Saccone CAPA(72, "Reserved");
1444*92022041SSam Saccone CAPA(73, "Extended Spectrum Management Capable");
1445*92022041SSam Saccone CAPA(74, "Reserved");
1446*92022041SSam Saccone default:
1447*92022041SSam Saccone printf(" %d", bit);
1448*92022041SSam Saccone break;
1449*92022041SSam Saccone }
1450*92022041SSam Saccone #undef ADD_BIT_VAL
1451*92022041SSam Saccone #undef CAPA
1452*92022041SSam Saccone }
1453*92022041SSam Saccone }
1454*92022041SSam Saccone
1455*92022041SSam Saccone if (s_psmp_support)
1456*92022041SSam Saccone printf("\n\t\t * Service Interval Granularity is %d ms",
1457*92022041SSam Saccone (si_duration + 1) * 5);
1458*92022041SSam Saccone
1459*92022041SSam Saccone if (is_vht_cap) {
1460*92022041SSam Saccone printf("\n\t\t * Max Number Of MSDUs In A-MSDU is ");
1461*92022041SSam Saccone switch (max_amsdu) {
1462*92022041SSam Saccone case 0:
1463*92022041SSam Saccone printf("unlimited");
1464*92022041SSam Saccone break;
1465*92022041SSam Saccone case 1:
1466*92022041SSam Saccone printf("32");
1467*92022041SSam Saccone break;
1468*92022041SSam Saccone case 2:
1469*92022041SSam Saccone printf("16");
1470*92022041SSam Saccone break;
1471*92022041SSam Saccone case 3:
1472*92022041SSam Saccone printf("8");
1473*92022041SSam Saccone break;
1474*92022041SSam Saccone default:
1475*92022041SSam Saccone break;
1476*92022041SSam Saccone }
1477*92022041SSam Saccone }
1478*92022041SSam Saccone
1479*92022041SSam Saccone printf("\n");
1480*92022041SSam Saccone }
1481*92022041SSam Saccone
print_tim(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1482*92022041SSam Saccone static void print_tim(const uint8_t type, uint8_t len, const uint8_t *data,
1483*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1484*92022041SSam Saccone {
1485*92022041SSam Saccone printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
1486*92022041SSam Saccone "Bitmap[0] 0x%x",
1487*92022041SSam Saccone data[0], data[1], data[2], data[3]);
1488*92022041SSam Saccone if (len - 4)
1489*92022041SSam Saccone printf(" (+ %u octet%s)", len - 4, len - 4 == 1 ? "" : "s");
1490*92022041SSam Saccone printf("\n");
1491*92022041SSam Saccone }
1492*92022041SSam Saccone
print_ibssatim(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1493*92022041SSam Saccone static void print_ibssatim(const uint8_t type, uint8_t len, const uint8_t *data,
1494*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1495*92022041SSam Saccone {
1496*92022041SSam Saccone printf(" %d TUs\n", (data[1] << 8) + data[0]);
1497*92022041SSam Saccone }
1498*92022041SSam Saccone
print_vht_capa(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1499*92022041SSam Saccone static void print_vht_capa(const uint8_t type, uint8_t len, const uint8_t *data,
1500*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1501*92022041SSam Saccone {
1502*92022041SSam Saccone printf("\n");
1503*92022041SSam Saccone print_vht_info((__u32) data[0] | ((__u32)data[1] << 8) |
1504*92022041SSam Saccone ((__u32)data[2] << 16) | ((__u32)data[3] << 24),
1505*92022041SSam Saccone data + 4);
1506*92022041SSam Saccone }
1507*92022041SSam Saccone
print_vht_oper(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1508*92022041SSam Saccone static void print_vht_oper(const uint8_t type, uint8_t len, const uint8_t *data,
1509*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1510*92022041SSam Saccone {
1511*92022041SSam Saccone const char *chandwidths[] = {
1512*92022041SSam Saccone [0] = "20 or 40 MHz",
1513*92022041SSam Saccone [1] = "80 MHz",
1514*92022041SSam Saccone [3] = "80+80 MHz",
1515*92022041SSam Saccone [2] = "160 MHz",
1516*92022041SSam Saccone };
1517*92022041SSam Saccone
1518*92022041SSam Saccone printf("\n");
1519*92022041SSam Saccone printf("\t\t * channel width: %d (%s)\n", data[0],
1520*92022041SSam Saccone data[0] < ARRAY_SIZE(chandwidths) ? chandwidths[data[0]] : "unknown");
1521*92022041SSam Saccone printf("\t\t * center freq segment 1: %d\n", data[1]);
1522*92022041SSam Saccone printf("\t\t * center freq segment 2: %d\n", data[2]);
1523*92022041SSam Saccone printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data[4], data[3]);
1524*92022041SSam Saccone }
1525*92022041SSam Saccone
print_supp_op_classes(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1526*92022041SSam Saccone static void print_supp_op_classes(const uint8_t type, uint8_t len,
1527*92022041SSam Saccone const uint8_t *data,
1528*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1529*92022041SSam Saccone {
1530*92022041SSam Saccone uint8_t *p = (uint8_t*) data;
1531*92022041SSam Saccone const uint8_t *next_data = p + len;
1532*92022041SSam Saccone int zero_delimiter = 0;
1533*92022041SSam Saccone int one_hundred_thirty_delimiter = 0;
1534*92022041SSam Saccone
1535*92022041SSam Saccone printf("\n");
1536*92022041SSam Saccone printf("\t\t * current operating class: %d\n", *p);
1537*92022041SSam Saccone while (++p < next_data) {
1538*92022041SSam Saccone if (*p == 130) {
1539*92022041SSam Saccone one_hundred_thirty_delimiter = 1;
1540*92022041SSam Saccone break;
1541*92022041SSam Saccone }
1542*92022041SSam Saccone if (*p == 0) {
1543*92022041SSam Saccone zero_delimiter = 0;
1544*92022041SSam Saccone break;
1545*92022041SSam Saccone }
1546*92022041SSam Saccone printf("\t\t * operating class: %d\n", *p);
1547*92022041SSam Saccone }
1548*92022041SSam Saccone if (one_hundred_thirty_delimiter)
1549*92022041SSam Saccone while (++p < next_data) {
1550*92022041SSam Saccone printf("\t\t * current operating class extension: %d\n", *p);
1551*92022041SSam Saccone }
1552*92022041SSam Saccone if (zero_delimiter)
1553*92022041SSam Saccone while (++p < next_data - 1) {
1554*92022041SSam Saccone printf("\t\t * operating class tuple: %d %d\n", p[0], p[1]);
1555*92022041SSam Saccone if (*p == 0)
1556*92022041SSam Saccone break;
1557*92022041SSam Saccone }
1558*92022041SSam Saccone }
1559*92022041SSam Saccone
print_measurement_pilot_tx(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1560*92022041SSam Saccone static void print_measurement_pilot_tx(const uint8_t type, uint8_t len,
1561*92022041SSam Saccone const uint8_t *data,
1562*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1563*92022041SSam Saccone {
1564*92022041SSam Saccone uint8_t *p, len_remaining;
1565*92022041SSam Saccone
1566*92022041SSam Saccone printf("\n");
1567*92022041SSam Saccone printf("\t\t * interval: %d TUs\n", data[0]);
1568*92022041SSam Saccone
1569*92022041SSam Saccone if (len <= 1)
1570*92022041SSam Saccone return;
1571*92022041SSam Saccone
1572*92022041SSam Saccone p = (uint8_t *) data + 1;
1573*92022041SSam Saccone len_remaining = len - 1;
1574*92022041SSam Saccone
1575*92022041SSam Saccone while (len_remaining >=5) {
1576*92022041SSam Saccone uint8_t subelement_id = *p, len, *end;
1577*92022041SSam Saccone
1578*92022041SSam Saccone p++;
1579*92022041SSam Saccone len = *p;
1580*92022041SSam Saccone p++;
1581*92022041SSam Saccone end = p + len;
1582*92022041SSam Saccone
1583*92022041SSam Saccone len_remaining -= 2;
1584*92022041SSam Saccone
1585*92022041SSam Saccone /* 802.11-2016 only allows vendor specific elements */
1586*92022041SSam Saccone if (subelement_id != 221) {
1587*92022041SSam Saccone printf("\t\t * <Invalid subelement ID %d>\n", subelement_id);
1588*92022041SSam Saccone return;
1589*92022041SSam Saccone }
1590*92022041SSam Saccone
1591*92022041SSam Saccone if (len < 3 || len > len_remaining) {
1592*92022041SSam Saccone printf(" <Parse error, element too short>\n");
1593*92022041SSam Saccone return;
1594*92022041SSam Saccone }
1595*92022041SSam Saccone
1596*92022041SSam Saccone printf("\t\t * vendor specific: OUI %.2x:%.2x:%.2x, data:",
1597*92022041SSam Saccone p[0], p[1], p[2]);
1598*92022041SSam Saccone /* add only two here and use ++p in while loop */
1599*92022041SSam Saccone p += 2;
1600*92022041SSam Saccone
1601*92022041SSam Saccone while (++p < end)
1602*92022041SSam Saccone printf(" %.2x", *p);
1603*92022041SSam Saccone printf("\n");
1604*92022041SSam Saccone
1605*92022041SSam Saccone len_remaining -= len;
1606*92022041SSam Saccone }
1607*92022041SSam Saccone }
1608*92022041SSam Saccone
print_obss_scan_params(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1609*92022041SSam Saccone static void print_obss_scan_params(const uint8_t type, uint8_t len,
1610*92022041SSam Saccone const uint8_t *data,
1611*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1612*92022041SSam Saccone {
1613*92022041SSam Saccone printf("\n");
1614*92022041SSam Saccone printf("\t\t * passive dwell: %d TUs\n", (data[1] << 8) | data[0]);
1615*92022041SSam Saccone printf("\t\t * active dwell: %d TUs\n", (data[3] << 8) | data[2]);
1616*92022041SSam Saccone printf("\t\t * channel width trigger scan interval: %d s\n", (data[5] << 8) | data[4]);
1617*92022041SSam Saccone printf("\t\t * scan passive total per channel: %d TUs\n", (data[7] << 8) | data[6]);
1618*92022041SSam Saccone printf("\t\t * scan active total per channel: %d TUs\n", (data[9] << 8) | data[8]);
1619*92022041SSam Saccone printf("\t\t * BSS width channel transition delay factor: %d\n", (data[11] << 8) | data[10]);
1620*92022041SSam Saccone printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
1621*92022041SSam Saccone ((data[13] << 8) | data[12]) / 100, ((data[13] << 8) | data[12]) % 100);
1622*92022041SSam Saccone }
1623*92022041SSam Saccone
print_secchan_offs(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1624*92022041SSam Saccone static void print_secchan_offs(const uint8_t type, uint8_t len,
1625*92022041SSam Saccone const uint8_t *data,
1626*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1627*92022041SSam Saccone {
1628*92022041SSam Saccone if (data[0] < ARRAY_SIZE(ht_secondary_offset))
1629*92022041SSam Saccone printf(" %s (%d)\n", ht_secondary_offset[data[0]], data[0]);
1630*92022041SSam Saccone else
1631*92022041SSam Saccone printf(" %d\n", data[0]);
1632*92022041SSam Saccone }
1633*92022041SSam Saccone
print_bss_load(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1634*92022041SSam Saccone static void print_bss_load(const uint8_t type, uint8_t len, const uint8_t *data,
1635*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1636*92022041SSam Saccone {
1637*92022041SSam Saccone printf("\n");
1638*92022041SSam Saccone printf("\t\t * station count: %d\n", (data[1] << 8) | data[0]);
1639*92022041SSam Saccone printf("\t\t * channel utilisation: %d/255\n", data[2]);
1640*92022041SSam Saccone printf("\t\t * available admission capacity: %d [*32us]\n", (data[4] << 8) | data[3]);
1641*92022041SSam Saccone }
1642*92022041SSam Saccone
print_mesh_conf(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1643*92022041SSam Saccone static void print_mesh_conf(const uint8_t type, uint8_t len,
1644*92022041SSam Saccone const uint8_t *data,
1645*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1646*92022041SSam Saccone {
1647*92022041SSam Saccone printf("\n");
1648*92022041SSam Saccone printf("\t\t * Active Path Selection Protocol ID: %d\n", data[0]);
1649*92022041SSam Saccone printf("\t\t * Active Path Selection Metric ID: %d\n", data[1]);
1650*92022041SSam Saccone printf("\t\t * Congestion Control Mode ID: %d\n", data[2]);
1651*92022041SSam Saccone printf("\t\t * Synchronization Method ID: %d\n", data[3]);
1652*92022041SSam Saccone printf("\t\t * Authentication Protocol ID: %d\n", data[4]);
1653*92022041SSam Saccone printf("\t\t * Mesh Formation Info:\n");
1654*92022041SSam Saccone printf("\t\t\t Number of Peerings: %d\n", (data[5] & 0x7E) >> 1);
1655*92022041SSam Saccone if (data[5] & 0x01)
1656*92022041SSam Saccone printf("\t\t\t Connected to Mesh Gate\n");
1657*92022041SSam Saccone if (data[5] & 0x80)
1658*92022041SSam Saccone printf("\t\t\t Connected to AS\n");
1659*92022041SSam Saccone printf("\t\t * Mesh Capability\n");
1660*92022041SSam Saccone if (data[6] & 0x01)
1661*92022041SSam Saccone printf("\t\t\t Accepting Additional Mesh Peerings\n");
1662*92022041SSam Saccone if (data[6] & 0x02)
1663*92022041SSam Saccone printf("\t\t\t MCCA Supported\n");
1664*92022041SSam Saccone if (data[6] & 0x04)
1665*92022041SSam Saccone printf("\t\t\t MCCA Enabled\n");
1666*92022041SSam Saccone if (data[6] & 0x08)
1667*92022041SSam Saccone printf("\t\t\t Forwarding\n");
1668*92022041SSam Saccone if (data[6] & 0x10)
1669*92022041SSam Saccone printf("\t\t\t MBCA Supported\n");
1670*92022041SSam Saccone if (data[6] & 0x20)
1671*92022041SSam Saccone printf("\t\t\t TBTT Adjusting\n");
1672*92022041SSam Saccone if (data[6] & 0x40)
1673*92022041SSam Saccone printf("\t\t\t Mesh Power Save Level\n");
1674*92022041SSam Saccone }
1675*92022041SSam Saccone
1676*92022041SSam Saccone struct ie_print {
1677*92022041SSam Saccone const char *name;
1678*92022041SSam Saccone void (*print)(const uint8_t type, uint8_t len, const uint8_t *data,
1679*92022041SSam Saccone const struct print_ies_data *ie_buffer);
1680*92022041SSam Saccone uint8_t minlen, maxlen;
1681*92022041SSam Saccone uint8_t flags;
1682*92022041SSam Saccone };
1683*92022041SSam Saccone
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)1684*92022041SSam Saccone static void print_ie(const struct ie_print *p, const uint8_t type, uint8_t len,
1685*92022041SSam Saccone const uint8_t *data,
1686*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1687*92022041SSam Saccone {
1688*92022041SSam Saccone int i;
1689*92022041SSam Saccone
1690*92022041SSam Saccone if (!p->print)
1691*92022041SSam Saccone return;
1692*92022041SSam Saccone
1693*92022041SSam Saccone printf("\t%s:", p->name);
1694*92022041SSam Saccone if (len < p->minlen || len > p->maxlen) {
1695*92022041SSam Saccone if (len > 1) {
1696*92022041SSam Saccone printf(" <invalid: %d bytes:", len);
1697*92022041SSam Saccone for (i = 0; i < len; i++)
1698*92022041SSam Saccone printf(" %.02x", data[i]);
1699*92022041SSam Saccone printf(">\n");
1700*92022041SSam Saccone } else if (len)
1701*92022041SSam Saccone printf(" <invalid: 1 byte: %.02x>\n", data[0]);
1702*92022041SSam Saccone else
1703*92022041SSam Saccone printf(" <invalid: no data>\n");
1704*92022041SSam Saccone return;
1705*92022041SSam Saccone }
1706*92022041SSam Saccone
1707*92022041SSam Saccone p->print(type, len, data, ie_buffer);
1708*92022041SSam Saccone }
1709*92022041SSam Saccone
1710*92022041SSam Saccone #define PRINT_IGN { \
1711*92022041SSam Saccone .name = "IGNORE", \
1712*92022041SSam Saccone .print = NULL, \
1713*92022041SSam Saccone .minlen = 0, \
1714*92022041SSam Saccone .maxlen = 255, \
1715*92022041SSam Saccone }
1716*92022041SSam Saccone
1717*92022041SSam Saccone static const struct ie_print ieprinters[] = {
1718*92022041SSam Saccone [0] = { "SSID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
1719*92022041SSam Saccone [1] = { "Supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
1720*92022041SSam Saccone [3] = { "DS Parameter set", print_ds, 1, 1, BIT(PRINT_SCAN), },
1721*92022041SSam Saccone [5] = { "TIM", print_tim, 4, 255, BIT(PRINT_SCAN), },
1722*92022041SSam Saccone [6] = { "IBSS ATIM window", print_ibssatim, 2, 2, BIT(PRINT_SCAN), },
1723*92022041SSam Saccone [7] = { "Country", print_country, 3, 255, BIT(PRINT_SCAN), },
1724*92022041SSam Saccone [11] = { "BSS Load", print_bss_load, 5, 5, BIT(PRINT_SCAN), },
1725*92022041SSam Saccone [32] = { "Power constraint", print_powerconstraint, 1, 1, BIT(PRINT_SCAN), },
1726*92022041SSam Saccone [35] = { "TPC report", print_tpcreport, 2, 2, BIT(PRINT_SCAN), },
1727*92022041SSam Saccone [42] = { "ERP", print_erp, 1, 255, BIT(PRINT_SCAN), },
1728*92022041SSam Saccone [45] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), },
1729*92022041SSam Saccone [47] = { "ERP D4.0", print_erp, 1, 255, BIT(PRINT_SCAN), },
1730*92022041SSam Saccone [51] = { "AP Channel Report", print_ap_channel_report, 1, 255, BIT(PRINT_SCAN), },
1731*92022041SSam Saccone [59] = { "Supported operating classes", print_supp_op_classes, 1, 255, BIT(PRINT_SCAN), },
1732*92022041SSam Saccone [66] = { "Measurement Pilot Transmission", print_measurement_pilot_tx, 1, 255, BIT(PRINT_SCAN), },
1733*92022041SSam Saccone [74] = { "Overlapping BSS scan params", print_obss_scan_params, 14, 255, BIT(PRINT_SCAN), },
1734*92022041SSam Saccone [61] = { "HT operation", print_ht_op, 22, 22, BIT(PRINT_SCAN), },
1735*92022041SSam Saccone [62] = { "Secondary Channel Offset", print_secchan_offs, 1, 1, BIT(PRINT_SCAN), },
1736*92022041SSam Saccone [191] = { "VHT capabilities", print_vht_capa, 12, 255, BIT(PRINT_SCAN), },
1737*92022041SSam Saccone [192] = { "VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN), },
1738*92022041SSam Saccone [48] = { "RSN", print_rsn, 2, 255, BIT(PRINT_SCAN), },
1739*92022041SSam Saccone [50] = { "Extended supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
1740*92022041SSam Saccone [70] = { "RM enabled capabilities", print_rm_enabled_capabilities, 5, 5, BIT(PRINT_SCAN), },
1741*92022041SSam Saccone [113] = { "MESH Configuration", print_mesh_conf, 7, 7, BIT(PRINT_SCAN), },
1742*92022041SSam Saccone [114] = { "MESH ID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
1743*92022041SSam Saccone [127] = { "Extended capabilities", print_capabilities, 0, 255, BIT(PRINT_SCAN), },
1744*92022041SSam Saccone [107] = { "802.11u Interworking", print_interworking, 0, 255, BIT(PRINT_SCAN), },
1745*92022041SSam Saccone [108] = { "802.11u Advertisement", print_11u_advert, 0, 255, BIT(PRINT_SCAN), },
1746*92022041SSam Saccone [111] = { "802.11u Roaming Consortium", print_11u_rcon, 2, 255, BIT(PRINT_SCAN), },
1747*92022041SSam Saccone [195] = { "Transmit Power Envelope", print_tx_power_envelope, 2, 5, BIT(PRINT_SCAN), },
1748*92022041SSam Saccone };
1749*92022041SSam Saccone
print_wifi_wpa(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1750*92022041SSam Saccone static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data,
1751*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1752*92022041SSam Saccone {
1753*92022041SSam Saccone print_rsn_ie("TKIP", "IEEE 802.1X", len, data);
1754*92022041SSam Saccone }
1755*92022041SSam Saccone
print_wifi_osen(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1756*92022041SSam Saccone static void print_wifi_osen(const uint8_t type, uint8_t len,
1757*92022041SSam Saccone const uint8_t *data,
1758*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1759*92022041SSam Saccone {
1760*92022041SSam Saccone print_osen_ie("OSEN", "OSEN", len, data);
1761*92022041SSam Saccone }
1762*92022041SSam Saccone
print_wifi_wmm_param(const uint8_t * data,uint8_t len)1763*92022041SSam Saccone static bool print_wifi_wmm_param(const uint8_t *data, uint8_t len)
1764*92022041SSam Saccone {
1765*92022041SSam Saccone int i;
1766*92022041SSam Saccone static const char *aci_tbl[] = { "BE", "BK", "VI", "VO" };
1767*92022041SSam Saccone
1768*92022041SSam Saccone if (len < 19)
1769*92022041SSam Saccone goto invalid;
1770*92022041SSam Saccone
1771*92022041SSam Saccone if (data[0] != 1) {
1772*92022041SSam Saccone printf("Parameter: not version 1: ");
1773*92022041SSam Saccone return false;
1774*92022041SSam Saccone }
1775*92022041SSam Saccone
1776*92022041SSam Saccone printf("\t * Parameter version 1");
1777*92022041SSam Saccone
1778*92022041SSam Saccone data++;
1779*92022041SSam Saccone
1780*92022041SSam Saccone if (data[0] & 0x80)
1781*92022041SSam Saccone printf("\n\t\t * u-APSD");
1782*92022041SSam Saccone
1783*92022041SSam Saccone data += 2;
1784*92022041SSam Saccone
1785*92022041SSam Saccone for (i = 0; i < 4; i++) {
1786*92022041SSam Saccone printf("\n\t\t * %s:", aci_tbl[(data[0] >> 5) & 3]);
1787*92022041SSam Saccone if (data[0] & 0x10)
1788*92022041SSam Saccone printf(" acm");
1789*92022041SSam Saccone printf(" CW %d-%d", (1 << (data[1] & 0xf)) - 1,
1790*92022041SSam Saccone (1 << (data[1] >> 4)) - 1);
1791*92022041SSam Saccone printf(", AIFSN %d", data[0] & 0xf);
1792*92022041SSam Saccone if (data[2] | data[3])
1793*92022041SSam Saccone printf(", TXOP %d usec", (data[2] + (data[3] << 8)) * 32);
1794*92022041SSam Saccone data += 4;
1795*92022041SSam Saccone }
1796*92022041SSam Saccone
1797*92022041SSam Saccone printf("\n");
1798*92022041SSam Saccone return true;
1799*92022041SSam Saccone
1800*92022041SSam Saccone invalid:
1801*92022041SSam Saccone printf("invalid: ");
1802*92022041SSam Saccone return false;
1803*92022041SSam Saccone }
1804*92022041SSam Saccone
print_wifi_wmm(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1805*92022041SSam Saccone static void print_wifi_wmm(const uint8_t type, uint8_t len, const uint8_t *data,
1806*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1807*92022041SSam Saccone {
1808*92022041SSam Saccone int i;
1809*92022041SSam Saccone
1810*92022041SSam Saccone switch (data[0]) {
1811*92022041SSam Saccone case 0x00:
1812*92022041SSam Saccone printf(" information:");
1813*92022041SSam Saccone break;
1814*92022041SSam Saccone case 0x01:
1815*92022041SSam Saccone if (print_wifi_wmm_param(data + 1, len - 1))
1816*92022041SSam Saccone return;
1817*92022041SSam Saccone break;
1818*92022041SSam Saccone default:
1819*92022041SSam Saccone printf(" type %d:", data[0]);
1820*92022041SSam Saccone break;
1821*92022041SSam Saccone }
1822*92022041SSam Saccone
1823*92022041SSam Saccone for(i = 1; i < len; i++)
1824*92022041SSam Saccone printf(" %.02x", data[i]);
1825*92022041SSam Saccone printf("\n");
1826*92022041SSam Saccone }
1827*92022041SSam Saccone
wifi_wps_dev_passwd_id(uint16_t id)1828*92022041SSam Saccone static const char * wifi_wps_dev_passwd_id(uint16_t id)
1829*92022041SSam Saccone {
1830*92022041SSam Saccone switch (id) {
1831*92022041SSam Saccone case 0:
1832*92022041SSam Saccone return "Default (PIN)";
1833*92022041SSam Saccone case 1:
1834*92022041SSam Saccone return "User-specified";
1835*92022041SSam Saccone case 2:
1836*92022041SSam Saccone return "Machine-specified";
1837*92022041SSam Saccone case 3:
1838*92022041SSam Saccone return "Rekey";
1839*92022041SSam Saccone case 4:
1840*92022041SSam Saccone return "PushButton";
1841*92022041SSam Saccone case 5:
1842*92022041SSam Saccone return "Registrar-specified";
1843*92022041SSam Saccone default:
1844*92022041SSam Saccone return "??";
1845*92022041SSam Saccone }
1846*92022041SSam Saccone }
1847*92022041SSam Saccone
print_wifi_wps(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)1848*92022041SSam Saccone static void print_wifi_wps(const uint8_t type, uint8_t len, const uint8_t *data,
1849*92022041SSam Saccone const struct print_ies_data *ie_buffer)
1850*92022041SSam Saccone {
1851*92022041SSam Saccone bool first = true;
1852*92022041SSam Saccone __u16 subtype, sublen;
1853*92022041SSam Saccone
1854*92022041SSam Saccone while (len >= 4) {
1855*92022041SSam Saccone subtype = (data[0] << 8) + data[1];
1856*92022041SSam Saccone sublen = (data[2] << 8) + data[3];
1857*92022041SSam Saccone if (sublen > len - 4)
1858*92022041SSam Saccone break;
1859*92022041SSam Saccone
1860*92022041SSam Saccone switch (subtype) {
1861*92022041SSam Saccone case 0x104a:
1862*92022041SSam Saccone tab_on_first(&first);
1863*92022041SSam Saccone if (sublen < 1) {
1864*92022041SSam Saccone printf("\t * Version: (invalid "
1865*92022041SSam Saccone "length %d)\n", sublen);
1866*92022041SSam Saccone break;
1867*92022041SSam Saccone }
1868*92022041SSam Saccone printf("\t * Version: %d.%d\n", data[4] >> 4, data[4] & 0xF);
1869*92022041SSam Saccone break;
1870*92022041SSam Saccone case 0x1011:
1871*92022041SSam Saccone tab_on_first(&first);
1872*92022041SSam Saccone printf("\t * Device name: %.*s\n", sublen, data + 4);
1873*92022041SSam Saccone break;
1874*92022041SSam Saccone case 0x1012: {
1875*92022041SSam Saccone uint16_t id;
1876*92022041SSam Saccone tab_on_first(&first);
1877*92022041SSam Saccone if (sublen != 2) {
1878*92022041SSam Saccone printf("\t * Device Password ID: (invalid length %d)\n",
1879*92022041SSam Saccone sublen);
1880*92022041SSam Saccone break;
1881*92022041SSam Saccone }
1882*92022041SSam Saccone id = data[4] << 8 | data[5];
1883*92022041SSam Saccone printf("\t * Device Password ID: %u (%s)\n",
1884*92022041SSam Saccone id, wifi_wps_dev_passwd_id(id));
1885*92022041SSam Saccone break;
1886*92022041SSam Saccone }
1887*92022041SSam Saccone case 0x1021:
1888*92022041SSam Saccone tab_on_first(&first);
1889*92022041SSam Saccone printf("\t * Manufacturer: %.*s\n", sublen, data + 4);
1890*92022041SSam Saccone break;
1891*92022041SSam Saccone case 0x1023:
1892*92022041SSam Saccone tab_on_first(&first);
1893*92022041SSam Saccone printf("\t * Model: %.*s\n", sublen, data + 4);
1894*92022041SSam Saccone break;
1895*92022041SSam Saccone case 0x1024:
1896*92022041SSam Saccone tab_on_first(&first);
1897*92022041SSam Saccone printf("\t * Model Number: %.*s\n", sublen, data + 4);
1898*92022041SSam Saccone break;
1899*92022041SSam Saccone case 0x103b: {
1900*92022041SSam Saccone __u8 val;
1901*92022041SSam Saccone
1902*92022041SSam Saccone if (sublen < 1) {
1903*92022041SSam Saccone printf("\t * Response Type: (invalid length %d)\n",
1904*92022041SSam Saccone sublen);
1905*92022041SSam Saccone break;
1906*92022041SSam Saccone }
1907*92022041SSam Saccone val = data[4];
1908*92022041SSam Saccone tab_on_first(&first);
1909*92022041SSam Saccone printf("\t * Response Type: %d%s\n",
1910*92022041SSam Saccone val, val == 3 ? " (AP)" : "");
1911*92022041SSam Saccone break;
1912*92022041SSam Saccone }
1913*92022041SSam Saccone case 0x103c: {
1914*92022041SSam Saccone __u8 val;
1915*92022041SSam Saccone
1916*92022041SSam Saccone if (sublen < 1) {
1917*92022041SSam Saccone printf("\t * RF Bands: (invalid length %d)\n",
1918*92022041SSam Saccone sublen);
1919*92022041SSam Saccone break;
1920*92022041SSam Saccone }
1921*92022041SSam Saccone val = data[4];
1922*92022041SSam Saccone tab_on_first(&first);
1923*92022041SSam Saccone printf("\t * RF Bands: 0x%x\n", val);
1924*92022041SSam Saccone break;
1925*92022041SSam Saccone }
1926*92022041SSam Saccone case 0x1041: {
1927*92022041SSam Saccone __u8 val;
1928*92022041SSam Saccone
1929*92022041SSam Saccone if (sublen < 1) {
1930*92022041SSam Saccone printf("\t * Selected Registrar: (invalid length %d)\n",
1931*92022041SSam Saccone sublen);
1932*92022041SSam Saccone break;
1933*92022041SSam Saccone }
1934*92022041SSam Saccone val = data[4];
1935*92022041SSam Saccone tab_on_first(&first);
1936*92022041SSam Saccone printf("\t * Selected Registrar: 0x%x\n", val);
1937*92022041SSam Saccone break;
1938*92022041SSam Saccone }
1939*92022041SSam Saccone case 0x1042:
1940*92022041SSam Saccone tab_on_first(&first);
1941*92022041SSam Saccone printf("\t * Serial Number: %.*s\n", sublen, data + 4);
1942*92022041SSam Saccone break;
1943*92022041SSam Saccone case 0x1044: {
1944*92022041SSam Saccone __u8 val;
1945*92022041SSam Saccone
1946*92022041SSam Saccone if (sublen < 1) {
1947*92022041SSam Saccone printf("\t * Wi-Fi Protected Setup State: (invalid length %d)\n",
1948*92022041SSam Saccone sublen);
1949*92022041SSam Saccone break;
1950*92022041SSam Saccone }
1951*92022041SSam Saccone val = data[4];
1952*92022041SSam Saccone tab_on_first(&first);
1953*92022041SSam Saccone printf("\t * Wi-Fi Protected Setup State: %d%s%s\n",
1954*92022041SSam Saccone val,
1955*92022041SSam Saccone val == 1 ? " (Unconfigured)" : "",
1956*92022041SSam Saccone val == 2 ? " (Configured)" : "");
1957*92022041SSam Saccone break;
1958*92022041SSam Saccone }
1959*92022041SSam Saccone case 0x1047:
1960*92022041SSam Saccone tab_on_first(&first);
1961*92022041SSam Saccone printf("\t * UUID: ");
1962*92022041SSam Saccone if (sublen != 16) {
1963*92022041SSam Saccone printf("(invalid, length=%d)\n", sublen);
1964*92022041SSam Saccone break;
1965*92022041SSam Saccone }
1966*92022041SSam Saccone printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
1967*92022041SSam Saccone "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
1968*92022041SSam Saccone data[4], data[5], data[6], data[7],
1969*92022041SSam Saccone data[8], data[9], data[10], data[11],
1970*92022041SSam Saccone data[12], data[13], data[14], data[15],
1971*92022041SSam Saccone data[16], data[17], data[18], data[19]);
1972*92022041SSam Saccone break;
1973*92022041SSam Saccone case 0x1049:
1974*92022041SSam Saccone tab_on_first(&first);
1975*92022041SSam Saccone if (sublen == 6 &&
1976*92022041SSam Saccone data[4] == 0x00 &&
1977*92022041SSam Saccone data[5] == 0x37 &&
1978*92022041SSam Saccone data[6] == 0x2a &&
1979*92022041SSam Saccone data[7] == 0x00 &&
1980*92022041SSam Saccone data[8] == 0x01) {
1981*92022041SSam Saccone uint8_t v2 = data[9];
1982*92022041SSam Saccone printf("\t * Version2: %d.%d\n", v2 >> 4, v2 & 0xf);
1983*92022041SSam Saccone } else {
1984*92022041SSam Saccone printf("\t * Unknown vendor extension. len=%u\n",
1985*92022041SSam Saccone sublen);
1986*92022041SSam Saccone }
1987*92022041SSam Saccone break;
1988*92022041SSam Saccone case 0x1054: {
1989*92022041SSam Saccone tab_on_first(&first);
1990*92022041SSam Saccone if (sublen != 8) {
1991*92022041SSam Saccone printf("\t * Primary Device Type: (invalid length %d)\n",
1992*92022041SSam Saccone sublen);
1993*92022041SSam Saccone break;
1994*92022041SSam Saccone }
1995*92022041SSam Saccone printf("\t * Primary Device Type: "
1996*92022041SSam Saccone "%u-%02x%02x%02x%02x-%u\n",
1997*92022041SSam Saccone data[4] << 8 | data[5],
1998*92022041SSam Saccone data[6], data[7], data[8], data[9],
1999*92022041SSam Saccone data[10] << 8 | data[11]);
2000*92022041SSam Saccone break;
2001*92022041SSam Saccone }
2002*92022041SSam Saccone case 0x1057: {
2003*92022041SSam Saccone __u8 val;
2004*92022041SSam Saccone tab_on_first(&first);
2005*92022041SSam Saccone if (sublen < 1) {
2006*92022041SSam Saccone printf("\t * AP setup locked: (invalid length %d)\n",
2007*92022041SSam Saccone sublen);
2008*92022041SSam Saccone break;
2009*92022041SSam Saccone }
2010*92022041SSam Saccone val = data[4];
2011*92022041SSam Saccone printf("\t * AP setup locked: 0x%.2x\n", val);
2012*92022041SSam Saccone break;
2013*92022041SSam Saccone }
2014*92022041SSam Saccone case 0x1008:
2015*92022041SSam Saccone case 0x1053: {
2016*92022041SSam Saccone __u16 meth;
2017*92022041SSam Saccone bool comma;
2018*92022041SSam Saccone
2019*92022041SSam Saccone if (sublen < 2) {
2020*92022041SSam Saccone printf("\t * Config methods: (invalid length %d)\n",
2021*92022041SSam Saccone sublen);
2022*92022041SSam Saccone break;
2023*92022041SSam Saccone }
2024*92022041SSam Saccone meth = (data[4] << 8) + data[5];
2025*92022041SSam Saccone comma = false;
2026*92022041SSam Saccone tab_on_first(&first);
2027*92022041SSam Saccone printf("\t * %sConfig methods:",
2028*92022041SSam Saccone subtype == 0x1053 ? "Selected Registrar ": "");
2029*92022041SSam Saccone #define T(bit, name) do { \
2030*92022041SSam Saccone if (meth & (1<<bit)) { \
2031*92022041SSam Saccone if (comma) \
2032*92022041SSam Saccone printf(","); \
2033*92022041SSam Saccone comma = true; \
2034*92022041SSam Saccone printf(" " name); \
2035*92022041SSam Saccone } } while (0)
2036*92022041SSam Saccone T(0, "USB");
2037*92022041SSam Saccone T(1, "Ethernet");
2038*92022041SSam Saccone T(2, "Label");
2039*92022041SSam Saccone T(3, "Display");
2040*92022041SSam Saccone T(4, "Ext. NFC");
2041*92022041SSam Saccone T(5, "Int. NFC");
2042*92022041SSam Saccone T(6, "NFC Intf.");
2043*92022041SSam Saccone T(7, "PBC");
2044*92022041SSam Saccone T(8, "Keypad");
2045*92022041SSam Saccone printf("\n");
2046*92022041SSam Saccone break;
2047*92022041SSam Saccone #undef T
2048*92022041SSam Saccone }
2049*92022041SSam Saccone default: {
2050*92022041SSam Saccone const __u8 *subdata = data + 4;
2051*92022041SSam Saccone __u16 tmplen = sublen;
2052*92022041SSam Saccone
2053*92022041SSam Saccone tab_on_first(&first);
2054*92022041SSam Saccone printf("\t * Unknown TLV (%#.4x, %d bytes):",
2055*92022041SSam Saccone subtype, tmplen);
2056*92022041SSam Saccone while (tmplen) {
2057*92022041SSam Saccone printf(" %.2x", *subdata);
2058*92022041SSam Saccone subdata++;
2059*92022041SSam Saccone tmplen--;
2060*92022041SSam Saccone }
2061*92022041SSam Saccone printf("\n");
2062*92022041SSam Saccone break;
2063*92022041SSam Saccone }
2064*92022041SSam Saccone }
2065*92022041SSam Saccone
2066*92022041SSam Saccone data += sublen + 4;
2067*92022041SSam Saccone len -= sublen + 4;
2068*92022041SSam Saccone }
2069*92022041SSam Saccone
2070*92022041SSam Saccone if (len != 0) {
2071*92022041SSam Saccone printf("\t\t * bogus tail data (%d):", len);
2072*92022041SSam Saccone while (len) {
2073*92022041SSam Saccone printf(" %.2x", *data);
2074*92022041SSam Saccone data++;
2075*92022041SSam Saccone len--;
2076*92022041SSam Saccone }
2077*92022041SSam Saccone printf("\n");
2078*92022041SSam Saccone }
2079*92022041SSam Saccone }
2080*92022041SSam Saccone
2081*92022041SSam Saccone static const struct ie_print wifiprinters[] = {
2082*92022041SSam Saccone [1] = { "WPA", print_wifi_wpa, 2, 255, BIT(PRINT_SCAN), },
2083*92022041SSam Saccone [2] = { "WMM", print_wifi_wmm, 1, 255, BIT(PRINT_SCAN), },
2084*92022041SSam Saccone [4] = { "WPS", print_wifi_wps, 0, 255, BIT(PRINT_SCAN), },
2085*92022041SSam Saccone };
2086*92022041SSam Saccone
print_p2p(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)2087*92022041SSam Saccone static inline void print_p2p(const uint8_t type, uint8_t len,
2088*92022041SSam Saccone const uint8_t *data,
2089*92022041SSam Saccone const struct print_ies_data *ie_buffer)
2090*92022041SSam Saccone {
2091*92022041SSam Saccone bool first = true;
2092*92022041SSam Saccone __u8 subtype;
2093*92022041SSam Saccone __u16 sublen;
2094*92022041SSam Saccone
2095*92022041SSam Saccone while (len >= 3) {
2096*92022041SSam Saccone subtype = data[0];
2097*92022041SSam Saccone sublen = (data[2] << 8) + data[1];
2098*92022041SSam Saccone
2099*92022041SSam Saccone if (sublen > len - 3)
2100*92022041SSam Saccone break;
2101*92022041SSam Saccone
2102*92022041SSam Saccone switch (subtype) {
2103*92022041SSam Saccone case 0x02: /* capability */
2104*92022041SSam Saccone tab_on_first(&first);
2105*92022041SSam Saccone if (sublen < 2) {
2106*92022041SSam Saccone printf("\t * malformed capability\n");
2107*92022041SSam Saccone break;
2108*92022041SSam Saccone }
2109*92022041SSam Saccone printf("\t * Group capa: 0x%.2x, Device capa: 0x%.2x\n",
2110*92022041SSam Saccone data[3], data[4]);
2111*92022041SSam Saccone break;
2112*92022041SSam Saccone case 0x0d: /* device info */
2113*92022041SSam Saccone if (sublen < 6 + 2 + 8 + 1) {
2114*92022041SSam Saccone printf("\t * malformed device info\n");
2115*92022041SSam Saccone break;
2116*92022041SSam Saccone }
2117*92022041SSam Saccone /* fall through */
2118*92022041SSam Saccone case 0x00: /* status */
2119*92022041SSam Saccone case 0x01: /* minor reason */
2120*92022041SSam Saccone case 0x03: /* device ID */
2121*92022041SSam Saccone case 0x04: /* GO intent */
2122*92022041SSam Saccone case 0x05: /* configuration timeout */
2123*92022041SSam Saccone case 0x06: /* listen channel */
2124*92022041SSam Saccone case 0x07: /* group BSSID */
2125*92022041SSam Saccone case 0x08: /* ext listen timing */
2126*92022041SSam Saccone case 0x09: /* intended interface address */
2127*92022041SSam Saccone case 0x0a: /* manageability */
2128*92022041SSam Saccone case 0x0b: /* channel list */
2129*92022041SSam Saccone case 0x0c: /* NoA */
2130*92022041SSam Saccone case 0x0e: /* group info */
2131*92022041SSam Saccone case 0x0f: /* group ID */
2132*92022041SSam Saccone case 0x10: /* interface */
2133*92022041SSam Saccone case 0x11: /* operating channel */
2134*92022041SSam Saccone case 0x12: /* invitation flags */
2135*92022041SSam Saccone case 0xdd: /* vendor specific */
2136*92022041SSam Saccone default: {
2137*92022041SSam Saccone const __u8 *subdata = data + 3;
2138*92022041SSam Saccone __u16 tmplen = sublen;
2139*92022041SSam Saccone
2140*92022041SSam Saccone tab_on_first(&first);
2141*92022041SSam Saccone printf("\t * Unknown TLV (%#.2x, %d bytes):",
2142*92022041SSam Saccone subtype, tmplen);
2143*92022041SSam Saccone while (tmplen) {
2144*92022041SSam Saccone printf(" %.2x", *subdata);
2145*92022041SSam Saccone subdata++;
2146*92022041SSam Saccone tmplen--;
2147*92022041SSam Saccone }
2148*92022041SSam Saccone printf("\n");
2149*92022041SSam Saccone break;
2150*92022041SSam Saccone }
2151*92022041SSam Saccone }
2152*92022041SSam Saccone
2153*92022041SSam Saccone data += sublen + 3;
2154*92022041SSam Saccone len -= sublen + 3;
2155*92022041SSam Saccone }
2156*92022041SSam Saccone
2157*92022041SSam Saccone if (len != 0) {
2158*92022041SSam Saccone tab_on_first(&first);
2159*92022041SSam Saccone printf("\t * bogus tail data (%d):", len);
2160*92022041SSam Saccone while (len) {
2161*92022041SSam Saccone printf(" %.2x", *data);
2162*92022041SSam Saccone data++;
2163*92022041SSam Saccone len--;
2164*92022041SSam Saccone }
2165*92022041SSam Saccone printf("\n");
2166*92022041SSam Saccone }
2167*92022041SSam Saccone }
2168*92022041SSam Saccone
print_hs20_ind(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)2169*92022041SSam Saccone static inline void print_hs20_ind(const uint8_t type, uint8_t len,
2170*92022041SSam Saccone const uint8_t *data,
2171*92022041SSam Saccone const struct print_ies_data *ie_buffer)
2172*92022041SSam Saccone {
2173*92022041SSam Saccone /* I can't find the spec for this...just going off what wireshark uses. */
2174*92022041SSam Saccone printf("\n");
2175*92022041SSam Saccone if (len > 0)
2176*92022041SSam Saccone printf("\t\tDGAF: %i\n", (int)(data[0] & 0x1));
2177*92022041SSam Saccone else
2178*92022041SSam Saccone printf("\t\tUnexpected length: %i\n", len);
2179*92022041SSam Saccone }
2180*92022041SSam Saccone
print_wifi_owe_tarns(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)2181*92022041SSam Saccone static void print_wifi_owe_tarns(const uint8_t type, uint8_t len,
2182*92022041SSam Saccone const uint8_t *data,
2183*92022041SSam Saccone const struct print_ies_data *ie_buffer)
2184*92022041SSam Saccone {
2185*92022041SSam Saccone char mac_addr[20];
2186*92022041SSam Saccone int ssid_len;
2187*92022041SSam Saccone
2188*92022041SSam Saccone printf("\n");
2189*92022041SSam Saccone if (len < 7)
2190*92022041SSam Saccone return;
2191*92022041SSam Saccone
2192*92022041SSam Saccone mac_addr_n2a(mac_addr, data);
2193*92022041SSam Saccone printf("\t\tBSSID: %s\n", mac_addr);
2194*92022041SSam Saccone
2195*92022041SSam Saccone ssid_len = data[6];
2196*92022041SSam Saccone if (ssid_len > len - 7)
2197*92022041SSam Saccone return;
2198*92022041SSam Saccone printf("\t\tSSID: ");
2199*92022041SSam Saccone print_ssid_escaped(ssid_len, data + 7);
2200*92022041SSam Saccone printf("\n");
2201*92022041SSam Saccone
2202*92022041SSam Saccone /* optional elements */
2203*92022041SSam Saccone if (len >= ssid_len + 9) {
2204*92022041SSam Saccone printf("\t\tBand Info: %u\n", data[ssid_len + 7]);
2205*92022041SSam Saccone printf("\t\tChannel Info: %u\n", data[ssid_len + 8]);
2206*92022041SSam Saccone }
2207*92022041SSam Saccone }
2208*92022041SSam Saccone
2209*92022041SSam Saccone static const struct ie_print wfa_printers[] = {
2210*92022041SSam Saccone [9] = { "P2P", print_p2p, 2, 255, BIT(PRINT_SCAN), },
2211*92022041SSam Saccone [16] = { "HotSpot 2.0 Indication", print_hs20_ind, 1, 255, BIT(PRINT_SCAN), },
2212*92022041SSam Saccone [18] = { "HotSpot 2.0 OSEN", print_wifi_osen, 1, 255, BIT(PRINT_SCAN), },
2213*92022041SSam Saccone [28] = { "OWE Transition Mode", print_wifi_owe_tarns, 7, 255, BIT(PRINT_SCAN), },
2214*92022041SSam Saccone };
2215*92022041SSam Saccone
print_vendor(unsigned char len,unsigned char * data,bool unknown,enum print_ie_type ptype)2216*92022041SSam Saccone static void print_vendor(unsigned char len, unsigned char *data,
2217*92022041SSam Saccone bool unknown, enum print_ie_type ptype)
2218*92022041SSam Saccone {
2219*92022041SSam Saccone int i;
2220*92022041SSam Saccone
2221*92022041SSam Saccone if (len < 3) {
2222*92022041SSam Saccone printf("\tVendor specific: <too short> data:");
2223*92022041SSam Saccone for(i = 0; i < len; i++)
2224*92022041SSam Saccone printf(" %.02x", data[i]);
2225*92022041SSam Saccone printf("\n");
2226*92022041SSam Saccone return;
2227*92022041SSam Saccone }
2228*92022041SSam Saccone
2229*92022041SSam Saccone if (len >= 4 && memcmp(data, ms_oui, 3) == 0) {
2230*92022041SSam Saccone if (data[3] < ARRAY_SIZE(wifiprinters) &&
2231*92022041SSam Saccone wifiprinters[data[3]].name &&
2232*92022041SSam Saccone wifiprinters[data[3]].flags & BIT(ptype)) {
2233*92022041SSam Saccone print_ie(&wifiprinters[data[3]],
2234*92022041SSam Saccone data[3], len - 4, data + 4,
2235*92022041SSam Saccone NULL);
2236*92022041SSam Saccone return;
2237*92022041SSam Saccone }
2238*92022041SSam Saccone if (!unknown)
2239*92022041SSam Saccone return;
2240*92022041SSam Saccone printf("\tMS/WiFi %#.2x, data:", data[3]);
2241*92022041SSam Saccone for(i = 0; i < len - 4; i++)
2242*92022041SSam Saccone printf(" %.02x", data[i + 4]);
2243*92022041SSam Saccone printf("\n");
2244*92022041SSam Saccone return;
2245*92022041SSam Saccone }
2246*92022041SSam Saccone
2247*92022041SSam Saccone if (len >= 4 && memcmp(data, wfa_oui, 3) == 0) {
2248*92022041SSam Saccone if (data[3] < ARRAY_SIZE(wfa_printers) &&
2249*92022041SSam Saccone wfa_printers[data[3]].name &&
2250*92022041SSam Saccone wfa_printers[data[3]].flags & BIT(ptype)) {
2251*92022041SSam Saccone print_ie(&wfa_printers[data[3]],
2252*92022041SSam Saccone data[3], len - 4, data + 4,
2253*92022041SSam Saccone NULL);
2254*92022041SSam Saccone return;
2255*92022041SSam Saccone }
2256*92022041SSam Saccone if (!unknown)
2257*92022041SSam Saccone return;
2258*92022041SSam Saccone printf("\tWFA %#.2x, data:", data[3]);
2259*92022041SSam Saccone for(i = 0; i < len - 4; i++)
2260*92022041SSam Saccone printf(" %.02x", data[i + 4]);
2261*92022041SSam Saccone printf("\n");
2262*92022041SSam Saccone return;
2263*92022041SSam Saccone }
2264*92022041SSam Saccone
2265*92022041SSam Saccone if (!unknown)
2266*92022041SSam Saccone return;
2267*92022041SSam Saccone
2268*92022041SSam Saccone printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:",
2269*92022041SSam Saccone data[0], data[1], data[2]);
2270*92022041SSam Saccone for (i = 3; i < len; i++)
2271*92022041SSam Saccone printf(" %.2x", data[i]);
2272*92022041SSam Saccone printf("\n");
2273*92022041SSam Saccone }
2274*92022041SSam Saccone
print_he_capa(const uint8_t type,uint8_t len,const uint8_t * data,const struct print_ies_data * ie_buffer)2275*92022041SSam Saccone static void print_he_capa(const uint8_t type, uint8_t len, const uint8_t *data,
2276*92022041SSam Saccone const struct print_ies_data *ie_buffer)
2277*92022041SSam Saccone {
2278*92022041SSam Saccone printf("\n");
2279*92022041SSam Saccone print_he_capability(data, len);
2280*92022041SSam Saccone }
2281*92022041SSam Saccone
2282*92022041SSam Saccone static const struct ie_print ext_printers[] = {
2283*92022041SSam Saccone [35] = { "HE capabilities", print_he_capa, 21, 54, BIT(PRINT_SCAN), },
2284*92022041SSam Saccone };
2285*92022041SSam Saccone
print_extension(unsigned char len,unsigned char * ie,bool unknown,enum print_ie_type ptype)2286*92022041SSam Saccone static void print_extension(unsigned char len, unsigned char *ie,
2287*92022041SSam Saccone bool unknown, enum print_ie_type ptype)
2288*92022041SSam Saccone {
2289*92022041SSam Saccone unsigned char tag;
2290*92022041SSam Saccone
2291*92022041SSam Saccone if (len < 1) {
2292*92022041SSam Saccone printf("\tExtension IE: <empty>\n");
2293*92022041SSam Saccone return;
2294*92022041SSam Saccone }
2295*92022041SSam Saccone
2296*92022041SSam Saccone tag = ie[0];
2297*92022041SSam Saccone if (tag < ARRAY_SIZE(ext_printers) && ext_printers[tag].name &&
2298*92022041SSam Saccone ext_printers[tag].flags & BIT(ptype)) {
2299*92022041SSam Saccone print_ie(&ext_printers[tag], tag, len - 1, ie + 1, NULL);
2300*92022041SSam Saccone return;
2301*92022041SSam Saccone }
2302*92022041SSam Saccone
2303*92022041SSam Saccone if (unknown) {
2304*92022041SSam Saccone int i;
2305*92022041SSam Saccone
2306*92022041SSam Saccone printf("\tUnknown Extension ID (%d):", ie[0]);
2307*92022041SSam Saccone for (i = 1; i < len; i++)
2308*92022041SSam Saccone printf(" %.2x", ie[i]);
2309*92022041SSam Saccone printf("\n");
2310*92022041SSam Saccone }
2311*92022041SSam Saccone }
2312*92022041SSam Saccone
print_ies(unsigned char * ie,int ielen,bool unknown,enum print_ie_type ptype)2313*92022041SSam Saccone void print_ies(unsigned char *ie, int ielen, bool unknown,
2314*92022041SSam Saccone enum print_ie_type ptype)
2315*92022041SSam Saccone {
2316*92022041SSam Saccone struct print_ies_data ie_buffer = {
2317*92022041SSam Saccone .ie = ie,
2318*92022041SSam Saccone .ielen = ielen };
2319*92022041SSam Saccone
2320*92022041SSam Saccone if (ie == NULL || ielen < 0)
2321*92022041SSam Saccone return;
2322*92022041SSam Saccone
2323*92022041SSam Saccone while (ielen >= 2 && ielen - 2 >= ie[1]) {
2324*92022041SSam Saccone if (ie[0] < ARRAY_SIZE(ieprinters) &&
2325*92022041SSam Saccone ieprinters[ie[0]].name &&
2326*92022041SSam Saccone ieprinters[ie[0]].flags & BIT(ptype)) {
2327*92022041SSam Saccone print_ie(&ieprinters[ie[0]],
2328*92022041SSam Saccone ie[0], ie[1], ie + 2, &ie_buffer);
2329*92022041SSam Saccone } else if (ie[0] == 221 /* vendor */) {
2330*92022041SSam Saccone print_vendor(ie[1], ie + 2, unknown, ptype);
2331*92022041SSam Saccone } else if (ie[0] == 255 /* extension */) {
2332*92022041SSam Saccone print_extension(ie[1], ie + 2, unknown, ptype);
2333*92022041SSam Saccone } else if (unknown) {
2334*92022041SSam Saccone int i;
2335*92022041SSam Saccone
2336*92022041SSam Saccone printf("\tUnknown IE (%d):", ie[0]);
2337*92022041SSam Saccone for (i=0; i<ie[1]; i++)
2338*92022041SSam Saccone printf(" %.2x", ie[2+i]);
2339*92022041SSam Saccone printf("\n");
2340*92022041SSam Saccone }
2341*92022041SSam Saccone ielen -= ie[1] + 2;
2342*92022041SSam Saccone ie += ie[1] + 2;
2343*92022041SSam Saccone }
2344*92022041SSam Saccone }
2345*92022041SSam Saccone
print_capa_dmg(__u16 capa)2346*92022041SSam Saccone static void print_capa_dmg(__u16 capa)
2347*92022041SSam Saccone {
2348*92022041SSam Saccone switch (capa & WLAN_CAPABILITY_DMG_TYPE_MASK) {
2349*92022041SSam Saccone case WLAN_CAPABILITY_DMG_TYPE_AP:
2350*92022041SSam Saccone printf(" DMG_ESS");
2351*92022041SSam Saccone break;
2352*92022041SSam Saccone case WLAN_CAPABILITY_DMG_TYPE_PBSS:
2353*92022041SSam Saccone printf(" DMG_PCP");
2354*92022041SSam Saccone break;
2355*92022041SSam Saccone case WLAN_CAPABILITY_DMG_TYPE_IBSS:
2356*92022041SSam Saccone printf(" DMG_IBSS");
2357*92022041SSam Saccone break;
2358*92022041SSam Saccone }
2359*92022041SSam Saccone
2360*92022041SSam Saccone if (capa & WLAN_CAPABILITY_DMG_CBAP_ONLY)
2361*92022041SSam Saccone printf(" CBAP_Only");
2362*92022041SSam Saccone if (capa & WLAN_CAPABILITY_DMG_CBAP_SOURCE)
2363*92022041SSam Saccone printf(" CBAP_Src");
2364*92022041SSam Saccone if (capa & WLAN_CAPABILITY_DMG_PRIVACY)
2365*92022041SSam Saccone printf(" Privacy");
2366*92022041SSam Saccone if (capa & WLAN_CAPABILITY_DMG_ECPAC)
2367*92022041SSam Saccone printf(" ECPAC");
2368*92022041SSam Saccone if (capa & WLAN_CAPABILITY_DMG_SPECTRUM_MGMT)
2369*92022041SSam Saccone printf(" SpectrumMgmt");
2370*92022041SSam Saccone if (capa & WLAN_CAPABILITY_DMG_RADIO_MEASURE)
2371*92022041SSam Saccone printf(" RadioMeasure");
2372*92022041SSam Saccone }
2373*92022041SSam Saccone
print_capa_non_dmg(__u16 capa)2374*92022041SSam Saccone static void print_capa_non_dmg(__u16 capa)
2375*92022041SSam Saccone {
2376*92022041SSam Saccone if (capa & WLAN_CAPABILITY_ESS)
2377*92022041SSam Saccone printf(" ESS");
2378*92022041SSam Saccone if (capa & WLAN_CAPABILITY_IBSS)
2379*92022041SSam Saccone printf(" IBSS");
2380*92022041SSam Saccone if (capa & WLAN_CAPABILITY_CF_POLLABLE)
2381*92022041SSam Saccone printf(" CfPollable");
2382*92022041SSam Saccone if (capa & WLAN_CAPABILITY_CF_POLL_REQUEST)
2383*92022041SSam Saccone printf(" CfPollReq");
2384*92022041SSam Saccone if (capa & WLAN_CAPABILITY_PRIVACY)
2385*92022041SSam Saccone printf(" Privacy");
2386*92022041SSam Saccone if (capa & WLAN_CAPABILITY_SHORT_PREAMBLE)
2387*92022041SSam Saccone printf(" ShortPreamble");
2388*92022041SSam Saccone if (capa & WLAN_CAPABILITY_PBCC)
2389*92022041SSam Saccone printf(" PBCC");
2390*92022041SSam Saccone if (capa & WLAN_CAPABILITY_CHANNEL_AGILITY)
2391*92022041SSam Saccone printf(" ChannelAgility");
2392*92022041SSam Saccone if (capa & WLAN_CAPABILITY_SPECTRUM_MGMT)
2393*92022041SSam Saccone printf(" SpectrumMgmt");
2394*92022041SSam Saccone if (capa & WLAN_CAPABILITY_QOS)
2395*92022041SSam Saccone printf(" QoS");
2396*92022041SSam Saccone if (capa & WLAN_CAPABILITY_SHORT_SLOT_TIME)
2397*92022041SSam Saccone printf(" ShortSlotTime");
2398*92022041SSam Saccone if (capa & WLAN_CAPABILITY_APSD)
2399*92022041SSam Saccone printf(" APSD");
2400*92022041SSam Saccone if (capa & WLAN_CAPABILITY_RADIO_MEASURE)
2401*92022041SSam Saccone printf(" RadioMeasure");
2402*92022041SSam Saccone if (capa & WLAN_CAPABILITY_DSSS_OFDM)
2403*92022041SSam Saccone printf(" DSSS-OFDM");
2404*92022041SSam Saccone if (capa & WLAN_CAPABILITY_DEL_BACK)
2405*92022041SSam Saccone printf(" DelayedBACK");
2406*92022041SSam Saccone if (capa & WLAN_CAPABILITY_IMM_BACK)
2407*92022041SSam Saccone printf(" ImmediateBACK");
2408*92022041SSam Saccone }
2409*92022041SSam Saccone
print_bss_handler(struct nl_msg * msg,void * arg)2410*92022041SSam Saccone static int print_bss_handler(struct nl_msg *msg, void *arg)
2411*92022041SSam Saccone {
2412*92022041SSam Saccone struct nlattr *tb[NL80211_ATTR_MAX + 1];
2413*92022041SSam Saccone struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
2414*92022041SSam Saccone struct nlattr *bss[NL80211_BSS_MAX + 1];
2415*92022041SSam Saccone char mac_addr[20], dev[20];
2416*92022041SSam Saccone static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
2417*92022041SSam Saccone [NL80211_BSS_TSF] = { .type = NLA_U64 },
2418*92022041SSam Saccone [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
2419*92022041SSam Saccone [NL80211_BSS_BSSID] = { },
2420*92022041SSam Saccone [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
2421*92022041SSam Saccone [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
2422*92022041SSam Saccone [NL80211_BSS_INFORMATION_ELEMENTS] = { },
2423*92022041SSam Saccone [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
2424*92022041SSam Saccone [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
2425*92022041SSam Saccone [NL80211_BSS_STATUS] = { .type = NLA_U32 },
2426*92022041SSam Saccone [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
2427*92022041SSam Saccone [NL80211_BSS_BEACON_IES] = { },
2428*92022041SSam Saccone };
2429*92022041SSam Saccone struct scan_params *params = arg;
2430*92022041SSam Saccone int show = params->show_both_ie_sets ? 2 : 1;
2431*92022041SSam Saccone bool is_dmg = false;
2432*92022041SSam Saccone
2433*92022041SSam Saccone nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
2434*92022041SSam Saccone genlmsg_attrlen(gnlh, 0), NULL);
2435*92022041SSam Saccone
2436*92022041SSam Saccone if (!tb[NL80211_ATTR_BSS]) {
2437*92022041SSam Saccone fprintf(stderr, "bss info missing!\n");
2438*92022041SSam Saccone return NL_SKIP;
2439*92022041SSam Saccone }
2440*92022041SSam Saccone if (nla_parse_nested(bss, NL80211_BSS_MAX,
2441*92022041SSam Saccone tb[NL80211_ATTR_BSS],
2442*92022041SSam Saccone bss_policy)) {
2443*92022041SSam Saccone fprintf(stderr, "failed to parse nested attributes!\n");
2444*92022041SSam Saccone return NL_SKIP;
2445*92022041SSam Saccone }
2446*92022041SSam Saccone
2447*92022041SSam Saccone if (!bss[NL80211_BSS_BSSID])
2448*92022041SSam Saccone return NL_SKIP;
2449*92022041SSam Saccone
2450*92022041SSam Saccone mac_addr_n2a(mac_addr, nla_data(bss[NL80211_BSS_BSSID]));
2451*92022041SSam Saccone printf("BSS %s", mac_addr);
2452*92022041SSam Saccone if (tb[NL80211_ATTR_IFINDEX]) {
2453*92022041SSam Saccone if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
2454*92022041SSam Saccone printf("(on %s)", dev);
2455*92022041SSam Saccone }
2456*92022041SSam Saccone
2457*92022041SSam Saccone if (bss[NL80211_BSS_STATUS]) {
2458*92022041SSam Saccone switch (nla_get_u32(bss[NL80211_BSS_STATUS])) {
2459*92022041SSam Saccone case NL80211_BSS_STATUS_AUTHENTICATED:
2460*92022041SSam Saccone printf(" -- authenticated");
2461*92022041SSam Saccone break;
2462*92022041SSam Saccone case NL80211_BSS_STATUS_ASSOCIATED:
2463*92022041SSam Saccone printf(" -- associated");
2464*92022041SSam Saccone break;
2465*92022041SSam Saccone case NL80211_BSS_STATUS_IBSS_JOINED:
2466*92022041SSam Saccone printf(" -- joined");
2467*92022041SSam Saccone break;
2468*92022041SSam Saccone default:
2469*92022041SSam Saccone printf(" -- unknown status: %d",
2470*92022041SSam Saccone nla_get_u32(bss[NL80211_BSS_STATUS]));
2471*92022041SSam Saccone break;
2472*92022041SSam Saccone }
2473*92022041SSam Saccone }
2474*92022041SSam Saccone printf("\n");
2475*92022041SSam Saccone
2476*92022041SSam Saccone if (bss[NL80211_BSS_LAST_SEEN_BOOTTIME]) {
2477*92022041SSam Saccone unsigned long long bt;
2478*92022041SSam Saccone bt = (unsigned long long)nla_get_u64(bss[NL80211_BSS_LAST_SEEN_BOOTTIME]);
2479*92022041SSam Saccone printf("\tlast seen: %llu.%.3llus [boottime]\n", bt/1000000000, (bt%1000000000)/1000000);
2480*92022041SSam Saccone }
2481*92022041SSam Saccone
2482*92022041SSam Saccone if (bss[NL80211_BSS_TSF]) {
2483*92022041SSam Saccone unsigned long long tsf;
2484*92022041SSam Saccone tsf = (unsigned long long)nla_get_u64(bss[NL80211_BSS_TSF]);
2485*92022041SSam Saccone printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n",
2486*92022041SSam Saccone tsf, tsf/1000/1000/60/60/24, (tsf/1000/1000/60/60) % 24,
2487*92022041SSam Saccone (tsf/1000/1000/60) % 60, (tsf/1000/1000) % 60);
2488*92022041SSam Saccone }
2489*92022041SSam Saccone if (bss[NL80211_BSS_FREQUENCY]) {
2490*92022041SSam Saccone int freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
2491*92022041SSam Saccone printf("\tfreq: %d\n", freq);
2492*92022041SSam Saccone if (freq > 45000)
2493*92022041SSam Saccone is_dmg = true;
2494*92022041SSam Saccone }
2495*92022041SSam Saccone if (bss[NL80211_BSS_BEACON_INTERVAL])
2496*92022041SSam Saccone printf("\tbeacon interval: %d TUs\n",
2497*92022041SSam Saccone nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]));
2498*92022041SSam Saccone if (bss[NL80211_BSS_CAPABILITY]) {
2499*92022041SSam Saccone __u16 capa = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
2500*92022041SSam Saccone printf("\tcapability:");
2501*92022041SSam Saccone if (is_dmg)
2502*92022041SSam Saccone print_capa_dmg(capa);
2503*92022041SSam Saccone else
2504*92022041SSam Saccone print_capa_non_dmg(capa);
2505*92022041SSam Saccone printf(" (0x%.4x)\n", capa);
2506*92022041SSam Saccone }
2507*92022041SSam Saccone if (bss[NL80211_BSS_SIGNAL_MBM]) {
2508*92022041SSam Saccone int s = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
2509*92022041SSam Saccone printf("\tsignal: %d.%.2d dBm\n", s/100, s%100);
2510*92022041SSam Saccone }
2511*92022041SSam Saccone if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
2512*92022041SSam Saccone unsigned char s = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
2513*92022041SSam Saccone printf("\tsignal: %d/100\n", s);
2514*92022041SSam Saccone }
2515*92022041SSam Saccone if (bss[NL80211_BSS_SEEN_MS_AGO]) {
2516*92022041SSam Saccone int age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
2517*92022041SSam Saccone printf("\tlast seen: %d ms ago\n", age);
2518*92022041SSam Saccone }
2519*92022041SSam Saccone
2520*92022041SSam Saccone if (bss[NL80211_BSS_INFORMATION_ELEMENTS] && show--) {
2521*92022041SSam Saccone struct nlattr *ies = bss[NL80211_BSS_INFORMATION_ELEMENTS];
2522*92022041SSam Saccone struct nlattr *bcnies = bss[NL80211_BSS_BEACON_IES];
2523*92022041SSam Saccone
2524*92022041SSam Saccone if (bss[NL80211_BSS_PRESP_DATA] ||
2525*92022041SSam Saccone (bcnies && (nla_len(ies) != nla_len(bcnies) ||
2526*92022041SSam Saccone memcmp(nla_data(ies), nla_data(bcnies),
2527*92022041SSam Saccone nla_len(ies)))))
2528*92022041SSam Saccone printf("\tInformation elements from Probe Response "
2529*92022041SSam Saccone "frame:\n");
2530*92022041SSam Saccone print_ies(nla_data(ies), nla_len(ies),
2531*92022041SSam Saccone params->unknown, params->type);
2532*92022041SSam Saccone }
2533*92022041SSam Saccone if (bss[NL80211_BSS_BEACON_IES] && show--) {
2534*92022041SSam Saccone printf("\tInformation elements from Beacon frame:\n");
2535*92022041SSam Saccone print_ies(nla_data(bss[NL80211_BSS_BEACON_IES]),
2536*92022041SSam Saccone nla_len(bss[NL80211_BSS_BEACON_IES]),
2537*92022041SSam Saccone params->unknown, params->type);
2538*92022041SSam Saccone }
2539*92022041SSam Saccone
2540*92022041SSam Saccone return NL_SKIP;
2541*92022041SSam Saccone }
2542*92022041SSam Saccone
2543*92022041SSam Saccone static struct scan_params scan_params;
2544*92022041SSam Saccone
handle_scan_dump(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)2545*92022041SSam Saccone static int handle_scan_dump(struct nl80211_state *state,
2546*92022041SSam Saccone struct nl_msg *msg,
2547*92022041SSam Saccone int argc, char **argv,
2548*92022041SSam Saccone enum id_input id)
2549*92022041SSam Saccone {
2550*92022041SSam Saccone if (argc > 1)
2551*92022041SSam Saccone return 1;
2552*92022041SSam Saccone
2553*92022041SSam Saccone memset(&scan_params, 0, sizeof(scan_params));
2554*92022041SSam Saccone
2555*92022041SSam Saccone if (argc == 1 && !strcmp(argv[0], "-u"))
2556*92022041SSam Saccone scan_params.unknown = true;
2557*92022041SSam Saccone else if (argc == 1 && !strcmp(argv[0], "-b"))
2558*92022041SSam Saccone scan_params.show_both_ie_sets = true;
2559*92022041SSam Saccone
2560*92022041SSam Saccone scan_params.type = PRINT_SCAN;
2561*92022041SSam Saccone
2562*92022041SSam Saccone register_handler(print_bss_handler, &scan_params);
2563*92022041SSam Saccone return 0;
2564*92022041SSam Saccone }
2565*92022041SSam Saccone
handle_scan_combined(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)2566*92022041SSam Saccone static int handle_scan_combined(struct nl80211_state *state,
2567*92022041SSam Saccone struct nl_msg *msg,
2568*92022041SSam Saccone int argc, char **argv,
2569*92022041SSam Saccone enum id_input id)
2570*92022041SSam Saccone {
2571*92022041SSam Saccone char **trig_argv;
2572*92022041SSam Saccone static char *dump_argv[] = {
2573*92022041SSam Saccone NULL,
2574*92022041SSam Saccone "scan",
2575*92022041SSam Saccone "dump",
2576*92022041SSam Saccone NULL,
2577*92022041SSam Saccone };
2578*92022041SSam Saccone static const __u32 cmds[] = {
2579*92022041SSam Saccone NL80211_CMD_NEW_SCAN_RESULTS,
2580*92022041SSam Saccone NL80211_CMD_SCAN_ABORTED,
2581*92022041SSam Saccone };
2582*92022041SSam Saccone int trig_argc, dump_argc, err;
2583*92022041SSam Saccone int i;
2584*92022041SSam Saccone
2585*92022041SSam Saccone if (argc >= 3 && !strcmp(argv[2], "-u")) {
2586*92022041SSam Saccone dump_argc = 4;
2587*92022041SSam Saccone dump_argv[3] = "-u";
2588*92022041SSam Saccone } else if (argc >= 3 && !strcmp(argv[2], "-b")) {
2589*92022041SSam Saccone dump_argc = 4;
2590*92022041SSam Saccone dump_argv[3] = "-b";
2591*92022041SSam Saccone } else
2592*92022041SSam Saccone dump_argc = 3;
2593*92022041SSam Saccone
2594*92022041SSam Saccone trig_argc = 3 + (argc - 2) + (3 - dump_argc);
2595*92022041SSam Saccone trig_argv = calloc(trig_argc, sizeof(*trig_argv));
2596*92022041SSam Saccone if (!trig_argv)
2597*92022041SSam Saccone return -ENOMEM;
2598*92022041SSam Saccone trig_argv[0] = argv[0];
2599*92022041SSam Saccone trig_argv[1] = "scan";
2600*92022041SSam Saccone trig_argv[2] = "trigger";
2601*92022041SSam Saccone
2602*92022041SSam Saccone for (i = 0; i < argc - 2 - (dump_argc - 3); i++)
2603*92022041SSam Saccone trig_argv[i + 3] = argv[i + 2 + (dump_argc - 3)];
2604*92022041SSam Saccone err = handle_cmd(state, id, trig_argc, trig_argv);
2605*92022041SSam Saccone free(trig_argv);
2606*92022041SSam Saccone if (err)
2607*92022041SSam Saccone return err;
2608*92022041SSam Saccone
2609*92022041SSam Saccone /*
2610*92022041SSam Saccone * WARNING: DO NOT COPY THIS CODE INTO YOUR APPLICATION
2611*92022041SSam Saccone *
2612*92022041SSam Saccone * This code has a bug, which requires creating a separate
2613*92022041SSam Saccone * nl80211 socket to fix:
2614*92022041SSam Saccone * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or
2615*92022041SSam Saccone * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel
2616*92022041SSam Saccone * before (!) we listen to it, because we only start listening
2617*92022041SSam Saccone * after we send our scan request.
2618*92022041SSam Saccone *
2619*92022041SSam Saccone * Doing it the other way around has a race condition as well,
2620*92022041SSam Saccone * if you first open the events socket you may get a notification
2621*92022041SSam Saccone * for a previous scan.
2622*92022041SSam Saccone *
2623*92022041SSam Saccone * The only proper way to fix this would be to listen to events
2624*92022041SSam Saccone * before sending the command, and for the kernel to send the
2625*92022041SSam Saccone * scan request along with the event, so that you can match up
2626*92022041SSam Saccone * whether the scan you requested was finished or aborted (this
2627*92022041SSam Saccone * may result in processing a scan that another application
2628*92022041SSam Saccone * requested, but that doesn't seem to be a problem).
2629*92022041SSam Saccone *
2630*92022041SSam Saccone * Alas, the kernel doesn't do that (yet).
2631*92022041SSam Saccone */
2632*92022041SSam Saccone
2633*92022041SSam Saccone if (listen_events(state, ARRAY_SIZE(cmds), cmds) ==
2634*92022041SSam Saccone NL80211_CMD_SCAN_ABORTED) {
2635*92022041SSam Saccone printf("scan aborted!\n");
2636*92022041SSam Saccone return 0;
2637*92022041SSam Saccone }
2638*92022041SSam Saccone
2639*92022041SSam Saccone dump_argv[0] = argv[0];
2640*92022041SSam Saccone return handle_cmd(state, id, dump_argc, dump_argv);
2641*92022041SSam Saccone }
2642*92022041SSam Saccone TOPLEVEL(scan, "[-u] [freq <freq>*] [duration <dur>] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force,duration-mandatory] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]", 0, 0,
2643*92022041SSam Saccone CIB_NETDEV, handle_scan_combined,
2644*92022041SSam Saccone "Scan on the given frequencies and probe for the given SSIDs\n"
2645*92022041SSam Saccone "(or wildcard if not given) unless passive scanning is requested.\n"
2646*92022041SSam Saccone "If -u is specified print unknown data in the scan results.\n"
2647*92022041SSam Saccone "Specified (vendor) IEs must be well-formed.");
2648*92022041SSam Saccone COMMAND(scan, dump, "[-u]",
2649*92022041SSam Saccone NL80211_CMD_GET_SCAN, NLM_F_DUMP, CIB_NETDEV, handle_scan_dump,
2650*92022041SSam Saccone "Dump the current scan results. If -u is specified, print unknown\n"
2651*92022041SSam Saccone "data in scan results.");
2652*92022041SSam Saccone COMMAND(scan, trigger, "[freq <freq>*] [duration <dur>] [ies <hex as 00:11:..>] [meshid <meshid>] [lowpri,flush,ap-force,duration-mandatory,coloc] [randomise[=<addr>/<mask>]] [ssid <ssid>*|passive]",
2653*92022041SSam Saccone NL80211_CMD_TRIGGER_SCAN, 0, CIB_NETDEV, handle_scan,
2654*92022041SSam Saccone "Trigger a scan on the given frequencies with probing for the given\n"
2655*92022041SSam Saccone "SSIDs (or wildcard if not given) unless passive scanning is requested.\n"
2656*92022041SSam Saccone "Duration(in TUs), if specified, will be used to set dwell times.\n");
2657*92022041SSam Saccone
2658*92022041SSam Saccone
handle_scan_abort(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)2659*92022041SSam Saccone static int handle_scan_abort(struct nl80211_state *state,
2660*92022041SSam Saccone struct nl_msg *msg,
2661*92022041SSam Saccone int argc, char **argv,
2662*92022041SSam Saccone enum id_input id)
2663*92022041SSam Saccone {
2664*92022041SSam Saccone return 0;
2665*92022041SSam Saccone }
2666*92022041SSam Saccone COMMAND(scan, abort, "",
2667*92022041SSam Saccone NL80211_CMD_ABORT_SCAN, 0, CIB_NETDEV, handle_scan_abort,
2668*92022041SSam Saccone "Abort ongoing scan");
2669*92022041SSam Saccone
handle_start_sched_scan(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)2670*92022041SSam Saccone static int handle_start_sched_scan(struct nl80211_state *state,
2671*92022041SSam Saccone struct nl_msg *msg,
2672*92022041SSam Saccone int argc, char **argv, enum id_input id)
2673*92022041SSam Saccone {
2674*92022041SSam Saccone return parse_sched_scan(msg, &argc, &argv);
2675*92022041SSam Saccone }
2676*92022041SSam Saccone
handle_stop_sched_scan(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)2677*92022041SSam Saccone static int handle_stop_sched_scan(struct nl80211_state *state,
2678*92022041SSam Saccone struct nl_msg *msg, int argc, char **argv,
2679*92022041SSam Saccone enum id_input id)
2680*92022041SSam Saccone {
2681*92022041SSam Saccone if (argc != 0)
2682*92022041SSam Saccone return 1;
2683*92022041SSam Saccone
2684*92022041SSam Saccone return 0;
2685*92022041SSam Saccone }
2686*92022041SSam Saccone
2687*92022041SSam Saccone COMMAND(scan, sched_start,
2688*92022041SSam Saccone SCHED_SCAN_OPTIONS,
2689*92022041SSam Saccone NL80211_CMD_START_SCHED_SCAN, 0, CIB_NETDEV, handle_start_sched_scan,
2690*92022041SSam Saccone "Start a scheduled scan at the specified interval on the given frequencies\n"
2691*92022041SSam Saccone "with probing for the given SSIDs (or wildcard if not given) unless passive\n"
2692*92022041SSam Saccone "scanning is requested. If matches are specified, only matching results\n"
2693*92022041SSam Saccone "will be returned.");
2694*92022041SSam Saccone COMMAND(scan, sched_stop, "",
2695*92022041SSam Saccone NL80211_CMD_STOP_SCHED_SCAN, 0, CIB_NETDEV, handle_stop_sched_scan,
2696*92022041SSam Saccone "Stop an ongoing scheduled scan.");
2697