/* Validates a packet's reported FCS value */ static int check_fcs(const unsigned char *packet, size_t len) { if(!has_rt_header()) return 1; uint32_t offset = 0, match = 0; uint32_t fcs = 0, fcs_calc = 0; struct radio_tap_header *rt_header = NULL; if(len > 4) { /* FCS is not calculated over the radio tap header */ if(len >= sizeof(*rt_header)) { uint32_t presentflags, flags; if(!rt_get_presentflags(packet, len, &presentflags, &offset)) goto skip; if(!(presentflags & (1U << IEEE80211_RADIOTAP_FLAGS))) goto skip; offset = rt_get_flag_offset(presentflags, IEEE80211_RADIOTAP_FLAGS, offset); if(offset < len) { memcpy(&flags, packet + offset, 4); flags = end_le32toh(flags); if(flags & IEEE80211_RADIOTAP_F_BADFCS) return 0; if(!(flags & IEEE80211_RADIOTAP_F_FCS)) return 1; } skip: rt_header = (struct radio_tap_header *) packet; offset = end_le16toh(rt_header->len); } /* Get the packet's reported FCS (last 4 bytes of the packet) */ fcs = end_le32toh(*(uint32_t*)(packet + (len-4))); if(len > offset) { /* FCS is the inverse of the CRC32 checksum of the data packet minus the frame's FCS and radio tap header (if any) */ fcs_calc = ~crc32((char *) packet+offset, (len-offset-4)); if(fcs_calc == fcs) { match = 1; } } } return match; }
/* * Returns a pointer to the radio tap header. If there is no radio tap header, * it returns a pointer to a dummy radio tap header. */ const u_char *radio_header(const u_char *packet, size_t len) { if(has_rt_header()) { return packet; } else { return (u_char *) FAKE_RADIO_TAP_HEADER; } }
/* * Returns a pointer to the radio tap header. If there is no radio tap header, * it returns a pointer to a dummy radio tap header. */ unsigned char *radio_header(const unsigned char *packet, size_t len) { if(has_rt_header()) { return (void*)packet; } else { return FAKE_RADIO_TAP_HEADER; } }
/* Extracts the signal strength field (if any) from the packet's radio tap header */ int8_t signal_strength(const u_char *packet, size_t len) { int8_t ssi = 0; int offset = sizeof(struct radio_tap_header); struct radio_tap_header *header = NULL; if(has_rt_header() && (len > (sizeof(struct radio_tap_header) + TSFT_SIZE + FLAGS_SIZE + RATE_SIZE + CHANNEL_SIZE + FHSS_FLAG))) { header = (struct radio_tap_header *) packet; if((header->flags & SSI_FLAG) == SSI_FLAG) { if((header->flags & TSFT_FLAG) == TSFT_FLAG) { offset += TSFT_SIZE; } if((header->flags & FLAGS_FLAG) == FLAGS_FLAG) { offset += FLAGS_SIZE; } if((header->flags & RATE_FLAG) == RATE_FLAG) { offset += RATE_SIZE; } if((header->flags & CHANNEL_FLAG) == CHANNEL_FLAG) { offset += CHANNEL_SIZE; } if((header->flags & FHSS_FLAG) == FHSS_FLAG) { offset += FHSS_FLAG; } else { offset += 12; } if(offset < len) { ssi = (int8_t) packet[offset]; } if (ssi > 100) { ssi = 100 - ssi; } } } return ssi; }
/* Extracts the signal strength field (if any) from the packet's radio tap header */ int8_t signal_strength(const unsigned char *packet, size_t len) { if(has_rt_header() && (len > (sizeof(struct radio_tap_header)))) { uint32_t offset, presentflags; if(!rt_get_presentflags(packet, len, &presentflags, &offset)) return 0; if(!(presentflags & (1U << IEEE80211_RADIOTAP_DBM_ANTSIGNAL))) return 0; offset = rt_get_flag_offset(presentflags, IEEE80211_RADIOTAP_DBM_ANTSIGNAL, offset); if (offset < len) return (int8_t) packet[offset]; } return 0; }
/* Validates a packet's reported FCS value */ int check_fcs(const u_char *packet, size_t len) { int offset = 0, match = 0; uint32_t fcs = 0, fcs_calc = 0; struct radio_tap_header *rt_header = NULL; if(len > 4) { /* Get the packet's reported FCS (last 4 bytes of the packet) */ memcpy((uint32_t *) &fcs, (packet + (len-4)), 4); /* FCS is not calculated over the radio tap header */ if(has_rt_header()) { rt_header = (struct radio_tap_header *) packet; #ifdef __APPLE__ unsigned char *body = (unsigned char*) (rt_header+1); uint32_t present = rt_header->flags; uint8_t rflags = 0; int i; for (i = IEEE80211_RADIOTAP_TSFT; i <= IEEE80211_RADIOTAP_EXT; i++) { if (!(present & (1 << i))) continue; switch (i) { case IEEE80211_RADIOTAP_TSFT: body += sizeof(uint64_t); break; case IEEE80211_RADIOTAP_FLAGS: rflags = *((uint8_t*)body); /* fall through */ case IEEE80211_RADIOTAP_RATE: body += sizeof(uint8_t); break; case IEEE80211_RADIOTAP_CHANNEL: body += sizeof(uint16_t)*2; break; case IEEE80211_RADIOTAP_RX_FLAGS: case IEEE80211_RADIOTAP_FHSS: body += sizeof(uint16_t); break; case IEEE80211_RADIOTAP_DB_ANTSIGNAL: case IEEE80211_RADIOTAP_DBM_ANTNOISE: case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: case IEEE80211_RADIOTAP_DB_ANTNOISE: case IEEE80211_RADIOTAP_ANTENNA: body++; break; case 18: // IEEE80211_RADIOTAP_XCHANNEL body += sizeof(uint32_t); body += sizeof(uint16_t); body += sizeof(uint8_t); body += sizeof(uint8_t); break; case 19: // IEEE80211_RADIOTAP_MCS body += 3*sizeof(uint8_t); break; default: i = IEEE80211_RADIOTAP_EXT+1; break; } } #define IEEE80211_RADIOTAP_F_BADFCS 0x40 if (rflags & IEEE80211_RADIOTAP_F_BADFCS) { // bad FCS, ignore return 0; } if (!(rflags & IEEE80211_RADIOTAP_F_FCS)) { // fcs not always present return 1; } #endif offset += rt_header->len; } if(len > offset) { /* FCS is the inverse of the CRC32 checksum of the data packet minus the frame's FCS and radio tap header (if any) */ fcs_calc = ~crc32((char *) packet+offset, (len-offset-4)); if(fcs_calc == fcs) { match = 1; } } } return match; }