1*9d5679eaSstsp /* $OpenBSD: print-802_11.c,v 1.29 2016/02/01 10:09:44 stsp 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 3277734011Sstsp #include <ctype.h> 3312a08440Sreyk #include <pcap.h> 3412a08440Sreyk #include <stdio.h> 3512a08440Sreyk #include <string.h> 3612a08440Sreyk 3712a08440Sreyk #include "addrtoname.h" 3812a08440Sreyk #include "interface.h" 3912a08440Sreyk 4012a08440Sreyk const char *ieee80211_mgt_subtype_name[] = { 4112a08440Sreyk "association request", 4212a08440Sreyk "association response", 4312a08440Sreyk "reassociation request", 4412a08440Sreyk "reassociation response", 4512a08440Sreyk "probe request", 4612a08440Sreyk "probe response", 4712a08440Sreyk "reserved#6", 4812a08440Sreyk "reserved#7", 4912a08440Sreyk "beacon", 5012a08440Sreyk "atim", 5112a08440Sreyk "disassociation", 5212a08440Sreyk "authentication", 5312a08440Sreyk "deauthentication", 54ab7e388eSclaudio "action", 55ab7e388eSclaudio "action noack", 5612a08440Sreyk "reserved#15" 5712a08440Sreyk }; 5812a08440Sreyk 59ab7e388eSclaudio const char *ieee80211_data_subtype_name[] = { 60ab7e388eSclaudio "data", 61ab7e388eSclaudio "data cf ack", 62ab7e388eSclaudio "data cf poll", 63ab7e388eSclaudio "data cf poll ack", 64ab7e388eSclaudio "no-data", 65ab7e388eSclaudio "no-data cf poll", 66ab7e388eSclaudio "no-data cf ack", 67ab7e388eSclaudio "no-data cf poll ack", 68ab7e388eSclaudio "QoS data", 69ab7e388eSclaudio "QoS data cf ack", 70ab7e388eSclaudio "QoS data cf poll", 71ab7e388eSclaudio "QoS data cf poll ack", 72ab7e388eSclaudio "QoS no-data", 73ab7e388eSclaudio "QoS no-data cf poll", 74ab7e388eSclaudio "QoS no-data cf ack", 75ab7e388eSclaudio "QoS no-data cf poll ack" 76ab7e388eSclaudio }; 77ab7e388eSclaudio 7812a08440Sreyk int ieee80211_hdr(struct ieee80211_frame *); 79b72abdefSreyk int ieee80211_data(struct ieee80211_frame *, u_int); 8012a08440Sreyk void ieee80211_print_element(u_int8_t *, u_int); 8112a08440Sreyk void ieee80211_print_essid(u_int8_t *, u_int); 8277734011Sstsp void ieee80211_print_country(u_int8_t *, u_int); 831e3bf20aSstsp void ieee80211_print_htcaps(u_int8_t *, u_int); 8436fa064cSstsp void ieee80211_print_htop(u_int8_t *, u_int); 8512a08440Sreyk int ieee80211_elements(struct ieee80211_frame *, u_int); 8612a08440Sreyk int ieee80211_frame(struct ieee80211_frame *, u_int); 8712a08440Sreyk int ieee80211_print(struct ieee80211_frame *, u_int); 8812a08440Sreyk u_int ieee80211_any2ieee(u_int, u_int); 8918786664Sclaudio void ieee80211_reason(u_int16_t); 9012a08440Sreyk 9112a08440Sreyk #define TCARR(a) TCHECK2(*a, sizeof(a)) 9212a08440Sreyk 93c79cf170Sreyk int ieee80211_encap = 0; 94c79cf170Sreyk 9512a08440Sreyk int 9612a08440Sreyk ieee80211_hdr(struct ieee80211_frame *wh) 9712a08440Sreyk { 9812a08440Sreyk struct ieee80211_frame_addr4 *w4; 9912a08440Sreyk 10012a08440Sreyk switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 10112a08440Sreyk case IEEE80211_FC1_DIR_NODS: 10212a08440Sreyk TCARR(wh->i_addr2); 10312a08440Sreyk printf("%s", etheraddr_string(wh->i_addr2)); 10412a08440Sreyk TCARR(wh->i_addr1); 10512a08440Sreyk printf(" > %s", etheraddr_string(wh->i_addr1)); 10612a08440Sreyk TCARR(wh->i_addr3); 10712a08440Sreyk printf(", bssid %s", etheraddr_string(wh->i_addr3)); 10812a08440Sreyk break; 10912a08440Sreyk case IEEE80211_FC1_DIR_TODS: 11012a08440Sreyk TCARR(wh->i_addr2); 11112a08440Sreyk printf("%s", etheraddr_string(wh->i_addr2)); 11212a08440Sreyk TCARR(wh->i_addr3); 11312a08440Sreyk printf(" > %s", etheraddr_string(wh->i_addr3)); 11412a08440Sreyk TCARR(wh->i_addr1); 11512a08440Sreyk printf(", bssid %s, > DS", etheraddr_string(wh->i_addr1)); 11612a08440Sreyk break; 11712a08440Sreyk case IEEE80211_FC1_DIR_FROMDS: 11812a08440Sreyk TCARR(wh->i_addr3); 11912a08440Sreyk printf("%s", etheraddr_string(wh->i_addr3)); 12012a08440Sreyk TCARR(wh->i_addr1); 12112a08440Sreyk printf(" > %s", etheraddr_string(wh->i_addr1)); 12212a08440Sreyk TCARR(wh->i_addr2); 12312a08440Sreyk printf(", bssid %s, DS >", etheraddr_string(wh->i_addr2)); 12412a08440Sreyk break; 12512a08440Sreyk case IEEE80211_FC1_DIR_DSTODS: 12612a08440Sreyk w4 = (struct ieee80211_frame_addr4 *) wh; 12712a08440Sreyk TCARR(w4->i_addr4); 12812a08440Sreyk printf("%s", etheraddr_string(w4->i_addr4)); 12912a08440Sreyk TCARR(w4->i_addr3); 13012a08440Sreyk printf(" > %s", etheraddr_string(w4->i_addr3)); 13112a08440Sreyk TCARR(w4->i_addr2); 13212a08440Sreyk printf(", bssid %s", etheraddr_string(w4->i_addr2)); 13312a08440Sreyk TCARR(w4->i_addr1); 13412a08440Sreyk printf(" > %s, DS > DS", etheraddr_string(w4->i_addr1)); 13512a08440Sreyk break; 13612a08440Sreyk } 13712a08440Sreyk if (vflag) { 138cce1ba42Sclaudio u_int16_t seq; 13912a08440Sreyk TCARR(wh->i_seq); 140cce1ba42Sclaudio bcopy(wh->i_seq, &seq, sizeof(u_int16_t)); 141cce1ba42Sclaudio printf(" (seq %u): ", letoh16(seq)); 14212a08440Sreyk } else 14312a08440Sreyk printf(": "); 14412a08440Sreyk 14512a08440Sreyk return (0); 14612a08440Sreyk 14712a08440Sreyk trunc: 14812a08440Sreyk /* Truncated elements in frame */ 14912a08440Sreyk return (1); 15012a08440Sreyk } 15112a08440Sreyk 152b72abdefSreyk int 153b72abdefSreyk ieee80211_data(struct ieee80211_frame *wh, u_int len) 154b72abdefSreyk { 155b72abdefSreyk u_int8_t *t = (u_int8_t *)wh; 156b72abdefSreyk u_int datalen; 15793cbfc44Sstsp int data = !(wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_NODATA); 158*9d5679eaSstsp int hasqos = ((wh->i_fc[0] & 159*9d5679eaSstsp (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) == 160*9d5679eaSstsp (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)); 161ab7e388eSclaudio u_char *esrc = NULL, *edst = NULL; 162b72abdefSreyk 163*9d5679eaSstsp if (hasqos) { 164*9d5679eaSstsp struct ieee80211_qosframe *wq; 165*9d5679eaSstsp 166*9d5679eaSstsp wq = (struct ieee80211_qosframe *) wh; 167*9d5679eaSstsp TCHECK(*wq); 168*9d5679eaSstsp t += sizeof(*wq); 169*9d5679eaSstsp datalen = len - sizeof(*wq); 170*9d5679eaSstsp } else { 171d49cb46eScanacar TCHECK(*wh); 172*9d5679eaSstsp t += sizeof(*wh); 173*9d5679eaSstsp datalen = len - sizeof(*wh); 174*9d5679eaSstsp } 175b72abdefSreyk 176b72abdefSreyk switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 177b72abdefSreyk case IEEE80211_FC1_DIR_TODS: 178ab7e388eSclaudio esrc = wh->i_addr2; 179ab7e388eSclaudio edst = wh->i_addr3; 180b72abdefSreyk break; 181b72abdefSreyk case IEEE80211_FC1_DIR_FROMDS: 182ab7e388eSclaudio esrc = wh->i_addr3; 183ab7e388eSclaudio edst = wh->i_addr1; 184b72abdefSreyk break; 185b72abdefSreyk case IEEE80211_FC1_DIR_NODS: 186ab7e388eSclaudio esrc = wh->i_addr2; 187ab7e388eSclaudio edst = wh->i_addr1; 188d49cb46eScanacar break; 189b72abdefSreyk case IEEE80211_FC1_DIR_DSTODS: 190*9d5679eaSstsp if (hasqos) { 191*9d5679eaSstsp struct ieee80211_qosframe_addr4 *w4; 192*9d5679eaSstsp 193*9d5679eaSstsp w4 = (struct ieee80211_qosframe_addr4 *) wh; 194*9d5679eaSstsp TCHECK(*w4); 195*9d5679eaSstsp t = (u_int8_t *) (w4 + 1); 196*9d5679eaSstsp datalen = len - sizeof(*w4); 197*9d5679eaSstsp esrc = w4->i_addr4; 198*9d5679eaSstsp edst = w4->i_addr3; 199*9d5679eaSstsp } else { 200*9d5679eaSstsp struct ieee80211_frame_addr4 *w4; 201*9d5679eaSstsp 202d49cb46eScanacar w4 = (struct ieee80211_frame_addr4 *) wh; 203d49cb46eScanacar TCHECK(*w4); 204d49cb46eScanacar t = (u_int8_t *) (w4 + 1); 205d49cb46eScanacar datalen = len - sizeof(*w4); 206ab7e388eSclaudio esrc = w4->i_addr4; 207ab7e388eSclaudio edst = w4->i_addr3; 208*9d5679eaSstsp } 209b72abdefSreyk break; 210b72abdefSreyk } 211b72abdefSreyk 212ab7e388eSclaudio if (data && esrc) 213ab7e388eSclaudio llc_print(t, datalen, datalen, esrc, edst); 214ab7e388eSclaudio else if (eflag && esrc) 215ab7e388eSclaudio printf("%s > %s", 216ab7e388eSclaudio etheraddr_string(esrc), etheraddr_string(edst)); 217ab7e388eSclaudio 218b72abdefSreyk return (0); 219b72abdefSreyk 220b72abdefSreyk trunc: 221b72abdefSreyk /* Truncated elements in frame */ 222b72abdefSreyk return (1); 223b72abdefSreyk } 224b72abdefSreyk 22512a08440Sreyk /* Caller checks len */ 22612a08440Sreyk void 22712a08440Sreyk ieee80211_print_element(u_int8_t *data, u_int len) 22812a08440Sreyk { 22912a08440Sreyk u_int8_t *p; 2309cbdb746Sderaadt int i; 23112a08440Sreyk 23212a08440Sreyk printf(" 0x"); 2339cbdb746Sderaadt for (i = 0, p = data; i < len; i++, p++) 23412a08440Sreyk printf("%02x", *p); 23512a08440Sreyk } 23612a08440Sreyk 23712a08440Sreyk /* Caller checks len */ 23812a08440Sreyk void 23912a08440Sreyk ieee80211_print_essid(u_int8_t *essid, u_int len) 24012a08440Sreyk { 24112a08440Sreyk u_int8_t *p; 2429cbdb746Sderaadt int i; 24312a08440Sreyk 24412a08440Sreyk if (len > IEEE80211_NWID_LEN) 24512a08440Sreyk len = IEEE80211_NWID_LEN; 24612a08440Sreyk 24712a08440Sreyk /* determine printable or not */ 24812a08440Sreyk for (i = 0, p = essid; i < len; i++, p++) { 24912a08440Sreyk if (*p < ' ' || *p > 0x7e) 25012a08440Sreyk break; 25112a08440Sreyk } 25212a08440Sreyk if (i == len) { 25312a08440Sreyk printf(" ("); 25412a08440Sreyk for (i = 0, p = essid; i < len; i++, p++) 25512a08440Sreyk putchar(*p); 25612a08440Sreyk putchar(')'); 2579cbdb746Sderaadt } else 25812a08440Sreyk ieee80211_print_element(essid, len); 25912a08440Sreyk } 26012a08440Sreyk 2611e3bf20aSstsp /* Caller checks len */ 2621e3bf20aSstsp void 26377734011Sstsp ieee80211_print_country(u_int8_t *data, u_int len) 26477734011Sstsp { 26577734011Sstsp u_int8_t first_chan, nchan, maxpower; 26677734011Sstsp 26777734011Sstsp if (len < 6) 26877734011Sstsp return; 26977734011Sstsp 27077734011Sstsp /* country string */ 27177734011Sstsp printf((isprint(data[0]) ? " '%c" : " '\\%03o"), data[0]); 27277734011Sstsp printf((isprint(data[1]) ? "%c" : "\\%03o"), data[1]); 27377734011Sstsp printf((isprint(data[2]) ? "%c'" : "\\%03o'"), data[2]); 27477734011Sstsp 27577734011Sstsp len -= 3; 27677734011Sstsp data += 3; 27777734011Sstsp 27877734011Sstsp /* channels and corresponding TX power limits */ 27977734011Sstsp while (len > 3) { 28077734011Sstsp /* no pretty-printing for nonsensical zero values, 28177734011Sstsp * nor for operating extension IDs (values >= 201) */ 28277734011Sstsp if (data[0] == 0 || data[1] == 0 || 28377734011Sstsp data[0] >= 201 || data[1] >= 201) { 28477734011Sstsp printf(", %d %d %d", data[0], data[1], data[2]); 28577734011Sstsp continue; 28677734011Sstsp } 28777734011Sstsp 28877734011Sstsp first_chan = data[0]; 28977734011Sstsp nchan = data[1]; 29077734011Sstsp maxpower = data[2]; 29177734011Sstsp 29277734011Sstsp printf(", channel%s %d", nchan == 1 ? "" : "s", first_chan); 29377734011Sstsp if (nchan > 1) 29477734011Sstsp printf("-%d", first_chan + nchan - 1); 29577734011Sstsp printf(" limit %ddB", maxpower); 29677734011Sstsp 29777734011Sstsp len -= 3; 29877734011Sstsp data += 3; 29977734011Sstsp } 30077734011Sstsp } 30177734011Sstsp 30277734011Sstsp /* Caller checks len */ 30377734011Sstsp void 3041e3bf20aSstsp ieee80211_print_htcaps(u_int8_t *data, u_int len) 3051e3bf20aSstsp { 306537e7cd0Sstsp uint16_t htcaps, rxrate; 3071e3bf20aSstsp int smps, rxstbc; 308537e7cd0Sstsp uint8_t ampdu, txmcs; 309537e7cd0Sstsp int i; 310537e7cd0Sstsp uint8_t *rxmcs; 3111e3bf20aSstsp 3121e3bf20aSstsp if (len < 2) { 3131e3bf20aSstsp ieee80211_print_element(data, len); 3141e3bf20aSstsp return; 3151e3bf20aSstsp } 3161e3bf20aSstsp 3171e3bf20aSstsp htcaps = (data[0]) | (data[1] << 8); 3181e3bf20aSstsp printf("=<"); 3191e3bf20aSstsp 3201e3bf20aSstsp /* channel width */ 3211e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_CBW20_40) 3221e3bf20aSstsp printf("20/40MHz"); 3231e3bf20aSstsp else 3241e3bf20aSstsp printf("20MHz"); 3251e3bf20aSstsp 3261e3bf20aSstsp /* LDPC coding */ 3271e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_LDPC) 3281e3bf20aSstsp printf(",LDPC"); 3291e3bf20aSstsp 3301e3bf20aSstsp /* spatial multiplexing power save mode */ 3311e3bf20aSstsp smps = (htcaps & IEEE80211_HTCAP_SMPS_MASK) 3321e3bf20aSstsp >> IEEE80211_HTCAP_SMPS_SHIFT; 3331e3bf20aSstsp if (smps == 0) 3341e3bf20aSstsp printf(",SMPS static"); 3351e3bf20aSstsp else if (smps == 1) 3361e3bf20aSstsp printf(",SMPS dynamic"); 3371e3bf20aSstsp 3381e3bf20aSstsp /* 11n greenfield mode */ 3391e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_GF) 3401e3bf20aSstsp printf(",greenfield"); 3411e3bf20aSstsp 3421e3bf20aSstsp /* short guard interval */ 3431e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_SGI20) 3441e3bf20aSstsp printf(",SGI@20MHz"); 3451e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_SGI40) 3461e3bf20aSstsp printf(",SGI@40MHz"); 3471e3bf20aSstsp 3481e3bf20aSstsp /* space-time block coding */ 3491e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_TXSTBC) 3501e3bf20aSstsp printf(",TXSTBC"); 3511e3bf20aSstsp rxstbc = (htcaps & IEEE80211_HTCAP_RXSTBC_MASK) 3521e3bf20aSstsp >> IEEE80211_HTCAP_RXSTBC_SHIFT; 3531e3bf20aSstsp if (rxstbc > 0 && rxstbc < 4) 3541e3bf20aSstsp printf(",RXSTBC %d stream", rxstbc); 3551e3bf20aSstsp 3561e3bf20aSstsp /* delayed block-ack */ 3571e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_DELAYEDBA) 3581e3bf20aSstsp printf(",delayed BA"); 3591e3bf20aSstsp 3601e3bf20aSstsp /* max A-MSDU length */ 3611e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_AMSDU7935) 3621e3bf20aSstsp printf(",A-MSDU 7935"); 3631e3bf20aSstsp else 3641e3bf20aSstsp printf(",A-MSDU 3839"); 3651e3bf20aSstsp 3661e3bf20aSstsp /* DSSS/CCK in 40MHz mode */ 3671e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_DSSSCCK40) 3681e3bf20aSstsp printf(",DSSS/CCK@40MHz"); 3691e3bf20aSstsp 3701e3bf20aSstsp /* 40MHz intolerant */ 3711e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_40INTOLERANT) 3721e3bf20aSstsp printf(",40MHz intolerant"); 3731e3bf20aSstsp 3741e3bf20aSstsp /* L-SIG TXOP protection */ 3751e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_LSIGTXOPPROT) 3761e3bf20aSstsp printf(",L-SIG TXOP prot"); 3771e3bf20aSstsp 378537e7cd0Sstsp if (len < 3) { 379537e7cd0Sstsp printf(">"); 380537e7cd0Sstsp return; 381537e7cd0Sstsp } 382537e7cd0Sstsp 383537e7cd0Sstsp /* A-MPDU parameters. */ 384537e7cd0Sstsp ampdu = data[2]; 385537e7cd0Sstsp 386537e7cd0Sstsp /* A-MPDU length exponent */ 387537e7cd0Sstsp if ((ampdu & IEEE80211_AMPDU_PARAM_LE) >= 0 && 388537e7cd0Sstsp (ampdu & IEEE80211_AMPDU_PARAM_LE) <= 3) 389537e7cd0Sstsp printf(",A-MPDU max %d", 3900b19ae84Sstsp (1 << (13 + (ampdu & IEEE80211_AMPDU_PARAM_LE))) - 1); 391537e7cd0Sstsp 392537e7cd0Sstsp /* A-MPDU start spacing */ 393537e7cd0Sstsp if (ampdu & IEEE80211_AMPDU_PARAM_SS) { 394537e7cd0Sstsp float ss; 395537e7cd0Sstsp 396537e7cd0Sstsp switch ((ampdu & IEEE80211_AMPDU_PARAM_SS) >> 2) { 397537e7cd0Sstsp case 1: 398537e7cd0Sstsp ss = 0.25; 399537e7cd0Sstsp break; 400537e7cd0Sstsp case 2: 401537e7cd0Sstsp ss = 0.5; 402537e7cd0Sstsp break; 403537e7cd0Sstsp case 3: 404537e7cd0Sstsp ss = 1; 405537e7cd0Sstsp break; 406537e7cd0Sstsp case 4: 407537e7cd0Sstsp ss = 2; 408537e7cd0Sstsp break; 409537e7cd0Sstsp case 5: 410537e7cd0Sstsp ss = 4; 411537e7cd0Sstsp break; 412537e7cd0Sstsp case 6: 413537e7cd0Sstsp ss = 8; 414537e7cd0Sstsp break; 415537e7cd0Sstsp case 7: 416537e7cd0Sstsp ss = 16; 417537e7cd0Sstsp break; 418537e7cd0Sstsp default: 419537e7cd0Sstsp ss = 0; 420537e7cd0Sstsp break; 421537e7cd0Sstsp } 422537e7cd0Sstsp if (ss != 0) 423537e7cd0Sstsp printf(",A-MPDU spacing %.2fus", ss); 424537e7cd0Sstsp } 425537e7cd0Sstsp 426537e7cd0Sstsp if (len < 21) { 427537e7cd0Sstsp printf(">"); 428537e7cd0Sstsp return; 429537e7cd0Sstsp } 430537e7cd0Sstsp 431537e7cd0Sstsp /* Supported MCS set. */ 432537e7cd0Sstsp printf(",RxMCS 0x"); 433537e7cd0Sstsp rxmcs = &data[3]; 434537e7cd0Sstsp for (i = 0; i < 10; i++) 435537e7cd0Sstsp printf("%02x", rxmcs[i]); 436537e7cd0Sstsp 437537e7cd0Sstsp /* Max MCS Rx rate (a value of 0 means "not specified"). */ 438537e7cd0Sstsp rxrate = ((data[13] | (data[14]) << 8) & IEEE80211_MCS_RX_RATE_HIGH); 439537e7cd0Sstsp if (rxrate) 440537e7cd0Sstsp printf(",RxMaxrate %huMb/s", rxrate); 441537e7cd0Sstsp 442537e7cd0Sstsp /* Tx MCS Set */ 443537e7cd0Sstsp txmcs = data[15]; 444537e7cd0Sstsp if (txmcs & IEEE80211_TX_MCS_SET_DEFINED) { 445537e7cd0Sstsp if (txmcs & IEEE80211_TX_RX_MCS_NOT_EQUAL) { 446537e7cd0Sstsp /* Number of spatial Tx streams. */ 447537e7cd0Sstsp printf(",%d Tx streams", 448537e7cd0Sstsp 1 + ((txmcs & IEEE80211_TX_SPATIAL_STREAMS) >> 2)); 449537e7cd0Sstsp /* Transmit unequal modulation supported. */ 450537e7cd0Sstsp if (txmcs & IEEE80211_TX_UNEQUAL_MODULATION) 451537e7cd0Sstsp printf(",UEQM"); 452537e7cd0Sstsp } 453537e7cd0Sstsp } 454537e7cd0Sstsp 4551e3bf20aSstsp printf(">"); 4561e3bf20aSstsp } 4571e3bf20aSstsp 45836fa064cSstsp /* Caller checks len */ 45936fa064cSstsp void 46036fa064cSstsp ieee80211_print_htop(u_int8_t *data, u_int len) 46136fa064cSstsp { 46236fa064cSstsp u_int8_t primary_chan; 46336fa064cSstsp u_int8_t htopinfo[5]; 46436fa064cSstsp u_int8_t basic_mcs[16]; 46536fa064cSstsp int sco, prot, i; 46636fa064cSstsp 46736fa064cSstsp if (len < sizeof(primary_chan) + sizeof(htopinfo) + sizeof(basic_mcs)) { 46836fa064cSstsp ieee80211_print_element(data, len); 46936fa064cSstsp return; 47036fa064cSstsp } 47136fa064cSstsp 47236fa064cSstsp htopinfo[0] = data[1]; 47336fa064cSstsp 47436fa064cSstsp printf("=<"); 47536fa064cSstsp 47636fa064cSstsp /* primary channel and secondary channel offset */ 47736fa064cSstsp primary_chan = data[0]; 47836fa064cSstsp sco = ((htopinfo[0] & IEEE80211_HTOP0_SCO_MASK) 47936fa064cSstsp >> IEEE80211_HTOP0_SCO_SHIFT); 480b144e175Sstsp if (sco == 0) /* no secondary channel */ 48136fa064cSstsp printf("20MHz chan %d", primary_chan); 482b144e175Sstsp else if (sco == 1) { /* secondary channel above */ 483b144e175Sstsp if (primary_chan >= 1 && primary_chan <= 13) /* 2GHz */ 484b144e175Sstsp printf("40MHz chan %d:%d", primary_chan, 485b144e175Sstsp primary_chan + 1); 486b144e175Sstsp else if (primary_chan >= 34) /* 5GHz */ 487b144e175Sstsp printf("40MHz chan %d:%d", primary_chan, 488b144e175Sstsp primary_chan + 4); 48936fa064cSstsp else 490b144e175Sstsp printf("[invalid 40MHz chan %d+]", primary_chan); 491b144e175Sstsp } else if (sco == 3) { /* secondary channel below */ 492b144e175Sstsp if (primary_chan >= 2 && primary_chan <= 14) /* 2GHz */ 493b144e175Sstsp printf("40MHz chan %d:%d", primary_chan, 494b144e175Sstsp primary_chan - 1); 495b144e175Sstsp else if (primary_chan >= 40) /* 5GHz */ 496b144e175Sstsp printf("40MHz chan %d:%d", primary_chan, 497b144e175Sstsp primary_chan - 4); 498b144e175Sstsp else 499b144e175Sstsp printf("[invalid 40MHz chan %d-]", primary_chan); 500b144e175Sstsp } else 50136fa064cSstsp printf("chan %d [invalid secondary channel offset %d]", 50236fa064cSstsp primary_chan, sco); 50336fa064cSstsp 50436fa064cSstsp /* STA channel width */ 50536fa064cSstsp if ((htopinfo[0] & IEEE80211_HTOP0_CHW) == 0) 50636fa064cSstsp printf(",STA chanw 20MHz"); 50736fa064cSstsp 50836fa064cSstsp /* reduced interframe space (RIFS) permitted */ 50936fa064cSstsp if (htopinfo[0] & IEEE80211_HTOP0_RIFS) 51036fa064cSstsp printf(",RIFS"); 51136fa064cSstsp 51236fa064cSstsp htopinfo[1] = data[2]; 51336fa064cSstsp 51436fa064cSstsp /* protection requirements for HT transmissions */ 51536fa064cSstsp prot = ((htopinfo[1] & IEEE80211_HTOP1_PROT_MASK) 51636fa064cSstsp >> IEEE80211_HTOP1_PROT_SHIFT); 51736fa064cSstsp if (prot == 1) 51836fa064cSstsp printf(",protect non-member"); 51936fa064cSstsp else if (prot == 2) 52036fa064cSstsp printf(",protect 20MHz"); 52136fa064cSstsp else if (prot == 3) 52236fa064cSstsp printf(",protect non-HT"); 52336fa064cSstsp 52436fa064cSstsp /* non-greenfield STA present */ 52536fa064cSstsp if (htopinfo[1] & IEEE80211_HTOP1_NONGF_STA) 52636fa064cSstsp printf(",non-greenfield STA"); 52736fa064cSstsp 52836fa064cSstsp /* non-HT STA present */ 52936fa064cSstsp if (htopinfo[1] & IEEE80211_HTOP1_OBSS_NONHT_STA) 53036fa064cSstsp printf(",non-HT STA"); 53136fa064cSstsp 53236fa064cSstsp htopinfo[3] = data[4]; 53336fa064cSstsp 53436fa064cSstsp /* dual-beacon */ 53536fa064cSstsp if (htopinfo[3] & IEEE80211_HTOP2_DUALBEACON) 53636fa064cSstsp printf(",dualbeacon"); 53736fa064cSstsp 53836fa064cSstsp /* dual CTS protection */ 53936fa064cSstsp if (htopinfo[3] & IEEE80211_HTOP2_DUALCTSPROT) 54036fa064cSstsp printf(",dualctsprot"); 54136fa064cSstsp 54236fa064cSstsp htopinfo[4] = data[5]; 54336fa064cSstsp 54436fa064cSstsp /* space-time block coding (STBC) beacon */ 54558089030Sstsp if ((htopinfo[4] << 8) & IEEE80211_HTOP2_STBCBEACON) 54636fa064cSstsp printf(",STBC beacon"); 54736fa064cSstsp 54836fa064cSstsp /* L-SIG (non-HT signal field) TX opportunity (TXOP) protection */ 54936fa064cSstsp if ((htopinfo[4] << 8) & IEEE80211_HTOP2_LSIGTXOP) 55036fa064cSstsp printf(",lsigtxprot"); 55136fa064cSstsp 55236fa064cSstsp /* phased-coexistence operation (PCO) active */ 55336fa064cSstsp if ((htopinfo[4] << 8) & IEEE80211_HTOP2_PCOACTIVE) { 55436fa064cSstsp /* PCO phase */ 55536fa064cSstsp if ((htopinfo[4] << 8) & IEEE80211_HTOP2_PCOPHASE40) 55636fa064cSstsp printf(",pco40MHz"); 55736fa064cSstsp else 55836fa064cSstsp printf(",pco20MHz"); 55936fa064cSstsp } 56036fa064cSstsp 56136fa064cSstsp /* basic MCS set */ 56236fa064cSstsp memcpy(basic_mcs, &data[6], sizeof(basic_mcs)); 56336fa064cSstsp printf(",basic MCS set 0x"); 56436fa064cSstsp for (i = 0; i < sizeof(basic_mcs) / sizeof(basic_mcs[0]); i++) 56536fa064cSstsp printf("%x", basic_mcs[i]); 56636fa064cSstsp 56736fa064cSstsp printf(">"); 56836fa064cSstsp } 56936fa064cSstsp 57012a08440Sreyk int 57112a08440Sreyk ieee80211_elements(struct ieee80211_frame *wh, u_int flen) 57212a08440Sreyk { 57312a08440Sreyk u_int8_t *buf, *frm; 574cce1ba42Sclaudio u_int64_t tstamp; 575cce1ba42Sclaudio u_int16_t bintval, capinfo; 57612a08440Sreyk int i; 57712a08440Sreyk 57812a08440Sreyk buf = (u_int8_t *)wh; 57912a08440Sreyk frm = (u_int8_t *)&wh[1]; 58012a08440Sreyk 5810a05c5bfSreyk TCHECK2(*frm, 8); 582cce1ba42Sclaudio bcopy(frm, &tstamp, sizeof(u_int64_t)); 58312a08440Sreyk frm += 8; 58412a08440Sreyk 58512a08440Sreyk if (vflag > 1) 586cce1ba42Sclaudio printf(", timestamp %llu", letoh64(tstamp)); 58712a08440Sreyk 5880a05c5bfSreyk TCHECK2(*frm, 2); 589cce1ba42Sclaudio bcopy(frm, &bintval, sizeof(u_int16_t)); 59012a08440Sreyk frm += 2; 59112a08440Sreyk 59212a08440Sreyk if (vflag > 1) 593cce1ba42Sclaudio printf(", interval %u", letoh16(bintval)); 59412a08440Sreyk 5950a05c5bfSreyk TCHECK2(*frm, 2); 596cce1ba42Sclaudio bcopy(frm, &capinfo, sizeof(u_int16_t)); 59712a08440Sreyk frm += 2; 59812a08440Sreyk 59912a08440Sreyk if (vflag) 600cce1ba42Sclaudio printb(", caps", letoh16(capinfo), 60112a08440Sreyk IEEE80211_CAPINFO_BITS); 60212a08440Sreyk 60312a08440Sreyk while (TTEST2(*frm, 2)) { 60412a08440Sreyk u_int len = frm[1]; 60512a08440Sreyk u_int8_t *data = frm + 2; 60612a08440Sreyk 60712a08440Sreyk if (!TTEST2(*data, len)) 60812a08440Sreyk break; 60912a08440Sreyk 61012a08440Sreyk #define ELEM_CHECK(l) if (len != l) break 61112a08440Sreyk 61212a08440Sreyk switch (*frm) { 61312a08440Sreyk case IEEE80211_ELEMID_SSID: 61412a08440Sreyk printf(", ssid"); 61512a08440Sreyk ieee80211_print_essid(data, len); 61612a08440Sreyk break; 61712a08440Sreyk case IEEE80211_ELEMID_RATES: 61812a08440Sreyk printf(", rates"); 61912a08440Sreyk if (!vflag) 62012a08440Sreyk break; 62112a08440Sreyk for (i = len; i > 0; i--, data++) 62212a08440Sreyk printf(" %uM", 62312a08440Sreyk (data[0] & IEEE80211_RATE_VAL) / 2); 62412a08440Sreyk break; 62512a08440Sreyk case IEEE80211_ELEMID_FHPARMS: 62612a08440Sreyk ELEM_CHECK(5); 62712a08440Sreyk printf(", fh (dwell %u, chan %u, index %u)", 62812a08440Sreyk (data[1] << 8) | data[0], 62912a08440Sreyk (data[2] - 1) * 80 + data[3], /* FH_CHAN */ 63012a08440Sreyk data[4]); 63112a08440Sreyk break; 63212a08440Sreyk case IEEE80211_ELEMID_DSPARMS: 63312a08440Sreyk ELEM_CHECK(1); 63412a08440Sreyk printf(", ds"); 63512a08440Sreyk if (vflag) 63612a08440Sreyk printf(" (chan %u)", data[0]); 63712a08440Sreyk break; 63812a08440Sreyk case IEEE80211_ELEMID_CFPARMS: 63912a08440Sreyk printf(", cf"); 64012a08440Sreyk if (vflag) 64112a08440Sreyk ieee80211_print_element(data, len); 64212a08440Sreyk break; 64312a08440Sreyk case IEEE80211_ELEMID_TIM: 64412a08440Sreyk printf(", tim"); 64512a08440Sreyk if (vflag) 64612a08440Sreyk ieee80211_print_element(data, len); 64712a08440Sreyk break; 64812a08440Sreyk case IEEE80211_ELEMID_IBSSPARMS: 64912a08440Sreyk printf(", ibss"); 65012a08440Sreyk if (vflag) 65112a08440Sreyk ieee80211_print_element(data, len); 65212a08440Sreyk break; 65312a08440Sreyk case IEEE80211_ELEMID_COUNTRY: 65412a08440Sreyk printf(", country"); 65577734011Sstsp ieee80211_print_country(data, len); 65612a08440Sreyk break; 65712a08440Sreyk case IEEE80211_ELEMID_CHALLENGE: 65812a08440Sreyk printf(", challenge"); 65912a08440Sreyk if (vflag) 66012a08440Sreyk ieee80211_print_element(data, len); 66112a08440Sreyk break; 662738acb58Ssthen case IEEE80211_ELEMID_CSA: 663958b7e45Ssthen ELEM_CHECK(3); 664738acb58Ssthen printf(", csa (chan %u count %u%s)", data[1], data[2], 665738acb58Ssthen (data[0] == 1) ? " noTX" : ""); 666738acb58Ssthen break; 66712a08440Sreyk case IEEE80211_ELEMID_ERP: 66812a08440Sreyk printf(", erp"); 66912a08440Sreyk if (vflag) 67012a08440Sreyk ieee80211_print_element(data, len); 67112a08440Sreyk break; 67212a08440Sreyk case IEEE80211_ELEMID_RSN: 67312a08440Sreyk printf(", rsn"); 67412a08440Sreyk if (vflag) 67512a08440Sreyk ieee80211_print_element(data, len); 67612a08440Sreyk break; 67712a08440Sreyk case IEEE80211_ELEMID_XRATES: 67812a08440Sreyk printf(", xrates"); 67912a08440Sreyk if (!vflag) 68012a08440Sreyk break; 68112a08440Sreyk for (i = len; i > 0; i--, data++) 68212a08440Sreyk printf(" %uM", 68312a08440Sreyk (data[0] & IEEE80211_RATE_VAL) / 2); 68412a08440Sreyk break; 6858138faddSstsp case IEEE80211_ELEMID_TPC_REPORT: 6868138faddSstsp printf(", tpcreport"); 68712a08440Sreyk if (vflag) 68812a08440Sreyk ieee80211_print_element(data, len); 68912a08440Sreyk break; 6908138faddSstsp case IEEE80211_ELEMID_TPC_REQUEST: 6918138faddSstsp printf(", tpcrequest"); 69212a08440Sreyk if (vflag) 69312a08440Sreyk ieee80211_print_element(data, len); 69412a08440Sreyk break; 6951e3bf20aSstsp case IEEE80211_ELEMID_HTCAPS: 6961e3bf20aSstsp printf(", htcaps"); 6971e3bf20aSstsp if (vflag) 6981e3bf20aSstsp ieee80211_print_htcaps(data, len); 6991e3bf20aSstsp break; 70036fa064cSstsp case IEEE80211_ELEMID_HTOP: 70136fa064cSstsp printf(", htop"); 70236fa064cSstsp if (vflag) 70336fa064cSstsp ieee80211_print_htop(data, len); 70436fa064cSstsp break; 70577734011Sstsp case IEEE80211_ELEMID_POWER_CONSTRAINT: 70677734011Sstsp ELEM_CHECK(1); 70777734011Sstsp printf(", power constraint %udB", data[0]); 70877734011Sstsp break; 7098f0a8537Sstsp case IEEE80211_ELEMID_QBSS_LOAD: 7108f0a8537Sstsp ELEM_CHECK(5); 7118f0a8537Sstsp printf(", %u stations, %d%% utilization, " 7128f0a8537Sstsp "admission capacity %uus/s", 7138f0a8537Sstsp (data[0] | data[1] << 8), 7148f0a8537Sstsp (data[2] * 100) / 255, 7158f0a8537Sstsp (data[3] | data[4] << 8) / 32); 7168f0a8537Sstsp break; 71712a08440Sreyk case IEEE80211_ELEMID_VENDOR: 71812a08440Sreyk printf(", vendor"); 71912a08440Sreyk if (vflag) 72012a08440Sreyk ieee80211_print_element(data, len); 72112a08440Sreyk break; 72212a08440Sreyk default: 72312a08440Sreyk printf(", %u:%u", (u_int) *frm, len); 72412a08440Sreyk if (vflag) 72512a08440Sreyk ieee80211_print_element(data, len); 72612a08440Sreyk break; 72712a08440Sreyk } 72812a08440Sreyk frm += len + 2; 72912a08440Sreyk 73012a08440Sreyk if (frm >= snapend) 73112a08440Sreyk break; 73212a08440Sreyk } 73312a08440Sreyk 73412a08440Sreyk #undef ELEM_CHECK 73512a08440Sreyk 73612a08440Sreyk return (0); 73712a08440Sreyk 73812a08440Sreyk trunc: 73912a08440Sreyk /* Truncated elements in frame */ 74012a08440Sreyk return (1); 74112a08440Sreyk } 74212a08440Sreyk 74312a08440Sreyk int 74412a08440Sreyk ieee80211_frame(struct ieee80211_frame *wh, u_int len) 74512a08440Sreyk { 74612a08440Sreyk u_int8_t subtype, type, *frm; 74712a08440Sreyk 74812a08440Sreyk TCARR(wh->i_fc); 74912a08440Sreyk 75012a08440Sreyk type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 75112a08440Sreyk subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 75212a08440Sreyk 75312a08440Sreyk frm = (u_int8_t *)&wh[1]; 75412a08440Sreyk 755ab7e388eSclaudio if (vflag) 756ab7e388eSclaudio printb(" flags", wh->i_fc[1], IEEE80211_FC1_BITS); 757ab7e388eSclaudio 75812a08440Sreyk switch (type) { 75912a08440Sreyk case IEEE80211_FC0_TYPE_DATA: 760ab7e388eSclaudio printf(": %s: ", ieee80211_data_subtype_name[ 761ab7e388eSclaudio subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]); 762b72abdefSreyk ieee80211_data(wh, len); 76312a08440Sreyk break; 76412a08440Sreyk case IEEE80211_FC0_TYPE_MGT: 76512a08440Sreyk printf(": %s", ieee80211_mgt_subtype_name[ 76612a08440Sreyk subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]); 76712a08440Sreyk switch (subtype) { 76812a08440Sreyk case IEEE80211_FC0_SUBTYPE_BEACON: 76912a08440Sreyk case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 77012a08440Sreyk if (ieee80211_elements(wh, len) != 0) 77112a08440Sreyk goto trunc; 77212a08440Sreyk break; 77312a08440Sreyk case IEEE80211_FC0_SUBTYPE_AUTH: 77412a08440Sreyk TCHECK2(*frm, 2); /* Auth Algorithm */ 77512a08440Sreyk switch (IEEE80211_AUTH_ALGORITHM(frm)) { 77612a08440Sreyk case IEEE80211_AUTH_ALG_OPEN: 77712a08440Sreyk TCHECK2(*frm, 4); /* Auth Transaction */ 77812a08440Sreyk switch (IEEE80211_AUTH_TRANSACTION(frm)) { 77912a08440Sreyk case IEEE80211_AUTH_OPEN_REQUEST: 78012a08440Sreyk printf(" request"); 78112a08440Sreyk break; 78212a08440Sreyk case IEEE80211_AUTH_OPEN_RESPONSE: 78312a08440Sreyk printf(" response"); 78412a08440Sreyk break; 78512a08440Sreyk } 78612a08440Sreyk break; 78712a08440Sreyk case IEEE80211_AUTH_ALG_SHARED: 78812a08440Sreyk TCHECK2(*frm, 4); /* Auth Transaction */ 78912a08440Sreyk switch (IEEE80211_AUTH_TRANSACTION(frm)) { 79012a08440Sreyk case IEEE80211_AUTH_SHARED_REQUEST: 79112a08440Sreyk printf(" request"); 79212a08440Sreyk break; 79312a08440Sreyk case IEEE80211_AUTH_SHARED_CHALLENGE: 79412a08440Sreyk printf(" challenge"); 79512a08440Sreyk break; 79612a08440Sreyk case IEEE80211_AUTH_SHARED_RESPONSE: 79712a08440Sreyk printf(" response"); 79812a08440Sreyk break; 79912a08440Sreyk case IEEE80211_AUTH_SHARED_PASS: 80012a08440Sreyk printf(" pass"); 80112a08440Sreyk break; 80212a08440Sreyk } 80312a08440Sreyk break; 80412a08440Sreyk case IEEE80211_AUTH_ALG_LEAP: 80512a08440Sreyk printf(" (leap)"); 80612a08440Sreyk break; 80712a08440Sreyk } 80812a08440Sreyk break; 80918786664Sclaudio case IEEE80211_FC0_SUBTYPE_DEAUTH: 81018786664Sclaudio case IEEE80211_FC0_SUBTYPE_DISASSOC: 81118786664Sclaudio TCHECK2(*frm, 2); /* Reason Code */ 81218786664Sclaudio ieee80211_reason(frm[0] | (frm[1] << 8)); 81318786664Sclaudio break; 81412a08440Sreyk } 81512a08440Sreyk break; 81612a08440Sreyk default: 81712a08440Sreyk printf(": type#%d", type); 81812a08440Sreyk break; 81912a08440Sreyk } 82012a08440Sreyk 82112a08440Sreyk return (0); 82212a08440Sreyk 82312a08440Sreyk trunc: 82412a08440Sreyk /* Truncated 802.11 frame */ 82512a08440Sreyk return (1); 82612a08440Sreyk } 82712a08440Sreyk 82812a08440Sreyk u_int 82912a08440Sreyk ieee80211_any2ieee(u_int freq, u_int flags) 83012a08440Sreyk { 83112a08440Sreyk if (flags & IEEE80211_CHAN_2GHZ) { 83212a08440Sreyk if (freq == 2484) 83312a08440Sreyk return 14; 83412a08440Sreyk if (freq < 2484) 83512a08440Sreyk return (freq - 2407) / 5; 83612a08440Sreyk else 83712a08440Sreyk return 15 + ((freq - 2512) / 20); 83812a08440Sreyk } else if (flags & IEEE80211_CHAN_5GHZ) { 83912a08440Sreyk return (freq - 5000) / 5; 84012a08440Sreyk } else { 84112a08440Sreyk /* Assume channel is already an IEEE number */ 84212a08440Sreyk return (freq); 84312a08440Sreyk } 84412a08440Sreyk } 84512a08440Sreyk 84612a08440Sreyk int 84712a08440Sreyk ieee80211_print(struct ieee80211_frame *wh, u_int len) 84812a08440Sreyk { 84912a08440Sreyk if (eflag) 85012a08440Sreyk if (ieee80211_hdr(wh)) 85112a08440Sreyk return (1); 85212a08440Sreyk 85312a08440Sreyk printf("802.11"); 85412a08440Sreyk 85512a08440Sreyk return (ieee80211_frame(wh, len)); 85612a08440Sreyk } 85712a08440Sreyk 85812a08440Sreyk void 85912a08440Sreyk ieee802_11_if_print(u_char *user, const struct pcap_pkthdr *h, 86012a08440Sreyk const u_char *p) 86112a08440Sreyk { 86212a08440Sreyk struct ieee80211_frame *wh = (struct ieee80211_frame*)p; 86312a08440Sreyk 864c79cf170Sreyk if (!ieee80211_encap) 86512a08440Sreyk ts_print(&h->ts); 86612a08440Sreyk 86712a08440Sreyk packetp = p; 86812a08440Sreyk snapend = p + h->caplen; 86912a08440Sreyk 870a0774ae9Smglocker if (ieee80211_print(wh, (u_int)h->len) != 0) 87112a08440Sreyk printf("[|802.11]"); 87212a08440Sreyk 873c79cf170Sreyk if (!ieee80211_encap) { 87412a08440Sreyk if (xflag) 875a0774ae9Smglocker default_print(p, (u_int)h->len); 87612a08440Sreyk putchar('\n'); 87712a08440Sreyk } 878c79cf170Sreyk } 87912a08440Sreyk 88012a08440Sreyk void 88112a08440Sreyk ieee802_11_radio_if_print(u_char *user, const struct pcap_pkthdr *h, 88212a08440Sreyk const u_char *p) 88312a08440Sreyk { 88412a08440Sreyk struct ieee80211_radiotap_header *rh = 88512a08440Sreyk (struct ieee80211_radiotap_header*)p; 88612a08440Sreyk struct ieee80211_frame *wh; 88712a08440Sreyk u_int8_t *t; 88812a08440Sreyk u_int32_t present; 88912a08440Sreyk u_int len, rh_len; 890cce1ba42Sclaudio u_int16_t tmp; 89112a08440Sreyk 892c79cf170Sreyk if (!ieee80211_encap) 89312a08440Sreyk ts_print(&h->ts); 89412a08440Sreyk 89512a08440Sreyk packetp = p; 89612a08440Sreyk snapend = p + h->caplen; 89712a08440Sreyk 89812a08440Sreyk TCHECK(*rh); 89912a08440Sreyk 900a0774ae9Smglocker len = h->len; 90112a08440Sreyk rh_len = letoh16(rh->it_len); 90212a08440Sreyk if (rh->it_version != 0) { 903c79cf170Sreyk printf("[?radiotap + 802.11 v:%u]", rh->it_version); 90412a08440Sreyk goto out; 90512a08440Sreyk } 90612a08440Sreyk 90712a08440Sreyk wh = (struct ieee80211_frame *)(p + rh_len); 90812a08440Sreyk if (len <= rh_len || ieee80211_print(wh, len - rh_len)) 90912a08440Sreyk printf("[|802.11]"); 91012a08440Sreyk 91112a08440Sreyk t = (u_int8_t*)p + sizeof(struct ieee80211_radiotap_header); 91212a08440Sreyk 91312a08440Sreyk if ((present = letoh32(rh->it_present)) == 0) 91412a08440Sreyk goto out; 91512a08440Sreyk 91612a08440Sreyk printf(", <radiotap v%u", rh->it_version); 91712a08440Sreyk 91812a08440Sreyk #define RADIOTAP(_x) \ 91912a08440Sreyk (present & (1 << IEEE80211_RADIOTAP_##_x)) 92012a08440Sreyk 92112a08440Sreyk if (RADIOTAP(TSFT)) { 922cce1ba42Sclaudio u_int64_t tsf; 923cce1ba42Sclaudio 92412a08440Sreyk TCHECK2(*t, 8); 925cce1ba42Sclaudio bcopy(t, &tsf, sizeof(u_int64_t)); 92612a08440Sreyk if (vflag > 1) 927cce1ba42Sclaudio printf(", tsf %llu", letoh64(tsf)); 92812a08440Sreyk t += 8; 92912a08440Sreyk } 93012a08440Sreyk 93112a08440Sreyk if (RADIOTAP(FLAGS)) { 93212a08440Sreyk u_int8_t flags = *(u_int8_t*)t; 933026ca542Sderaadt TCHECK2(*t, 1); 934026ca542Sderaadt 93512a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_CFP) 93612a08440Sreyk printf(", CFP"); 93712a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_SHORTPRE) 93812a08440Sreyk printf(", SHORTPRE"); 93912a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_WEP) 94012a08440Sreyk printf(", WEP"); 94112a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_FRAG) 94212a08440Sreyk printf(", FRAG"); 94312a08440Sreyk t += 1; 94412a08440Sreyk } 94512a08440Sreyk 94612a08440Sreyk if (RADIOTAP(RATE)) { 94712a08440Sreyk TCHECK2(*t, 1); 94812a08440Sreyk if (vflag) 94912a08440Sreyk printf(", %uMbit/s", (*(u_int8_t*)t) / 2); 95012a08440Sreyk t += 1; 95112a08440Sreyk } 95212a08440Sreyk 95312a08440Sreyk if (RADIOTAP(CHANNEL)) { 95412a08440Sreyk u_int16_t freq, flags; 95512a08440Sreyk TCHECK2(*t, 2); 95612a08440Sreyk 957cce1ba42Sclaudio bcopy(t, &freq, sizeof(u_int16_t)); 958cce1ba42Sclaudio freq = letoh16(freq); 95912a08440Sreyk t += 2; 96012a08440Sreyk TCHECK2(*t, 2); 961cce1ba42Sclaudio bcopy(t, &flags, sizeof(u_int16_t)); 962cce1ba42Sclaudio flags = letoh16(flags); 96312a08440Sreyk t += 2; 96412a08440Sreyk 96512a08440Sreyk printf(", chan %u", ieee80211_any2ieee(freq, flags)); 96612a08440Sreyk 96712a08440Sreyk if (flags & IEEE80211_CHAN_DYN && 96812a08440Sreyk flags & IEEE80211_CHAN_2GHZ) 96912a08440Sreyk printf(", 11g"); 97012a08440Sreyk else if (flags & IEEE80211_CHAN_CCK && 97112a08440Sreyk flags & IEEE80211_CHAN_2GHZ) 97212a08440Sreyk printf(", 11b"); 97312a08440Sreyk else if (flags & IEEE80211_CHAN_OFDM && 97412a08440Sreyk flags & IEEE80211_CHAN_2GHZ) 97512a08440Sreyk printf(", 11G"); 97612a08440Sreyk else if (flags & IEEE80211_CHAN_OFDM && 97712a08440Sreyk flags & IEEE80211_CHAN_5GHZ) 97812a08440Sreyk printf(", 11a"); 97912a08440Sreyk 98012a08440Sreyk if (flags & IEEE80211_CHAN_XR) 98112a08440Sreyk printf(", XR"); 98212a08440Sreyk } 98312a08440Sreyk 98412a08440Sreyk if (RADIOTAP(FHSS)) { 98512a08440Sreyk TCHECK2(*t, 2); 98612a08440Sreyk printf(", fhss %u/%u", *(u_int8_t*)t, *(u_int8_t*)t + 1); 98712a08440Sreyk t += 2; 98812a08440Sreyk } 98912a08440Sreyk 99012a08440Sreyk if (RADIOTAP(DBM_ANTSIGNAL)) { 99112a08440Sreyk TCHECK(*t); 99212a08440Sreyk printf(", sig %ddBm", *(int8_t*)t); 99312a08440Sreyk t += 1; 99412a08440Sreyk } 99512a08440Sreyk 99612a08440Sreyk if (RADIOTAP(DBM_ANTNOISE)) { 99712a08440Sreyk TCHECK(*t); 99812a08440Sreyk printf(", noise %ddBm", *(int8_t*)t); 99912a08440Sreyk t += 1; 100012a08440Sreyk } 100112a08440Sreyk 100212a08440Sreyk if (RADIOTAP(LOCK_QUALITY)) { 100312a08440Sreyk TCHECK2(*t, 2); 1004cce1ba42Sclaudio if (vflag) { 1005cce1ba42Sclaudio bcopy(t, &tmp, sizeof(u_int16_t)); 1006cce1ba42Sclaudio printf(", quality %u", letoh16(tmp)); 1007cce1ba42Sclaudio } 100812a08440Sreyk t += 2; 100912a08440Sreyk } 101012a08440Sreyk 101112a08440Sreyk if (RADIOTAP(TX_ATTENUATION)) { 101212a08440Sreyk TCHECK2(*t, 2); 1013cce1ba42Sclaudio if (vflag) { 1014cce1ba42Sclaudio bcopy(t, &tmp, sizeof(u_int16_t)); 1015cce1ba42Sclaudio printf(", txatt %u", letoh16(tmp)); 1016cce1ba42Sclaudio } 101712a08440Sreyk t += 2; 101812a08440Sreyk } 101912a08440Sreyk 102012a08440Sreyk if (RADIOTAP(DB_TX_ATTENUATION)) { 102112a08440Sreyk TCHECK2(*t, 2); 1022cce1ba42Sclaudio if (vflag) { 1023cce1ba42Sclaudio bcopy(t, &tmp, sizeof(u_int16_t)); 1024cce1ba42Sclaudio printf(", txatt %udB", letoh16(tmp)); 1025cce1ba42Sclaudio } 102612a08440Sreyk t += 2; 102712a08440Sreyk } 102812a08440Sreyk 102912a08440Sreyk if (RADIOTAP(DBM_TX_POWER)) { 103012a08440Sreyk TCHECK(*t); 103112a08440Sreyk printf(", txpower %ddBm", *(int8_t*)t); 103212a08440Sreyk t += 1; 103312a08440Sreyk } 103412a08440Sreyk 103512a08440Sreyk if (RADIOTAP(ANTENNA)) { 103612a08440Sreyk TCHECK(*t); 103712a08440Sreyk if (vflag) 103812a08440Sreyk printf(", antenna %u", *(u_int8_t*)t); 103912a08440Sreyk t += 1; 104012a08440Sreyk } 104112a08440Sreyk 104212a08440Sreyk if (RADIOTAP(DB_ANTSIGNAL)) { 104312a08440Sreyk TCHECK(*t); 104412a08440Sreyk printf(", signal %udB", *(u_int8_t*)t); 104512a08440Sreyk t += 1; 104612a08440Sreyk } 104712a08440Sreyk 104812a08440Sreyk if (RADIOTAP(DB_ANTNOISE)) { 104912a08440Sreyk TCHECK(*t); 105012a08440Sreyk printf(", noise %udB", *(u_int8_t*)t); 105112a08440Sreyk t += 1; 105212a08440Sreyk } 105312a08440Sreyk 105412a08440Sreyk if (RADIOTAP(FCS)) { 105512a08440Sreyk TCHECK2(*t, 4); 1056cce1ba42Sclaudio if (vflag) { 1057cce1ba42Sclaudio u_int32_t fcs; 1058cce1ba42Sclaudio bcopy(t, &fcs, sizeof(u_int32_t)); 1059cce1ba42Sclaudio printf(", fcs %08x", letoh32(fcs)); 1060cce1ba42Sclaudio } 106112a08440Sreyk t += 4; 106212a08440Sreyk } 106312a08440Sreyk 10646fc94ee3Sreyk if (RADIOTAP(RSSI)) { 10656fc94ee3Sreyk u_int8_t rssi, max_rssi; 10666fc94ee3Sreyk TCHECK(*t); 10676fc94ee3Sreyk rssi = *(u_int8_t*)t; 10686fc94ee3Sreyk t += 1; 10696fc94ee3Sreyk TCHECK(*t); 10706fc94ee3Sreyk max_rssi = *(u_int8_t*)t; 10716fc94ee3Sreyk t += 1; 10726fc94ee3Sreyk 10736fc94ee3Sreyk printf(", rssi %u/%u", rssi, max_rssi); 10746fc94ee3Sreyk } 10756fc94ee3Sreyk 107612a08440Sreyk #undef RADIOTAP 107712a08440Sreyk 107812a08440Sreyk putchar('>'); 107912a08440Sreyk goto out; 108012a08440Sreyk 108112a08440Sreyk trunc: 108212a08440Sreyk /* Truncated frame */ 108312a08440Sreyk printf("[|radiotap + 802.11]"); 108412a08440Sreyk 108512a08440Sreyk out: 1086c79cf170Sreyk if (!ieee80211_encap) { 108712a08440Sreyk if (xflag) 1088a0774ae9Smglocker default_print(p, h->len); 108912a08440Sreyk putchar('\n'); 109012a08440Sreyk } 1091c79cf170Sreyk } 109218786664Sclaudio 109318786664Sclaudio void 109418786664Sclaudio ieee80211_reason(u_int16_t reason) 109518786664Sclaudio { 109618786664Sclaudio if (!vflag) 109718786664Sclaudio return; 109818786664Sclaudio 109918786664Sclaudio switch (reason) { 110018786664Sclaudio case IEEE80211_REASON_UNSPECIFIED: 110118786664Sclaudio printf(", unspecified failure"); 110218786664Sclaudio break; 110318786664Sclaudio case IEEE80211_REASON_AUTH_EXPIRE: 110418786664Sclaudio printf(", authentication expired"); 110518786664Sclaudio break; 110618786664Sclaudio case IEEE80211_REASON_AUTH_LEAVE: 110718786664Sclaudio printf(", deauth - station left"); 110818786664Sclaudio break; 110918786664Sclaudio case IEEE80211_REASON_ASSOC_EXPIRE: 111018786664Sclaudio printf(", association expired"); 111118786664Sclaudio break; 111218786664Sclaudio case IEEE80211_REASON_ASSOC_TOOMANY: 111318786664Sclaudio printf(", too many associated stations"); 111418786664Sclaudio break; 111518786664Sclaudio case IEEE80211_REASON_NOT_AUTHED: 111618786664Sclaudio printf(", not authenticated"); 111718786664Sclaudio break; 111818786664Sclaudio case IEEE80211_REASON_NOT_ASSOCED: 111918786664Sclaudio printf(", not associated"); 112018786664Sclaudio break; 112118786664Sclaudio case IEEE80211_REASON_ASSOC_LEAVE: 112218786664Sclaudio printf(", disassociated - station left"); 112318786664Sclaudio break; 112418786664Sclaudio case IEEE80211_REASON_ASSOC_NOT_AUTHED: 112518786664Sclaudio printf(", association but not authenticated"); 112618786664Sclaudio break; 112718786664Sclaudio case IEEE80211_REASON_RSN_REQUIRED: 112818786664Sclaudio printf(", rsn required"); 112918786664Sclaudio break; 113018786664Sclaudio case IEEE80211_REASON_RSN_INCONSISTENT: 113118786664Sclaudio printf(", rsn inconsistent"); 113218786664Sclaudio break; 113318786664Sclaudio case IEEE80211_REASON_IE_INVALID: 113418786664Sclaudio printf(", ie invalid"); 113518786664Sclaudio break; 113618786664Sclaudio case IEEE80211_REASON_MIC_FAILURE: 113718786664Sclaudio printf(", mic failure"); 113818786664Sclaudio break; 113918786664Sclaudio default: 114018786664Sclaudio printf(", unknown reason %u", reason); 114118786664Sclaudio } 114218786664Sclaudio } 1143