1*9533a5eaSstsp /* $OpenBSD: print-802_11.c,v 1.34 2016/10/08 14:45:11 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 408dd9ce3eSstsp const char *ieee80211_ctl_subtype_name[] = { 418dd9ce3eSstsp "reserved#0", 428dd9ce3eSstsp "reserved#1", 438dd9ce3eSstsp "reserved#2", 448dd9ce3eSstsp "reserved#3", 458dd9ce3eSstsp "reserved#4", 468dd9ce3eSstsp "reserved#5", 478dd9ce3eSstsp "reserved#6", 488dd9ce3eSstsp "wrapper", 498dd9ce3eSstsp "block ack request", 508dd9ce3eSstsp "block ack", 518dd9ce3eSstsp "ps poll", 528dd9ce3eSstsp "rts", 538dd9ce3eSstsp "cts", 548dd9ce3eSstsp "ack", 558dd9ce3eSstsp "cf-end", 568dd9ce3eSstsp "cf-end-ack", 578dd9ce3eSstsp }; 588dd9ce3eSstsp 5912a08440Sreyk const char *ieee80211_mgt_subtype_name[] = { 6012a08440Sreyk "association request", 6112a08440Sreyk "association response", 6212a08440Sreyk "reassociation request", 6312a08440Sreyk "reassociation response", 6412a08440Sreyk "probe request", 6512a08440Sreyk "probe response", 6612a08440Sreyk "reserved#6", 6712a08440Sreyk "reserved#7", 6812a08440Sreyk "beacon", 6912a08440Sreyk "atim", 7012a08440Sreyk "disassociation", 7112a08440Sreyk "authentication", 7212a08440Sreyk "deauthentication", 73ab7e388eSclaudio "action", 74ab7e388eSclaudio "action noack", 7512a08440Sreyk "reserved#15" 7612a08440Sreyk }; 7712a08440Sreyk 78ab7e388eSclaudio const char *ieee80211_data_subtype_name[] = { 79ab7e388eSclaudio "data", 80ab7e388eSclaudio "data cf ack", 81ab7e388eSclaudio "data cf poll", 82ab7e388eSclaudio "data cf poll ack", 83ab7e388eSclaudio "no-data", 84ab7e388eSclaudio "no-data cf poll", 85ab7e388eSclaudio "no-data cf ack", 86ab7e388eSclaudio "no-data cf poll ack", 87ab7e388eSclaudio "QoS data", 88ab7e388eSclaudio "QoS data cf ack", 89ab7e388eSclaudio "QoS data cf poll", 90ab7e388eSclaudio "QoS data cf poll ack", 91ab7e388eSclaudio "QoS no-data", 92ab7e388eSclaudio "QoS no-data cf poll", 93ab7e388eSclaudio "QoS no-data cf ack", 94ab7e388eSclaudio "QoS no-data cf poll ack" 95ab7e388eSclaudio }; 96ab7e388eSclaudio 9712a08440Sreyk int ieee80211_hdr(struct ieee80211_frame *); 98b72abdefSreyk int ieee80211_data(struct ieee80211_frame *, u_int); 9912a08440Sreyk void ieee80211_print_element(u_int8_t *, u_int); 10012a08440Sreyk void ieee80211_print_essid(u_int8_t *, u_int); 10177734011Sstsp void ieee80211_print_country(u_int8_t *, u_int); 1021e3bf20aSstsp void ieee80211_print_htcaps(u_int8_t *, u_int); 10336fa064cSstsp void ieee80211_print_htop(u_int8_t *, u_int); 1046f9acb7aSstsp int ieee80211_print_beacon(struct ieee80211_frame *, u_int); 1056f9acb7aSstsp int ieee80211_print_assocreq(struct ieee80211_frame *, u_int); 1066f9acb7aSstsp int ieee80211_print_elements(uint8_t *); 10712a08440Sreyk int ieee80211_frame(struct ieee80211_frame *, u_int); 10812a08440Sreyk int ieee80211_print(struct ieee80211_frame *, u_int); 10912a08440Sreyk u_int ieee80211_any2ieee(u_int, u_int); 11018786664Sclaudio void ieee80211_reason(u_int16_t); 11112a08440Sreyk 11212a08440Sreyk #define TCARR(a) TCHECK2(*a, sizeof(a)) 11312a08440Sreyk 114c79cf170Sreyk int ieee80211_encap = 0; 115c79cf170Sreyk 11612a08440Sreyk int 11712a08440Sreyk ieee80211_hdr(struct ieee80211_frame *wh) 11812a08440Sreyk { 11912a08440Sreyk struct ieee80211_frame_addr4 *w4; 12012a08440Sreyk 12112a08440Sreyk switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 12212a08440Sreyk case IEEE80211_FC1_DIR_NODS: 12312a08440Sreyk TCARR(wh->i_addr2); 12412a08440Sreyk printf("%s", etheraddr_string(wh->i_addr2)); 12512a08440Sreyk TCARR(wh->i_addr1); 12612a08440Sreyk printf(" > %s", etheraddr_string(wh->i_addr1)); 12712a08440Sreyk TCARR(wh->i_addr3); 12812a08440Sreyk printf(", bssid %s", etheraddr_string(wh->i_addr3)); 12912a08440Sreyk break; 13012a08440Sreyk case IEEE80211_FC1_DIR_TODS: 13112a08440Sreyk TCARR(wh->i_addr2); 13212a08440Sreyk printf("%s", etheraddr_string(wh->i_addr2)); 13312a08440Sreyk TCARR(wh->i_addr3); 13412a08440Sreyk printf(" > %s", etheraddr_string(wh->i_addr3)); 13512a08440Sreyk TCARR(wh->i_addr1); 13612a08440Sreyk printf(", bssid %s, > DS", etheraddr_string(wh->i_addr1)); 13712a08440Sreyk break; 13812a08440Sreyk case IEEE80211_FC1_DIR_FROMDS: 13912a08440Sreyk TCARR(wh->i_addr3); 14012a08440Sreyk printf("%s", etheraddr_string(wh->i_addr3)); 14112a08440Sreyk TCARR(wh->i_addr1); 14212a08440Sreyk printf(" > %s", etheraddr_string(wh->i_addr1)); 14312a08440Sreyk TCARR(wh->i_addr2); 14412a08440Sreyk printf(", bssid %s, DS >", etheraddr_string(wh->i_addr2)); 14512a08440Sreyk break; 14612a08440Sreyk case IEEE80211_FC1_DIR_DSTODS: 14712a08440Sreyk w4 = (struct ieee80211_frame_addr4 *) wh; 14812a08440Sreyk TCARR(w4->i_addr4); 14912a08440Sreyk printf("%s", etheraddr_string(w4->i_addr4)); 15012a08440Sreyk TCARR(w4->i_addr3); 15112a08440Sreyk printf(" > %s", etheraddr_string(w4->i_addr3)); 15212a08440Sreyk TCARR(w4->i_addr2); 15312a08440Sreyk printf(", bssid %s", etheraddr_string(w4->i_addr2)); 15412a08440Sreyk TCARR(w4->i_addr1); 15512a08440Sreyk printf(" > %s, DS > DS", etheraddr_string(w4->i_addr1)); 15612a08440Sreyk break; 15712a08440Sreyk } 15812a08440Sreyk if (vflag) { 159cce1ba42Sclaudio u_int16_t seq; 16012a08440Sreyk TCARR(wh->i_seq); 161cce1ba42Sclaudio bcopy(wh->i_seq, &seq, sizeof(u_int16_t)); 162cce1ba42Sclaudio printf(" (seq %u): ", letoh16(seq)); 16312a08440Sreyk } else 16412a08440Sreyk printf(": "); 16512a08440Sreyk 16612a08440Sreyk return (0); 16712a08440Sreyk 16812a08440Sreyk trunc: 16912a08440Sreyk /* Truncated elements in frame */ 17012a08440Sreyk return (1); 17112a08440Sreyk } 17212a08440Sreyk 173b72abdefSreyk int 174b72abdefSreyk ieee80211_data(struct ieee80211_frame *wh, u_int len) 175b72abdefSreyk { 176b72abdefSreyk u_int8_t *t = (u_int8_t *)wh; 177b72abdefSreyk u_int datalen; 17893cbfc44Sstsp int data = !(wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_NODATA); 1799d5679eaSstsp int hasqos = ((wh->i_fc[0] & 1809d5679eaSstsp (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) == 1819d5679eaSstsp (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)); 182ab7e388eSclaudio u_char *esrc = NULL, *edst = NULL; 183b72abdefSreyk 1849d5679eaSstsp if (hasqos) { 1859d5679eaSstsp struct ieee80211_qosframe *wq; 1869d5679eaSstsp 1879d5679eaSstsp wq = (struct ieee80211_qosframe *) wh; 1889d5679eaSstsp TCHECK(*wq); 1899d5679eaSstsp t += sizeof(*wq); 1909d5679eaSstsp datalen = len - sizeof(*wq); 1919d5679eaSstsp } else { 192d49cb46eScanacar TCHECK(*wh); 1939d5679eaSstsp t += sizeof(*wh); 1949d5679eaSstsp datalen = len - sizeof(*wh); 1959d5679eaSstsp } 196b72abdefSreyk 197b72abdefSreyk switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 198b72abdefSreyk case IEEE80211_FC1_DIR_TODS: 199ab7e388eSclaudio esrc = wh->i_addr2; 200ab7e388eSclaudio edst = wh->i_addr3; 201b72abdefSreyk break; 202b72abdefSreyk case IEEE80211_FC1_DIR_FROMDS: 203ab7e388eSclaudio esrc = wh->i_addr3; 204ab7e388eSclaudio edst = wh->i_addr1; 205b72abdefSreyk break; 206b72abdefSreyk case IEEE80211_FC1_DIR_NODS: 207ab7e388eSclaudio esrc = wh->i_addr2; 208ab7e388eSclaudio edst = wh->i_addr1; 209d49cb46eScanacar break; 210b72abdefSreyk case IEEE80211_FC1_DIR_DSTODS: 2119d5679eaSstsp if (hasqos) { 2129d5679eaSstsp struct ieee80211_qosframe_addr4 *w4; 2139d5679eaSstsp 2149d5679eaSstsp w4 = (struct ieee80211_qosframe_addr4 *) wh; 2159d5679eaSstsp TCHECK(*w4); 2169d5679eaSstsp t = (u_int8_t *) (w4 + 1); 2179d5679eaSstsp datalen = len - sizeof(*w4); 2189d5679eaSstsp esrc = w4->i_addr4; 2199d5679eaSstsp edst = w4->i_addr3; 2209d5679eaSstsp } else { 2219d5679eaSstsp struct ieee80211_frame_addr4 *w4; 2229d5679eaSstsp 223d49cb46eScanacar w4 = (struct ieee80211_frame_addr4 *) wh; 224d49cb46eScanacar TCHECK(*w4); 225d49cb46eScanacar t = (u_int8_t *) (w4 + 1); 226d49cb46eScanacar datalen = len - sizeof(*w4); 227ab7e388eSclaudio esrc = w4->i_addr4; 228ab7e388eSclaudio edst = w4->i_addr3; 2299d5679eaSstsp } 230b72abdefSreyk break; 231b72abdefSreyk } 232b72abdefSreyk 233ab7e388eSclaudio if (data && esrc) 234ab7e388eSclaudio llc_print(t, datalen, datalen, esrc, edst); 235ab7e388eSclaudio else if (eflag && esrc) 236ab7e388eSclaudio printf("%s > %s", 237ab7e388eSclaudio etheraddr_string(esrc), etheraddr_string(edst)); 238ab7e388eSclaudio 239b72abdefSreyk return (0); 240b72abdefSreyk 241b72abdefSreyk trunc: 242b72abdefSreyk /* Truncated elements in frame */ 243b72abdefSreyk return (1); 244b72abdefSreyk } 245b72abdefSreyk 24612a08440Sreyk /* Caller checks len */ 24712a08440Sreyk void 24812a08440Sreyk ieee80211_print_element(u_int8_t *data, u_int len) 24912a08440Sreyk { 25012a08440Sreyk u_int8_t *p; 2519cbdb746Sderaadt int i; 25212a08440Sreyk 25312a08440Sreyk printf(" 0x"); 2549cbdb746Sderaadt for (i = 0, p = data; i < len; i++, p++) 25512a08440Sreyk printf("%02x", *p); 25612a08440Sreyk } 25712a08440Sreyk 25812a08440Sreyk /* Caller checks len */ 25912a08440Sreyk void 26012a08440Sreyk ieee80211_print_essid(u_int8_t *essid, u_int len) 26112a08440Sreyk { 26212a08440Sreyk u_int8_t *p; 2639cbdb746Sderaadt int i; 26412a08440Sreyk 26512a08440Sreyk if (len > IEEE80211_NWID_LEN) 26612a08440Sreyk len = IEEE80211_NWID_LEN; 26712a08440Sreyk 26812a08440Sreyk /* determine printable or not */ 26912a08440Sreyk for (i = 0, p = essid; i < len; i++, p++) { 27012a08440Sreyk if (*p < ' ' || *p > 0x7e) 27112a08440Sreyk break; 27212a08440Sreyk } 27312a08440Sreyk if (i == len) { 27412a08440Sreyk printf(" ("); 27512a08440Sreyk for (i = 0, p = essid; i < len; i++, p++) 27612a08440Sreyk putchar(*p); 27712a08440Sreyk putchar(')'); 2789cbdb746Sderaadt } else 27912a08440Sreyk ieee80211_print_element(essid, len); 28012a08440Sreyk } 28112a08440Sreyk 2821e3bf20aSstsp /* Caller checks len */ 2831e3bf20aSstsp void 28477734011Sstsp ieee80211_print_country(u_int8_t *data, u_int len) 28577734011Sstsp { 28677734011Sstsp u_int8_t first_chan, nchan, maxpower; 28777734011Sstsp 28877734011Sstsp if (len < 6) 28977734011Sstsp return; 29077734011Sstsp 29177734011Sstsp /* country string */ 29277734011Sstsp printf((isprint(data[0]) ? " '%c" : " '\\%03o"), data[0]); 29377734011Sstsp printf((isprint(data[1]) ? "%c" : "\\%03o"), data[1]); 29477734011Sstsp printf((isprint(data[2]) ? "%c'" : "\\%03o'"), data[2]); 29577734011Sstsp 29677734011Sstsp len -= 3; 29777734011Sstsp data += 3; 29877734011Sstsp 29977734011Sstsp /* channels and corresponding TX power limits */ 30075f33b99Sstsp while (len >= 3) { 30177734011Sstsp /* no pretty-printing for nonsensical zero values, 30277734011Sstsp * nor for operating extension IDs (values >= 201) */ 30377734011Sstsp if (data[0] == 0 || data[1] == 0 || 30477734011Sstsp data[0] >= 201 || data[1] >= 201) { 30577734011Sstsp printf(", %d %d %d", data[0], data[1], data[2]); 30675f33b99Sstsp len -= 3; 30775f33b99Sstsp data += 3; 30877734011Sstsp continue; 30977734011Sstsp } 31077734011Sstsp 31177734011Sstsp first_chan = data[0]; 31277734011Sstsp nchan = data[1]; 31377734011Sstsp maxpower = data[2]; 31477734011Sstsp 31577734011Sstsp printf(", channel%s %d", nchan == 1 ? "" : "s", first_chan); 31677734011Sstsp if (nchan > 1) 31777734011Sstsp printf("-%d", first_chan + nchan - 1); 31877734011Sstsp printf(" limit %ddB", maxpower); 31977734011Sstsp 32077734011Sstsp len -= 3; 32177734011Sstsp data += 3; 32277734011Sstsp } 32377734011Sstsp } 32477734011Sstsp 32577734011Sstsp /* Caller checks len */ 32677734011Sstsp void 3271e3bf20aSstsp ieee80211_print_htcaps(u_int8_t *data, u_int len) 3281e3bf20aSstsp { 329537e7cd0Sstsp uint16_t htcaps, rxrate; 3301e3bf20aSstsp int smps, rxstbc; 331537e7cd0Sstsp uint8_t ampdu, txmcs; 332537e7cd0Sstsp int i; 333537e7cd0Sstsp uint8_t *rxmcs; 3341e3bf20aSstsp 3351e3bf20aSstsp if (len < 2) { 3361e3bf20aSstsp ieee80211_print_element(data, len); 3371e3bf20aSstsp return; 3381e3bf20aSstsp } 3391e3bf20aSstsp 3401e3bf20aSstsp htcaps = (data[0]) | (data[1] << 8); 3411e3bf20aSstsp printf("=<"); 3421e3bf20aSstsp 3431e3bf20aSstsp /* channel width */ 3441e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_CBW20_40) 3451e3bf20aSstsp printf("20/40MHz"); 3461e3bf20aSstsp else 3471e3bf20aSstsp printf("20MHz"); 3481e3bf20aSstsp 3491e3bf20aSstsp /* LDPC coding */ 3501e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_LDPC) 3511e3bf20aSstsp printf(",LDPC"); 3521e3bf20aSstsp 3531e3bf20aSstsp /* spatial multiplexing power save mode */ 3541e3bf20aSstsp smps = (htcaps & IEEE80211_HTCAP_SMPS_MASK) 3551e3bf20aSstsp >> IEEE80211_HTCAP_SMPS_SHIFT; 3561e3bf20aSstsp if (smps == 0) 3571e3bf20aSstsp printf(",SMPS static"); 3581e3bf20aSstsp else if (smps == 1) 3591e3bf20aSstsp printf(",SMPS dynamic"); 3601e3bf20aSstsp 3611e3bf20aSstsp /* 11n greenfield mode */ 3621e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_GF) 3631e3bf20aSstsp printf(",greenfield"); 3641e3bf20aSstsp 3651e3bf20aSstsp /* short guard interval */ 3661e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_SGI20) 3671e3bf20aSstsp printf(",SGI@20MHz"); 3681e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_SGI40) 3691e3bf20aSstsp printf(",SGI@40MHz"); 3701e3bf20aSstsp 3711e3bf20aSstsp /* space-time block coding */ 3721e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_TXSTBC) 3731e3bf20aSstsp printf(",TXSTBC"); 3741e3bf20aSstsp rxstbc = (htcaps & IEEE80211_HTCAP_RXSTBC_MASK) 3751e3bf20aSstsp >> IEEE80211_HTCAP_RXSTBC_SHIFT; 3761e3bf20aSstsp if (rxstbc > 0 && rxstbc < 4) 3771e3bf20aSstsp printf(",RXSTBC %d stream", rxstbc); 3781e3bf20aSstsp 3791e3bf20aSstsp /* delayed block-ack */ 3801e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_DELAYEDBA) 3811e3bf20aSstsp printf(",delayed BA"); 3821e3bf20aSstsp 3831e3bf20aSstsp /* max A-MSDU length */ 3841e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_AMSDU7935) 3851e3bf20aSstsp printf(",A-MSDU 7935"); 3861e3bf20aSstsp else 3871e3bf20aSstsp printf(",A-MSDU 3839"); 3881e3bf20aSstsp 3891e3bf20aSstsp /* DSSS/CCK in 40MHz mode */ 3901e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_DSSSCCK40) 3911e3bf20aSstsp printf(",DSSS/CCK@40MHz"); 3921e3bf20aSstsp 3931e3bf20aSstsp /* 40MHz intolerant */ 3941e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_40INTOLERANT) 3951e3bf20aSstsp printf(",40MHz intolerant"); 3961e3bf20aSstsp 3971e3bf20aSstsp /* L-SIG TXOP protection */ 3981e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_LSIGTXOPPROT) 3991e3bf20aSstsp printf(",L-SIG TXOP prot"); 4001e3bf20aSstsp 401537e7cd0Sstsp if (len < 3) { 402537e7cd0Sstsp printf(">"); 403537e7cd0Sstsp return; 404537e7cd0Sstsp } 405537e7cd0Sstsp 406537e7cd0Sstsp /* A-MPDU parameters. */ 407537e7cd0Sstsp ampdu = data[2]; 408537e7cd0Sstsp 409537e7cd0Sstsp /* A-MPDU length exponent */ 410537e7cd0Sstsp if ((ampdu & IEEE80211_AMPDU_PARAM_LE) >= 0 && 411537e7cd0Sstsp (ampdu & IEEE80211_AMPDU_PARAM_LE) <= 3) 412537e7cd0Sstsp printf(",A-MPDU max %d", 4130b19ae84Sstsp (1 << (13 + (ampdu & IEEE80211_AMPDU_PARAM_LE))) - 1); 414537e7cd0Sstsp 415537e7cd0Sstsp /* A-MPDU start spacing */ 416537e7cd0Sstsp if (ampdu & IEEE80211_AMPDU_PARAM_SS) { 417537e7cd0Sstsp float ss; 418537e7cd0Sstsp 419537e7cd0Sstsp switch ((ampdu & IEEE80211_AMPDU_PARAM_SS) >> 2) { 420537e7cd0Sstsp case 1: 421537e7cd0Sstsp ss = 0.25; 422537e7cd0Sstsp break; 423537e7cd0Sstsp case 2: 424537e7cd0Sstsp ss = 0.5; 425537e7cd0Sstsp break; 426537e7cd0Sstsp case 3: 427537e7cd0Sstsp ss = 1; 428537e7cd0Sstsp break; 429537e7cd0Sstsp case 4: 430537e7cd0Sstsp ss = 2; 431537e7cd0Sstsp break; 432537e7cd0Sstsp case 5: 433537e7cd0Sstsp ss = 4; 434537e7cd0Sstsp break; 435537e7cd0Sstsp case 6: 436537e7cd0Sstsp ss = 8; 437537e7cd0Sstsp break; 438537e7cd0Sstsp case 7: 439537e7cd0Sstsp ss = 16; 440537e7cd0Sstsp break; 441537e7cd0Sstsp default: 442537e7cd0Sstsp ss = 0; 443537e7cd0Sstsp break; 444537e7cd0Sstsp } 445537e7cd0Sstsp if (ss != 0) 446537e7cd0Sstsp printf(",A-MPDU spacing %.2fus", ss); 447537e7cd0Sstsp } 448537e7cd0Sstsp 449537e7cd0Sstsp if (len < 21) { 450537e7cd0Sstsp printf(">"); 451537e7cd0Sstsp return; 452537e7cd0Sstsp } 453537e7cd0Sstsp 454537e7cd0Sstsp /* Supported MCS set. */ 455537e7cd0Sstsp printf(",RxMCS 0x"); 456537e7cd0Sstsp rxmcs = &data[3]; 457537e7cd0Sstsp for (i = 0; i < 10; i++) 458537e7cd0Sstsp printf("%02x", rxmcs[i]); 459537e7cd0Sstsp 460537e7cd0Sstsp /* Max MCS Rx rate (a value of 0 means "not specified"). */ 461537e7cd0Sstsp rxrate = ((data[13] | (data[14]) << 8) & IEEE80211_MCS_RX_RATE_HIGH); 462537e7cd0Sstsp if (rxrate) 463537e7cd0Sstsp printf(",RxMaxrate %huMb/s", rxrate); 464537e7cd0Sstsp 465537e7cd0Sstsp /* Tx MCS Set */ 466537e7cd0Sstsp txmcs = data[15]; 467537e7cd0Sstsp if (txmcs & IEEE80211_TX_MCS_SET_DEFINED) { 468537e7cd0Sstsp if (txmcs & IEEE80211_TX_RX_MCS_NOT_EQUAL) { 469537e7cd0Sstsp /* Number of spatial Tx streams. */ 470537e7cd0Sstsp printf(",%d Tx streams", 471537e7cd0Sstsp 1 + ((txmcs & IEEE80211_TX_SPATIAL_STREAMS) >> 2)); 472537e7cd0Sstsp /* Transmit unequal modulation supported. */ 473537e7cd0Sstsp if (txmcs & IEEE80211_TX_UNEQUAL_MODULATION) 474537e7cd0Sstsp printf(",UEQM"); 475537e7cd0Sstsp } 476537e7cd0Sstsp } 477537e7cd0Sstsp 4781e3bf20aSstsp printf(">"); 4791e3bf20aSstsp } 4801e3bf20aSstsp 48136fa064cSstsp /* Caller checks len */ 48236fa064cSstsp void 48336fa064cSstsp ieee80211_print_htop(u_int8_t *data, u_int len) 48436fa064cSstsp { 48536fa064cSstsp u_int8_t primary_chan; 48636fa064cSstsp u_int8_t htopinfo[5]; 48736fa064cSstsp u_int8_t basic_mcs[16]; 48836fa064cSstsp int sco, prot, i; 48936fa064cSstsp 49036fa064cSstsp if (len < sizeof(primary_chan) + sizeof(htopinfo) + sizeof(basic_mcs)) { 49136fa064cSstsp ieee80211_print_element(data, len); 49236fa064cSstsp return; 49336fa064cSstsp } 49436fa064cSstsp 49536fa064cSstsp htopinfo[0] = data[1]; 49636fa064cSstsp 49736fa064cSstsp printf("=<"); 49836fa064cSstsp 49936fa064cSstsp /* primary channel and secondary channel offset */ 50036fa064cSstsp primary_chan = data[0]; 50136fa064cSstsp sco = ((htopinfo[0] & IEEE80211_HTOP0_SCO_MASK) 50236fa064cSstsp >> IEEE80211_HTOP0_SCO_SHIFT); 503b144e175Sstsp if (sco == 0) /* no secondary channel */ 50436fa064cSstsp printf("20MHz chan %d", primary_chan); 505b144e175Sstsp else if (sco == 1) { /* secondary channel above */ 506b144e175Sstsp if (primary_chan >= 1 && primary_chan <= 13) /* 2GHz */ 507b144e175Sstsp printf("40MHz chan %d:%d", primary_chan, 508b144e175Sstsp primary_chan + 1); 509b144e175Sstsp else if (primary_chan >= 34) /* 5GHz */ 510b144e175Sstsp printf("40MHz chan %d:%d", primary_chan, 511b144e175Sstsp primary_chan + 4); 51236fa064cSstsp else 513b144e175Sstsp printf("[invalid 40MHz chan %d+]", primary_chan); 514b144e175Sstsp } else if (sco == 3) { /* secondary channel below */ 515b144e175Sstsp if (primary_chan >= 2 && primary_chan <= 14) /* 2GHz */ 516b144e175Sstsp printf("40MHz chan %d:%d", primary_chan, 517b144e175Sstsp primary_chan - 1); 518b144e175Sstsp else if (primary_chan >= 40) /* 5GHz */ 519b144e175Sstsp printf("40MHz chan %d:%d", primary_chan, 520b144e175Sstsp primary_chan - 4); 521b144e175Sstsp else 522b144e175Sstsp printf("[invalid 40MHz chan %d-]", primary_chan); 523b144e175Sstsp } else 52436fa064cSstsp printf("chan %d [invalid secondary channel offset %d]", 52536fa064cSstsp primary_chan, sco); 52636fa064cSstsp 52736fa064cSstsp /* STA channel width */ 52836fa064cSstsp if ((htopinfo[0] & IEEE80211_HTOP0_CHW) == 0) 52936fa064cSstsp printf(",STA chanw 20MHz"); 53036fa064cSstsp 53136fa064cSstsp /* reduced interframe space (RIFS) permitted */ 53236fa064cSstsp if (htopinfo[0] & IEEE80211_HTOP0_RIFS) 53336fa064cSstsp printf(",RIFS"); 53436fa064cSstsp 53536fa064cSstsp htopinfo[1] = data[2]; 53636fa064cSstsp 53736fa064cSstsp /* protection requirements for HT transmissions */ 53836fa064cSstsp prot = ((htopinfo[1] & IEEE80211_HTOP1_PROT_MASK) 53936fa064cSstsp >> IEEE80211_HTOP1_PROT_SHIFT); 54036fa064cSstsp if (prot == 1) 54136fa064cSstsp printf(",protect non-member"); 54236fa064cSstsp else if (prot == 2) 54336fa064cSstsp printf(",protect 20MHz"); 54436fa064cSstsp else if (prot == 3) 54536fa064cSstsp printf(",protect non-HT"); 54636fa064cSstsp 54736fa064cSstsp /* non-greenfield STA present */ 54836fa064cSstsp if (htopinfo[1] & IEEE80211_HTOP1_NONGF_STA) 54936fa064cSstsp printf(",non-greenfield STA"); 55036fa064cSstsp 55136fa064cSstsp /* non-HT STA present */ 55236fa064cSstsp if (htopinfo[1] & IEEE80211_HTOP1_OBSS_NONHT_STA) 55336fa064cSstsp printf(",non-HT STA"); 55436fa064cSstsp 55536fa064cSstsp htopinfo[3] = data[4]; 55636fa064cSstsp 55736fa064cSstsp /* dual-beacon */ 55836fa064cSstsp if (htopinfo[3] & IEEE80211_HTOP2_DUALBEACON) 55936fa064cSstsp printf(",dualbeacon"); 56036fa064cSstsp 56136fa064cSstsp /* dual CTS protection */ 56236fa064cSstsp if (htopinfo[3] & IEEE80211_HTOP2_DUALCTSPROT) 56336fa064cSstsp printf(",dualctsprot"); 56436fa064cSstsp 56536fa064cSstsp htopinfo[4] = data[5]; 56636fa064cSstsp 56736fa064cSstsp /* space-time block coding (STBC) beacon */ 56858089030Sstsp if ((htopinfo[4] << 8) & IEEE80211_HTOP2_STBCBEACON) 56936fa064cSstsp printf(",STBC beacon"); 57036fa064cSstsp 57136fa064cSstsp /* L-SIG (non-HT signal field) TX opportunity (TXOP) protection */ 57236fa064cSstsp if ((htopinfo[4] << 8) & IEEE80211_HTOP2_LSIGTXOP) 57336fa064cSstsp printf(",lsigtxprot"); 57436fa064cSstsp 57536fa064cSstsp /* phased-coexistence operation (PCO) active */ 57636fa064cSstsp if ((htopinfo[4] << 8) & IEEE80211_HTOP2_PCOACTIVE) { 57736fa064cSstsp /* PCO phase */ 57836fa064cSstsp if ((htopinfo[4] << 8) & IEEE80211_HTOP2_PCOPHASE40) 57936fa064cSstsp printf(",pco40MHz"); 58036fa064cSstsp else 58136fa064cSstsp printf(",pco20MHz"); 58236fa064cSstsp } 58336fa064cSstsp 58436fa064cSstsp /* basic MCS set */ 58536fa064cSstsp memcpy(basic_mcs, &data[6], sizeof(basic_mcs)); 58636fa064cSstsp printf(",basic MCS set 0x"); 58736fa064cSstsp for (i = 0; i < sizeof(basic_mcs) / sizeof(basic_mcs[0]); i++) 58836fa064cSstsp printf("%x", basic_mcs[i]); 58936fa064cSstsp 59036fa064cSstsp printf(">"); 59136fa064cSstsp } 59236fa064cSstsp 59312a08440Sreyk int 5946f9acb7aSstsp ieee80211_print_beacon(struct ieee80211_frame *wh, u_int len) 59512a08440Sreyk { 5966f9acb7aSstsp uint64_t tstamp; 5976f9acb7aSstsp uint16_t bintval, capinfo; 5986f9acb7aSstsp uint8_t *frm; 59912a08440Sreyk 6006f9acb7aSstsp if (len < sizeof(tstamp) + sizeof(bintval) + sizeof(capinfo)) 6016f9acb7aSstsp return 1; /* truncated */ 6026f9acb7aSstsp 60312a08440Sreyk frm = (u_int8_t *)&wh[1]; 60412a08440Sreyk 605cce1ba42Sclaudio bcopy(frm, &tstamp, sizeof(u_int64_t)); 60612a08440Sreyk frm += 8; 60712a08440Sreyk if (vflag > 1) 608cce1ba42Sclaudio printf(", timestamp %llu", letoh64(tstamp)); 60912a08440Sreyk 610cce1ba42Sclaudio bcopy(frm, &bintval, sizeof(u_int16_t)); 61112a08440Sreyk frm += 2; 61212a08440Sreyk if (vflag > 1) 613cce1ba42Sclaudio printf(", interval %u", letoh16(bintval)); 61412a08440Sreyk 615cce1ba42Sclaudio bcopy(frm, &capinfo, sizeof(u_int16_t)); 61612a08440Sreyk frm += 2; 61712a08440Sreyk if (vflag) 6186f9acb7aSstsp printb(", caps", letoh16(capinfo), IEEE80211_CAPINFO_BITS); 6196f9acb7aSstsp 6206f9acb7aSstsp return ieee80211_print_elements(frm); 6216f9acb7aSstsp } 6226f9acb7aSstsp 6236f9acb7aSstsp int 6246f9acb7aSstsp ieee80211_print_assocreq(struct ieee80211_frame *wh, u_int len) 6256f9acb7aSstsp { 6266f9acb7aSstsp uint8_t subtype; 6276f9acb7aSstsp uint16_t capinfo, lintval; 6286f9acb7aSstsp uint8_t *frm; 6296f9acb7aSstsp 6306f9acb7aSstsp subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 6316f9acb7aSstsp 6326f9acb7aSstsp if (len < sizeof(capinfo) + sizeof(lintval) + 6336f9acb7aSstsp (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ ? 6346f9acb7aSstsp IEEE80211_ADDR_LEN : 0)) 6356f9acb7aSstsp return 1; /* truncated */ 6366f9acb7aSstsp 6376f9acb7aSstsp frm = (u_int8_t *)&wh[1]; 6386f9acb7aSstsp 6396f9acb7aSstsp bcopy(frm, &capinfo, sizeof(u_int16_t)); 6406f9acb7aSstsp frm += 2; 6416f9acb7aSstsp if (vflag) 6426f9acb7aSstsp printb(", caps", letoh16(capinfo), IEEE80211_CAPINFO_BITS); 6436f9acb7aSstsp 6446f9acb7aSstsp bcopy(frm, &lintval, sizeof(u_int16_t)); 6456f9acb7aSstsp frm += 2; 6466f9acb7aSstsp if (vflag > 1) 6476f9acb7aSstsp printf(", listen interval %u", letoh16(lintval)); 6486f9acb7aSstsp 6496f9acb7aSstsp if (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { 6506f9acb7aSstsp if (vflag) 6516f9acb7aSstsp printf(", AP %s", etheraddr_string(frm)); 6526f9acb7aSstsp frm += IEEE80211_ADDR_LEN; 6536f9acb7aSstsp } 6546f9acb7aSstsp 6556f9acb7aSstsp return ieee80211_print_elements(frm); 6566f9acb7aSstsp } 6576f9acb7aSstsp 6586f9acb7aSstsp int 6596f9acb7aSstsp ieee80211_print_elements(uint8_t *frm) 6606f9acb7aSstsp { 6616f9acb7aSstsp int i; 66212a08440Sreyk 66312a08440Sreyk while (TTEST2(*frm, 2)) { 66412a08440Sreyk u_int len = frm[1]; 66512a08440Sreyk u_int8_t *data = frm + 2; 66612a08440Sreyk 66712a08440Sreyk if (!TTEST2(*data, len)) 66812a08440Sreyk break; 66912a08440Sreyk 6706f9acb7aSstsp #define ELEM_CHECK(l) if (len != l) goto trunc 67112a08440Sreyk 67212a08440Sreyk switch (*frm) { 67312a08440Sreyk case IEEE80211_ELEMID_SSID: 67412a08440Sreyk printf(", ssid"); 67512a08440Sreyk ieee80211_print_essid(data, len); 67612a08440Sreyk break; 67712a08440Sreyk case IEEE80211_ELEMID_RATES: 67812a08440Sreyk printf(", rates"); 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; 68512a08440Sreyk case IEEE80211_ELEMID_FHPARMS: 68612a08440Sreyk ELEM_CHECK(5); 68712a08440Sreyk printf(", fh (dwell %u, chan %u, index %u)", 68812a08440Sreyk (data[1] << 8) | data[0], 68912a08440Sreyk (data[2] - 1) * 80 + data[3], /* FH_CHAN */ 69012a08440Sreyk data[4]); 69112a08440Sreyk break; 69212a08440Sreyk case IEEE80211_ELEMID_DSPARMS: 69312a08440Sreyk ELEM_CHECK(1); 69412a08440Sreyk printf(", ds"); 69512a08440Sreyk if (vflag) 69612a08440Sreyk printf(" (chan %u)", data[0]); 69712a08440Sreyk break; 69812a08440Sreyk case IEEE80211_ELEMID_CFPARMS: 69912a08440Sreyk printf(", cf"); 70012a08440Sreyk if (vflag) 70112a08440Sreyk ieee80211_print_element(data, len); 70212a08440Sreyk break; 70312a08440Sreyk case IEEE80211_ELEMID_TIM: 70412a08440Sreyk printf(", tim"); 70512a08440Sreyk if (vflag) 70612a08440Sreyk ieee80211_print_element(data, len); 70712a08440Sreyk break; 70812a08440Sreyk case IEEE80211_ELEMID_IBSSPARMS: 70912a08440Sreyk printf(", ibss"); 71012a08440Sreyk if (vflag) 71112a08440Sreyk ieee80211_print_element(data, len); 71212a08440Sreyk break; 71312a08440Sreyk case IEEE80211_ELEMID_COUNTRY: 71412a08440Sreyk printf(", country"); 7157ccd2116Sstsp if (vflag) 71677734011Sstsp ieee80211_print_country(data, len); 71712a08440Sreyk break; 71812a08440Sreyk case IEEE80211_ELEMID_CHALLENGE: 71912a08440Sreyk printf(", challenge"); 72012a08440Sreyk if (vflag) 72112a08440Sreyk ieee80211_print_element(data, len); 72212a08440Sreyk break; 723738acb58Ssthen case IEEE80211_ELEMID_CSA: 724958b7e45Ssthen ELEM_CHECK(3); 725738acb58Ssthen printf(", csa (chan %u count %u%s)", data[1], data[2], 726738acb58Ssthen (data[0] == 1) ? " noTX" : ""); 727738acb58Ssthen break; 72812a08440Sreyk case IEEE80211_ELEMID_ERP: 72912a08440Sreyk printf(", erp"); 73012a08440Sreyk if (vflag) 73112a08440Sreyk ieee80211_print_element(data, len); 73212a08440Sreyk break; 73312a08440Sreyk case IEEE80211_ELEMID_RSN: 73412a08440Sreyk printf(", rsn"); 73512a08440Sreyk if (vflag) 73612a08440Sreyk ieee80211_print_element(data, len); 73712a08440Sreyk break; 73812a08440Sreyk case IEEE80211_ELEMID_XRATES: 73912a08440Sreyk printf(", xrates"); 74012a08440Sreyk if (!vflag) 74112a08440Sreyk break; 74212a08440Sreyk for (i = len; i > 0; i--, data++) 74312a08440Sreyk printf(" %uM", 74412a08440Sreyk (data[0] & IEEE80211_RATE_VAL) / 2); 74512a08440Sreyk break; 7468138faddSstsp case IEEE80211_ELEMID_TPC_REPORT: 7478138faddSstsp printf(", tpcreport"); 74812a08440Sreyk if (vflag) 74912a08440Sreyk ieee80211_print_element(data, len); 75012a08440Sreyk break; 7518138faddSstsp case IEEE80211_ELEMID_TPC_REQUEST: 7528138faddSstsp printf(", tpcrequest"); 75312a08440Sreyk if (vflag) 75412a08440Sreyk ieee80211_print_element(data, len); 75512a08440Sreyk break; 7561e3bf20aSstsp case IEEE80211_ELEMID_HTCAPS: 7571e3bf20aSstsp printf(", htcaps"); 7581e3bf20aSstsp if (vflag) 7591e3bf20aSstsp ieee80211_print_htcaps(data, len); 7601e3bf20aSstsp break; 76136fa064cSstsp case IEEE80211_ELEMID_HTOP: 76236fa064cSstsp printf(", htop"); 76336fa064cSstsp if (vflag) 76436fa064cSstsp ieee80211_print_htop(data, len); 76536fa064cSstsp break; 76677734011Sstsp case IEEE80211_ELEMID_POWER_CONSTRAINT: 76777734011Sstsp ELEM_CHECK(1); 76877734011Sstsp printf(", power constraint %udB", data[0]); 76977734011Sstsp break; 7708f0a8537Sstsp case IEEE80211_ELEMID_QBSS_LOAD: 7718f0a8537Sstsp ELEM_CHECK(5); 7728f0a8537Sstsp printf(", %u stations, %d%% utilization, " 7738f0a8537Sstsp "admission capacity %uus/s", 7748f0a8537Sstsp (data[0] | data[1] << 8), 7758f0a8537Sstsp (data[2] * 100) / 255, 7768f0a8537Sstsp (data[3] | data[4] << 8) / 32); 7778f0a8537Sstsp break; 77812a08440Sreyk case IEEE80211_ELEMID_VENDOR: 77912a08440Sreyk printf(", vendor"); 78012a08440Sreyk if (vflag) 78112a08440Sreyk ieee80211_print_element(data, len); 78212a08440Sreyk break; 78312a08440Sreyk default: 78412a08440Sreyk printf(", %u:%u", (u_int) *frm, len); 78512a08440Sreyk if (vflag) 78612a08440Sreyk ieee80211_print_element(data, len); 78712a08440Sreyk break; 78812a08440Sreyk } 78912a08440Sreyk frm += len + 2; 79012a08440Sreyk 79112a08440Sreyk if (frm >= snapend) 79212a08440Sreyk break; 79312a08440Sreyk } 79412a08440Sreyk 79512a08440Sreyk #undef ELEM_CHECK 79612a08440Sreyk 79712a08440Sreyk return (0); 79812a08440Sreyk 79912a08440Sreyk trunc: 80012a08440Sreyk /* Truncated elements in frame */ 80112a08440Sreyk return (1); 80212a08440Sreyk } 80312a08440Sreyk 80412a08440Sreyk int 80512a08440Sreyk ieee80211_frame(struct ieee80211_frame *wh, u_int len) 80612a08440Sreyk { 80712a08440Sreyk u_int8_t subtype, type, *frm; 80812a08440Sreyk 80912a08440Sreyk TCARR(wh->i_fc); 81012a08440Sreyk 81112a08440Sreyk type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 81212a08440Sreyk subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 81312a08440Sreyk 81412a08440Sreyk frm = (u_int8_t *)&wh[1]; 81512a08440Sreyk 816ab7e388eSclaudio if (vflag) 817ab7e388eSclaudio printb(" flags", wh->i_fc[1], IEEE80211_FC1_BITS); 818ab7e388eSclaudio 81912a08440Sreyk switch (type) { 82012a08440Sreyk case IEEE80211_FC0_TYPE_DATA: 821ab7e388eSclaudio printf(": %s: ", ieee80211_data_subtype_name[ 822ab7e388eSclaudio subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]); 823b72abdefSreyk ieee80211_data(wh, len); 82412a08440Sreyk break; 82512a08440Sreyk case IEEE80211_FC0_TYPE_MGT: 82612a08440Sreyk printf(": %s", ieee80211_mgt_subtype_name[ 82712a08440Sreyk subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]); 82812a08440Sreyk switch (subtype) { 82912a08440Sreyk case IEEE80211_FC0_SUBTYPE_BEACON: 83012a08440Sreyk case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 8316f9acb7aSstsp if (ieee80211_print_beacon(wh, len) != 0) 8326f9acb7aSstsp goto trunc; 8336f9acb7aSstsp break; 8346f9acb7aSstsp case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: 8356f9acb7aSstsp case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: 8366f9acb7aSstsp if (ieee80211_print_assocreq(wh, len) != 0) 83712a08440Sreyk goto trunc; 83812a08440Sreyk break; 83912a08440Sreyk case IEEE80211_FC0_SUBTYPE_AUTH: 84012a08440Sreyk TCHECK2(*frm, 2); /* Auth Algorithm */ 84112a08440Sreyk switch (IEEE80211_AUTH_ALGORITHM(frm)) { 84212a08440Sreyk case IEEE80211_AUTH_ALG_OPEN: 84312a08440Sreyk TCHECK2(*frm, 4); /* Auth Transaction */ 84412a08440Sreyk switch (IEEE80211_AUTH_TRANSACTION(frm)) { 84512a08440Sreyk case IEEE80211_AUTH_OPEN_REQUEST: 84612a08440Sreyk printf(" request"); 84712a08440Sreyk break; 84812a08440Sreyk case IEEE80211_AUTH_OPEN_RESPONSE: 84912a08440Sreyk printf(" response"); 85012a08440Sreyk break; 85112a08440Sreyk } 85212a08440Sreyk break; 85312a08440Sreyk case IEEE80211_AUTH_ALG_SHARED: 85412a08440Sreyk TCHECK2(*frm, 4); /* Auth Transaction */ 85512a08440Sreyk switch (IEEE80211_AUTH_TRANSACTION(frm)) { 85612a08440Sreyk case IEEE80211_AUTH_SHARED_REQUEST: 85712a08440Sreyk printf(" request"); 85812a08440Sreyk break; 85912a08440Sreyk case IEEE80211_AUTH_SHARED_CHALLENGE: 86012a08440Sreyk printf(" challenge"); 86112a08440Sreyk break; 86212a08440Sreyk case IEEE80211_AUTH_SHARED_RESPONSE: 86312a08440Sreyk printf(" response"); 86412a08440Sreyk break; 86512a08440Sreyk case IEEE80211_AUTH_SHARED_PASS: 86612a08440Sreyk printf(" pass"); 86712a08440Sreyk break; 86812a08440Sreyk } 86912a08440Sreyk break; 87012a08440Sreyk case IEEE80211_AUTH_ALG_LEAP: 87112a08440Sreyk printf(" (leap)"); 87212a08440Sreyk break; 87312a08440Sreyk } 87412a08440Sreyk break; 87518786664Sclaudio case IEEE80211_FC0_SUBTYPE_DEAUTH: 87618786664Sclaudio case IEEE80211_FC0_SUBTYPE_DISASSOC: 87718786664Sclaudio TCHECK2(*frm, 2); /* Reason Code */ 87818786664Sclaudio ieee80211_reason(frm[0] | (frm[1] << 8)); 87918786664Sclaudio break; 88012a08440Sreyk } 88112a08440Sreyk break; 8828dd9ce3eSstsp case IEEE80211_FC0_TYPE_CTL: { 8838dd9ce3eSstsp u_int8_t *t = (u_int8_t *) wh; 8848dd9ce3eSstsp 8858dd9ce3eSstsp printf(": %s", ieee80211_ctl_subtype_name[ 8868dd9ce3eSstsp subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]); 8878dd9ce3eSstsp if (!vflag) 8888dd9ce3eSstsp break; 8898dd9ce3eSstsp 8908dd9ce3eSstsp /* See 802.11 2012 "8.3.1 Control frames". */ 8918dd9ce3eSstsp t += 2; /* skip Frame Control */ 8928dd9ce3eSstsp switch (subtype) { 8938dd9ce3eSstsp case IEEE80211_FC0_SUBTYPE_RTS: 8948dd9ce3eSstsp case IEEE80211_FC0_SUBTYPE_BAR: 8958dd9ce3eSstsp case IEEE80211_FC0_SUBTYPE_BA: 8968dd9ce3eSstsp TCHECK2(*t, 2); /* Duration */ 8978dd9ce3eSstsp printf(", duration %dms", (t[0] | t[1] << 8)); 8988dd9ce3eSstsp t += 2; 8998dd9ce3eSstsp TCHECK2(*t, 6); /* RA */ 9008dd9ce3eSstsp printf(", ra %s", etheraddr_string(t)); 9018dd9ce3eSstsp t += 6; 9028dd9ce3eSstsp TCHECK2(*t, 6); /* TA */ 9038dd9ce3eSstsp printf(", ta %s", etheraddr_string(t)); 9048dd9ce3eSstsp if (subtype == IEEE80211_FC0_SUBTYPE_BAR || 9058dd9ce3eSstsp subtype == IEEE80211_FC0_SUBTYPE_BA) { 9068dd9ce3eSstsp u_int16_t ctrl; 9078dd9ce3eSstsp 9088dd9ce3eSstsp t += 6; 9098dd9ce3eSstsp TCHECK2(*t, 2); /* BAR/BA control */ 9108dd9ce3eSstsp ctrl = t[0] | (t[1] << 8); 9118dd9ce3eSstsp if (ctrl & IEEE80211_BA_ACK_POLICY) 9128dd9ce3eSstsp printf(", no ack"); 9138dd9ce3eSstsp else 9148dd9ce3eSstsp printf(", normal ack"); 9158dd9ce3eSstsp if ((ctrl & IEEE80211_BA_MULTI_TID) == 0 && 9168dd9ce3eSstsp (ctrl & IEEE80211_BA_COMPRESSED) == 0) 9178dd9ce3eSstsp printf(", basic variant"); 9188dd9ce3eSstsp else if ((ctrl & IEEE80211_BA_MULTI_TID) && 9198dd9ce3eSstsp (ctrl & IEEE80211_BA_COMPRESSED)) 9208dd9ce3eSstsp printf(", multi-tid variant"); 9218dd9ce3eSstsp else if (ctrl & IEEE80211_BA_COMPRESSED) 9228dd9ce3eSstsp printf(", compressed variant"); 9238dd9ce3eSstsp } 9248dd9ce3eSstsp break; 9258dd9ce3eSstsp case IEEE80211_FC0_SUBTYPE_CTS: 9268dd9ce3eSstsp case IEEE80211_FC0_SUBTYPE_ACK: 9278dd9ce3eSstsp TCHECK2(*t, 2); /* Duration */ 9288dd9ce3eSstsp printf(", duration %dms", (t[0] | t[1] << 8)); 9298dd9ce3eSstsp t += 2; 9308dd9ce3eSstsp TCHECK2(*t, 6); /* RA */ 9318dd9ce3eSstsp printf(", ra %s", etheraddr_string(t)); 9328dd9ce3eSstsp break; 9338dd9ce3eSstsp case IEEE80211_FC0_SUBTYPE_PS_POLL: 9348dd9ce3eSstsp TCHECK2(*t, 2); /* AID */ 9358dd9ce3eSstsp printf(", aid 0x%x", (t[0] | t[1] << 8)); 9368dd9ce3eSstsp t += 2; 9378dd9ce3eSstsp TCHECK2(*t, 6); /* BSSID(RA) */ 9388dd9ce3eSstsp printf(", ra %s", etheraddr_string(t)); 9398dd9ce3eSstsp t += 6; 9408dd9ce3eSstsp TCHECK2(*t, 6); /* TA */ 9418dd9ce3eSstsp printf(", ta %s", etheraddr_string(t)); 9428dd9ce3eSstsp break; 9438dd9ce3eSstsp } 9448dd9ce3eSstsp break; 9458dd9ce3eSstsp } 94612a08440Sreyk default: 94712a08440Sreyk printf(": type#%d", type); 94812a08440Sreyk break; 94912a08440Sreyk } 95012a08440Sreyk 95112a08440Sreyk return (0); 95212a08440Sreyk 95312a08440Sreyk trunc: 95412a08440Sreyk /* Truncated 802.11 frame */ 95512a08440Sreyk return (1); 95612a08440Sreyk } 95712a08440Sreyk 95812a08440Sreyk u_int 95912a08440Sreyk ieee80211_any2ieee(u_int freq, u_int flags) 96012a08440Sreyk { 96112a08440Sreyk if (flags & IEEE80211_CHAN_2GHZ) { 96212a08440Sreyk if (freq == 2484) 96312a08440Sreyk return 14; 96412a08440Sreyk if (freq < 2484) 96512a08440Sreyk return (freq - 2407) / 5; 96612a08440Sreyk else 96712a08440Sreyk return 15 + ((freq - 2512) / 20); 96812a08440Sreyk } else if (flags & IEEE80211_CHAN_5GHZ) { 96912a08440Sreyk return (freq - 5000) / 5; 97012a08440Sreyk } else { 97112a08440Sreyk /* Assume channel is already an IEEE number */ 97212a08440Sreyk return (freq); 97312a08440Sreyk } 97412a08440Sreyk } 97512a08440Sreyk 97612a08440Sreyk int 97712a08440Sreyk ieee80211_print(struct ieee80211_frame *wh, u_int len) 97812a08440Sreyk { 97912a08440Sreyk if (eflag) 98012a08440Sreyk if (ieee80211_hdr(wh)) 98112a08440Sreyk return (1); 98212a08440Sreyk 98312a08440Sreyk printf("802.11"); 98412a08440Sreyk 98512a08440Sreyk return (ieee80211_frame(wh, len)); 98612a08440Sreyk } 98712a08440Sreyk 98812a08440Sreyk void 98912a08440Sreyk ieee802_11_if_print(u_char *user, const struct pcap_pkthdr *h, 99012a08440Sreyk const u_char *p) 99112a08440Sreyk { 99212a08440Sreyk struct ieee80211_frame *wh = (struct ieee80211_frame*)p; 99312a08440Sreyk 994c79cf170Sreyk if (!ieee80211_encap) 99512a08440Sreyk ts_print(&h->ts); 99612a08440Sreyk 99712a08440Sreyk packetp = p; 99812a08440Sreyk snapend = p + h->caplen; 99912a08440Sreyk 1000a0774ae9Smglocker if (ieee80211_print(wh, (u_int)h->len) != 0) 100112a08440Sreyk printf("[|802.11]"); 100212a08440Sreyk 1003c79cf170Sreyk if (!ieee80211_encap) { 100412a08440Sreyk if (xflag) 1005a0774ae9Smglocker default_print(p, (u_int)h->len); 100612a08440Sreyk putchar('\n'); 100712a08440Sreyk } 1008c79cf170Sreyk } 100912a08440Sreyk 101012a08440Sreyk void 101112a08440Sreyk ieee802_11_radio_if_print(u_char *user, const struct pcap_pkthdr *h, 101212a08440Sreyk const u_char *p) 101312a08440Sreyk { 101412a08440Sreyk struct ieee80211_radiotap_header *rh = 101512a08440Sreyk (struct ieee80211_radiotap_header*)p; 101612a08440Sreyk struct ieee80211_frame *wh; 101712a08440Sreyk u_int8_t *t; 101812a08440Sreyk u_int32_t present; 101912a08440Sreyk u_int len, rh_len; 1020cce1ba42Sclaudio u_int16_t tmp; 102112a08440Sreyk 1022c79cf170Sreyk if (!ieee80211_encap) 102312a08440Sreyk ts_print(&h->ts); 102412a08440Sreyk 102512a08440Sreyk packetp = p; 102612a08440Sreyk snapend = p + h->caplen; 102712a08440Sreyk 102812a08440Sreyk TCHECK(*rh); 102912a08440Sreyk 1030a0774ae9Smglocker len = h->len; 103112a08440Sreyk rh_len = letoh16(rh->it_len); 103212a08440Sreyk if (rh->it_version != 0) { 1033c79cf170Sreyk printf("[?radiotap + 802.11 v:%u]", rh->it_version); 103412a08440Sreyk goto out; 103512a08440Sreyk } 103612a08440Sreyk 103712a08440Sreyk wh = (struct ieee80211_frame *)(p + rh_len); 103812a08440Sreyk if (len <= rh_len || ieee80211_print(wh, len - rh_len)) 103912a08440Sreyk printf("[|802.11]"); 104012a08440Sreyk 104112a08440Sreyk t = (u_int8_t*)p + sizeof(struct ieee80211_radiotap_header); 104212a08440Sreyk 104312a08440Sreyk if ((present = letoh32(rh->it_present)) == 0) 104412a08440Sreyk goto out; 104512a08440Sreyk 104612a08440Sreyk printf(", <radiotap v%u", rh->it_version); 104712a08440Sreyk 104812a08440Sreyk #define RADIOTAP(_x) \ 104912a08440Sreyk (present & (1 << IEEE80211_RADIOTAP_##_x)) 105012a08440Sreyk 105112a08440Sreyk if (RADIOTAP(TSFT)) { 1052cce1ba42Sclaudio u_int64_t tsf; 1053cce1ba42Sclaudio 105412a08440Sreyk TCHECK2(*t, 8); 1055cce1ba42Sclaudio bcopy(t, &tsf, sizeof(u_int64_t)); 105612a08440Sreyk if (vflag > 1) 1057cce1ba42Sclaudio printf(", tsf %llu", letoh64(tsf)); 105812a08440Sreyk t += 8; 105912a08440Sreyk } 106012a08440Sreyk 106112a08440Sreyk if (RADIOTAP(FLAGS)) { 106212a08440Sreyk u_int8_t flags = *(u_int8_t*)t; 1063026ca542Sderaadt TCHECK2(*t, 1); 1064026ca542Sderaadt 106512a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_CFP) 106612a08440Sreyk printf(", CFP"); 106712a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_SHORTPRE) 106812a08440Sreyk printf(", SHORTPRE"); 106912a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_WEP) 107012a08440Sreyk printf(", WEP"); 107112a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_FRAG) 107212a08440Sreyk printf(", FRAG"); 107312a08440Sreyk t += 1; 107412a08440Sreyk } 107512a08440Sreyk 107612a08440Sreyk if (RADIOTAP(RATE)) { 107712a08440Sreyk TCHECK2(*t, 1); 1078*9533a5eaSstsp if (vflag) { 1079*9533a5eaSstsp uint8_t rate = *(u_int8_t*)t; 1080*9533a5eaSstsp if (rate & 0x80) 1081*9533a5eaSstsp printf(", MCS %u", rate & 0x7f); 1082*9533a5eaSstsp else 1083*9533a5eaSstsp printf(", %uMbit/s", rate / 2); 1084*9533a5eaSstsp } 108512a08440Sreyk t += 1; 108612a08440Sreyk } 108712a08440Sreyk 108812a08440Sreyk if (RADIOTAP(CHANNEL)) { 108912a08440Sreyk u_int16_t freq, flags; 109012a08440Sreyk TCHECK2(*t, 2); 109112a08440Sreyk 1092cce1ba42Sclaudio bcopy(t, &freq, sizeof(u_int16_t)); 1093cce1ba42Sclaudio freq = letoh16(freq); 109412a08440Sreyk t += 2; 109512a08440Sreyk TCHECK2(*t, 2); 1096cce1ba42Sclaudio bcopy(t, &flags, sizeof(u_int16_t)); 1097cce1ba42Sclaudio flags = letoh16(flags); 109812a08440Sreyk t += 2; 109912a08440Sreyk 110012a08440Sreyk printf(", chan %u", ieee80211_any2ieee(freq, flags)); 110112a08440Sreyk 110212a08440Sreyk if (flags & IEEE80211_CHAN_DYN && 110312a08440Sreyk flags & IEEE80211_CHAN_2GHZ) 110412a08440Sreyk printf(", 11g"); 110512a08440Sreyk else if (flags & IEEE80211_CHAN_CCK && 110612a08440Sreyk flags & IEEE80211_CHAN_2GHZ) 110712a08440Sreyk printf(", 11b"); 110812a08440Sreyk else if (flags & IEEE80211_CHAN_OFDM && 110912a08440Sreyk flags & IEEE80211_CHAN_2GHZ) 111012a08440Sreyk printf(", 11G"); 111112a08440Sreyk else if (flags & IEEE80211_CHAN_OFDM && 111212a08440Sreyk flags & IEEE80211_CHAN_5GHZ) 111312a08440Sreyk printf(", 11a"); 111412a08440Sreyk 111512a08440Sreyk if (flags & IEEE80211_CHAN_XR) 111612a08440Sreyk printf(", XR"); 111712a08440Sreyk } 111812a08440Sreyk 111912a08440Sreyk if (RADIOTAP(FHSS)) { 112012a08440Sreyk TCHECK2(*t, 2); 112112a08440Sreyk printf(", fhss %u/%u", *(u_int8_t*)t, *(u_int8_t*)t + 1); 112212a08440Sreyk t += 2; 112312a08440Sreyk } 112412a08440Sreyk 112512a08440Sreyk if (RADIOTAP(DBM_ANTSIGNAL)) { 112612a08440Sreyk TCHECK(*t); 112712a08440Sreyk printf(", sig %ddBm", *(int8_t*)t); 112812a08440Sreyk t += 1; 112912a08440Sreyk } 113012a08440Sreyk 113112a08440Sreyk if (RADIOTAP(DBM_ANTNOISE)) { 113212a08440Sreyk TCHECK(*t); 113312a08440Sreyk printf(", noise %ddBm", *(int8_t*)t); 113412a08440Sreyk t += 1; 113512a08440Sreyk } 113612a08440Sreyk 113712a08440Sreyk if (RADIOTAP(LOCK_QUALITY)) { 113812a08440Sreyk TCHECK2(*t, 2); 1139cce1ba42Sclaudio if (vflag) { 1140cce1ba42Sclaudio bcopy(t, &tmp, sizeof(u_int16_t)); 1141cce1ba42Sclaudio printf(", quality %u", letoh16(tmp)); 1142cce1ba42Sclaudio } 114312a08440Sreyk t += 2; 114412a08440Sreyk } 114512a08440Sreyk 114612a08440Sreyk if (RADIOTAP(TX_ATTENUATION)) { 114712a08440Sreyk TCHECK2(*t, 2); 1148cce1ba42Sclaudio if (vflag) { 1149cce1ba42Sclaudio bcopy(t, &tmp, sizeof(u_int16_t)); 1150cce1ba42Sclaudio printf(", txatt %u", letoh16(tmp)); 1151cce1ba42Sclaudio } 115212a08440Sreyk t += 2; 115312a08440Sreyk } 115412a08440Sreyk 115512a08440Sreyk if (RADIOTAP(DB_TX_ATTENUATION)) { 115612a08440Sreyk TCHECK2(*t, 2); 1157cce1ba42Sclaudio if (vflag) { 1158cce1ba42Sclaudio bcopy(t, &tmp, sizeof(u_int16_t)); 1159cce1ba42Sclaudio printf(", txatt %udB", letoh16(tmp)); 1160cce1ba42Sclaudio } 116112a08440Sreyk t += 2; 116212a08440Sreyk } 116312a08440Sreyk 116412a08440Sreyk if (RADIOTAP(DBM_TX_POWER)) { 116512a08440Sreyk TCHECK(*t); 116612a08440Sreyk printf(", txpower %ddBm", *(int8_t*)t); 116712a08440Sreyk t += 1; 116812a08440Sreyk } 116912a08440Sreyk 117012a08440Sreyk if (RADIOTAP(ANTENNA)) { 117112a08440Sreyk TCHECK(*t); 117212a08440Sreyk if (vflag) 117312a08440Sreyk printf(", antenna %u", *(u_int8_t*)t); 117412a08440Sreyk t += 1; 117512a08440Sreyk } 117612a08440Sreyk 117712a08440Sreyk if (RADIOTAP(DB_ANTSIGNAL)) { 117812a08440Sreyk TCHECK(*t); 117912a08440Sreyk printf(", signal %udB", *(u_int8_t*)t); 118012a08440Sreyk t += 1; 118112a08440Sreyk } 118212a08440Sreyk 118312a08440Sreyk if (RADIOTAP(DB_ANTNOISE)) { 118412a08440Sreyk TCHECK(*t); 118512a08440Sreyk printf(", noise %udB", *(u_int8_t*)t); 118612a08440Sreyk t += 1; 118712a08440Sreyk } 118812a08440Sreyk 118912a08440Sreyk if (RADIOTAP(FCS)) { 119012a08440Sreyk TCHECK2(*t, 4); 1191cce1ba42Sclaudio if (vflag) { 1192cce1ba42Sclaudio u_int32_t fcs; 1193cce1ba42Sclaudio bcopy(t, &fcs, sizeof(u_int32_t)); 1194cce1ba42Sclaudio printf(", fcs %08x", letoh32(fcs)); 1195cce1ba42Sclaudio } 119612a08440Sreyk t += 4; 119712a08440Sreyk } 119812a08440Sreyk 11996fc94ee3Sreyk if (RADIOTAP(RSSI)) { 12006fc94ee3Sreyk u_int8_t rssi, max_rssi; 12016fc94ee3Sreyk TCHECK(*t); 12026fc94ee3Sreyk rssi = *(u_int8_t*)t; 12036fc94ee3Sreyk t += 1; 12046fc94ee3Sreyk TCHECK(*t); 12056fc94ee3Sreyk max_rssi = *(u_int8_t*)t; 12066fc94ee3Sreyk t += 1; 12076fc94ee3Sreyk 12086fc94ee3Sreyk printf(", rssi %u/%u", rssi, max_rssi); 12096fc94ee3Sreyk } 12106fc94ee3Sreyk 121112a08440Sreyk #undef RADIOTAP 121212a08440Sreyk 121312a08440Sreyk putchar('>'); 121412a08440Sreyk goto out; 121512a08440Sreyk 121612a08440Sreyk trunc: 121712a08440Sreyk /* Truncated frame */ 121812a08440Sreyk printf("[|radiotap + 802.11]"); 121912a08440Sreyk 122012a08440Sreyk out: 1221c79cf170Sreyk if (!ieee80211_encap) { 122212a08440Sreyk if (xflag) 1223a0774ae9Smglocker default_print(p, h->len); 122412a08440Sreyk putchar('\n'); 122512a08440Sreyk } 1226c79cf170Sreyk } 122718786664Sclaudio 122818786664Sclaudio void 122918786664Sclaudio ieee80211_reason(u_int16_t reason) 123018786664Sclaudio { 123118786664Sclaudio if (!vflag) 123218786664Sclaudio return; 123318786664Sclaudio 123418786664Sclaudio switch (reason) { 123518786664Sclaudio case IEEE80211_REASON_UNSPECIFIED: 123618786664Sclaudio printf(", unspecified failure"); 123718786664Sclaudio break; 123818786664Sclaudio case IEEE80211_REASON_AUTH_EXPIRE: 123918786664Sclaudio printf(", authentication expired"); 124018786664Sclaudio break; 124118786664Sclaudio case IEEE80211_REASON_AUTH_LEAVE: 124218786664Sclaudio printf(", deauth - station left"); 124318786664Sclaudio break; 124418786664Sclaudio case IEEE80211_REASON_ASSOC_EXPIRE: 124518786664Sclaudio printf(", association expired"); 124618786664Sclaudio break; 124718786664Sclaudio case IEEE80211_REASON_ASSOC_TOOMANY: 124818786664Sclaudio printf(", too many associated stations"); 124918786664Sclaudio break; 125018786664Sclaudio case IEEE80211_REASON_NOT_AUTHED: 125118786664Sclaudio printf(", not authenticated"); 125218786664Sclaudio break; 125318786664Sclaudio case IEEE80211_REASON_NOT_ASSOCED: 125418786664Sclaudio printf(", not associated"); 125518786664Sclaudio break; 125618786664Sclaudio case IEEE80211_REASON_ASSOC_LEAVE: 125718786664Sclaudio printf(", disassociated - station left"); 125818786664Sclaudio break; 125918786664Sclaudio case IEEE80211_REASON_ASSOC_NOT_AUTHED: 126018786664Sclaudio printf(", association but not authenticated"); 126118786664Sclaudio break; 126218786664Sclaudio case IEEE80211_REASON_RSN_REQUIRED: 126318786664Sclaudio printf(", rsn required"); 126418786664Sclaudio break; 126518786664Sclaudio case IEEE80211_REASON_RSN_INCONSISTENT: 126618786664Sclaudio printf(", rsn inconsistent"); 126718786664Sclaudio break; 126818786664Sclaudio case IEEE80211_REASON_IE_INVALID: 126918786664Sclaudio printf(", ie invalid"); 127018786664Sclaudio break; 127118786664Sclaudio case IEEE80211_REASON_MIC_FAILURE: 127218786664Sclaudio printf(", mic failure"); 127318786664Sclaudio break; 127418786664Sclaudio default: 127518786664Sclaudio printf(", unknown reason %u", reason); 127618786664Sclaudio } 127718786664Sclaudio } 1278