77*/
88#include <stdlib.h>
99#include <string.h>
10+ #include <dirent.h>
1011#include "argtable3/argtable3.h"
12+ #include "esp_spiffs.h"
1113#include "freertos/FreeRTOS.h"
1214#include "freertos/queue.h"
1315#include "freertos/semphr.h"
@@ -38,6 +40,9 @@ static const char* TAG = "cmd_pcap";
3840#define TRACE_TIMER_FLUSH_INT_MS (1000)
3941#define PCAP_FLUSH_INTERVAL_PACKETS \
4042 (100) // Flush file every N packets to prevent buffer overflow
43+ // Minimum free bytes required in internal flash before starting a new capture.
44+ // Shared logic with cmd_sniffer.c — keep in sync if changed there.
45+ #define PCAP_FLASH_MIN_FREE_BYTES (51200)
4146
4247#define ANALIZER_SD_CARD "/sdcard"
4348#define ANALIZER_FLASH_FS "/internal"
@@ -100,6 +105,56 @@ static void create_pcaps_dir() {
100105 }
101106}
102107
108+ /**
109+ * @brief Remove all analizer*.pcap files from the internal SPIFFS partition.
110+ *
111+ * The analyzer accumulates one .pcap file per session and never deletes old
112+ * ones. On a 512 KB partition this quickly exhausts all available space.
113+ * We only ever need the most-recent capture, so we wipe the stale files
114+ * before opening a new session.
115+ */
116+ static void cleanup_internal_pcap_files (void ) {
117+ DIR * dir = opendir (ANALIZER_FLASH_FS );
118+ if (!dir ) {
119+ return ;
120+ }
121+ struct dirent * entry ;
122+ char filepath [280 ];
123+ while ((entry = readdir (dir )) != NULL ) {
124+ // Match any file that starts with "analizer" and ends with ".pcap"
125+ const char * name = entry -> d_name ;
126+ size_t len = strlen (name );
127+ if (len > 5 &&
128+ strncmp (name , "analizer" , 8 ) == 0 &&
129+ strcmp (name + len - 5 , ".pcap" ) == 0 ) {
130+ snprintf (filepath , sizeof (filepath ), "%s/%s" , ANALIZER_FLASH_FS , name );
131+ ESP_LOGI (TAG , "Removing stale pcap: %s" , filepath );
132+ remove (filepath );
133+ }
134+ }
135+ closedir (dir );
136+ }
137+
138+ /**
139+ * @brief Return ESP_ERR_NO_MEM if the internal partition has less than the
140+ * minimum free bytes required to start a new capture session.
141+ */
142+ static esp_err_t check_internal_free_space (void ) {
143+ size_t total = 0 , used = 0 ;
144+ esp_err_t ret = esp_spiffs_info ("internal" , & total , & used );
145+ if (ret != ESP_OK ) {
146+ // Cannot determine free space — optimistically continue
147+ return ESP_OK ;
148+ }
149+ size_t free_bytes = (used < total ) ? (total - used ) : 0 ;
150+ if (free_bytes < PCAP_FLASH_MIN_FREE_BYTES ) {
151+ ESP_LOGW (TAG , "Not enough internal space: %zu free / %zu total (need %d)" ,
152+ free_bytes , total , PCAP_FLASH_MIN_FREE_BYTES );
153+ return ESP_ERR_NO_MEM ;
154+ }
155+ return ESP_OK ;
156+ }
157+
103158void wifi_sniffer_register_summary_cb (summary_cb_t cb ) {
104159 summary_cb = cb ;
105160}
@@ -162,8 +217,16 @@ static esp_err_t pcap_open(pcap_cmd_runtime_t* pcap) {
162217 fp = fopen (pcap -> filename , "wb+" );
163218 } else if (wifi_sniffer_is_destination_internal ()) {
164219 flash_fs_mount ();
165- files_ops_incremental_name (ANALIZER_FLASH_FS , "analizer" , ".pcap" ,
166- pcap -> filename );
220+ // Remove leftover .pcap files from previous sessions to reclaim space,
221+ // then verify there is enough room before attempting to create the file.
222+ cleanup_internal_pcap_files ();
223+ esp_err_t space_ret = check_internal_free_space ();
224+ if (space_ret != ESP_OK ) {
225+ return space_ret ; // ESP_ERR_NO_MEM → triggers out_of_mem_cb correctly
226+ }
227+ // Always overwrite the same filename so we never accumulate old captures.
228+ snprintf (pcap -> filename , PCAP_FILE_NAME_MAX_LEN , "%s/analizer00.pcap" ,
229+ ANALIZER_FLASH_FS );
167230 fp = fopen (pcap -> filename , "wb+" );
168231 } else {
169232 ESP_LOGE (TAG , "pcap file destination hasn't specified" );
@@ -185,6 +248,12 @@ static esp_err_t pcap_open(pcap_cmd_runtime_t* pcap) {
185248 if (fp ) {
186249 fclose (fp );
187250 }
251+ // If the file could not be opened and we don't already have a specific error
252+ // code, promote ESP_FAIL to ESP_ERR_NO_MEM so the caller's out_of_mem_cb
253+ // fires correctly (ESP_FAIL would be silently ignored after our earlier fix).
254+ if (ret == ESP_FAIL ) {
255+ ret = ESP_ERR_NO_MEM ;
256+ }
188257 return ret ;
189258}
190259
0 commit comments