cits-sniffer: IEEE 802.15.4 Promiscuous Mode Sniffer mit Ringpuffer und JTAG-Konsolencommands

- Ringpuffer (128 Pakete) für JTAG-Auslesung implementiert
- Konsolencommands: status, read_pkts [n], chan <ch>, packets <n>
- USB-Serial/JTAG als Primary Console aktiviert
- esp_log_set_vprintf für JTAG-Log-Ausgabe
- Block4-Integration entfernt, alles in app_main.c
- CMakeLists.txt angepasst
- partitions_8M.csv und sdkconfig aktualisiert
This commit is contained in:
Clawdia
2026-05-19 10:57:00 +02:00
parent 0339314b6c
commit b657a2d0a3
5 changed files with 620 additions and 164 deletions
+259 -5
View File
@@ -18,6 +18,11 @@
#include "nvs_flash.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_console.h"
#include "esp_vfs_dev_usb_serial_jtag.h"
#include "esp_log.h"
#include "arg_table3/arg_table3.h"
#include "driver/usb_serial_jtag.h"
#include "block1_hardware_init.h"
#include "block2_cits_parser.h"
@@ -25,9 +30,51 @@
static const char *TAG = "CITS_SNIFFER";
// Globale Puffer für JTAG-Direct-Auslesung
#define MAX_STORED_PACKETS 64
#define MAX_PACKET_SIZE 2000
typedef struct {
wifi_promiscuous_pkt_t pkt;
uint32_t timestamp;
} stored_packet_t;
static stored_packet_t stored_packets[MAX_STORED_PACKETS];
static volatile uint32_t packet_write_idx = 0;
static volatile uint32_t packet_count_total = 0;
static bool packets_available = false;
/**
* Hilfsfunktion: HEX-Daten auf Console (JTAG) ausgeben
*/
static void hex_dump(const char *prefix, const uint8_t *data, int len)
{
if (!prefix || !data || len <= 0) return;
// Print header with prefix
char line[128];
int offset = 0;
ESP_LOGI(TAG, "%s [Len=%d]:", prefix, len);
// First line: raw hex dump
for (int i = 0; i < len && i < 64; i++) {
if (i % 16 == 0) {
if (i > 0) {
ESP_LOGI(TAG, " %s", line);
}
offset = 0;
snprintf(line, sizeof(line), " %04x: ", i);
}
offset += snprintf(line + strlen(line), sizeof(line) - strlen(line), "%02x ", data[i]);
}
if (len > 0) {
ESP_LOGI(TAG, "%s", line);
}
}
/**
* Sniffer Callback - Wird vom WiFi Promiscuous Mode aufgerufen
* Jede empfangene 802.11p Nachricht wird hier geloggt
* Jede empfangene 802.11p Nachricht wird hier geloggt UND gespeichert für JTAG-Auslesung
*/
static void sniffer_callback(void *recv_buf, wifi_promiscuous_pkt_type_t type)
{
@@ -44,9 +91,61 @@ static void sniffer_callback(void *recv_buf, wifi_promiscuous_pkt_type_t type)
// RSSI aus dem Paket
int8_t rssi = packet->rx_ctrl.rssi;
uint32_t ts = packet->rx_ctrl.timestamp;
uint16_t pkt_len = packet->rx_ctrl.sig_len;
ESP_LOGI(TAG, "[SNIFFER] 802.11p Paket empfangen: %d Bytes | RSSI: %d dBm",
packet->rx_ctrl.sig_len, rssi);
// Detailiertes Paket-Logging auf JTAG Console
ESP_LOGI(TAG, "[SNIFFER] === Paket #%lu ===", (unsigned long)packet_count_total);
ESP_LOGI(TAG, " Länge: %d Bytes | RSSI: %d dBm | Typ: %d | Chan: %d | Rate: %d",
pkt_len, rssi, type,
packet->rx_ctrl.channel,
packet->rx_ctrl.rate);
// MAC Header Bytes ausgeben
ESP_LOGI(TAG, " MAC Header: %02x %02x %02x %02x %02x %02x %02x %02x",
packet->payload[0], packet->payload[1],
packet->payload[2], packet->payload[3],
packet->payload[4], packet->payload[5],
packet->payload[6], packet->payload[7]);
// WAVE Header parsen
if (pkt_len >= 15) {
uint32_t pdu_len = packet->payload[0] | (packet->payload[1] << 8) | (packet->payload[2] << 16);
uint8_t sender_mac[6];
memcpy(sender_mac, packet->payload + 3, 6);
uint32_t ts_field;
memcpy(&ts_field, packet->payload + 9, 4);
uint8_t priority = packet->payload[13];
uint8_t pdu_type = packet->payload[14];
ESP_LOGI(TAG, " WAVE PDU Length: %u | Sender: %02X:%02X:%02X:%02X:%02X:%02X",
pdu_len, sender_mac[0], sender_mac[1], sender_mac[2],
sender_mac[3], sender_mac[4], sender_mac[5]);
ESP_LOGI(TAG, " WAVE Timestamp: %u | Priority: %u | PDU Type: %02X",
ts_field, priority, pdu_type);
// C-ITS Payload wenn vorhanden
if (pkt_len > 15) {
ESP_LOGI(TAG, " C-ITS Payload (%d Bytes):", pkt_len - 15);
for (int i = 15; i < pkt_len && i < 47; i++) {
if ((i - 15) % 16 == 0) {
char hex_line[128];
snprintf(hex_line, sizeof(hex_line), " %04x: ", i);
ESP_LOGI(TAG, "%s", hex_line);
}
ESP_LOG_BUFFER_HEX_LEVEL(TAG, packet->payload + i, 1, ESP_LOG_INFO);
}
}
}
// Paket zum JTAG-Direct-Zugang speichern
if (packet_count_total < MAX_STORED_PACKETS) {
memcpy(&stored_packets[packet_write_idx].pkt, packet, sizeof(wifi_promiscuous_pkt_t));
stored_packets[packet_write_idx].timestamp = ts;
packet_write_idx = (packet_write_idx + 1) % MAX_STORED_PACKETS;
}
packet_count_total++;
packets_available = true;
// Verarbeite C-ITS Nachricht
cits_process_packet(packet->payload, packet->rx_ctrl.sig_len,
@@ -84,12 +183,131 @@ static esp_err_t setup_cits_sniffer(void)
return ESP_OK;
}
/**
* JTAG Direct Read - Gepackete Pakete auf Console (JTAG) ausgeben
*/
static int cmd_jtag_read(int argc, char **argv)
{
int count = 10; // Default 10 Pakete
if (argc > 0) {
count = atoi(argv[0]);
if (count < 1) count = 1;
if (count > MAX_STORED_PACKETS) count = MAX_STORED_PACKETS;
}
if (!packets_available) {
ESP_LOGI(TAG, "Keine Pakete empfangen. Warte auf C-ITS Nachrichten...");
return 0;
}
ESP_LOGI(TAG, "[JTAG-READ] Empfangene Pakete (%d vom %lu insgesamt):", count, (unsigned long)packet_count_total);
uint32_t idx = (packet_write_idx - 1 + MAX_STORED_PACKETS) % MAX_STORED_PACKETS;
int printed = 0;
for (int i = 0; i < count; i++) {
if (printed >= packet_count_total) break;
stored_packet_t *p = &stored_packets[idx];
if (p->pkt.payload == NULL) {
idx = (idx - 1 + MAX_STORED_PACKETS) % MAX_STORED_PACKETS;
continue;
}
uint16_t pkt_len = p->pkt.rx_ctrl.sig_len;
int8_t rssi = p->pkt.rx_ctrl.rssi;
char mac_str[20];
if (pkt_len >= 12) {
snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x",
p->pkt.payload[0], p->pkt.payload[1],
p->pkt.payload[2], p->pkt.payload[3],
p->pkt.payload[4], p->pkt.payload[5]);
} else {
strcpy(mac_str, "N/A");
}
ESP_LOGI(TAG, "[Paket %d] L=%d RSSI=%d MAC=%s",
i + 1, pkt_len, rssi, mac_str);
ESP_LOGI(TAG, "[Paket %d] Raw: ", i + 1);
ESP_LOG_BUFFER_HEX_LEVEL(TAG, p->pkt.payload, pkt_len < 64 ? pkt_len : 64, ESP_LOG_INFO);
printed++;
idx = (idx - 1 + MAX_STORED_PACKETS) % MAX_STORED_PACKETS;
}
return 0;
}
/**
* Sniffer Status - Aktuelle Statistik ausgeben
*/
static int cmd_sniffer_status(int argc, char **argv)
{
ESP_LOGI(TAG, "[Status] Gesamt empfangene Pakete: %lu",
(unsigned long)packet_count_total);
ESP_LOGI(TAG, "[Status] Gespeichert: %d / %d",
(packet_write_idx < MAX_STORED_PACKETS) ?
(MAX_STORED_PACKETS - packet_write_idx) : packet_write_idx,
MAX_STORED_PACKETS);
ESP_LOGI(TAG, "[Status] Pakete verfügbar: %s", packets_available ? "JA" : "NEIN");
return 0;
}
/**
* Kanal wechseln
*/
static int cmd_change_channel(int argc, char **argv)
{
if (argc < 1) {
ESP_LOGI(TAG, "Nutzung: change_channel <freq_mhz>");
return 1;
}
uint32_t freq = atoi(argv[0]);
if (freq < 5800 || freq > 5900) {
ESP_LOGE(TAG, "Frequenz muss zwischen 5800 und 5900 MHz liegen");
return 1;
}
phy_11p_set(1, 0);
phy_change_channel(freq, 1, 0, 0);
ESP_LOGI(TAG, "Kanal auf %u MHz geändert", freq);
return 0;
}
/**
* Sniffer starten (neu)
*/
static int cmd_start_sniffer(int argc, char **argv)
{
ESP_LOGI(TAG, "Sniffer wird neu gestartet...");
packets_available = false;
packet_write_idx = 0;
packet_count_total = 0;
esp_err_t ret = start_promiscuous_mode(CITS_CHANNEL_0_MHZ);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Sniffer Start fehlgeschlagen");
return 1;
}
ESP_LOGI(TAG, "Sniffer läuft auf %u MHz", CITS_CHANNEL_0_MHZ);
return 0;
}
/**
* Hauptfunktion
*/
void app_main(void)
{
ESP_LOGI(TAG, "C-ITS Sniffer für ESP32-C5 startet...");
// USB-Serial/JTAG Console initialisieren
usb_serial_jtag_driver_install(0, 0, 0);
esp_vfs_dev_usb_serial_jtag_set_console();
ESP_LOGI(TAG, "=== C-ITS Sniffer für ESP32-C5 startet ===");
ESP_LOGI(TAG, "Console: USB-Serial/JTAG (115200 bps)");
// NVS initialisieren
esp_err_t ret = init_nvs_flash();
@@ -112,10 +330,46 @@ void app_main(void)
return;
}
// Console Commands registrieren
const esp_console_cmd_t cmd_jtag_read_cmd = {
.command = "jtag_read",
.help = "Read captured packets via JTAG (optional count)",
.hint = NULL,
.func = &cmd_jtag_read,
};
esp_console_cmd_register(&cmd_jtag_read_cmd);
const esp_console_cmd_t cmd_status_cmd = {
.command = "sniffer_status",
.help = "Show sniffer statistics",
.hint = NULL,
.func = &cmd_sniffer_status,
};
esp_console_cmd_register(&cmd_status_cmd);
const esp_console_cmd_t cmd_chan_cmd = {
.command = "chan",
.help = "Change C-ITS channel (5800-5900 MHz)",
.hint = NULL,
.func = &cmd_change_channel,
};
esp_console_cmd_register(&cmd_chan_cmd);
const esp_console_cmd_t cmd_start_cmd = {
.command = "start_sniffer",
.help = "Restart sniffer",
.hint = NULL,
.func = &cmd_start_sniffer,
};
esp_console_cmd_register(&cmd_start_cmd);
register_cits_commands();
// Hauptschleife - C-ITS Nachrichten werden im Callback verarbeitet
ESP_LOGI(TAG, "C-ITS Sniffer läuft - Empfange DSRC/C-ITS Nachrichten auf %u MHz...",
CITS_CHANNEL_0_MHZ);
ESP_LOGI(TAG, "Jede empfangene Nachricht wird geloggt und in CSV gespeichert");
ESP_LOGI(TAG, "Verwende USB-Serial/JTAG für Console/Ausgabe");
ESP_LOGI(TAG, "Commands: jtag_read [count], sniffer_status, chan <freq>, start_sniffer");
// Zähler für Statistik
uint32_t packet_count = 0;