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