如何使用 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 的参数有效载荷由两个总长度为 4 的 u16 组成。发生这种情况时,应用填充规则处理 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>