fiwi_monitor/src/frame_parser.c

162 lines
5.4 KiB
C

#include "config.h"
#include "frame_parser.h"
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
// Radiotap header parsing (simplified)
static int skip_radiotap_header(const uint8_t *packet, size_t len, size_t *offset) {
if (len < 8) return -1;
// Check for radiotap header (starts with version 0)
if (packet[0] == 0 && packet[1] == 0) {
// Radiotap header present
uint16_t rt_len = *(uint16_t *)&packet[2];
if (rt_len > len || rt_len < 8) return -1;
// Extract RSSI and rate from radiotap (simplified - full parsing is complex)
// For now, just skip the header
*offset = rt_len;
return 0;
}
// No radiotap header
*offset = 0;
return 0;
}
int parse_80211_frame(const uint8_t *packet, size_t len, wifi_frame_info_t *frame_info) {
size_t offset = 0;
// Skip radiotap header if present
if (skip_radiotap_header(packet, len, &offset) < 0) {
return -1;
}
if (len < offset + 24) {
return -1; // Too short for 802.11 header
}
const uint8_t *frame = packet + offset;
// Parse Frame Control (bytes 0-1)
frame_info->frame_control = frame[0] | (frame[1] << 8);
frame_info->type = (frame[0] >> 2) & 0x03;
frame_info->subtype = (frame[0] >> 4) & 0x0F;
frame_info->to_ds = (frame[1] >> 0) & 0x01;
frame_info->from_ds = (frame[1] >> 1) & 0x01;
frame_info->retry = (frame[1] >> 3) & 0x01;
// Parse Duration/ID (bytes 2-3)
frame_info->duration_id = frame[2] | (frame[3] << 8);
// Parse Addresses based on To DS / From DS bits
// addr1 = RA (Receiver Address)
// addr2 = TA (Transmitter Address)
// addr3 = BSSID/SA/DA
memcpy(frame_info->addr1, &frame[4], 6); // RA
memcpy(frame_info->addr2, &frame[10], 6); // TA
memcpy(frame_info->addr3, &frame[16], 6); // BSSID/SA/DA
// Check for Address 4 (only if To DS and From DS both set)
frame_info->has_addr4 = frame_info->to_ds && frame_info->from_ds;
if (frame_info->has_addr4) {
if (len < offset + 30) return -1;
memcpy(frame_info->addr4, &frame[22], 6);
}
// Parse Sequence Control (bytes 22-23 or 28-29)
uint16_t seq_offset = frame_info->has_addr4 ? 28 : 22;
if (len < offset + seq_offset + 2) return -1;
frame_info->seq_ctrl = frame[seq_offset] | (frame[seq_offset + 1] << 8);
frame_info->fragment_num = frame_info->seq_ctrl & 0x0F;
frame_info->sequence_num = (frame_info->seq_ctrl >> 4) & 0x0FFF;
// Initialize PHY info (would need radiotap parsing for accurate values)
frame_info->rssi = -100; // Default
frame_info->mcs = 0;
frame_info->spatial_streams = 1;
frame_info->bandwidth = 0;
frame_info->sgi = false;
frame_info->phy_rate_kbps = 0;
frame_info->frame_len = len - offset;
return 0;
}
const char *get_frame_type_name(uint8_t type, uint8_t subtype) {
switch (type) {
case FRAME_TYPE_MANAGEMENT:
switch (subtype) {
case 0: return "ASSOC_REQ";
case 1: return "ASSOC_RESP";
case 2: return "REASSOC_REQ";
case 3: return "REASSOC_RESP";
case 4: return "PROBE_REQ";
case 5: return "PROBE_RESP";
case 8: return "BEACON";
case 10: return "DISASSOC";
case 11: return "AUTH";
case 12: return "DEAUTH";
default: return "MGMT_UNKNOWN";
}
case FRAME_TYPE_CONTROL:
switch (subtype) {
case 11: return "RTS";
case 12: return "CTS";
case 13: return "ACK";
default: return "CTRL_UNKNOWN";
}
case FRAME_TYPE_DATA:
switch (subtype) {
case 0: return "DATA";
case 1: return "DATA_CF_ACK";
case 2: return "DATA_CF_POLL";
case 3: return "DATA_CF_ACK_POLL";
case 4: return "NULL";
case 8: return "QOS_DATA";
case 12: return "QOS_NULL";
default: return "DATA_UNKNOWN";
}
default:
return "UNKNOWN";
}
}
void print_frame_info(const wifi_frame_info_t *frame_info, uint64_t timestamp_us) {
const char *type_name = get_frame_type_name(frame_info->type, frame_info->subtype);
printf("[%llu.%03llu] %s: ",
timestamp_us / 1000000, (timestamp_us / 1000) % 1000);
printf("TA=%02x:%02x:%02x:%02x:%02x:%02x, ",
frame_info->addr2[0], frame_info->addr2[1], frame_info->addr2[2],
frame_info->addr2[3], frame_info->addr2[4], frame_info->addr2[5]);
printf("RA=%02x:%02x:%02x:%02x:%02x:%02x, ",
frame_info->addr1[0], frame_info->addr1[1], frame_info->addr1[2],
frame_info->addr1[3], frame_info->addr1[4], frame_info->addr1[5]);
printf("Size=%u bytes, ", frame_info->frame_len);
printf("Dur=%u us, ", frame_info->duration_id);
printf("RSSI=%d dBm", frame_info->rssi);
if (frame_info->retry) {
printf(", Retry=YES");
} else {
printf(", Retry=no");
}
if (frame_info->mcs > 0) {
printf(", MCS=%u", frame_info->mcs);
}
if (frame_info->spatial_streams > 1) {
printf(", SS=%u", frame_info->spatial_streams);
}
printf("\n");
}