1*026ca542Sderaadt /* $OpenBSD: print-802_11.c,v 1.2 2005/03/08 14:55:41 deraadt Exp $ */ 212a08440Sreyk 312a08440Sreyk /* 412a08440Sreyk * Copyright (c) 2005 Reyk Floeter <reyk@vantronix.net> 512a08440Sreyk * 612a08440Sreyk * Permission to use, copy, modify, and distribute this software for any 712a08440Sreyk * purpose with or without fee is hereby granted, provided that the above 812a08440Sreyk * copyright notice and this permission notice appear in all copies. 912a08440Sreyk * 1012a08440Sreyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1112a08440Sreyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1212a08440Sreyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1312a08440Sreyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1412a08440Sreyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1512a08440Sreyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1612a08440Sreyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1712a08440Sreyk */ 1812a08440Sreyk 1912a08440Sreyk #include <sys/param.h> 2012a08440Sreyk #include <sys/time.h> 2112a08440Sreyk #include <sys/socket.h> 2212a08440Sreyk #include <sys/file.h> 2312a08440Sreyk #include <sys/ioctl.h> 2412a08440Sreyk 2512a08440Sreyk #include <net/if.h> 2612a08440Sreyk 2712a08440Sreyk #include <netinet/in.h> 2812a08440Sreyk #include <netinet/in_systm.h> 2912a08440Sreyk #include <netinet/if_ether.h> 3012a08440Sreyk 3112a08440Sreyk #include <net80211/ieee80211.h> 3212a08440Sreyk #include <net80211/ieee80211_radiotap.h> 3312a08440Sreyk 3412a08440Sreyk #include <pcap.h> 3512a08440Sreyk #include <stdio.h> 3612a08440Sreyk #include <string.h> 3712a08440Sreyk 3812a08440Sreyk #include "addrtoname.h" 3912a08440Sreyk #include "interface.h" 4012a08440Sreyk 4112a08440Sreyk const char *ieee80211_mgt_subtype_name[] = { 4212a08440Sreyk "association request", 4312a08440Sreyk "association response", 4412a08440Sreyk "reassociation request", 4512a08440Sreyk "reassociation response", 4612a08440Sreyk "probe request", 4712a08440Sreyk "probe response", 4812a08440Sreyk "reserved#6", 4912a08440Sreyk "reserved#7", 5012a08440Sreyk "beacon", 5112a08440Sreyk "atim", 5212a08440Sreyk "disassociation", 5312a08440Sreyk "authentication", 5412a08440Sreyk "deauthentication", 5512a08440Sreyk "reserved#13", 5612a08440Sreyk "reserved#14", 5712a08440Sreyk "reserved#15" 5812a08440Sreyk }; 5912a08440Sreyk 6012a08440Sreyk int ieee80211_hdr(struct ieee80211_frame *); 6112a08440Sreyk void ieee80211_print_element(u_int8_t *, u_int); 6212a08440Sreyk void ieee80211_print_essid(u_int8_t *, u_int); 6312a08440Sreyk int ieee80211_elements(struct ieee80211_frame *, u_int); 6412a08440Sreyk int ieee80211_frame(struct ieee80211_frame *, u_int); 6512a08440Sreyk int ieee80211_print(struct ieee80211_frame *, u_int); 6612a08440Sreyk u_int ieee80211_any2ieee(u_int, u_int); 6712a08440Sreyk 6812a08440Sreyk #define TCARR(a) TCHECK2(*a, sizeof(a)) 6912a08440Sreyk 7012a08440Sreyk int 7112a08440Sreyk ieee80211_hdr(struct ieee80211_frame *wh) 7212a08440Sreyk { 7312a08440Sreyk struct ieee80211_frame_addr4 *w4; 7412a08440Sreyk 7512a08440Sreyk switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 7612a08440Sreyk case IEEE80211_FC1_DIR_NODS: 7712a08440Sreyk TCARR(wh->i_addr2); 7812a08440Sreyk printf("%s", etheraddr_string(wh->i_addr2)); 7912a08440Sreyk TCARR(wh->i_addr1); 8012a08440Sreyk printf(" > %s", etheraddr_string(wh->i_addr1)); 8112a08440Sreyk TCARR(wh->i_addr3); 8212a08440Sreyk printf(", bssid %s", etheraddr_string(wh->i_addr3)); 8312a08440Sreyk break; 8412a08440Sreyk case IEEE80211_FC1_DIR_TODS: 8512a08440Sreyk TCARR(wh->i_addr2); 8612a08440Sreyk printf("%s", etheraddr_string(wh->i_addr2)); 8712a08440Sreyk TCARR(wh->i_addr3); 8812a08440Sreyk printf(" > %s", etheraddr_string(wh->i_addr3)); 8912a08440Sreyk TCARR(wh->i_addr1); 9012a08440Sreyk printf(", bssid %s, > DS", etheraddr_string(wh->i_addr1)); 9112a08440Sreyk break; 9212a08440Sreyk case IEEE80211_FC1_DIR_FROMDS: 9312a08440Sreyk TCARR(wh->i_addr3); 9412a08440Sreyk printf("%s", etheraddr_string(wh->i_addr3)); 9512a08440Sreyk TCARR(wh->i_addr1); 9612a08440Sreyk printf(" > %s", etheraddr_string(wh->i_addr1)); 9712a08440Sreyk TCARR(wh->i_addr2); 9812a08440Sreyk printf(", bssid %s, DS >", etheraddr_string(wh->i_addr2)); 9912a08440Sreyk break; 10012a08440Sreyk case IEEE80211_FC1_DIR_DSTODS: 10112a08440Sreyk w4 = (struct ieee80211_frame_addr4 *) wh; 10212a08440Sreyk TCARR(w4->i_addr4); 10312a08440Sreyk printf("%s", etheraddr_string(w4->i_addr4)); 10412a08440Sreyk TCARR(w4->i_addr3); 10512a08440Sreyk printf(" > %s", etheraddr_string(w4->i_addr3)); 10612a08440Sreyk TCARR(w4->i_addr2); 10712a08440Sreyk printf(", bssid %s", etheraddr_string(w4->i_addr2)); 10812a08440Sreyk TCARR(w4->i_addr1); 10912a08440Sreyk printf(" > %s, DS > DS", etheraddr_string(w4->i_addr1)); 11012a08440Sreyk break; 11112a08440Sreyk } 11212a08440Sreyk if (vflag) { 11312a08440Sreyk TCARR(wh->i_seq); 11412a08440Sreyk printf(" (seq %u): ", letoh16(*(u_int16_t *)&wh->i_seq[0])); 11512a08440Sreyk } else 11612a08440Sreyk printf(": "); 11712a08440Sreyk 11812a08440Sreyk return (0); 11912a08440Sreyk 12012a08440Sreyk trunc: 12112a08440Sreyk /* Truncated elements in frame */ 12212a08440Sreyk return (1); 12312a08440Sreyk } 12412a08440Sreyk 12512a08440Sreyk /* Caller checks len */ 12612a08440Sreyk void 12712a08440Sreyk ieee80211_print_element(u_int8_t *data, u_int len) 12812a08440Sreyk { 12912a08440Sreyk int i; 13012a08440Sreyk u_int8_t *p; 13112a08440Sreyk 13212a08440Sreyk printf(" 0x"); 13312a08440Sreyk for (i = 0, p = data; i < len; i++, p++) { 13412a08440Sreyk printf("%02x", *p); 13512a08440Sreyk } 13612a08440Sreyk } 13712a08440Sreyk 13812a08440Sreyk /* Caller checks len */ 13912a08440Sreyk void 14012a08440Sreyk ieee80211_print_essid(u_int8_t *essid, u_int len) 14112a08440Sreyk { 14212a08440Sreyk int i; 14312a08440Sreyk u_int8_t *p; 14412a08440Sreyk 14512a08440Sreyk if (len > IEEE80211_NWID_LEN) 14612a08440Sreyk len = IEEE80211_NWID_LEN; 14712a08440Sreyk 14812a08440Sreyk /* determine printable or not */ 14912a08440Sreyk for (i = 0, p = essid; i < len; i++, p++) { 15012a08440Sreyk if (*p < ' ' || *p > 0x7e) 15112a08440Sreyk break; 15212a08440Sreyk } 15312a08440Sreyk if (i == len) { 15412a08440Sreyk printf(" ("); 15512a08440Sreyk for (i = 0, p = essid; i < len; i++, p++) 15612a08440Sreyk putchar(*p); 15712a08440Sreyk putchar(')'); 15812a08440Sreyk } else { 15912a08440Sreyk ieee80211_print_element(essid, len); 16012a08440Sreyk } 16112a08440Sreyk } 16212a08440Sreyk 16312a08440Sreyk int 16412a08440Sreyk ieee80211_elements(struct ieee80211_frame *wh, u_int flen) 16512a08440Sreyk { 16612a08440Sreyk u_int8_t *buf, *frm; 16712a08440Sreyk u_int8_t *tstamp, *bintval, *capinfo; 16812a08440Sreyk int i; 16912a08440Sreyk 17012a08440Sreyk buf = (u_int8_t *)wh; 17112a08440Sreyk frm = (u_int8_t *)&wh[1]; 17212a08440Sreyk 17312a08440Sreyk tstamp = frm; 17412a08440Sreyk TCHECK2(*tstamp, 8); 17512a08440Sreyk frm += 8; 17612a08440Sreyk 17712a08440Sreyk if (vflag > 1) 17812a08440Sreyk printf(", timestamp %llu", letoh64(*(u_int64_t *)tstamp)); 17912a08440Sreyk 18012a08440Sreyk bintval = frm; 18112a08440Sreyk TCHECK2(*bintval, 2); 18212a08440Sreyk frm += 2; 18312a08440Sreyk 18412a08440Sreyk if (vflag > 1) 18512a08440Sreyk printf(", interval %u", letoh16(*(u_int16_t *)bintval)); 18612a08440Sreyk 18712a08440Sreyk capinfo = frm; 18812a08440Sreyk TCHECK2(*capinfo, 2); 18912a08440Sreyk frm += 2; 19012a08440Sreyk 19112a08440Sreyk if (vflag) 19212a08440Sreyk printb(", caps", letoh16(*(u_int16_t *)capinfo), 19312a08440Sreyk IEEE80211_CAPINFO_BITS); 19412a08440Sreyk 19512a08440Sreyk while (TTEST2(*frm, 2)) { 19612a08440Sreyk u_int len = frm[1]; 19712a08440Sreyk u_int8_t *data = frm + 2; 19812a08440Sreyk 19912a08440Sreyk if (!TTEST2(*data, len)) 20012a08440Sreyk break; 20112a08440Sreyk 20212a08440Sreyk #define ELEM_CHECK(l) if (len != l) break 20312a08440Sreyk 20412a08440Sreyk switch (*frm) { 20512a08440Sreyk case IEEE80211_ELEMID_SSID: 20612a08440Sreyk printf(", ssid"); 20712a08440Sreyk ieee80211_print_essid(data, len); 20812a08440Sreyk break; 20912a08440Sreyk case IEEE80211_ELEMID_RATES: 21012a08440Sreyk printf(", rates"); 21112a08440Sreyk if (!vflag) 21212a08440Sreyk break; 21312a08440Sreyk for (i = len; i > 0; i--, data++) 21412a08440Sreyk printf(" %uM", 21512a08440Sreyk (data[0] & IEEE80211_RATE_VAL) / 2); 21612a08440Sreyk break; 21712a08440Sreyk case IEEE80211_ELEMID_FHPARMS: 21812a08440Sreyk ELEM_CHECK(5); 21912a08440Sreyk printf(", fh (dwell %u, chan %u, index %u)", 22012a08440Sreyk (data[1] << 8) | data[0], 22112a08440Sreyk (data[2] - 1) * 80 + data[3], /* FH_CHAN */ 22212a08440Sreyk data[4]); 22312a08440Sreyk break; 22412a08440Sreyk case IEEE80211_ELEMID_DSPARMS: 22512a08440Sreyk ELEM_CHECK(1); 22612a08440Sreyk printf(", ds"); 22712a08440Sreyk if (vflag) 22812a08440Sreyk printf(" (chan %u)", data[0]); 22912a08440Sreyk break; 23012a08440Sreyk case IEEE80211_ELEMID_CFPARMS: 23112a08440Sreyk printf(", cf"); 23212a08440Sreyk if (vflag) 23312a08440Sreyk ieee80211_print_element(data, len); 23412a08440Sreyk break; 23512a08440Sreyk case IEEE80211_ELEMID_TIM: 23612a08440Sreyk printf(", tim"); 23712a08440Sreyk if (vflag) 23812a08440Sreyk ieee80211_print_element(data, len); 23912a08440Sreyk break; 24012a08440Sreyk case IEEE80211_ELEMID_IBSSPARMS: 24112a08440Sreyk printf(", ibss"); 24212a08440Sreyk if (vflag) 24312a08440Sreyk ieee80211_print_element(data, len); 24412a08440Sreyk break; 24512a08440Sreyk case IEEE80211_ELEMID_COUNTRY: 24612a08440Sreyk printf(", country"); 24712a08440Sreyk for (i = len; i > 0; i--, data++) 24812a08440Sreyk printf(" %u", data[0]); 24912a08440Sreyk break; 25012a08440Sreyk case IEEE80211_ELEMID_CHALLENGE: 25112a08440Sreyk printf(", challenge"); 25212a08440Sreyk if (vflag) 25312a08440Sreyk ieee80211_print_element(data, len); 25412a08440Sreyk break; 25512a08440Sreyk case IEEE80211_ELEMID_ERP: 25612a08440Sreyk printf(", erp"); 25712a08440Sreyk if (vflag) 25812a08440Sreyk ieee80211_print_element(data, len); 25912a08440Sreyk break; 26012a08440Sreyk case IEEE80211_ELEMID_RSN: 26112a08440Sreyk printf(", rsn"); 26212a08440Sreyk if (vflag) 26312a08440Sreyk ieee80211_print_element(data, len); 26412a08440Sreyk break; 26512a08440Sreyk case IEEE80211_ELEMID_XRATES: 26612a08440Sreyk printf(", xrates"); 26712a08440Sreyk if (!vflag) 26812a08440Sreyk break; 26912a08440Sreyk for (i = len; i > 0; i--, data++) 27012a08440Sreyk printf(" %uM", 27112a08440Sreyk (data[0] & IEEE80211_RATE_VAL) / 2); 27212a08440Sreyk break; 27312a08440Sreyk case IEEE80211_ELEMID_TPC: 27412a08440Sreyk printf(", tpc"); 27512a08440Sreyk if (vflag) 27612a08440Sreyk ieee80211_print_element(data, len); 27712a08440Sreyk break; 27812a08440Sreyk case IEEE80211_ELEMID_CCKM: 27912a08440Sreyk printf(", cckm"); 28012a08440Sreyk if (vflag) 28112a08440Sreyk ieee80211_print_element(data, len); 28212a08440Sreyk break; 28312a08440Sreyk case IEEE80211_ELEMID_VENDOR: 28412a08440Sreyk printf(", vendor"); 28512a08440Sreyk if (vflag) 28612a08440Sreyk ieee80211_print_element(data, len); 28712a08440Sreyk break; 28812a08440Sreyk default: 28912a08440Sreyk printf(", %u:%u", (u_int) *frm, len); 29012a08440Sreyk if (vflag) 29112a08440Sreyk ieee80211_print_element(data, len); 29212a08440Sreyk break; 29312a08440Sreyk } 29412a08440Sreyk frm += len + 2; 29512a08440Sreyk 29612a08440Sreyk if (frm >= snapend) 29712a08440Sreyk break; 29812a08440Sreyk } 29912a08440Sreyk 30012a08440Sreyk #undef ELEM_CHECK 30112a08440Sreyk 30212a08440Sreyk return (0); 30312a08440Sreyk 30412a08440Sreyk trunc: 30512a08440Sreyk /* Truncated elements in frame */ 30612a08440Sreyk return (1); 30712a08440Sreyk } 30812a08440Sreyk 30912a08440Sreyk int 31012a08440Sreyk ieee80211_frame(struct ieee80211_frame *wh, u_int len) 31112a08440Sreyk { 31212a08440Sreyk u_int8_t subtype, type, *frm; 31312a08440Sreyk 31412a08440Sreyk TCARR(wh->i_fc); 31512a08440Sreyk 31612a08440Sreyk type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 31712a08440Sreyk subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 31812a08440Sreyk 31912a08440Sreyk frm = (u_int8_t *)&wh[1]; 32012a08440Sreyk 32112a08440Sreyk switch (type) { 32212a08440Sreyk case IEEE80211_FC0_TYPE_DATA: 32312a08440Sreyk printf(": data"); 32412a08440Sreyk break; 32512a08440Sreyk case IEEE80211_FC0_TYPE_MGT: 32612a08440Sreyk printf(": %s", ieee80211_mgt_subtype_name[ 32712a08440Sreyk subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]); 32812a08440Sreyk switch (subtype) { 32912a08440Sreyk case IEEE80211_FC0_SUBTYPE_BEACON: 33012a08440Sreyk case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 33112a08440Sreyk if (ieee80211_elements(wh, len) != 0) 33212a08440Sreyk goto trunc; 33312a08440Sreyk break; 33412a08440Sreyk case IEEE80211_FC0_SUBTYPE_AUTH: 33512a08440Sreyk TCHECK2(*frm, 2); /* Auth Algorithm */ 33612a08440Sreyk switch (IEEE80211_AUTH_ALGORITHM(frm)) { 33712a08440Sreyk case IEEE80211_AUTH_ALG_OPEN: 33812a08440Sreyk TCHECK2(*frm, 4); /* Auth Transaction */ 33912a08440Sreyk switch (IEEE80211_AUTH_TRANSACTION(frm)) { 34012a08440Sreyk case IEEE80211_AUTH_OPEN_REQUEST: 34112a08440Sreyk printf(" request"); 34212a08440Sreyk break; 34312a08440Sreyk case IEEE80211_AUTH_OPEN_RESPONSE: 34412a08440Sreyk printf(" response"); 34512a08440Sreyk break; 34612a08440Sreyk } 34712a08440Sreyk break; 34812a08440Sreyk case IEEE80211_AUTH_ALG_SHARED: 34912a08440Sreyk TCHECK2(*frm, 4); /* Auth Transaction */ 35012a08440Sreyk switch (IEEE80211_AUTH_TRANSACTION(frm)) { 35112a08440Sreyk case IEEE80211_AUTH_SHARED_REQUEST: 35212a08440Sreyk printf(" request"); 35312a08440Sreyk break; 35412a08440Sreyk case IEEE80211_AUTH_SHARED_CHALLENGE: 35512a08440Sreyk printf(" challenge"); 35612a08440Sreyk break; 35712a08440Sreyk case IEEE80211_AUTH_SHARED_RESPONSE: 35812a08440Sreyk printf(" response"); 35912a08440Sreyk break; 36012a08440Sreyk case IEEE80211_AUTH_SHARED_PASS: 36112a08440Sreyk printf(" pass"); 36212a08440Sreyk break; 36312a08440Sreyk } 36412a08440Sreyk break; 36512a08440Sreyk case IEEE80211_AUTH_ALG_LEAP: 36612a08440Sreyk printf(" (leap)"); 36712a08440Sreyk break; 36812a08440Sreyk } 36912a08440Sreyk break; 37012a08440Sreyk } 37112a08440Sreyk break; 37212a08440Sreyk default: 37312a08440Sreyk printf(": type#%d", type); 37412a08440Sreyk break; 37512a08440Sreyk } 37612a08440Sreyk 37712a08440Sreyk if (wh->i_fc[1] & IEEE80211_FC1_WEP) 37812a08440Sreyk printf(", WEP"); 37912a08440Sreyk 38012a08440Sreyk return (0); 38112a08440Sreyk 38212a08440Sreyk trunc: 38312a08440Sreyk /* Truncated 802.11 frame */ 38412a08440Sreyk return (1); 38512a08440Sreyk } 38612a08440Sreyk 38712a08440Sreyk u_int 38812a08440Sreyk ieee80211_any2ieee(u_int freq, u_int flags) 38912a08440Sreyk { 39012a08440Sreyk if (flags & IEEE80211_CHAN_2GHZ) { 39112a08440Sreyk if (freq == 2484) 39212a08440Sreyk return 14; 39312a08440Sreyk if (freq < 2484) 39412a08440Sreyk return (freq - 2407) / 5; 39512a08440Sreyk else 39612a08440Sreyk return 15 + ((freq - 2512) / 20); 39712a08440Sreyk } else if (flags & IEEE80211_CHAN_5GHZ) { 39812a08440Sreyk return (freq - 5000) / 5; 39912a08440Sreyk } else { 40012a08440Sreyk /* Assume channel is already an IEEE number */ 40112a08440Sreyk return (freq); 40212a08440Sreyk } 40312a08440Sreyk } 40412a08440Sreyk 40512a08440Sreyk int 40612a08440Sreyk ieee80211_print(struct ieee80211_frame *wh, u_int len) 40712a08440Sreyk { 40812a08440Sreyk if (eflag) 40912a08440Sreyk if (ieee80211_hdr(wh)) 41012a08440Sreyk return (1); 41112a08440Sreyk 41212a08440Sreyk printf("802.11"); 41312a08440Sreyk 41412a08440Sreyk return (ieee80211_frame(wh, len)); 41512a08440Sreyk } 41612a08440Sreyk 41712a08440Sreyk void 41812a08440Sreyk ieee802_11_if_print(u_char *user, const struct pcap_pkthdr *h, 41912a08440Sreyk const u_char *p) 42012a08440Sreyk { 42112a08440Sreyk struct ieee80211_frame *wh = (struct ieee80211_frame*)p; 42212a08440Sreyk 42312a08440Sreyk ts_print(&h->ts); 42412a08440Sreyk 42512a08440Sreyk packetp = p; 42612a08440Sreyk snapend = p + h->caplen; 42712a08440Sreyk 42812a08440Sreyk if (ieee80211_print(wh, (u_int)h->caplen) != 0) 42912a08440Sreyk printf("[|802.11]"); 43012a08440Sreyk 43112a08440Sreyk if (xflag) 43212a08440Sreyk default_print(p, (u_int)h->caplen); 43312a08440Sreyk 43412a08440Sreyk putchar('\n'); 43512a08440Sreyk 43612a08440Sreyk return; 43712a08440Sreyk } 43812a08440Sreyk 43912a08440Sreyk void 44012a08440Sreyk ieee802_11_radio_if_print(u_char *user, const struct pcap_pkthdr *h, 44112a08440Sreyk const u_char *p) 44212a08440Sreyk { 44312a08440Sreyk struct ieee80211_radiotap_header *rh = 44412a08440Sreyk (struct ieee80211_radiotap_header*)p; 44512a08440Sreyk struct ieee80211_frame *wh; 44612a08440Sreyk u_int8_t *t; 44712a08440Sreyk u_int32_t present; 44812a08440Sreyk u_int len, rh_len; 44912a08440Sreyk 45012a08440Sreyk ts_print(&h->ts); 45112a08440Sreyk 45212a08440Sreyk packetp = p; 45312a08440Sreyk snapend = p + h->caplen; 45412a08440Sreyk 45512a08440Sreyk TCHECK(*rh); 45612a08440Sreyk 45712a08440Sreyk len = h->caplen; 45812a08440Sreyk rh_len = letoh16(rh->it_len); 45912a08440Sreyk if (rh->it_version != 0) { 46012a08440Sreyk printf("[?radiotap + 802.11 v:%u]\n", rh->it_version); 46112a08440Sreyk goto out; 46212a08440Sreyk } 46312a08440Sreyk 46412a08440Sreyk wh = (struct ieee80211_frame *)(p + rh_len); 46512a08440Sreyk if (len <= rh_len || ieee80211_print(wh, len - rh_len)) 46612a08440Sreyk printf("[|802.11]"); 46712a08440Sreyk 46812a08440Sreyk t = (u_int8_t*)p + sizeof(struct ieee80211_radiotap_header); 46912a08440Sreyk 47012a08440Sreyk if ((present = letoh32(rh->it_present)) == 0) 47112a08440Sreyk goto out; 47212a08440Sreyk 47312a08440Sreyk printf(", <radiotap v%u", rh->it_version); 47412a08440Sreyk 47512a08440Sreyk #define RADIOTAP(_x) \ 47612a08440Sreyk (present & (1 << IEEE80211_RADIOTAP_##_x)) 47712a08440Sreyk 47812a08440Sreyk if (RADIOTAP(TSFT)) { 47912a08440Sreyk TCHECK2(*t, 8); 48012a08440Sreyk if (vflag > 1) 48112a08440Sreyk printf(", tsf %llu", letoh64(*(u_int64_t*)t)); 48212a08440Sreyk t += 8; 48312a08440Sreyk } 48412a08440Sreyk 48512a08440Sreyk if (RADIOTAP(FLAGS)) { 48612a08440Sreyk u_int8_t flags = *(u_int8_t*)t; 487*026ca542Sderaadt TCHECK2(*t, 1); 488*026ca542Sderaadt 48912a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_CFP) 49012a08440Sreyk printf(", CFP"); 49112a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_SHORTPRE) 49212a08440Sreyk printf(", SHORTPRE"); 49312a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_WEP) 49412a08440Sreyk printf(", WEP"); 49512a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_FRAG) 49612a08440Sreyk printf(", FRAG"); 49712a08440Sreyk t += 1; 49812a08440Sreyk } 49912a08440Sreyk 50012a08440Sreyk if (RADIOTAP(RATE)) { 50112a08440Sreyk TCHECK2(*t, 1); 50212a08440Sreyk if (vflag) 50312a08440Sreyk printf(", %uMbit/s", (*(u_int8_t*)t) / 2); 50412a08440Sreyk t += 1; 50512a08440Sreyk } 50612a08440Sreyk 50712a08440Sreyk if (RADIOTAP(CHANNEL)) { 50812a08440Sreyk u_int16_t freq, flags; 50912a08440Sreyk TCHECK2(*t, 2); 51012a08440Sreyk 51112a08440Sreyk freq = letoh16(*(u_int16_t*)t); 51212a08440Sreyk t += 2; 51312a08440Sreyk TCHECK2(*t, 2); 51412a08440Sreyk flags = letoh16(*(u_int16_t*)t); 51512a08440Sreyk t += 2; 51612a08440Sreyk 51712a08440Sreyk printf(", chan %u", ieee80211_any2ieee(freq, flags)); 51812a08440Sreyk 51912a08440Sreyk if (flags & IEEE80211_CHAN_DYN && 52012a08440Sreyk flags & IEEE80211_CHAN_2GHZ) 52112a08440Sreyk printf(", 11g"); 52212a08440Sreyk else if (flags & IEEE80211_CHAN_CCK && 52312a08440Sreyk flags & IEEE80211_CHAN_2GHZ) 52412a08440Sreyk printf(", 11b"); 52512a08440Sreyk else if (flags & IEEE80211_CHAN_OFDM && 52612a08440Sreyk flags & IEEE80211_CHAN_2GHZ) 52712a08440Sreyk printf(", 11G"); 52812a08440Sreyk else if (flags & IEEE80211_CHAN_OFDM && 52912a08440Sreyk flags & IEEE80211_CHAN_5GHZ) 53012a08440Sreyk printf(", 11a"); 53112a08440Sreyk 53212a08440Sreyk if (flags & IEEE80211_CHAN_TURBO) 53312a08440Sreyk printf(", TURBO"); 53412a08440Sreyk if (flags & IEEE80211_CHAN_XR) 53512a08440Sreyk printf(", XR"); 53612a08440Sreyk } 53712a08440Sreyk 53812a08440Sreyk if (RADIOTAP(FHSS)) { 53912a08440Sreyk TCHECK2(*t, 2); 54012a08440Sreyk printf(", fhss %u/%u", *(u_int8_t*)t, *(u_int8_t*)t + 1); 54112a08440Sreyk t += 2; 54212a08440Sreyk } 54312a08440Sreyk 54412a08440Sreyk if (RADIOTAP(DBM_ANTSIGNAL)) { 54512a08440Sreyk TCHECK(*t); 54612a08440Sreyk printf(", sig %ddBm", *(int8_t*)t); 54712a08440Sreyk t += 1; 54812a08440Sreyk } 54912a08440Sreyk 55012a08440Sreyk if (RADIOTAP(DBM_ANTNOISE)) { 55112a08440Sreyk TCHECK(*t); 55212a08440Sreyk printf(", noise %ddBm", *(int8_t*)t); 55312a08440Sreyk t += 1; 55412a08440Sreyk } 55512a08440Sreyk 55612a08440Sreyk if (RADIOTAP(LOCK_QUALITY)) { 55712a08440Sreyk TCHECK2(*t, 2); 55812a08440Sreyk if (vflag) 55912a08440Sreyk printf(", quality %u", letoh16(*(u_int16_t*)t)); 56012a08440Sreyk t += 2; 56112a08440Sreyk } 56212a08440Sreyk 56312a08440Sreyk if (RADIOTAP(TX_ATTENUATION)) { 56412a08440Sreyk TCHECK2(*t, 2); 56512a08440Sreyk if (vflag) 56612a08440Sreyk printf(", txatt %u", 56712a08440Sreyk letoh16(*(u_int16_t*)t)); 56812a08440Sreyk t += 2; 56912a08440Sreyk } 57012a08440Sreyk 57112a08440Sreyk if (RADIOTAP(DB_TX_ATTENUATION)) { 57212a08440Sreyk TCHECK2(*t, 2); 57312a08440Sreyk if (vflag) 57412a08440Sreyk printf(", txatt %udB", 57512a08440Sreyk letoh16(*(u_int16_t*)t)); 57612a08440Sreyk t += 2; 57712a08440Sreyk } 57812a08440Sreyk 57912a08440Sreyk if (RADIOTAP(DBM_TX_POWER)) { 58012a08440Sreyk TCHECK(*t); 58112a08440Sreyk printf(", txpower %ddBm", *(int8_t*)t); 58212a08440Sreyk t += 1; 58312a08440Sreyk } 58412a08440Sreyk 58512a08440Sreyk if (RADIOTAP(ANTENNA)) { 58612a08440Sreyk TCHECK(*t); 58712a08440Sreyk if (vflag) 58812a08440Sreyk printf(", antenna %u", *(u_int8_t*)t); 58912a08440Sreyk t += 1; 59012a08440Sreyk } 59112a08440Sreyk 59212a08440Sreyk if (RADIOTAP(DB_ANTSIGNAL)) { 59312a08440Sreyk TCHECK(*t); 59412a08440Sreyk printf(", signal %udB", *(u_int8_t*)t); 59512a08440Sreyk t += 1; 59612a08440Sreyk } 59712a08440Sreyk 59812a08440Sreyk if (RADIOTAP(DB_ANTNOISE)) { 59912a08440Sreyk TCHECK(*t); 60012a08440Sreyk printf(", noise %udB", *(u_int8_t*)t); 60112a08440Sreyk t += 1; 60212a08440Sreyk } 60312a08440Sreyk 60412a08440Sreyk if (RADIOTAP(FCS)) { 60512a08440Sreyk TCHECK2(*t, 4); 60612a08440Sreyk if (vflag) 60712a08440Sreyk printf(", fcs %08x", letoh32(*(u_int32_t*)t)); 60812a08440Sreyk t += 4; 60912a08440Sreyk } 61012a08440Sreyk 61112a08440Sreyk #undef RADIOTAP 61212a08440Sreyk 61312a08440Sreyk putchar('>'); 61412a08440Sreyk 61512a08440Sreyk goto out; 61612a08440Sreyk 61712a08440Sreyk trunc: 61812a08440Sreyk /* Truncated frame */ 61912a08440Sreyk printf("[|radiotap + 802.11]"); 62012a08440Sreyk 62112a08440Sreyk out: 62212a08440Sreyk if (xflag) 62312a08440Sreyk default_print(p, h->caplen); 62412a08440Sreyk 62512a08440Sreyk putchar('\n'); 62612a08440Sreyk 62712a08440Sreyk return; 62812a08440Sreyk } 629