1*958b7e45Ssthen /* $OpenBSD: print-802_11.c,v 1.20 2015/07/16 23:34:54 sthen Exp $ */ 212a08440Sreyk 312a08440Sreyk /* 42c56d0d6Sreyk * Copyright (c) 2005 Reyk Floeter <reyk@openbsd.org> 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/time.h> 2012a08440Sreyk #include <sys/socket.h> 2112a08440Sreyk #include <sys/file.h> 2212a08440Sreyk #include <sys/ioctl.h> 2312a08440Sreyk 2412a08440Sreyk #include <net/if.h> 2512a08440Sreyk 2612a08440Sreyk #include <netinet/in.h> 2712a08440Sreyk #include <netinet/if_ether.h> 2812a08440Sreyk 2912a08440Sreyk #include <net80211/ieee80211.h> 3012a08440Sreyk #include <net80211/ieee80211_radiotap.h> 3112a08440Sreyk 3212a08440Sreyk #include <pcap.h> 3312a08440Sreyk #include <stdio.h> 3412a08440Sreyk #include <string.h> 3512a08440Sreyk 3612a08440Sreyk #include "addrtoname.h" 3712a08440Sreyk #include "interface.h" 3812a08440Sreyk 3912a08440Sreyk const char *ieee80211_mgt_subtype_name[] = { 4012a08440Sreyk "association request", 4112a08440Sreyk "association response", 4212a08440Sreyk "reassociation request", 4312a08440Sreyk "reassociation response", 4412a08440Sreyk "probe request", 4512a08440Sreyk "probe response", 4612a08440Sreyk "reserved#6", 4712a08440Sreyk "reserved#7", 4812a08440Sreyk "beacon", 4912a08440Sreyk "atim", 5012a08440Sreyk "disassociation", 5112a08440Sreyk "authentication", 5212a08440Sreyk "deauthentication", 53ab7e388eSclaudio "action", 54ab7e388eSclaudio "action noack", 5512a08440Sreyk "reserved#15" 5612a08440Sreyk }; 5712a08440Sreyk 58ab7e388eSclaudio const char *ieee80211_data_subtype_name[] = { 59ab7e388eSclaudio "data", 60ab7e388eSclaudio "data cf ack", 61ab7e388eSclaudio "data cf poll", 62ab7e388eSclaudio "data cf poll ack", 63ab7e388eSclaudio "no-data", 64ab7e388eSclaudio "no-data cf poll", 65ab7e388eSclaudio "no-data cf ack", 66ab7e388eSclaudio "no-data cf poll ack", 67ab7e388eSclaudio "QoS data", 68ab7e388eSclaudio "QoS data cf ack", 69ab7e388eSclaudio "QoS data cf poll", 70ab7e388eSclaudio "QoS data cf poll ack", 71ab7e388eSclaudio "QoS no-data", 72ab7e388eSclaudio "QoS no-data cf poll", 73ab7e388eSclaudio "QoS no-data cf ack", 74ab7e388eSclaudio "QoS no-data cf poll ack" 75ab7e388eSclaudio }; 76ab7e388eSclaudio 7712a08440Sreyk int ieee80211_hdr(struct ieee80211_frame *); 78b72abdefSreyk int ieee80211_data(struct ieee80211_frame *, u_int); 7912a08440Sreyk void ieee80211_print_element(u_int8_t *, u_int); 8012a08440Sreyk void ieee80211_print_essid(u_int8_t *, u_int); 811e3bf20aSstsp void ieee80211_print_htcaps(u_int8_t *, u_int); 8212a08440Sreyk int ieee80211_elements(struct ieee80211_frame *, u_int); 8312a08440Sreyk int ieee80211_frame(struct ieee80211_frame *, u_int); 8412a08440Sreyk int ieee80211_print(struct ieee80211_frame *, u_int); 8512a08440Sreyk u_int ieee80211_any2ieee(u_int, u_int); 8618786664Sclaudio void ieee80211_reason(u_int16_t); 8712a08440Sreyk 8812a08440Sreyk #define TCARR(a) TCHECK2(*a, sizeof(a)) 8912a08440Sreyk 90c79cf170Sreyk int ieee80211_encap = 0; 91c79cf170Sreyk 9212a08440Sreyk int 9312a08440Sreyk ieee80211_hdr(struct ieee80211_frame *wh) 9412a08440Sreyk { 9512a08440Sreyk struct ieee80211_frame_addr4 *w4; 9612a08440Sreyk 9712a08440Sreyk switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 9812a08440Sreyk case IEEE80211_FC1_DIR_NODS: 9912a08440Sreyk TCARR(wh->i_addr2); 10012a08440Sreyk printf("%s", etheraddr_string(wh->i_addr2)); 10112a08440Sreyk TCARR(wh->i_addr1); 10212a08440Sreyk printf(" > %s", etheraddr_string(wh->i_addr1)); 10312a08440Sreyk TCARR(wh->i_addr3); 10412a08440Sreyk printf(", bssid %s", etheraddr_string(wh->i_addr3)); 10512a08440Sreyk break; 10612a08440Sreyk case IEEE80211_FC1_DIR_TODS: 10712a08440Sreyk TCARR(wh->i_addr2); 10812a08440Sreyk printf("%s", etheraddr_string(wh->i_addr2)); 10912a08440Sreyk TCARR(wh->i_addr3); 11012a08440Sreyk printf(" > %s", etheraddr_string(wh->i_addr3)); 11112a08440Sreyk TCARR(wh->i_addr1); 11212a08440Sreyk printf(", bssid %s, > DS", etheraddr_string(wh->i_addr1)); 11312a08440Sreyk break; 11412a08440Sreyk case IEEE80211_FC1_DIR_FROMDS: 11512a08440Sreyk TCARR(wh->i_addr3); 11612a08440Sreyk printf("%s", etheraddr_string(wh->i_addr3)); 11712a08440Sreyk TCARR(wh->i_addr1); 11812a08440Sreyk printf(" > %s", etheraddr_string(wh->i_addr1)); 11912a08440Sreyk TCARR(wh->i_addr2); 12012a08440Sreyk printf(", bssid %s, DS >", etheraddr_string(wh->i_addr2)); 12112a08440Sreyk break; 12212a08440Sreyk case IEEE80211_FC1_DIR_DSTODS: 12312a08440Sreyk w4 = (struct ieee80211_frame_addr4 *) wh; 12412a08440Sreyk TCARR(w4->i_addr4); 12512a08440Sreyk printf("%s", etheraddr_string(w4->i_addr4)); 12612a08440Sreyk TCARR(w4->i_addr3); 12712a08440Sreyk printf(" > %s", etheraddr_string(w4->i_addr3)); 12812a08440Sreyk TCARR(w4->i_addr2); 12912a08440Sreyk printf(", bssid %s", etheraddr_string(w4->i_addr2)); 13012a08440Sreyk TCARR(w4->i_addr1); 13112a08440Sreyk printf(" > %s, DS > DS", etheraddr_string(w4->i_addr1)); 13212a08440Sreyk break; 13312a08440Sreyk } 13412a08440Sreyk if (vflag) { 135cce1ba42Sclaudio u_int16_t seq; 13612a08440Sreyk TCARR(wh->i_seq); 137cce1ba42Sclaudio bcopy(wh->i_seq, &seq, sizeof(u_int16_t)); 138cce1ba42Sclaudio printf(" (seq %u): ", letoh16(seq)); 13912a08440Sreyk } else 14012a08440Sreyk printf(": "); 14112a08440Sreyk 14212a08440Sreyk return (0); 14312a08440Sreyk 14412a08440Sreyk trunc: 14512a08440Sreyk /* Truncated elements in frame */ 14612a08440Sreyk return (1); 14712a08440Sreyk } 14812a08440Sreyk 149b72abdefSreyk int 150b72abdefSreyk ieee80211_data(struct ieee80211_frame *wh, u_int len) 151b72abdefSreyk { 152b72abdefSreyk u_int8_t *t = (u_int8_t *)wh; 153d49cb46eScanacar struct ieee80211_frame_addr4 *w4; 154b72abdefSreyk u_int datalen; 15593cbfc44Sstsp int data = !(wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_NODATA); 156ab7e388eSclaudio u_char *esrc = NULL, *edst = NULL; 157b72abdefSreyk 158d49cb46eScanacar TCHECK(*wh); 159b72abdefSreyk t += sizeof(struct ieee80211_frame); 160b72abdefSreyk datalen = len - sizeof(struct ieee80211_frame); 161b72abdefSreyk 162b72abdefSreyk switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 163b72abdefSreyk case IEEE80211_FC1_DIR_TODS: 164ab7e388eSclaudio esrc = wh->i_addr2; 165ab7e388eSclaudio edst = wh->i_addr3; 166b72abdefSreyk break; 167b72abdefSreyk case IEEE80211_FC1_DIR_FROMDS: 168ab7e388eSclaudio esrc = wh->i_addr3; 169ab7e388eSclaudio edst = wh->i_addr1; 170b72abdefSreyk break; 171b72abdefSreyk case IEEE80211_FC1_DIR_NODS: 172ab7e388eSclaudio esrc = wh->i_addr2; 173ab7e388eSclaudio edst = wh->i_addr1; 174d49cb46eScanacar break; 175b72abdefSreyk case IEEE80211_FC1_DIR_DSTODS: 176d49cb46eScanacar w4 = (struct ieee80211_frame_addr4 *) wh; 177d49cb46eScanacar TCHECK(*w4); 178d49cb46eScanacar t = (u_int8_t *) (w4 + 1); 179d49cb46eScanacar datalen = len - sizeof(*w4); 180ab7e388eSclaudio esrc = w4->i_addr4; 181ab7e388eSclaudio edst = w4->i_addr3; 182b72abdefSreyk break; 183b72abdefSreyk } 184b72abdefSreyk 185ab7e388eSclaudio if (data && esrc) 186ab7e388eSclaudio llc_print(t, datalen, datalen, esrc, edst); 187ab7e388eSclaudio else if (eflag && esrc) 188ab7e388eSclaudio printf("%s > %s", 189ab7e388eSclaudio etheraddr_string(esrc), etheraddr_string(edst)); 190ab7e388eSclaudio 191b72abdefSreyk return (0); 192b72abdefSreyk 193b72abdefSreyk trunc: 194b72abdefSreyk /* Truncated elements in frame */ 195b72abdefSreyk return (1); 196b72abdefSreyk } 197b72abdefSreyk 19812a08440Sreyk /* Caller checks len */ 19912a08440Sreyk void 20012a08440Sreyk ieee80211_print_element(u_int8_t *data, u_int len) 20112a08440Sreyk { 20212a08440Sreyk u_int8_t *p; 2039cbdb746Sderaadt int i; 20412a08440Sreyk 20512a08440Sreyk printf(" 0x"); 2069cbdb746Sderaadt for (i = 0, p = data; i < len; i++, p++) 20712a08440Sreyk printf("%02x", *p); 20812a08440Sreyk } 20912a08440Sreyk 21012a08440Sreyk /* Caller checks len */ 21112a08440Sreyk void 21212a08440Sreyk ieee80211_print_essid(u_int8_t *essid, u_int len) 21312a08440Sreyk { 21412a08440Sreyk u_int8_t *p; 2159cbdb746Sderaadt int i; 21612a08440Sreyk 21712a08440Sreyk if (len > IEEE80211_NWID_LEN) 21812a08440Sreyk len = IEEE80211_NWID_LEN; 21912a08440Sreyk 22012a08440Sreyk /* determine printable or not */ 22112a08440Sreyk for (i = 0, p = essid; i < len; i++, p++) { 22212a08440Sreyk if (*p < ' ' || *p > 0x7e) 22312a08440Sreyk break; 22412a08440Sreyk } 22512a08440Sreyk if (i == len) { 22612a08440Sreyk printf(" ("); 22712a08440Sreyk for (i = 0, p = essid; i < len; i++, p++) 22812a08440Sreyk putchar(*p); 22912a08440Sreyk putchar(')'); 2309cbdb746Sderaadt } else 23112a08440Sreyk ieee80211_print_element(essid, len); 23212a08440Sreyk } 23312a08440Sreyk 2341e3bf20aSstsp /* Caller checks len */ 2351e3bf20aSstsp void 2361e3bf20aSstsp ieee80211_print_htcaps(u_int8_t *data, u_int len) 2371e3bf20aSstsp { 2381e3bf20aSstsp u_int16_t htcaps; 2391e3bf20aSstsp int smps, rxstbc; 2401e3bf20aSstsp 2411e3bf20aSstsp if (len < 2) { 2421e3bf20aSstsp ieee80211_print_element(data, len); 2431e3bf20aSstsp return; 2441e3bf20aSstsp } 2451e3bf20aSstsp 2461e3bf20aSstsp htcaps = (data[0]) | (data[1] << 8); 2471e3bf20aSstsp printf("=<"); 2481e3bf20aSstsp 2491e3bf20aSstsp /* channel width */ 2501e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_CBW20_40) 2511e3bf20aSstsp printf("20/40MHz"); 2521e3bf20aSstsp else 2531e3bf20aSstsp printf("20MHz"); 2541e3bf20aSstsp 2551e3bf20aSstsp /* LDPC coding */ 2561e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_LDPC) 2571e3bf20aSstsp printf(",LDPC"); 2581e3bf20aSstsp 2591e3bf20aSstsp /* spatial multiplexing power save mode */ 2601e3bf20aSstsp smps = (htcaps & IEEE80211_HTCAP_SMPS_MASK) 2611e3bf20aSstsp >> IEEE80211_HTCAP_SMPS_SHIFT; 2621e3bf20aSstsp if (smps == 0) 2631e3bf20aSstsp printf(",SMPS static"); 2641e3bf20aSstsp else if (smps == 1) 2651e3bf20aSstsp printf(",SMPS dynamic"); 2661e3bf20aSstsp 2671e3bf20aSstsp /* 11n greenfield mode */ 2681e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_GF) 2691e3bf20aSstsp printf(",greenfield"); 2701e3bf20aSstsp 2711e3bf20aSstsp /* short guard interval */ 2721e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_SGI20) 2731e3bf20aSstsp printf(",SGI@20MHz"); 2741e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_SGI40) 2751e3bf20aSstsp printf(",SGI@40MHz"); 2761e3bf20aSstsp 2771e3bf20aSstsp /* space-time block coding */ 2781e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_TXSTBC) 2791e3bf20aSstsp printf(",TXSTBC"); 2801e3bf20aSstsp rxstbc = (htcaps & IEEE80211_HTCAP_RXSTBC_MASK) 2811e3bf20aSstsp >> IEEE80211_HTCAP_RXSTBC_SHIFT; 2821e3bf20aSstsp if (rxstbc > 0 && rxstbc < 4) 2831e3bf20aSstsp printf(",RXSTBC %d stream", rxstbc); 2841e3bf20aSstsp 2851e3bf20aSstsp /* delayed block-ack */ 2861e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_DELAYEDBA) 2871e3bf20aSstsp printf(",delayed BA"); 2881e3bf20aSstsp 2891e3bf20aSstsp /* max A-MSDU length */ 2901e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_AMSDU7935) 2911e3bf20aSstsp printf(",A-MSDU 7935"); 2921e3bf20aSstsp else 2931e3bf20aSstsp printf(",A-MSDU 3839"); 2941e3bf20aSstsp 2951e3bf20aSstsp /* DSSS/CCK in 40MHz mode */ 2961e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_DSSSCCK40) 2971e3bf20aSstsp printf(",DSSS/CCK@40MHz"); 2981e3bf20aSstsp 2991e3bf20aSstsp /* 40MHz intolerant */ 3001e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_40INTOLERANT) 3011e3bf20aSstsp printf(",40MHz intolerant"); 3021e3bf20aSstsp 3031e3bf20aSstsp /* L-SIG TXOP protection */ 3041e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_LSIGTXOPPROT) 3051e3bf20aSstsp printf(",L-SIG TXOP prot"); 3061e3bf20aSstsp 3071e3bf20aSstsp printf(">"); 3081e3bf20aSstsp } 3091e3bf20aSstsp 31012a08440Sreyk int 31112a08440Sreyk ieee80211_elements(struct ieee80211_frame *wh, u_int flen) 31212a08440Sreyk { 31312a08440Sreyk u_int8_t *buf, *frm; 314cce1ba42Sclaudio u_int64_t tstamp; 315cce1ba42Sclaudio u_int16_t bintval, capinfo; 31612a08440Sreyk int i; 31712a08440Sreyk 31812a08440Sreyk buf = (u_int8_t *)wh; 31912a08440Sreyk frm = (u_int8_t *)&wh[1]; 32012a08440Sreyk 3210a05c5bfSreyk TCHECK2(*frm, 8); 322cce1ba42Sclaudio bcopy(frm, &tstamp, sizeof(u_int64_t)); 32312a08440Sreyk frm += 8; 32412a08440Sreyk 32512a08440Sreyk if (vflag > 1) 326cce1ba42Sclaudio printf(", timestamp %llu", letoh64(tstamp)); 32712a08440Sreyk 3280a05c5bfSreyk TCHECK2(*frm, 2); 329cce1ba42Sclaudio bcopy(frm, &bintval, sizeof(u_int16_t)); 33012a08440Sreyk frm += 2; 33112a08440Sreyk 33212a08440Sreyk if (vflag > 1) 333cce1ba42Sclaudio printf(", interval %u", letoh16(bintval)); 33412a08440Sreyk 3350a05c5bfSreyk TCHECK2(*frm, 2); 336cce1ba42Sclaudio bcopy(frm, &capinfo, sizeof(u_int16_t)); 33712a08440Sreyk frm += 2; 33812a08440Sreyk 33912a08440Sreyk if (vflag) 340cce1ba42Sclaudio printb(", caps", letoh16(capinfo), 34112a08440Sreyk IEEE80211_CAPINFO_BITS); 34212a08440Sreyk 34312a08440Sreyk while (TTEST2(*frm, 2)) { 34412a08440Sreyk u_int len = frm[1]; 34512a08440Sreyk u_int8_t *data = frm + 2; 34612a08440Sreyk 34712a08440Sreyk if (!TTEST2(*data, len)) 34812a08440Sreyk break; 34912a08440Sreyk 35012a08440Sreyk #define ELEM_CHECK(l) if (len != l) break 35112a08440Sreyk 35212a08440Sreyk switch (*frm) { 35312a08440Sreyk case IEEE80211_ELEMID_SSID: 35412a08440Sreyk printf(", ssid"); 35512a08440Sreyk ieee80211_print_essid(data, len); 35612a08440Sreyk break; 35712a08440Sreyk case IEEE80211_ELEMID_RATES: 35812a08440Sreyk printf(", rates"); 35912a08440Sreyk if (!vflag) 36012a08440Sreyk break; 36112a08440Sreyk for (i = len; i > 0; i--, data++) 36212a08440Sreyk printf(" %uM", 36312a08440Sreyk (data[0] & IEEE80211_RATE_VAL) / 2); 36412a08440Sreyk break; 36512a08440Sreyk case IEEE80211_ELEMID_FHPARMS: 36612a08440Sreyk ELEM_CHECK(5); 36712a08440Sreyk printf(", fh (dwell %u, chan %u, index %u)", 36812a08440Sreyk (data[1] << 8) | data[0], 36912a08440Sreyk (data[2] - 1) * 80 + data[3], /* FH_CHAN */ 37012a08440Sreyk data[4]); 37112a08440Sreyk break; 37212a08440Sreyk case IEEE80211_ELEMID_DSPARMS: 37312a08440Sreyk ELEM_CHECK(1); 37412a08440Sreyk printf(", ds"); 37512a08440Sreyk if (vflag) 37612a08440Sreyk printf(" (chan %u)", data[0]); 37712a08440Sreyk break; 37812a08440Sreyk case IEEE80211_ELEMID_CFPARMS: 37912a08440Sreyk printf(", cf"); 38012a08440Sreyk if (vflag) 38112a08440Sreyk ieee80211_print_element(data, len); 38212a08440Sreyk break; 38312a08440Sreyk case IEEE80211_ELEMID_TIM: 38412a08440Sreyk printf(", tim"); 38512a08440Sreyk if (vflag) 38612a08440Sreyk ieee80211_print_element(data, len); 38712a08440Sreyk break; 38812a08440Sreyk case IEEE80211_ELEMID_IBSSPARMS: 38912a08440Sreyk printf(", ibss"); 39012a08440Sreyk if (vflag) 39112a08440Sreyk ieee80211_print_element(data, len); 39212a08440Sreyk break; 39312a08440Sreyk case IEEE80211_ELEMID_COUNTRY: 39412a08440Sreyk printf(", country"); 39512a08440Sreyk for (i = len; i > 0; i--, data++) 39612a08440Sreyk printf(" %u", data[0]); 39712a08440Sreyk break; 39812a08440Sreyk case IEEE80211_ELEMID_CHALLENGE: 39912a08440Sreyk printf(", challenge"); 40012a08440Sreyk if (vflag) 40112a08440Sreyk ieee80211_print_element(data, len); 40212a08440Sreyk break; 403738acb58Ssthen case IEEE80211_ELEMID_CSA: 404*958b7e45Ssthen ELEM_CHECK(3); 405738acb58Ssthen printf(", csa (chan %u count %u%s)", data[1], data[2], 406738acb58Ssthen (data[0] == 1) ? " noTX" : ""); 407738acb58Ssthen break; 40812a08440Sreyk case IEEE80211_ELEMID_ERP: 40912a08440Sreyk printf(", erp"); 41012a08440Sreyk if (vflag) 41112a08440Sreyk ieee80211_print_element(data, len); 41212a08440Sreyk break; 41312a08440Sreyk case IEEE80211_ELEMID_RSN: 41412a08440Sreyk printf(", rsn"); 41512a08440Sreyk if (vflag) 41612a08440Sreyk ieee80211_print_element(data, len); 41712a08440Sreyk break; 41812a08440Sreyk case IEEE80211_ELEMID_XRATES: 41912a08440Sreyk printf(", xrates"); 42012a08440Sreyk if (!vflag) 42112a08440Sreyk break; 42212a08440Sreyk for (i = len; i > 0; i--, data++) 42312a08440Sreyk printf(" %uM", 42412a08440Sreyk (data[0] & IEEE80211_RATE_VAL) / 2); 42512a08440Sreyk break; 4268138faddSstsp case IEEE80211_ELEMID_TPC_REPORT: 4278138faddSstsp printf(", tpcreport"); 42812a08440Sreyk if (vflag) 42912a08440Sreyk ieee80211_print_element(data, len); 43012a08440Sreyk break; 4318138faddSstsp case IEEE80211_ELEMID_TPC_REQUEST: 4328138faddSstsp printf(", tpcrequest"); 43312a08440Sreyk if (vflag) 43412a08440Sreyk ieee80211_print_element(data, len); 43512a08440Sreyk break; 4361e3bf20aSstsp case IEEE80211_ELEMID_HTCAPS: 4371e3bf20aSstsp printf(", htcaps"); 4381e3bf20aSstsp if (vflag) 4391e3bf20aSstsp ieee80211_print_htcaps(data, len); 4401e3bf20aSstsp break; 44112a08440Sreyk case IEEE80211_ELEMID_VENDOR: 44212a08440Sreyk printf(", vendor"); 44312a08440Sreyk if (vflag) 44412a08440Sreyk ieee80211_print_element(data, len); 44512a08440Sreyk break; 44612a08440Sreyk default: 44712a08440Sreyk printf(", %u:%u", (u_int) *frm, len); 44812a08440Sreyk if (vflag) 44912a08440Sreyk ieee80211_print_element(data, len); 45012a08440Sreyk break; 45112a08440Sreyk } 45212a08440Sreyk frm += len + 2; 45312a08440Sreyk 45412a08440Sreyk if (frm >= snapend) 45512a08440Sreyk break; 45612a08440Sreyk } 45712a08440Sreyk 45812a08440Sreyk #undef ELEM_CHECK 45912a08440Sreyk 46012a08440Sreyk return (0); 46112a08440Sreyk 46212a08440Sreyk trunc: 46312a08440Sreyk /* Truncated elements in frame */ 46412a08440Sreyk return (1); 46512a08440Sreyk } 46612a08440Sreyk 46712a08440Sreyk int 46812a08440Sreyk ieee80211_frame(struct ieee80211_frame *wh, u_int len) 46912a08440Sreyk { 47012a08440Sreyk u_int8_t subtype, type, *frm; 47112a08440Sreyk 47212a08440Sreyk TCARR(wh->i_fc); 47312a08440Sreyk 47412a08440Sreyk type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 47512a08440Sreyk subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 47612a08440Sreyk 47712a08440Sreyk frm = (u_int8_t *)&wh[1]; 47812a08440Sreyk 479ab7e388eSclaudio if (vflag) 480ab7e388eSclaudio printb(" flags", wh->i_fc[1], IEEE80211_FC1_BITS); 481ab7e388eSclaudio 48212a08440Sreyk switch (type) { 48312a08440Sreyk case IEEE80211_FC0_TYPE_DATA: 484ab7e388eSclaudio printf(": %s: ", ieee80211_data_subtype_name[ 485ab7e388eSclaudio subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]); 486b72abdefSreyk ieee80211_data(wh, len); 48712a08440Sreyk break; 48812a08440Sreyk case IEEE80211_FC0_TYPE_MGT: 48912a08440Sreyk printf(": %s", ieee80211_mgt_subtype_name[ 49012a08440Sreyk subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]); 49112a08440Sreyk switch (subtype) { 49212a08440Sreyk case IEEE80211_FC0_SUBTYPE_BEACON: 49312a08440Sreyk case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 49412a08440Sreyk if (ieee80211_elements(wh, len) != 0) 49512a08440Sreyk goto trunc; 49612a08440Sreyk break; 49712a08440Sreyk case IEEE80211_FC0_SUBTYPE_AUTH: 49812a08440Sreyk TCHECK2(*frm, 2); /* Auth Algorithm */ 49912a08440Sreyk switch (IEEE80211_AUTH_ALGORITHM(frm)) { 50012a08440Sreyk case IEEE80211_AUTH_ALG_OPEN: 50112a08440Sreyk TCHECK2(*frm, 4); /* Auth Transaction */ 50212a08440Sreyk switch (IEEE80211_AUTH_TRANSACTION(frm)) { 50312a08440Sreyk case IEEE80211_AUTH_OPEN_REQUEST: 50412a08440Sreyk printf(" request"); 50512a08440Sreyk break; 50612a08440Sreyk case IEEE80211_AUTH_OPEN_RESPONSE: 50712a08440Sreyk printf(" response"); 50812a08440Sreyk break; 50912a08440Sreyk } 51012a08440Sreyk break; 51112a08440Sreyk case IEEE80211_AUTH_ALG_SHARED: 51212a08440Sreyk TCHECK2(*frm, 4); /* Auth Transaction */ 51312a08440Sreyk switch (IEEE80211_AUTH_TRANSACTION(frm)) { 51412a08440Sreyk case IEEE80211_AUTH_SHARED_REQUEST: 51512a08440Sreyk printf(" request"); 51612a08440Sreyk break; 51712a08440Sreyk case IEEE80211_AUTH_SHARED_CHALLENGE: 51812a08440Sreyk printf(" challenge"); 51912a08440Sreyk break; 52012a08440Sreyk case IEEE80211_AUTH_SHARED_RESPONSE: 52112a08440Sreyk printf(" response"); 52212a08440Sreyk break; 52312a08440Sreyk case IEEE80211_AUTH_SHARED_PASS: 52412a08440Sreyk printf(" pass"); 52512a08440Sreyk break; 52612a08440Sreyk } 52712a08440Sreyk break; 52812a08440Sreyk case IEEE80211_AUTH_ALG_LEAP: 52912a08440Sreyk printf(" (leap)"); 53012a08440Sreyk break; 53112a08440Sreyk } 53212a08440Sreyk break; 53318786664Sclaudio case IEEE80211_FC0_SUBTYPE_DEAUTH: 53418786664Sclaudio case IEEE80211_FC0_SUBTYPE_DISASSOC: 53518786664Sclaudio TCHECK2(*frm, 2); /* Reason Code */ 53618786664Sclaudio ieee80211_reason(frm[0] | (frm[1] << 8)); 53718786664Sclaudio break; 53812a08440Sreyk } 53912a08440Sreyk break; 54012a08440Sreyk default: 54112a08440Sreyk printf(": type#%d", type); 54212a08440Sreyk break; 54312a08440Sreyk } 54412a08440Sreyk 54512a08440Sreyk return (0); 54612a08440Sreyk 54712a08440Sreyk trunc: 54812a08440Sreyk /* Truncated 802.11 frame */ 54912a08440Sreyk return (1); 55012a08440Sreyk } 55112a08440Sreyk 55212a08440Sreyk u_int 55312a08440Sreyk ieee80211_any2ieee(u_int freq, u_int flags) 55412a08440Sreyk { 55512a08440Sreyk if (flags & IEEE80211_CHAN_2GHZ) { 55612a08440Sreyk if (freq == 2484) 55712a08440Sreyk return 14; 55812a08440Sreyk if (freq < 2484) 55912a08440Sreyk return (freq - 2407) / 5; 56012a08440Sreyk else 56112a08440Sreyk return 15 + ((freq - 2512) / 20); 56212a08440Sreyk } else if (flags & IEEE80211_CHAN_5GHZ) { 56312a08440Sreyk return (freq - 5000) / 5; 56412a08440Sreyk } else { 56512a08440Sreyk /* Assume channel is already an IEEE number */ 56612a08440Sreyk return (freq); 56712a08440Sreyk } 56812a08440Sreyk } 56912a08440Sreyk 57012a08440Sreyk int 57112a08440Sreyk ieee80211_print(struct ieee80211_frame *wh, u_int len) 57212a08440Sreyk { 57312a08440Sreyk if (eflag) 57412a08440Sreyk if (ieee80211_hdr(wh)) 57512a08440Sreyk return (1); 57612a08440Sreyk 57712a08440Sreyk printf("802.11"); 57812a08440Sreyk 57912a08440Sreyk return (ieee80211_frame(wh, len)); 58012a08440Sreyk } 58112a08440Sreyk 58212a08440Sreyk void 58312a08440Sreyk ieee802_11_if_print(u_char *user, const struct pcap_pkthdr *h, 58412a08440Sreyk const u_char *p) 58512a08440Sreyk { 58612a08440Sreyk struct ieee80211_frame *wh = (struct ieee80211_frame*)p; 58712a08440Sreyk 588c79cf170Sreyk if (!ieee80211_encap) 58912a08440Sreyk ts_print(&h->ts); 59012a08440Sreyk 59112a08440Sreyk packetp = p; 59212a08440Sreyk snapend = p + h->caplen; 59312a08440Sreyk 594a0774ae9Smglocker if (ieee80211_print(wh, (u_int)h->len) != 0) 59512a08440Sreyk printf("[|802.11]"); 59612a08440Sreyk 597c79cf170Sreyk if (!ieee80211_encap) { 59812a08440Sreyk if (xflag) 599a0774ae9Smglocker default_print(p, (u_int)h->len); 60012a08440Sreyk putchar('\n'); 60112a08440Sreyk } 602c79cf170Sreyk } 60312a08440Sreyk 60412a08440Sreyk void 60512a08440Sreyk ieee802_11_radio_if_print(u_char *user, const struct pcap_pkthdr *h, 60612a08440Sreyk const u_char *p) 60712a08440Sreyk { 60812a08440Sreyk struct ieee80211_radiotap_header *rh = 60912a08440Sreyk (struct ieee80211_radiotap_header*)p; 61012a08440Sreyk struct ieee80211_frame *wh; 61112a08440Sreyk u_int8_t *t; 61212a08440Sreyk u_int32_t present; 61312a08440Sreyk u_int len, rh_len; 614cce1ba42Sclaudio u_int16_t tmp; 61512a08440Sreyk 616c79cf170Sreyk if (!ieee80211_encap) 61712a08440Sreyk ts_print(&h->ts); 61812a08440Sreyk 61912a08440Sreyk packetp = p; 62012a08440Sreyk snapend = p + h->caplen; 62112a08440Sreyk 62212a08440Sreyk TCHECK(*rh); 62312a08440Sreyk 624a0774ae9Smglocker len = h->len; 62512a08440Sreyk rh_len = letoh16(rh->it_len); 62612a08440Sreyk if (rh->it_version != 0) { 627c79cf170Sreyk printf("[?radiotap + 802.11 v:%u]", rh->it_version); 62812a08440Sreyk goto out; 62912a08440Sreyk } 63012a08440Sreyk 63112a08440Sreyk wh = (struct ieee80211_frame *)(p + rh_len); 63212a08440Sreyk if (len <= rh_len || ieee80211_print(wh, len - rh_len)) 63312a08440Sreyk printf("[|802.11]"); 63412a08440Sreyk 63512a08440Sreyk t = (u_int8_t*)p + sizeof(struct ieee80211_radiotap_header); 63612a08440Sreyk 63712a08440Sreyk if ((present = letoh32(rh->it_present)) == 0) 63812a08440Sreyk goto out; 63912a08440Sreyk 64012a08440Sreyk printf(", <radiotap v%u", rh->it_version); 64112a08440Sreyk 64212a08440Sreyk #define RADIOTAP(_x) \ 64312a08440Sreyk (present & (1 << IEEE80211_RADIOTAP_##_x)) 64412a08440Sreyk 64512a08440Sreyk if (RADIOTAP(TSFT)) { 646cce1ba42Sclaudio u_int64_t tsf; 647cce1ba42Sclaudio 64812a08440Sreyk TCHECK2(*t, 8); 649cce1ba42Sclaudio bcopy(t, &tsf, sizeof(u_int64_t)); 65012a08440Sreyk if (vflag > 1) 651cce1ba42Sclaudio printf(", tsf %llu", letoh64(tsf)); 65212a08440Sreyk t += 8; 65312a08440Sreyk } 65412a08440Sreyk 65512a08440Sreyk if (RADIOTAP(FLAGS)) { 65612a08440Sreyk u_int8_t flags = *(u_int8_t*)t; 657026ca542Sderaadt TCHECK2(*t, 1); 658026ca542Sderaadt 65912a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_CFP) 66012a08440Sreyk printf(", CFP"); 66112a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_SHORTPRE) 66212a08440Sreyk printf(", SHORTPRE"); 66312a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_WEP) 66412a08440Sreyk printf(", WEP"); 66512a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_FRAG) 66612a08440Sreyk printf(", FRAG"); 66712a08440Sreyk t += 1; 66812a08440Sreyk } 66912a08440Sreyk 67012a08440Sreyk if (RADIOTAP(RATE)) { 67112a08440Sreyk TCHECK2(*t, 1); 67212a08440Sreyk if (vflag) 67312a08440Sreyk printf(", %uMbit/s", (*(u_int8_t*)t) / 2); 67412a08440Sreyk t += 1; 67512a08440Sreyk } 67612a08440Sreyk 67712a08440Sreyk if (RADIOTAP(CHANNEL)) { 67812a08440Sreyk u_int16_t freq, flags; 67912a08440Sreyk TCHECK2(*t, 2); 68012a08440Sreyk 681cce1ba42Sclaudio bcopy(t, &freq, sizeof(u_int16_t)); 682cce1ba42Sclaudio freq = letoh16(freq); 68312a08440Sreyk t += 2; 68412a08440Sreyk TCHECK2(*t, 2); 685cce1ba42Sclaudio bcopy(t, &flags, sizeof(u_int16_t)); 686cce1ba42Sclaudio flags = letoh16(flags); 68712a08440Sreyk t += 2; 68812a08440Sreyk 68912a08440Sreyk printf(", chan %u", ieee80211_any2ieee(freq, flags)); 69012a08440Sreyk 69112a08440Sreyk if (flags & IEEE80211_CHAN_DYN && 69212a08440Sreyk flags & IEEE80211_CHAN_2GHZ) 69312a08440Sreyk printf(", 11g"); 69412a08440Sreyk else if (flags & IEEE80211_CHAN_CCK && 69512a08440Sreyk flags & IEEE80211_CHAN_2GHZ) 69612a08440Sreyk printf(", 11b"); 69712a08440Sreyk else if (flags & IEEE80211_CHAN_OFDM && 69812a08440Sreyk flags & IEEE80211_CHAN_2GHZ) 69912a08440Sreyk printf(", 11G"); 70012a08440Sreyk else if (flags & IEEE80211_CHAN_OFDM && 70112a08440Sreyk flags & IEEE80211_CHAN_5GHZ) 70212a08440Sreyk printf(", 11a"); 70312a08440Sreyk 70412a08440Sreyk if (flags & IEEE80211_CHAN_TURBO) 70512a08440Sreyk printf(", TURBO"); 70612a08440Sreyk if (flags & IEEE80211_CHAN_XR) 70712a08440Sreyk printf(", XR"); 70812a08440Sreyk } 70912a08440Sreyk 71012a08440Sreyk if (RADIOTAP(FHSS)) { 71112a08440Sreyk TCHECK2(*t, 2); 71212a08440Sreyk printf(", fhss %u/%u", *(u_int8_t*)t, *(u_int8_t*)t + 1); 71312a08440Sreyk t += 2; 71412a08440Sreyk } 71512a08440Sreyk 71612a08440Sreyk if (RADIOTAP(DBM_ANTSIGNAL)) { 71712a08440Sreyk TCHECK(*t); 71812a08440Sreyk printf(", sig %ddBm", *(int8_t*)t); 71912a08440Sreyk t += 1; 72012a08440Sreyk } 72112a08440Sreyk 72212a08440Sreyk if (RADIOTAP(DBM_ANTNOISE)) { 72312a08440Sreyk TCHECK(*t); 72412a08440Sreyk printf(", noise %ddBm", *(int8_t*)t); 72512a08440Sreyk t += 1; 72612a08440Sreyk } 72712a08440Sreyk 72812a08440Sreyk if (RADIOTAP(LOCK_QUALITY)) { 72912a08440Sreyk TCHECK2(*t, 2); 730cce1ba42Sclaudio if (vflag) { 731cce1ba42Sclaudio bcopy(t, &tmp, sizeof(u_int16_t)); 732cce1ba42Sclaudio printf(", quality %u", letoh16(tmp)); 733cce1ba42Sclaudio } 73412a08440Sreyk t += 2; 73512a08440Sreyk } 73612a08440Sreyk 73712a08440Sreyk if (RADIOTAP(TX_ATTENUATION)) { 73812a08440Sreyk TCHECK2(*t, 2); 739cce1ba42Sclaudio if (vflag) { 740cce1ba42Sclaudio bcopy(t, &tmp, sizeof(u_int16_t)); 741cce1ba42Sclaudio printf(", txatt %u", letoh16(tmp)); 742cce1ba42Sclaudio } 74312a08440Sreyk t += 2; 74412a08440Sreyk } 74512a08440Sreyk 74612a08440Sreyk if (RADIOTAP(DB_TX_ATTENUATION)) { 74712a08440Sreyk TCHECK2(*t, 2); 748cce1ba42Sclaudio if (vflag) { 749cce1ba42Sclaudio bcopy(t, &tmp, sizeof(u_int16_t)); 750cce1ba42Sclaudio printf(", txatt %udB", letoh16(tmp)); 751cce1ba42Sclaudio } 75212a08440Sreyk t += 2; 75312a08440Sreyk } 75412a08440Sreyk 75512a08440Sreyk if (RADIOTAP(DBM_TX_POWER)) { 75612a08440Sreyk TCHECK(*t); 75712a08440Sreyk printf(", txpower %ddBm", *(int8_t*)t); 75812a08440Sreyk t += 1; 75912a08440Sreyk } 76012a08440Sreyk 76112a08440Sreyk if (RADIOTAP(ANTENNA)) { 76212a08440Sreyk TCHECK(*t); 76312a08440Sreyk if (vflag) 76412a08440Sreyk printf(", antenna %u", *(u_int8_t*)t); 76512a08440Sreyk t += 1; 76612a08440Sreyk } 76712a08440Sreyk 76812a08440Sreyk if (RADIOTAP(DB_ANTSIGNAL)) { 76912a08440Sreyk TCHECK(*t); 77012a08440Sreyk printf(", signal %udB", *(u_int8_t*)t); 77112a08440Sreyk t += 1; 77212a08440Sreyk } 77312a08440Sreyk 77412a08440Sreyk if (RADIOTAP(DB_ANTNOISE)) { 77512a08440Sreyk TCHECK(*t); 77612a08440Sreyk printf(", noise %udB", *(u_int8_t*)t); 77712a08440Sreyk t += 1; 77812a08440Sreyk } 77912a08440Sreyk 78012a08440Sreyk if (RADIOTAP(FCS)) { 78112a08440Sreyk TCHECK2(*t, 4); 782cce1ba42Sclaudio if (vflag) { 783cce1ba42Sclaudio u_int32_t fcs; 784cce1ba42Sclaudio bcopy(t, &fcs, sizeof(u_int32_t)); 785cce1ba42Sclaudio printf(", fcs %08x", letoh32(fcs)); 786cce1ba42Sclaudio } 78712a08440Sreyk t += 4; 78812a08440Sreyk } 78912a08440Sreyk 7906fc94ee3Sreyk if (RADIOTAP(RSSI)) { 7916fc94ee3Sreyk u_int8_t rssi, max_rssi; 7926fc94ee3Sreyk TCHECK(*t); 7936fc94ee3Sreyk rssi = *(u_int8_t*)t; 7946fc94ee3Sreyk t += 1; 7956fc94ee3Sreyk TCHECK(*t); 7966fc94ee3Sreyk max_rssi = *(u_int8_t*)t; 7976fc94ee3Sreyk t += 1; 7986fc94ee3Sreyk 7996fc94ee3Sreyk printf(", rssi %u/%u", rssi, max_rssi); 8006fc94ee3Sreyk } 8016fc94ee3Sreyk 80212a08440Sreyk #undef RADIOTAP 80312a08440Sreyk 80412a08440Sreyk putchar('>'); 80512a08440Sreyk goto out; 80612a08440Sreyk 80712a08440Sreyk trunc: 80812a08440Sreyk /* Truncated frame */ 80912a08440Sreyk printf("[|radiotap + 802.11]"); 81012a08440Sreyk 81112a08440Sreyk out: 812c79cf170Sreyk if (!ieee80211_encap) { 81312a08440Sreyk if (xflag) 814a0774ae9Smglocker default_print(p, h->len); 81512a08440Sreyk putchar('\n'); 81612a08440Sreyk } 817c79cf170Sreyk } 81818786664Sclaudio 81918786664Sclaudio void 82018786664Sclaudio ieee80211_reason(u_int16_t reason) 82118786664Sclaudio { 82218786664Sclaudio if (!vflag) 82318786664Sclaudio return; 82418786664Sclaudio 82518786664Sclaudio switch (reason) { 82618786664Sclaudio case IEEE80211_REASON_UNSPECIFIED: 82718786664Sclaudio printf(", unspecified failure"); 82818786664Sclaudio break; 82918786664Sclaudio case IEEE80211_REASON_AUTH_EXPIRE: 83018786664Sclaudio printf(", authentication expired"); 83118786664Sclaudio break; 83218786664Sclaudio case IEEE80211_REASON_AUTH_LEAVE: 83318786664Sclaudio printf(", deauth - station left"); 83418786664Sclaudio break; 83518786664Sclaudio case IEEE80211_REASON_ASSOC_EXPIRE: 83618786664Sclaudio printf(", association expired"); 83718786664Sclaudio break; 83818786664Sclaudio case IEEE80211_REASON_ASSOC_TOOMANY: 83918786664Sclaudio printf(", too many associated stations"); 84018786664Sclaudio break; 84118786664Sclaudio case IEEE80211_REASON_NOT_AUTHED: 84218786664Sclaudio printf(", not authenticated"); 84318786664Sclaudio break; 84418786664Sclaudio case IEEE80211_REASON_NOT_ASSOCED: 84518786664Sclaudio printf(", not associated"); 84618786664Sclaudio break; 84718786664Sclaudio case IEEE80211_REASON_ASSOC_LEAVE: 84818786664Sclaudio printf(", disassociated - station left"); 84918786664Sclaudio break; 85018786664Sclaudio case IEEE80211_REASON_ASSOC_NOT_AUTHED: 85118786664Sclaudio printf(", association but not authenticated"); 85218786664Sclaudio break; 85318786664Sclaudio case IEEE80211_REASON_RSN_REQUIRED: 85418786664Sclaudio printf(", rsn required"); 85518786664Sclaudio break; 85618786664Sclaudio case IEEE80211_REASON_RSN_INCONSISTENT: 85718786664Sclaudio printf(", rsn inconsistent"); 85818786664Sclaudio break; 85918786664Sclaudio case IEEE80211_REASON_IE_INVALID: 86018786664Sclaudio printf(", ie invalid"); 86118786664Sclaudio break; 86218786664Sclaudio case IEEE80211_REASON_MIC_FAILURE: 86318786664Sclaudio printf(", mic failure"); 86418786664Sclaudio break; 86518786664Sclaudio default: 86618786664Sclaudio printf(", unknown reason %u", reason); 86718786664Sclaudio } 86818786664Sclaudio } 869