1*4882a593Smuzhiyun.. SPDX-License-Identifier: GPL-2.0 2*4882a593Smuzhiyun 3*4882a593Smuzhiyun=========================== 4*4882a593SmuzhiyunHow to use radiotap headers 5*4882a593Smuzhiyun=========================== 6*4882a593Smuzhiyun 7*4882a593SmuzhiyunPointer to the radiotap include file 8*4882a593Smuzhiyun------------------------------------ 9*4882a593Smuzhiyun 10*4882a593SmuzhiyunRadiotap headers are variable-length and extensible, you can get most of the 11*4882a593Smuzhiyuninformation you need to know on them from:: 12*4882a593Smuzhiyun 13*4882a593Smuzhiyun ./include/net/ieee80211_radiotap.h 14*4882a593Smuzhiyun 15*4882a593SmuzhiyunThis document gives an overview and warns on some corner cases. 16*4882a593Smuzhiyun 17*4882a593Smuzhiyun 18*4882a593SmuzhiyunStructure of the header 19*4882a593Smuzhiyun----------------------- 20*4882a593Smuzhiyun 21*4882a593SmuzhiyunThere is a fixed portion at the start which contains a u32 bitmap that defines 22*4882a593Smuzhiyunif the possible argument associated with that bit is present or not. So if b0 23*4882a593Smuzhiyunof the it_present member of ieee80211_radiotap_header is set, it means that 24*4882a593Smuzhiyunthe header for argument index 0 (IEEE80211_RADIOTAP_TSFT) is present in the 25*4882a593Smuzhiyunargument area. 26*4882a593Smuzhiyun 27*4882a593Smuzhiyun:: 28*4882a593Smuzhiyun 29*4882a593Smuzhiyun < 8-byte ieee80211_radiotap_header > 30*4882a593Smuzhiyun [ <possible argument bitmap extensions ... > ] 31*4882a593Smuzhiyun [ <argument> ... ] 32*4882a593Smuzhiyun 33*4882a593SmuzhiyunAt the moment there are only 13 possible argument indexes defined, but in case 34*4882a593Smuzhiyunwe run out of space in the u32 it_present member, it is defined that b31 set 35*4882a593Smuzhiyunindicates that there is another u32 bitmap following (shown as "possible 36*4882a593Smuzhiyunargument bitmap extensions..." above), and the start of the arguments is moved 37*4882a593Smuzhiyunforward 4 bytes each time. 38*4882a593Smuzhiyun 39*4882a593SmuzhiyunNote also that the it_len member __le16 is set to the total number of bytes 40*4882a593Smuzhiyuncovered by the ieee80211_radiotap_header and any arguments following. 41*4882a593Smuzhiyun 42*4882a593Smuzhiyun 43*4882a593SmuzhiyunRequirements for arguments 44*4882a593Smuzhiyun-------------------------- 45*4882a593Smuzhiyun 46*4882a593SmuzhiyunAfter the fixed part of the header, the arguments follow for each argument 47*4882a593Smuzhiyunindex whose matching bit is set in the it_present member of 48*4882a593Smuzhiyunieee80211_radiotap_header. 49*4882a593Smuzhiyun 50*4882a593Smuzhiyun - the arguments are all stored little-endian! 51*4882a593Smuzhiyun 52*4882a593Smuzhiyun - the argument payload for a given argument index has a fixed size. So 53*4882a593Smuzhiyun IEEE80211_RADIOTAP_TSFT being present always indicates an 8-byte argument is 54*4882a593Smuzhiyun present. See the comments in ./include/net/ieee80211_radiotap.h for a nice 55*4882a593Smuzhiyun breakdown of all the argument sizes 56*4882a593Smuzhiyun 57*4882a593Smuzhiyun - the arguments must be aligned to a boundary of the argument size using 58*4882a593Smuzhiyun padding. So a u16 argument must start on the next u16 boundary if it isn't 59*4882a593Smuzhiyun already on one, a u32 must start on the next u32 boundary and so on. 60*4882a593Smuzhiyun 61*4882a593Smuzhiyun - "alignment" is relative to the start of the ieee80211_radiotap_header, ie, 62*4882a593Smuzhiyun the first byte of the radiotap header. The absolute alignment of that first 63*4882a593Smuzhiyun byte isn't defined. So even if the whole radiotap header is starting at, eg, 64*4882a593Smuzhiyun address 0x00000003, still the first byte of the radiotap header is treated as 65*4882a593Smuzhiyun 0 for alignment purposes. 66*4882a593Smuzhiyun 67*4882a593Smuzhiyun - the above point that there may be no absolute alignment for multibyte 68*4882a593Smuzhiyun entities in the fixed radiotap header or the argument region means that you 69*4882a593Smuzhiyun have to take special evasive action when trying to access these multibyte 70*4882a593Smuzhiyun entities. Some arches like Blackfin cannot deal with an attempt to 71*4882a593Smuzhiyun dereference, eg, a u16 pointer that is pointing to an odd address. Instead 72*4882a593Smuzhiyun you have to use a kernel API get_unaligned() to dereference the pointer, 73*4882a593Smuzhiyun which will do it bytewise on the arches that require that. 74*4882a593Smuzhiyun 75*4882a593Smuzhiyun - The arguments for a given argument index can be a compound of multiple types 76*4882a593Smuzhiyun together. For example IEEE80211_RADIOTAP_CHANNEL has an argument payload 77*4882a593Smuzhiyun consisting of two u16s of total length 4. When this happens, the padding 78*4882a593Smuzhiyun rule is applied dealing with a u16, NOT dealing with a 4-byte single entity. 79*4882a593Smuzhiyun 80*4882a593Smuzhiyun 81*4882a593SmuzhiyunExample valid radiotap header 82*4882a593Smuzhiyun----------------------------- 83*4882a593Smuzhiyun 84*4882a593Smuzhiyun:: 85*4882a593Smuzhiyun 86*4882a593Smuzhiyun 0x00, 0x00, // <-- radiotap version + pad byte 87*4882a593Smuzhiyun 0x0b, 0x00, // <- radiotap header length 88*4882a593Smuzhiyun 0x04, 0x0c, 0x00, 0x00, // <-- bitmap 89*4882a593Smuzhiyun 0x6c, // <-- rate (in 500kHz units) 90*4882a593Smuzhiyun 0x0c, //<-- tx power 91*4882a593Smuzhiyun 0x01 //<-- antenna 92*4882a593Smuzhiyun 93*4882a593Smuzhiyun 94*4882a593SmuzhiyunUsing the Radiotap Parser 95*4882a593Smuzhiyun------------------------- 96*4882a593Smuzhiyun 97*4882a593SmuzhiyunIf you are having to parse a radiotap struct, you can radically simplify the 98*4882a593Smuzhiyunjob by using the radiotap parser that lives in net/wireless/radiotap.c and has 99*4882a593Smuzhiyunits prototypes available in include/net/cfg80211.h. You use it like this:: 100*4882a593Smuzhiyun 101*4882a593Smuzhiyun #include <net/cfg80211.h> 102*4882a593Smuzhiyun 103*4882a593Smuzhiyun /* buf points to the start of the radiotap header part */ 104*4882a593Smuzhiyun 105*4882a593Smuzhiyun int MyFunction(u8 * buf, int buflen) 106*4882a593Smuzhiyun { 107*4882a593Smuzhiyun int pkt_rate_100kHz = 0, antenna = 0, pwr = 0; 108*4882a593Smuzhiyun struct ieee80211_radiotap_iterator iterator; 109*4882a593Smuzhiyun int ret = ieee80211_radiotap_iterator_init(&iterator, buf, buflen); 110*4882a593Smuzhiyun 111*4882a593Smuzhiyun while (!ret) { 112*4882a593Smuzhiyun 113*4882a593Smuzhiyun ret = ieee80211_radiotap_iterator_next(&iterator); 114*4882a593Smuzhiyun 115*4882a593Smuzhiyun if (ret) 116*4882a593Smuzhiyun continue; 117*4882a593Smuzhiyun 118*4882a593Smuzhiyun /* see if this argument is something we can use */ 119*4882a593Smuzhiyun 120*4882a593Smuzhiyun switch (iterator.this_arg_index) { 121*4882a593Smuzhiyun /* 122*4882a593Smuzhiyun * You must take care when dereferencing iterator.this_arg 123*4882a593Smuzhiyun * for multibyte types... the pointer is not aligned. Use 124*4882a593Smuzhiyun * get_unaligned((type *)iterator.this_arg) to dereference 125*4882a593Smuzhiyun * iterator.this_arg for type "type" safely on all arches. 126*4882a593Smuzhiyun */ 127*4882a593Smuzhiyun case IEEE80211_RADIOTAP_RATE: 128*4882a593Smuzhiyun /* radiotap "rate" u8 is in 129*4882a593Smuzhiyun * 500kbps units, eg, 0x02=1Mbps 130*4882a593Smuzhiyun */ 131*4882a593Smuzhiyun pkt_rate_100kHz = (*iterator.this_arg) * 5; 132*4882a593Smuzhiyun break; 133*4882a593Smuzhiyun 134*4882a593Smuzhiyun case IEEE80211_RADIOTAP_ANTENNA: 135*4882a593Smuzhiyun /* radiotap uses 0 for 1st ant */ 136*4882a593Smuzhiyun antenna = *iterator.this_arg); 137*4882a593Smuzhiyun break; 138*4882a593Smuzhiyun 139*4882a593Smuzhiyun case IEEE80211_RADIOTAP_DBM_TX_POWER: 140*4882a593Smuzhiyun pwr = *iterator.this_arg; 141*4882a593Smuzhiyun break; 142*4882a593Smuzhiyun 143*4882a593Smuzhiyun default: 144*4882a593Smuzhiyun break; 145*4882a593Smuzhiyun } 146*4882a593Smuzhiyun } /* while more rt headers */ 147*4882a593Smuzhiyun 148*4882a593Smuzhiyun if (ret != -ENOENT) 149*4882a593Smuzhiyun return TXRX_DROP; 150*4882a593Smuzhiyun 151*4882a593Smuzhiyun /* discard the radiotap header part */ 152*4882a593Smuzhiyun buf += iterator.max_length; 153*4882a593Smuzhiyun buflen -= iterator.max_length; 154*4882a593Smuzhiyun 155*4882a593Smuzhiyun ... 156*4882a593Smuzhiyun 157*4882a593Smuzhiyun } 158*4882a593Smuzhiyun 159*4882a593SmuzhiyunAndy Green <andy@warmcat.com> 160