Question

I've some trouble parsing packets in PPI frame format. I need the 802.11+mac+phy field, after the common field it seems i have a mistake in the offset. Here is my code:

void process_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
int offset = 0;

const struct ppi_packetheader *ppi_header = (struct ppi_packetheader *)(packet + offset);
offset += 8;

const struct ppi_fieldheader *ppi_80211_common = (struct ppi_fieldheader *)(packet + offset);
printf("common type: %d | len: %d\n", ppi_80211_common->pfh_type, ppi_80211_common->pfh_datalen);
offset += 4 + 20;

const struct ppi_fieldheader *ppi_80211_mac = (struct ppi_fieldheader *)(packet + offset);
printf("mac type: %d | len: %d\n", ppi_80211_mac->pfh_type, ppi_80211_mac->pfh_datalen);
offset += 4 + 27;

const struct ppi_fieldheader *ppi_80211_mac_phy = (struct ppi_fieldheader *)(packet + offset);
printf("mac+phy type: %d | len: %d\n", ppi_80211_mac_phy->pfh_type, ppi_80211_mac_phy->pfh_datalen);
}

The output for the common field is correct, it says type: 2, len: 20. But the other values are wrong, like it says for the mac field type: 64, len: 0 (mac+phy looks similar). Is it a problem with little/big endian or where is my mistake? I've been looking at the wireshark implementation, but they use a function tvb_get_letohs() for the offset and that is pretty intricate... Hope someone can help.

Was it helpful?

Solution

First of all, you're not looking at the alignment bit in pph_flags - if it's set, then each field is aligned on a 4-byte boundary and, if it's clear, the fields are not necessarily aligned on 4-byte boundaries. However, the length of the 802.11-Common field is a multiple of 4, as is the length of the field header, so, while you should be looking at that bit, that wouldn't cause this particular problem.

And, yes, "Multi-byte integers in the packet header and field headers MUST be stored as little-endian.", so there could be a byte-order problem. However, that applies to pfh_type and pfh_datalen, so, while you should be byte-swapping those values if you're on a big-endian machine (that's what tvb_get_letohs() is doing - it's getting, from a Wireshark buffer that does bounds-checking, a Little Endian, Short (16-bit) value, and converting it to Host byte order; it also works regardless of whether the field is aligned on a "natural" byte boundary), you're apparently running on a little-endian machine (if it's an x86-based PC - which includes all Intel-based Macs - you're running on a little-endian machine), as the output for the common field is correct, so that's probably not causing this particular problem.

Third, however, you're not looking at ppi_header->pph_len! There is no guarantee that any particular fields are present in the PPI header - you have to check, for each field, whether it's present, by seeing whether you've gone past the length of the PPI header.

When I captured on my Retina MBP on Mountain Lion, with PPI headers, the header length was 32 bytes, and the only field that was present was the 802.11-Common field - the 802.11n MAC+PHY Extensions field was not present (and our network is an 802.11n network). When your code thinks it's looking at the 802.11n MAC+PHY Extensions field, it might actually be looking at the 802.11 MAC header from the 802.11 packet.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top