发送802.11帧的“帧控制字段”数据的顺序?
以下是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
我的是一个小端机器。
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中的所有其他多字节组合字段一样,以little-endian字节顺序传输,而不是以big-endian字节顺序传输。“网络字节顺序” 很大 –字节序字节顺序;并非所有通过网络传输的数据都是“网络字节顺序” – 互联网协议标准中的字段(如IPv4,IPv6,TCP和UDP)采用“网络字节顺序”,但其他协议,包括其中一些IP被传输,一些通过TCP或UDP传输,可能使用little-endian字节顺序。)
由小端机器接收,并被视为16位整数量,即0x4288 – 在小端机器上,具有多个八位字节的积分量,内存中的第一个八位字节是低阶八位字节数量。 因此,您的代码在您的little-endian机器上打印为0x4288; 如果它在大端机器上运行,它会将其打印为0x8842。
将其打印为0x4288是打印它的“正确”方式,因为它是“在线上”的小端(或者说,“在空中”,因为这是802.11 :-))。 Wireshark在“数据包详细信息”窗格(默认情况下为中间窗格)中将数据包的帧控制字段显示为0x4288; 它在“hex转储”窗格(默认情况下为底部窗格)中显示为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
。
这是一个字节排序错误。 除非您知道您的平台具有与数据包内容相同的字节顺序,否则您不能执行(unsigned short int)(*(packet+2))
。 在你的情况下,它们不同,这就是你看到字节交换位置的原因。
有关字节顺序或字节序的更多信息,请参阅此维基百科文章 ,因为它也被称为。
FC打印为4288
因为您的系统使用little-endian格式将数据存储在内存中。 网络通信遵循大端格式的地方。
确保使用以下程序
#include 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
2.http://www.ccplusplus.com/2011/10/htons-example-in-c.html