xref: /OK3568_Linux_fs/kernel/Documentation/networking/radiotap-headers.rst (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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