如何使用 radiotap 頭部

指向 radiotap 包含檔案的指標

Radiotap 頭部是可變長度且可擴充套件的,您可以從以下位置獲取有關它們的大部分資訊:

./include/net/ieee80211_radiotap.h

本文件提供概述並警告一些極端情況。

頭部的結構

頭部開頭有一個固定部分,其中包含一個 u32 點陣圖,用於定義與該位關聯的可能引數是否存在。因此,如果 ieee80211_radiotap_header 的 it_present 成員的 b0 被設定,則表示引數索引 0 (IEEE80211_RADIOTAP_TSFT) 的頭部存在於引數區域中。

< 8-byte ieee80211_radiotap_header >
[ <possible argument bitmap extensions ... > ]
[ <argument> ... ]

目前只定義了 13 個可能的引數索引,但如果我們用完 u32 it_present 成員中的空間,則定義 b31 設定表示後面還有另一個 u32 點陣圖(如上面的“可能的引數點陣圖擴充套件...”所示),並且每次引數的起始位置向前移動 4 個位元組。

另請注意,it_len 成員 __le16 設定為 ieee80211_radiotap_header 和任何後續引數所覆蓋的總位元組數。

引數的要求

在頭部的固定部分之後,是每個引數索引的引數,其匹配位在 ieee80211_radiotap_header 的 it_present 成員中設定。

  • 所有引數都以小端儲存!

  • 給定引數索引的引數有效負載具有固定大小。因此,存在 IEEE80211_RADIOTAP_TSFT 始終表示存在 8 位元組的引數。請參閱 ./include/net/ieee80211_radiotap.h 中的註釋,以獲得所有引數大小的詳細分解

  • 引數必須使用填充與引數大小的邊界對齊。因此,如果 u16 引數還不是 u16 邊界上的,則必須從下一個 u16 邊界開始,u32 必須從下一個 u32 邊界開始,依此類推。

  • “對齊”是相對於 ieee80211_radiotap_header 的開始,即 radiotap 頭部的第一位元組。該第一位元組的絕對對齊未定義。因此,即使整個 radiotap 頭部從地址 0x00000003 開始,radiotap 頭部的第一位元組仍然被視為 0 以進行對齊。

  • 上面關於固定 radiotap 頭部或引數區域中可能沒有多位元組實體的絕對對齊的點意味著在嘗試訪問這些多位元組實體時,您必須採取特殊的規避措施。某些架構(如 Blackfin)無法處理嘗試取消引用指向奇數地址的 u16 指標。相反,您必須使用核心 API get_unaligned() 來取消引用該指標,這將會在需要它的架構上逐位元組地執行。

  • 給定引數索引的引數可以是多種型別組合而成。例如,IEEE80211_RADIOTAP_CHANNEL 的引數有效負載由兩個 u16 組成,總長度為 4。發生這種情況時,應用填充規則處理 u16,而不是處理 4 位元組的單個實體。

有效 radiotap 頭部示例

0x00, 0x00, // <-- radiotap version + pad byte
0x0b, 0x00, // <- radiotap header length
0x04, 0x0c, 0x00, 0x00, // <-- bitmap
0x6c, // <-- rate (in 500kHz units)
0x0c, //<-- tx power
0x01 //<-- antenna

使用 Radiotap 解析器

如果您需要解析 radiotap 結構,您可以使用位於 net/wireless/radiotap.c 中的 radiotap 解析器來從根本上簡化這項工作,其原型在 include/net/cfg80211.h 中可用。您可以這樣使用它

#include <net/cfg80211.h>

/* buf points to the start of the radiotap header part */

int MyFunction(u8 * buf, int buflen)
{
        int pkt_rate_100kHz = 0, antenna = 0, pwr = 0;
        struct ieee80211_radiotap_iterator iterator;
        int ret = ieee80211_radiotap_iterator_init(&iterator, buf, buflen);

        while (!ret) {

                ret = ieee80211_radiotap_iterator_next(&iterator);

                if (ret)
                        continue;

                /* see if this argument is something we can use */

                switch (iterator.this_arg_index) {
                /*
                * You must take care when dereferencing iterator.this_arg
                * for multibyte types... the pointer is not aligned.  Use
                * get_unaligned((type *)iterator.this_arg) to dereference
                * iterator.this_arg for type "type" safely on all arches.
                */
                case IEEE80211_RADIOTAP_RATE:
                        /* radiotap "rate" u8 is in
                        * 500kbps units, eg, 0x02=1Mbps
                        */
                        pkt_rate_100kHz = (*iterator.this_arg) * 5;
                        break;

                case IEEE80211_RADIOTAP_ANTENNA:
                        /* radiotap uses 0 for 1st ant */
                        antenna = *iterator.this_arg);
                        break;

                case IEEE80211_RADIOTAP_DBM_TX_POWER:
                        pwr = *iterator.this_arg;
                        break;

                default:
                        break;
                }
        }  /* while more rt headers */

        if (ret != -ENOENT)
                return TXRX_DROP;

        /* discard the radiotap header part */
        buf += iterator.max_length;
        buflen -= iterator.max_length;

        ...

}

Andy Green <andy@warmcat.com>