发送802.11帧的“帧控制字段”数据的顺序?

时间:2012-07-19 13:33:26

标签: c libpcap wlan

以下是QoS数据的FC字段的位格式:

00|01|0001  01000010

前2位代表版本,后2位代表,后4位子类型,ToDS = 0,FromDS = 1,保护位= 1。

那么,上面的数据以什么顺序通过界面发送? (即从左到右或从右到左)

我看到wireshark将数据捕获为“ 8842 ”(在显示原始数据包数据的最后一段中)。

但是,如果我编写以下代码来打印FC字段数据:

struct mgmt_header_t {
    u_int16_t    fc;          /* 2 bytes */
    u_int16_t    duration;    /* 2 bytes */
    u_int8_t     addr1[6];    /* 6 bytes */  
    u_int8_t     addr2[6];    /* 6 bytes */  
    u_int8_t     addr3[6];    /* 6 bytes */  
    u_int16_t    seq_ctrl;    /* 2 bytes */
};
void my_callback(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
    int radiotapheader_length = (unsigned short int)(*(packet+2));
    struct mgmt_header_t *mac_header = (struct mgmt_header_t *)  (packet+radiotapheader_length);
    printf("FC = %X\n", mac_header->fc);
}

输出结果为:

FC = 4288

所以我的第二个问题是,它不应该打印 8842 而不是 4288 吗?

更新 我正在更新这个问题,以便更清楚我的怀疑是什么。

比如,我想发送一个QoS数据包,其FC字段的格式如下:

00|01|0001  01000010

所以,我应该写一下:

mac_header->fc = 0x1142 /* value if read from left to right */

或者

mac_header->fc = 0x4211

或者

mac_header->fc = 0x4288 /* value if read from right to left */

或者

mac_header->fc = 0x8842

我的是一个小端机器。

3 个答案:

答案 0 :(得分:8)

IEEE 802.11标准(遗憾的是,目前无法从the IEEE Get program获得)说:

  

MAC子层中的MPDU或帧被描述为特定顺序的字段序列。第7章中的每个图描绘了它们出现在MAC帧中的字段/子字段,以及它们从左到右传递到物理层会聚过程(PLCP)的顺序。

     

在图中,字段内的所有位都编号,从0到k,其中字段的长度是k + 1位。字段内的八位字节边界可以通过取模数字8的位数来获得。数字字段中比单个八位字节长的八位字节以重要性的递增顺序描绘,从最低编号位到最高编号位。长度超过单个八位字节的字段中的八位字节按从包含最低编号位的八位字节到包含最高编号位的八位字节的顺序发送到PLCP。

因此,发送到PLCP的帧控制字段的第一个八位字节是包含B0的字节,即包含协议版本,类型和子类型字段的八位字节。之后是包含To DS,From DS,More Frag等的八位字节。因此,00|01|0001八位字节是传输的第一个八位字节。在内存中的一个字节中变为10001000,从高位到低位而不是低位到高位,因此为0x88。下一个八位字节是01000010,因此是0x42。

因此,00010001后跟01000010,它将作为0x88后跟0x42出现在内存中。 (顺便说一句,这意味着FC字段与802.11中的所有其他多字节组合字段一样,以 little-endian 字节顺序传输,而不是以 big-endian <传输/ em>字节顺序。“网络字节顺序”是大端字节顺序;并非所有通过网络传输的数据都是“网络字节顺序” - 互联网协议标准中的字段,如IPv4,IPv6,TCP和UDP都在“网络字节顺序”,但其他协议,包括传输IP的一些协议和一些通过TCP或UDP传输的协议,可能会使用little-endian字节顺序。)

由小端机器接收,并被视为16位整数,即0x4288 - 在小端机器上,具有多个八位字节的积分量,内存中的第一个八位字节为低 - 数量的八位字节。因此,您的代码在您的little-endian机器上打印为0x4288;如果它在大端机器上运行,它会将其打印为0x8842。

将其打印为0x4288是打印它的“正确”方式,因为它是“在线上”的小端(或者说,“在空中”,因为这是802.11 :-))。 Wireshark在“数据包详细信息”窗格(默认情况下为中间窗格)中将数据包的帧控制字段显示为0x4288;它在“十六进制转储”窗格(默认情况下为底部窗格)中显示为88 42,因为它只是按照它们在内存中出现的顺序显示每个单独的八位字节。

如果您希望它在big-endian和little-endian机器上打印为0x4288,则需要将它从little-endian字节顺序转换为主机字节顺序。最简单的方法是使用Wireshark中的pletohs()宏:

#define pletohs(p) ((unsigned short)                       \
                    ((unsigned short)*((const unsigned char *)(p)+1)<<8|  \
                     (unsigned short)*((const unsigned char *)(p)+0)<<0))

并执行诸如

之类的操作
printf("FC = %X\n", pletohs(&mac_header->fc));

对于传输该值,以一种无论机器的字节顺序如何工作的 的最简单方法是使用诸如来自Wireshark的phtoles()宏:

#define phtoles(p, v) \
    {                 \
        (p)[0] = (unsigned char)((v) >> 0);    \
        (p)[1] = (unsigned char)((v) >> 8);    \
    }

并做

pletohs(&mac_header->fc, 0x4288);

设置mac_header->fc

答案 1 :(得分:1)

这是一个字节排序错误。除非您知道您的平台具有与数据包内容相同的字节顺序,否则您无法执行(unsigned short int)(*(packet+2))。在你的情况下,它们不同,这就是你看到字节交换位置的原因。

有关字节顺序或字节序的更多信息,请参阅this Wikipedia article,因为它也被称为。

答案 2 :(得分:1)

FC打印为4288,因为您的系统使用little-endian格式将数据存储在内存中。网络通信遵循大端格式的地方。

确保使用以下程序

#include <stdio.h>
int main()
{

int a = 0x12345678, j = 0;
char *b =(char*)&a;
printf("\n0x");
for(j=0; j < sizeof(int); j++)
        printf("%x", *b++);

printf("\n");

return 0;
}

如果它打印0x78563412,那么你的机器是小端的。否则,如果它打印0x12345678那么它是big-endian。

编辑:
我希望以下链接会有所帮助。

1. http://www.cs.odu.edu/~cs476/fall03/lectures/sockets.htm {
{3}}