1*b72abdefSreyk /* $OpenBSD: print-802_11.c,v 1.4 2005/05/28 09:01:52 reyk 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 *); 61*b72abdefSreyk int ieee80211_data(struct ieee80211_frame *, u_int); 6212a08440Sreyk void ieee80211_print_element(u_int8_t *, u_int); 6312a08440Sreyk void ieee80211_print_essid(u_int8_t *, u_int); 6412a08440Sreyk int ieee80211_elements(struct ieee80211_frame *, u_int); 6512a08440Sreyk int ieee80211_frame(struct ieee80211_frame *, u_int); 6612a08440Sreyk int ieee80211_print(struct ieee80211_frame *, u_int); 6712a08440Sreyk u_int ieee80211_any2ieee(u_int, u_int); 6812a08440Sreyk 6912a08440Sreyk #define TCARR(a) TCHECK2(*a, sizeof(a)) 7012a08440Sreyk 7112a08440Sreyk int 7212a08440Sreyk ieee80211_hdr(struct ieee80211_frame *wh) 7312a08440Sreyk { 7412a08440Sreyk struct ieee80211_frame_addr4 *w4; 7512a08440Sreyk 7612a08440Sreyk switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 7712a08440Sreyk case IEEE80211_FC1_DIR_NODS: 7812a08440Sreyk TCARR(wh->i_addr2); 7912a08440Sreyk printf("%s", etheraddr_string(wh->i_addr2)); 8012a08440Sreyk TCARR(wh->i_addr1); 8112a08440Sreyk printf(" > %s", etheraddr_string(wh->i_addr1)); 8212a08440Sreyk TCARR(wh->i_addr3); 8312a08440Sreyk printf(", bssid %s", etheraddr_string(wh->i_addr3)); 8412a08440Sreyk break; 8512a08440Sreyk case IEEE80211_FC1_DIR_TODS: 8612a08440Sreyk TCARR(wh->i_addr2); 8712a08440Sreyk printf("%s", etheraddr_string(wh->i_addr2)); 8812a08440Sreyk TCARR(wh->i_addr3); 8912a08440Sreyk printf(" > %s", etheraddr_string(wh->i_addr3)); 9012a08440Sreyk TCARR(wh->i_addr1); 9112a08440Sreyk printf(", bssid %s, > DS", etheraddr_string(wh->i_addr1)); 9212a08440Sreyk break; 9312a08440Sreyk case IEEE80211_FC1_DIR_FROMDS: 9412a08440Sreyk TCARR(wh->i_addr3); 9512a08440Sreyk printf("%s", etheraddr_string(wh->i_addr3)); 9612a08440Sreyk TCARR(wh->i_addr1); 9712a08440Sreyk printf(" > %s", etheraddr_string(wh->i_addr1)); 9812a08440Sreyk TCARR(wh->i_addr2); 9912a08440Sreyk printf(", bssid %s, DS >", etheraddr_string(wh->i_addr2)); 10012a08440Sreyk break; 10112a08440Sreyk case IEEE80211_FC1_DIR_DSTODS: 10212a08440Sreyk w4 = (struct ieee80211_frame_addr4 *) wh; 10312a08440Sreyk TCARR(w4->i_addr4); 10412a08440Sreyk printf("%s", etheraddr_string(w4->i_addr4)); 10512a08440Sreyk TCARR(w4->i_addr3); 10612a08440Sreyk printf(" > %s", etheraddr_string(w4->i_addr3)); 10712a08440Sreyk TCARR(w4->i_addr2); 10812a08440Sreyk printf(", bssid %s", etheraddr_string(w4->i_addr2)); 10912a08440Sreyk TCARR(w4->i_addr1); 11012a08440Sreyk printf(" > %s, DS > DS", etheraddr_string(w4->i_addr1)); 11112a08440Sreyk break; 11212a08440Sreyk } 11312a08440Sreyk if (vflag) { 11412a08440Sreyk TCARR(wh->i_seq); 11512a08440Sreyk printf(" (seq %u): ", letoh16(*(u_int16_t *)&wh->i_seq[0])); 11612a08440Sreyk } else 11712a08440Sreyk printf(": "); 11812a08440Sreyk 11912a08440Sreyk return (0); 12012a08440Sreyk 12112a08440Sreyk trunc: 12212a08440Sreyk /* Truncated elements in frame */ 12312a08440Sreyk return (1); 12412a08440Sreyk } 12512a08440Sreyk 126*b72abdefSreyk int 127*b72abdefSreyk ieee80211_data(struct ieee80211_frame *wh, u_int len) 128*b72abdefSreyk { 129*b72abdefSreyk u_int8_t *t = (u_int8_t *)wh; 130*b72abdefSreyk u_int datalen; 131*b72abdefSreyk 132*b72abdefSreyk TCHECK2(*t, sizeof(struct ieee80211_frame)); 133*b72abdefSreyk t += sizeof(struct ieee80211_frame); 134*b72abdefSreyk datalen = len - sizeof(struct ieee80211_frame); 135*b72abdefSreyk 136*b72abdefSreyk switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 137*b72abdefSreyk case IEEE80211_FC1_DIR_TODS: 138*b72abdefSreyk llc_print(t, datalen, datalen, wh->i_addr2, wh->i_addr3); 139*b72abdefSreyk break; 140*b72abdefSreyk case IEEE80211_FC1_DIR_FROMDS: 141*b72abdefSreyk llc_print(t, datalen, datalen, wh->i_addr3, wh->i_addr1); 142*b72abdefSreyk break; 143*b72abdefSreyk case IEEE80211_FC1_DIR_NODS: 144*b72abdefSreyk case IEEE80211_FC1_DIR_DSTODS: 145*b72abdefSreyk break; 146*b72abdefSreyk } 147*b72abdefSreyk 148*b72abdefSreyk return (0); 149*b72abdefSreyk 150*b72abdefSreyk trunc: 151*b72abdefSreyk /* Truncated elements in frame */ 152*b72abdefSreyk return (1); 153*b72abdefSreyk } 154*b72abdefSreyk 15512a08440Sreyk /* Caller checks len */ 15612a08440Sreyk void 15712a08440Sreyk ieee80211_print_element(u_int8_t *data, u_int len) 15812a08440Sreyk { 15912a08440Sreyk u_int8_t *p; 1609cbdb746Sderaadt int i; 16112a08440Sreyk 16212a08440Sreyk printf(" 0x"); 1639cbdb746Sderaadt for (i = 0, p = data; i < len; i++, p++) 16412a08440Sreyk printf("%02x", *p); 16512a08440Sreyk } 16612a08440Sreyk 16712a08440Sreyk /* Caller checks len */ 16812a08440Sreyk void 16912a08440Sreyk ieee80211_print_essid(u_int8_t *essid, u_int len) 17012a08440Sreyk { 17112a08440Sreyk u_int8_t *p; 1729cbdb746Sderaadt int i; 17312a08440Sreyk 17412a08440Sreyk if (len > IEEE80211_NWID_LEN) 17512a08440Sreyk len = IEEE80211_NWID_LEN; 17612a08440Sreyk 17712a08440Sreyk /* determine printable or not */ 17812a08440Sreyk for (i = 0, p = essid; i < len; i++, p++) { 17912a08440Sreyk if (*p < ' ' || *p > 0x7e) 18012a08440Sreyk break; 18112a08440Sreyk } 18212a08440Sreyk if (i == len) { 18312a08440Sreyk printf(" ("); 18412a08440Sreyk for (i = 0, p = essid; i < len; i++, p++) 18512a08440Sreyk putchar(*p); 18612a08440Sreyk putchar(')'); 1879cbdb746Sderaadt } else 18812a08440Sreyk ieee80211_print_element(essid, len); 18912a08440Sreyk } 19012a08440Sreyk 19112a08440Sreyk int 19212a08440Sreyk ieee80211_elements(struct ieee80211_frame *wh, u_int flen) 19312a08440Sreyk { 19412a08440Sreyk u_int8_t *buf, *frm; 19512a08440Sreyk u_int8_t *tstamp, *bintval, *capinfo; 19612a08440Sreyk int i; 19712a08440Sreyk 19812a08440Sreyk buf = (u_int8_t *)wh; 19912a08440Sreyk frm = (u_int8_t *)&wh[1]; 20012a08440Sreyk 20112a08440Sreyk tstamp = frm; 20212a08440Sreyk TCHECK2(*tstamp, 8); 20312a08440Sreyk frm += 8; 20412a08440Sreyk 20512a08440Sreyk if (vflag > 1) 20612a08440Sreyk printf(", timestamp %llu", letoh64(*(u_int64_t *)tstamp)); 20712a08440Sreyk 20812a08440Sreyk bintval = frm; 20912a08440Sreyk TCHECK2(*bintval, 2); 21012a08440Sreyk frm += 2; 21112a08440Sreyk 21212a08440Sreyk if (vflag > 1) 21312a08440Sreyk printf(", interval %u", letoh16(*(u_int16_t *)bintval)); 21412a08440Sreyk 21512a08440Sreyk capinfo = frm; 21612a08440Sreyk TCHECK2(*capinfo, 2); 21712a08440Sreyk frm += 2; 21812a08440Sreyk 21912a08440Sreyk if (vflag) 22012a08440Sreyk printb(", caps", letoh16(*(u_int16_t *)capinfo), 22112a08440Sreyk IEEE80211_CAPINFO_BITS); 22212a08440Sreyk 22312a08440Sreyk while (TTEST2(*frm, 2)) { 22412a08440Sreyk u_int len = frm[1]; 22512a08440Sreyk u_int8_t *data = frm + 2; 22612a08440Sreyk 22712a08440Sreyk if (!TTEST2(*data, len)) 22812a08440Sreyk break; 22912a08440Sreyk 23012a08440Sreyk #define ELEM_CHECK(l) if (len != l) break 23112a08440Sreyk 23212a08440Sreyk switch (*frm) { 23312a08440Sreyk case IEEE80211_ELEMID_SSID: 23412a08440Sreyk printf(", ssid"); 23512a08440Sreyk ieee80211_print_essid(data, len); 23612a08440Sreyk break; 23712a08440Sreyk case IEEE80211_ELEMID_RATES: 23812a08440Sreyk printf(", rates"); 23912a08440Sreyk if (!vflag) 24012a08440Sreyk break; 24112a08440Sreyk for (i = len; i > 0; i--, data++) 24212a08440Sreyk printf(" %uM", 24312a08440Sreyk (data[0] & IEEE80211_RATE_VAL) / 2); 24412a08440Sreyk break; 24512a08440Sreyk case IEEE80211_ELEMID_FHPARMS: 24612a08440Sreyk ELEM_CHECK(5); 24712a08440Sreyk printf(", fh (dwell %u, chan %u, index %u)", 24812a08440Sreyk (data[1] << 8) | data[0], 24912a08440Sreyk (data[2] - 1) * 80 + data[3], /* FH_CHAN */ 25012a08440Sreyk data[4]); 25112a08440Sreyk break; 25212a08440Sreyk case IEEE80211_ELEMID_DSPARMS: 25312a08440Sreyk ELEM_CHECK(1); 25412a08440Sreyk printf(", ds"); 25512a08440Sreyk if (vflag) 25612a08440Sreyk printf(" (chan %u)", data[0]); 25712a08440Sreyk break; 25812a08440Sreyk case IEEE80211_ELEMID_CFPARMS: 25912a08440Sreyk printf(", cf"); 26012a08440Sreyk if (vflag) 26112a08440Sreyk ieee80211_print_element(data, len); 26212a08440Sreyk break; 26312a08440Sreyk case IEEE80211_ELEMID_TIM: 26412a08440Sreyk printf(", tim"); 26512a08440Sreyk if (vflag) 26612a08440Sreyk ieee80211_print_element(data, len); 26712a08440Sreyk break; 26812a08440Sreyk case IEEE80211_ELEMID_IBSSPARMS: 26912a08440Sreyk printf(", ibss"); 27012a08440Sreyk if (vflag) 27112a08440Sreyk ieee80211_print_element(data, len); 27212a08440Sreyk break; 27312a08440Sreyk case IEEE80211_ELEMID_COUNTRY: 27412a08440Sreyk printf(", country"); 27512a08440Sreyk for (i = len; i > 0; i--, data++) 27612a08440Sreyk printf(" %u", data[0]); 27712a08440Sreyk break; 27812a08440Sreyk case IEEE80211_ELEMID_CHALLENGE: 27912a08440Sreyk printf(", challenge"); 28012a08440Sreyk if (vflag) 28112a08440Sreyk ieee80211_print_element(data, len); 28212a08440Sreyk break; 28312a08440Sreyk case IEEE80211_ELEMID_ERP: 28412a08440Sreyk printf(", erp"); 28512a08440Sreyk if (vflag) 28612a08440Sreyk ieee80211_print_element(data, len); 28712a08440Sreyk break; 28812a08440Sreyk case IEEE80211_ELEMID_RSN: 28912a08440Sreyk printf(", rsn"); 29012a08440Sreyk if (vflag) 29112a08440Sreyk ieee80211_print_element(data, len); 29212a08440Sreyk break; 29312a08440Sreyk case IEEE80211_ELEMID_XRATES: 29412a08440Sreyk printf(", xrates"); 29512a08440Sreyk if (!vflag) 29612a08440Sreyk break; 29712a08440Sreyk for (i = len; i > 0; i--, data++) 29812a08440Sreyk printf(" %uM", 29912a08440Sreyk (data[0] & IEEE80211_RATE_VAL) / 2); 30012a08440Sreyk break; 30112a08440Sreyk case IEEE80211_ELEMID_TPC: 30212a08440Sreyk printf(", tpc"); 30312a08440Sreyk if (vflag) 30412a08440Sreyk ieee80211_print_element(data, len); 30512a08440Sreyk break; 30612a08440Sreyk case IEEE80211_ELEMID_CCKM: 30712a08440Sreyk printf(", cckm"); 30812a08440Sreyk if (vflag) 30912a08440Sreyk ieee80211_print_element(data, len); 31012a08440Sreyk break; 31112a08440Sreyk case IEEE80211_ELEMID_VENDOR: 31212a08440Sreyk printf(", vendor"); 31312a08440Sreyk if (vflag) 31412a08440Sreyk ieee80211_print_element(data, len); 31512a08440Sreyk break; 31612a08440Sreyk default: 31712a08440Sreyk printf(", %u:%u", (u_int) *frm, len); 31812a08440Sreyk if (vflag) 31912a08440Sreyk ieee80211_print_element(data, len); 32012a08440Sreyk break; 32112a08440Sreyk } 32212a08440Sreyk frm += len + 2; 32312a08440Sreyk 32412a08440Sreyk if (frm >= snapend) 32512a08440Sreyk break; 32612a08440Sreyk } 32712a08440Sreyk 32812a08440Sreyk #undef ELEM_CHECK 32912a08440Sreyk 33012a08440Sreyk return (0); 33112a08440Sreyk 33212a08440Sreyk trunc: 33312a08440Sreyk /* Truncated elements in frame */ 33412a08440Sreyk return (1); 33512a08440Sreyk } 33612a08440Sreyk 33712a08440Sreyk int 33812a08440Sreyk ieee80211_frame(struct ieee80211_frame *wh, u_int len) 33912a08440Sreyk { 34012a08440Sreyk u_int8_t subtype, type, *frm; 34112a08440Sreyk 34212a08440Sreyk TCARR(wh->i_fc); 34312a08440Sreyk 34412a08440Sreyk type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 34512a08440Sreyk subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 34612a08440Sreyk 34712a08440Sreyk frm = (u_int8_t *)&wh[1]; 34812a08440Sreyk 34912a08440Sreyk switch (type) { 35012a08440Sreyk case IEEE80211_FC0_TYPE_DATA: 351*b72abdefSreyk printf(": data: "); 352*b72abdefSreyk ieee80211_data(wh, len); 35312a08440Sreyk break; 35412a08440Sreyk case IEEE80211_FC0_TYPE_MGT: 35512a08440Sreyk printf(": %s", ieee80211_mgt_subtype_name[ 35612a08440Sreyk subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]); 35712a08440Sreyk switch (subtype) { 35812a08440Sreyk case IEEE80211_FC0_SUBTYPE_BEACON: 35912a08440Sreyk case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 36012a08440Sreyk if (ieee80211_elements(wh, len) != 0) 36112a08440Sreyk goto trunc; 36212a08440Sreyk break; 36312a08440Sreyk case IEEE80211_FC0_SUBTYPE_AUTH: 36412a08440Sreyk TCHECK2(*frm, 2); /* Auth Algorithm */ 36512a08440Sreyk switch (IEEE80211_AUTH_ALGORITHM(frm)) { 36612a08440Sreyk case IEEE80211_AUTH_ALG_OPEN: 36712a08440Sreyk TCHECK2(*frm, 4); /* Auth Transaction */ 36812a08440Sreyk switch (IEEE80211_AUTH_TRANSACTION(frm)) { 36912a08440Sreyk case IEEE80211_AUTH_OPEN_REQUEST: 37012a08440Sreyk printf(" request"); 37112a08440Sreyk break; 37212a08440Sreyk case IEEE80211_AUTH_OPEN_RESPONSE: 37312a08440Sreyk printf(" response"); 37412a08440Sreyk break; 37512a08440Sreyk } 37612a08440Sreyk break; 37712a08440Sreyk case IEEE80211_AUTH_ALG_SHARED: 37812a08440Sreyk TCHECK2(*frm, 4); /* Auth Transaction */ 37912a08440Sreyk switch (IEEE80211_AUTH_TRANSACTION(frm)) { 38012a08440Sreyk case IEEE80211_AUTH_SHARED_REQUEST: 38112a08440Sreyk printf(" request"); 38212a08440Sreyk break; 38312a08440Sreyk case IEEE80211_AUTH_SHARED_CHALLENGE: 38412a08440Sreyk printf(" challenge"); 38512a08440Sreyk break; 38612a08440Sreyk case IEEE80211_AUTH_SHARED_RESPONSE: 38712a08440Sreyk printf(" response"); 38812a08440Sreyk break; 38912a08440Sreyk case IEEE80211_AUTH_SHARED_PASS: 39012a08440Sreyk printf(" pass"); 39112a08440Sreyk break; 39212a08440Sreyk } 39312a08440Sreyk break; 39412a08440Sreyk case IEEE80211_AUTH_ALG_LEAP: 39512a08440Sreyk printf(" (leap)"); 39612a08440Sreyk break; 39712a08440Sreyk } 39812a08440Sreyk break; 39912a08440Sreyk } 40012a08440Sreyk break; 40112a08440Sreyk default: 40212a08440Sreyk printf(": type#%d", type); 40312a08440Sreyk break; 40412a08440Sreyk } 40512a08440Sreyk 40612a08440Sreyk if (wh->i_fc[1] & IEEE80211_FC1_WEP) 40712a08440Sreyk printf(", WEP"); 40812a08440Sreyk 40912a08440Sreyk return (0); 41012a08440Sreyk 41112a08440Sreyk trunc: 41212a08440Sreyk /* Truncated 802.11 frame */ 41312a08440Sreyk return (1); 41412a08440Sreyk } 41512a08440Sreyk 41612a08440Sreyk u_int 41712a08440Sreyk ieee80211_any2ieee(u_int freq, u_int flags) 41812a08440Sreyk { 41912a08440Sreyk if (flags & IEEE80211_CHAN_2GHZ) { 42012a08440Sreyk if (freq == 2484) 42112a08440Sreyk return 14; 42212a08440Sreyk if (freq < 2484) 42312a08440Sreyk return (freq - 2407) / 5; 42412a08440Sreyk else 42512a08440Sreyk return 15 + ((freq - 2512) / 20); 42612a08440Sreyk } else if (flags & IEEE80211_CHAN_5GHZ) { 42712a08440Sreyk return (freq - 5000) / 5; 42812a08440Sreyk } else { 42912a08440Sreyk /* Assume channel is already an IEEE number */ 43012a08440Sreyk return (freq); 43112a08440Sreyk } 43212a08440Sreyk } 43312a08440Sreyk 43412a08440Sreyk int 43512a08440Sreyk ieee80211_print(struct ieee80211_frame *wh, u_int len) 43612a08440Sreyk { 43712a08440Sreyk if (eflag) 43812a08440Sreyk if (ieee80211_hdr(wh)) 43912a08440Sreyk return (1); 44012a08440Sreyk 44112a08440Sreyk printf("802.11"); 44212a08440Sreyk 44312a08440Sreyk return (ieee80211_frame(wh, len)); 44412a08440Sreyk } 44512a08440Sreyk 44612a08440Sreyk void 44712a08440Sreyk ieee802_11_if_print(u_char *user, const struct pcap_pkthdr *h, 44812a08440Sreyk const u_char *p) 44912a08440Sreyk { 45012a08440Sreyk struct ieee80211_frame *wh = (struct ieee80211_frame*)p; 45112a08440Sreyk 45212a08440Sreyk ts_print(&h->ts); 45312a08440Sreyk 45412a08440Sreyk packetp = p; 45512a08440Sreyk snapend = p + h->caplen; 45612a08440Sreyk 45712a08440Sreyk if (ieee80211_print(wh, (u_int)h->caplen) != 0) 45812a08440Sreyk printf("[|802.11]"); 45912a08440Sreyk 46012a08440Sreyk if (xflag) 46112a08440Sreyk default_print(p, (u_int)h->caplen); 46212a08440Sreyk 46312a08440Sreyk putchar('\n'); 46412a08440Sreyk } 46512a08440Sreyk 46612a08440Sreyk void 46712a08440Sreyk ieee802_11_radio_if_print(u_char *user, const struct pcap_pkthdr *h, 46812a08440Sreyk const u_char *p) 46912a08440Sreyk { 47012a08440Sreyk struct ieee80211_radiotap_header *rh = 47112a08440Sreyk (struct ieee80211_radiotap_header*)p; 47212a08440Sreyk struct ieee80211_frame *wh; 47312a08440Sreyk u_int8_t *t; 47412a08440Sreyk u_int32_t present; 47512a08440Sreyk u_int len, rh_len; 47612a08440Sreyk 47712a08440Sreyk ts_print(&h->ts); 47812a08440Sreyk 47912a08440Sreyk packetp = p; 48012a08440Sreyk snapend = p + h->caplen; 48112a08440Sreyk 48212a08440Sreyk TCHECK(*rh); 48312a08440Sreyk 48412a08440Sreyk len = h->caplen; 48512a08440Sreyk rh_len = letoh16(rh->it_len); 48612a08440Sreyk if (rh->it_version != 0) { 48712a08440Sreyk printf("[?radiotap + 802.11 v:%u]\n", rh->it_version); 48812a08440Sreyk goto out; 48912a08440Sreyk } 49012a08440Sreyk 49112a08440Sreyk wh = (struct ieee80211_frame *)(p + rh_len); 49212a08440Sreyk if (len <= rh_len || ieee80211_print(wh, len - rh_len)) 49312a08440Sreyk printf("[|802.11]"); 49412a08440Sreyk 49512a08440Sreyk t = (u_int8_t*)p + sizeof(struct ieee80211_radiotap_header); 49612a08440Sreyk 49712a08440Sreyk if ((present = letoh32(rh->it_present)) == 0) 49812a08440Sreyk goto out; 49912a08440Sreyk 50012a08440Sreyk printf(", <radiotap v%u", rh->it_version); 50112a08440Sreyk 50212a08440Sreyk #define RADIOTAP(_x) \ 50312a08440Sreyk (present & (1 << IEEE80211_RADIOTAP_##_x)) 50412a08440Sreyk 50512a08440Sreyk if (RADIOTAP(TSFT)) { 50612a08440Sreyk TCHECK2(*t, 8); 50712a08440Sreyk if (vflag > 1) 50812a08440Sreyk printf(", tsf %llu", letoh64(*(u_int64_t*)t)); 50912a08440Sreyk t += 8; 51012a08440Sreyk } 51112a08440Sreyk 51212a08440Sreyk if (RADIOTAP(FLAGS)) { 51312a08440Sreyk u_int8_t flags = *(u_int8_t*)t; 514026ca542Sderaadt TCHECK2(*t, 1); 515026ca542Sderaadt 51612a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_CFP) 51712a08440Sreyk printf(", CFP"); 51812a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_SHORTPRE) 51912a08440Sreyk printf(", SHORTPRE"); 52012a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_WEP) 52112a08440Sreyk printf(", WEP"); 52212a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_FRAG) 52312a08440Sreyk printf(", FRAG"); 52412a08440Sreyk t += 1; 52512a08440Sreyk } 52612a08440Sreyk 52712a08440Sreyk if (RADIOTAP(RATE)) { 52812a08440Sreyk TCHECK2(*t, 1); 52912a08440Sreyk if (vflag) 53012a08440Sreyk printf(", %uMbit/s", (*(u_int8_t*)t) / 2); 53112a08440Sreyk t += 1; 53212a08440Sreyk } 53312a08440Sreyk 53412a08440Sreyk if (RADIOTAP(CHANNEL)) { 53512a08440Sreyk u_int16_t freq, flags; 53612a08440Sreyk TCHECK2(*t, 2); 53712a08440Sreyk 53812a08440Sreyk freq = letoh16(*(u_int16_t*)t); 53912a08440Sreyk t += 2; 54012a08440Sreyk TCHECK2(*t, 2); 54112a08440Sreyk flags = letoh16(*(u_int16_t*)t); 54212a08440Sreyk t += 2; 54312a08440Sreyk 54412a08440Sreyk printf(", chan %u", ieee80211_any2ieee(freq, flags)); 54512a08440Sreyk 54612a08440Sreyk if (flags & IEEE80211_CHAN_DYN && 54712a08440Sreyk flags & IEEE80211_CHAN_2GHZ) 54812a08440Sreyk printf(", 11g"); 54912a08440Sreyk else if (flags & IEEE80211_CHAN_CCK && 55012a08440Sreyk flags & IEEE80211_CHAN_2GHZ) 55112a08440Sreyk printf(", 11b"); 55212a08440Sreyk else if (flags & IEEE80211_CHAN_OFDM && 55312a08440Sreyk flags & IEEE80211_CHAN_2GHZ) 55412a08440Sreyk printf(", 11G"); 55512a08440Sreyk else if (flags & IEEE80211_CHAN_OFDM && 55612a08440Sreyk flags & IEEE80211_CHAN_5GHZ) 55712a08440Sreyk printf(", 11a"); 55812a08440Sreyk 55912a08440Sreyk if (flags & IEEE80211_CHAN_TURBO) 56012a08440Sreyk printf(", TURBO"); 56112a08440Sreyk if (flags & IEEE80211_CHAN_XR) 56212a08440Sreyk printf(", XR"); 56312a08440Sreyk } 56412a08440Sreyk 56512a08440Sreyk if (RADIOTAP(FHSS)) { 56612a08440Sreyk TCHECK2(*t, 2); 56712a08440Sreyk printf(", fhss %u/%u", *(u_int8_t*)t, *(u_int8_t*)t + 1); 56812a08440Sreyk t += 2; 56912a08440Sreyk } 57012a08440Sreyk 57112a08440Sreyk if (RADIOTAP(DBM_ANTSIGNAL)) { 57212a08440Sreyk TCHECK(*t); 57312a08440Sreyk printf(", sig %ddBm", *(int8_t*)t); 57412a08440Sreyk t += 1; 57512a08440Sreyk } 57612a08440Sreyk 57712a08440Sreyk if (RADIOTAP(DBM_ANTNOISE)) { 57812a08440Sreyk TCHECK(*t); 57912a08440Sreyk printf(", noise %ddBm", *(int8_t*)t); 58012a08440Sreyk t += 1; 58112a08440Sreyk } 58212a08440Sreyk 58312a08440Sreyk if (RADIOTAP(LOCK_QUALITY)) { 58412a08440Sreyk TCHECK2(*t, 2); 58512a08440Sreyk if (vflag) 58612a08440Sreyk printf(", quality %u", letoh16(*(u_int16_t*)t)); 58712a08440Sreyk t += 2; 58812a08440Sreyk } 58912a08440Sreyk 59012a08440Sreyk if (RADIOTAP(TX_ATTENUATION)) { 59112a08440Sreyk TCHECK2(*t, 2); 59212a08440Sreyk if (vflag) 59312a08440Sreyk printf(", txatt %u", 59412a08440Sreyk letoh16(*(u_int16_t*)t)); 59512a08440Sreyk t += 2; 59612a08440Sreyk } 59712a08440Sreyk 59812a08440Sreyk if (RADIOTAP(DB_TX_ATTENUATION)) { 59912a08440Sreyk TCHECK2(*t, 2); 60012a08440Sreyk if (vflag) 60112a08440Sreyk printf(", txatt %udB", 60212a08440Sreyk letoh16(*(u_int16_t*)t)); 60312a08440Sreyk t += 2; 60412a08440Sreyk } 60512a08440Sreyk 60612a08440Sreyk if (RADIOTAP(DBM_TX_POWER)) { 60712a08440Sreyk TCHECK(*t); 60812a08440Sreyk printf(", txpower %ddBm", *(int8_t*)t); 60912a08440Sreyk t += 1; 61012a08440Sreyk } 61112a08440Sreyk 61212a08440Sreyk if (RADIOTAP(ANTENNA)) { 61312a08440Sreyk TCHECK(*t); 61412a08440Sreyk if (vflag) 61512a08440Sreyk printf(", antenna %u", *(u_int8_t*)t); 61612a08440Sreyk t += 1; 61712a08440Sreyk } 61812a08440Sreyk 61912a08440Sreyk if (RADIOTAP(DB_ANTSIGNAL)) { 62012a08440Sreyk TCHECK(*t); 62112a08440Sreyk printf(", signal %udB", *(u_int8_t*)t); 62212a08440Sreyk t += 1; 62312a08440Sreyk } 62412a08440Sreyk 62512a08440Sreyk if (RADIOTAP(DB_ANTNOISE)) { 62612a08440Sreyk TCHECK(*t); 62712a08440Sreyk printf(", noise %udB", *(u_int8_t*)t); 62812a08440Sreyk t += 1; 62912a08440Sreyk } 63012a08440Sreyk 63112a08440Sreyk if (RADIOTAP(FCS)) { 63212a08440Sreyk TCHECK2(*t, 4); 63312a08440Sreyk if (vflag) 63412a08440Sreyk printf(", fcs %08x", letoh32(*(u_int32_t*)t)); 63512a08440Sreyk t += 4; 63612a08440Sreyk } 63712a08440Sreyk 63812a08440Sreyk #undef RADIOTAP 63912a08440Sreyk 64012a08440Sreyk putchar('>'); 64112a08440Sreyk goto out; 64212a08440Sreyk 64312a08440Sreyk trunc: 64412a08440Sreyk /* Truncated frame */ 64512a08440Sreyk printf("[|radiotap + 802.11]"); 64612a08440Sreyk 64712a08440Sreyk out: 64812a08440Sreyk if (xflag) 64912a08440Sreyk default_print(p, h->caplen); 65012a08440Sreyk putchar('\n'); 65112a08440Sreyk } 652