5

Is the below code correctly calculating the FCS value of wireless 802.11 frames?
Because the value produced by the below code does not match the value shown by wireshark.

const uint32_t crctable[] = {
   0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
   0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
   0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
   0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
   0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
   0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
   0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
   0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
   0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
   0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
   0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
   0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
   0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
   0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
   0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
   0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
   0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
   0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
   0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
   0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
   0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
   0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
   0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
   0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
   0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
   0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
   0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
   0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
   0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
   0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
   0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
   0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
};

uint32_t crc32(uint32_t bytes_sz, const uint8_t *bytes)
{
   uint32_t crc = ~0;
   uint32_t i;
   for(i = 0; i < bytes_sz; ++i) {
      crc = crctable[(crc ^ bytes[i]) & 0xff] ^ (crc >> 8);
   }
   return ~crc;
}


I am calling the above function in the following manner:

uint32_t crc = crc32(header->len - 4, packet);


where header is of type:

struct pcap_pkthdr *header;

The header information is handled by pcap callback:

void my_callback(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)

I got the code for crc32() and crctable[] from this link

An EDIT 2 years later:

The above code of crc32() does work; the line
printf("0x%x\n",crc32(sizeof(MSG)-16-4,MSG+16));
prints the right 802.11 CRC, where:

MSG is an array (unsigned char[]) of message bytes copied and pasted from Wireshark;

16 is the radiotap header size,

4 is the size of FCS (frame check sequence, crc32, little-endian=the x86 order).

18446744073709551615
  • 16,368
  • 4
  • 94
  • 127
bengaluriga
  • 319
  • 2
  • 5
  • 9
  • test some values with known checksums and check against that. If they do not match yours is probably wrong. – RedX Jul 17 '12 at 13:48
  • @RedX I tested it with the checksum produced by wireshark and they don't match. Could you please tell me what is the problem with the above code? – bengaluriga Jul 17 '12 at 13:51
  • There are many unknowns with the wireshark crc32 and how you checksum your code. Go to http://www.lammertbies.nl/comm/info/crc-calculation.html and put a number in there an calculate the checksum and see if it matches with yours. – RedX Jul 17 '12 at 13:54
  • @RedX The checksum calculated by the above link and the checksum calculated by my code matches. But, still you can't ignore the fact that that the wireshark shows a different checksum. Maybe checksum for 802.11 frames are calculated in a different manner. And that is exactly what my question is. Should we have employ a different method for calculating CRC32 for 802.11 frames? – bengaluriga Jul 17 '12 at 15:13
  • now that is a much better explanation of your problem that should have already been stated in the question. As it seems you know your calculation is correct. You need to konw how to checksum the package, which has nothing to do with your (working) implementation. – RedX Jul 17 '12 at 15:32

2 Answers2

4

What is the value returned by pcap_datalink() for the pcap_t on which you're capturing or from which you're reading a capture file?

Unless it's DLT_IEEE802_11 (with a value of 105), the packet is either not an 802.11 packet or is not only an 802.11 packet.

If, for example, it's DLT_EN10MB, it's an Ethernet packet (which you might get from an 802.11 adapter, especially if you're not capturing in monitor mode), and if it's DLT_IEEE802_11_RADIO, it begins with a "radiotap" header as described at the radiotap.org Web site, and you need to skip past the radiotap header to get to the 802.11 frame, and checksum only the 802.11 frame.

(In addition, for some Atheros adapters, the 802.11 frame will have some padding added between the 802.11 header and the 802.11 payload, which you have to remove when checksumming; if you have radiotap headers, that's indicated by the "frame has padding between 802.11 header and payload (to 32-bit boundary)" flag in the flags field.)

  • 1
    Thanks a lot. You are brilliant. You nailed the problem. pcap_datalink() returned DLT_IEEE802_11_RADIO. And I checked the flags field of radiotap header, my wireless card is not doing any data padding. So, I applied crc32() function on the packet skipping over the radiotap header (and minus the last 4 bytes of the packet) and got the checksum value which matched with that of wireshark's. Thanks a ton once again. – bengaluriga Jul 18 '12 at 05:52
0

Some hardware is capable of offloading the checksum verification, effectively giving pre-verified checksum packets to the CPU instead of burdening the CPU with checksum verification. According to wireshark's page on checksums, this may leave the checksum field with zeros or garbage.

Under such a condition the packet will still be processed because the OS is aware that the checksum was already verified in the NIC. The OS will not throw away the packet due to an invalid checksum because it knows the NIC already validated the checksum.

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
  • added bit about offloaded checksum verification – Edwin Buck Jul 17 '12 at 15:25
  • This is an 802.11 checksum, not an Internet checksum, so the entire packet is subject to checksumming, and the checksum is recomputed by the networking hardware on routers during network traversal when the packet is transmitted by the router. –  Jul 17 '12 at 18:06