Order of sending "Frame Control field"data of an 802.11 frame?
c, libpcap, wifi
Solution
The IEEE 802.11 standard (which, unfortunately, is not currently available from the IEEE Get program) says:
The MPDUs or frames in the MAC sublayer are described as a sequence of fields in specific order. Each figure in Clause 7 depicts the fields/subfields as they appear in the MAC frame and in the order in which they are passed to the physical layer convergence procedure (PLCP), from left to right.
In figures, all bits within fields are numbered, from 0 to k, where the length of the field is k + 1 bits. The octet boundaries within a field can be obtained by taking the bit numbers of the field modulo 8. Octets within numeric fields that are longer than a single octet are depicted in increasing order of significance, from lowest numbered bit to highest numbered bit. The octets in fields longer than a single octet are sent to the PLCP in order from the octet containing the lowest numbered bits to the octet containing the highest numbered bits.
So the first octet of the Frame Control field sent to the PLCP is the one containing B0, i.e. the octet containing the protocol version, type, and subtype fields. After that comes the octet containing To DS, From DS, More Frag, and so on. The `00|01|0001` octet is, therefore, the first octet transmitted. That turns into 10001000 in a byte in memory, from high-order bit to low-order bit rather than low-order bit to high-order bit, hence 0x88. The next octet is the `01000010` one, hence 0x42.
So that goes over the wire as `00010001` followed by `01000010`, and would appear in memory as 0x88 followed by 0x42. (This, by the way, means that the FC field, like all other multi-octet integral fields in 802.11, is transmitted in little-endian byte order, rather than in big-endian byte order. "Network byte order" is big-endian byte order; not all data transmitted over a network is in "network byte order" - fields in Internet protocol standards such as IPv4, IPv6, TCP, and UDP are in "network byte order", but other protocols, including some over which IP is transmitted and some that are transmitted over TCP or UDP, may use little-endian byte order.)
As received by a little-endian machine, and treated as a 16-bit integral quantity, that would be 0x4288 - on a little-endian machine, with a multiple-octet integral quantity, the first octet in memory is the low-order octet of the quantity. Therefore, your code prints it as 0x4288 on your little-endian machine; if it were running on a big-endian machine, it would print it as 0x8842.
Printing it as 0x4288 is the "correct" way to print it, as it's little-endian "on the wire" (or, rather, "on the air", as this is 802.11 :-)). Wireshark shows the Frame Control field for your packet as 0x4288 in the "packet details" pane (the middle pane, by default); it shows up as 88 42 in the "hex dump" pane (the bottom pane, by default) because it's just showing each individual octet in the order in which they appear in memory.
You would need to convert it from little-endian byte order to host byte order if you want it to print as 0x4288 on both big-endian and little-endian machines. The easiest way to do that would be to use something such as the `pletohs()` macro from Wireshark:
#define pletohs(p) ((unsigned short) \
((unsigned short)*((const unsigned char *)(p)+1)<<8| \
(unsigned short)*((const unsigned char *)(p)+0)<<0))
and do something such as
printf("FC = %X\n", pletohs(&mac_header->fc));
As for transmitting that value, the easiest way to do that in a way that works regardless of the byte order of your machine would be to use something such as the `phtoles()` macro from Wireshark:
#define phtoles(p, v) \
{ \
(p)[0] = (unsigned char)((v) >> 0); \
(p)[1] = (unsigned char)((v) >> 8); \
}
and do
pletohs(&mac_header->fc, 0x4288);
to set `mac_header->fc`.
Problem
Below is bit format for FC field for QoS Data: ``` 00|01|0001 01000010 ``` The first 2 bits represent version, the next 2 bits type, the next 4 bits subtype, with ToDS=0, FromDS=1,Protection bit=1. So, in what order is the above data sent through the interface on the air? (i.e left to right or right to left ) I see the wireshark catching the data as "8842"(in the last segment where it shows raw packet data). But, if I write the following code to print FC field data: ``` 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); } ``` The output is: ``` FC = 4288 ``` So my secondary question is, shouldn't it print 8842 instead of 4288? Update: I am updating the question so as to be more clear about what my doubt is. Say, I want to send a QoS Data packet whose FC field is in the format below: ``` 00|01|0001 01000010 ``` So, should I have to write: ``` mac_header->fc = 0x1142 /* value if read from left to right */ ``` Or ``` mac_header->fc = 0x4211 ``` Or ``` mac_header->fc = 0x4288 /* value if read from right to left */ ``` Or ``` mac_header->fc = 0x8842 ``` Mine is a little endian machine.