1*cb21588bSguenther /* $OpenBSD: print-802_11.c,v 1.11 2019/05/10 01:29:31 guenther Exp $ */
250ce650fSreyk
350ce650fSreyk /*
42c56d0d6Sreyk * Copyright (c) 2005 Reyk Floeter <reyk@openbsd.org>
550ce650fSreyk *
650ce650fSreyk * Permission to use, copy, modify, and distribute this software for any
750ce650fSreyk * purpose with or without fee is hereby granted, provided that the above
850ce650fSreyk * copyright notice and this permission notice appear in all copies.
950ce650fSreyk *
1050ce650fSreyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1150ce650fSreyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1250ce650fSreyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1350ce650fSreyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1450ce650fSreyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1550ce650fSreyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1650ce650fSreyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1750ce650fSreyk */
1850ce650fSreyk
1950ce650fSreyk /* usr.sbin/tcpdump/print-802_11.c,v 1.3 2005/03/09 11:43:17 deraadt Exp */
2050ce650fSreyk
2150ce650fSreyk #include <sys/time.h>
2250ce650fSreyk #include <sys/socket.h>
2350ce650fSreyk
2450ce650fSreyk #include <net/if.h>
2550ce650fSreyk #include <net/if_media.h>
2650ce650fSreyk #include <net/if_arp.h>
2750ce650fSreyk #include <net/if_llc.h>
2850ce650fSreyk #include <net/bpf.h>
2950ce650fSreyk
3050ce650fSreyk #include <netinet/in.h>
3150ce650fSreyk #include <netinet/if_ether.h>
3250ce650fSreyk #include <arpa/inet.h>
3350ce650fSreyk
3450ce650fSreyk #include <net80211/ieee80211.h>
3550ce650fSreyk #include <net80211/ieee80211_radiotap.h>
3650ce650fSreyk
3750ce650fSreyk #include <pcap.h>
3850ce650fSreyk #include <stdio.h>
3950ce650fSreyk #include <string.h>
40b9fc9a72Sderaadt #include <limits.h>
4150ce650fSreyk
4250ce650fSreyk #include "hostapd.h"
4350ce650fSreyk
4450ce650fSreyk const char *ieee80211_mgt_subtype_name[] = {
4550ce650fSreyk "association request",
4650ce650fSreyk "association response",
4750ce650fSreyk "reassociation request",
4850ce650fSreyk "reassociation response",
4950ce650fSreyk "probe request",
5050ce650fSreyk "probe response",
5150ce650fSreyk "reserved#6",
5250ce650fSreyk "reserved#7",
5350ce650fSreyk "beacon",
5450ce650fSreyk "atim",
5550ce650fSreyk "disassociation",
5650ce650fSreyk "authentication",
5750ce650fSreyk "deauthentication",
5850ce650fSreyk "reserved#13",
5950ce650fSreyk "reserved#14",
6050ce650fSreyk "reserved#15"
6150ce650fSreyk };
6250ce650fSreyk
6350ce650fSreyk const u_int8_t *snapend;
6450ce650fSreyk int vflag = 1, eflag = 1;
6550ce650fSreyk
6650ce650fSreyk int ieee80211_hdr(struct ieee80211_frame *);
6750ce650fSreyk void ieee80211_print_element(u_int8_t *, u_int);
6850ce650fSreyk void ieee80211_print_essid(u_int8_t *, u_int);
6969952658Sreyk int ieee80211_elements(struct ieee80211_frame *);
7069952658Sreyk int ieee80211_frame(struct ieee80211_frame *);
7169952658Sreyk int ieee80211_print(struct ieee80211_frame *);
7250ce650fSreyk u_int ieee80211_any2ieee(u_int, u_int);
7350ce650fSreyk void ieee802_11_if_print(u_int8_t *, u_int);
7450ce650fSreyk void ieee802_11_radio_if_print(u_int8_t *, u_int);
7550ce650fSreyk
7650ce650fSreyk #define TCARR(a) TCHECK2(*a, sizeof(a))
7750ce650fSreyk
7850ce650fSreyk int
ieee80211_hdr(struct ieee80211_frame * wh)7950ce650fSreyk ieee80211_hdr(struct ieee80211_frame *wh)
8050ce650fSreyk {
8150ce650fSreyk struct ieee80211_frame_addr4 *w4;
8250ce650fSreyk
8350ce650fSreyk switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
8450ce650fSreyk case IEEE80211_FC1_DIR_NODS:
8550ce650fSreyk TCARR(wh->i_addr2);
8650ce650fSreyk PRINTF("%s", etheraddr_string(wh->i_addr2));
8750ce650fSreyk TCARR(wh->i_addr1);
8850ce650fSreyk PRINTF(" > %s", etheraddr_string(wh->i_addr1));
8950ce650fSreyk TCARR(wh->i_addr3);
9050ce650fSreyk PRINTF(", bssid %s", etheraddr_string(wh->i_addr3));
9150ce650fSreyk break;
9250ce650fSreyk case IEEE80211_FC1_DIR_TODS:
9350ce650fSreyk TCARR(wh->i_addr2);
9450ce650fSreyk PRINTF("%s", etheraddr_string(wh->i_addr2));
9550ce650fSreyk TCARR(wh->i_addr3);
9650ce650fSreyk PRINTF(" > %s", etheraddr_string(wh->i_addr3));
9750ce650fSreyk TCARR(wh->i_addr1);
9850ce650fSreyk PRINTF(", bssid %s, > DS", etheraddr_string(wh->i_addr1));
9950ce650fSreyk break;
10050ce650fSreyk case IEEE80211_FC1_DIR_FROMDS:
10150ce650fSreyk TCARR(wh->i_addr3);
10250ce650fSreyk PRINTF("%s", etheraddr_string(wh->i_addr3));
10350ce650fSreyk TCARR(wh->i_addr1);
10450ce650fSreyk PRINTF(" > %s", etheraddr_string(wh->i_addr1));
10550ce650fSreyk TCARR(wh->i_addr2);
10650ce650fSreyk PRINTF(", bssid %s, DS >", etheraddr_string(wh->i_addr2));
10750ce650fSreyk break;
10850ce650fSreyk case IEEE80211_FC1_DIR_DSTODS:
10950ce650fSreyk w4 = (struct ieee80211_frame_addr4 *) wh;
11050ce650fSreyk TCARR(w4->i_addr4);
11150ce650fSreyk PRINTF("%s", etheraddr_string(w4->i_addr4));
11250ce650fSreyk TCARR(w4->i_addr3);
11350ce650fSreyk PRINTF(" > %s", etheraddr_string(w4->i_addr3));
11450ce650fSreyk TCARR(w4->i_addr2);
11550ce650fSreyk PRINTF(", bssid %s", etheraddr_string(w4->i_addr2));
11650ce650fSreyk TCARR(w4->i_addr1);
11750ce650fSreyk PRINTF(" > %s, DS > DS", etheraddr_string(w4->i_addr1));
11850ce650fSreyk break;
11950ce650fSreyk }
12050ce650fSreyk if (vflag) {
12150ce650fSreyk TCARR(wh->i_seq);
12250ce650fSreyk PRINTF(" (seq %u)", letoh16(*(u_int16_t *)&wh->i_seq[0]));
12350ce650fSreyk }
12450ce650fSreyk
12550ce650fSreyk return (0);
12650ce650fSreyk
12750ce650fSreyk trunc:
12850ce650fSreyk /* Truncated elements in frame */
12950ce650fSreyk return (1);
13050ce650fSreyk }
13150ce650fSreyk
13250ce650fSreyk /* Caller checks len */
13350ce650fSreyk void
ieee80211_print_element(u_int8_t * data,u_int len)13450ce650fSreyk ieee80211_print_element(u_int8_t *data, u_int len)
13550ce650fSreyk {
13650ce650fSreyk u_int8_t *p;
13750ce650fSreyk u_int i;
13850ce650fSreyk
13950ce650fSreyk PRINTF(" 0x");
14050ce650fSreyk for (i = 0, p = data; i < len; i++, p++)
14150ce650fSreyk PRINTF("%02x", *p);
14250ce650fSreyk }
14350ce650fSreyk
14450ce650fSreyk /* Caller checks len */
14550ce650fSreyk void
ieee80211_print_essid(u_int8_t * essid,u_int len)14650ce650fSreyk ieee80211_print_essid(u_int8_t *essid, u_int len)
14750ce650fSreyk {
14850ce650fSreyk u_int8_t *p;
14950ce650fSreyk u_int i;
15050ce650fSreyk
15150ce650fSreyk if (len > IEEE80211_NWID_LEN)
15250ce650fSreyk len = IEEE80211_NWID_LEN;
15350ce650fSreyk
15450ce650fSreyk /* determine printable or not */
15550ce650fSreyk for (i = 0, p = essid; i < len; i++, p++) {
15650ce650fSreyk if (*p < ' ' || *p > 0x7e)
15750ce650fSreyk break;
15850ce650fSreyk }
15950ce650fSreyk if (i == len) {
16050ce650fSreyk PRINTF(" (");
16150ce650fSreyk for (i = 0, p = essid; i < len; i++, p++)
16250ce650fSreyk PRINTF("%c", *p);
16350ce650fSreyk PRINTF(")");
16450ce650fSreyk } else
16550ce650fSreyk ieee80211_print_element(essid, len);
16650ce650fSreyk }
16750ce650fSreyk
16850ce650fSreyk int
ieee80211_elements(struct ieee80211_frame * wh)16969952658Sreyk ieee80211_elements(struct ieee80211_frame *wh)
17050ce650fSreyk {
17169952658Sreyk u_int8_t *frm;
17250ce650fSreyk u_int8_t *tstamp, *bintval, *capinfo;
17350ce650fSreyk int i;
17450ce650fSreyk
17550ce650fSreyk frm = (u_int8_t *)&wh[1];
17650ce650fSreyk
17750ce650fSreyk tstamp = frm;
17850ce650fSreyk TCHECK2(*tstamp, 8);
17950ce650fSreyk frm += 8;
18050ce650fSreyk
18150ce650fSreyk bintval = frm;
18250ce650fSreyk TCHECK2(*bintval, 2);
18350ce650fSreyk frm += 2;
18450ce650fSreyk
18550ce650fSreyk if (vflag)
18650ce650fSreyk PRINTF(", interval %u", letoh16(*(u_int16_t *)bintval));
18750ce650fSreyk
18850ce650fSreyk capinfo = frm;
18950ce650fSreyk TCHECK2(*capinfo, 2);
19050ce650fSreyk frm += 2;
19150ce650fSreyk
19250ce650fSreyk #if 0
19350ce650fSreyk if (vflag)
19450ce650fSreyk printb(", caps", letoh16(*(u_int16_t *)capinfo),
19550ce650fSreyk IEEE80211_CAPINFO_BITS);
19650ce650fSreyk #endif
19750ce650fSreyk
19850ce650fSreyk while (TTEST2(*frm, 2)) {
19950ce650fSreyk u_int len = frm[1];
20050ce650fSreyk u_int8_t *data = frm + 2;
20150ce650fSreyk
20250ce650fSreyk if (!TTEST2(*data, len))
20350ce650fSreyk break;
20450ce650fSreyk
20550ce650fSreyk #define ELEM_CHECK(l) if (len != l) break
20650ce650fSreyk
20750ce650fSreyk switch (*frm) {
20850ce650fSreyk case IEEE80211_ELEMID_SSID:
20950ce650fSreyk PRINTF(", ssid");
21050ce650fSreyk ieee80211_print_essid(data, len);
21150ce650fSreyk break;
21250ce650fSreyk case IEEE80211_ELEMID_RATES:
21350ce650fSreyk if (!vflag)
21450ce650fSreyk break;
21550ce650fSreyk PRINTF(", rates");
21650ce650fSreyk for (i = len; i > 0; i--, data++)
21750ce650fSreyk PRINTF(" %uM",
21850ce650fSreyk (data[0] & IEEE80211_RATE_VAL) / 2);
21950ce650fSreyk break;
22050ce650fSreyk case IEEE80211_ELEMID_FHPARMS:
22150ce650fSreyk ELEM_CHECK(5);
22250ce650fSreyk PRINTF(", fh (dwell %u, chan %u, index %u)",
22350ce650fSreyk (data[1] << 8) | data[0],
22450ce650fSreyk (data[2] - 1) * 80 + data[3], /* FH_CHAN */
22550ce650fSreyk data[4]);
22650ce650fSreyk break;
22750ce650fSreyk case IEEE80211_ELEMID_DSPARMS:
22850ce650fSreyk ELEM_CHECK(1);
22950ce650fSreyk if (!vflag)
23050ce650fSreyk break;
23150ce650fSreyk PRINTF(", ds");
23250ce650fSreyk PRINTF(" (chan %u)", data[0]);
23350ce650fSreyk break;
23450ce650fSreyk case IEEE80211_ELEMID_CFPARMS:
23550ce650fSreyk if (!vflag)
23650ce650fSreyk break;
23750ce650fSreyk PRINTF(", cf");
23850ce650fSreyk ieee80211_print_element(data, len);
23950ce650fSreyk break;
24050ce650fSreyk case IEEE80211_ELEMID_TIM:
24150ce650fSreyk if (!vflag)
24250ce650fSreyk break;
24350ce650fSreyk PRINTF(", tim");
24450ce650fSreyk ieee80211_print_element(data, len);
24550ce650fSreyk break;
24650ce650fSreyk case IEEE80211_ELEMID_IBSSPARMS:
24750ce650fSreyk if (!vflag)
24850ce650fSreyk break;
24950ce650fSreyk PRINTF(", ibss");
25050ce650fSreyk ieee80211_print_element(data, len);
25150ce650fSreyk break;
25250ce650fSreyk case IEEE80211_ELEMID_COUNTRY:
25350ce650fSreyk if (!vflag)
25450ce650fSreyk break;
25550ce650fSreyk PRINTF(", country");
25650ce650fSreyk for (i = len; i > 0; i--, data++)
25750ce650fSreyk PRINTF(" %u", data[0]);
25850ce650fSreyk break;
25950ce650fSreyk case IEEE80211_ELEMID_CHALLENGE:
26050ce650fSreyk if (!vflag)
26150ce650fSreyk break;
26250ce650fSreyk PRINTF(", challenge");
26350ce650fSreyk ieee80211_print_element(data, len);
26450ce650fSreyk break;
26550ce650fSreyk case IEEE80211_ELEMID_ERP:
26650ce650fSreyk if (!vflag)
26750ce650fSreyk break;
26850ce650fSreyk PRINTF(", erp");
26950ce650fSreyk ieee80211_print_element(data, len);
27050ce650fSreyk break;
27150ce650fSreyk case IEEE80211_ELEMID_RSN:
27250ce650fSreyk if (!vflag)
27350ce650fSreyk break;
27450ce650fSreyk PRINTF(", rsn");
27550ce650fSreyk ieee80211_print_element(data, len);
27650ce650fSreyk break;
27750ce650fSreyk case IEEE80211_ELEMID_XRATES:
27850ce650fSreyk if (!vflag)
27950ce650fSreyk break;
28050ce650fSreyk PRINTF(", xrates");
28150ce650fSreyk for (i = len; i > 0; i--, data++)
28250ce650fSreyk PRINTF(" %uM",
28350ce650fSreyk (data[0] & IEEE80211_RATE_VAL) / 2);
28450ce650fSreyk break;
2858138faddSstsp case IEEE80211_ELEMID_TPC_REQUEST:
28650ce650fSreyk if (!vflag)
28750ce650fSreyk break;
2888138faddSstsp PRINTF(", tpcrequest");
28950ce650fSreyk ieee80211_print_element(data, len);
29050ce650fSreyk break;
2918138faddSstsp case IEEE80211_ELEMID_TPC_REPORT:
29250ce650fSreyk if (!vflag)
29350ce650fSreyk break;
2948138faddSstsp PRINTF(", tpcreport");
29550ce650fSreyk ieee80211_print_element(data, len);
29650ce650fSreyk break;
29750ce650fSreyk case IEEE80211_ELEMID_VENDOR:
29850ce650fSreyk if (!vflag)
29950ce650fSreyk break;
30050ce650fSreyk PRINTF(", vendor");
30150ce650fSreyk ieee80211_print_element(data, len);
30250ce650fSreyk break;
30350ce650fSreyk default:
30450ce650fSreyk if (!vflag)
30550ce650fSreyk break;
30650ce650fSreyk PRINTF(", %u:%u", (u_int) *frm, len);
30750ce650fSreyk ieee80211_print_element(data, len);
30850ce650fSreyk break;
30950ce650fSreyk }
31050ce650fSreyk frm += len + 2;
31150ce650fSreyk
31250ce650fSreyk if (frm >= snapend)
31350ce650fSreyk break;
31450ce650fSreyk }
31550ce650fSreyk
31650ce650fSreyk #undef ELEM_CHECK
31750ce650fSreyk
31850ce650fSreyk return (0);
31950ce650fSreyk
32050ce650fSreyk trunc:
32150ce650fSreyk /* Truncated elements in frame */
32250ce650fSreyk return (1);
32350ce650fSreyk }
32450ce650fSreyk
32550ce650fSreyk int
ieee80211_frame(struct ieee80211_frame * wh)32669952658Sreyk ieee80211_frame(struct ieee80211_frame *wh)
32750ce650fSreyk {
32850ce650fSreyk u_int8_t subtype, type, *frm;
32950ce650fSreyk
33050ce650fSreyk TCARR(wh->i_fc);
33150ce650fSreyk
33250ce650fSreyk type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
33350ce650fSreyk subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
33450ce650fSreyk
33550ce650fSreyk frm = (u_int8_t *)&wh[1];
33650ce650fSreyk
33750ce650fSreyk switch (type) {
33850ce650fSreyk case IEEE80211_FC0_TYPE_DATA:
33950ce650fSreyk PRINTF(": data");
34050ce650fSreyk break;
34150ce650fSreyk case IEEE80211_FC0_TYPE_MGT:
34250ce650fSreyk PRINTF(": %s", ieee80211_mgt_subtype_name[
34350ce650fSreyk subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]);
34450ce650fSreyk switch (subtype) {
34550ce650fSreyk case IEEE80211_FC0_SUBTYPE_BEACON:
34650ce650fSreyk case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
34769952658Sreyk if (ieee80211_elements(wh) != 0)
34850ce650fSreyk goto trunc;
34950ce650fSreyk break;
35050ce650fSreyk case IEEE80211_FC0_SUBTYPE_AUTH:
35150ce650fSreyk TCHECK2(*frm, 2); /* Auth Algorithm */
35250ce650fSreyk switch (IEEE80211_AUTH_ALGORITHM(frm)) {
35350ce650fSreyk case IEEE80211_AUTH_ALG_OPEN:
35450ce650fSreyk TCHECK2(*frm, 4); /* Auth Transaction */
35550ce650fSreyk switch (IEEE80211_AUTH_TRANSACTION(frm)) {
35650ce650fSreyk case IEEE80211_AUTH_OPEN_REQUEST:
35750ce650fSreyk PRINTF(" request");
35850ce650fSreyk break;
35950ce650fSreyk case IEEE80211_AUTH_OPEN_RESPONSE:
36050ce650fSreyk PRINTF(" response");
36150ce650fSreyk break;
36250ce650fSreyk }
36350ce650fSreyk break;
36450ce650fSreyk case IEEE80211_AUTH_ALG_SHARED:
36550ce650fSreyk TCHECK2(*frm, 4); /* Auth Transaction */
36650ce650fSreyk switch (IEEE80211_AUTH_TRANSACTION(frm)) {
36750ce650fSreyk case IEEE80211_AUTH_SHARED_REQUEST:
36850ce650fSreyk PRINTF(" request");
36950ce650fSreyk break;
37050ce650fSreyk case IEEE80211_AUTH_SHARED_CHALLENGE:
37150ce650fSreyk PRINTF(" challenge");
37250ce650fSreyk break;
37350ce650fSreyk case IEEE80211_AUTH_SHARED_RESPONSE:
37450ce650fSreyk PRINTF(" response");
37550ce650fSreyk break;
37650ce650fSreyk case IEEE80211_AUTH_SHARED_PASS:
37750ce650fSreyk PRINTF(" pass");
37850ce650fSreyk break;
37950ce650fSreyk }
38050ce650fSreyk break;
38150ce650fSreyk case IEEE80211_AUTH_ALG_LEAP:
38250ce650fSreyk PRINTF(" (leap)");
38350ce650fSreyk break;
38450ce650fSreyk }
38550ce650fSreyk break;
38650ce650fSreyk }
38750ce650fSreyk break;
38850ce650fSreyk default:
38950ce650fSreyk PRINTF(": type#%d", type);
39050ce650fSreyk break;
39150ce650fSreyk }
39250ce650fSreyk
39350ce650fSreyk if (wh->i_fc[1] & IEEE80211_FC1_WEP)
39450ce650fSreyk PRINTF(", WEP");
39550ce650fSreyk
39650ce650fSreyk return (0);
39750ce650fSreyk
39850ce650fSreyk trunc:
39950ce650fSreyk /* Truncated 802.11 frame */
40050ce650fSreyk return (1);
40150ce650fSreyk }
40250ce650fSreyk
40350ce650fSreyk u_int
ieee80211_any2ieee(u_int freq,u_int flags)40450ce650fSreyk ieee80211_any2ieee(u_int freq, u_int flags)
40550ce650fSreyk {
40650ce650fSreyk if (flags & IEEE80211_CHAN_2GHZ) {
40750ce650fSreyk if (freq == 2484)
40850ce650fSreyk return 14;
40950ce650fSreyk if (freq < 2484)
41050ce650fSreyk return (freq - 2407) / 5;
41150ce650fSreyk else
41250ce650fSreyk return 15 + ((freq - 2512) / 20);
41350ce650fSreyk } else if (flags & IEEE80211_CHAN_5GHZ) {
41450ce650fSreyk return (freq - 5000) / 5;
41550ce650fSreyk } else {
41650ce650fSreyk /* Assume channel is already an IEEE number */
41750ce650fSreyk return (freq);
41850ce650fSreyk }
41950ce650fSreyk }
42050ce650fSreyk
42150ce650fSreyk int
ieee80211_print(struct ieee80211_frame * wh)42269952658Sreyk ieee80211_print(struct ieee80211_frame *wh)
42350ce650fSreyk {
42450ce650fSreyk if (eflag)
42550ce650fSreyk if (ieee80211_hdr(wh))
42650ce650fSreyk return (1);
42750ce650fSreyk
42869952658Sreyk return (ieee80211_frame(wh));
42950ce650fSreyk }
43050ce650fSreyk
43150ce650fSreyk void
ieee802_11_if_print(u_int8_t * buf,u_int len)43250ce650fSreyk ieee802_11_if_print(u_int8_t *buf, u_int len)
43350ce650fSreyk {
43450ce650fSreyk struct ieee80211_frame *wh = (struct ieee80211_frame*)buf;
43550ce650fSreyk
43650ce650fSreyk snapend = buf + len;
43750ce650fSreyk
43869952658Sreyk if (ieee80211_print(wh) != 0)
43950ce650fSreyk PRINTF("[|802.11]");
44050ce650fSreyk
441f83005a6Sreyk PRINTF(NULL);
44250ce650fSreyk }
44350ce650fSreyk
44450ce650fSreyk void
ieee802_11_radio_if_print(u_int8_t * buf,u_int len)44550ce650fSreyk ieee802_11_radio_if_print(u_int8_t *buf, u_int len)
44650ce650fSreyk {
44750ce650fSreyk struct ieee80211_radiotap_header *rh =
44850ce650fSreyk (struct ieee80211_radiotap_header*)buf;
44950ce650fSreyk struct ieee80211_frame *wh;
45050ce650fSreyk u_int8_t *t;
45150ce650fSreyk u_int32_t present;
45250ce650fSreyk u_int rh_len;
45350ce650fSreyk
45450ce650fSreyk snapend = buf + len;
45550ce650fSreyk
45650ce650fSreyk TCHECK(*rh);
45750ce650fSreyk
45850ce650fSreyk rh_len = letoh16(rh->it_len);
45950ce650fSreyk if (rh->it_version != 0) {
460f83005a6Sreyk PRINTF("[?radiotap + 802.11 v:%u]", rh->it_version);
46150ce650fSreyk goto out;
46250ce650fSreyk }
46350ce650fSreyk
46450ce650fSreyk wh = (struct ieee80211_frame *)(buf + rh_len);
46569952658Sreyk if (len <= rh_len || ieee80211_print(wh))
46650ce650fSreyk PRINTF("[|802.11]");
46750ce650fSreyk
46850ce650fSreyk t = (u_int8_t*)buf + sizeof(struct ieee80211_radiotap_header);
46950ce650fSreyk
47050ce650fSreyk if ((present = letoh32(rh->it_present)) == 0)
47150ce650fSreyk goto out;
47250ce650fSreyk
47350ce650fSreyk PRINTF(", <radiotap v%u", rh->it_version);
47450ce650fSreyk
47550ce650fSreyk #define RADIOTAP(_x) \
47650ce650fSreyk (present & (1 << IEEE80211_RADIOTAP_##_x))
47750ce650fSreyk
47850ce650fSreyk if (RADIOTAP(TSFT)) {
47950ce650fSreyk u_int64_t tsf;
48050ce650fSreyk u_int32_t tsf_v[2];
48150ce650fSreyk
48250ce650fSreyk TCHECK2(*t, 8);
48350ce650fSreyk
48450ce650fSreyk tsf = letoh64(*(u_int64_t *)t);
48550ce650fSreyk tsf_v[0] = (u_int32_t)(tsf >> 32);
48650ce650fSreyk tsf_v[1] = (u_int32_t)(tsf & 0x00000000ffffffff);
48750ce650fSreyk if (vflag > 1)
48850ce650fSreyk PRINTF(", tsf 0x%08x%08x", tsf_v[0], tsf_v[1]);
48950ce650fSreyk t += 8;
49050ce650fSreyk }
49150ce650fSreyk
49250ce650fSreyk if (RADIOTAP(FLAGS)) {
49350ce650fSreyk u_int8_t flags = *(u_int8_t*)t;
49450ce650fSreyk TCHECK2(*t, 1);
49550ce650fSreyk
49650ce650fSreyk if (flags & IEEE80211_RADIOTAP_F_CFP)
49750ce650fSreyk PRINTF(", CFP");
49850ce650fSreyk if (flags & IEEE80211_RADIOTAP_F_SHORTPRE)
49950ce650fSreyk PRINTF(", SHORTPRE");
50050ce650fSreyk if (flags & IEEE80211_RADIOTAP_F_WEP)
50150ce650fSreyk PRINTF(", WEP");
50250ce650fSreyk if (flags & IEEE80211_RADIOTAP_F_FRAG)
50350ce650fSreyk PRINTF(", FRAG");
50450ce650fSreyk t += 1;
50550ce650fSreyk }
50650ce650fSreyk
50750ce650fSreyk if (RADIOTAP(RATE)) {
50850ce650fSreyk TCHECK2(*t, 1);
50950ce650fSreyk if (vflag)
51050ce650fSreyk PRINTF(", %uMbit/s", (*(u_int8_t*)t) / 2);
51150ce650fSreyk t += 1;
51250ce650fSreyk }
51350ce650fSreyk
51450ce650fSreyk if (RADIOTAP(CHANNEL)) {
51550ce650fSreyk u_int16_t freq, flags;
51650ce650fSreyk TCHECK2(*t, 2);
51750ce650fSreyk
51850ce650fSreyk freq = letoh16(*(u_int16_t*)t);
51950ce650fSreyk t += 2;
52050ce650fSreyk TCHECK2(*t, 2);
52150ce650fSreyk flags = letoh16(*(u_int16_t*)t);
52250ce650fSreyk t += 2;
52350ce650fSreyk
52450ce650fSreyk PRINTF(", chan %u", ieee80211_any2ieee(freq, flags));
52550ce650fSreyk
52650ce650fSreyk if (flags & IEEE80211_CHAN_DYN &&
52750ce650fSreyk flags & IEEE80211_CHAN_2GHZ)
52850ce650fSreyk PRINTF(", 11g");
52950ce650fSreyk else if (flags & IEEE80211_CHAN_CCK &&
53050ce650fSreyk flags & IEEE80211_CHAN_2GHZ)
53150ce650fSreyk PRINTF(", 11b");
53250ce650fSreyk else if (flags & IEEE80211_CHAN_OFDM &&
53350ce650fSreyk flags & IEEE80211_CHAN_2GHZ)
53450ce650fSreyk PRINTF(", 11G");
53550ce650fSreyk else if (flags & IEEE80211_CHAN_OFDM &&
53650ce650fSreyk flags & IEEE80211_CHAN_5GHZ)
53750ce650fSreyk PRINTF(", 11a");
53850ce650fSreyk
53950ce650fSreyk if (flags & IEEE80211_CHAN_XR)
54050ce650fSreyk PRINTF(", XR");
54150ce650fSreyk }
54250ce650fSreyk
54350ce650fSreyk if (RADIOTAP(FHSS)) {
54450ce650fSreyk TCHECK2(*t, 2);
54550ce650fSreyk PRINTF(", fhss %u/%u", *(u_int8_t*)t, *(u_int8_t*)t + 1);
54650ce650fSreyk t += 2;
54750ce650fSreyk }
54850ce650fSreyk
54950ce650fSreyk if (RADIOTAP(DBM_ANTSIGNAL)) {
55050ce650fSreyk TCHECK(*t);
55150ce650fSreyk PRINTF(", sig %ddBm", *(int8_t*)t);
55250ce650fSreyk t += 1;
55350ce650fSreyk }
55450ce650fSreyk
55550ce650fSreyk if (RADIOTAP(DBM_ANTNOISE)) {
55650ce650fSreyk TCHECK(*t);
55750ce650fSreyk PRINTF(", noise %ddBm", *(int8_t*)t);
55850ce650fSreyk t += 1;
55950ce650fSreyk }
56050ce650fSreyk
56150ce650fSreyk if (RADIOTAP(LOCK_QUALITY)) {
56250ce650fSreyk TCHECK2(*t, 2);
56350ce650fSreyk if (vflag)
56450ce650fSreyk PRINTF(", quality %u", letoh16(*(u_int16_t*)t));
56550ce650fSreyk t += 2;
56650ce650fSreyk }
56750ce650fSreyk
56850ce650fSreyk if (RADIOTAP(TX_ATTENUATION)) {
56950ce650fSreyk TCHECK2(*t, 2);
57050ce650fSreyk if (vflag)
57150ce650fSreyk PRINTF(", txatt %u",
57250ce650fSreyk letoh16(*(u_int16_t*)t));
57350ce650fSreyk t += 2;
57450ce650fSreyk }
57550ce650fSreyk
57650ce650fSreyk if (RADIOTAP(DB_TX_ATTENUATION)) {
57750ce650fSreyk TCHECK2(*t, 2);
57850ce650fSreyk if (vflag)
57950ce650fSreyk PRINTF(", txatt %udB",
58050ce650fSreyk letoh16(*(u_int16_t*)t));
58150ce650fSreyk t += 2;
58250ce650fSreyk }
58350ce650fSreyk
58450ce650fSreyk if (RADIOTAP(DBM_TX_POWER)) {
58550ce650fSreyk TCHECK(*t);
58650ce650fSreyk PRINTF(", txpower %ddBm", *(int8_t*)t);
58750ce650fSreyk t += 1;
58850ce650fSreyk }
58950ce650fSreyk
59050ce650fSreyk if (RADIOTAP(ANTENNA)) {
59150ce650fSreyk TCHECK(*t);
59250ce650fSreyk if (vflag)
59350ce650fSreyk PRINTF(", antenna %u", *(u_int8_t*)t);
59450ce650fSreyk t += 1;
59550ce650fSreyk }
59650ce650fSreyk
59750ce650fSreyk if (RADIOTAP(DB_ANTSIGNAL)) {
59850ce650fSreyk TCHECK(*t);
59950ce650fSreyk PRINTF(", signal %udB", *(u_int8_t*)t);
60050ce650fSreyk t += 1;
60150ce650fSreyk }
60250ce650fSreyk
60350ce650fSreyk if (RADIOTAP(DB_ANTNOISE)) {
60450ce650fSreyk TCHECK(*t);
60550ce650fSreyk PRINTF(", noise %udB", *(u_int8_t*)t);
60650ce650fSreyk t += 1;
60750ce650fSreyk }
60850ce650fSreyk
60950ce650fSreyk if (RADIOTAP(FCS)) {
61050ce650fSreyk TCHECK2(*t, 4);
61150ce650fSreyk if (vflag)
61250ce650fSreyk PRINTF(", fcs %08x", letoh32(*(u_int32_t*)t));
61350ce650fSreyk t += 4;
61450ce650fSreyk }
61550ce650fSreyk
6166fc94ee3Sreyk if (RADIOTAP(RSSI)) {
6176fc94ee3Sreyk u_int8_t rssi, max_rssi;
6186fc94ee3Sreyk TCHECK(*t);
6196fc94ee3Sreyk rssi = *(u_int8_t*)t;
6206fc94ee3Sreyk t += 1;
6216fc94ee3Sreyk TCHECK(*t);
6226fc94ee3Sreyk max_rssi = *(u_int8_t*)t;
6236fc94ee3Sreyk t += 1;
6246fc94ee3Sreyk
6259aa8b2e1Sreyk PRINTF(", rssi %u/%u", rssi, max_rssi);
6266fc94ee3Sreyk }
6276fc94ee3Sreyk
62850ce650fSreyk #undef RADIOTAP
62950ce650fSreyk
63050ce650fSreyk PRINTF(">");
63150ce650fSreyk goto out;
63250ce650fSreyk
63350ce650fSreyk trunc:
63450ce650fSreyk /* Truncated frame */
63550ce650fSreyk PRINTF("[|radiotap + 802.11]");
63650ce650fSreyk
63750ce650fSreyk out:
638f83005a6Sreyk PRINTF(NULL);
63950ce650fSreyk }
64050ce650fSreyk
64150ce650fSreyk void
hostapd_print_ieee80211(u_int dlt,u_int verbose,u_int8_t * buf,u_int len)64250ce650fSreyk hostapd_print_ieee80211(u_int dlt, u_int verbose, u_int8_t *buf, u_int len)
64350ce650fSreyk {
64450ce650fSreyk if (verbose)
64550ce650fSreyk vflag = 1;
64650ce650fSreyk else
64750ce650fSreyk vflag = 0;
64850ce650fSreyk
64950ce650fSreyk if (dlt == DLT_IEEE802_11)
65050ce650fSreyk ieee802_11_if_print(buf, len);
65150ce650fSreyk else
65250ce650fSreyk ieee802_11_radio_if_print(buf, len);
65350ce650fSreyk }
654