- Phase 2 (Observation): passive client mapping from data frame headers, ClientInfo array per slot (up to 8 clients), 5s observation window - Phase 3 (Targeting): unicast deauth burst to each discovered client instead of broadcast, reason code 7, 5 frames per client - Phase 4 (Capture): timeout + retry loop cycles back to observation to refresh stale client list (2 cycles within 30s channel timeout) - Fix EAPOL detection: compute LLC/SNAP offset from QoS vs non-QoS header length, verify AA-AA-03 SNAP prefix, skip protected frames - Concurrency: portMUX spinlock for callback/main-loop shared state, no dynamic alloc in callback, pre-allocated 4KB PCAP buffer per slot - Phase-aware LCD status display (mapping → capturing → EAPOL count) Made-with: Cursor
112 lines
2.6 KiB
C++
112 lines
2.6 KiB
C++
/*
|
|
* WiFi Handshake Capture - ESP32-C6 1.47" LCD
|
|
* Multi-target capture: up to 3 networks per channel, deauth all, capture all.
|
|
* Display: green = not captured, red = captured.
|
|
*/
|
|
|
|
#include "Display_ST7789.h"
|
|
#include "LVGL_Driver.h"
|
|
#include "WiFi_Scanner.h"
|
|
#include "SD_Card.h"
|
|
#include "HandshakeCapture.h"
|
|
|
|
enum CaptureState {
|
|
STATE_SCANNING,
|
|
STATE_CAPTURING,
|
|
STATE_WAITING
|
|
};
|
|
|
|
CaptureState captureState = STATE_SCANNING;
|
|
unsigned long capture_start_time = 0;
|
|
const unsigned long CHANNEL_TIMEOUT_MS = 30000;
|
|
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
LCD_Init();
|
|
Set_Backlight(100);
|
|
Lvgl_Init();
|
|
|
|
if (!SD_Init()) {
|
|
Ui_SetWifiStatus("SD: no card");
|
|
} else {
|
|
Ui_SetWifiStatus("SD OK");
|
|
}
|
|
|
|
handshakeCaptureInit();
|
|
WiFiScanner_Refresh();
|
|
captureState = STATE_SCANNING;
|
|
}
|
|
|
|
void loop() {
|
|
Timer_Loop();
|
|
handshakeCaptureProcessPending();
|
|
handshakeCaptureLoop();
|
|
|
|
switch (captureState) {
|
|
case STATE_SCANNING: {
|
|
if (getCaptureableCount() == 0) {
|
|
Ui_SetWifiStatus("Rescan");
|
|
WiFiScanner_Refresh();
|
|
delay(500);
|
|
break;
|
|
}
|
|
startMultiCapture();
|
|
if (is_capturing) {
|
|
captureState = STATE_CAPTURING;
|
|
capture_start_time = millis();
|
|
Ui_SetWifiStatus("Mapping clients");
|
|
} else {
|
|
Ui_SetWifiStatus("No targets");
|
|
delay(1000);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case STATE_CAPTURING: {
|
|
bool any_active = false;
|
|
for (int i = 0; i < MAX_SLOTS; i++) {
|
|
if (slots[i].active) {
|
|
any_active = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Phase-aware status display
|
|
static CapturePhase last_shown_phase = PHASE_CAPTURING;
|
|
if (capturePhase != last_shown_phase) {
|
|
Ui_SetWifiStatus(capturePhase == PHASE_OBSERVING ? "Mapping clients" : "Capturing...");
|
|
last_shown_phase = capturePhase;
|
|
}
|
|
|
|
static int last_eapol = -1;
|
|
if (capturePhase == PHASE_CAPTURING && latest_eapol_count != last_eapol) {
|
|
char buf[64];
|
|
snprintf(buf, sizeof(buf), "EAPOL %d/2", latest_eapol_count);
|
|
Ui_SetWifiStatus(buf);
|
|
last_eapol = latest_eapol_count;
|
|
}
|
|
|
|
if (!any_active && getCaptureableCount() == 0) {
|
|
Ui_SetWifiStatus("Done");
|
|
stopCapture();
|
|
captureState = STATE_SCANNING;
|
|
delay(2000);
|
|
} else if (!any_active) {
|
|
stopCapture();
|
|
captureState = STATE_SCANNING;
|
|
} else if (millis() - capture_start_time > CHANNEL_TIMEOUT_MS) {
|
|
Ui_SetWifiStatus("Ch timeout");
|
|
stopCapture();
|
|
captureState = STATE_SCANNING;
|
|
delay(2000);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case STATE_WAITING:
|
|
break;
|
|
}
|
|
|
|
delay(16);
|
|
}
|