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 49235530Sdelphij/* Radiotap state */ 50235530Sdelphij/* This is used to save state when parsing/processing parameters */ 51235530Sdelphijstruct radiotap_state 52235530Sdelphij{ 53235530Sdelphij u_int32_t present; 54235530Sdelphij 55235530Sdelphij u_int8_t rate; 56235530Sdelphij}; 57235530Sdelphij 58172686Smlaier#define PRINT_SSID(p) \ 59214478Srpaulo if (p.ssid_present) { \ 60172686Smlaier printf(" ("); \ 61172686Smlaier fn_print(p.ssid.ssid, NULL); \ 62172686Smlaier printf(")"); \ 63172686Smlaier } 64172686Smlaier 65146773Ssam#define PRINT_RATE(_sep, _r, _suf) \ 66146773Ssam printf("%s%2.1f%s", _sep, (.5 * ((_r) & 0x7f)), _suf) 67111726Sfenner#define PRINT_RATES(p) \ 68214478Srpaulo if (p.rates_present) { \ 69214478Srpaulo int z; \ 70214478Srpaulo const char *sep = " ["; \ 71214478Srpaulo for (z = 0; z < p.rates.length ; z++) { \ 72214478Srpaulo PRINT_RATE(sep, p.rates.rate[z], \ 73214478Srpaulo (p.rates.rate[z] & 0x80 ? "*" : "")); \ 74214478Srpaulo sep = " "; \ 75214478Srpaulo } \ 76214478Srpaulo if (p.rates.length != 0) \ 77214478Srpaulo printf(" Mbit]"); \ 78172686Smlaier } 79172686Smlaier 80172686Smlaier#define PRINT_DS_CHANNEL(p) \ 81214478Srpaulo if (p.ds_present) \ 82172686Smlaier printf(" CH: %u", p.ds.channel); \ 83172686Smlaier printf("%s", \ 84172686Smlaier CAPABILITY_PRIVACY(p.capability_info) ? ", PRIVACY" : "" ); 8598524Sfenner 86235530Sdelphij#define MAX_MCS_INDEX 76 87235530Sdelphij 88235530Sdelphij/* 89235530Sdelphij * Indices are: 90235530Sdelphij * 91235530Sdelphij * the MCS index (0-76); 92235530Sdelphij * 93235530Sdelphij * 0 for 20 MHz, 1 for 40 MHz; 94235530Sdelphij * 95235530Sdelphij * 0 for a long guard interval, 1 for a short guard interval. 96235530Sdelphij */ 97235530Sdelphijstatic const float ieee80211_float_htrates[MAX_MCS_INDEX+1][2][2] = { 98235530Sdelphij /* MCS 0 */ 99235530Sdelphij { /* 20 Mhz */ { 6.5, /* SGI */ 7.2, }, 100235530Sdelphij /* 40 Mhz */ { 13.5, /* SGI */ 15.0, }, 101235530Sdelphij }, 102235530Sdelphij 103235530Sdelphij /* MCS 1 */ 104235530Sdelphij { /* 20 Mhz */ { 13.0, /* SGI */ 14.4, }, 105235530Sdelphij /* 40 Mhz */ { 27.0, /* SGI */ 30.0, }, 106235530Sdelphij }, 107235530Sdelphij 108235530Sdelphij /* MCS 2 */ 109235530Sdelphij { /* 20 Mhz */ { 19.5, /* SGI */ 21.7, }, 110235530Sdelphij /* 40 Mhz */ { 40.5, /* SGI */ 45.0, }, 111235530Sdelphij }, 112235530Sdelphij 113235530Sdelphij /* MCS 3 */ 114235530Sdelphij { /* 20 Mhz */ { 26.0, /* SGI */ 28.9, }, 115235530Sdelphij /* 40 Mhz */ { 54.0, /* SGI */ 60.0, }, 116235530Sdelphij }, 117235530Sdelphij 118235530Sdelphij /* MCS 4 */ 119235530Sdelphij { /* 20 Mhz */ { 39.0, /* SGI */ 43.3, }, 120235530Sdelphij /* 40 Mhz */ { 81.0, /* SGI */ 90.0, }, 121235530Sdelphij }, 122235530Sdelphij 123235530Sdelphij /* MCS 5 */ 124235530Sdelphij { /* 20 Mhz */ { 52.0, /* SGI */ 57.8, }, 125235530Sdelphij /* 40 Mhz */ { 108.0, /* SGI */ 120.0, }, 126235530Sdelphij }, 127235530Sdelphij 128235530Sdelphij /* MCS 6 */ 129235530Sdelphij { /* 20 Mhz */ { 58.5, /* SGI */ 65.0, }, 130235530Sdelphij /* 40 Mhz */ { 121.5, /* SGI */ 135.0, }, 131235530Sdelphij }, 132235530Sdelphij 133235530Sdelphij /* MCS 7 */ 134235530Sdelphij { /* 20 Mhz */ { 65.0, /* SGI */ 72.2, }, 135235530Sdelphij /* 40 Mhz */ { 135.0, /* SGI */ 150.0, }, 136235530Sdelphij }, 137235530Sdelphij 138235530Sdelphij /* MCS 8 */ 139235530Sdelphij { /* 20 Mhz */ { 13.0, /* SGI */ 14.4, }, 140235530Sdelphij /* 40 Mhz */ { 27.0, /* SGI */ 30.0, }, 141235530Sdelphij }, 142235530Sdelphij 143235530Sdelphij /* MCS 9 */ 144235530Sdelphij { /* 20 Mhz */ { 26.0, /* SGI */ 28.9, }, 145235530Sdelphij /* 40 Mhz */ { 54.0, /* SGI */ 60.0, }, 146235530Sdelphij }, 147235530Sdelphij 148235530Sdelphij /* MCS 10 */ 149235530Sdelphij { /* 20 Mhz */ { 39.0, /* SGI */ 43.3, }, 150235530Sdelphij /* 40 Mhz */ { 81.0, /* SGI */ 90.0, }, 151235530Sdelphij }, 152235530Sdelphij 153235530Sdelphij /* MCS 11 */ 154235530Sdelphij { /* 20 Mhz */ { 52.0, /* SGI */ 57.8, }, 155235530Sdelphij /* 40 Mhz */ { 108.0, /* SGI */ 120.0, }, 156235530Sdelphij }, 157235530Sdelphij 158235530Sdelphij /* MCS 12 */ 159235530Sdelphij { /* 20 Mhz */ { 78.0, /* SGI */ 86.7, }, 160235530Sdelphij /* 40 Mhz */ { 162.0, /* SGI */ 180.0, }, 161235530Sdelphij }, 162235530Sdelphij 163235530Sdelphij /* MCS 13 */ 164235530Sdelphij { /* 20 Mhz */ { 104.0, /* SGI */ 115.6, }, 165235530Sdelphij /* 40 Mhz */ { 216.0, /* SGI */ 240.0, }, 166235530Sdelphij }, 167235530Sdelphij 168235530Sdelphij /* MCS 14 */ 169235530Sdelphij { /* 20 Mhz */ { 117.0, /* SGI */ 130.0, }, 170235530Sdelphij /* 40 Mhz */ { 243.0, /* SGI */ 270.0, }, 171235530Sdelphij }, 172235530Sdelphij 173235530Sdelphij /* MCS 15 */ 174235530Sdelphij { /* 20 Mhz */ { 130.0, /* SGI */ 144.4, }, 175235530Sdelphij /* 40 Mhz */ { 270.0, /* SGI */ 300.0, }, 176235530Sdelphij }, 177235530Sdelphij 178235530Sdelphij /* MCS 16 */ 179235530Sdelphij { /* 20 Mhz */ { 19.5, /* SGI */ 21.7, }, 180235530Sdelphij /* 40 Mhz */ { 40.5, /* SGI */ 45.0, }, 181235530Sdelphij }, 182235530Sdelphij 183235530Sdelphij /* MCS 17 */ 184235530Sdelphij { /* 20 Mhz */ { 39.0, /* SGI */ 43.3, }, 185235530Sdelphij /* 40 Mhz */ { 81.0, /* SGI */ 90.0, }, 186235530Sdelphij }, 187235530Sdelphij 188235530Sdelphij /* MCS 18 */ 189235530Sdelphij { /* 20 Mhz */ { 58.5, /* SGI */ 65.0, }, 190235530Sdelphij /* 40 Mhz */ { 121.5, /* SGI */ 135.0, }, 191235530Sdelphij }, 192235530Sdelphij 193235530Sdelphij /* MCS 19 */ 194235530Sdelphij { /* 20 Mhz */ { 78.0, /* SGI */ 86.7, }, 195235530Sdelphij /* 40 Mhz */ { 162.0, /* SGI */ 180.0, }, 196235530Sdelphij }, 197235530Sdelphij 198235530Sdelphij /* MCS 20 */ 199235530Sdelphij { /* 20 Mhz */ { 117.0, /* SGI */ 130.0, }, 200235530Sdelphij /* 40 Mhz */ { 243.0, /* SGI */ 270.0, }, 201235530Sdelphij }, 202235530Sdelphij 203235530Sdelphij /* MCS 21 */ 204235530Sdelphij { /* 20 Mhz */ { 156.0, /* SGI */ 173.3, }, 205235530Sdelphij /* 40 Mhz */ { 324.0, /* SGI */ 360.0, }, 206235530Sdelphij }, 207235530Sdelphij 208235530Sdelphij /* MCS 22 */ 209235530Sdelphij { /* 20 Mhz */ { 175.5, /* SGI */ 195.0, }, 210235530Sdelphij /* 40 Mhz */ { 364.5, /* SGI */ 405.0, }, 211235530Sdelphij }, 212235530Sdelphij 213235530Sdelphij /* MCS 23 */ 214235530Sdelphij { /* 20 Mhz */ { 195.0, /* SGI */ 216.7, }, 215235530Sdelphij /* 40 Mhz */ { 405.0, /* SGI */ 450.0, }, 216235530Sdelphij }, 217235530Sdelphij 218235530Sdelphij /* MCS 24 */ 219235530Sdelphij { /* 20 Mhz */ { 26.0, /* SGI */ 28.9, }, 220235530Sdelphij /* 40 Mhz */ { 54.0, /* SGI */ 60.0, }, 221235530Sdelphij }, 222235530Sdelphij 223235530Sdelphij /* MCS 25 */ 224235530Sdelphij { /* 20 Mhz */ { 52.0, /* SGI */ 57.8, }, 225235530Sdelphij /* 40 Mhz */ { 108.0, /* SGI */ 120.0, }, 226235530Sdelphij }, 227235530Sdelphij 228235530Sdelphij /* MCS 26 */ 229235530Sdelphij { /* 20 Mhz */ { 78.0, /* SGI */ 86.7, }, 230235530Sdelphij /* 40 Mhz */ { 162.0, /* SGI */ 180.0, }, 231235530Sdelphij }, 232235530Sdelphij 233235530Sdelphij /* MCS 27 */ 234235530Sdelphij { /* 20 Mhz */ { 104.0, /* SGI */ 115.6, }, 235235530Sdelphij /* 40 Mhz */ { 216.0, /* SGI */ 240.0, }, 236235530Sdelphij }, 237235530Sdelphij 238235530Sdelphij /* MCS 28 */ 239235530Sdelphij { /* 20 Mhz */ { 156.0, /* SGI */ 173.3, }, 240235530Sdelphij /* 40 Mhz */ { 324.0, /* SGI */ 360.0, }, 241235530Sdelphij }, 242235530Sdelphij 243235530Sdelphij /* MCS 29 */ 244235530Sdelphij { /* 20 Mhz */ { 208.0, /* SGI */ 231.1, }, 245235530Sdelphij /* 40 Mhz */ { 432.0, /* SGI */ 480.0, }, 246235530Sdelphij }, 247235530Sdelphij 248235530Sdelphij /* MCS 30 */ 249235530Sdelphij { /* 20 Mhz */ { 234.0, /* SGI */ 260.0, }, 250235530Sdelphij /* 40 Mhz */ { 486.0, /* SGI */ 540.0, }, 251235530Sdelphij }, 252235530Sdelphij 253235530Sdelphij /* MCS 31 */ 254235530Sdelphij { /* 20 Mhz */ { 260.0, /* SGI */ 288.9, }, 255235530Sdelphij /* 40 Mhz */ { 540.0, /* SGI */ 600.0, }, 256235530Sdelphij }, 257235530Sdelphij 258235530Sdelphij /* MCS 32 */ 259235530Sdelphij { /* 20 Mhz */ { 0.0, /* SGI */ 0.0, }, /* not valid */ 260235530Sdelphij /* 40 Mhz */ { 6.0, /* SGI */ 6.7, }, 261235530Sdelphij }, 262235530Sdelphij 263235530Sdelphij /* MCS 33 */ 264235530Sdelphij { /* 20 Mhz */ { 39.0, /* SGI */ 43.3, }, 265235530Sdelphij /* 40 Mhz */ { 81.0, /* SGI */ 90.0, }, 266235530Sdelphij }, 267235530Sdelphij 268235530Sdelphij /* MCS 34 */ 269235530Sdelphij { /* 20 Mhz */ { 52.0, /* SGI */ 57.8, }, 270235530Sdelphij /* 40 Mhz */ { 108.0, /* SGI */ 120.0, }, 271235530Sdelphij }, 272235530Sdelphij 273235530Sdelphij /* MCS 35 */ 274235530Sdelphij { /* 20 Mhz */ { 65.0, /* SGI */ 72.2, }, 275235530Sdelphij /* 40 Mhz */ { 135.0, /* SGI */ 150.0, }, 276235530Sdelphij }, 277235530Sdelphij 278235530Sdelphij /* MCS 36 */ 279235530Sdelphij { /* 20 Mhz */ { 58.5, /* SGI */ 65.0, }, 280235530Sdelphij /* 40 Mhz */ { 121.5, /* SGI */ 135.0, }, 281235530Sdelphij }, 282235530Sdelphij 283235530Sdelphij /* MCS 37 */ 284235530Sdelphij { /* 20 Mhz */ { 78.0, /* SGI */ 86.7, }, 285235530Sdelphij /* 40 Mhz */ { 162.0, /* SGI */ 180.0, }, 286235530Sdelphij }, 287235530Sdelphij 288235530Sdelphij /* MCS 38 */ 289235530Sdelphij { /* 20 Mhz */ { 97.5, /* SGI */ 108.3, }, 290235530Sdelphij /* 40 Mhz */ { 202.5, /* SGI */ 225.0, }, 291235530Sdelphij }, 292235530Sdelphij 293235530Sdelphij /* MCS 39 */ 294235530Sdelphij { /* 20 Mhz */ { 52.0, /* SGI */ 57.8, }, 295235530Sdelphij /* 40 Mhz */ { 108.0, /* SGI */ 120.0, }, 296235530Sdelphij }, 297235530Sdelphij 298235530Sdelphij /* MCS 40 */ 299235530Sdelphij { /* 20 Mhz */ { 65.0, /* SGI */ 72.2, }, 300235530Sdelphij /* 40 Mhz */ { 135.0, /* SGI */ 150.0, }, 301235530Sdelphij }, 302235530Sdelphij 303235530Sdelphij /* MCS 41 */ 304235530Sdelphij { /* 20 Mhz */ { 65.0, /* SGI */ 72.2, }, 305235530Sdelphij /* 40 Mhz */ { 135.0, /* SGI */ 150.0, }, 306235530Sdelphij }, 307235530Sdelphij 308235530Sdelphij /* MCS 42 */ 309235530Sdelphij { /* 20 Mhz */ { 78.0, /* SGI */ 86.7, }, 310235530Sdelphij /* 40 Mhz */ { 162.0, /* SGI */ 180.0, }, 311235530Sdelphij }, 312235530Sdelphij 313235530Sdelphij /* MCS 43 */ 314235530Sdelphij { /* 20 Mhz */ { 91.0, /* SGI */ 101.1, }, 315235530Sdelphij /* 40 Mhz */ { 189.0, /* SGI */ 210.0, }, 316235530Sdelphij }, 317235530Sdelphij 318235530Sdelphij /* MCS 44 */ 319235530Sdelphij { /* 20 Mhz */ { 91.0, /* SGI */ 101.1, }, 320235530Sdelphij /* 40 Mhz */ { 189.0, /* SGI */ 210.0, }, 321235530Sdelphij }, 322235530Sdelphij 323235530Sdelphij /* MCS 45 */ 324235530Sdelphij { /* 20 Mhz */ { 104.0, /* SGI */ 115.6, }, 325235530Sdelphij /* 40 Mhz */ { 216.0, /* SGI */ 240.0, }, 326235530Sdelphij }, 327235530Sdelphij 328235530Sdelphij /* MCS 46 */ 329235530Sdelphij { /* 20 Mhz */ { 78.0, /* SGI */ 86.7, }, 330235530Sdelphij /* 40 Mhz */ { 162.0, /* SGI */ 180.0, }, 331235530Sdelphij }, 332235530Sdelphij 333235530Sdelphij /* MCS 47 */ 334235530Sdelphij { /* 20 Mhz */ { 97.5, /* SGI */ 108.3, }, 335235530Sdelphij /* 40 Mhz */ { 202.5, /* SGI */ 225.0, }, 336235530Sdelphij }, 337235530Sdelphij 338235530Sdelphij /* MCS 48 */ 339235530Sdelphij { /* 20 Mhz */ { 97.5, /* SGI */ 108.3, }, 340235530Sdelphij /* 40 Mhz */ { 202.5, /* SGI */ 225.0, }, 341235530Sdelphij }, 342235530Sdelphij 343235530Sdelphij /* MCS 49 */ 344235530Sdelphij { /* 20 Mhz */ { 117.0, /* SGI */ 130.0, }, 345235530Sdelphij /* 40 Mhz */ { 243.0, /* SGI */ 270.0, }, 346235530Sdelphij }, 347235530Sdelphij 348235530Sdelphij /* MCS 50 */ 349235530Sdelphij { /* 20 Mhz */ { 136.5, /* SGI */ 151.7, }, 350235530Sdelphij /* 40 Mhz */ { 283.5, /* SGI */ 315.0, }, 351235530Sdelphij }, 352235530Sdelphij 353235530Sdelphij /* MCS 51 */ 354235530Sdelphij { /* 20 Mhz */ { 136.5, /* SGI */ 151.7, }, 355235530Sdelphij /* 40 Mhz */ { 283.5, /* SGI */ 315.0, }, 356235530Sdelphij }, 357235530Sdelphij 358235530Sdelphij /* MCS 52 */ 359235530Sdelphij { /* 20 Mhz */ { 156.0, /* SGI */ 173.3, }, 360235530Sdelphij /* 40 Mhz */ { 324.0, /* SGI */ 360.0, }, 361235530Sdelphij }, 362235530Sdelphij 363235530Sdelphij /* MCS 53 */ 364235530Sdelphij { /* 20 Mhz */ { 65.0, /* SGI */ 72.2, }, 365235530Sdelphij /* 40 Mhz */ { 135.0, /* SGI */ 150.0, }, 366235530Sdelphij }, 367235530Sdelphij 368235530Sdelphij /* MCS 54 */ 369235530Sdelphij { /* 20 Mhz */ { 78.0, /* SGI */ 86.7, }, 370235530Sdelphij /* 40 Mhz */ { 162.0, /* SGI */ 180.0, }, 371235530Sdelphij }, 372235530Sdelphij 373235530Sdelphij /* MCS 55 */ 374235530Sdelphij { /* 20 Mhz */ { 91.0, /* SGI */ 101.1, }, 375235530Sdelphij /* 40 Mhz */ { 189.0, /* SGI */ 210.0, }, 376235530Sdelphij }, 377235530Sdelphij 378235530Sdelphij /* MCS 56 */ 379235530Sdelphij { /* 20 Mhz */ { 78.0, /* SGI */ 86.7, }, 380235530Sdelphij /* 40 Mhz */ { 162.0, /* SGI */ 180.0, }, 381235530Sdelphij }, 382235530Sdelphij 383235530Sdelphij /* MCS 57 */ 384235530Sdelphij { /* 20 Mhz */ { 91.0, /* SGI */ 101.1, }, 385235530Sdelphij /* 40 Mhz */ { 189.0, /* SGI */ 210.0, }, 386235530Sdelphij }, 387235530Sdelphij 388235530Sdelphij /* MCS 58 */ 389235530Sdelphij { /* 20 Mhz */ { 104.0, /* SGI */ 115.6, }, 390235530Sdelphij /* 40 Mhz */ { 216.0, /* SGI */ 240.0, }, 391235530Sdelphij }, 392235530Sdelphij 393235530Sdelphij /* MCS 59 */ 394235530Sdelphij { /* 20 Mhz */ { 117.0, /* SGI */ 130.0, }, 395235530Sdelphij /* 40 Mhz */ { 243.0, /* SGI */ 270.0, }, 396235530Sdelphij }, 397235530Sdelphij 398235530Sdelphij /* MCS 60 */ 399235530Sdelphij { /* 20 Mhz */ { 104.0, /* SGI */ 115.6, }, 400235530Sdelphij /* 40 Mhz */ { 216.0, /* SGI */ 240.0, }, 401235530Sdelphij }, 402235530Sdelphij 403235530Sdelphij /* MCS 61 */ 404235530Sdelphij { /* 20 Mhz */ { 117.0, /* SGI */ 130.0, }, 405235530Sdelphij /* 40 Mhz */ { 243.0, /* SGI */ 270.0, }, 406235530Sdelphij }, 407235530Sdelphij 408235530Sdelphij /* MCS 62 */ 409235530Sdelphij { /* 20 Mhz */ { 130.0, /* SGI */ 144.4, }, 410235530Sdelphij /* 40 Mhz */ { 270.0, /* SGI */ 300.0, }, 411235530Sdelphij }, 412235530Sdelphij 413235530Sdelphij /* MCS 63 */ 414235530Sdelphij { /* 20 Mhz */ { 130.0, /* SGI */ 144.4, }, 415235530Sdelphij /* 40 Mhz */ { 270.0, /* SGI */ 300.0, }, 416235530Sdelphij }, 417235530Sdelphij 418235530Sdelphij /* MCS 64 */ 419235530Sdelphij { /* 20 Mhz */ { 143.0, /* SGI */ 158.9, }, 420235530Sdelphij /* 40 Mhz */ { 297.0, /* SGI */ 330.0, }, 421235530Sdelphij }, 422235530Sdelphij 423235530Sdelphij /* MCS 65 */ 424235530Sdelphij { /* 20 Mhz */ { 97.5, /* SGI */ 108.3, }, 425235530Sdelphij /* 40 Mhz */ { 202.5, /* SGI */ 225.0, }, 426235530Sdelphij }, 427235530Sdelphij 428235530Sdelphij /* MCS 66 */ 429235530Sdelphij { /* 20 Mhz */ { 117.0, /* SGI */ 130.0, }, 430235530Sdelphij /* 40 Mhz */ { 243.0, /* SGI */ 270.0, }, 431235530Sdelphij }, 432235530Sdelphij 433235530Sdelphij /* MCS 67 */ 434235530Sdelphij { /* 20 Mhz */ { 136.5, /* SGI */ 151.7, }, 435235530Sdelphij /* 40 Mhz */ { 283.5, /* SGI */ 315.0, }, 436235530Sdelphij }, 437235530Sdelphij 438235530Sdelphij /* MCS 68 */ 439235530Sdelphij { /* 20 Mhz */ { 117.0, /* SGI */ 130.0, }, 440235530Sdelphij /* 40 Mhz */ { 243.0, /* SGI */ 270.0, }, 441235530Sdelphij }, 442235530Sdelphij 443235530Sdelphij /* MCS 69 */ 444235530Sdelphij { /* 20 Mhz */ { 136.5, /* SGI */ 151.7, }, 445235530Sdelphij /* 40 Mhz */ { 283.5, /* SGI */ 315.0, }, 446235530Sdelphij }, 447235530Sdelphij 448235530Sdelphij /* MCS 70 */ 449235530Sdelphij { /* 20 Mhz */ { 156.0, /* SGI */ 173.3, }, 450235530Sdelphij /* 40 Mhz */ { 324.0, /* SGI */ 360.0, }, 451235530Sdelphij }, 452235530Sdelphij 453235530Sdelphij /* MCS 71 */ 454235530Sdelphij { /* 20 Mhz */ { 175.5, /* SGI */ 195.0, }, 455235530Sdelphij /* 40 Mhz */ { 364.5, /* SGI */ 405.0, }, 456235530Sdelphij }, 457235530Sdelphij 458235530Sdelphij /* MCS 72 */ 459235530Sdelphij { /* 20 Mhz */ { 156.0, /* SGI */ 173.3, }, 460235530Sdelphij /* 40 Mhz */ { 324.0, /* SGI */ 360.0, }, 461235530Sdelphij }, 462235530Sdelphij 463235530Sdelphij /* MCS 73 */ 464235530Sdelphij { /* 20 Mhz */ { 175.5, /* SGI */ 195.0, }, 465235530Sdelphij /* 40 Mhz */ { 364.5, /* SGI */ 405.0, }, 466235530Sdelphij }, 467235530Sdelphij 468235530Sdelphij /* MCS 74 */ 469235530Sdelphij { /* 20 Mhz */ { 195.0, /* SGI */ 216.7, }, 470235530Sdelphij /* 40 Mhz */ { 405.0, /* SGI */ 450.0, }, 471235530Sdelphij }, 472235530Sdelphij 473235530Sdelphij /* MCS 75 */ 474235530Sdelphij { /* 20 Mhz */ { 195.0, /* SGI */ 216.7, }, 475235530Sdelphij /* 40 Mhz */ { 405.0, /* SGI */ 450.0, }, 476235530Sdelphij }, 477235530Sdelphij 478235530Sdelphij /* MCS 76 */ 479235530Sdelphij { /* 20 Mhz */ { 214.5, /* SGI */ 238.3, }, 480235530Sdelphij /* 40 Mhz */ { 445.5, /* SGI */ 495.0, }, 481235530Sdelphij }, 482170533Ssam}; 483170533Ssam 48498524Sfennerstatic const char *auth_alg_text[]={"Open System","Shared Key","EAP"}; 485162017Ssam#define NUM_AUTH_ALGS (sizeof auth_alg_text / sizeof auth_alg_text[0]) 48698524Sfenner 48798524Sfennerstatic const char *status_text[] = { 488241235Sdelphij "Successful", /* 0 */ 489195684Ssam "Unspecified failure", /* 1 */ 490195684Ssam "Reserved", /* 2 */ 491195684Ssam "Reserved", /* 3 */ 492195684Ssam "Reserved", /* 4 */ 493195684Ssam "Reserved", /* 5 */ 494195684Ssam "Reserved", /* 6 */ 495195684Ssam "Reserved", /* 7 */ 496195684Ssam "Reserved", /* 8 */ 497195684Ssam "Reserved", /* 9 */ 498195684Ssam "Cannot Support all requested capabilities in the Capability " 499195684Ssam "Information field", /* 10 */ 500195684Ssam "Reassociation denied due to inability to confirm that association " 501195684Ssam "exists", /* 11 */ 502195684Ssam "Association denied due to reason outside the scope of the " 503195684Ssam "standard", /* 12 */ 504195684Ssam "Responding station does not support the specified authentication " 505195684Ssam "algorithm ", /* 13 */ 506195684Ssam "Received an Authentication frame with authentication transaction " 507195684Ssam "sequence number out of expected sequence", /* 14 */ 508195684Ssam "Authentication rejected because of challenge failure", /* 15 */ 509195684Ssam "Authentication rejected due to timeout waiting for next frame in " 510195684Ssam "sequence", /* 16 */ 511195684Ssam "Association denied because AP is unable to handle additional" 512195684Ssam "associated stations", /* 17 */ 513195684Ssam "Association denied due to requesting station not supporting all of " 514195684Ssam "the data rates in BSSBasicRateSet parameter", /* 18 */ 515195684Ssam "Association denied due to requesting station not supporting " 516195684Ssam "short preamble operation", /* 19 */ 517195684Ssam "Association denied due to requesting station not supporting " 518195684Ssam "PBCC encoding", /* 20 */ 519195684Ssam "Association denied due to requesting station not supporting " 520195684Ssam "channel agility", /* 21 */ 521195684Ssam "Association request rejected because Spectrum Management " 522195684Ssam "capability is required", /* 22 */ 523195684Ssam "Association request rejected because the information in the " 524195684Ssam "Power Capability element is unacceptable", /* 23 */ 525195684Ssam "Association request rejected because the information in the " 526195684Ssam "Supported Channels element is unacceptable", /* 24 */ 527195684Ssam "Association denied due to requesting station not supporting " 528195684Ssam "short slot operation", /* 25 */ 529195684Ssam "Association denied due to requesting station not supporting " 530195684Ssam "DSSS-OFDM operation", /* 26 */ 531195684Ssam "Association denied because the requested STA does not support HT " 532195684Ssam "features", /* 27 */ 533195684Ssam "Reserved", /* 28 */ 534195684Ssam "Association denied because the requested STA does not support " 535195684Ssam "the PCO transition time required by the AP", /* 29 */ 536195684Ssam "Reserved", /* 30 */ 537195684Ssam "Reserved", /* 31 */ 538195684Ssam "Unspecified, QoS-related failure", /* 32 */ 539195684Ssam "Association denied due to QAP having insufficient bandwidth " 540195684Ssam "to handle another QSTA", /* 33 */ 541195684Ssam "Association denied due to excessive frame loss rates and/or " 542195684Ssam "poor conditions on current operating channel", /* 34 */ 543195684Ssam "Association (with QBSS) denied due to requesting station not " 544195684Ssam "supporting the QoS facility", /* 35 */ 545195684Ssam "Association denied due to requesting station not supporting " 546195684Ssam "Block Ack", /* 36 */ 547195684Ssam "The request has been declined", /* 37 */ 548195684Ssam "The request has not been successful as one or more parameters " 549195684Ssam "have invalid values", /* 38 */ 550195684Ssam "The TS has not been created because the request cannot be honored. " 551195684Ssam "However, a suggested TSPEC is provided so that the initiating QSTA" 552195684Ssam "may attempt to set another TS with the suggested changes to the " 553195684Ssam "TSPEC", /* 39 */ 554195684Ssam "Invalid Information Element", /* 40 */ 555195684Ssam "Group Cipher is not valid", /* 41 */ 556195684Ssam "Pairwise Cipher is not valid", /* 42 */ 557195684Ssam "AKMP is not valid", /* 43 */ 558195684Ssam "Unsupported RSN IE version", /* 44 */ 559195684Ssam "Invalid RSN IE Capabilities", /* 45 */ 560195684Ssam "Cipher suite is rejected per security policy", /* 46 */ 561195684Ssam "The TS has not been created. However, the HC may be capable of " 562195684Ssam "creating a TS, in response to a request, after the time indicated " 563195684Ssam "in the TS Delay element", /* 47 */ 564195684Ssam "Direct Link is not allowed in the BSS by policy", /* 48 */ 565195684Ssam "Destination STA is not present within this QBSS.", /* 49 */ 566195684Ssam "The Destination STA is not a QSTA.", /* 50 */ 567195684Ssam 56898524Sfenner}; 569162017Ssam#define NUM_STATUSES (sizeof status_text / sizeof status_text[0]) 57098524Sfenner 57198524Sfennerstatic const char *reason_text[] = { 572195684Ssam "Reserved", /* 0 */ 573195684Ssam "Unspecified reason", /* 1 */ 574195684Ssam "Previous authentication no longer valid", /* 2 */ 575195684Ssam "Deauthenticated because sending station is leaving (or has left) " 576195684Ssam "IBSS or ESS", /* 3 */ 577195684Ssam "Disassociated due to inactivity", /* 4 */ 578195684Ssam "Disassociated because AP is unable to handle all currently " 579195684Ssam " associated stations", /* 5 */ 580162017Ssam "Class 2 frame received from nonauthenticated station", /* 6 */ 581195684Ssam "Class 3 frame received from nonassociated station", /* 7 */ 582195684Ssam "Disassociated because sending station is leaving " 583195684Ssam "(or has left) BSS", /* 8 */ 584195684Ssam "Station requesting (re)association is not authenticated with " 585195684Ssam "responding station", /* 9 */ 586195684Ssam "Disassociated because the information in the Power Capability " 587195684Ssam "element is unacceptable", /* 10 */ 588195684Ssam "Disassociated because the information in the SupportedChannels " 589195684Ssam "element is unacceptable", /* 11 */ 590195684Ssam "Invalid Information Element", /* 12 */ 591195684Ssam "Reserved", /* 13 */ 592195684Ssam "Michael MIC failure", /* 14 */ 593195684Ssam "4-Way Handshake timeout", /* 15 */ 594195684Ssam "Group key update timeout", /* 16 */ 595195684Ssam "Information element in 4-Way Handshake different from (Re)Association" 596195684Ssam "Request/Probe Response/Beacon", /* 17 */ 597195684Ssam "Group Cipher is not valid", /* 18 */ 598195684Ssam "AKMP is not valid", /* 20 */ 599195684Ssam "Unsupported RSN IE version", /* 21 */ 600195684Ssam "Invalid RSN IE Capabilities", /* 22 */ 601195684Ssam "IEEE 802.1X Authentication failed", /* 23 */ 602195684Ssam "Cipher suite is rejected per security policy", /* 24 */ 603195684Ssam "Reserved", /* 25 */ 604195684Ssam "Reserved", /* 26 */ 605195684Ssam "Reserved", /* 27 */ 606195684Ssam "Reserved", /* 28 */ 607195684Ssam "Reserved", /* 29 */ 608195684Ssam "Reserved", /* 30 */ 609195684Ssam "TS deleted because QoS AP lacks sufficient bandwidth for this " 610195684Ssam "QoS STA due to a change in BSS service characteristics or " 611195684Ssam "operational mode (e.g. an HT BSS change from 40 MHz channel " 612195684Ssam "to 20 MHz channel)", /* 31 */ 613195684Ssam "Disassociated for unspecified, QoS-related reason", /* 32 */ 614195684Ssam "Disassociated because QoS AP lacks sufficient bandwidth for this " 615195684Ssam "QoS STA", /* 33 */ 616195684Ssam "Disassociated because of excessive number of frames that need to be " 617195684Ssam "acknowledged, but are not acknowledged for AP transmissions " 618195684Ssam "and/or poor channel conditions", /* 34 */ 619195684Ssam "Disassociated because STA is transmitting outside the limits " 620195684Ssam "of its TXOPs", /* 35 */ 621195684Ssam "Requested from peer STA as the STA is leaving the BSS " 622195684Ssam "(or resetting)", /* 36 */ 623195684Ssam "Requested from peer STA as it does not want to use the " 624195684Ssam "mechanism", /* 37 */ 625195684Ssam "Requested from peer STA as the STA received frames using the " 626195684Ssam "mechanism for which a set up is required", /* 38 */ 627195684Ssam "Requested from peer STA due to time out", /* 39 */ 628195684Ssam "Reserved", /* 40 */ 629195684Ssam "Reserved", /* 41 */ 630195684Ssam "Reserved", /* 42 */ 631195684Ssam "Reserved", /* 43 */ 632195684Ssam "Reserved", /* 44 */ 633195684Ssam "Peer STA does not support the requested cipher suite", /* 45 */ 634195684Ssam "Association denied due to requesting STA not supporting HT " 635195684Ssam "features", /* 46 */ 63698524Sfenner}; 637162017Ssam#define NUM_REASONS (sizeof reason_text / sizeof reason_text[0]) 63898524Sfenner 639127668Sbmsstatic int 640127668Sbmswep_print(const u_char *p) 64198524Sfenner{ 64298524Sfenner u_int32_t iv; 64398524Sfenner 644127668Sbms if (!TTEST2(*p, IEEE802_11_IV_LEN + IEEE802_11_KID_LEN)) 64598524Sfenner return 0; 64698524Sfenner iv = EXTRACT_LE_32BITS(p); 64798524Sfenner 64898524Sfenner printf("Data IV:%3x Pad %x KeyID %x", IV_IV(iv), IV_PAD(iv), 64998524Sfenner IV_KEYID(iv)); 65098524Sfenner 65198524Sfenner return 1; 65298524Sfenner} 65398524Sfenner 654214478Srpaulostatic int 655214478Srpauloparse_elements(struct mgmt_body_t *pbody, const u_char *p, int offset, 656214478Srpaulo u_int length) 65798524Sfenner{ 658235530Sdelphij u_int elementlen; 659214478Srpaulo struct ssid_t ssid; 660214478Srpaulo struct challenge_t challenge; 661214478Srpaulo struct rates_t rates; 662214478Srpaulo struct ds_t ds; 663214478Srpaulo struct cf_t cf; 664214478Srpaulo struct tim_t tim; 665214478Srpaulo 666172686Smlaier /* 667172686Smlaier * We haven't seen any elements yet. 668172686Smlaier */ 669214478Srpaulo pbody->challenge_present = 0; 670214478Srpaulo pbody->ssid_present = 0; 671214478Srpaulo pbody->rates_present = 0; 672214478Srpaulo pbody->ds_present = 0; 673214478Srpaulo pbody->cf_present = 0; 674214478Srpaulo pbody->tim_present = 0; 675172686Smlaier 676214478Srpaulo while (length != 0) { 67798524Sfenner if (!TTEST2(*(p + offset), 1)) 678214478Srpaulo return 0; 679214478Srpaulo if (length < 1) 680214478Srpaulo return 0; 68198524Sfenner switch (*(p + offset)) { 68298524Sfenner case E_SSID: 683127668Sbms if (!TTEST2(*(p + offset), 2)) 684214478Srpaulo return 0; 685214478Srpaulo if (length < 2) 686214478Srpaulo return 0; 687214478Srpaulo memcpy(&ssid, p + offset, 2); 688127668Sbms offset += 2; 689214478Srpaulo length -= 2; 690214478Srpaulo if (ssid.length != 0) { 691214478Srpaulo if (ssid.length > sizeof(ssid.ssid) - 1) 692214478Srpaulo return 0; 693214478Srpaulo if (!TTEST2(*(p + offset), ssid.length)) 694214478Srpaulo return 0; 695214478Srpaulo if (length < ssid.length) 696214478Srpaulo return 0; 697214478Srpaulo memcpy(&ssid.ssid, p + offset, ssid.length); 698214478Srpaulo offset += ssid.length; 699214478Srpaulo length -= ssid.length; 700172686Smlaier } 701214478Srpaulo ssid.ssid[ssid.length] = '\0'; 702214478Srpaulo /* 703214478Srpaulo * Present and not truncated. 704214478Srpaulo * 705214478Srpaulo * If we haven't already seen an SSID IE, 706214478Srpaulo * copy this one, otherwise ignore this one, 707214478Srpaulo * so we later report the first one we saw. 708214478Srpaulo */ 709214478Srpaulo if (!pbody->ssid_present) { 710214478Srpaulo pbody->ssid = ssid; 711214478Srpaulo pbody->ssid_present = 1; 712214478Srpaulo } 71398524Sfenner break; 71498524Sfenner case E_CHALLENGE: 715127668Sbms if (!TTEST2(*(p + offset), 2)) 716214478Srpaulo return 0; 717214478Srpaulo if (length < 2) 718214478Srpaulo return 0; 719214478Srpaulo memcpy(&challenge, p + offset, 2); 720127668Sbms offset += 2; 721214478Srpaulo length -= 2; 722214478Srpaulo if (challenge.length != 0) { 723214478Srpaulo if (challenge.length > 724214478Srpaulo sizeof(challenge.text) - 1) 725214478Srpaulo return 0; 726214478Srpaulo if (!TTEST2(*(p + offset), challenge.length)) 727214478Srpaulo return 0; 728214478Srpaulo if (length < challenge.length) 729214478Srpaulo return 0; 730214478Srpaulo memcpy(&challenge.text, p + offset, 731214478Srpaulo challenge.length); 732214478Srpaulo offset += challenge.length; 733214478Srpaulo length -= challenge.length; 734172686Smlaier } 735214478Srpaulo challenge.text[challenge.length] = '\0'; 736214478Srpaulo /* 737214478Srpaulo * Present and not truncated. 738214478Srpaulo * 739214478Srpaulo * If we haven't already seen a challenge IE, 740214478Srpaulo * copy this one, otherwise ignore this one, 741214478Srpaulo * so we later report the first one we saw. 742214478Srpaulo */ 743214478Srpaulo if (!pbody->challenge_present) { 744214478Srpaulo pbody->challenge = challenge; 745214478Srpaulo pbody->challenge_present = 1; 746214478Srpaulo } 74798524Sfenner break; 74898524Sfenner case E_RATES: 749127668Sbms if (!TTEST2(*(p + offset), 2)) 750214478Srpaulo return 0; 751214478Srpaulo if (length < 2) 752214478Srpaulo return 0; 753214478Srpaulo memcpy(&rates, p + offset, 2); 754127668Sbms offset += 2; 755214478Srpaulo length -= 2; 756214478Srpaulo if (rates.length != 0) { 757214478Srpaulo if (rates.length > sizeof rates.rate) 758214478Srpaulo return 0; 759214478Srpaulo if (!TTEST2(*(p + offset), rates.length)) 760214478Srpaulo return 0; 761214478Srpaulo if (length < rates.length) 762214478Srpaulo return 0; 763214478Srpaulo memcpy(&rates.rate, p + offset, rates.length); 764214478Srpaulo offset += rates.length; 765214478Srpaulo length -= rates.length; 766172686Smlaier } 767214478Srpaulo /* 768214478Srpaulo * Present and not truncated. 769214478Srpaulo * 770214478Srpaulo * If we haven't already seen a rates IE, 771214478Srpaulo * copy this one if it's not zero-length, 772214478Srpaulo * otherwise ignore this one, so we later 773214478Srpaulo * report the first one we saw. 774214478Srpaulo * 775214478Srpaulo * We ignore zero-length rates IEs as some 776214478Srpaulo * devices seem to put a zero-length rates 777214478Srpaulo * IE, followed by an SSID IE, followed by 778214478Srpaulo * a non-zero-length rates IE into frames, 779214478Srpaulo * even though IEEE Std 802.11-2007 doesn't 780214478Srpaulo * seem to indicate that a zero-length rates 781214478Srpaulo * IE is valid. 782214478Srpaulo */ 783214478Srpaulo if (!pbody->rates_present && rates.length != 0) { 784214478Srpaulo pbody->rates = rates; 785214478Srpaulo pbody->rates_present = 1; 786214478Srpaulo } 78798524Sfenner break; 78898524Sfenner case E_DS: 789127668Sbms if (!TTEST2(*(p + offset), 3)) 790214478Srpaulo return 0; 791214478Srpaulo if (length < 3) 792214478Srpaulo return 0; 793214478Srpaulo memcpy(&ds, p + offset, 3); 794127668Sbms offset += 3; 795214478Srpaulo length -= 3; 796214478Srpaulo /* 797214478Srpaulo * Present and not truncated. 798214478Srpaulo * 799214478Srpaulo * If we haven't already seen a DS IE, 800214478Srpaulo * copy this one, otherwise ignore this one, 801214478Srpaulo * so we later report the first one we saw. 802214478Srpaulo */ 803214478Srpaulo if (!pbody->ds_present) { 804214478Srpaulo pbody->ds = ds; 805214478Srpaulo pbody->ds_present = 1; 806214478Srpaulo } 80798524Sfenner break; 80898524Sfenner case E_CF: 809127668Sbms if (!TTEST2(*(p + offset), 8)) 810214478Srpaulo return 0; 811214478Srpaulo if (length < 8) 812214478Srpaulo return 0; 813214478Srpaulo memcpy(&cf, p + offset, 8); 814127668Sbms offset += 8; 815214478Srpaulo length -= 8; 816214478Srpaulo /* 817214478Srpaulo * Present and not truncated. 818214478Srpaulo * 819214478Srpaulo * If we haven't already seen a CF IE, 820214478Srpaulo * copy this one, otherwise ignore this one, 821214478Srpaulo * so we later report the first one we saw. 822214478Srpaulo */ 823214478Srpaulo if (!pbody->cf_present) { 824214478Srpaulo pbody->cf = cf; 825214478Srpaulo pbody->cf_present = 1; 826214478Srpaulo } 82798524Sfenner break; 82898524Sfenner case E_TIM: 829127668Sbms if (!TTEST2(*(p + offset), 2)) 830214478Srpaulo return 0; 831214478Srpaulo if (length < 2) 832214478Srpaulo return 0; 833214478Srpaulo memcpy(&tim, p + offset, 2); 834127668Sbms offset += 2; 835214478Srpaulo length -= 2; 836127668Sbms if (!TTEST2(*(p + offset), 3)) 837214478Srpaulo return 0; 838214478Srpaulo if (length < 3) 839214478Srpaulo return 0; 840214478Srpaulo memcpy(&tim.count, p + offset, 3); 841127668Sbms offset += 3; 842214478Srpaulo length -= 3; 84398524Sfenner 844214478Srpaulo if (tim.length <= 3) 845127668Sbms break; 846214478Srpaulo if (tim.length - 3 > (int)sizeof tim.bitmap) 847214478Srpaulo return 0; 848214478Srpaulo if (!TTEST2(*(p + offset), tim.length - 3)) 849214478Srpaulo return 0; 850214478Srpaulo if (length < (u_int)(tim.length - 3)) 851214478Srpaulo return 0; 852214478Srpaulo memcpy(tim.bitmap, p + (tim.length - 3), 853214478Srpaulo (tim.length - 3)); 854214478Srpaulo offset += tim.length - 3; 855214478Srpaulo length -= tim.length - 3; 856214478Srpaulo /* 857214478Srpaulo * Present and not truncated. 858214478Srpaulo * 859214478Srpaulo * If we haven't already seen a TIM IE, 860214478Srpaulo * copy this one, otherwise ignore this one, 861214478Srpaulo * so we later report the first one we saw. 862214478Srpaulo */ 863214478Srpaulo if (!pbody->tim_present) { 864214478Srpaulo pbody->tim = tim; 865214478Srpaulo pbody->tim_present = 1; 866214478Srpaulo } 86798524Sfenner break; 86898524Sfenner default: 86998524Sfenner#if 0 870127668Sbms printf("(1) unhandled element_id (%d) ", 871214478Srpaulo *(p + offset)); 87298524Sfenner#endif 873172686Smlaier if (!TTEST2(*(p + offset), 2)) 874214478Srpaulo return 0; 875214478Srpaulo if (length < 2) 876214478Srpaulo return 0; 877235530Sdelphij elementlen = *(p + offset + 1); 878235530Sdelphij if (!TTEST2(*(p + offset + 2), elementlen)) 879214478Srpaulo return 0; 880235530Sdelphij if (length < elementlen + 2) 881214478Srpaulo return 0; 882235530Sdelphij offset += elementlen + 2; 883235530Sdelphij length -= elementlen + 2; 88498524Sfenner break; 88598524Sfenner } 88698524Sfenner } 887214478Srpaulo 888214478Srpaulo /* No problems found. */ 889214478Srpaulo return 1; 89098524Sfenner} 89198524Sfenner 89298524Sfenner/********************************************************************************* 89398524Sfenner * Print Handle functions for the management frame types 89498524Sfenner *********************************************************************************/ 89598524Sfenner 896127668Sbmsstatic int 897214478Srpaulohandle_beacon(const u_char *p, u_int length) 89898524Sfenner{ 89998524Sfenner struct mgmt_body_t pbody; 90098524Sfenner int offset = 0; 901214478Srpaulo int ret; 90298524Sfenner 90398524Sfenner memset(&pbody, 0, sizeof(pbody)); 90498524Sfenner 905127668Sbms if (!TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN + 906127668Sbms IEEE802_11_CAPINFO_LEN)) 90798524Sfenner return 0; 908214478Srpaulo if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN + 909214478Srpaulo IEEE802_11_CAPINFO_LEN) 910214478Srpaulo return 0; 911172686Smlaier memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN); 912127668Sbms offset += IEEE802_11_TSTAMP_LEN; 913214478Srpaulo length -= IEEE802_11_TSTAMP_LEN; 91498524Sfenner pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset); 915127668Sbms offset += IEEE802_11_BCNINT_LEN; 916214478Srpaulo length -= IEEE802_11_BCNINT_LEN; 91798524Sfenner pbody.capability_info = EXTRACT_LE_16BITS(p+offset); 918127668Sbms offset += IEEE802_11_CAPINFO_LEN; 919214478Srpaulo length -= IEEE802_11_CAPINFO_LEN; 92098524Sfenner 921214478Srpaulo ret = parse_elements(&pbody, p, offset, length); 92298524Sfenner 923172686Smlaier PRINT_SSID(pbody); 924111726Sfenner PRINT_RATES(pbody); 925172686Smlaier printf(" %s", 926172686Smlaier CAPABILITY_ESS(pbody.capability_info) ? "ESS" : "IBSS"); 927172686Smlaier PRINT_DS_CHANNEL(pbody); 92898524Sfenner 929214478Srpaulo return ret; 93098524Sfenner} 93198524Sfenner 932127668Sbmsstatic int 933214478Srpaulohandle_assoc_request(const u_char *p, u_int length) 93498524Sfenner{ 93598524Sfenner struct mgmt_body_t pbody; 93698524Sfenner int offset = 0; 937214478Srpaulo int ret; 93898524Sfenner 93998524Sfenner memset(&pbody, 0, sizeof(pbody)); 94098524Sfenner 941127668Sbms if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN)) 94298524Sfenner return 0; 943214478Srpaulo if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN) 944214478Srpaulo return 0; 94598524Sfenner pbody.capability_info = EXTRACT_LE_16BITS(p); 946127668Sbms offset += IEEE802_11_CAPINFO_LEN; 947214478Srpaulo length -= IEEE802_11_CAPINFO_LEN; 94898524Sfenner pbody.listen_interval = EXTRACT_LE_16BITS(p+offset); 949127668Sbms offset += IEEE802_11_LISTENINT_LEN; 950214478Srpaulo length -= IEEE802_11_LISTENINT_LEN; 95198524Sfenner 952214478Srpaulo ret = parse_elements(&pbody, p, offset, length); 95398524Sfenner 954172686Smlaier PRINT_SSID(pbody); 955111726Sfenner PRINT_RATES(pbody); 956214478Srpaulo return ret; 95798524Sfenner} 95898524Sfenner 959127668Sbmsstatic int 960214478Srpaulohandle_assoc_response(const u_char *p, u_int length) 96198524Sfenner{ 96298524Sfenner struct mgmt_body_t pbody; 96398524Sfenner int offset = 0; 964214478Srpaulo int ret; 96598524Sfenner 96698524Sfenner memset(&pbody, 0, sizeof(pbody)); 96798524Sfenner 968127668Sbms if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN + 969127668Sbms IEEE802_11_AID_LEN)) 97098524Sfenner return 0; 971214478Srpaulo if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN + 972214478Srpaulo IEEE802_11_AID_LEN) 973214478Srpaulo return 0; 97498524Sfenner pbody.capability_info = EXTRACT_LE_16BITS(p); 975127668Sbms offset += IEEE802_11_CAPINFO_LEN; 976214478Srpaulo length -= IEEE802_11_CAPINFO_LEN; 97798524Sfenner pbody.status_code = EXTRACT_LE_16BITS(p+offset); 978127668Sbms offset += IEEE802_11_STATUS_LEN; 979214478Srpaulo length -= IEEE802_11_STATUS_LEN; 98098524Sfenner pbody.aid = EXTRACT_LE_16BITS(p+offset); 981127668Sbms offset += IEEE802_11_AID_LEN; 982214478Srpaulo length -= IEEE802_11_AID_LEN; 98398524Sfenner 984214478Srpaulo ret = parse_elements(&pbody, p, offset, length); 98598524Sfenner 986127668Sbms printf(" AID(%x) :%s: %s", ((u_int16_t)(pbody.aid << 2 )) >> 2 , 98798524Sfenner CAPABILITY_PRIVACY(pbody.capability_info) ? " PRIVACY " : "", 988162017Ssam (pbody.status_code < NUM_STATUSES 989162017Ssam ? status_text[pbody.status_code] 990162017Ssam : "n/a")); 99198524Sfenner 992214478Srpaulo return ret; 99398524Sfenner} 99498524Sfenner 995127668Sbmsstatic int 996214478Srpaulohandle_reassoc_request(const u_char *p, u_int length) 99798524Sfenner{ 99898524Sfenner struct mgmt_body_t pbody; 99998524Sfenner int offset = 0; 1000214478Srpaulo int ret; 100198524Sfenner 100298524Sfenner memset(&pbody, 0, sizeof(pbody)); 100398524Sfenner 1004127668Sbms if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN + 1005127668Sbms IEEE802_11_AP_LEN)) 100698524Sfenner return 0; 1007214478Srpaulo if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN + 1008214478Srpaulo IEEE802_11_AP_LEN) 1009214478Srpaulo return 0; 101098524Sfenner pbody.capability_info = EXTRACT_LE_16BITS(p); 1011127668Sbms offset += IEEE802_11_CAPINFO_LEN; 1012214478Srpaulo length -= IEEE802_11_CAPINFO_LEN; 101398524Sfenner pbody.listen_interval = EXTRACT_LE_16BITS(p+offset); 1014127668Sbms offset += IEEE802_11_LISTENINT_LEN; 1015214478Srpaulo length -= IEEE802_11_LISTENINT_LEN; 1016127668Sbms memcpy(&pbody.ap, p+offset, IEEE802_11_AP_LEN); 1017127668Sbms offset += IEEE802_11_AP_LEN; 1018214478Srpaulo length -= IEEE802_11_AP_LEN; 101998524Sfenner 1020214478Srpaulo ret = parse_elements(&pbody, p, offset, length); 102198524Sfenner 1022172686Smlaier PRINT_SSID(pbody); 1023172686Smlaier printf(" AP : %s", etheraddr_string( pbody.ap )); 102498524Sfenner 1025214478Srpaulo return ret; 102698524Sfenner} 102798524Sfenner 1028127668Sbmsstatic int 1029214478Srpaulohandle_reassoc_response(const u_char *p, u_int length) 103098524Sfenner{ 103198524Sfenner /* Same as a Association Reponse */ 1032214478Srpaulo return handle_assoc_response(p, length); 103398524Sfenner} 103498524Sfenner 1035127668Sbmsstatic int 1036214478Srpaulohandle_probe_request(const u_char *p, u_int length) 103798524Sfenner{ 103898524Sfenner struct mgmt_body_t pbody; 103998524Sfenner int offset = 0; 1040214478Srpaulo int ret; 104198524Sfenner 104298524Sfenner memset(&pbody, 0, sizeof(pbody)); 104398524Sfenner 1044214478Srpaulo ret = parse_elements(&pbody, p, offset, length); 104598524Sfenner 1046172686Smlaier PRINT_SSID(pbody); 1047111726Sfenner PRINT_RATES(pbody); 104898524Sfenner 1049214478Srpaulo return ret; 105098524Sfenner} 105198524Sfenner 1052127668Sbmsstatic int 1053214478Srpaulohandle_probe_response(const u_char *p, u_int length) 105498524Sfenner{ 105598524Sfenner struct mgmt_body_t pbody; 105698524Sfenner int offset = 0; 1057214478Srpaulo int ret; 105898524Sfenner 105998524Sfenner memset(&pbody, 0, sizeof(pbody)); 106098524Sfenner 1061127668Sbms if (!TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN + 1062127668Sbms IEEE802_11_CAPINFO_LEN)) 106398524Sfenner return 0; 1064214478Srpaulo if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN + 1065214478Srpaulo IEEE802_11_CAPINFO_LEN) 1066214478Srpaulo return 0; 1067127668Sbms memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN); 1068127668Sbms offset += IEEE802_11_TSTAMP_LEN; 1069214478Srpaulo length -= IEEE802_11_TSTAMP_LEN; 107098524Sfenner pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset); 1071127668Sbms offset += IEEE802_11_BCNINT_LEN; 1072214478Srpaulo length -= IEEE802_11_BCNINT_LEN; 107398524Sfenner pbody.capability_info = EXTRACT_LE_16BITS(p+offset); 1074127668Sbms offset += IEEE802_11_CAPINFO_LEN; 1075214478Srpaulo length -= IEEE802_11_CAPINFO_LEN; 107698524Sfenner 1077214478Srpaulo ret = parse_elements(&pbody, p, offset, length); 107898524Sfenner 1079172686Smlaier PRINT_SSID(pbody); 1080111726Sfenner PRINT_RATES(pbody); 1081172686Smlaier PRINT_DS_CHANNEL(pbody); 108298524Sfenner 1083214478Srpaulo return ret; 108498524Sfenner} 108598524Sfenner 1086127668Sbmsstatic int 1087127668Sbmshandle_atim(void) 108898524Sfenner{ 108998524Sfenner /* the frame body for ATIM is null. */ 109098524Sfenner return 1; 109198524Sfenner} 109298524Sfenner 1093127668Sbmsstatic int 1094214478Srpaulohandle_disassoc(const u_char *p, u_int length) 109598524Sfenner{ 109698524Sfenner struct mgmt_body_t pbody; 109798524Sfenner 109898524Sfenner memset(&pbody, 0, sizeof(pbody)); 109998524Sfenner 1100127668Sbms if (!TTEST2(*p, IEEE802_11_REASON_LEN)) 110198524Sfenner return 0; 1102214478Srpaulo if (length < IEEE802_11_REASON_LEN) 1103214478Srpaulo return 0; 110498524Sfenner pbody.reason_code = EXTRACT_LE_16BITS(p); 110598524Sfenner 1106127668Sbms printf(": %s", 1107162017Ssam (pbody.reason_code < NUM_REASONS) 1108162017Ssam ? reason_text[pbody.reason_code] 1109162017Ssam : "Reserved" ); 111098524Sfenner 111198524Sfenner return 1; 111298524Sfenner} 111398524Sfenner 1114127668Sbmsstatic int 1115214478Srpaulohandle_auth(const u_char *p, u_int length) 111698524Sfenner{ 111798524Sfenner struct mgmt_body_t pbody; 111898524Sfenner int offset = 0; 1119214478Srpaulo int ret; 112098524Sfenner 112198524Sfenner memset(&pbody, 0, sizeof(pbody)); 112298524Sfenner 112398524Sfenner if (!TTEST2(*p, 6)) 112498524Sfenner return 0; 1125214478Srpaulo if (length < 6) 1126214478Srpaulo return 0; 112798524Sfenner pbody.auth_alg = EXTRACT_LE_16BITS(p); 112898524Sfenner offset += 2; 1129214478Srpaulo length -= 2; 113098524Sfenner pbody.auth_trans_seq_num = EXTRACT_LE_16BITS(p + offset); 113198524Sfenner offset += 2; 1132214478Srpaulo length -= 2; 113398524Sfenner pbody.status_code = EXTRACT_LE_16BITS(p + offset); 113498524Sfenner offset += 2; 1135214478Srpaulo length -= 2; 113698524Sfenner 1137214478Srpaulo ret = parse_elements(&pbody, p, offset, length); 113898524Sfenner 113998524Sfenner if ((pbody.auth_alg == 1) && 1140127668Sbms ((pbody.auth_trans_seq_num == 2) || 1141127668Sbms (pbody.auth_trans_seq_num == 3))) { 1142127668Sbms printf(" (%s)-%x [Challenge Text] %s", 1143162017Ssam (pbody.auth_alg < NUM_AUTH_ALGS) 1144162017Ssam ? auth_alg_text[pbody.auth_alg] 1145162017Ssam : "Reserved", 114698524Sfenner pbody.auth_trans_seq_num, 1147127668Sbms ((pbody.auth_trans_seq_num % 2) 1148162017Ssam ? ((pbody.status_code < NUM_STATUSES) 1149127668Sbms ? status_text[pbody.status_code] 1150127668Sbms : "n/a") : "")); 1151214478Srpaulo return ret; 115298524Sfenner } 1153127668Sbms printf(" (%s)-%x: %s", 1154162017Ssam (pbody.auth_alg < NUM_AUTH_ALGS) 1155162017Ssam ? auth_alg_text[pbody.auth_alg] 1156162017Ssam : "Reserved", 1157127668Sbms pbody.auth_trans_seq_num, 1158127668Sbms (pbody.auth_trans_seq_num % 2) 1159162017Ssam ? ((pbody.status_code < NUM_STATUSES) 1160162017Ssam ? status_text[pbody.status_code] 1161162017Ssam : "n/a") 1162127668Sbms : ""); 116398524Sfenner 1164214478Srpaulo return ret; 116598524Sfenner} 116698524Sfenner 1167127668Sbmsstatic int 1168214478Srpaulohandle_deauth(const struct mgmt_header_t *pmh, const u_char *p, u_int length) 116998524Sfenner{ 117098524Sfenner struct mgmt_body_t pbody; 117198524Sfenner int offset = 0; 1172127668Sbms const char *reason = NULL; 117398524Sfenner 117498524Sfenner memset(&pbody, 0, sizeof(pbody)); 117598524Sfenner 1176127668Sbms if (!TTEST2(*p, IEEE802_11_REASON_LEN)) 117798524Sfenner return 0; 1178214478Srpaulo if (length < IEEE802_11_REASON_LEN) 1179214478Srpaulo return 0; 118098524Sfenner pbody.reason_code = EXTRACT_LE_16BITS(p); 1181127668Sbms offset += IEEE802_11_REASON_LEN; 1182214478Srpaulo length -= IEEE802_11_REASON_LEN; 118398524Sfenner 1184162017Ssam reason = (pbody.reason_code < NUM_REASONS) 1185162017Ssam ? reason_text[pbody.reason_code] 1186162017Ssam : "Reserved"; 1187127668Sbms 118898524Sfenner if (eflag) { 1189127668Sbms printf(": %s", reason); 119098524Sfenner } else { 1191127668Sbms printf(" (%s): %s", etheraddr_string(pmh->sa), reason); 119298524Sfenner } 119398524Sfenner return 1; 119498524Sfenner} 119598524Sfenner 1196195684Ssam#define PRINT_HT_ACTION(v) (\ 1197195684Ssam (v) == 0 ? printf("TxChWidth") : \ 1198195684Ssam (v) == 1 ? printf("MIMOPwrSave") : \ 1199195684Ssam printf("Act#%d", (v)) \ 1200195684Ssam) 1201195684Ssam#define PRINT_BA_ACTION(v) (\ 1202195684Ssam (v) == 0 ? printf("ADDBA Request") : \ 1203195684Ssam (v) == 1 ? printf("ADDBA Response") : \ 1204195684Ssam (v) == 2 ? printf("DELBA") : \ 1205195684Ssam printf("Act#%d", (v)) \ 1206195684Ssam) 1207195684Ssam#define PRINT_MESHLINK_ACTION(v) (\ 1208195684Ssam (v) == 0 ? printf("Request") : \ 1209195684Ssam (v) == 1 ? printf("Report") : \ 1210195684Ssam printf("Act#%d", (v)) \ 1211195684Ssam) 1212195684Ssam#define PRINT_MESHPEERING_ACTION(v) (\ 1213195684Ssam (v) == 0 ? printf("Open") : \ 1214195684Ssam (v) == 1 ? printf("Confirm") : \ 1215195684Ssam (v) == 2 ? printf("Close") : \ 1216195684Ssam printf("Act#%d", (v)) \ 1217195684Ssam) 1218195684Ssam#define PRINT_MESHPATH_ACTION(v) (\ 1219195684Ssam (v) == 0 ? printf("Request") : \ 1220195684Ssam (v) == 1 ? printf("Report") : \ 1221195684Ssam (v) == 2 ? printf("Error") : \ 1222195684Ssam (v) == 3 ? printf("RootAnnouncement") : \ 1223195684Ssam printf("Act#%d", (v)) \ 1224195684Ssam) 122598524Sfenner 1226251158Sdelphij#define PRINT_MESH_ACTION(v) (\ 1227251158Sdelphij (v) == 0 ? printf("MeshLink") : \ 1228251158Sdelphij (v) == 1 ? printf("HWMP") : \ 1229251158Sdelphij (v) == 2 ? printf("Gate Announcement") : \ 1230251158Sdelphij (v) == 3 ? printf("Congestion Control") : \ 1231251158Sdelphij (v) == 4 ? printf("MCCA Setup Request") : \ 1232251158Sdelphij (v) == 5 ? printf("MCCA Setup Reply") : \ 1233251158Sdelphij (v) == 6 ? printf("MCCA Advertisement Request") : \ 1234251158Sdelphij (v) == 7 ? printf("MCCA Advertisement") : \ 1235251158Sdelphij (v) == 8 ? printf("MCCA Teardown") : \ 1236251158Sdelphij (v) == 9 ? printf("TBTT Adjustment Request") : \ 1237251158Sdelphij (v) == 10 ? printf("TBTT Adjustment Response") : \ 1238251158Sdelphij printf("Act#%d", (v)) \ 1239251158Sdelphij) 1240251158Sdelphij#define PRINT_MULTIHOP_ACTION(v) (\ 1241251158Sdelphij (v) == 0 ? printf("Proxy Update") : \ 1242251158Sdelphij (v) == 1 ? printf("Proxy Update Confirmation") : \ 1243251158Sdelphij printf("Act#%d", (v)) \ 1244251158Sdelphij) 1245251158Sdelphij#define PRINT_SELFPROT_ACTION(v) (\ 1246251158Sdelphij (v) == 1 ? printf("Peering Open") : \ 1247251158Sdelphij (v) == 2 ? printf("Peering Confirm") : \ 1248251158Sdelphij (v) == 3 ? printf("Peering Close") : \ 1249251158Sdelphij (v) == 4 ? printf("Group Key Inform") : \ 1250251158Sdelphij (v) == 5 ? printf("Group Key Acknowledge") : \ 1251251158Sdelphij printf("Act#%d", (v)) \ 1252251158Sdelphij) 1253251158Sdelphij 1254195684Ssamstatic int 1255214478Srpaulohandle_action(const struct mgmt_header_t *pmh, const u_char *p, u_int length) 1256195684Ssam{ 1257195684Ssam if (!TTEST2(*p, 2)) 1258195684Ssam return 0; 1259214478Srpaulo if (length < 2) 1260214478Srpaulo return 0; 1261195684Ssam if (eflag) { 1262195684Ssam printf(": "); 1263195684Ssam } else { 1264195684Ssam printf(" (%s): ", etheraddr_string(pmh->sa)); 1265195684Ssam } 1266195684Ssam switch (p[0]) { 1267195684Ssam case 0: printf("Spectrum Management Act#%d", p[1]); break; 1268195684Ssam case 1: printf("QoS Act#%d", p[1]); break; 1269195684Ssam case 2: printf("DLS Act#%d", p[1]); break; 1270195684Ssam case 3: printf("BA "); PRINT_BA_ACTION(p[1]); break; 1271195684Ssam case 7: printf("HT "); PRINT_HT_ACTION(p[1]); break; 1272251158Sdelphij case 13: printf("MeshAction "); PRINT_MESH_ACTION(p[1]); break; 1273251158Sdelphij case 14: 1274251158Sdelphij printf("MultiohopAction "); 1275251158Sdelphij PRINT_MULTIHOP_ACTION(p[1]); break; 1276251158Sdelphij case 15: 1277251158Sdelphij printf("SelfprotectAction "); 1278251158Sdelphij PRINT_SELFPROT_ACTION(p[1]); break; 1279195684Ssam case 127: printf("Vendor Act#%d", p[1]); break; 1280195684Ssam default: 1281195684Ssam printf("Reserved(%d) Act#%d", p[0], p[1]); 1282195684Ssam break; 1283195684Ssam } 1284195684Ssam return 1; 1285195684Ssam} 1286195684Ssam 1287195684Ssam 128898524Sfenner/********************************************************************************* 128998524Sfenner * Print Body funcs 129098524Sfenner *********************************************************************************/ 129198524Sfenner 129298524Sfenner 1293127668Sbmsstatic int 1294127668Sbmsmgmt_body_print(u_int16_t fc, const struct mgmt_header_t *pmh, 1295214478Srpaulo const u_char *p, u_int length) 129698524Sfenner{ 129798524Sfenner switch (FC_SUBTYPE(fc)) { 129898524Sfenner case ST_ASSOC_REQUEST: 1299162017Ssam printf("Assoc Request"); 1300214478Srpaulo return handle_assoc_request(p, length); 130198524Sfenner case ST_ASSOC_RESPONSE: 1302162017Ssam printf("Assoc Response"); 1303214478Srpaulo return handle_assoc_response(p, length); 130498524Sfenner case ST_REASSOC_REQUEST: 1305162017Ssam printf("ReAssoc Request"); 1306214478Srpaulo return handle_reassoc_request(p, length); 130798524Sfenner case ST_REASSOC_RESPONSE: 1308162017Ssam printf("ReAssoc Response"); 1309214478Srpaulo return handle_reassoc_response(p, length); 131098524Sfenner case ST_PROBE_REQUEST: 1311162017Ssam printf("Probe Request"); 1312214478Srpaulo return handle_probe_request(p, length); 131398524Sfenner case ST_PROBE_RESPONSE: 1314162017Ssam printf("Probe Response"); 1315214478Srpaulo return handle_probe_response(p, length); 131698524Sfenner case ST_BEACON: 1317162017Ssam printf("Beacon"); 1318214478Srpaulo return handle_beacon(p, length); 131998524Sfenner case ST_ATIM: 1320162017Ssam printf("ATIM"); 1321127668Sbms return handle_atim(); 132298524Sfenner case ST_DISASSOC: 1323162017Ssam printf("Disassociation"); 1324214478Srpaulo return handle_disassoc(p, length); 132598524Sfenner case ST_AUTH: 1326162017Ssam printf("Authentication"); 132798524Sfenner if (!TTEST2(*p, 3)) 132898524Sfenner return 0; 132998524Sfenner if ((p[0] == 0 ) && (p[1] == 0) && (p[2] == 0)) { 133098524Sfenner printf("Authentication (Shared-Key)-3 "); 1331127668Sbms return wep_print(p); 133298524Sfenner } 1333214478Srpaulo return handle_auth(p, length); 133498524Sfenner case ST_DEAUTH: 1335162017Ssam printf("DeAuthentication"); 1336214478Srpaulo return handle_deauth(pmh, p, length); 133798524Sfenner break; 1338195684Ssam case ST_ACTION: 1339195684Ssam printf("Action"); 1340214478Srpaulo return handle_action(pmh, p, length); 1341195684Ssam break; 134298524Sfenner default: 1343127668Sbms printf("Unhandled Management subtype(%x)", 134498524Sfenner FC_SUBTYPE(fc)); 134598524Sfenner return 1; 134698524Sfenner } 134798524Sfenner} 134898524Sfenner 134998524Sfenner 135098524Sfenner/********************************************************************************* 135198524Sfenner * Handles printing all the control frame types 135298524Sfenner *********************************************************************************/ 135398524Sfenner 1354127668Sbmsstatic int 1355127668Sbmsctrl_body_print(u_int16_t fc, const u_char *p) 135698524Sfenner{ 135798524Sfenner switch (FC_SUBTYPE(fc)) { 1358214478Srpaulo case CTRL_CONTROL_WRAPPER: 1359214478Srpaulo printf("Control Wrapper"); 1360214478Srpaulo /* XXX - requires special handling */ 1361214478Srpaulo break; 1362170533Ssam case CTRL_BAR: 1363170533Ssam printf("BAR"); 1364170533Ssam if (!TTEST2(*p, CTRL_BAR_HDRLEN)) 1365170533Ssam return 0; 1366170533Ssam if (!eflag) 1367170533Ssam printf(" RA:%s TA:%s CTL(%x) SEQ(%u) ", 1368170533Ssam etheraddr_string(((const struct ctrl_bar_t *)p)->ra), 1369170533Ssam etheraddr_string(((const struct ctrl_bar_t *)p)->ta), 1370170533Ssam EXTRACT_LE_16BITS(&(((const struct ctrl_bar_t *)p)->ctl)), 1371170533Ssam EXTRACT_LE_16BITS(&(((const struct ctrl_bar_t *)p)->seq))); 1372170533Ssam break; 1373195684Ssam case CTRL_BA: 1374195684Ssam printf("BA"); 1375195684Ssam if (!TTEST2(*p, CTRL_BA_HDRLEN)) 1376195684Ssam return 0; 1377195684Ssam if (!eflag) 1378195684Ssam printf(" RA:%s ", 1379195684Ssam etheraddr_string(((const struct ctrl_ba_t *)p)->ra)); 1380195684Ssam break; 138198524Sfenner case CTRL_PS_POLL: 1382127668Sbms printf("Power Save-Poll"); 1383127668Sbms if (!TTEST2(*p, CTRL_PS_POLL_HDRLEN)) 138498524Sfenner return 0; 1385127668Sbms printf(" AID(%x)", 138698524Sfenner EXTRACT_LE_16BITS(&(((const struct ctrl_ps_poll_t *)p)->aid))); 138798524Sfenner break; 138898524Sfenner case CTRL_RTS: 1389127668Sbms printf("Request-To-Send"); 1390127668Sbms if (!TTEST2(*p, CTRL_RTS_HDRLEN)) 139198524Sfenner return 0; 1392127668Sbms if (!eflag) 1393127668Sbms printf(" TA:%s ", 139498524Sfenner etheraddr_string(((const struct ctrl_rts_t *)p)->ta)); 139598524Sfenner break; 139698524Sfenner case CTRL_CTS: 1397127668Sbms printf("Clear-To-Send"); 1398127668Sbms if (!TTEST2(*p, CTRL_CTS_HDRLEN)) 139998524Sfenner return 0; 1400127668Sbms if (!eflag) 1401127668Sbms printf(" RA:%s ", 140298524Sfenner etheraddr_string(((const struct ctrl_cts_t *)p)->ra)); 140398524Sfenner break; 140498524Sfenner case CTRL_ACK: 1405127668Sbms printf("Acknowledgment"); 1406127668Sbms if (!TTEST2(*p, CTRL_ACK_HDRLEN)) 140798524Sfenner return 0; 1408127668Sbms if (!eflag) 1409127668Sbms printf(" RA:%s ", 141098524Sfenner etheraddr_string(((const struct ctrl_ack_t *)p)->ra)); 141198524Sfenner break; 141298524Sfenner case CTRL_CF_END: 1413127668Sbms printf("CF-End"); 1414127668Sbms if (!TTEST2(*p, CTRL_END_HDRLEN)) 141598524Sfenner return 0; 1416127668Sbms if (!eflag) 1417127668Sbms printf(" RA:%s ", 141898524Sfenner etheraddr_string(((const struct ctrl_end_t *)p)->ra)); 141998524Sfenner break; 142098524Sfenner case CTRL_END_ACK: 1421127668Sbms printf("CF-End+CF-Ack"); 1422127668Sbms if (!TTEST2(*p, CTRL_END_ACK_HDRLEN)) 142398524Sfenner return 0; 1424127668Sbms if (!eflag) 1425127668Sbms printf(" RA:%s ", 142698524Sfenner etheraddr_string(((const struct ctrl_end_ack_t *)p)->ra)); 142798524Sfenner break; 142898524Sfenner default: 1429127668Sbms printf("Unknown Ctrl Subtype"); 143098524Sfenner } 143198524Sfenner return 1; 143298524Sfenner} 143398524Sfenner 143498524Sfenner/* 143598524Sfenner * Print Header funcs 143698524Sfenner */ 143798524Sfenner 143898524Sfenner/* 143998524Sfenner * Data Frame - Address field contents 144098524Sfenner * 144198524Sfenner * To Ds | From DS | Addr 1 | Addr 2 | Addr 3 | Addr 4 144298524Sfenner * 0 | 0 | DA | SA | BSSID | n/a 144398524Sfenner * 0 | 1 | DA | BSSID | SA | n/a 144498524Sfenner * 1 | 0 | BSSID | SA | DA | n/a 144598524Sfenner * 1 | 1 | RA | TA | DA | SA 144698524Sfenner */ 144798524Sfenner 1448127668Sbmsstatic void 1449127668Sbmsdata_header_print(u_int16_t fc, const u_char *p, const u_int8_t **srcp, 1450127668Sbms const u_int8_t **dstp) 145198524Sfenner{ 1452172686Smlaier u_int subtype = FC_SUBTYPE(fc); 1453172686Smlaier 1454172686Smlaier if (DATA_FRAME_IS_CF_ACK(subtype) || DATA_FRAME_IS_CF_POLL(subtype) || 1455172686Smlaier DATA_FRAME_IS_QOS(subtype)) { 1456172686Smlaier printf("CF "); 1457172686Smlaier if (DATA_FRAME_IS_CF_ACK(subtype)) { 1458172686Smlaier if (DATA_FRAME_IS_CF_POLL(subtype)) 1459172686Smlaier printf("Ack/Poll"); 1460172686Smlaier else 1461172686Smlaier printf("Ack"); 1462172686Smlaier } else { 1463172686Smlaier if (DATA_FRAME_IS_CF_POLL(subtype)) 1464172686Smlaier printf("Poll"); 1465172686Smlaier } 1466172686Smlaier if (DATA_FRAME_IS_QOS(subtype)) 1467172686Smlaier printf("+QoS"); 1468172686Smlaier printf(" "); 1469127668Sbms } 1470127668Sbms 147198524Sfenner#define ADDR1 (p + 4) 147298524Sfenner#define ADDR2 (p + 10) 147398524Sfenner#define ADDR3 (p + 16) 147498524Sfenner#define ADDR4 (p + 24) 147598524Sfenner 1476127668Sbms if (!FC_TO_DS(fc) && !FC_FROM_DS(fc)) { 1477127668Sbms if (srcp != NULL) 1478127668Sbms *srcp = ADDR2; 1479127668Sbms if (dstp != NULL) 1480127668Sbms *dstp = ADDR1; 1481127668Sbms if (!eflag) 1482127668Sbms return; 1483127668Sbms printf("DA:%s SA:%s BSSID:%s ", 1484127668Sbms etheraddr_string(ADDR1), etheraddr_string(ADDR2), 1485127668Sbms etheraddr_string(ADDR3)); 1486127668Sbms } else if (!FC_TO_DS(fc) && FC_FROM_DS(fc)) { 1487127668Sbms if (srcp != NULL) 1488127668Sbms *srcp = ADDR3; 1489127668Sbms if (dstp != NULL) 1490127668Sbms *dstp = ADDR1; 1491127668Sbms if (!eflag) 1492127668Sbms return; 1493127668Sbms printf("DA:%s BSSID:%s SA:%s ", 1494127668Sbms etheraddr_string(ADDR1), etheraddr_string(ADDR2), 1495127668Sbms etheraddr_string(ADDR3)); 1496127668Sbms } else if (FC_TO_DS(fc) && !FC_FROM_DS(fc)) { 1497127668Sbms if (srcp != NULL) 1498127668Sbms *srcp = ADDR2; 1499127668Sbms if (dstp != NULL) 1500127668Sbms *dstp = ADDR3; 1501127668Sbms if (!eflag) 1502127668Sbms return; 1503127668Sbms printf("BSSID:%s SA:%s DA:%s ", 1504127668Sbms etheraddr_string(ADDR1), etheraddr_string(ADDR2), 1505127668Sbms etheraddr_string(ADDR3)); 1506127668Sbms } else if (FC_TO_DS(fc) && FC_FROM_DS(fc)) { 1507127668Sbms if (srcp != NULL) 1508127668Sbms *srcp = ADDR4; 1509127668Sbms if (dstp != NULL) 1510127668Sbms *dstp = ADDR3; 1511127668Sbms if (!eflag) 1512127668Sbms return; 1513127668Sbms printf("RA:%s TA:%s DA:%s SA:%s ", 1514127668Sbms etheraddr_string(ADDR1), etheraddr_string(ADDR2), 1515127668Sbms etheraddr_string(ADDR3), etheraddr_string(ADDR4)); 151698524Sfenner } 151798524Sfenner 151898524Sfenner#undef ADDR1 151998524Sfenner#undef ADDR2 152098524Sfenner#undef ADDR3 152198524Sfenner#undef ADDR4 152298524Sfenner} 152398524Sfenner 1524127668Sbmsstatic void 1525127668Sbmsmgmt_header_print(const u_char *p, const u_int8_t **srcp, 1526127668Sbms const u_int8_t **dstp) 152798524Sfenner{ 152898524Sfenner const struct mgmt_header_t *hp = (const struct mgmt_header_t *) p; 152998524Sfenner 1530127668Sbms if (srcp != NULL) 1531127668Sbms *srcp = hp->sa; 1532127668Sbms if (dstp != NULL) 1533127668Sbms *dstp = hp->da; 1534127668Sbms if (!eflag) 1535127668Sbms return; 1536127668Sbms 153798524Sfenner printf("BSSID:%s DA:%s SA:%s ", 153898524Sfenner etheraddr_string((hp)->bssid), etheraddr_string((hp)->da), 153998524Sfenner etheraddr_string((hp)->sa)); 154098524Sfenner} 154198524Sfenner 1542127668Sbmsstatic void 1543127668Sbmsctrl_header_print(u_int16_t fc, const u_char *p, const u_int8_t **srcp, 1544127668Sbms const u_int8_t **dstp) 154598524Sfenner{ 1546127668Sbms if (srcp != NULL) 1547127668Sbms *srcp = NULL; 1548127668Sbms if (dstp != NULL) 1549127668Sbms *dstp = NULL; 1550127668Sbms if (!eflag) 1551127668Sbms return; 1552127668Sbms 155398524Sfenner switch (FC_SUBTYPE(fc)) { 1554170533Ssam case CTRL_BAR: 1555170533Ssam printf(" RA:%s TA:%s CTL(%x) SEQ(%u) ", 1556170533Ssam etheraddr_string(((const struct ctrl_bar_t *)p)->ra), 1557170533Ssam etheraddr_string(((const struct ctrl_bar_t *)p)->ta), 1558170533Ssam EXTRACT_LE_16BITS(&(((const struct ctrl_bar_t *)p)->ctl)), 1559170533Ssam EXTRACT_LE_16BITS(&(((const struct ctrl_bar_t *)p)->seq))); 1560170533Ssam break; 1561195684Ssam case CTRL_BA: 1562195684Ssam printf("RA:%s ", 1563195684Ssam etheraddr_string(((const struct ctrl_ba_t *)p)->ra)); 1564195684Ssam break; 156598524Sfenner case CTRL_PS_POLL: 156698524Sfenner printf("BSSID:%s TA:%s ", 156798524Sfenner etheraddr_string(((const struct ctrl_ps_poll_t *)p)->bssid), 156898524Sfenner etheraddr_string(((const struct ctrl_ps_poll_t *)p)->ta)); 156998524Sfenner break; 157098524Sfenner case CTRL_RTS: 157198524Sfenner printf("RA:%s TA:%s ", 157298524Sfenner etheraddr_string(((const struct ctrl_rts_t *)p)->ra), 157398524Sfenner etheraddr_string(((const struct ctrl_rts_t *)p)->ta)); 157498524Sfenner break; 157598524Sfenner case CTRL_CTS: 157698524Sfenner printf("RA:%s ", 157798524Sfenner etheraddr_string(((const struct ctrl_cts_t *)p)->ra)); 157898524Sfenner break; 157998524Sfenner case CTRL_ACK: 158098524Sfenner printf("RA:%s ", 158198524Sfenner etheraddr_string(((const struct ctrl_ack_t *)p)->ra)); 158298524Sfenner break; 158398524Sfenner case CTRL_CF_END: 158498524Sfenner printf("RA:%s BSSID:%s ", 158598524Sfenner etheraddr_string(((const struct ctrl_end_t *)p)->ra), 158698524Sfenner etheraddr_string(((const struct ctrl_end_t *)p)->bssid)); 158798524Sfenner break; 158898524Sfenner case CTRL_END_ACK: 158998524Sfenner printf("RA:%s BSSID:%s ", 159098524Sfenner etheraddr_string(((const struct ctrl_end_ack_t *)p)->ra), 159198524Sfenner etheraddr_string(((const struct ctrl_end_ack_t *)p)->bssid)); 159298524Sfenner break; 159398524Sfenner default: 159498524Sfenner printf("(H) Unknown Ctrl Subtype"); 1595127668Sbms break; 159698524Sfenner } 159798524Sfenner} 159898524Sfenner 1599127668Sbmsstatic int 1600127668Sbmsextract_header_length(u_int16_t fc) 160198524Sfenner{ 1602172686Smlaier int len; 1603172686Smlaier 160498524Sfenner switch (FC_TYPE(fc)) { 160598524Sfenner case T_MGMT: 1606127668Sbms return MGMT_HDRLEN; 160798524Sfenner case T_CTRL: 160898524Sfenner switch (FC_SUBTYPE(fc)) { 1609170533Ssam case CTRL_BAR: 1610170533Ssam return CTRL_BAR_HDRLEN; 161198524Sfenner case CTRL_PS_POLL: 1612127668Sbms return CTRL_PS_POLL_HDRLEN; 161398524Sfenner case CTRL_RTS: 1614127668Sbms return CTRL_RTS_HDRLEN; 161598524Sfenner case CTRL_CTS: 1616127668Sbms return CTRL_CTS_HDRLEN; 161798524Sfenner case CTRL_ACK: 1618127668Sbms return CTRL_ACK_HDRLEN; 161998524Sfenner case CTRL_CF_END: 1620127668Sbms return CTRL_END_HDRLEN; 162198524Sfenner case CTRL_END_ACK: 1622127668Sbms return CTRL_END_ACK_HDRLEN; 162398524Sfenner default: 1624127668Sbms return 0; 162598524Sfenner } 162698524Sfenner case T_DATA: 1627172686Smlaier len = (FC_TO_DS(fc) && FC_FROM_DS(fc)) ? 30 : 24; 1628172686Smlaier if (DATA_FRAME_IS_QOS(FC_SUBTYPE(fc))) 1629172686Smlaier len += 2; 1630172686Smlaier return len; 163198524Sfenner default: 1632127668Sbms printf("unknown IEEE802.11 frame type (%d)", FC_TYPE(fc)); 1633127668Sbms return 0; 163498524Sfenner } 163598524Sfenner} 163698524Sfenner 1637195684Ssamstatic int 1638195684Ssamextract_mesh_header_length(const u_char *p) 1639195684Ssam{ 1640195684Ssam return (p[0] &~ 3) ? 0 : 6*(1 + (p[0] & 3)); 1641195684Ssam} 1642195684Ssam 164398524Sfenner/* 1644127668Sbms * Print the 802.11 MAC header if eflag is set, and set "*srcp" and "*dstp" 1645127668Sbms * to point to the source and destination MAC addresses in any case if 1646127668Sbms * "srcp" and "dstp" aren't null. 164798524Sfenner */ 1648195684Ssamstatic void 1649195684Ssamieee_802_11_hdr_print(u_int16_t fc, const u_char *p, u_int hdrlen, 1650195684Ssam u_int meshdrlen, const u_int8_t **srcp, const u_int8_t **dstp) 165198524Sfenner{ 1652127668Sbms if (vflag) { 1653127668Sbms if (FC_MORE_DATA(fc)) 1654127668Sbms printf("More Data "); 1655127668Sbms if (FC_MORE_FLAG(fc)) 1656127668Sbms printf("More Fragments "); 1657127668Sbms if (FC_POWER_MGMT(fc)) 1658127668Sbms printf("Pwr Mgmt "); 1659127668Sbms if (FC_RETRY(fc)) 1660127668Sbms printf("Retry "); 1661127668Sbms if (FC_ORDER(fc)) 1662127668Sbms printf("Strictly Ordered "); 1663127668Sbms if (FC_WEP(fc)) 1664127668Sbms printf("WEP Encrypted "); 1665127668Sbms if (FC_TYPE(fc) != T_CTRL || FC_SUBTYPE(fc) != CTRL_PS_POLL) 1666127668Sbms printf("%dus ", 1667127668Sbms EXTRACT_LE_16BITS( 1668127668Sbms &((const struct mgmt_header_t *)p)->duration)); 1669127668Sbms } 1670195684Ssam if (meshdrlen != 0) { 1671195684Ssam const struct meshcntl_t *mc = 1672195684Ssam (const struct meshcntl_t *)&p[hdrlen - meshdrlen]; 1673195684Ssam int ae = mc->flags & 3; 1674127668Sbms 1675195684Ssam printf("MeshData (AE %d TTL %u seq %u", ae, mc->ttl, 1676195684Ssam EXTRACT_LE_32BITS(mc->seq)); 1677195684Ssam if (ae > 0) 1678195684Ssam printf(" A4:%s", etheraddr_string(mc->addr4)); 1679195684Ssam if (ae > 1) 1680195684Ssam printf(" A5:%s", etheraddr_string(mc->addr5)); 1681195684Ssam if (ae > 2) 1682195684Ssam printf(" A6:%s", etheraddr_string(mc->addr6)); 1683195684Ssam printf(") "); 1684195684Ssam } 1685195684Ssam 168698524Sfenner switch (FC_TYPE(fc)) { 168798524Sfenner case T_MGMT: 1688127668Sbms mgmt_header_print(p, srcp, dstp); 168998524Sfenner break; 169098524Sfenner case T_CTRL: 1691127668Sbms ctrl_header_print(fc, p, srcp, dstp); 169298524Sfenner break; 169398524Sfenner case T_DATA: 1694127668Sbms data_header_print(fc, p, srcp, dstp); 169598524Sfenner break; 169698524Sfenner default: 169798524Sfenner printf("(header) unknown IEEE802.11 frame type (%d)", 169898524Sfenner FC_TYPE(fc)); 1699127668Sbms *srcp = NULL; 1700127668Sbms *dstp = NULL; 170198524Sfenner break; 170298524Sfenner } 170398524Sfenner} 170498524Sfenner 1705172686Smlaier#ifndef roundup2 1706172686Smlaier#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */ 1707172686Smlaier#endif 1708172686Smlaier 1709127668Sbmsstatic u_int 1710214478Srpauloieee802_11_print(const u_char *p, u_int length, u_int orig_caplen, int pad, 1711214478Srpaulo u_int fcslen) 171298524Sfenner{ 171398524Sfenner u_int16_t fc; 1714214478Srpaulo u_int caplen, hdrlen, meshdrlen; 1715127668Sbms const u_int8_t *src, *dst; 171698524Sfenner u_short extracted_ethertype; 171798524Sfenner 1718214478Srpaulo caplen = orig_caplen; 1719214478Srpaulo /* Remove FCS, if present */ 1720214478Srpaulo if (length < fcslen) { 172198524Sfenner printf("[|802.11]"); 1722127668Sbms return caplen; 172398524Sfenner } 1724214478Srpaulo length -= fcslen; 1725214478Srpaulo if (caplen > length) { 1726214478Srpaulo /* Amount of FCS in actual packet data, if any */ 1727214478Srpaulo fcslen = caplen - length; 1728214478Srpaulo caplen -= fcslen; 1729214478Srpaulo snapend -= fcslen; 1730214478Srpaulo } 173198524Sfenner 1732214478Srpaulo if (caplen < IEEE802_11_FC_LEN) { 1733214478Srpaulo printf("[|802.11]"); 1734214478Srpaulo return orig_caplen; 1735214478Srpaulo } 1736214478Srpaulo 1737127668Sbms fc = EXTRACT_LE_16BITS(p); 1738127668Sbms hdrlen = extract_header_length(fc); 1739172686Smlaier if (pad) 1740172686Smlaier hdrlen = roundup2(hdrlen, 4); 1741235530Sdelphij if (Hflag && FC_TYPE(fc) == T_DATA && 1742235530Sdelphij DATA_FRAME_IS_QOS(FC_SUBTYPE(fc))) { 1743195684Ssam meshdrlen = extract_mesh_header_length(p+hdrlen); 1744195684Ssam hdrlen += meshdrlen; 1745195684Ssam } else 1746195684Ssam meshdrlen = 0; 174798524Sfenner 1748195684Ssam 1749127668Sbms if (caplen < hdrlen) { 1750127668Sbms printf("[|802.11]"); 1751127668Sbms return hdrlen; 1752127668Sbms } 175398524Sfenner 1754195684Ssam ieee_802_11_hdr_print(fc, p, hdrlen, meshdrlen, &src, &dst); 1755127668Sbms 175698524Sfenner /* 1757127668Sbms * Go past the 802.11 header. 175898524Sfenner */ 1759127668Sbms length -= hdrlen; 1760127668Sbms caplen -= hdrlen; 1761127668Sbms p += hdrlen; 176298524Sfenner 176398524Sfenner switch (FC_TYPE(fc)) { 176498524Sfenner case T_MGMT: 1765127668Sbms if (!mgmt_body_print(fc, 1766214478Srpaulo (const struct mgmt_header_t *)(p - hdrlen), p, length)) { 176798524Sfenner printf("[|802.11]"); 1768127668Sbms return hdrlen; 176998524Sfenner } 177098524Sfenner break; 177198524Sfenner case T_CTRL: 1772127668Sbms if (!ctrl_body_print(fc, p - hdrlen)) { 177398524Sfenner printf("[|802.11]"); 1774127668Sbms return hdrlen; 177598524Sfenner } 177698524Sfenner break; 177798524Sfenner case T_DATA: 1778172686Smlaier if (DATA_FRAME_IS_NULL(FC_SUBTYPE(fc))) 1779172686Smlaier return hdrlen; /* no-data frame */ 178098524Sfenner /* There may be a problem w/ AP not having this bit set */ 1781127668Sbms if (FC_WEP(fc)) { 1782127668Sbms if (!wep_print(p)) { 178398524Sfenner printf("[|802.11]"); 1784127668Sbms return hdrlen; 178598524Sfenner } 1786127668Sbms } else if (llc_print(p, length, caplen, dst, src, 1787127668Sbms &extracted_ethertype) == 0) { 1788127668Sbms /* 1789127668Sbms * Some kinds of LLC packet we cannot 1790127668Sbms * handle intelligently 1791127668Sbms */ 1792127668Sbms if (!eflag) 1793195684Ssam ieee_802_11_hdr_print(fc, p - hdrlen, hdrlen, 1794195684Ssam meshdrlen, NULL, NULL); 1795127668Sbms if (extracted_ethertype) 1796127668Sbms printf("(LLC %s) ", 1797127668Sbms etherproto_string( 1798127668Sbms htons(extracted_ethertype))); 1799162017Ssam if (!suppress_default_print) 1800127668Sbms default_print(p, caplen); 180198524Sfenner } 180298524Sfenner break; 180398524Sfenner default: 1804127668Sbms printf("unknown 802.11 frame type (%d)", FC_TYPE(fc)); 180598524Sfenner break; 180698524Sfenner } 180798524Sfenner 1808127668Sbms return hdrlen; 180998524Sfenner} 1810127668Sbms 1811127668Sbms/* 1812127668Sbms * This is the top level routine of the printer. 'p' points 1813127668Sbms * to the 802.11 header of the packet, 'h->ts' is the timestamp, 1814146773Ssam * 'h->len' is the length of the packet off the wire, and 'h->caplen' 1815127668Sbms * is the number of bytes actually captured. 1816127668Sbms */ 1817127668Sbmsu_int 1818127668Sbmsieee802_11_if_print(const struct pcap_pkthdr *h, const u_char *p) 1819127668Sbms{ 1820214478Srpaulo return ieee802_11_print(p, h->len, h->caplen, 0, 0); 1821127668Sbms} 1822127668Sbms 1823170533Ssam#define IEEE80211_CHAN_FHSS \ 1824170533Ssam (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK) 1825170533Ssam#define IEEE80211_CHAN_A \ 1826170533Ssam (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM) 1827170533Ssam#define IEEE80211_CHAN_B \ 1828170533Ssam (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK) 1829170533Ssam#define IEEE80211_CHAN_PUREG \ 1830170533Ssam (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM) 1831170533Ssam#define IEEE80211_CHAN_G \ 1832170533Ssam (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN) 1833170533Ssam 1834170533Ssam#define IS_CHAN_FHSS(flags) \ 1835170533Ssam ((flags & IEEE80211_CHAN_FHSS) == IEEE80211_CHAN_FHSS) 1836170533Ssam#define IS_CHAN_A(flags) \ 1837170533Ssam ((flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) 1838170533Ssam#define IS_CHAN_B(flags) \ 1839170533Ssam ((flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B) 1840170533Ssam#define IS_CHAN_PUREG(flags) \ 1841170533Ssam ((flags & IEEE80211_CHAN_PUREG) == IEEE80211_CHAN_PUREG) 1842170533Ssam#define IS_CHAN_G(flags) \ 1843170533Ssam ((flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) 1844170533Ssam#define IS_CHAN_ANYG(flags) \ 1845170533Ssam (IS_CHAN_PUREG(flags) || IS_CHAN_G(flags)) 1846170533Ssam 1847170533Ssamstatic void 1848170533Ssamprint_chaninfo(int freq, int flags) 1849170533Ssam{ 1850170533Ssam printf("%u MHz", freq); 1851170533Ssam if (IS_CHAN_FHSS(flags)) 1852170533Ssam printf(" FHSS"); 1853170533Ssam if (IS_CHAN_A(flags)) { 1854170533Ssam if (flags & IEEE80211_CHAN_HALF) 1855170533Ssam printf(" 11a/10Mhz"); 1856170533Ssam else if (flags & IEEE80211_CHAN_QUARTER) 1857170533Ssam printf(" 11a/5Mhz"); 1858170533Ssam else 1859170533Ssam printf(" 11a"); 1860170533Ssam } 1861170533Ssam if (IS_CHAN_ANYG(flags)) { 1862170533Ssam if (flags & IEEE80211_CHAN_HALF) 1863170533Ssam printf(" 11g/10Mhz"); 1864170533Ssam else if (flags & IEEE80211_CHAN_QUARTER) 1865170533Ssam printf(" 11g/5Mhz"); 1866170533Ssam else 1867170533Ssam printf(" 11g"); 1868170533Ssam } else if (IS_CHAN_B(flags)) 1869170533Ssam printf(" 11b"); 1870170533Ssam if (flags & IEEE80211_CHAN_TURBO) 1871170533Ssam printf(" Turbo"); 1872170533Ssam if (flags & IEEE80211_CHAN_HT20) 1873170533Ssam printf(" ht/20"); 1874170533Ssam else if (flags & IEEE80211_CHAN_HT40D) 1875170533Ssam printf(" ht/40-"); 1876170533Ssam else if (flags & IEEE80211_CHAN_HT40U) 1877170533Ssam printf(" ht/40+"); 1878170533Ssam printf(" "); 1879170533Ssam} 1880170533Ssam 1881146773Ssamstatic int 1882235530Sdelphijprint_radiotap_field(struct cpack_state *s, u_int32_t bit, u_int8_t *flags, 1883235530Sdelphij struct radiotap_state *state, u_int32_t presentflags) 1884146773Ssam{ 1885146773Ssam union { 1886146773Ssam int8_t i8; 1887146773Ssam u_int8_t u8; 1888146773Ssam int16_t i16; 1889146773Ssam u_int16_t u16; 1890146773Ssam u_int32_t u32; 1891146773Ssam u_int64_t u64; 1892170533Ssam } u, u2, u3, u4; 1893146773Ssam int rc; 1894146773Ssam 1895146773Ssam switch (bit) { 1896146773Ssam case IEEE80211_RADIOTAP_FLAGS: 1897172686Smlaier rc = cpack_uint8(s, &u.u8); 1898235530Sdelphij if (rc != 0) 1899235530Sdelphij break; 1900214478Srpaulo *flags = u.u8; 1901172686Smlaier break; 1902146773Ssam case IEEE80211_RADIOTAP_RATE: 1903235530Sdelphij rc = cpack_uint8(s, &u.u8); 1904235530Sdelphij if (rc != 0) 1905235530Sdelphij break; 1906235530Sdelphij 1907235530Sdelphij /* Save state rate */ 1908235530Sdelphij state->rate = u.u8; 1909235530Sdelphij break; 1910146773Ssam case IEEE80211_RADIOTAP_DB_ANTSIGNAL: 1911146773Ssam case IEEE80211_RADIOTAP_DB_ANTNOISE: 1912146773Ssam case IEEE80211_RADIOTAP_ANTENNA: 1913146773Ssam rc = cpack_uint8(s, &u.u8); 1914146773Ssam break; 1915146773Ssam case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: 1916146773Ssam case IEEE80211_RADIOTAP_DBM_ANTNOISE: 1917146773Ssam rc = cpack_int8(s, &u.i8); 1918146773Ssam break; 1919146773Ssam case IEEE80211_RADIOTAP_CHANNEL: 1920146773Ssam rc = cpack_uint16(s, &u.u16); 1921146773Ssam if (rc != 0) 1922146773Ssam break; 1923146773Ssam rc = cpack_uint16(s, &u2.u16); 1924146773Ssam break; 1925146773Ssam case IEEE80211_RADIOTAP_FHSS: 1926146773Ssam case IEEE80211_RADIOTAP_LOCK_QUALITY: 1927146773Ssam case IEEE80211_RADIOTAP_TX_ATTENUATION: 1928235530Sdelphij case IEEE80211_RADIOTAP_RX_FLAGS: 1929146773Ssam rc = cpack_uint16(s, &u.u16); 1930146773Ssam break; 1931146773Ssam case IEEE80211_RADIOTAP_DB_TX_ATTENUATION: 1932146773Ssam rc = cpack_uint8(s, &u.u8); 1933146773Ssam break; 1934146773Ssam case IEEE80211_RADIOTAP_DBM_TX_POWER: 1935146773Ssam rc = cpack_int8(s, &u.i8); 1936146773Ssam break; 1937146773Ssam case IEEE80211_RADIOTAP_TSFT: 1938146773Ssam rc = cpack_uint64(s, &u.u64); 1939146773Ssam break; 1940170533Ssam case IEEE80211_RADIOTAP_XCHANNEL: 1941170533Ssam rc = cpack_uint32(s, &u.u32); 1942170533Ssam if (rc != 0) 1943170533Ssam break; 1944170533Ssam rc = cpack_uint16(s, &u2.u16); 1945170533Ssam if (rc != 0) 1946170533Ssam break; 1947170533Ssam rc = cpack_uint8(s, &u3.u8); 1948170533Ssam if (rc != 0) 1949170533Ssam break; 1950170533Ssam rc = cpack_uint8(s, &u4.u8); 1951170533Ssam break; 1952235530Sdelphij case IEEE80211_RADIOTAP_MCS: 1953235530Sdelphij rc = cpack_uint8(s, &u.u8); 1954235530Sdelphij if (rc != 0) 1955235530Sdelphij break; 1956235530Sdelphij rc = cpack_uint8(s, &u2.u8); 1957235530Sdelphij if (rc != 0) 1958235530Sdelphij break; 1959235530Sdelphij rc = cpack_uint8(s, &u3.u8); 1960235530Sdelphij break; 1961235530Sdelphij case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: { 1962235530Sdelphij u_int8_t vns[3]; 1963235530Sdelphij u_int16_t length; 1964235530Sdelphij u_int8_t subspace; 1965235530Sdelphij 1966235530Sdelphij if ((cpack_align_and_reserve(s, 2)) == NULL) { 1967235530Sdelphij rc = -1; 1968235530Sdelphij break; 1969235530Sdelphij } 1970235530Sdelphij 1971235530Sdelphij rc = cpack_uint8(s, &vns[0]); 1972235530Sdelphij if (rc != 0) 1973235530Sdelphij break; 1974235530Sdelphij rc = cpack_uint8(s, &vns[1]); 1975235530Sdelphij if (rc != 0) 1976235530Sdelphij break; 1977235530Sdelphij rc = cpack_uint8(s, &vns[2]); 1978235530Sdelphij if (rc != 0) 1979235530Sdelphij break; 1980235530Sdelphij rc = cpack_uint8(s, &subspace); 1981235530Sdelphij if (rc != 0) 1982235530Sdelphij break; 1983235530Sdelphij rc = cpack_uint16(s, &length); 1984235530Sdelphij if (rc != 0) 1985235530Sdelphij break; 1986235530Sdelphij 1987235530Sdelphij /* Skip up to length */ 1988235530Sdelphij s->c_next += length; 1989235530Sdelphij break; 1990235530Sdelphij } 1991146773Ssam default: 1992146773Ssam /* this bit indicates a field whose 1993146773Ssam * size we do not know, so we cannot 1994214478Srpaulo * proceed. Just print the bit number. 1995146773Ssam */ 1996214478Srpaulo printf("[bit %u] ", bit); 1997146773Ssam return -1; 1998146773Ssam } 1999146773Ssam 2000146773Ssam if (rc != 0) { 2001146773Ssam printf("[|802.11]"); 2002146773Ssam return rc; 2003146773Ssam } 2004146773Ssam 2005235530Sdelphij /* Preserve the state present flags */ 2006235530Sdelphij state->present = presentflags; 2007235530Sdelphij 2008146773Ssam switch (bit) { 2009146773Ssam case IEEE80211_RADIOTAP_CHANNEL: 2010235530Sdelphij /* 2011235530Sdelphij * If CHANNEL and XCHANNEL are both present, skip 2012235530Sdelphij * CHANNEL. 2013235530Sdelphij */ 2014235530Sdelphij if (presentflags & (1 << IEEE80211_RADIOTAP_XCHANNEL)) 2015235530Sdelphij break; 2016170533Ssam print_chaninfo(u.u16, u2.u16); 2017146773Ssam break; 2018146773Ssam case IEEE80211_RADIOTAP_FHSS: 2019146773Ssam printf("fhset %d fhpat %d ", u.u16 & 0xff, (u.u16 >> 8) & 0xff); 2020146773Ssam break; 2021146773Ssam case IEEE80211_RADIOTAP_RATE: 2022235530Sdelphij /* 2023235530Sdelphij * XXX On FreeBSD rate & 0x80 means we have an MCS. On 2024235530Sdelphij * Linux and AirPcap it does not. (What about 2025235530Sdelphij * Mac OS X, NetBSD, OpenBSD, and DragonFly BSD?) 2026235530Sdelphij * 2027235530Sdelphij * This is an issue either for proprietary extensions 2028235530Sdelphij * to 11a or 11g, which do exist, or for 11n 2029235530Sdelphij * implementations that stuff a rate value into 2030235530Sdelphij * this field, which also appear to exist. 2031235530Sdelphij * 2032235530Sdelphij * We currently handle that by assuming that 2033235530Sdelphij * if the 0x80 bit is set *and* the remaining 2034235530Sdelphij * bits have a value between 0 and 15 it's 2035235530Sdelphij * an MCS value, otherwise it's a rate. If 2036235530Sdelphij * there are cases where systems that use 2037235530Sdelphij * "0x80 + MCS index" for MCS indices > 15, 2038235530Sdelphij * or stuff a rate value here between 64 and 2039235530Sdelphij * 71.5 Mb/s in here, we'll need a preference 2040235530Sdelphij * setting. Such rates do exist, e.g. 11n 2041235530Sdelphij * MCS 7 at 20 MHz with a long guard interval. 2042235530Sdelphij */ 2043235530Sdelphij if (u.u8 >= 0x80 && u.u8 <= 0x8f) { 2044235530Sdelphij /* 2045235530Sdelphij * XXX - we don't know the channel width 2046235530Sdelphij * or guard interval length, so we can't 2047235530Sdelphij * convert this to a data rate. 2048235530Sdelphij * 2049235530Sdelphij * If you want us to show a data rate, 2050235530Sdelphij * use the MCS field, not the Rate field; 2051235530Sdelphij * the MCS field includes not only the 2052235530Sdelphij * MCS index, it also includes bandwidth 2053235530Sdelphij * and guard interval information. 2054235530Sdelphij * 2055235530Sdelphij * XXX - can we get the channel width 2056235530Sdelphij * from XChannel and the guard interval 2057235530Sdelphij * information from Flags, at least on 2058235530Sdelphij * FreeBSD? 2059235530Sdelphij */ 2060235530Sdelphij printf("MCS %u ", u.u8 & 0x7f); 2061235530Sdelphij } else 2062235530Sdelphij printf("%2.1f Mb/s ", .5*u.u8); 2063146773Ssam break; 2064146773Ssam case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: 2065146773Ssam printf("%ddB signal ", u.i8); 2066146773Ssam break; 2067146773Ssam case IEEE80211_RADIOTAP_DBM_ANTNOISE: 2068146773Ssam printf("%ddB noise ", u.i8); 2069146773Ssam break; 2070146773Ssam case IEEE80211_RADIOTAP_DB_ANTSIGNAL: 2071146773Ssam printf("%ddB signal ", u.u8); 2072146773Ssam break; 2073146773Ssam case IEEE80211_RADIOTAP_DB_ANTNOISE: 2074146773Ssam printf("%ddB noise ", u.u8); 2075146773Ssam break; 2076146773Ssam case IEEE80211_RADIOTAP_LOCK_QUALITY: 2077146773Ssam printf("%u sq ", u.u16); 2078146773Ssam break; 2079146773Ssam case IEEE80211_RADIOTAP_TX_ATTENUATION: 2080146773Ssam printf("%d tx power ", -(int)u.u16); 2081146773Ssam break; 2082146773Ssam case IEEE80211_RADIOTAP_DB_TX_ATTENUATION: 2083146773Ssam printf("%ddB tx power ", -(int)u.u8); 2084146773Ssam break; 2085146773Ssam case IEEE80211_RADIOTAP_DBM_TX_POWER: 2086146773Ssam printf("%ddBm tx power ", u.i8); 2087146773Ssam break; 2088146773Ssam case IEEE80211_RADIOTAP_FLAGS: 2089146773Ssam if (u.u8 & IEEE80211_RADIOTAP_F_CFP) 2090146773Ssam printf("cfp "); 2091146773Ssam if (u.u8 & IEEE80211_RADIOTAP_F_SHORTPRE) 2092146773Ssam printf("short preamble "); 2093146773Ssam if (u.u8 & IEEE80211_RADIOTAP_F_WEP) 2094146773Ssam printf("wep "); 2095146773Ssam if (u.u8 & IEEE80211_RADIOTAP_F_FRAG) 2096146773Ssam printf("fragmented "); 2097170533Ssam if (u.u8 & IEEE80211_RADIOTAP_F_BADFCS) 2098172686Smlaier printf("bad-fcs "); 2099146773Ssam break; 2100146773Ssam case IEEE80211_RADIOTAP_ANTENNA: 2101146773Ssam printf("antenna %d ", u.u8); 2102146773Ssam break; 2103146773Ssam case IEEE80211_RADIOTAP_TSFT: 2104146773Ssam printf("%" PRIu64 "us tsft ", u.u64); 2105146773Ssam break; 2106235530Sdelphij case IEEE80211_RADIOTAP_RX_FLAGS: 2107235530Sdelphij /* Do nothing for now */ 2108235530Sdelphij break; 2109170533Ssam case IEEE80211_RADIOTAP_XCHANNEL: 2110170533Ssam print_chaninfo(u2.u16, u.u32); 2111170533Ssam break; 2112235530Sdelphij case IEEE80211_RADIOTAP_MCS: { 2113235530Sdelphij static const char *bandwidth[4] = { 2114235530Sdelphij "20 MHz", 2115235530Sdelphij "40 MHz", 2116235530Sdelphij "20 MHz (L)", 2117235530Sdelphij "20 MHz (U)" 2118235530Sdelphij }; 2119235530Sdelphij float htrate; 2120235530Sdelphij 2121235530Sdelphij if (u.u8 & IEEE80211_RADIOTAP_MCS_MCS_INDEX_KNOWN) { 2122235530Sdelphij /* 2123235530Sdelphij * We know the MCS index. 2124235530Sdelphij */ 2125235530Sdelphij if (u3.u8 <= MAX_MCS_INDEX) { 2126235530Sdelphij /* 2127235530Sdelphij * And it's in-range. 2128235530Sdelphij */ 2129235530Sdelphij if (u.u8 & (IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN|IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN)) { 2130235530Sdelphij /* 2131235530Sdelphij * And we know both the bandwidth and 2132235530Sdelphij * the guard interval, so we can look 2133235530Sdelphij * up the rate. 2134235530Sdelphij */ 2135235530Sdelphij htrate = 2136235530Sdelphij ieee80211_float_htrates \ 2137235530Sdelphij [u3.u8] \ 2138235530Sdelphij [((u2.u8 & IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK) == IEEE80211_RADIOTAP_MCS_BANDWIDTH_40 ? 1 : 0)] \ 2139235530Sdelphij [((u2.u8 & IEEE80211_RADIOTAP_MCS_SHORT_GI) ? 1 : 0)]; 2140235530Sdelphij } else { 2141235530Sdelphij /* 2142235530Sdelphij * We don't know both the bandwidth 2143235530Sdelphij * and the guard interval, so we can 2144235530Sdelphij * only report the MCS index. 2145235530Sdelphij */ 2146235530Sdelphij htrate = 0.0; 2147235530Sdelphij } 2148235530Sdelphij } else { 2149235530Sdelphij /* 2150235530Sdelphij * The MCS value is out of range. 2151235530Sdelphij */ 2152235530Sdelphij htrate = 0.0; 2153235530Sdelphij } 2154235530Sdelphij if (htrate != 0.0) { 2155235530Sdelphij /* 2156235530Sdelphij * We have the rate. 2157235530Sdelphij * Print it. 2158235530Sdelphij */ 2159235530Sdelphij printf("%.1f Mb/s MCS %u ", htrate, u3.u8); 2160235530Sdelphij } else { 2161235530Sdelphij /* 2162235530Sdelphij * We at least have the MCS index. 2163235530Sdelphij * Print it. 2164235530Sdelphij */ 2165235530Sdelphij printf("MCS %u ", u3.u8); 2166235530Sdelphij } 2167235530Sdelphij } 2168235530Sdelphij if (u.u8 & IEEE80211_RADIOTAP_MCS_BANDWIDTH_KNOWN) { 2169235530Sdelphij printf("%s ", 2170235530Sdelphij bandwidth[u2.u8 & IEEE80211_RADIOTAP_MCS_BANDWIDTH_MASK]); 2171235530Sdelphij } 2172235530Sdelphij if (u.u8 & IEEE80211_RADIOTAP_MCS_GUARD_INTERVAL_KNOWN) { 2173235530Sdelphij printf("%s GI ", 2174235530Sdelphij (u2.u8 & IEEE80211_RADIOTAP_MCS_SHORT_GI) ? 2175235530Sdelphij "short" : "lon"); 2176235530Sdelphij } 2177235530Sdelphij if (u.u8 & IEEE80211_RADIOTAP_MCS_HT_FORMAT_KNOWN) { 2178235530Sdelphij printf("%s ", 2179235530Sdelphij (u2.u8 & IEEE80211_RADIOTAP_MCS_HT_GREENFIELD) ? 2180235530Sdelphij "greenfield" : "mixed"); 2181235530Sdelphij } 2182235530Sdelphij if (u.u8 & IEEE80211_RADIOTAP_MCS_FEC_TYPE_KNOWN) { 2183235530Sdelphij printf("%s FEC ", 2184235530Sdelphij (u2.u8 & IEEE80211_RADIOTAP_MCS_FEC_LDPC) ? 2185235530Sdelphij "LDPC" : "BCC"); 2186235530Sdelphij } 2187235530Sdelphij break; 2188235530Sdelphij } 2189146773Ssam } 2190146773Ssam return 0; 2191146773Ssam} 2192146773Ssam 2193127668Sbmsstatic u_int 2194127668Sbmsieee802_11_radio_print(const u_char *p, u_int length, u_int caplen) 2195127668Sbms{ 2196146773Ssam#define BITNO_32(x) (((x) >> 16) ? 16 + BITNO_16((x) >> 16) : BITNO_16((x))) 2197146773Ssam#define BITNO_16(x) (((x) >> 8) ? 8 + BITNO_8((x) >> 8) : BITNO_8((x))) 2198146773Ssam#define BITNO_8(x) (((x) >> 4) ? 4 + BITNO_4((x) >> 4) : BITNO_4((x))) 2199146773Ssam#define BITNO_4(x) (((x) >> 2) ? 2 + BITNO_2((x) >> 2) : BITNO_2((x))) 2200146773Ssam#define BITNO_2(x) (((x) & 2) ? 1 : 0) 2201214478Srpaulo#define BIT(n) (1U << n) 2202146773Ssam#define IS_EXTENDED(__p) \ 2203146773Ssam (EXTRACT_LE_32BITS(__p) & BIT(IEEE80211_RADIOTAP_EXT)) != 0 2204146773Ssam 2205146773Ssam struct cpack_state cpacker; 2206146773Ssam struct ieee80211_radiotap_header *hdr; 2207146773Ssam u_int32_t present, next_present; 2208235530Sdelphij u_int32_t presentflags = 0; 2209146773Ssam u_int32_t *presentp, *last_presentp; 2210146773Ssam enum ieee80211_radiotap_type bit; 2211146773Ssam int bit0; 2212146773Ssam const u_char *iter; 2213146773Ssam u_int len; 2214214478Srpaulo u_int8_t flags; 2215172686Smlaier int pad; 2216214478Srpaulo u_int fcslen; 2217235530Sdelphij struct radiotap_state state; 2218146773Ssam 2219146773Ssam if (caplen < sizeof(*hdr)) { 2220146773Ssam printf("[|802.11]"); 2221146773Ssam return caplen; 2222146773Ssam } 2223146773Ssam 2224146773Ssam hdr = (struct ieee80211_radiotap_header *)p; 2225146773Ssam 2226146773Ssam len = EXTRACT_LE_16BITS(&hdr->it_len); 2227146773Ssam 2228146773Ssam if (caplen < len) { 2229146773Ssam printf("[|802.11]"); 2230146773Ssam return caplen; 2231146773Ssam } 2232146773Ssam for (last_presentp = &hdr->it_present; 2233146773Ssam IS_EXTENDED(last_presentp) && 2234146773Ssam (u_char*)(last_presentp + 1) <= p + len; 2235146773Ssam last_presentp++); 2236146773Ssam 2237146773Ssam /* are there more bitmap extensions than bytes in header? */ 2238146773Ssam if (IS_EXTENDED(last_presentp)) { 2239146773Ssam printf("[|802.11]"); 2240146773Ssam return caplen; 2241146773Ssam } 2242146773Ssam 2243146773Ssam iter = (u_char*)(last_presentp + 1); 2244146773Ssam 2245146773Ssam if (cpack_init(&cpacker, (u_int8_t*)iter, len - (iter - p)) != 0) { 2246146773Ssam /* XXX */ 2247146773Ssam printf("[|802.11]"); 2248146773Ssam return caplen; 2249146773Ssam } 2250146773Ssam 2251214478Srpaulo /* Assume no flags */ 2252214478Srpaulo flags = 0; 2253172686Smlaier /* Assume no Atheros padding between 802.11 header and body */ 2254172686Smlaier pad = 0; 2255214478Srpaulo /* Assume no FCS at end of frame */ 2256214478Srpaulo fcslen = 0; 2257146773Ssam for (bit0 = 0, presentp = &hdr->it_present; presentp <= last_presentp; 2258146773Ssam presentp++, bit0 += 32) { 2259235530Sdelphij presentflags = EXTRACT_LE_32BITS(presentp); 2260235530Sdelphij 2261235530Sdelphij /* Clear state. */ 2262235530Sdelphij memset(&state, 0, sizeof(state)); 2263235530Sdelphij 2264146773Ssam for (present = EXTRACT_LE_32BITS(presentp); present; 2265146773Ssam present = next_present) { 2266146773Ssam /* clear the least significant bit that is set */ 2267146773Ssam next_present = present & (present - 1); 2268146773Ssam 2269146773Ssam /* extract the least significant bit that is set */ 2270147899Ssam bit = (enum ieee80211_radiotap_type) 2271147899Ssam (bit0 + BITNO_32(present ^ next_present)); 2272146773Ssam 2273235530Sdelphij if (print_radiotap_field(&cpacker, bit, &flags, &state, presentflags) != 0) 2274146773Ssam goto out; 2275146773Ssam } 2276146773Ssam } 2277214478Srpaulo 2278235530Sdelphijout: 2279214478Srpaulo if (flags & IEEE80211_RADIOTAP_F_DATAPAD) 2280214478Srpaulo pad = 1; /* Atheros padding */ 2281214478Srpaulo if (flags & IEEE80211_RADIOTAP_F_FCS) 2282214478Srpaulo fcslen = 4; /* FCS at end of packet */ 2283214478Srpaulo return len + ieee802_11_print(p + len, length - len, caplen - len, pad, 2284214478Srpaulo fcslen); 2285146773Ssam#undef BITNO_32 2286146773Ssam#undef BITNO_16 2287146773Ssam#undef BITNO_8 2288146773Ssam#undef BITNO_4 2289146773Ssam#undef BITNO_2 2290146773Ssam#undef BIT 2291146773Ssam} 2292146773Ssam 2293146773Ssamstatic u_int 2294146773Ssamieee802_11_avs_radio_print(const u_char *p, u_int length, u_int caplen) 2295146773Ssam{ 2296127668Sbms u_int32_t caphdr_len; 2297127668Sbms 2298190207Srpaulo if (caplen < 8) { 2299190207Srpaulo printf("[|802.11]"); 2300190207Srpaulo return caplen; 2301190207Srpaulo } 2302190207Srpaulo 2303127668Sbms caphdr_len = EXTRACT_32BITS(p + 4); 2304127668Sbms if (caphdr_len < 8) { 2305127668Sbms /* 2306127668Sbms * Yow! The capture header length is claimed not 2307127668Sbms * to be large enough to include even the version 2308127668Sbms * cookie or capture header length! 2309127668Sbms */ 2310127668Sbms printf("[|802.11]"); 2311127668Sbms return caplen; 2312127668Sbms } 2313127668Sbms 2314127668Sbms if (caplen < caphdr_len) { 2315127668Sbms printf("[|802.11]"); 2316127668Sbms return caplen; 2317127668Sbms } 2318127668Sbms 2319127668Sbms return caphdr_len + ieee802_11_print(p + caphdr_len, 2320214478Srpaulo length - caphdr_len, caplen - caphdr_len, 0, 0); 2321127668Sbms} 2322127668Sbms 2323127668Sbms#define PRISM_HDR_LEN 144 2324127668Sbms 2325190207Srpaulo#define WLANCAP_MAGIC_COOKIE_BASE 0x80211000 2326127668Sbms#define WLANCAP_MAGIC_COOKIE_V1 0x80211001 2327190207Srpaulo#define WLANCAP_MAGIC_COOKIE_V2 0x80211002 2328127668Sbms 2329127668Sbms/* 2330127668Sbms * For DLT_PRISM_HEADER; like DLT_IEEE802_11, but with an extra header, 2331127668Sbms * containing information such as radio information, which we 2332127668Sbms * currently ignore. 2333127668Sbms * 2334190207Srpaulo * If, however, the packet begins with WLANCAP_MAGIC_COOKIE_V1 or 2335190207Srpaulo * WLANCAP_MAGIC_COOKIE_V2, it's really DLT_IEEE802_11_RADIO_AVS 2336190207Srpaulo * (currently, on Linux, there's no ARPHRD_ type for 2337190207Srpaulo * DLT_IEEE802_11_RADIO_AVS, as there is a ARPHRD_IEEE80211_PRISM 2338190207Srpaulo * for DLT_PRISM_HEADER, so ARPHRD_IEEE80211_PRISM is used for 2339190207Srpaulo * the AVS header, and the first 4 bytes of the header are used to 2340190207Srpaulo * indicate whether it's a Prism header or an AVS header). 2341127668Sbms */ 2342127668Sbmsu_int 2343127668Sbmsprism_if_print(const struct pcap_pkthdr *h, const u_char *p) 2344127668Sbms{ 2345127668Sbms u_int caplen = h->caplen; 2346127668Sbms u_int length = h->len; 2347190207Srpaulo u_int32_t msgcode; 2348127668Sbms 2349127668Sbms if (caplen < 4) { 2350127668Sbms printf("[|802.11]"); 2351127668Sbms return caplen; 2352127668Sbms } 2353127668Sbms 2354190207Srpaulo msgcode = EXTRACT_32BITS(p); 2355190207Srpaulo if (msgcode == WLANCAP_MAGIC_COOKIE_V1 || 2356190207Srpaulo msgcode == WLANCAP_MAGIC_COOKIE_V2) 2357146773Ssam return ieee802_11_avs_radio_print(p, length, caplen); 2358127668Sbms 2359127668Sbms if (caplen < PRISM_HDR_LEN) { 2360127668Sbms printf("[|802.11]"); 2361127668Sbms return caplen; 2362127668Sbms } 2363127668Sbms 2364127668Sbms return PRISM_HDR_LEN + ieee802_11_print(p + PRISM_HDR_LEN, 2365214478Srpaulo length - PRISM_HDR_LEN, caplen - PRISM_HDR_LEN, 0, 0); 2366127668Sbms} 2367127668Sbms 2368127668Sbms/* 2369127668Sbms * For DLT_IEEE802_11_RADIO; like DLT_IEEE802_11, but with an extra 2370190207Srpaulo * header, containing information such as radio information. 2371127668Sbms */ 2372127668Sbmsu_int 2373127668Sbmsieee802_11_radio_if_print(const struct pcap_pkthdr *h, const u_char *p) 2374127668Sbms{ 2375190207Srpaulo return ieee802_11_radio_print(p, h->len, h->caplen); 2376190207Srpaulo} 2377127668Sbms 2378190207Srpaulo/* 2379190207Srpaulo * For DLT_IEEE802_11_RADIO_AVS; like DLT_IEEE802_11, but with an 2380190207Srpaulo * extra header, containing information such as radio information, 2381190207Srpaulo * which we currently ignore. 2382190207Srpaulo */ 2383190207Srpaulou_int 2384190207Srpauloieee802_11_radio_avs_if_print(const struct pcap_pkthdr *h, const u_char *p) 2385190207Srpaulo{ 2386190207Srpaulo return ieee802_11_avs_radio_print(p, h->len, h->caplen); 2387127668Sbms} 2388