【问题标题】:Order of sending "Frame Control field"data of an 802.11 frame?发送 802.11 帧的“帧控制字段”数据的顺序?
【发布时间】:2015-07-06 21:59:01
【问题描述】:

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

我的是一个小端机器。

【问题讨论】:

  • 查找网络字节顺序。它应该是大端。

标签: c libpcap wifi


【解决方案1】:

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

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

将其打印为 0x4288 是“正确”的打印方式,因为它是 little-endian “在线”(或者,更确切地说,“在线”,因为这是 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));

至于 transmitting 该值,最简单的that方法是使用诸如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-&gt;fc

【讨论】:

  • 美丽的解释......谢谢......我有一个问题。是否也有按名称命名的宏:pbetohs() 和 phtobes()?
  • Wireshark 确实具有执行这些功能的宏,但它们的名称源自 ntohs()ntohl()htons()htonl() - pntohs()pntohl()、@ 987654339@ 和 phtonl()。这些名称反映了“大端”字节顺序为“网络”字节顺序。
【解决方案2】:

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

请参阅this Wikipedia article 了解更多关于字节顺序或字节序的信息。

【讨论】:

  • 您所指的字段恰好是little-endian;它是radiotap 标头中的长度字段。该代码适用于 little-endian 机器,例如具有 x86 处理器的个人计算机。它不适用于大端机器,例如大多数基于 PowerPC 的机器。
  • @GuyHarris 所以,解决办法是这样的:struct radiolength{u_int16_t length;}}struct radiolength *rl = (struct radiolength *)(packet + 2);r1-&gt;length = pletohs(r1-&gt;length);我说的对吗?
  • 或者只是int radiotapheader_length = pletohs(packet+2);
  • @GuyHarris 谢谢……但不应该是int radiotapheader_length = pletohs(*(packet+2));吗?因为数据包是一个指针。
  • ...和pletohs() 将指针作为参数 - 这就是“pletohs”中的“p”的含义。它一次获取一个字节的值,因此它可以得到一个未对齐的指针,并且不会在不允许未对齐访问的处理器(例如 SPARC 处理器)上发生对齐错误。
【解决方案3】:

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 那么你的机器是 little-endian。否则如果它打印 0x12345678 那么它是大端的。

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

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

【讨论】:

  • 是的.. little endian machine ...我在更新中更清楚地说明了我的疑问。你能回答一下吗?
  • @anil.babbur 使用字节序交换函数。 forums.codeguru.com/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多