• [转] ieee802.11数据radiotap介绍


    之前写有文章介绍了在Linux系统用wireshark或tcpdump抓无线网卡数据包。分析包时发现每一数据帧前面都有一个叫radiotap的东西。它包含了如信号强度、频率等信息。当时没有研究,直接跳过。本文就对此介绍补充。首先介绍radiotap,然后利用radiotap解析库对一段radiotap数据进行解析,获取其中的信息。

    介绍

    radiotap比传统的Prism或AVS头部更有灵活性,成为是ieee802.11事实上的标准。支持radiotap的系统较多,如Linux、FreeBSD、NetBSD、OpenBSD,还有Windows(需使用AirPcap)。它的头部定义如下:

    struct ieee80211_radiotap_header {
            u_int8_t        it_version;     /* set to 0 */
            u_int8_t        it_pad;
            u_int16_t       it_len;         /* entire length */
            u_int32_t       it_present;     /* fields present */
    } __attribute__((__packed__));

    其中第一个字段it_version表示版本号,当前为0。

    第二个字段it_pad没有使用,仅仅是为了结构体对齐。

    第三个字段it_present表示长度,包括了radiotap头部和数据两部分。此设计的好处在于,如果不需要了解radiotap,则可以跳过直接到ieee802.11头部。——半个月前写抓包程序时,还不了解radio,就是直接跳过的。

    第四个字段it_present表示radiotap数据的位掩码。radiotap的数据紧跟其头部。当其中的位掩码为true时,表示有对应的数据,可以认为每一比特表示一种类型。比如bit5为1表示有通道数据,则可以获取到信号强度。反之就是没有对应的数据。因此radiotap的长度其实是不固定的。bit31为1表示还有多个it_present。不过目前笔者还没有碰到此情况,没有深入了解。

    radiotap的每个类型都是有严格的顺序的。另外,radiotap数据的字序是小端格式(little endian byte-order)——包括头部的it_len和it_present。

    目前应用比较广的解析库是radiotap-library——在horst软件和Linux内核中都使用到。关于每个类型的解释,可以参考radiotap.h文件的ieee80211_radiotap_type注释。

    下面看一下wireshark抓到的包的radiotap头部数据:

     

    由图可见,radiotap包括的东西挺多的。

    解析

    radiotap解析库使用十分简单,先对此有个基本面的认知概念:

    1、首先

    完整代码如下:

    /**
    radiotap头部解析
    使用radiotap库,源码地址:
    https://github.com/radiotap/radiotap-library
    
    */
    
    #include <unistd.h>
    #include <stdio.h>
    #include <stdint.h>
    #include <endian.h>
    #include <errno.h>
    #include <string.h>
    
    #include "radiotap_iter.h"
    
    // 根据wireshark抓包抽取的radiotap头部数据
    char radiotap_buf[][18] = {
                    {0x00, 0x00, 0x12, 0x00, 0x2e, 0x48,
                     0x00, 0x00, 0x00, 0x02, 0x85, 0x09,
                     0xc0, 0x00, 0xc9, 0x00, 0x00, 0x00},
                    {0x00, 0x00, 0x12, 0x00, 0x2e, 0x48,
                     0x00, 0x00, 0x00, 0x02, 0x85, 0x09,
                     0xa0, 0x00, 0xa8, 0x00, 0x00, 0x00},
                    };
    
    static void print_radiotap_namespace(struct ieee80211_radiotap_iterator *iter)
    {
        char signal = 0;
        uint32_t phy_freq = 0;
    
    	switch (iter->this_arg_index)
        {
    	case IEEE80211_RADIOTAP_TSFT:
    		printf("	TSFT: %llu
    ", le64toh(*(unsigned long long *)iter->this_arg));
    		break;
    	case IEEE80211_RADIOTAP_FLAGS:
    		printf("	flags: %02x
    ", *iter->this_arg);
    		break;
        // 速率?
    	case IEEE80211_RADIOTAP_RATE:
    		printf("	rate: %.2f Mbit/s
    ", (double)*iter->this_arg/2);
    		break;
    
    #define IEEE80211_CHAN_A 
    	(IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
    #define IEEE80211_CHAN_G 
    	(IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM)
        // 通信信息
    	case IEEE80211_RADIOTAP_CHANNEL:
            phy_freq = le16toh(*(uint16_t*)iter->this_arg); // 信道
            iter->this_arg = iter->this_arg + 2; // 通道信息如2G、5G,等
            int x = le16toh(*(uint16_t*)iter->this_arg);
            printf("	freq: %d type: ", phy_freq);
            if ((x & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)
            {
                printf("A
    ");
            }
            else if ((x & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)
            {
                printf("G
    ");
            }
            else if ((x & IEEE80211_CHAN_2GHZ) == IEEE80211_CHAN_2GHZ)
            {
                printf("B
    ");
            }
            break;
        // 信号强度
    	case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
            signal = *(signed char*)iter->this_arg;
            printf("	signal: %d dBm
    ", signal);
            break;
    		break;
        // 接收标志
    	case IEEE80211_RADIOTAP_RX_FLAGS:
    		printf("	RX flags: %#.4x
    ", le16toh(*(uint16_t *)iter->this_arg));
    		break;
        case IEEE80211_RADIOTAP_ANTENNA:
            printf("	antenna: %x
    ", *iter->this_arg);
            break;
        // 忽略下面的
    	case IEEE80211_RADIOTAP_RTS_RETRIES:
    	case IEEE80211_RADIOTAP_DATA_RETRIES:
        case IEEE80211_RADIOTAP_FHSS:
    	case IEEE80211_RADIOTAP_DBM_ANTNOISE:
    	case IEEE80211_RADIOTAP_LOCK_QUALITY:
    	case IEEE80211_RADIOTAP_TX_ATTENUATION:
    	case IEEE80211_RADIOTAP_DB_TX_ATTENUATION:
    	case IEEE80211_RADIOTAP_DBM_TX_POWER:
    	case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
    	case IEEE80211_RADIOTAP_DB_ANTNOISE:
    	case IEEE80211_RADIOTAP_TX_FLAGS:
    		break;
    	default:
    		printf("	BOGUS DATA
    ");
    		break;
    	}
    }
    
    int main(void)
    {
        struct ieee80211_radiotap_iterator iter;
        int err;
        int i, j;
    
        for (i = 0; i < sizeof(radiotap_buf)/sizeof(radiotap_buf[0]); i++)
        {
            printf("parsing [%d]
    ", i);
            // 初始化
            err = ieee80211_radiotap_iterator_init(&iter, 
            (struct ieee80211_radiotap_header *)radiotap_buf[i], sizeof(radiotap_buf[i]), NULL);
            if (err)
            {
                printf("not valid radiotap...
    ");
                return -1;
            }
            j = 0;
            /**
            遍历时,this_arg_index表示当前索引(如IEEE80211_RADIOTAP_TSFT等),
            this_arg表示当前索引的值,this_arg_size表示值的大小。
            只有flag为true时才会进一步解析。
            */
            while (!(err = ieee80211_radiotap_iterator_next(&iter)))
            {
                printf("next[%d]: index: %d size: %d
    ",
                        j, iter.this_arg_index, iter.this_arg_size);
                if (iter.is_radiotap_ns) // 表示是radiotap的命名空间
                {
                    print_radiotap_namespace(&iter);
                }
                j++;
            }
            printf("==================================
    ");
        }
    
        return 0;
    }

    执行结果:
    parsing [0]
    next[0]: index: 1 size: 1
            flags: 00
    next[1]: index: 2 size: 1
            rate: 1.00 Mbit/s
    next[2]: index: 3 size: 4
            freq: 2437 type: G
    next[3]: index: 5 size: 1
            signal: -55 dBm
    next[4]: index: 11 size: 1
            antenna: 0
    next[5]: index: 14 size: 2
            RX flags: 0000
    ==================================
    parsing [1]
    next[0]: index: 1 size: 1
            flags: 00
    next[1]: index: 2 size: 1
            rate: 1.00 Mbit/s
    next[2]: index: 3 size: 4
            freq: 2437 type: B
    next[3]: index: 5 size: 1
            signal: -88 dBm
    next[4]: index: 11 size: 1
            antenna: 0
    next[5]: index: 14 size: 2
            RX flags: 0000
    ==================================

    参考资料:

    http://www.radiotap.org/

    https://github.com/radiotap/radiotap-library


    李迟 2016.11.16 周三 晚

  • 相关阅读:
    Python的with语句(文件打开方式)
    python代码异常范围检查方法(非常实用)
    python一标准异常总结大全(非常全)
    python里pickle模块
    pyhon文件操作典型代码实现(非常经典!)
    codeblocks中cocos2dx项目添加新的.cpp和.h文件后编译运行的方法
    ubuntu安装cocos2dx
    学习资料整理
    Spring学习笔记--在SpEL中筛选集合
    Spring学习笔记--Spring表达式语言SpEL
  • 原文地址:https://www.cnblogs.com/cxt-janson/p/9274133.html
Copyright © 2020-2023  润新知