print-802_11.c revision 214478
198524Sfenner/* 298524Sfenner * Copyright (c) 2001 398524Sfenner * Fortress Technologies, Inc. All rights reserved. 498524Sfenner * Charlie Lenahan (clenahan@fortresstech.com) 598524Sfenner * 698524Sfenner * Redistribution and use in source and binary forms, with or without 798524Sfenner * modification, are permitted provided that: (1) source code distributions 898524Sfenner * retain the above copyright notice and this paragraph in its entirety, (2) 998524Sfenner * distributions including binary code include the above copyright notice and 1098524Sfenner * this paragraph in its entirety in the documentation or other materials 1198524Sfenner * provided with the distribution, and (3) all advertising materials mentioning 1298524Sfenner * features or use of this software display the following acknowledgement: 1398524Sfenner * ``This product includes software developed by the University of California, 1498524Sfenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1598524Sfenner * the University nor the names of its contributors may be used to endorse 1698524Sfenner * or promote products derived from this software without specific prior 1798524Sfenner * written permission. 1898524Sfenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1998524Sfenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 2098524Sfenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2198524Sfenner */ 2298524Sfenner 2398524Sfenner#ifndef lint 24127668Sbmsstatic const char rcsid[] _U_ = 25214478Srpaulo "@(#) $Header: /tcpdump/master/tcpdump/print-802_11.c,v 1.49 2007-12-29 23:25:02 guy Exp $ (LBL)"; 2698524Sfenner#endif 2798524Sfenner 2898524Sfenner#ifdef HAVE_CONFIG_H 2998524Sfenner#include "config.h" 3098524Sfenner#endif 3198524Sfenner 32127668Sbms#include <tcpdump-stdinc.h> 3398524Sfenner 3498524Sfenner#include <stdio.h> 3598524Sfenner#include <pcap.h> 3698524Sfenner#include <string.h> 3798524Sfenner 3898524Sfenner#include "interface.h" 3998524Sfenner#include "addrtoname.h" 4098524Sfenner#include "ethertype.h" 4198524Sfenner 4298524Sfenner#include "extract.h" 4398524Sfenner 44146773Ssam#include "cpack.h" 45146773Ssam 4698524Sfenner#include "ieee802_11.h" 47146773Ssam#include "ieee802_11_radio.h" 4898524Sfenner 49172686Smlaier#define PRINT_SSID(p) \ 50214478Srpaulo if (p.ssid_present) { \ 51172686Smlaier printf(" ("); \ 52172686Smlaier fn_print(p.ssid.ssid, NULL); \ 53172686Smlaier printf(")"); \ 54172686Smlaier } 55172686Smlaier 56146773Ssam#define PRINT_RATE(_sep, _r, _suf) \ 57146773Ssam printf("%s%2.1f%s", _sep, (.5 * ((_r) & 0x7f)), _suf) 58111726Sfenner#define PRINT_RATES(p) \ 59214478Srpaulo if (p.rates_present) { \ 60214478Srpaulo int z; \ 61214478Srpaulo const char *sep = " ["; \ 62214478Srpaulo for (z = 0; z < p.rates.length ; z++) { \ 63214478Srpaulo PRINT_RATE(sep, p.rates.rate[z], \ 64214478Srpaulo (p.rates.rate[z] & 0x80 ? "*" : "")); \ 65214478Srpaulo sep = " "; \ 66214478Srpaulo } \ 67214478Srpaulo if (p.rates.length != 0) \ 68214478Srpaulo printf(" Mbit]"); \ 69172686Smlaier } 70172686Smlaier 71172686Smlaier#define PRINT_DS_CHANNEL(p) \ 72214478Srpaulo if (p.ds_present) \ 73172686Smlaier printf(" CH: %u", p.ds.channel); \ 74172686Smlaier printf("%s", \ 75172686Smlaier CAPABILITY_PRIVACY(p.capability_info) ? ", PRIVACY" : "" ); 7698524Sfenner 77170533Ssamstatic const int ieee80211_htrates[16] = { 78170533Ssam 13, /* IFM_IEEE80211_MCS0 */ 79170533Ssam 26, /* IFM_IEEE80211_MCS1 */ 80170533Ssam 39, /* IFM_IEEE80211_MCS2 */ 81170533Ssam 52, /* IFM_IEEE80211_MCS3 */ 82170533Ssam 78, /* IFM_IEEE80211_MCS4 */ 83170533Ssam 104, /* IFM_IEEE80211_MCS5 */ 84170533Ssam 117, /* IFM_IEEE80211_MCS6 */ 85170533Ssam 130, /* IFM_IEEE80211_MCS7 */ 86170533Ssam 26, /* IFM_IEEE80211_MCS8 */ 87170533Ssam 52, /* IFM_IEEE80211_MCS9 */ 88170533Ssam 78, /* IFM_IEEE80211_MCS10 */ 89170533Ssam 104, /* IFM_IEEE80211_MCS11 */ 90170533Ssam 156, /* IFM_IEEE80211_MCS12 */ 91170533Ssam 208, /* IFM_IEEE80211_MCS13 */ 92170533Ssam 234, /* IFM_IEEE80211_MCS14 */ 93170533Ssam 260, /* IFM_IEEE80211_MCS15 */ 94170533Ssam}; 95170533Ssam#define PRINT_HT_RATE(_sep, _r, _suf) \ 96170533Ssam printf("%s%.1f%s", _sep, (.5 * ieee80211_htrates[(_r) & 0xf]), _suf) 97170533Ssam 9898524Sfennerstatic const char *auth_alg_text[]={"Open System","Shared Key","EAP"}; 99162017Ssam#define NUM_AUTH_ALGS (sizeof auth_alg_text / sizeof auth_alg_text[0]) 10098524Sfenner 10198524Sfennerstatic const char *status_text[] = { 102195684Ssam "Succesful", /* 0 */ 103195684Ssam "Unspecified failure", /* 1 */ 104195684Ssam "Reserved", /* 2 */ 105195684Ssam "Reserved", /* 3 */ 106195684Ssam "Reserved", /* 4 */ 107195684Ssam "Reserved", /* 5 */ 108195684Ssam "Reserved", /* 6 */ 109195684Ssam "Reserved", /* 7 */ 110195684Ssam "Reserved", /* 8 */ 111195684Ssam "Reserved", /* 9 */ 112195684Ssam "Cannot Support all requested capabilities in the Capability " 113195684Ssam "Information field", /* 10 */ 114195684Ssam "Reassociation denied due to inability to confirm that association " 115195684Ssam "exists", /* 11 */ 116195684Ssam "Association denied due to reason outside the scope of the " 117195684Ssam "standard", /* 12 */ 118195684Ssam "Responding station does not support the specified authentication " 119195684Ssam "algorithm ", /* 13 */ 120195684Ssam "Received an Authentication frame with authentication transaction " 121195684Ssam "sequence number out of expected sequence", /* 14 */ 122195684Ssam "Authentication rejected because of challenge failure", /* 15 */ 123195684Ssam "Authentication rejected due to timeout waiting for next frame in " 124195684Ssam "sequence", /* 16 */ 125195684Ssam "Association denied because AP is unable to handle additional" 126195684Ssam "associated stations", /* 17 */ 127195684Ssam "Association denied due to requesting station not supporting all of " 128195684Ssam "the data rates in BSSBasicRateSet parameter", /* 18 */ 129195684Ssam "Association denied due to requesting station not supporting " 130195684Ssam "short preamble operation", /* 19 */ 131195684Ssam "Association denied due to requesting station not supporting " 132195684Ssam "PBCC encoding", /* 20 */ 133195684Ssam "Association denied due to requesting station not supporting " 134195684Ssam "channel agility", /* 21 */ 135195684Ssam "Association request rejected because Spectrum Management " 136195684Ssam "capability is required", /* 22 */ 137195684Ssam "Association request rejected because the information in the " 138195684Ssam "Power Capability element is unacceptable", /* 23 */ 139195684Ssam "Association request rejected because the information in the " 140195684Ssam "Supported Channels element is unacceptable", /* 24 */ 141195684Ssam "Association denied due to requesting station not supporting " 142195684Ssam "short slot operation", /* 25 */ 143195684Ssam "Association denied due to requesting station not supporting " 144195684Ssam "DSSS-OFDM operation", /* 26 */ 145195684Ssam "Association denied because the requested STA does not support HT " 146195684Ssam "features", /* 27 */ 147195684Ssam "Reserved", /* 28 */ 148195684Ssam "Association denied because the requested STA does not support " 149195684Ssam "the PCO transition time required by the AP", /* 29 */ 150195684Ssam "Reserved", /* 30 */ 151195684Ssam "Reserved", /* 31 */ 152195684Ssam "Unspecified, QoS-related failure", /* 32 */ 153195684Ssam "Association denied due to QAP having insufficient bandwidth " 154195684Ssam "to handle another QSTA", /* 33 */ 155195684Ssam "Association denied due to excessive frame loss rates and/or " 156195684Ssam "poor conditions on current operating channel", /* 34 */ 157195684Ssam "Association (with QBSS) denied due to requesting station not " 158195684Ssam "supporting the QoS facility", /* 35 */ 159195684Ssam "Association denied due to requesting station not supporting " 160195684Ssam "Block Ack", /* 36 */ 161195684Ssam "The request has been declined", /* 37 */ 162195684Ssam "The request has not been successful as one or more parameters " 163195684Ssam "have invalid values", /* 38 */ 164195684Ssam "The TS has not been created because the request cannot be honored. " 165195684Ssam "However, a suggested TSPEC is provided so that the initiating QSTA" 166195684Ssam "may attempt to set another TS with the suggested changes to the " 167195684Ssam "TSPEC", /* 39 */ 168195684Ssam "Invalid Information Element", /* 40 */ 169195684Ssam "Group Cipher is not valid", /* 41 */ 170195684Ssam "Pairwise Cipher is not valid", /* 42 */ 171195684Ssam "AKMP is not valid", /* 43 */ 172195684Ssam "Unsupported RSN IE version", /* 44 */ 173195684Ssam "Invalid RSN IE Capabilities", /* 45 */ 174195684Ssam "Cipher suite is rejected per security policy", /* 46 */ 175195684Ssam "The TS has not been created. However, the HC may be capable of " 176195684Ssam "creating a TS, in response to a request, after the time indicated " 177195684Ssam "in the TS Delay element", /* 47 */ 178195684Ssam "Direct Link is not allowed in the BSS by policy", /* 48 */ 179195684Ssam "Destination STA is not present within this QBSS.", /* 49 */ 180195684Ssam "The Destination STA is not a QSTA.", /* 50 */ 181195684Ssam 18298524Sfenner}; 183162017Ssam#define NUM_STATUSES (sizeof status_text / sizeof status_text[0]) 18498524Sfenner 18598524Sfennerstatic const char *reason_text[] = { 186195684Ssam "Reserved", /* 0 */ 187195684Ssam "Unspecified reason", /* 1 */ 188195684Ssam "Previous authentication no longer valid", /* 2 */ 189195684Ssam "Deauthenticated because sending station is leaving (or has left) " 190195684Ssam "IBSS or ESS", /* 3 */ 191195684Ssam "Disassociated due to inactivity", /* 4 */ 192195684Ssam "Disassociated because AP is unable to handle all currently " 193195684Ssam " associated stations", /* 5 */ 194162017Ssam "Class 2 frame received from nonauthenticated station", /* 6 */ 195195684Ssam "Class 3 frame received from nonassociated station", /* 7 */ 196195684Ssam "Disassociated because sending station is leaving " 197195684Ssam "(or has left) BSS", /* 8 */ 198195684Ssam "Station requesting (re)association is not authenticated with " 199195684Ssam "responding station", /* 9 */ 200195684Ssam "Disassociated because the information in the Power Capability " 201195684Ssam "element is unacceptable", /* 10 */ 202195684Ssam "Disassociated because the information in the SupportedChannels " 203195684Ssam "element is unacceptable", /* 11 */ 204195684Ssam "Invalid Information Element", /* 12 */ 205195684Ssam "Reserved", /* 13 */ 206195684Ssam "Michael MIC failure", /* 14 */ 207195684Ssam "4-Way Handshake timeout", /* 15 */ 208195684Ssam "Group key update timeout", /* 16 */ 209195684Ssam "Information element in 4-Way Handshake different from (Re)Association" 210195684Ssam "Request/Probe Response/Beacon", /* 17 */ 211195684Ssam "Group Cipher is not valid", /* 18 */ 212195684Ssam "AKMP is not valid", /* 20 */ 213195684Ssam "Unsupported RSN IE version", /* 21 */ 214195684Ssam "Invalid RSN IE Capabilities", /* 22 */ 215195684Ssam "IEEE 802.1X Authentication failed", /* 23 */ 216195684Ssam "Cipher suite is rejected per security policy", /* 24 */ 217195684Ssam "Reserved", /* 25 */ 218195684Ssam "Reserved", /* 26 */ 219195684Ssam "Reserved", /* 27 */ 220195684Ssam "Reserved", /* 28 */ 221195684Ssam "Reserved", /* 29 */ 222195684Ssam "Reserved", /* 30 */ 223195684Ssam "TS deleted because QoS AP lacks sufficient bandwidth for this " 224195684Ssam "QoS STA due to a change in BSS service characteristics or " 225195684Ssam "operational mode (e.g. an HT BSS change from 40 MHz channel " 226195684Ssam "to 20 MHz channel)", /* 31 */ 227195684Ssam "Disassociated for unspecified, QoS-related reason", /* 32 */ 228195684Ssam "Disassociated because QoS AP lacks sufficient bandwidth for this " 229195684Ssam "QoS STA", /* 33 */ 230195684Ssam "Disassociated because of excessive number of frames that need to be " 231195684Ssam "acknowledged, but are not acknowledged for AP transmissions " 232195684Ssam "and/or poor channel conditions", /* 34 */ 233195684Ssam "Disassociated because STA is transmitting outside the limits " 234195684Ssam "of its TXOPs", /* 35 */ 235195684Ssam "Requested from peer STA as the STA is leaving the BSS " 236195684Ssam "(or resetting)", /* 36 */ 237195684Ssam "Requested from peer STA as it does not want to use the " 238195684Ssam "mechanism", /* 37 */ 239195684Ssam "Requested from peer STA as the STA received frames using the " 240195684Ssam "mechanism for which a set up is required", /* 38 */ 241195684Ssam "Requested from peer STA due to time out", /* 39 */ 242195684Ssam "Reserved", /* 40 */ 243195684Ssam "Reserved", /* 41 */ 244195684Ssam "Reserved", /* 42 */ 245195684Ssam "Reserved", /* 43 */ 246195684Ssam "Reserved", /* 44 */ 247195684Ssam "Peer STA does not support the requested cipher suite", /* 45 */ 248195684Ssam "Association denied due to requesting STA not supporting HT " 249195684Ssam "features", /* 46 */ 25098524Sfenner}; 251162017Ssam#define NUM_REASONS (sizeof reason_text / sizeof reason_text[0]) 25298524Sfenner 253127668Sbmsstatic int 254127668Sbmswep_print(const u_char *p) 25598524Sfenner{ 25698524Sfenner u_int32_t iv; 25798524Sfenner 258127668Sbms if (!TTEST2(*p, IEEE802_11_IV_LEN + IEEE802_11_KID_LEN)) 25998524Sfenner return 0; 26098524Sfenner iv = EXTRACT_LE_32BITS(p); 26198524Sfenner 26298524Sfenner printf("Data IV:%3x Pad %x KeyID %x", IV_IV(iv), IV_PAD(iv), 26398524Sfenner IV_KEYID(iv)); 26498524Sfenner 26598524Sfenner return 1; 26698524Sfenner} 26798524Sfenner 268214478Srpaulostatic int 269214478Srpauloparse_elements(struct mgmt_body_t *pbody, const u_char *p, int offset, 270214478Srpaulo u_int length) 27198524Sfenner{ 272214478Srpaulo struct ssid_t ssid; 273214478Srpaulo struct challenge_t challenge; 274214478Srpaulo struct rates_t rates; 275214478Srpaulo struct ds_t ds; 276214478Srpaulo struct cf_t cf; 277214478Srpaulo struct tim_t tim; 278214478Srpaulo 279172686Smlaier /* 280172686Smlaier * We haven't seen any elements yet. 281172686Smlaier */ 282214478Srpaulo pbody->challenge_present = 0; 283214478Srpaulo pbody->ssid_present = 0; 284214478Srpaulo pbody->rates_present = 0; 285214478Srpaulo pbody->ds_present = 0; 286214478Srpaulo pbody->cf_present = 0; 287214478Srpaulo pbody->tim_present = 0; 288172686Smlaier 289214478Srpaulo while (length != 0) { 29098524Sfenner if (!TTEST2(*(p + offset), 1)) 291214478Srpaulo return 0; 292214478Srpaulo if (length < 1) 293214478Srpaulo return 0; 29498524Sfenner switch (*(p + offset)) { 29598524Sfenner case E_SSID: 296127668Sbms if (!TTEST2(*(p + offset), 2)) 297214478Srpaulo return 0; 298214478Srpaulo if (length < 2) 299214478Srpaulo return 0; 300214478Srpaulo memcpy(&ssid, p + offset, 2); 301127668Sbms offset += 2; 302214478Srpaulo length -= 2; 303214478Srpaulo if (ssid.length != 0) { 304214478Srpaulo if (ssid.length > sizeof(ssid.ssid) - 1) 305214478Srpaulo return 0; 306214478Srpaulo if (!TTEST2(*(p + offset), ssid.length)) 307214478Srpaulo return 0; 308214478Srpaulo if (length < ssid.length) 309214478Srpaulo return 0; 310214478Srpaulo memcpy(&ssid.ssid, p + offset, ssid.length); 311214478Srpaulo offset += ssid.length; 312214478Srpaulo length -= ssid.length; 313172686Smlaier } 314214478Srpaulo ssid.ssid[ssid.length] = '\0'; 315214478Srpaulo /* 316214478Srpaulo * Present and not truncated. 317214478Srpaulo * 318214478Srpaulo * If we haven't already seen an SSID IE, 319214478Srpaulo * copy this one, otherwise ignore this one, 320214478Srpaulo * so we later report the first one we saw. 321214478Srpaulo */ 322214478Srpaulo if (!pbody->ssid_present) { 323214478Srpaulo pbody->ssid = ssid; 324214478Srpaulo pbody->ssid_present = 1; 325214478Srpaulo } 32698524Sfenner break; 32798524Sfenner case E_CHALLENGE: 328127668Sbms if (!TTEST2(*(p + offset), 2)) 329214478Srpaulo return 0; 330214478Srpaulo if (length < 2) 331214478Srpaulo return 0; 332214478Srpaulo memcpy(&challenge, p + offset, 2); 333127668Sbms offset += 2; 334214478Srpaulo length -= 2; 335214478Srpaulo if (challenge.length != 0) { 336214478Srpaulo if (challenge.length > 337214478Srpaulo sizeof(challenge.text) - 1) 338214478Srpaulo return 0; 339214478Srpaulo if (!TTEST2(*(p + offset), challenge.length)) 340214478Srpaulo return 0; 341214478Srpaulo if (length < challenge.length) 342214478Srpaulo return 0; 343214478Srpaulo memcpy(&challenge.text, p + offset, 344214478Srpaulo challenge.length); 345214478Srpaulo offset += challenge.length; 346214478Srpaulo length -= challenge.length; 347172686Smlaier } 348214478Srpaulo challenge.text[challenge.length] = '\0'; 349214478Srpaulo /* 350214478Srpaulo * Present and not truncated. 351214478Srpaulo * 352214478Srpaulo * If we haven't already seen a challenge IE, 353214478Srpaulo * copy this one, otherwise ignore this one, 354214478Srpaulo * so we later report the first one we saw. 355214478Srpaulo */ 356214478Srpaulo if (!pbody->challenge_present) { 357214478Srpaulo pbody->challenge = challenge; 358214478Srpaulo pbody->challenge_present = 1; 359214478Srpaulo } 36098524Sfenner break; 36198524Sfenner case E_RATES: 362127668Sbms if (!TTEST2(*(p + offset), 2)) 363214478Srpaulo return 0; 364214478Srpaulo if (length < 2) 365214478Srpaulo return 0; 366214478Srpaulo memcpy(&rates, p + offset, 2); 367127668Sbms offset += 2; 368214478Srpaulo length -= 2; 369214478Srpaulo if (rates.length != 0) { 370214478Srpaulo if (rates.length > sizeof rates.rate) 371214478Srpaulo return 0; 372214478Srpaulo if (!TTEST2(*(p + offset), rates.length)) 373214478Srpaulo return 0; 374214478Srpaulo if (length < rates.length) 375214478Srpaulo return 0; 376214478Srpaulo memcpy(&rates.rate, p + offset, rates.length); 377214478Srpaulo offset += rates.length; 378214478Srpaulo length -= rates.length; 379172686Smlaier } 380214478Srpaulo /* 381214478Srpaulo * Present and not truncated. 382214478Srpaulo * 383214478Srpaulo * If we haven't already seen a rates IE, 384214478Srpaulo * copy this one if it's not zero-length, 385214478Srpaulo * otherwise ignore this one, so we later 386214478Srpaulo * report the first one we saw. 387214478Srpaulo * 388214478Srpaulo * We ignore zero-length rates IEs as some 389214478Srpaulo * devices seem to put a zero-length rates 390214478Srpaulo * IE, followed by an SSID IE, followed by 391214478Srpaulo * a non-zero-length rates IE into frames, 392214478Srpaulo * even though IEEE Std 802.11-2007 doesn't 393214478Srpaulo * seem to indicate that a zero-length rates 394214478Srpaulo * IE is valid. 395214478Srpaulo */ 396214478Srpaulo if (!pbody->rates_present && rates.length != 0) { 397214478Srpaulo pbody->rates = rates; 398214478Srpaulo pbody->rates_present = 1; 399214478Srpaulo } 40098524Sfenner break; 40198524Sfenner case E_DS: 402127668Sbms if (!TTEST2(*(p + offset), 3)) 403214478Srpaulo return 0; 404214478Srpaulo if (length < 3) 405214478Srpaulo return 0; 406214478Srpaulo memcpy(&ds, p + offset, 3); 407127668Sbms offset += 3; 408214478Srpaulo length -= 3; 409214478Srpaulo /* 410214478Srpaulo * Present and not truncated. 411214478Srpaulo * 412214478Srpaulo * If we haven't already seen a DS IE, 413214478Srpaulo * copy this one, otherwise ignore this one, 414214478Srpaulo * so we later report the first one we saw. 415214478Srpaulo */ 416214478Srpaulo if (!pbody->ds_present) { 417214478Srpaulo pbody->ds = ds; 418214478Srpaulo pbody->ds_present = 1; 419214478Srpaulo } 42098524Sfenner break; 42198524Sfenner case E_CF: 422127668Sbms if (!TTEST2(*(p + offset), 8)) 423214478Srpaulo return 0; 424214478Srpaulo if (length < 8) 425214478Srpaulo return 0; 426214478Srpaulo memcpy(&cf, p + offset, 8); 427127668Sbms offset += 8; 428214478Srpaulo length -= 8; 429214478Srpaulo /* 430214478Srpaulo * Present and not truncated. 431214478Srpaulo * 432214478Srpaulo * If we haven't already seen a CF IE, 433214478Srpaulo * copy this one, otherwise ignore this one, 434214478Srpaulo * so we later report the first one we saw. 435214478Srpaulo */ 436214478Srpaulo if (!pbody->cf_present) { 437214478Srpaulo pbody->cf = cf; 438214478Srpaulo pbody->cf_present = 1; 439214478Srpaulo } 44098524Sfenner break; 44198524Sfenner case E_TIM: 442127668Sbms if (!TTEST2(*(p + offset), 2)) 443214478Srpaulo return 0; 444214478Srpaulo if (length < 2) 445214478Srpaulo return 0; 446214478Srpaulo memcpy(&tim, p + offset, 2); 447127668Sbms offset += 2; 448214478Srpaulo length -= 2; 449127668Sbms if (!TTEST2(*(p + offset), 3)) 450214478Srpaulo return 0; 451214478Srpaulo if (length < 3) 452214478Srpaulo return 0; 453214478Srpaulo memcpy(&tim.count, p + offset, 3); 454127668Sbms offset += 3; 455214478Srpaulo length -= 3; 45698524Sfenner 457214478Srpaulo if (tim.length <= 3) 458127668Sbms break; 459214478Srpaulo if (tim.length - 3 > (int)sizeof tim.bitmap) 460214478Srpaulo return 0; 461214478Srpaulo if (!TTEST2(*(p + offset), tim.length - 3)) 462214478Srpaulo return 0; 463214478Srpaulo if (length < (u_int)(tim.length - 3)) 464214478Srpaulo return 0; 465214478Srpaulo memcpy(tim.bitmap, p + (tim.length - 3), 466214478Srpaulo (tim.length - 3)); 467214478Srpaulo offset += tim.length - 3; 468214478Srpaulo length -= tim.length - 3; 469214478Srpaulo /* 470214478Srpaulo * Present and not truncated. 471214478Srpaulo * 472214478Srpaulo * If we haven't already seen a TIM IE, 473214478Srpaulo * copy this one, otherwise ignore this one, 474214478Srpaulo * so we later report the first one we saw. 475214478Srpaulo */ 476214478Srpaulo if (!pbody->tim_present) { 477214478Srpaulo pbody->tim = tim; 478214478Srpaulo pbody->tim_present = 1; 479214478Srpaulo } 48098524Sfenner break; 48198524Sfenner default: 48298524Sfenner#if 0 483127668Sbms printf("(1) unhandled element_id (%d) ", 484214478Srpaulo *(p + offset)); 48598524Sfenner#endif 486172686Smlaier if (!TTEST2(*(p + offset), 2)) 487214478Srpaulo return 0; 488214478Srpaulo if (length < 2) 489214478Srpaulo return 0; 490172686Smlaier if (!TTEST2(*(p + offset + 2), *(p + offset + 1))) 491214478Srpaulo return 0; 492214478Srpaulo if (length < (u_int)(*(p + offset + 1) + 2)) 493214478Srpaulo return 0; 494127668Sbms offset += *(p + offset + 1) + 2; 495214478Srpaulo length -= *(p + offset + 1) + 2; 49698524Sfenner break; 49798524Sfenner } 49898524Sfenner } 499214478Srpaulo 500214478Srpaulo /* No problems found. */ 501214478Srpaulo return 1; 50298524Sfenner} 50398524Sfenner 50498524Sfenner/********************************************************************************* 50598524Sfenner * Print Handle functions for the management frame types 50698524Sfenner *********************************************************************************/ 50798524Sfenner 508127668Sbmsstatic int 509214478Srpaulohandle_beacon(const u_char *p, u_int length) 51098524Sfenner{ 51198524Sfenner struct mgmt_body_t pbody; 51298524Sfenner int offset = 0; 513214478Srpaulo int ret; 51498524Sfenner 51598524Sfenner memset(&pbody, 0, sizeof(pbody)); 51698524Sfenner 517127668Sbms if (!TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN + 518127668Sbms IEEE802_11_CAPINFO_LEN)) 51998524Sfenner return 0; 520214478Srpaulo if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN + 521214478Srpaulo IEEE802_11_CAPINFO_LEN) 522214478Srpaulo return 0; 523172686Smlaier memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN); 524127668Sbms offset += IEEE802_11_TSTAMP_LEN; 525214478Srpaulo length -= IEEE802_11_TSTAMP_LEN; 52698524Sfenner pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset); 527127668Sbms offset += IEEE802_11_BCNINT_LEN; 528214478Srpaulo length -= IEEE802_11_BCNINT_LEN; 52998524Sfenner pbody.capability_info = EXTRACT_LE_16BITS(p+offset); 530127668Sbms offset += IEEE802_11_CAPINFO_LEN; 531214478Srpaulo length -= IEEE802_11_CAPINFO_LEN; 53298524Sfenner 533214478Srpaulo ret = parse_elements(&pbody, p, offset, length); 53498524Sfenner 535172686Smlaier PRINT_SSID(pbody); 536111726Sfenner PRINT_RATES(pbody); 537172686Smlaier printf(" %s", 538172686Smlaier CAPABILITY_ESS(pbody.capability_info) ? "ESS" : "IBSS"); 539172686Smlaier PRINT_DS_CHANNEL(pbody); 54098524Sfenner 541214478Srpaulo return ret; 54298524Sfenner} 54398524Sfenner 544127668Sbmsstatic int 545214478Srpaulohandle_assoc_request(const u_char *p, u_int length) 54698524Sfenner{ 54798524Sfenner struct mgmt_body_t pbody; 54898524Sfenner int offset = 0; 549214478Srpaulo int ret; 55098524Sfenner 55198524Sfenner memset(&pbody, 0, sizeof(pbody)); 55298524Sfenner 553127668Sbms if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN)) 55498524Sfenner return 0; 555214478Srpaulo if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN) 556214478Srpaulo return 0; 55798524Sfenner pbody.capability_info = EXTRACT_LE_16BITS(p); 558127668Sbms offset += IEEE802_11_CAPINFO_LEN; 559214478Srpaulo length -= IEEE802_11_CAPINFO_LEN; 56098524Sfenner pbody.listen_interval = EXTRACT_LE_16BITS(p+offset); 561127668Sbms offset += IEEE802_11_LISTENINT_LEN; 562214478Srpaulo length -= IEEE802_11_LISTENINT_LEN; 56398524Sfenner 564214478Srpaulo ret = parse_elements(&pbody, p, offset, length); 56598524Sfenner 566172686Smlaier PRINT_SSID(pbody); 567111726Sfenner PRINT_RATES(pbody); 568214478Srpaulo return ret; 56998524Sfenner} 57098524Sfenner 571127668Sbmsstatic int 572214478Srpaulohandle_assoc_response(const u_char *p, u_int length) 57398524Sfenner{ 57498524Sfenner struct mgmt_body_t pbody; 57598524Sfenner int offset = 0; 576214478Srpaulo int ret; 57798524Sfenner 57898524Sfenner memset(&pbody, 0, sizeof(pbody)); 57998524Sfenner 580127668Sbms if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN + 581127668Sbms IEEE802_11_AID_LEN)) 58298524Sfenner return 0; 583214478Srpaulo if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN + 584214478Srpaulo IEEE802_11_AID_LEN) 585214478Srpaulo return 0; 58698524Sfenner pbody.capability_info = EXTRACT_LE_16BITS(p); 587127668Sbms offset += IEEE802_11_CAPINFO_LEN; 588214478Srpaulo length -= IEEE802_11_CAPINFO_LEN; 58998524Sfenner pbody.status_code = EXTRACT_LE_16BITS(p+offset); 590127668Sbms offset += IEEE802_11_STATUS_LEN; 591214478Srpaulo length -= IEEE802_11_STATUS_LEN; 59298524Sfenner pbody.aid = EXTRACT_LE_16BITS(p+offset); 593127668Sbms offset += IEEE802_11_AID_LEN; 594214478Srpaulo length -= IEEE802_11_AID_LEN; 59598524Sfenner 596214478Srpaulo ret = parse_elements(&pbody, p, offset, length); 59798524Sfenner 598127668Sbms printf(" AID(%x) :%s: %s", ((u_int16_t)(pbody.aid << 2 )) >> 2 , 59998524Sfenner CAPABILITY_PRIVACY(pbody.capability_info) ? " PRIVACY " : "", 600162017Ssam (pbody.status_code < NUM_STATUSES 601162017Ssam ? status_text[pbody.status_code] 602162017Ssam : "n/a")); 60398524Sfenner 604214478Srpaulo return ret; 60598524Sfenner} 60698524Sfenner 607127668Sbmsstatic int 608214478Srpaulohandle_reassoc_request(const u_char *p, u_int length) 60998524Sfenner{ 61098524Sfenner struct mgmt_body_t pbody; 61198524Sfenner int offset = 0; 612214478Srpaulo int ret; 61398524Sfenner 61498524Sfenner memset(&pbody, 0, sizeof(pbody)); 61598524Sfenner 616127668Sbms if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN + 617127668Sbms IEEE802_11_AP_LEN)) 61898524Sfenner return 0; 619214478Srpaulo if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN + 620214478Srpaulo IEEE802_11_AP_LEN) 621214478Srpaulo return 0; 62298524Sfenner pbody.capability_info = EXTRACT_LE_16BITS(p); 623127668Sbms offset += IEEE802_11_CAPINFO_LEN; 624214478Srpaulo length -= IEEE802_11_CAPINFO_LEN; 62598524Sfenner pbody.listen_interval = EXTRACT_LE_16BITS(p+offset); 626127668Sbms offset += IEEE802_11_LISTENINT_LEN; 627214478Srpaulo length -= IEEE802_11_LISTENINT_LEN; 628127668Sbms memcpy(&pbody.ap, p+offset, IEEE802_11_AP_LEN); 629127668Sbms offset += IEEE802_11_AP_LEN; 630214478Srpaulo length -= IEEE802_11_AP_LEN; 63198524Sfenner 632214478Srpaulo ret = parse_elements(&pbody, p, offset, length); 63398524Sfenner 634172686Smlaier PRINT_SSID(pbody); 635172686Smlaier printf(" AP : %s", etheraddr_string( pbody.ap )); 63698524Sfenner 637214478Srpaulo return ret; 63898524Sfenner} 63998524Sfenner 640127668Sbmsstatic int 641214478Srpaulohandle_reassoc_response(const u_char *p, u_int length) 64298524Sfenner{ 64398524Sfenner /* Same as a Association Reponse */ 644214478Srpaulo return handle_assoc_response(p, length); 64598524Sfenner} 64698524Sfenner 647127668Sbmsstatic int 648214478Srpaulohandle_probe_request(const u_char *p, u_int length) 64998524Sfenner{ 65098524Sfenner struct mgmt_body_t pbody; 65198524Sfenner int offset = 0; 652214478Srpaulo int ret; 65398524Sfenner 65498524Sfenner memset(&pbody, 0, sizeof(pbody)); 65598524Sfenner 656214478Srpaulo ret = parse_elements(&pbody, p, offset, length); 65798524Sfenner 658172686Smlaier PRINT_SSID(pbody); 659111726Sfenner PRINT_RATES(pbody); 66098524Sfenner 661214478Srpaulo return ret; 66298524Sfenner} 66398524Sfenner 664127668Sbmsstatic int 665214478Srpaulohandle_probe_response(const u_char *p, u_int length) 66698524Sfenner{ 66798524Sfenner struct mgmt_body_t pbody; 66898524Sfenner int offset = 0; 669214478Srpaulo int ret; 67098524Sfenner 67198524Sfenner memset(&pbody, 0, sizeof(pbody)); 67298524Sfenner 673127668Sbms if (!TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN + 674127668Sbms IEEE802_11_CAPINFO_LEN)) 67598524Sfenner return 0; 676214478Srpaulo if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN + 677214478Srpaulo IEEE802_11_CAPINFO_LEN) 678214478Srpaulo return 0; 679127668Sbms memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN); 680127668Sbms offset += IEEE802_11_TSTAMP_LEN; 681214478Srpaulo length -= IEEE802_11_TSTAMP_LEN; 68298524Sfenner pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset); 683127668Sbms offset += IEEE802_11_BCNINT_LEN; 684214478Srpaulo length -= IEEE802_11_BCNINT_LEN; 68598524Sfenner pbody.capability_info = EXTRACT_LE_16BITS(p+offset); 686127668Sbms offset += IEEE802_11_CAPINFO_LEN; 687214478Srpaulo length -= IEEE802_11_CAPINFO_LEN; 68898524Sfenner 689214478Srpaulo ret = parse_elements(&pbody, p, offset, length); 69098524Sfenner 691172686Smlaier PRINT_SSID(pbody); 692111726Sfenner PRINT_RATES(pbody); 693172686Smlaier PRINT_DS_CHANNEL(pbody); 69498524Sfenner 695214478Srpaulo return ret; 69698524Sfenner} 69798524Sfenner 698127668Sbmsstatic int 699127668Sbmshandle_atim(void) 70098524Sfenner{ 70198524Sfenner /* the frame body for ATIM is null. */ 70298524Sfenner return 1; 70398524Sfenner} 70498524Sfenner 705127668Sbmsstatic int 706214478Srpaulohandle_disassoc(const u_char *p, u_int length) 70798524Sfenner{ 70898524Sfenner struct mgmt_body_t pbody; 70998524Sfenner 71098524Sfenner memset(&pbody, 0, sizeof(pbody)); 71198524Sfenner 712127668Sbms if (!TTEST2(*p, IEEE802_11_REASON_LEN)) 71398524Sfenner return 0; 714214478Srpaulo if (length < IEEE802_11_REASON_LEN) 715214478Srpaulo return 0; 71698524Sfenner pbody.reason_code = EXTRACT_LE_16BITS(p); 71798524Sfenner 718127668Sbms printf(": %s", 719162017Ssam (pbody.reason_code < NUM_REASONS) 720162017Ssam ? reason_text[pbody.reason_code] 721162017Ssam : "Reserved" ); 72298524Sfenner 72398524Sfenner return 1; 72498524Sfenner} 72598524Sfenner 726127668Sbmsstatic int 727214478Srpaulohandle_auth(const u_char *p, u_int length) 72898524Sfenner{ 72998524Sfenner struct mgmt_body_t pbody; 73098524Sfenner int offset = 0; 731214478Srpaulo int ret; 73298524Sfenner 73398524Sfenner memset(&pbody, 0, sizeof(pbody)); 73498524Sfenner 73598524Sfenner if (!TTEST2(*p, 6)) 73698524Sfenner return 0; 737214478Srpaulo if (length < 6) 738214478Srpaulo return 0; 73998524Sfenner pbody.auth_alg = EXTRACT_LE_16BITS(p); 74098524Sfenner offset += 2; 741214478Srpaulo length -= 2; 74298524Sfenner pbody.auth_trans_seq_num = EXTRACT_LE_16BITS(p + offset); 74398524Sfenner offset += 2; 744214478Srpaulo length -= 2; 74598524Sfenner pbody.status_code = EXTRACT_LE_16BITS(p + offset); 74698524Sfenner offset += 2; 747214478Srpaulo length -= 2; 74898524Sfenner 749214478Srpaulo ret = parse_elements(&pbody, p, offset, length); 75098524Sfenner 75198524Sfenner if ((pbody.auth_alg == 1) && 752127668Sbms ((pbody.auth_trans_seq_num == 2) || 753127668Sbms (pbody.auth_trans_seq_num == 3))) { 754127668Sbms printf(" (%s)-%x [Challenge Text] %s", 755162017Ssam (pbody.auth_alg < NUM_AUTH_ALGS) 756162017Ssam ? auth_alg_text[pbody.auth_alg] 757162017Ssam : "Reserved", 75898524Sfenner pbody.auth_trans_seq_num, 759127668Sbms ((pbody.auth_trans_seq_num % 2) 760162017Ssam ? ((pbody.status_code < NUM_STATUSES) 761127668Sbms ? status_text[pbody.status_code] 762127668Sbms : "n/a") : "")); 763214478Srpaulo return ret; 76498524Sfenner } 765127668Sbms printf(" (%s)-%x: %s", 766162017Ssam (pbody.auth_alg < NUM_AUTH_ALGS) 767162017Ssam ? auth_alg_text[pbody.auth_alg] 768162017Ssam : "Reserved", 769127668Sbms pbody.auth_trans_seq_num, 770127668Sbms (pbody.auth_trans_seq_num % 2) 771162017Ssam ? ((pbody.status_code < NUM_STATUSES) 772162017Ssam ? status_text[pbody.status_code] 773162017Ssam : "n/a") 774127668Sbms : ""); 77598524Sfenner 776214478Srpaulo return ret; 77798524Sfenner} 77898524Sfenner 779127668Sbmsstatic int 780214478Srpaulohandle_deauth(const struct mgmt_header_t *pmh, const u_char *p, u_int length) 78198524Sfenner{ 78298524Sfenner struct mgmt_body_t pbody; 78398524Sfenner int offset = 0; 784127668Sbms const char *reason = NULL; 78598524Sfenner 78698524Sfenner memset(&pbody, 0, sizeof(pbody)); 78798524Sfenner 788127668Sbms if (!TTEST2(*p, IEEE802_11_REASON_LEN)) 78998524Sfenner return 0; 790214478Srpaulo if (length < IEEE802_11_REASON_LEN) 791214478Srpaulo return 0; 79298524Sfenner pbody.reason_code = EXTRACT_LE_16BITS(p); 793127668Sbms offset += IEEE802_11_REASON_LEN; 794214478Srpaulo length -= IEEE802_11_REASON_LEN; 79598524Sfenner 796162017Ssam reason = (pbody.reason_code < NUM_REASONS) 797162017Ssam ? reason_text[pbody.reason_code] 798162017Ssam : "Reserved"; 799127668Sbms 80098524Sfenner if (eflag) { 801127668Sbms printf(": %s", reason); 80298524Sfenner } else { 803127668Sbms printf(" (%s): %s", etheraddr_string(pmh->sa), reason); 80498524Sfenner } 80598524Sfenner return 1; 80698524Sfenner} 80798524Sfenner 808195684Ssam#define PRINT_HT_ACTION(v) (\ 809195684Ssam (v) == 0 ? printf("TxChWidth") : \ 810195684Ssam (v) == 1 ? printf("MIMOPwrSave") : \ 811195684Ssam printf("Act#%d", (v)) \ 812195684Ssam) 813195684Ssam#define PRINT_BA_ACTION(v) (\ 814195684Ssam (v) == 0 ? printf("ADDBA Request") : \ 815195684Ssam (v) == 1 ? printf("ADDBA Response") : \ 816195684Ssam (v) == 2 ? printf("DELBA") : \ 817195684Ssam printf("Act#%d", (v)) \ 818195684Ssam) 819195684Ssam#define PRINT_MESHLINK_ACTION(v) (\ 820195684Ssam (v) == 0 ? printf("Request") : \ 821195684Ssam (v) == 1 ? printf("Report") : \ 822195684Ssam printf("Act#%d", (v)) \ 823195684Ssam) 824195684Ssam#define PRINT_MESHPEERING_ACTION(v) (\ 825195684Ssam (v) == 0 ? printf("Open") : \ 826195684Ssam (v) == 1 ? printf("Confirm") : \ 827195684Ssam (v) == 2 ? printf("Close") : \ 828195684Ssam printf("Act#%d", (v)) \ 829195684Ssam) 830195684Ssam#define PRINT_MESHPATH_ACTION(v) (\ 831195684Ssam (v) == 0 ? printf("Request") : \ 832195684Ssam (v) == 1 ? printf("Report") : \ 833195684Ssam (v) == 2 ? printf("Error") : \ 834195684Ssam (v) == 3 ? printf("RootAnnouncement") : \ 835195684Ssam printf("Act#%d", (v)) \ 836195684Ssam) 83798524Sfenner 838195684Ssamstatic int 839214478Srpaulohandle_action(const struct mgmt_header_t *pmh, const u_char *p, u_int length) 840195684Ssam{ 841195684Ssam if (!TTEST2(*p, 2)) 842195684Ssam return 0; 843214478Srpaulo if (length < 2) 844214478Srpaulo return 0; 845195684Ssam if (eflag) { 846195684Ssam printf(": "); 847195684Ssam } else { 848195684Ssam printf(" (%s): ", etheraddr_string(pmh->sa)); 849195684Ssam } 850195684Ssam switch (p[0]) { 851195684Ssam case 0: printf("Spectrum Management Act#%d", p[1]); break; 852195684Ssam case 1: printf("QoS Act#%d", p[1]); break; 853195684Ssam case 2: printf("DLS Act#%d", p[1]); break; 854195684Ssam case 3: printf("BA "); PRINT_BA_ACTION(p[1]); break; 855195684Ssam case 7: printf("HT "); PRINT_HT_ACTION(p[1]); break; 856195684Ssam case 13: printf("MeshLMetric "); PRINT_MESHLINK_ACTION(p[1]); break; 857195684Ssam case 15: printf("Interwork Act#%d", p[1]); break; 858195684Ssam case 16: printf("Resource Act#%d", p[1]); break; 859195684Ssam case 17: printf("Proxy Act#%d", p[1]); break; 860195684Ssam case 30: printf("MeshPeering "); PRINT_MESHPEERING_ACTION(p[1]); break; 861195684Ssam case 32: printf("MeshPath "); PRINT_MESHPATH_ACTION(p[1]); break; 862195684Ssam case 127: printf("Vendor Act#%d", p[1]); break; 863195684Ssam default: 864195684Ssam printf("Reserved(%d) Act#%d", p[0], p[1]); 865195684Ssam break; 866195684Ssam } 867195684Ssam return 1; 868195684Ssam} 869195684Ssam 870195684Ssam 87198524Sfenner/********************************************************************************* 87298524Sfenner * Print Body funcs 87398524Sfenner *********************************************************************************/ 87498524Sfenner 87598524Sfenner 876127668Sbmsstatic int 877127668Sbmsmgmt_body_print(u_int16_t fc, const struct mgmt_header_t *pmh, 878214478Srpaulo const u_char *p, u_int length) 87998524Sfenner{ 88098524Sfenner switch (FC_SUBTYPE(fc)) { 88198524Sfenner case ST_ASSOC_REQUEST: 882162017Ssam printf("Assoc Request"); 883214478Srpaulo return handle_assoc_request(p, length); 88498524Sfenner case ST_ASSOC_RESPONSE: 885162017Ssam printf("Assoc Response"); 886214478Srpaulo return handle_assoc_response(p, length); 88798524Sfenner case ST_REASSOC_REQUEST: 888162017Ssam printf("ReAssoc Request"); 889214478Srpaulo return handle_reassoc_request(p, length); 89098524Sfenner case ST_REASSOC_RESPONSE: 891162017Ssam printf("ReAssoc Response"); 892214478Srpaulo return handle_reassoc_response(p, length); 89398524Sfenner case ST_PROBE_REQUEST: 894162017Ssam printf("Probe Request"); 895214478Srpaulo return handle_probe_request(p, length); 89698524Sfenner case ST_PROBE_RESPONSE: 897162017Ssam printf("Probe Response"); 898214478Srpaulo return handle_probe_response(p, length); 89998524Sfenner case ST_BEACON: 900162017Ssam printf("Beacon"); 901214478Srpaulo return handle_beacon(p, length); 90298524Sfenner case ST_ATIM: 903162017Ssam printf("ATIM"); 904127668Sbms return handle_atim(); 90598524Sfenner case ST_DISASSOC: 906162017Ssam printf("Disassociation"); 907214478Srpaulo return handle_disassoc(p, length); 90898524Sfenner case ST_AUTH: 909162017Ssam printf("Authentication"); 91098524Sfenner if (!TTEST2(*p, 3)) 91198524Sfenner return 0; 91298524Sfenner if ((p[0] == 0 ) && (p[1] == 0) && (p[2] == 0)) { 91398524Sfenner printf("Authentication (Shared-Key)-3 "); 914127668Sbms return wep_print(p); 91598524Sfenner } 916214478Srpaulo return handle_auth(p, length); 91798524Sfenner case ST_DEAUTH: 918162017Ssam printf("DeAuthentication"); 919214478Srpaulo return handle_deauth(pmh, p, length); 92098524Sfenner break; 921195684Ssam case ST_ACTION: 922195684Ssam printf("Action"); 923214478Srpaulo return handle_action(pmh, p, length); 924195684Ssam break; 92598524Sfenner default: 926127668Sbms printf("Unhandled Management subtype(%x)", 92798524Sfenner FC_SUBTYPE(fc)); 92898524Sfenner return 1; 92998524Sfenner } 93098524Sfenner} 93198524Sfenner 93298524Sfenner 93398524Sfenner/********************************************************************************* 93498524Sfenner * Handles printing all the control frame types 93598524Sfenner *********************************************************************************/ 93698524Sfenner 937127668Sbmsstatic int 938127668Sbmsctrl_body_print(u_int16_t fc, const u_char *p) 93998524Sfenner{ 94098524Sfenner switch (FC_SUBTYPE(fc)) { 941214478Srpaulo case CTRL_CONTROL_WRAPPER: 942214478Srpaulo printf("Control Wrapper"); 943214478Srpaulo /* XXX - requires special handling */ 944214478Srpaulo break; 945170533Ssam case CTRL_BAR: 946170533Ssam printf("BAR"); 947170533Ssam if (!TTEST2(*p, CTRL_BAR_HDRLEN)) 948170533Ssam return 0; 949170533Ssam if (!eflag) 950170533Ssam printf(" RA:%s TA:%s CTL(%x) SEQ(%u) ", 951170533Ssam etheraddr_string(((const struct ctrl_bar_t *)p)->ra), 952170533Ssam etheraddr_string(((const struct ctrl_bar_t *)p)->ta), 953170533Ssam EXTRACT_LE_16BITS(&(((const struct ctrl_bar_t *)p)->ctl)), 954170533Ssam EXTRACT_LE_16BITS(&(((const struct ctrl_bar_t *)p)->seq))); 955170533Ssam break; 956195684Ssam case CTRL_BA: 957195684Ssam printf("BA"); 958195684Ssam if (!TTEST2(*p, CTRL_BA_HDRLEN)) 959195684Ssam return 0; 960195684Ssam if (!eflag) 961195684Ssam printf(" RA:%s ", 962195684Ssam etheraddr_string(((const struct ctrl_ba_t *)p)->ra)); 963195684Ssam break; 96498524Sfenner case CTRL_PS_POLL: 965127668Sbms printf("Power Save-Poll"); 966127668Sbms if (!TTEST2(*p, CTRL_PS_POLL_HDRLEN)) 96798524Sfenner return 0; 968127668Sbms printf(" AID(%x)", 96998524Sfenner EXTRACT_LE_16BITS(&(((const struct ctrl_ps_poll_t *)p)->aid))); 97098524Sfenner break; 97198524Sfenner case CTRL_RTS: 972127668Sbms printf("Request-To-Send"); 973127668Sbms if (!TTEST2(*p, CTRL_RTS_HDRLEN)) 97498524Sfenner return 0; 975127668Sbms if (!eflag) 976127668Sbms printf(" TA:%s ", 97798524Sfenner etheraddr_string(((const struct ctrl_rts_t *)p)->ta)); 97898524Sfenner break; 97998524Sfenner case CTRL_CTS: 980127668Sbms printf("Clear-To-Send"); 981127668Sbms if (!TTEST2(*p, CTRL_CTS_HDRLEN)) 98298524Sfenner return 0; 983127668Sbms if (!eflag) 984127668Sbms printf(" RA:%s ", 98598524Sfenner etheraddr_string(((const struct ctrl_cts_t *)p)->ra)); 98698524Sfenner break; 98798524Sfenner case CTRL_ACK: 988127668Sbms printf("Acknowledgment"); 989127668Sbms if (!TTEST2(*p, CTRL_ACK_HDRLEN)) 99098524Sfenner return 0; 991127668Sbms if (!eflag) 992127668Sbms printf(" RA:%s ", 99398524Sfenner etheraddr_string(((const struct ctrl_ack_t *)p)->ra)); 99498524Sfenner break; 99598524Sfenner case CTRL_CF_END: 996127668Sbms printf("CF-End"); 997127668Sbms if (!TTEST2(*p, CTRL_END_HDRLEN)) 99898524Sfenner return 0; 999127668Sbms if (!eflag) 1000127668Sbms printf(" RA:%s ", 100198524Sfenner etheraddr_string(((const struct ctrl_end_t *)p)->ra)); 100298524Sfenner break; 100398524Sfenner case CTRL_END_ACK: 1004127668Sbms printf("CF-End+CF-Ack"); 1005127668Sbms if (!TTEST2(*p, CTRL_END_ACK_HDRLEN)) 100698524Sfenner return 0; 1007127668Sbms if (!eflag) 1008127668Sbms printf(" RA:%s ", 100998524Sfenner etheraddr_string(((const struct ctrl_end_ack_t *)p)->ra)); 101098524Sfenner break; 101198524Sfenner default: 1012127668Sbms printf("Unknown Ctrl Subtype"); 101398524Sfenner } 101498524Sfenner return 1; 101598524Sfenner} 101698524Sfenner 101798524Sfenner/* 101898524Sfenner * Print Header funcs 101998524Sfenner */ 102098524Sfenner 102198524Sfenner/* 102298524Sfenner * Data Frame - Address field contents 102398524Sfenner * 102498524Sfenner * To Ds | From DS | Addr 1 | Addr 2 | Addr 3 | Addr 4 102598524Sfenner * 0 | 0 | DA | SA | BSSID | n/a 102698524Sfenner * 0 | 1 | DA | BSSID | SA | n/a 102798524Sfenner * 1 | 0 | BSSID | SA | DA | n/a 102898524Sfenner * 1 | 1 | RA | TA | DA | SA 102998524Sfenner */ 103098524Sfenner 1031127668Sbmsstatic void 1032127668Sbmsdata_header_print(u_int16_t fc, const u_char *p, const u_int8_t **srcp, 1033127668Sbms const u_int8_t **dstp) 103498524Sfenner{ 1035172686Smlaier u_int subtype = FC_SUBTYPE(fc); 1036172686Smlaier 1037172686Smlaier if (DATA_FRAME_IS_CF_ACK(subtype) || DATA_FRAME_IS_CF_POLL(subtype) || 1038172686Smlaier DATA_FRAME_IS_QOS(subtype)) { 1039172686Smlaier printf("CF "); 1040172686Smlaier if (DATA_FRAME_IS_CF_ACK(subtype)) { 1041172686Smlaier if (DATA_FRAME_IS_CF_POLL(subtype)) 1042172686Smlaier printf("Ack/Poll"); 1043172686Smlaier else 1044172686Smlaier printf("Ack"); 1045172686Smlaier } else { 1046172686Smlaier if (DATA_FRAME_IS_CF_POLL(subtype)) 1047172686Smlaier printf("Poll"); 1048172686Smlaier } 1049172686Smlaier if (DATA_FRAME_IS_QOS(subtype)) 1050172686Smlaier printf("+QoS"); 1051172686Smlaier printf(" "); 1052127668Sbms } 1053127668Sbms 105498524Sfenner#define ADDR1 (p + 4) 105598524Sfenner#define ADDR2 (p + 10) 105698524Sfenner#define ADDR3 (p + 16) 105798524Sfenner#define ADDR4 (p + 24) 105898524Sfenner 1059127668Sbms if (!FC_TO_DS(fc) && !FC_FROM_DS(fc)) { 1060127668Sbms if (srcp != NULL) 1061127668Sbms *srcp = ADDR2; 1062127668Sbms if (dstp != NULL) 1063127668Sbms *dstp = ADDR1; 1064127668Sbms if (!eflag) 1065127668Sbms return; 1066127668Sbms printf("DA:%s SA:%s BSSID:%s ", 1067127668Sbms etheraddr_string(ADDR1), etheraddr_string(ADDR2), 1068127668Sbms etheraddr_string(ADDR3)); 1069127668Sbms } else if (!FC_TO_DS(fc) && FC_FROM_DS(fc)) { 1070127668Sbms if (srcp != NULL) 1071127668Sbms *srcp = ADDR3; 1072127668Sbms if (dstp != NULL) 1073127668Sbms *dstp = ADDR1; 1074127668Sbms if (!eflag) 1075127668Sbms return; 1076127668Sbms printf("DA:%s BSSID:%s SA:%s ", 1077127668Sbms etheraddr_string(ADDR1), etheraddr_string(ADDR2), 1078127668Sbms etheraddr_string(ADDR3)); 1079127668Sbms } else if (FC_TO_DS(fc) && !FC_FROM_DS(fc)) { 1080127668Sbms if (srcp != NULL) 1081127668Sbms *srcp = ADDR2; 1082127668Sbms if (dstp != NULL) 1083127668Sbms *dstp = ADDR3; 1084127668Sbms if (!eflag) 1085127668Sbms return; 1086127668Sbms printf("BSSID:%s SA:%s DA:%s ", 1087127668Sbms etheraddr_string(ADDR1), etheraddr_string(ADDR2), 1088127668Sbms etheraddr_string(ADDR3)); 1089127668Sbms } else if (FC_TO_DS(fc) && FC_FROM_DS(fc)) { 1090127668Sbms if (srcp != NULL) 1091127668Sbms *srcp = ADDR4; 1092127668Sbms if (dstp != NULL) 1093127668Sbms *dstp = ADDR3; 1094127668Sbms if (!eflag) 1095127668Sbms return; 1096127668Sbms printf("RA:%s TA:%s DA:%s SA:%s ", 1097127668Sbms etheraddr_string(ADDR1), etheraddr_string(ADDR2), 1098127668Sbms etheraddr_string(ADDR3), etheraddr_string(ADDR4)); 109998524Sfenner } 110098524Sfenner 110198524Sfenner#undef ADDR1 110298524Sfenner#undef ADDR2 110398524Sfenner#undef ADDR3 110498524Sfenner#undef ADDR4 110598524Sfenner} 110698524Sfenner 1107127668Sbmsstatic void 1108127668Sbmsmgmt_header_print(const u_char *p, const u_int8_t **srcp, 1109127668Sbms const u_int8_t **dstp) 111098524Sfenner{ 111198524Sfenner const struct mgmt_header_t *hp = (const struct mgmt_header_t *) p; 111298524Sfenner 1113127668Sbms if (srcp != NULL) 1114127668Sbms *srcp = hp->sa; 1115127668Sbms if (dstp != NULL) 1116127668Sbms *dstp = hp->da; 1117127668Sbms if (!eflag) 1118127668Sbms return; 1119127668Sbms 112098524Sfenner printf("BSSID:%s DA:%s SA:%s ", 112198524Sfenner etheraddr_string((hp)->bssid), etheraddr_string((hp)->da), 112298524Sfenner etheraddr_string((hp)->sa)); 112398524Sfenner} 112498524Sfenner 1125127668Sbmsstatic void 1126127668Sbmsctrl_header_print(u_int16_t fc, const u_char *p, const u_int8_t **srcp, 1127127668Sbms const u_int8_t **dstp) 112898524Sfenner{ 1129127668Sbms if (srcp != NULL) 1130127668Sbms *srcp = NULL; 1131127668Sbms if (dstp != NULL) 1132127668Sbms *dstp = NULL; 1133127668Sbms if (!eflag) 1134127668Sbms return; 1135127668Sbms 113698524Sfenner switch (FC_SUBTYPE(fc)) { 1137170533Ssam case CTRL_BAR: 1138170533Ssam printf(" RA:%s TA:%s CTL(%x) SEQ(%u) ", 1139170533Ssam etheraddr_string(((const struct ctrl_bar_t *)p)->ra), 1140170533Ssam etheraddr_string(((const struct ctrl_bar_t *)p)->ta), 1141170533Ssam EXTRACT_LE_16BITS(&(((const struct ctrl_bar_t *)p)->ctl)), 1142170533Ssam EXTRACT_LE_16BITS(&(((const struct ctrl_bar_t *)p)->seq))); 1143170533Ssam break; 1144195684Ssam case CTRL_BA: 1145195684Ssam printf("RA:%s ", 1146195684Ssam etheraddr_string(((const struct ctrl_ba_t *)p)->ra)); 1147195684Ssam break; 114898524Sfenner case CTRL_PS_POLL: 114998524Sfenner printf("BSSID:%s TA:%s ", 115098524Sfenner etheraddr_string(((const struct ctrl_ps_poll_t *)p)->bssid), 115198524Sfenner etheraddr_string(((const struct ctrl_ps_poll_t *)p)->ta)); 115298524Sfenner break; 115398524Sfenner case CTRL_RTS: 115498524Sfenner printf("RA:%s TA:%s ", 115598524Sfenner etheraddr_string(((const struct ctrl_rts_t *)p)->ra), 115698524Sfenner etheraddr_string(((const struct ctrl_rts_t *)p)->ta)); 115798524Sfenner break; 115898524Sfenner case CTRL_CTS: 115998524Sfenner printf("RA:%s ", 116098524Sfenner etheraddr_string(((const struct ctrl_cts_t *)p)->ra)); 116198524Sfenner break; 116298524Sfenner case CTRL_ACK: 116398524Sfenner printf("RA:%s ", 116498524Sfenner etheraddr_string(((const struct ctrl_ack_t *)p)->ra)); 116598524Sfenner break; 116698524Sfenner case CTRL_CF_END: 116798524Sfenner printf("RA:%s BSSID:%s ", 116898524Sfenner etheraddr_string(((const struct ctrl_end_t *)p)->ra), 116998524Sfenner etheraddr_string(((const struct ctrl_end_t *)p)->bssid)); 117098524Sfenner break; 117198524Sfenner case CTRL_END_ACK: 117298524Sfenner printf("RA:%s BSSID:%s ", 117398524Sfenner etheraddr_string(((const struct ctrl_end_ack_t *)p)->ra), 117498524Sfenner etheraddr_string(((const struct ctrl_end_ack_t *)p)->bssid)); 117598524Sfenner break; 117698524Sfenner default: 117798524Sfenner printf("(H) Unknown Ctrl Subtype"); 1178127668Sbms break; 117998524Sfenner } 118098524Sfenner} 118198524Sfenner 1182127668Sbmsstatic int 1183127668Sbmsextract_header_length(u_int16_t fc) 118498524Sfenner{ 1185172686Smlaier int len; 1186172686Smlaier 118798524Sfenner switch (FC_TYPE(fc)) { 118898524Sfenner case T_MGMT: 1189127668Sbms return MGMT_HDRLEN; 119098524Sfenner case T_CTRL: 119198524Sfenner switch (FC_SUBTYPE(fc)) { 1192170533Ssam case CTRL_BAR: 1193170533Ssam return CTRL_BAR_HDRLEN; 119498524Sfenner case CTRL_PS_POLL: 1195127668Sbms return CTRL_PS_POLL_HDRLEN; 119698524Sfenner case CTRL_RTS: 1197127668Sbms return CTRL_RTS_HDRLEN; 119898524Sfenner case CTRL_CTS: 1199127668Sbms return CTRL_CTS_HDRLEN; 120098524Sfenner case CTRL_ACK: 1201127668Sbms return CTRL_ACK_HDRLEN; 120298524Sfenner case CTRL_CF_END: 1203127668Sbms return CTRL_END_HDRLEN; 120498524Sfenner case CTRL_END_ACK: 1205127668Sbms return CTRL_END_ACK_HDRLEN; 120698524Sfenner default: 1207127668Sbms return 0; 120898524Sfenner } 120998524Sfenner case T_DATA: 1210172686Smlaier len = (FC_TO_DS(fc) && FC_FROM_DS(fc)) ? 30 : 24; 1211172686Smlaier if (DATA_FRAME_IS_QOS(FC_SUBTYPE(fc))) 1212172686Smlaier len += 2; 1213172686Smlaier return len; 121498524Sfenner default: 1215127668Sbms printf("unknown IEEE802.11 frame type (%d)", FC_TYPE(fc)); 1216127668Sbms return 0; 121798524Sfenner } 121898524Sfenner} 121998524Sfenner 1220195684Ssamstatic int 1221195684Ssamextract_mesh_header_length(const u_char *p) 1222195684Ssam{ 1223195684Ssam return (p[0] &~ 3) ? 0 : 6*(1 + (p[0] & 3)); 1224195684Ssam} 1225195684Ssam 122698524Sfenner/* 1227127668Sbms * Print the 802.11 MAC header if eflag is set, and set "*srcp" and "*dstp" 1228127668Sbms * to point to the source and destination MAC addresses in any case if 1229127668Sbms * "srcp" and "dstp" aren't null. 123098524Sfenner */ 1231195684Ssamstatic void 1232195684Ssamieee_802_11_hdr_print(u_int16_t fc, const u_char *p, u_int hdrlen, 1233195684Ssam u_int meshdrlen, const u_int8_t **srcp, const u_int8_t **dstp) 123498524Sfenner{ 1235127668Sbms if (vflag) { 1236127668Sbms if (FC_MORE_DATA(fc)) 1237127668Sbms printf("More Data "); 1238127668Sbms if (FC_MORE_FLAG(fc)) 1239127668Sbms printf("More Fragments "); 1240127668Sbms if (FC_POWER_MGMT(fc)) 1241127668Sbms printf("Pwr Mgmt "); 1242127668Sbms if (FC_RETRY(fc)) 1243127668Sbms printf("Retry "); 1244127668Sbms if (FC_ORDER(fc)) 1245127668Sbms printf("Strictly Ordered "); 1246127668Sbms if (FC_WEP(fc)) 1247127668Sbms printf("WEP Encrypted "); 1248127668Sbms if (FC_TYPE(fc) != T_CTRL || FC_SUBTYPE(fc) != CTRL_PS_POLL) 1249127668Sbms printf("%dus ", 1250127668Sbms EXTRACT_LE_16BITS( 1251127668Sbms &((const struct mgmt_header_t *)p)->duration)); 1252127668Sbms } 1253195684Ssam if (meshdrlen != 0) { 1254195684Ssam const struct meshcntl_t *mc = 1255195684Ssam (const struct meshcntl_t *)&p[hdrlen - meshdrlen]; 1256195684Ssam int ae = mc->flags & 3; 1257127668Sbms 1258195684Ssam printf("MeshData (AE %d TTL %u seq %u", ae, mc->ttl, 1259195684Ssam EXTRACT_LE_32BITS(mc->seq)); 1260195684Ssam if (ae > 0) 1261195684Ssam printf(" A4:%s", etheraddr_string(mc->addr4)); 1262195684Ssam if (ae > 1) 1263195684Ssam printf(" A5:%s", etheraddr_string(mc->addr5)); 1264195684Ssam if (ae > 2) 1265195684Ssam printf(" A6:%s", etheraddr_string(mc->addr6)); 1266195684Ssam printf(") "); 1267195684Ssam } 1268195684Ssam 126998524Sfenner switch (FC_TYPE(fc)) { 127098524Sfenner case T_MGMT: 1271127668Sbms mgmt_header_print(p, srcp, dstp); 127298524Sfenner break; 127398524Sfenner case T_CTRL: 1274127668Sbms ctrl_header_print(fc, p, srcp, dstp); 127598524Sfenner break; 127698524Sfenner case T_DATA: 1277127668Sbms data_header_print(fc, p, srcp, dstp); 127898524Sfenner break; 127998524Sfenner default: 128098524Sfenner printf("(header) unknown IEEE802.11 frame type (%d)", 128198524Sfenner FC_TYPE(fc)); 1282127668Sbms *srcp = NULL; 1283127668Sbms *dstp = NULL; 128498524Sfenner break; 128598524Sfenner } 128698524Sfenner} 128798524Sfenner 1288172686Smlaier#ifndef roundup2 1289172686Smlaier#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */ 1290172686Smlaier#endif 1291172686Smlaier 1292127668Sbmsstatic u_int 1293214478Srpauloieee802_11_print(const u_char *p, u_int length, u_int orig_caplen, int pad, 1294214478Srpaulo u_int fcslen) 129598524Sfenner{ 129698524Sfenner u_int16_t fc; 1297214478Srpaulo u_int caplen, hdrlen, meshdrlen; 1298127668Sbms const u_int8_t *src, *dst; 129998524Sfenner u_short extracted_ethertype; 130098524Sfenner 1301214478Srpaulo caplen = orig_caplen; 1302214478Srpaulo /* Remove FCS, if present */ 1303214478Srpaulo if (length < fcslen) { 130498524Sfenner printf("[|802.11]"); 1305127668Sbms return caplen; 130698524Sfenner } 1307214478Srpaulo length -= fcslen; 1308214478Srpaulo if (caplen > length) { 1309214478Srpaulo /* Amount of FCS in actual packet data, if any */ 1310214478Srpaulo fcslen = caplen - length; 1311214478Srpaulo caplen -= fcslen; 1312214478Srpaulo snapend -= fcslen; 1313214478Srpaulo } 131498524Sfenner 1315214478Srpaulo if (caplen < IEEE802_11_FC_LEN) { 1316214478Srpaulo printf("[|802.11]"); 1317214478Srpaulo return orig_caplen; 1318214478Srpaulo } 1319214478Srpaulo 1320127668Sbms fc = EXTRACT_LE_16BITS(p); 1321127668Sbms hdrlen = extract_header_length(fc); 1322172686Smlaier if (pad) 1323172686Smlaier hdrlen = roundup2(hdrlen, 4); 1324195684Ssam if (FC_TYPE(fc) == T_DATA && DATA_FRAME_IS_QOS(FC_SUBTYPE(fc))) { 1325195684Ssam meshdrlen = extract_mesh_header_length(p+hdrlen); 1326195684Ssam hdrlen += meshdrlen; 1327195684Ssam } else 1328195684Ssam meshdrlen = 0; 132998524Sfenner 1330195684Ssam 1331127668Sbms if (caplen < hdrlen) { 1332127668Sbms printf("[|802.11]"); 1333127668Sbms return hdrlen; 1334127668Sbms } 133598524Sfenner 1336195684Ssam ieee_802_11_hdr_print(fc, p, hdrlen, meshdrlen, &src, &dst); 1337127668Sbms 133898524Sfenner /* 1339127668Sbms * Go past the 802.11 header. 134098524Sfenner */ 1341127668Sbms length -= hdrlen; 1342127668Sbms caplen -= hdrlen; 1343127668Sbms p += hdrlen; 134498524Sfenner 134598524Sfenner switch (FC_TYPE(fc)) { 134698524Sfenner case T_MGMT: 1347127668Sbms if (!mgmt_body_print(fc, 1348214478Srpaulo (const struct mgmt_header_t *)(p - hdrlen), p, length)) { 134998524Sfenner printf("[|802.11]"); 1350127668Sbms return hdrlen; 135198524Sfenner } 135298524Sfenner break; 135398524Sfenner case T_CTRL: 1354127668Sbms if (!ctrl_body_print(fc, p - hdrlen)) { 135598524Sfenner printf("[|802.11]"); 1356127668Sbms return hdrlen; 135798524Sfenner } 135898524Sfenner break; 135998524Sfenner case T_DATA: 1360172686Smlaier if (DATA_FRAME_IS_NULL(FC_SUBTYPE(fc))) 1361172686Smlaier return hdrlen; /* no-data frame */ 136298524Sfenner /* There may be a problem w/ AP not having this bit set */ 1363127668Sbms if (FC_WEP(fc)) { 1364127668Sbms if (!wep_print(p)) { 136598524Sfenner printf("[|802.11]"); 1366127668Sbms return hdrlen; 136798524Sfenner } 1368127668Sbms } else if (llc_print(p, length, caplen, dst, src, 1369127668Sbms &extracted_ethertype) == 0) { 1370127668Sbms /* 1371127668Sbms * Some kinds of LLC packet we cannot 1372127668Sbms * handle intelligently 1373127668Sbms */ 1374127668Sbms if (!eflag) 1375195684Ssam ieee_802_11_hdr_print(fc, p - hdrlen, hdrlen, 1376195684Ssam meshdrlen, NULL, NULL); 1377127668Sbms if (extracted_ethertype) 1378127668Sbms printf("(LLC %s) ", 1379127668Sbms etherproto_string( 1380127668Sbms htons(extracted_ethertype))); 1381162017Ssam if (!suppress_default_print) 1382127668Sbms default_print(p, caplen); 138398524Sfenner } 138498524Sfenner break; 138598524Sfenner default: 1386127668Sbms printf("unknown 802.11 frame type (%d)", FC_TYPE(fc)); 138798524Sfenner break; 138898524Sfenner } 138998524Sfenner 1390127668Sbms return hdrlen; 139198524Sfenner} 1392127668Sbms 1393127668Sbms/* 1394127668Sbms * This is the top level routine of the printer. 'p' points 1395127668Sbms * to the 802.11 header of the packet, 'h->ts' is the timestamp, 1396146773Ssam * 'h->len' is the length of the packet off the wire, and 'h->caplen' 1397127668Sbms * is the number of bytes actually captured. 1398127668Sbms */ 1399127668Sbmsu_int 1400127668Sbmsieee802_11_if_print(const struct pcap_pkthdr *h, const u_char *p) 1401127668Sbms{ 1402214478Srpaulo return ieee802_11_print(p, h->len, h->caplen, 0, 0); 1403127668Sbms} 1404127668Sbms 1405170533Ssam#define IEEE80211_CHAN_FHSS \ 1406170533Ssam (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK) 1407170533Ssam#define IEEE80211_CHAN_A \ 1408170533Ssam (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM) 1409170533Ssam#define IEEE80211_CHAN_B \ 1410170533Ssam (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK) 1411170533Ssam#define IEEE80211_CHAN_PUREG \ 1412170533Ssam (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM) 1413170533Ssam#define IEEE80211_CHAN_G \ 1414170533Ssam (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN) 1415170533Ssam 1416170533Ssam#define IS_CHAN_FHSS(flags) \ 1417170533Ssam ((flags & IEEE80211_CHAN_FHSS) == IEEE80211_CHAN_FHSS) 1418170533Ssam#define IS_CHAN_A(flags) \ 1419170533Ssam ((flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) 1420170533Ssam#define IS_CHAN_B(flags) \ 1421170533Ssam ((flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B) 1422170533Ssam#define IS_CHAN_PUREG(flags) \ 1423170533Ssam ((flags & IEEE80211_CHAN_PUREG) == IEEE80211_CHAN_PUREG) 1424170533Ssam#define IS_CHAN_G(flags) \ 1425170533Ssam ((flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) 1426170533Ssam#define IS_CHAN_ANYG(flags) \ 1427170533Ssam (IS_CHAN_PUREG(flags) || IS_CHAN_G(flags)) 1428170533Ssam 1429170533Ssamstatic void 1430170533Ssamprint_chaninfo(int freq, int flags) 1431170533Ssam{ 1432170533Ssam printf("%u MHz", freq); 1433170533Ssam if (IS_CHAN_FHSS(flags)) 1434170533Ssam printf(" FHSS"); 1435170533Ssam if (IS_CHAN_A(flags)) { 1436170533Ssam if (flags & IEEE80211_CHAN_HALF) 1437170533Ssam printf(" 11a/10Mhz"); 1438170533Ssam else if (flags & IEEE80211_CHAN_QUARTER) 1439170533Ssam printf(" 11a/5Mhz"); 1440170533Ssam else 1441170533Ssam printf(" 11a"); 1442170533Ssam } 1443170533Ssam if (IS_CHAN_ANYG(flags)) { 1444170533Ssam if (flags & IEEE80211_CHAN_HALF) 1445170533Ssam printf(" 11g/10Mhz"); 1446170533Ssam else if (flags & IEEE80211_CHAN_QUARTER) 1447170533Ssam printf(" 11g/5Mhz"); 1448170533Ssam else 1449170533Ssam printf(" 11g"); 1450170533Ssam } else if (IS_CHAN_B(flags)) 1451170533Ssam printf(" 11b"); 1452170533Ssam if (flags & IEEE80211_CHAN_TURBO) 1453170533Ssam printf(" Turbo"); 1454170533Ssam if (flags & IEEE80211_CHAN_HT20) 1455170533Ssam printf(" ht/20"); 1456170533Ssam else if (flags & IEEE80211_CHAN_HT40D) 1457170533Ssam printf(" ht/40-"); 1458170533Ssam else if (flags & IEEE80211_CHAN_HT40U) 1459170533Ssam printf(" ht/40+"); 1460170533Ssam printf(" "); 1461170533Ssam} 1462170533Ssam 1463146773Ssamstatic int 1464214478Srpauloprint_radiotap_field(struct cpack_state *s, u_int32_t bit, u_int8_t *flags) 1465146773Ssam{ 1466146773Ssam union { 1467146773Ssam int8_t i8; 1468146773Ssam u_int8_t u8; 1469146773Ssam int16_t i16; 1470146773Ssam u_int16_t u16; 1471146773Ssam u_int32_t u32; 1472146773Ssam u_int64_t u64; 1473170533Ssam } u, u2, u3, u4; 1474146773Ssam int rc; 1475146773Ssam 1476146773Ssam switch (bit) { 1477146773Ssam case IEEE80211_RADIOTAP_FLAGS: 1478172686Smlaier rc = cpack_uint8(s, &u.u8); 1479214478Srpaulo *flags = u.u8; 1480172686Smlaier break; 1481146773Ssam case IEEE80211_RADIOTAP_RATE: 1482146773Ssam case IEEE80211_RADIOTAP_DB_ANTSIGNAL: 1483146773Ssam case IEEE80211_RADIOTAP_DB_ANTNOISE: 1484146773Ssam case IEEE80211_RADIOTAP_ANTENNA: 1485146773Ssam rc = cpack_uint8(s, &u.u8); 1486146773Ssam break; 1487146773Ssam case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: 1488146773Ssam case IEEE80211_RADIOTAP_DBM_ANTNOISE: 1489146773Ssam rc = cpack_int8(s, &u.i8); 1490146773Ssam break; 1491146773Ssam case IEEE80211_RADIOTAP_CHANNEL: 1492146773Ssam rc = cpack_uint16(s, &u.u16); 1493146773Ssam if (rc != 0) 1494146773Ssam break; 1495146773Ssam rc = cpack_uint16(s, &u2.u16); 1496146773Ssam break; 1497146773Ssam case IEEE80211_RADIOTAP_FHSS: 1498146773Ssam case IEEE80211_RADIOTAP_LOCK_QUALITY: 1499146773Ssam case IEEE80211_RADIOTAP_TX_ATTENUATION: 1500146773Ssam rc = cpack_uint16(s, &u.u16); 1501146773Ssam break; 1502146773Ssam case IEEE80211_RADIOTAP_DB_TX_ATTENUATION: 1503146773Ssam rc = cpack_uint8(s, &u.u8); 1504146773Ssam break; 1505146773Ssam case IEEE80211_RADIOTAP_DBM_TX_POWER: 1506146773Ssam rc = cpack_int8(s, &u.i8); 1507146773Ssam break; 1508146773Ssam case IEEE80211_RADIOTAP_TSFT: 1509146773Ssam rc = cpack_uint64(s, &u.u64); 1510146773Ssam break; 1511170533Ssam case IEEE80211_RADIOTAP_XCHANNEL: 1512170533Ssam rc = cpack_uint32(s, &u.u32); 1513170533Ssam if (rc != 0) 1514170533Ssam break; 1515170533Ssam rc = cpack_uint16(s, &u2.u16); 1516170533Ssam if (rc != 0) 1517170533Ssam break; 1518170533Ssam rc = cpack_uint8(s, &u3.u8); 1519170533Ssam if (rc != 0) 1520170533Ssam break; 1521170533Ssam rc = cpack_uint8(s, &u4.u8); 1522170533Ssam break; 1523146773Ssam default: 1524146773Ssam /* this bit indicates a field whose 1525146773Ssam * size we do not know, so we cannot 1526214478Srpaulo * proceed. Just print the bit number. 1527146773Ssam */ 1528214478Srpaulo printf("[bit %u] ", bit); 1529146773Ssam return -1; 1530146773Ssam } 1531146773Ssam 1532146773Ssam if (rc != 0) { 1533146773Ssam printf("[|802.11]"); 1534146773Ssam return rc; 1535146773Ssam } 1536146773Ssam 1537146773Ssam switch (bit) { 1538146773Ssam case IEEE80211_RADIOTAP_CHANNEL: 1539170533Ssam print_chaninfo(u.u16, u2.u16); 1540146773Ssam break; 1541146773Ssam case IEEE80211_RADIOTAP_FHSS: 1542146773Ssam printf("fhset %d fhpat %d ", u.u16 & 0xff, (u.u16 >> 8) & 0xff); 1543146773Ssam break; 1544146773Ssam case IEEE80211_RADIOTAP_RATE: 1545170533Ssam if (u.u8 & 0x80) 1546176535Ssam PRINT_HT_RATE("", u.u8, " Mb/s "); 1547176535Ssam else 1548170533Ssam PRINT_RATE("", u.u8, " Mb/s "); 1549146773Ssam break; 1550146773Ssam case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: 1551146773Ssam printf("%ddB signal ", u.i8); 1552146773Ssam break; 1553146773Ssam case IEEE80211_RADIOTAP_DBM_ANTNOISE: 1554146773Ssam printf("%ddB noise ", u.i8); 1555146773Ssam break; 1556146773Ssam case IEEE80211_RADIOTAP_DB_ANTSIGNAL: 1557146773Ssam printf("%ddB signal ", u.u8); 1558146773Ssam break; 1559146773Ssam case IEEE80211_RADIOTAP_DB_ANTNOISE: 1560146773Ssam printf("%ddB noise ", u.u8); 1561146773Ssam break; 1562146773Ssam case IEEE80211_RADIOTAP_LOCK_QUALITY: 1563146773Ssam printf("%u sq ", u.u16); 1564146773Ssam break; 1565146773Ssam case IEEE80211_RADIOTAP_TX_ATTENUATION: 1566146773Ssam printf("%d tx power ", -(int)u.u16); 1567146773Ssam break; 1568146773Ssam case IEEE80211_RADIOTAP_DB_TX_ATTENUATION: 1569146773Ssam printf("%ddB tx power ", -(int)u.u8); 1570146773Ssam break; 1571146773Ssam case IEEE80211_RADIOTAP_DBM_TX_POWER: 1572146773Ssam printf("%ddBm tx power ", u.i8); 1573146773Ssam break; 1574146773Ssam case IEEE80211_RADIOTAP_FLAGS: 1575146773Ssam if (u.u8 & IEEE80211_RADIOTAP_F_CFP) 1576146773Ssam printf("cfp "); 1577146773Ssam if (u.u8 & IEEE80211_RADIOTAP_F_SHORTPRE) 1578146773Ssam printf("short preamble "); 1579146773Ssam if (u.u8 & IEEE80211_RADIOTAP_F_WEP) 1580146773Ssam printf("wep "); 1581146773Ssam if (u.u8 & IEEE80211_RADIOTAP_F_FRAG) 1582146773Ssam printf("fragmented "); 1583170533Ssam if (u.u8 & IEEE80211_RADIOTAP_F_BADFCS) 1584172686Smlaier printf("bad-fcs "); 1585146773Ssam break; 1586146773Ssam case IEEE80211_RADIOTAP_ANTENNA: 1587146773Ssam printf("antenna %d ", u.u8); 1588146773Ssam break; 1589146773Ssam case IEEE80211_RADIOTAP_TSFT: 1590146773Ssam printf("%" PRIu64 "us tsft ", u.u64); 1591146773Ssam break; 1592170533Ssam case IEEE80211_RADIOTAP_XCHANNEL: 1593170533Ssam print_chaninfo(u2.u16, u.u32); 1594170533Ssam break; 1595146773Ssam } 1596146773Ssam return 0; 1597146773Ssam} 1598146773Ssam 1599127668Sbmsstatic u_int 1600127668Sbmsieee802_11_radio_print(const u_char *p, u_int length, u_int caplen) 1601127668Sbms{ 1602146773Ssam#define BITNO_32(x) (((x) >> 16) ? 16 + BITNO_16((x) >> 16) : BITNO_16((x))) 1603146773Ssam#define BITNO_16(x) (((x) >> 8) ? 8 + BITNO_8((x) >> 8) : BITNO_8((x))) 1604146773Ssam#define BITNO_8(x) (((x) >> 4) ? 4 + BITNO_4((x) >> 4) : BITNO_4((x))) 1605146773Ssam#define BITNO_4(x) (((x) >> 2) ? 2 + BITNO_2((x) >> 2) : BITNO_2((x))) 1606146773Ssam#define BITNO_2(x) (((x) & 2) ? 1 : 0) 1607214478Srpaulo#define BIT(n) (1U << n) 1608146773Ssam#define IS_EXTENDED(__p) \ 1609146773Ssam (EXTRACT_LE_32BITS(__p) & BIT(IEEE80211_RADIOTAP_EXT)) != 0 1610146773Ssam 1611146773Ssam struct cpack_state cpacker; 1612146773Ssam struct ieee80211_radiotap_header *hdr; 1613146773Ssam u_int32_t present, next_present; 1614146773Ssam u_int32_t *presentp, *last_presentp; 1615146773Ssam enum ieee80211_radiotap_type bit; 1616146773Ssam int bit0; 1617146773Ssam const u_char *iter; 1618146773Ssam u_int len; 1619214478Srpaulo u_int8_t flags; 1620172686Smlaier int pad; 1621214478Srpaulo u_int fcslen; 1622146773Ssam 1623146773Ssam if (caplen < sizeof(*hdr)) { 1624146773Ssam printf("[|802.11]"); 1625146773Ssam return caplen; 1626146773Ssam } 1627146773Ssam 1628146773Ssam hdr = (struct ieee80211_radiotap_header *)p; 1629146773Ssam 1630146773Ssam len = EXTRACT_LE_16BITS(&hdr->it_len); 1631146773Ssam 1632146773Ssam if (caplen < len) { 1633146773Ssam printf("[|802.11]"); 1634146773Ssam return caplen; 1635146773Ssam } 1636146773Ssam for (last_presentp = &hdr->it_present; 1637146773Ssam IS_EXTENDED(last_presentp) && 1638146773Ssam (u_char*)(last_presentp + 1) <= p + len; 1639146773Ssam last_presentp++); 1640146773Ssam 1641146773Ssam /* are there more bitmap extensions than bytes in header? */ 1642146773Ssam if (IS_EXTENDED(last_presentp)) { 1643146773Ssam printf("[|802.11]"); 1644146773Ssam return caplen; 1645146773Ssam } 1646146773Ssam 1647146773Ssam iter = (u_char*)(last_presentp + 1); 1648146773Ssam 1649146773Ssam if (cpack_init(&cpacker, (u_int8_t*)iter, len - (iter - p)) != 0) { 1650146773Ssam /* XXX */ 1651146773Ssam printf("[|802.11]"); 1652146773Ssam return caplen; 1653146773Ssam } 1654146773Ssam 1655214478Srpaulo /* Assume no flags */ 1656214478Srpaulo flags = 0; 1657172686Smlaier /* Assume no Atheros padding between 802.11 header and body */ 1658172686Smlaier pad = 0; 1659214478Srpaulo /* Assume no FCS at end of frame */ 1660214478Srpaulo fcslen = 0; 1661146773Ssam for (bit0 = 0, presentp = &hdr->it_present; presentp <= last_presentp; 1662146773Ssam presentp++, bit0 += 32) { 1663146773Ssam for (present = EXTRACT_LE_32BITS(presentp); present; 1664146773Ssam present = next_present) { 1665146773Ssam /* clear the least significant bit that is set */ 1666146773Ssam next_present = present & (present - 1); 1667146773Ssam 1668146773Ssam /* extract the least significant bit that is set */ 1669147899Ssam bit = (enum ieee80211_radiotap_type) 1670147899Ssam (bit0 + BITNO_32(present ^ next_present)); 1671146773Ssam 1672214478Srpaulo if (print_radiotap_field(&cpacker, bit, &flags) != 0) 1673146773Ssam goto out; 1674146773Ssam } 1675146773Ssam } 1676214478Srpaulo 1677214478Srpaulo if (flags & IEEE80211_RADIOTAP_F_DATAPAD) 1678214478Srpaulo pad = 1; /* Atheros padding */ 1679214478Srpaulo if (flags & IEEE80211_RADIOTAP_F_FCS) 1680214478Srpaulo fcslen = 4; /* FCS at end of packet */ 1681146773Ssamout: 1682214478Srpaulo return len + ieee802_11_print(p + len, length - len, caplen - len, pad, 1683214478Srpaulo fcslen); 1684146773Ssam#undef BITNO_32 1685146773Ssam#undef BITNO_16 1686146773Ssam#undef BITNO_8 1687146773Ssam#undef BITNO_4 1688146773Ssam#undef BITNO_2 1689146773Ssam#undef BIT 1690146773Ssam} 1691146773Ssam 1692146773Ssamstatic u_int 1693146773Ssamieee802_11_avs_radio_print(const u_char *p, u_int length, u_int caplen) 1694146773Ssam{ 1695127668Sbms u_int32_t caphdr_len; 1696127668Sbms 1697190207Srpaulo if (caplen < 8) { 1698190207Srpaulo printf("[|802.11]"); 1699190207Srpaulo return caplen; 1700190207Srpaulo } 1701190207Srpaulo 1702127668Sbms caphdr_len = EXTRACT_32BITS(p + 4); 1703127668Sbms if (caphdr_len < 8) { 1704127668Sbms /* 1705127668Sbms * Yow! The capture header length is claimed not 1706127668Sbms * to be large enough to include even the version 1707127668Sbms * cookie or capture header length! 1708127668Sbms */ 1709127668Sbms printf("[|802.11]"); 1710127668Sbms return caplen; 1711127668Sbms } 1712127668Sbms 1713127668Sbms if (caplen < caphdr_len) { 1714127668Sbms printf("[|802.11]"); 1715127668Sbms return caplen; 1716127668Sbms } 1717127668Sbms 1718127668Sbms return caphdr_len + ieee802_11_print(p + caphdr_len, 1719214478Srpaulo length - caphdr_len, caplen - caphdr_len, 0, 0); 1720127668Sbms} 1721127668Sbms 1722127668Sbms#define PRISM_HDR_LEN 144 1723127668Sbms 1724190207Srpaulo#define WLANCAP_MAGIC_COOKIE_BASE 0x80211000 1725127668Sbms#define WLANCAP_MAGIC_COOKIE_V1 0x80211001 1726190207Srpaulo#define WLANCAP_MAGIC_COOKIE_V2 0x80211002 1727127668Sbms 1728127668Sbms/* 1729127668Sbms * For DLT_PRISM_HEADER; like DLT_IEEE802_11, but with an extra header, 1730127668Sbms * containing information such as radio information, which we 1731127668Sbms * currently ignore. 1732127668Sbms * 1733190207Srpaulo * If, however, the packet begins with WLANCAP_MAGIC_COOKIE_V1 or 1734190207Srpaulo * WLANCAP_MAGIC_COOKIE_V2, it's really DLT_IEEE802_11_RADIO_AVS 1735190207Srpaulo * (currently, on Linux, there's no ARPHRD_ type for 1736190207Srpaulo * DLT_IEEE802_11_RADIO_AVS, as there is a ARPHRD_IEEE80211_PRISM 1737190207Srpaulo * for DLT_PRISM_HEADER, so ARPHRD_IEEE80211_PRISM is used for 1738190207Srpaulo * the AVS header, and the first 4 bytes of the header are used to 1739190207Srpaulo * indicate whether it's a Prism header or an AVS header). 1740127668Sbms */ 1741127668Sbmsu_int 1742127668Sbmsprism_if_print(const struct pcap_pkthdr *h, const u_char *p) 1743127668Sbms{ 1744127668Sbms u_int caplen = h->caplen; 1745127668Sbms u_int length = h->len; 1746190207Srpaulo u_int32_t msgcode; 1747127668Sbms 1748127668Sbms if (caplen < 4) { 1749127668Sbms printf("[|802.11]"); 1750127668Sbms return caplen; 1751127668Sbms } 1752127668Sbms 1753190207Srpaulo msgcode = EXTRACT_32BITS(p); 1754190207Srpaulo if (msgcode == WLANCAP_MAGIC_COOKIE_V1 || 1755190207Srpaulo msgcode == WLANCAP_MAGIC_COOKIE_V2) 1756146773Ssam return ieee802_11_avs_radio_print(p, length, caplen); 1757127668Sbms 1758127668Sbms if (caplen < PRISM_HDR_LEN) { 1759127668Sbms printf("[|802.11]"); 1760127668Sbms return caplen; 1761127668Sbms } 1762127668Sbms 1763127668Sbms return PRISM_HDR_LEN + ieee802_11_print(p + PRISM_HDR_LEN, 1764214478Srpaulo length - PRISM_HDR_LEN, caplen - PRISM_HDR_LEN, 0, 0); 1765127668Sbms} 1766127668Sbms 1767127668Sbms/* 1768127668Sbms * For DLT_IEEE802_11_RADIO; like DLT_IEEE802_11, but with an extra 1769190207Srpaulo * header, containing information such as radio information. 1770127668Sbms */ 1771127668Sbmsu_int 1772127668Sbmsieee802_11_radio_if_print(const struct pcap_pkthdr *h, const u_char *p) 1773127668Sbms{ 1774190207Srpaulo return ieee802_11_radio_print(p, h->len, h->caplen); 1775190207Srpaulo} 1776127668Sbms 1777190207Srpaulo/* 1778190207Srpaulo * For DLT_IEEE802_11_RADIO_AVS; like DLT_IEEE802_11, but with an 1779190207Srpaulo * extra header, containing information such as radio information, 1780190207Srpaulo * which we currently ignore. 1781190207Srpaulo */ 1782190207Srpaulou_int 1783190207Srpauloieee802_11_radio_avs_if_print(const struct pcap_pkthdr *h, const u_char *p) 1784190207Srpaulo{ 1785190207Srpaulo return ieee802_11_avs_radio_print(p, h->len, h->caplen); 1786127668Sbms} 1787