feat: Add HMAC command auth, deauth flood detection, sign all tools

Firmware:
- HMAC-SHA256 command authentication (AUTH command, NVS persisted)
- Deauth flood detection with ring buffer and aggregate ALERT_DATA
- FLOODTHRESH command (count + window, NVS persisted)
- New STATUS fields: auth=on/off, flood_thresh=5/10
- mbedtls dependency in CMakeLists.txt, rx_buf increased to 192

Tools:
- esp-cmd/esp-fleet/esp-ota import sign_command from esp_ctl.auth
- Commands auto-signed when ESP_CMD_SECRET env var is set

Docs:
- CHEATSHEET: AUTH, FLOODTHRESH, HMAC auth, OUI, watch, osint sections
- TASKS: v1.3 completed section with all new features
This commit is contained in:
user
2026-02-04 21:07:00 +01:00
parent 7ca58fee72
commit 2586234473
7 changed files with 495 additions and 55 deletions

View File

@@ -41,6 +41,7 @@
#include "driver/temperature_sensor.h"
#endif
#include "mdns.h"
#include "mbedtls/md.h"
#include "lwip/inet.h"
#include "lwip/netdb.h"
@@ -95,6 +96,24 @@ static volatile int8_t s_rssi_min = 0;
static volatile int8_t s_rssi_max = -128;
static uint32_t s_boot_count = 0;
/* CSI output mode */
typedef enum {
CSI_MODE_RAW = 0,
CSI_MODE_COMPACT = 1,
CSI_MODE_HYBRID = 2,
} csi_mode_t;
typedef struct {
float amp_rms;
float amp_std;
float amp_max;
uint8_t amp_max_idx;
uint32_t energy;
} csi_features_t;
static csi_mode_t s_csi_mode = CSI_MODE_RAW;
static int s_hybrid_interval = 10;
/* Adaptive sampling */
#define WANDER_WINDOW 50
#define RATE_ACTIVE 100
@@ -128,6 +147,7 @@ static char s_udp_buffer[2048];
static char s_target_ip[16]; /* runtime target IP (NVS or Kconfig default) */
static uint16_t s_target_port; /* runtime target port */
static char s_hostname[32]; /* runtime hostname (NVS or Kconfig default) */
static char s_auth_secret[65] = ""; /* empty = auth disabled */
/* --- NVS helpers --- */
@@ -170,10 +190,28 @@ static void config_load_nvs(void)
}
size_t hn_len = sizeof(s_hostname);
nvs_get_str(h, "hostname", s_hostname, &hn_len);
int8_t csi_mode;
if (nvs_get_i8(h, "csi_mode", &csi_mode) == ESP_OK && csi_mode >= 0 && csi_mode <= 2) {
s_csi_mode = (csi_mode_t)csi_mode;
}
int32_t hybrid_n;
if (nvs_get_i32(h, "hybrid_n", &hybrid_n) == ESP_OK && hybrid_n >= 1 && hybrid_n <= 100) {
s_hybrid_interval = (int)hybrid_n;
}
size_t sec_len = sizeof(s_auth_secret);
nvs_get_str(h, "auth_secret", s_auth_secret, &sec_len);
int32_t flood_t;
if (nvs_get_i32(h, "flood_thresh", &flood_t) == ESP_OK && flood_t >= 1 && flood_t <= 100) {
s_flood_thresh = (int)flood_t;
}
int32_t flood_w;
if (nvs_get_i32(h, "flood_window", &flood_w) == ESP_OK && flood_w >= 1 && flood_w <= 300) {
s_flood_window_s = (int)flood_w;
}
nvs_close(h);
ESP_LOGI(TAG, "NVS loaded: hostname=%s rate=%d tx_power=%d adaptive=%d threshold=%.6f ble=%d target=%s:%d",
ESP_LOGI(TAG, "NVS loaded: hostname=%s rate=%d tx_power=%d adaptive=%d threshold=%.6f ble=%d target=%s:%d csi_mode=%d hybrid_n=%d",
s_hostname, s_send_frequency, s_tx_power_dbm, s_adaptive, s_motion_threshold, s_ble_enabled,
s_target_ip, s_target_port);
s_target_ip, s_target_port, (int)s_csi_mode, s_hybrid_interval);
} else {
ESP_LOGI(TAG, "NVS: no saved config, using defaults");
}
@@ -298,6 +336,52 @@ static void led_task(void *arg)
}
}
/* --- CSI feature extraction --- */
static void csi_extract_features(const int8_t *buf, int len, float gain, csi_features_t *out)
{
int n_pairs = len / 2;
if (n_pairs > 64) n_pairs = 64;
float amps[64];
float sum_sq = 0.0f;
float sum_amp = 0.0f;
float max_amp = 0.0f;
uint8_t max_idx = 0;
uint32_t energy = 0;
/* Pass 1: compute per-subcarrier amplitude, accumulate sums */
for (int i = 0; i < n_pairs; i++) {
float iv = gain * buf[i * 2];
float qv = gain * buf[i * 2 + 1];
float amp = sqrtf(iv * iv + qv * qv);
amps[i] = amp;
sum_amp += amp;
sum_sq += iv * iv + qv * qv;
energy += abs(buf[i * 2]) + abs(buf[i * 2 + 1]);
if (amp > max_amp) {
max_amp = amp;
max_idx = (uint8_t)i;
}
}
float mean_amp = (n_pairs > 0) ? sum_amp / n_pairs : 0.0f;
/* Pass 2: compute variance */
float var = 0.0f;
for (int i = 0; i < n_pairs; i++) {
float d = amps[i] - mean_amp;
var += d * d;
}
var = (n_pairs > 0) ? var / n_pairs : 0.0f;
out->amp_rms = (n_pairs > 0) ? sqrtf(sum_sq / n_pairs) : 0.0f;
out->amp_std = sqrtf(var);
out->amp_max = max_amp;
out->amp_max_idx = max_idx;
out->energy = energy;
}
/* --- CSI callback --- */
static void wifi_csi_rx_cb(void *ctx, wifi_csi_info_t *info)
@@ -339,6 +423,17 @@ static void wifi_csi_rx_cb(void *ctx, wifi_csi_info_t *info)
ESP_LOGD(TAG, "compensate_gain %f, agc_gain %d, fft_gain %d", compensate_gain, agc_gain, fft_gain);
#endif
/* Extract features (used for compact mode and adaptive sampling) */
csi_features_t features = {0};
if (s_csi_mode != CSI_MODE_RAW || s_adaptive) {
csi_extract_features(info->buf, info->len, compensate_gain, &features);
}
/* Determine whether to send raw I/Q data this packet */
csi_mode_t mode = s_csi_mode;
bool send_raw = (mode == CSI_MODE_RAW) ||
(mode == CSI_MODE_HYBRID && (s_csi_count % s_hybrid_interval) == 0);
/* Build CSI data into buffer for UDP transmission */
int pos = 0;
@@ -364,35 +459,41 @@ static void wifi_csi_rx_cb(void *ctx, wifi_csi_info_t *info)
rx_ctrl->timestamp, rx_ctrl->ant, rx_ctrl->sig_len, rx_ctrl->rx_state);
#endif
if (send_raw) {
/* Raw I/Q array payload */
#if (CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C61) && CSI_FORCE_LLTF
int16_t csi = ((int16_t)(((((uint16_t)info->buf[1]) << 8) | info->buf[0]) << 4) >> 4);
pos += snprintf(s_udp_buffer + pos, sizeof(s_udp_buffer) - pos,
",%d,%d,\"[%d", (info->len - 2) / 2, info->first_word_invalid, (int16_t)(compensate_gain * csi));
for (int i = 2; i < (info->len - 2); i += 2) {
csi = ((int16_t)(((((uint16_t)info->buf[i + 1]) << 8) | info->buf[i]) << 4) >> 4);
pos += snprintf(s_udp_buffer + pos, sizeof(s_udp_buffer) - pos, ",%d", (int16_t)(compensate_gain * csi));
}
int16_t csi = ((int16_t)(((((uint16_t)info->buf[1]) << 8) | info->buf[0]) << 4) >> 4);
pos += snprintf(s_udp_buffer + pos, sizeof(s_udp_buffer) - pos,
",%d,%d,\"[%d", (info->len - 2) / 2, info->first_word_invalid, (int16_t)(compensate_gain * csi));
for (int i = 2; i < (info->len - 2); i += 2) {
csi = ((int16_t)(((((uint16_t)info->buf[i + 1]) << 8) | info->buf[i]) << 4) >> 4);
pos += snprintf(s_udp_buffer + pos, sizeof(s_udp_buffer) - pos, ",%d", (int16_t)(compensate_gain * csi));
}
#else
pos += snprintf(s_udp_buffer + pos, sizeof(s_udp_buffer) - pos,
",%d,%d,\"[%d", info->len, info->first_word_invalid, (int16_t)(compensate_gain * info->buf[0]));
for (int i = 1; i < info->len; i++) {
pos += snprintf(s_udp_buffer + pos, sizeof(s_udp_buffer) - pos, ",%d", (int16_t)(compensate_gain * info->buf[i]));
}
pos += snprintf(s_udp_buffer + pos, sizeof(s_udp_buffer) - pos,
",%d,%d,\"[%d", info->len, info->first_word_invalid, (int16_t)(compensate_gain * info->buf[0]));
for (int i = 1; i < info->len; i++) {
pos += snprintf(s_udp_buffer + pos, sizeof(s_udp_buffer) - pos, ",%d", (int16_t)(compensate_gain * info->buf[i]));
}
#endif
pos += snprintf(s_udp_buffer + pos, sizeof(s_udp_buffer) - pos, "]\"\n");
pos += snprintf(s_udp_buffer + pos, sizeof(s_udp_buffer) - pos, "]\"\n");
} else {
/* Compact feature payload */
pos += snprintf(s_udp_buffer + pos, sizeof(s_udp_buffer) - pos,
",%d,%d,\"F:%.1f,%.1f,%.1f,%u,%lu\"\n",
info->len, info->first_word_invalid,
features.amp_rms, features.amp_std, features.amp_max,
(unsigned)features.amp_max_idx, (unsigned long)features.energy);
}
/* Send via UDP */
if (s_udp_socket >= 0) {
sendto(s_udp_socket, s_udp_buffer, pos, 0, (struct sockaddr *)&s_dest_addr, sizeof(s_dest_addr));
}
/* Compute CSI energy for adaptive sampling */
/* Adaptive sampling: reuse extracted energy (features always computed when adaptive is on) */
if (s_adaptive) {
uint32_t energy = 0;
for (int i = 0; i < info->len; i++) {
energy += abs(info->buf[i]);
}
s_energy_buf[s_energy_idx % WANDER_WINDOW] = energy;
s_energy_buf[s_energy_idx % WANDER_WINDOW] = features.energy;
s_energy_idx++;
}
@@ -723,6 +824,19 @@ typedef struct {
uint16_t seq_ctrl;
} __attribute__((packed)) wifi_ieee80211_mac_hdr_t;
/* Deauth flood detection */
#define FLOOD_WINDOW_DEFAULT 10
#define FLOOD_THRESH_DEFAULT 5
#define FLOOD_RING_SIZE 64
static int s_flood_thresh = FLOOD_THRESH_DEFAULT;
static int s_flood_window_s = FLOOD_WINDOW_DEFAULT;
static bool s_flood_active = false;
static int64_t s_flood_alert_ts = 0;
static struct { int64_t ts; } s_deauth_ring[FLOOD_RING_SIZE];
static int s_deauth_ring_head = 0;
static int s_deauth_ring_count = 0;
/* Probe request deduplication: report each MAC at most once per N seconds */
#define PROBE_DEDUP_SIZE 32
#define PROBE_DEDUP_DEFAULT_US 10000000LL
@@ -759,6 +873,28 @@ static bool probe_dedup_check(const uint8_t *mac)
return false;
}
static int deauth_flood_check(void)
{
int64_t now = esp_timer_get_time();
int64_t window_us = (int64_t)s_flood_window_s * 1000000LL;
/* Record this event */
s_deauth_ring[s_deauth_ring_head].ts = now;
s_deauth_ring_head = (s_deauth_ring_head + 1) % FLOOD_RING_SIZE;
if (s_deauth_ring_count < FLOOD_RING_SIZE) {
s_deauth_ring_count++;
}
/* Count events within window */
int count = 0;
for (int i = 0; i < s_deauth_ring_count; i++) {
if (now - s_deauth_ring[i].ts <= window_us) {
count++;
}
}
return count;
}
static void wifi_promiscuous_cb(void *buf, wifi_promiscuous_pkt_type_t type)
{
if (type != WIFI_PKT_MGMT) return;
@@ -772,31 +908,56 @@ static void wifi_promiscuous_cb(void *buf, wifi_promiscuous_pkt_type_t type)
if (subtype == 0x0C || subtype == 0x0A) {
const char *type_str = (subtype == 0x0C) ? "deauth" : "disassoc";
char alert[160];
int len = snprintf(alert, sizeof(alert),
"ALERT_DATA,%s,%s,"
"%02x:%02x:%02x:%02x:%02x:%02x,"
"%02x:%02x:%02x:%02x:%02x:%02x,"
"%d\n",
s_hostname, type_str,
hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
pkt->rx_ctrl.rssi);
int flood_count = deauth_flood_check();
char alert[192];
int len;
if (s_udp_socket >= 0) {
sendto(s_udp_socket, alert, len, 0,
(struct sockaddr *)&s_dest_addr, sizeof(s_dest_addr));
if (flood_count >= s_flood_thresh) {
/* Flood detected — send aggregate alert, suppress individual */
int64_t now = esp_timer_get_time();
if (!s_flood_active || (now - s_flood_alert_ts > 5000000LL)) {
/* Send flood alert at most every 5 seconds */
s_flood_active = true;
s_flood_alert_ts = now;
len = snprintf(alert, sizeof(alert),
"ALERT_DATA,%s,deauth_flood,%d,%d\n",
s_hostname, flood_count, s_flood_window_s);
if (s_udp_socket >= 0) {
sendto(s_udp_socket, alert, len, 0,
(struct sockaddr *)&s_dest_addr, sizeof(s_dest_addr));
}
ESP_LOGW(TAG, "ALERT: deauth_flood count=%d window=%ds", flood_count, s_flood_window_s);
}
} else {
/* Below threshold — send individual alert */
if (s_flood_active) {
s_flood_active = false;
}
len = snprintf(alert, sizeof(alert),
"ALERT_DATA,%s,%s,"
"%02x:%02x:%02x:%02x:%02x:%02x,"
"%02x:%02x:%02x:%02x:%02x:%02x,"
"%d\n",
s_hostname, type_str,
hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
pkt->rx_ctrl.rssi);
if (s_udp_socket >= 0) {
sendto(s_udp_socket, alert, len, 0,
(struct sockaddr *)&s_dest_addr, sizeof(s_dest_addr));
}
ESP_LOGW(TAG, "ALERT: %s from " MACSTR " -> " MACSTR " rssi=%d",
type_str,
hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
pkt->rx_ctrl.rssi);
}
ESP_LOGW(TAG, "ALERT: %s from " MACSTR " -> " MACSTR " rssi=%d",
type_str,
hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
pkt->rx_ctrl.rssi);
return;
}
@@ -845,6 +1006,63 @@ static void wifi_promiscuous_init(void)
ESP_LOGI(TAG, "Promiscuous mode: deauth/disassoc/probe detection enabled");
}
/* --- HMAC command authentication --- */
/**
* Verify HMAC-signed command. Format: "HMAC:<16hex>:<cmd>"
* Returns pointer to actual command on success, or NULL on failure
* (with error message written to reply).
*/
static const char *auth_verify(const char *input, char *reply, size_t reply_size)
{
/* No secret configured — accept everything */
if (s_auth_secret[0] == '\0') {
return input;
}
/* Check for HMAC: prefix */
if (strncmp(input, "HMAC:", 5) != 0) {
snprintf(reply, reply_size, "ERR AUTH required");
return NULL;
}
/* Find second colon after 16 hex chars */
if (strlen(input) < 5 + 16 + 1) {
snprintf(reply, reply_size, "ERR AUTH malformed");
return NULL;
}
if (input[5 + 16] != ':') {
snprintf(reply, reply_size, "ERR AUTH malformed");
return NULL;
}
const char *cmd = input + 5 + 16 + 1;
/* Compute HMAC-SHA256 of the command */
uint8_t hmac[32];
mbedtls_md_context_t ctx;
mbedtls_md_init(&ctx);
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
mbedtls_md_setup(&ctx, md_info, 1);
mbedtls_md_hmac_starts(&ctx, (const uint8_t *)s_auth_secret, strlen(s_auth_secret));
mbedtls_md_hmac_update(&ctx, (const uint8_t *)cmd, strlen(cmd));
mbedtls_md_hmac_finish(&ctx, hmac);
mbedtls_md_free(&ctx);
/* Format first 8 bytes as 16 hex chars */
char expected[17];
for (int i = 0; i < 8; i++) {
snprintf(expected + i * 2, 3, "%02x", hmac[i]);
}
if (strncmp(input + 5, expected, 16) != 0) {
snprintf(reply, reply_size, "ERR AUTH failed");
return NULL;
}
return cmd;
}
/* --- Command handler --- */
static void reboot_after_delay(void *arg)
@@ -906,17 +1124,24 @@ static int cmd_handle(const char *cmd, char *reply, size_t reply_size)
snprintf(uptime_str, sizeof(uptime_str), "%dm", mins);
}
const char *csi_mode_str = (s_csi_mode == CSI_MODE_COMPACT) ? "compact" :
(s_csi_mode == CSI_MODE_HYBRID) ? "hybrid" : "raw";
snprintf(reply, reply_size,
"OK STATUS uptime=%s uptime_s=%lld heap=%lu rssi=%d channel=%d tx_power=%d rate=%d csi_rate=%d"
" hostname=%s version=%s adaptive=%s motion=%d ble=%s target=%s:%d"
" temp=%.1f csi_count=%lu boots=%lu rssi_min=%d rssi_max=%d",
" temp=%.1f csi_count=%lu boots=%lu rssi_min=%d rssi_max=%d"
" csi_mode=%s hybrid_n=%d auth=%s flood_thresh=%d/%d",
uptime_str, (long long)up, (unsigned long)heap, rssi, channel, (int)s_tx_power_dbm,
s_send_frequency, actual_rate,
s_hostname, app_desc->version,
s_adaptive ? "on" : "off", s_motion_detected ? 1 : 0,
s_ble_enabled ? "on" : "off", s_target_ip, s_target_port,
chip_temp, (unsigned long)s_csi_count, (unsigned long)s_boot_count,
(int)s_rssi_min, (int)s_rssi_max);
(int)s_rssi_min, (int)s_rssi_max,
csi_mode_str, s_hybrid_interval,
s_auth_secret[0] ? "on" : "off",
s_flood_thresh, s_flood_window_s);
return strlen(reply);
}
@@ -1084,6 +1309,47 @@ static int cmd_handle(const char *cmd, char *reply, size_t reply_size)
return strlen(reply);
}
/* CSIMODE [RAW|COMPACT|HYBRID N] */
if (strcmp(cmd, "CSIMODE") == 0) {
const char *mode_str = (s_csi_mode == CSI_MODE_COMPACT) ? "COMPACT" :
(s_csi_mode == CSI_MODE_HYBRID) ? "HYBRID" : "RAW";
if (s_csi_mode == CSI_MODE_HYBRID) {
snprintf(reply, reply_size, "OK CSIMODE %s %d", mode_str, s_hybrid_interval);
} else {
snprintf(reply, reply_size, "OK CSIMODE %s", mode_str);
}
return strlen(reply);
}
if (strncmp(cmd, "CSIMODE ", 8) == 0) {
const char *arg = cmd + 8;
if (strncmp(arg, "RAW", 3) == 0) {
s_csi_mode = CSI_MODE_RAW;
config_save_i8("csi_mode", (int8_t)CSI_MODE_RAW);
snprintf(reply, reply_size, "OK CSIMODE RAW");
} else if (strncmp(arg, "COMPACT", 7) == 0) {
s_csi_mode = CSI_MODE_COMPACT;
config_save_i8("csi_mode", (int8_t)CSI_MODE_COMPACT);
snprintf(reply, reply_size, "OK CSIMODE COMPACT");
} else if (strncmp(arg, "HYBRID", 6) == 0) {
int n = 10;
if (arg[6] == ' ') {
n = atoi(arg + 7);
}
if (n < 1 || n > 100) {
snprintf(reply, reply_size, "ERR CSIMODE HYBRID N range 1-100");
return strlen(reply);
}
s_csi_mode = CSI_MODE_HYBRID;
s_hybrid_interval = n;
config_save_i8("csi_mode", (int8_t)CSI_MODE_HYBRID);
config_save_i32("hybrid_n", (int32_t)n);
snprintf(reply, reply_size, "OK CSIMODE HYBRID %d", n);
} else {
snprintf(reply, reply_size, "ERR CSIMODE RAW|COMPACT|HYBRID [N]");
}
return strlen(reply);
}
/* PROFILE */
if (strcmp(cmd, "PROFILE") == 0) {
int pos = 0;
@@ -1133,6 +1399,54 @@ static int cmd_handle(const char *cmd, char *reply, size_t reply_size)
return pos;
}
/* FLOODTHRESH [count [window_s]] */
if (strcmp(cmd, "FLOODTHRESH") == 0) {
snprintf(reply, reply_size, "OK FLOODTHRESH %d/%ds", s_flood_thresh, s_flood_window_s);
return strlen(reply);
}
if (strncmp(cmd, "FLOODTHRESH ", 12) == 0) {
int count = 0, window = s_flood_window_s;
if (sscanf(cmd + 12, "%d %d", &count, &window) < 1 || count < 1 || count > 100) {
snprintf(reply, reply_size, "ERR FLOODTHRESH <1-100> [window_s 1-300]");
return strlen(reply);
}
if (window < 1 || window > 300) {
snprintf(reply, reply_size, "ERR FLOODTHRESH window range 1-300");
return strlen(reply);
}
s_flood_thresh = count;
s_flood_window_s = window;
config_save_i32("flood_thresh", (int32_t)count);
config_save_i32("flood_window", (int32_t)window);
snprintf(reply, reply_size, "OK FLOODTHRESH %d/%ds", s_flood_thresh, s_flood_window_s);
return strlen(reply);
}
/* AUTH [secret|OFF] */
if (strcmp(cmd, "AUTH") == 0) {
snprintf(reply, reply_size, "OK AUTH %s", s_auth_secret[0] ? "on" : "off");
return strlen(reply);
}
if (strncmp(cmd, "AUTH ", 5) == 0) {
const char *arg = cmd + 5;
if (strcmp(arg, "OFF") == 0) {
s_auth_secret[0] = '\0';
config_save_str("auth_secret", "");
snprintf(reply, reply_size, "OK AUTH off");
} else {
size_t alen = strlen(arg);
if (alen < 8 || alen > 64) {
snprintf(reply, reply_size, "ERR AUTH secret length 8-64");
return strlen(reply);
}
strncpy(s_auth_secret, arg, sizeof(s_auth_secret) - 1);
s_auth_secret[sizeof(s_auth_secret) - 1] = '\0';
config_save_str("auth_secret", s_auth_secret);
snprintf(reply, reply_size, "OK AUTH on");
}
return strlen(reply);
}
/* OTA <url> */
if (strncmp(cmd, "OTA ", 4) == 0) {
const char *url = cmd + 4;
@@ -1183,7 +1497,7 @@ static void cmd_task(void *arg)
ESP_LOGI(TAG, "Command listener on UDP port %d", CONFIG_CSI_CMD_PORT);
char rx_buf[128];
char rx_buf[192];
char reply_buf[1400];
struct sockaddr_in src_addr;
socklen_t src_len;
@@ -1206,7 +1520,13 @@ static void cmd_task(void *arg)
ESP_LOGI(TAG, "CMD rx: \"%s\"", rx_buf);
int reply_len = cmd_handle(rx_buf, reply_buf, sizeof(reply_buf));
const char *verified = auth_verify(rx_buf, reply_buf, sizeof(reply_buf));
int reply_len;
if (verified) {
reply_len = cmd_handle(verified, reply_buf, sizeof(reply_buf));
} else {
reply_len = strlen(reply_buf);
}
sendto(sock, reply_buf, reply_len, 0,
(struct sockaddr *)&src_addr, src_len);