4

下面是 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

我的是一个小端机器。

4

3 回答 3

8

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

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 中的所有其他多字节整数字段一样,以小端字节顺序传输,而不是大端字节顺序。“网络字节顺序”是大端endian 字节顺序;并非所有通过网络传输的数据都采用“网络字节顺序”——IPv4、IPv6、TCP 和 UDP 等 Internet 协议标准中的字段采用“网络字节顺序”,但其他协议,包括一些IP 是传输的,有些是通过 TCP 或 UDP 传输的,可能使用 little-endian 字节顺序。)

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

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

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

#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));

至于传输该值,无论您的机器的字节顺序如何最简单的方法是使用诸如phtoles()来自 Wireshark 的宏之类的东西:

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

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

设置mac_header->fc

于 2012-07-19T18:31:36.860 回答
1

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

有关字节顺序或也称为字节序的更多信息,请参阅此 Wikipedia 文章。

于 2012-07-19T14:07:04.613 回答
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 那么它是大端的。

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

1. http://www.cs.odu.edu/~cs476/fall03/lectures/sockets.htm
2.http://www.ccplusplus.com/2011/10/htons-example-in-c.html

于 2012-07-19T14:20:40.840 回答