simple_sniffer: can store packets in memory

This commit is contained in:
bizhuangyang 2021-05-13 15:59:03 +08:00 committed by Ondrej Kosta
parent f04f078825
commit d6d0c37b30
12 changed files with 714 additions and 188 deletions

View File

@ -2,7 +2,7 @@
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/advanced/components)
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/examples/common_components/pcap")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(simple_sniffer)

View File

@ -5,6 +5,6 @@
PROJECT_NAME := simple_sniffer
EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/system/console/advanced/components
EXTRA_COMPONENT_DIRS += $(IDF_PATH)/examples/common_components/pcap
include $(IDF_PATH)/make/project.mk

View File

@ -28,7 +28,8 @@ Open the project configuration menu (`idf.py menuconfig`). Then go into `Example
- Check `Store command history in flash` if you want to save command history into flash (recommend).
- Select where to save the pcap file in `Select destination to store pcap file` menu item.
- `SD Card` means saving packets (pcap format) into the SD card you plug in. The default SD card work mode is set to SDMMC for target ESP32 and ESP32S3, but SPI is the only choice for other targets.
- `JTAG (App Trace)` means sending packets (pcap format) to host via JTAG interface. This feature depends on [app trace component](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/app_trace.html), Component config -> Application Level Tracing -> Data Destination -> Trace memory should be enabled to choose `JTAG (App Trace)` as destination.
- `Memory` means saving packets in memory and can parse packets in place.
- `JTAG (App Trace)` means sending packets (pcap format) to host via JTAG interface. This feature depends on [app trace component](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/app_trace.html), Component config -> Application Lelvel Tracing -> Data Destination -> Trace memory should be enabled to choose `JTAG (App Trace)` as destination.
- Set the mount point in your filesystem in `SD card mount point in the filesystem` menu item. This configuration only takes effect when you choose to save packets into SD card.
- Set max name length of pcap file in `Max name length of pcap file` menu item.
- Set the length of sniffer work queue in `Length of sniffer work queue` menu item.
@ -52,23 +53,20 @@ idf.py -p PORT flash monitor
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example Output
### `sniffer` Command Usage
> sniffer [-f <file>][-i <wlan|eth0|eth1|...>] [-F <mgmt|data|ctrl|misc|mpdu|ampdu>]... [-c <channel>][--stop]
> sniffer [-i <wlan|eth0|eth1|...>] [-F <mgmt|data|ctrl|misc|mpdu|ampdu|fcsfail>]... [-c <channel>] [--stop] [-n <num>]
> Capture specific packet and store in pcap format
> -f, --file=<file> name of the file storing the packets in pcap format
> -i, --interface=<wlan|eth0|eth1|...> which interface to capture packet
> -F, --filter=<mgmt|data|ctrl|misc|mpdu|ampdu> filter parameters
> -F, --filter=<mgmt|data|ctrl|misc|mpdu|ampdu|fcsfail> filter parameters
> -c, --channel=<channel> communication channel to use
> --stop stop running sniffer
> -n, --number=<num> the number of the packets to be captured
The `sniffer` command support some important options as follow:
* `-f`: Specify the name of file which will store the packets, default value is `sniffer`, and the resulting file name will be like “snifferX.pcap”, here X shows the files order.
* `-i`: Specify the interface to sniffer packets, currently support `wlan` and `eth0`
* `-c` :Specify the channel to sniffer packet at `wlan` interface
* `-i`: Specify the interface to sniff packets, currently only support `wlan` and `eth0`
* `-c`: Specify the channel to sniff packet at `wlan` interface
* `-F`: Specify the filter condition at `wlan` interface, currently only support following filter conditions, you can select any number of them
* mgmt: Management packets
* data: Data packets
@ -76,66 +74,239 @@ The `sniffer` command support some important options as follow:
* misc: Other packets
* mpdu: MPDU packets
* ampdu: AMPDU packets
* `-n`: Specify the number of packages to capture in this sniffer job. The sniffer job will stop automatically without using `sniffer --stop` command.
* `--stop`: Stop sniffer job
### Mount SD Card
### `pcap` Command Usage When the Destination is `SD Card`
> pcap -f <file> [--open] [--close] [--summary]
> Save and parse pcap file
> -f, --file=<file> name of the file storing the packets in pcap format
> --open open .pcap file
> --close close .pcap file
> --summary option to parse and show the summary of .pcap file
The `pcap` command support some important options as follow:
* `-f`: Specify the name of file which will store the packets or show summary, default value is `sniffer`, and the resulting file name will be like “snifferX.pcap”, here X shows the files order.
* `--open`: Option to open a '.pcap' file
* `--close`: Option to close the '.pcap' file
* `--summary`: Show the summary of '.pcap' file
### `pcap` Command Usage When the Destination is `Memory`
> pcap -f <file> [--open] [--close] [--summary]
> Save and parse pcap file
> -f, --file=<file> name of the file storing the packets in pcap format
> --open open .pcap file
> --close close .pcap file
> --summary option to parse and show the summary of .pcap file
The `pcap` command support some important options as follow:
* `-f`: Specify the file name to storage packet or show summary
* `--open`: Option to open a '.pcap' file
* `--close`: Option to close the '.pcap' file
* `--summary`: Show the summary of '.pcap' file (needs to be called prior file closing)
### `pcap` Command Usage When the Destination is `JTAG`
pcap command is not used when destination is JTAG. The pcap session is started automatically with the Sniffer start.
## Example Output
### Steps for using **SD Card** to storage packages and watch summary
#### Mount SD Card
```bash
=======================================================
| Steps to sniffer WiFi packets |
| Steps to sniff network packets |
| |
| 1. Enter 'help' to check all commands usage |
| 2. Enter 'mount <device>' to mount filesystem |
| 3. Enter 'sniffer' to start capture packets |
| 4. Enter 'unmount <device>' to unmount filesystem |
| 3. Enter 'pcap' to create pcap file |
| 4. Enter 'sniffer' to start capture packets |
| 5. Enter 'unmount <device>' to unmount filesystem |
| |
=======================================================
Type 'help' to get the list of commands.
Use UP/DOWN arrows to navigate through command history.
Press TAB when typing command name to auto-complete.
sniffer> mount sd
I (158912) example: Initializing SD card
I (158912) example: Using SDMMC peripheral
I (158912) gpio: GPIO[13]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
Name: SA16G
I (12653) example: Initializing SD card
I (12653) example: Using SDMMC peripheral
I (12663) gpio: GPIO[13]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
Name: SC64G
Type: SDHC/SDXC
Speed: 20 MHz
Size: 14832MB
Size: 60906MB
```
### Start Sniffer
#### Create .pcap file
```bash
sniffer> sniffer -f sniffer-example -i wlan -c 2
I (8946) cmd_sniffer: open file successfully
W (8966) phy_init: failed to load RF calibration data (0x1102), falling back to full calibration
I (9176) phy: phy_version: 4100, 6fa5e27, Jan 25 2019, 17:02:06, 0, 2
I (9186) wifi: ic_enable_sniffer
I (9196) cmd_sniffer: start WiFi promiscuous ok
sniffer> sniffer --stop
I (31456) wifi: ic_disable_sniffer
I (31456) wifi: flush txq
I (31456) wifi: stop sw txq
I (31456) wifi: lmac stop hw txq
I (31456) cmd_sniffer: stop WiFi promiscuous ok
sniffer> pcap --open -f simple-sniffer
I (41383) cmd_pcap: open file successfully
```
### Unmount SD Card
#### Start Sniffer (with 10 packages)
```bash
sniffer> sniffer -i wlan -c 2 -n 10
I (58153) cmd_sniffer: 10 packages will be captured
I (58163) phy_init: phy_version 4670,719f9f6,Feb 18 2021,17:07:07
I (58263) wifi:ic_enable_sniffer
I (58263) cmd_sniffer: start WiFi promiscuous ok
I (58303) wifi:ic_disable_sniffer
I (58303) wifi:flush txq
I (58303) wifi:stop sw txq
I (58303) wifi:lmac stop hw txq
I (58303) cmd_sniffer: stop promiscuous ok
```
#### Close .pcap file
```bash
sniffer> pcap --close -f simple-sniffer
I (80453) cmd_pcap: .pcap file close done
```
#### Parse '.pcap' file and watch at bash with '--summary' option
```bash
sniffer> pcap --summary -f simple-sniffer
I (112833) cmd_pcap: /sdcard/simple-sniffer.pcap is to be parsed
------------------------------------------------------------------------
Pcap packet Head:
------------------------------------------------------------------------
Magic Number: a1b2c3d4
Major Version: 2
Minor Version: 4
SnapLen: 262144
LinkType: 105
------------------------------------------------------------------------
Packet 0:
Timestamp (Seconds): 0
Timestamp (Microseconds): 3670
Capture Length: 303
Packet Length: 303
Packet Type: 0
Packet Subtype: 5
Destination: 0 0 0 0 a1 0
Source: 2 84 56 e 0 0
------------------------------------------------------------------------
Packet 1:
Timestamp (Seconds): 0
Timestamp (Microseconds): 3670
Capture Length: 294
Packet Length: 294
Packet Type: 0
Packet Subtype: 5
Destination: 0 0 0 0 a1 0
Source: 2 84 56 e 0 0
------------------------------------------------------------------------
Packet 2:
...
------------------------------------------------------------------------
Pcap packet Number: 10
------------------------------------------------------------------------
```
#### Unmount SD Card
```bash
sniffer> unmount sd
I (248800) example: Card unmounted
I (183873) example: Card unmounted
```
### Steps for sending packets to host via JTAG interface
1. Select `JTAG (App Trace)` as the destination of pcap files.
### Steps for using **memory** to storage packages and watch summary
#### Open a memory for pcap
```bash
sniffer> pcap --open -f simple-sniffer
I (11816) cmd_pcap: open file successfully
```
#### Sniff 10 packages
```bash
sniffer> sniffer -i wlan -c 2 -n 10
I (71086) cmd_sniffer: 10 packages will be captured
I (71096) phy_init: phy_version 4670,719f9f6,Feb 18 2021,17:07:07
I (71186) wifi:ic_enable_sniffer
I (71186) cmd_sniffer: start WiFi promiscuous ok
I (71246) wifi:ic_disable_sniffer
I (71246) wifi:flush txq
I (71256) wifi:stop sw txq
I (71256) wifi:lmac stop hw txq
I (71256) cmd_sniffer: stop promiscuous ok
```
#### Watch the summary of the package captured above
```bash
sniffer> pcap --summary -f simple-sniffer
I (93396) cmd_pcap: Memory is to be parsed
------------------------------------------------------------------------
Pcap packet Head:
------------------------------------------------------------------------
Magic Number: a1b2c3d4
Major Version: 2
Minor Version: 4
SnapLen: 262144
LinkType: 105
------------------------------------------------------------------------
Packet 0:
Timestamp (Seconds): 0
Timestamp (Microseconds): 5481
Capture Length: 266
Packet Length: 266
Packet Type: 0
Packet Subtype: 2
Destination: 0 0 0 0 a1 0
Source: 2 8a 69 15 0 0
------------------------------------------------------------------------
Packet 1:
Timestamp (Seconds): 0
Timestamp (Microseconds): 24405
Capture Length: 175
Packet Length: 175
Packet Type: 0
Packet Subtype: f
Destination: 0 0 0 0 a1 0
Source: 2 84 55 5f 0 0
------------------------------------------------------------------------
Packet 2:
...
------------------------------------------------------------------------
Pcap packet Number: 10
------------------------------------------------------------------------
```
#### Close pcap file in memory
```bash
sniffer> pcap --close -f simple-sniffer
I (130566) cmd_pcap: free memory successfully
I (130566) cmd_pcap: .pcap file close done
```
### Steps for sending packets to host via **JTAG interface**
1. Select `JTAG (App Trace)` as the destination of pcap files in project configuration.
2. Build & Flash with `idf.py -p PORT flash`
3. Connect JTAG, run OpenOCD (for more information about how-to please refer to [JTAG Debugging](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/index.html)).
4. Telnet to localhost with 4444 port: `telnet localhost 4444`.
5. In the telnet session, run command like `esp32 apptrace start file://sniffer-esp32.pcap 1 -1 20` (more information about this command, please refer to [apptrace command](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/app_trace.html#openocd-application-level-tracing-commands)).
6. Run the example, start sniffer with command `sniffer` (you don't need to specify the filename, because it has been set in step5).
6. Run the example, start sniffer with `sniffer` command.
7. Stop sniffer by entering command `sniffer --stop` in the example console.
8. Stop tracing by entering command `esp32 apptrace stop` in the telnet session.
### Open PCap File in Wireshark
![sniffer-example0.pcap](sniffer-esp32-pcap.png)

View File

@ -0,0 +1,50 @@
from __future__ import unicode_literals
import re
from typing import Any
import ttfw_idf
@ttfw_idf.idf_example_test(env_tag='Example_WIFI_Protocols')
def test_examples_simple_sniffer(env, _): # type: (Any, Any) -> None
dut = env.get_dut('simple_sniffer', 'examples/network/simple_sniffer', app_config_name='mem')
dut.start_app()
dut.expect('sniffer>')
dut.write('pcap --open -f simple-sniffer')
dut.expect('cmd_pcap: open file successfully')
dut.write('sniffer -i wlan -c 2 -n 10')
dut.expect('cmd_sniffer: 10 packages will be captured')
dut.expect('cmd_sniffer: start WiFi promiscuous ok')
dut.expect('cmd_sniffer: stop promiscuous ok')
dut.write('pcap --summary -f simple-sniffer')
dut.expect('cmd_pcap: Memory is to be parsed')
dut.expect('Pcap packet Head:')
dut.expect('Magic Number: a1b2c3d4')
dut.expect(re.compile(r'Major Version: [0-9]*'))
dut.expect(re.compile(r'Minor Version: [0-9]*'))
dut.expect(re.compile(r'SnapLen: [0-9]*'))
dut.expect(re.compile(r'LinkType: [0-9]*'))
for i in range(0, 10):
dut.expect('Packet ' + str(i) + ':')
dut.expect(re.compile(r'Timestamp \(Seconds\): [0-9]*'))
dut.expect(re.compile(r'Timestamp \(Microseconds\): [0-9]*'))
dut.expect(re.compile(r'Capture Length: [0-9]*'))
dut.expect(re.compile(r'Packet Length: [0-9]*'))
dut.expect(re.compile(r'Packet Type: .*'))
dut.expect(re.compile(r'Packet Subtype: .*'))
dut.expect(re.compile(r'Destination: .*'))
dut.expect(re.compile(r'Source: .*'))
dut.expect('Pcap packet Number: 10')
dut.write('pcap --close -f simple-sniffer')
dut.expect('cmd_pcap: free memory successfully')
dut.expect('cmd_pcap: .pcap file close done')
dut.write('')
dut.expect('sniffer>')
if __name__ == '__main__':
test_examples_simple_sniffer()

View File

@ -1,3 +1,4 @@
idf_component_register(SRCS "simple_sniffer_example_main.c"
"cmd_sniffer.c"
"cmd_pcap.c"
INCLUDE_DIRS ".")

View File

@ -22,6 +22,10 @@ menu "Example Configuration"
depends on APPTRACE_DEST_TRAX
help
Store pcap file to host via JTAG interface.
config SNIFFER_PCAP_DESTINATION_MEMORY
bool "Memory"
help
Store pcap file to memory.
endchoice
if SNIFFER_PCAP_DESTINATION_SD
@ -53,6 +57,14 @@ menu "Example Configuration"
Specify maximum name length of pcap file.
endif
if SNIFFER_PCAP_DESTINATION_MEMORY
config SNIFFER_PCAP_MEMORY_SIZE
int "Memory size of the '.pcap' file in memory"
default 4096
help
Max memory size to storage packet in memory.
endif
config SNIFFER_WORK_QUEUE_LEN
int "Length of sniffer work queue"
default 128

View File

@ -0,0 +1,300 @@
/* cmd_pcap example.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <stdlib.h>
#include "argtable3/argtable3.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#ifdef CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
#include "freertos/timers.h"
#endif // CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
#include <sys/unistd.h>
#include <sys/fcntl.h>
#include "esp_log.h"
#include "esp_wifi.h"
#include "esp_console.h"
#include "esp_app_trace.h"
#include "esp_check.h"
#include "cmd_sniffer.h"
#include "cmd_pcap.h"
#include "sdkconfig.h"
static const char *CMD_PCAP_TAG = "cmd_pcap";
#define PCAP_FILE_NAME_MAX_LEN CONFIG_SNIFFER_PCAP_FILE_NAME_MAX_LEN
#define PCAP_MEMORY_BUFFER_SIZE CONFIG_SNIFFER_PCAP_MEMORY_SIZE
#define SNIFFER_PROCESS_APPTRACE_TIMEOUT_US (100)
#define SNIFFER_APPTRACE_RETRY (10)
#define TRACE_TIMER_FLUSH_INT_MS (1000)
#if CONFIG_SNIFFER_PCAP_DESTINATION_MEMORY
/**
* @brief Pcap memory buffer Type Definition
*
*/
typedef struct {
char *buffer;
uint32_t buffer_size;
} pcap_memory_buffer_t;
#endif
typedef struct {
bool is_opened;
bool is_writing;
bool link_type_set;
#if CONFIG_SNIFFER_PCAP_DESTINATION_SD
char filename[PCAP_FILE_NAME_MAX_LEN];
#endif // CONFIG_SNIFFER_PCAP_DESTINATION_SD
pcap_file_handle_t pcap_handle;
pcap_link_type_t link_type;
#if CONFIG_SNIFFER_PCAP_DESTINATION_MEMORY
pcap_memory_buffer_t pcap_buffer;
#endif // CONFIG_SNIFFER_PCAP_DESTINATION_MEMORY
#ifdef CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
TimerHandle_t trace_flush_timer; /*!< Timer handle for Trace buffer flush */
#endif // CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
} pcap_cmd_runtime_t;
static pcap_cmd_runtime_t pcap_cmd_rt = {0};
#if CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
static int trace_writefun(void *cookie, const char *buf, int len)
{
return esp_apptrace_write(ESP_APPTRACE_DEST_TRAX, buf, len, SNIFFER_PROCESS_APPTRACE_TIMEOUT_US) ==
ESP_OK ? len : -1;
}
static int trace_closefun(void *cookie)
{
return esp_apptrace_flush(ESP_APPTRACE_DEST_TRAX, ESP_APPTRACE_TMO_INFINITE) == ESP_OK ? 0 : -1;
}
void pcap_flush_apptrace_timer_cb(TimerHandle_t pxTimer)
{
esp_apptrace_flush(ESP_APPTRACE_DEST_TRAX, pdMS_TO_TICKS(10));
}
#endif // CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
static esp_err_t pcap_close(pcap_cmd_runtime_t *pcap)
{
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(pcap->is_opened, ESP_ERR_INVALID_STATE, err, CMD_PCAP_TAG, ".pcap file is already closed");
ESP_GOTO_ON_ERROR(pcap_del_session(pcap->pcap_handle) != ESP_OK, err, CMD_PCAP_TAG, "stop pcap session failed");
pcap->is_opened = false;
pcap->link_type_set = false;
pcap->pcap_handle = NULL;
#if CONFIG_SNIFFER_PCAP_DESTINATION_MEMORY
free(pcap->pcap_buffer.buffer);
pcap->pcap_buffer.buffer_size = 0;
ESP_LOGI(CMD_PCAP_TAG, "free memory successfully");
#endif
#if CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
if (pcap->trace_flush_timer != NULL) {
xTimerDelete(pcap->trace_flush_timer, pdMS_TO_TICKS(100));
pcap->trace_flush_timer = NULL;
}
#endif // CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
err:
return ret;
}
static esp_err_t pcap_open(pcap_cmd_runtime_t *pcap)
{
esp_err_t ret = ESP_OK;
/* Create file to write, binary format */
FILE *fp = NULL;
#if CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
fp = funopen("trace", NULL, trace_writefun, NULL, trace_closefun);
#elif CONFIG_SNIFFER_PCAP_DESTINATION_SD
fp = fopen(pcap->filename, "wb+");
#elif CONFIG_SNIFFER_PCAP_DESTINATION_MEMORY
pcap->pcap_buffer.buffer = calloc(PCAP_MEMORY_BUFFER_SIZE, sizeof(char));
ESP_GOTO_ON_FALSE(pcap->pcap_buffer.buffer, ESP_ERR_NO_MEM, err, CMD_PCAP_TAG, "pcap buffer calloc failed");
fp = fmemopen(pcap->pcap_buffer.buffer, PCAP_MEMORY_BUFFER_SIZE, "wb+");
#else
#error "pcap file destination hasn't specified"
#endif
ESP_GOTO_ON_FALSE(fp, ESP_FAIL, err, CMD_PCAP_TAG, "open file failed");
pcap_config_t pcap_config = {
.fp = fp,
.major_version = PCAP_DEFAULT_VERSION_MAJOR,
.minor_version = PCAP_DEFAULT_VERSION_MINOR,
.time_zone = PCAP_DEFAULT_TIME_ZONE_GMT,
};
ESP_GOTO_ON_ERROR(pcap_new_session(&pcap_config, &pcap_cmd_rt.pcap_handle), err, CMD_PCAP_TAG, "pcap init failed");
pcap->is_opened = true;
ESP_LOGI(CMD_PCAP_TAG, "open file successfully");
return ret;
err:
if (fp) {
fclose(fp);
}
return ret;
}
esp_err_t packet_capture(void *payload, uint32_t length, uint32_t seconds, uint32_t microseconds)
{
return pcap_capture_packet(pcap_cmd_rt.pcap_handle, payload, length, seconds, microseconds);
}
esp_err_t sniff_packet_start(pcap_link_type_t link_type)
{
esp_err_t ret = ESP_OK;
#if CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
uint32_t retry = 0;
/* wait until apptrace communication established or timeout */
while (!esp_apptrace_host_is_connected(ESP_APPTRACE_DEST_TRAX) && (retry < SNIFFER_APPTRACE_RETRY)) {
retry++;
ESP_LOGW(CMD_PCAP_TAG, "waiting for apptrace established");
vTaskDelay(pdMS_TO_TICKS(1000));
}
ESP_GOTO_ON_FALSE(retry < SNIFFER_APPTRACE_RETRY, ESP_ERR_TIMEOUT, err, CMD_PCAP_TAG, "waiting for apptrace established timeout");
pcap_open(&pcap_cmd_rt);
#endif //CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
ESP_GOTO_ON_FALSE(pcap_cmd_rt.is_opened, ESP_ERR_INVALID_STATE, err, CMD_PCAP_TAG, "no .pcap file stream is open");
if (pcap_cmd_rt.link_type_set) {
ESP_GOTO_ON_FALSE(link_type == pcap_cmd_rt.link_type, ESP_ERR_INVALID_STATE, err, CMD_PCAP_TAG, "link type error");
ESP_GOTO_ON_FALSE(!pcap_cmd_rt.is_writing, ESP_ERR_INVALID_STATE, err, CMD_PCAP_TAG, "still sniffing");
} else {
pcap_cmd_rt.link_type = link_type;
/* Create file to write, binary format */
#if CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
/* Ethernet Link layer traffic amount may be much less than on Wi-Fi (no link management msgs.) and trace data is sent to listener
only after filling trace buffer. Hence the trace buffer might not be filled prior listener's timeout. This condition is resolved by
flushing the trace buffer periodically. */
if (link_type == PCAP_LINK_TYPE_ETHERNET) {
int timer_id = 0xFEED;
pcap_cmd_rt.trace_flush_timer = xTimerCreate("flush_apptrace_timer",
pdMS_TO_TICKS(TRACE_TIMER_FLUSH_INT_MS),
pdTRUE, (void *) timer_id,
pcap_flush_apptrace_timer_cb);
ESP_GOTO_ON_FALSE(pcap_cmd_rt.trace_flush_timer, ESP_FAIL, err, CMD_PCAP_TAG, "pcap xTimerCreate failed");
ESP_GOTO_ON_FALSE(xTimerStart(pcap_cmd_rt.trace_flush_timer, 0), ESP_FAIL, err_timer_start, CMD_PCAP_TAG, "pcap xTimerStart failed");
}
#endif // CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
pcap_write_header(pcap_cmd_rt.pcap_handle, link_type);
pcap_cmd_rt.link_type_set = true;
}
pcap_cmd_rt.is_writing = true;
return ret;
#ifdef CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
err_timer_start:
xTimerDelete(pcap_cmd_rt.trace_flush_timer, pdMS_TO_TICKS(100));
pcap_cmd_rt.trace_flush_timer = NULL;
#endif // CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
err:
return ret;
}
esp_err_t sniff_packet_stop(void)
{
pcap_cmd_rt.is_writing = false;
#if CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
pcap_close(&pcap_cmd_rt);
#endif // CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
return ESP_OK;
}
#if !CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
static struct {
struct arg_str *file;
struct arg_lit *open;
struct arg_lit *close;
struct arg_lit *summary;
struct arg_end *end;
} pcap_args;
static int do_pcap_cmd(int argc, char **argv)
{
int ret = 0;
int nerrors = arg_parse(argc, argv, (void **)&pcap_args);
if (nerrors != 0) {
arg_print_errors(stderr, pcap_args.end, argv[0]);
return 1;
}
/* Check whether or not to close pcap file: "--close" option */
if (pcap_args.close->count) {
/* close the pcap file */
ESP_GOTO_ON_FALSE(!(pcap_cmd_rt.is_writing), ESP_FAIL, err, CMD_PCAP_TAG, "still sniffing, file will not close");
pcap_close(&pcap_cmd_rt);
ESP_LOGI(CMD_PCAP_TAG, ".pcap file close done");
return ret;
}
#if CONFIG_SNIFFER_PCAP_DESTINATION_SD
/* set pcap file name: "-f" option */
int len = snprintf(pcap_cmd_rt.filename, sizeof(pcap_cmd_rt.filename), "%s/%s.pcap", CONFIG_SNIFFER_MOUNT_POINT, pcap_args.file->sval[0]);
if (len >= sizeof(pcap_cmd_rt.filename)) {
ESP_LOGW(CMD_PCAP_TAG, "pcap file name too long, try to enlarge memory in menuconfig");
}
/* Check if needs to be parsed and shown: "--summary" option */
if (pcap_args.summary->count) {
ESP_LOGI(CMD_PCAP_TAG, "%s is to be parsed", pcap_cmd_rt.filename);
if (pcap_cmd_rt.is_opened) {
ESP_GOTO_ON_FALSE(!(pcap_cmd_rt.is_writing), ESP_FAIL, err, CMD_PCAP_TAG, "still writing");
ESP_GOTO_ON_ERROR(pcap_print_summary(pcap_cmd_rt.pcap_handle, stdout), err, CMD_PCAP_TAG, "pcap print summary failed");
} else {
FILE *fp;
fp = fopen(pcap_cmd_rt.filename, "rb");
ESP_GOTO_ON_FALSE(fp, ESP_FAIL, err, CMD_PCAP_TAG, "open file failed");
pcap_config_t pcap_config = {
.fp = fp,
.major_version = PCAP_DEFAULT_VERSION_MAJOR,
.minor_version = PCAP_DEFAULT_VERSION_MINOR,
.time_zone = PCAP_DEFAULT_TIME_ZONE_GMT,
};
ESP_GOTO_ON_ERROR(pcap_new_session(&pcap_config, &pcap_cmd_rt.pcap_handle), err, CMD_PCAP_TAG, "pcap init failed");
ESP_GOTO_ON_ERROR(pcap_print_summary(pcap_cmd_rt.pcap_handle, stdout), err, CMD_PCAP_TAG, "pcap print summary failed");
ESP_GOTO_ON_ERROR(pcap_del_session(pcap_cmd_rt.pcap_handle), err, CMD_PCAP_TAG, "stop pcap session failed");
}
}
#endif // CONFIG_SNIFFER_PCAP_DESTINATION_SD
#if CONFIG_SNIFFER_PCAP_DESTINATION_MEMORY
/* Check if needs to be parsed and shown: "--summary" option */
if (pcap_args.summary->count) {
ESP_LOGI(CMD_PCAP_TAG, "Memory is to be parsed");
ESP_GOTO_ON_ERROR(pcap_print_summary(pcap_cmd_rt.pcap_handle, stdout), err, CMD_PCAP_TAG, "pcap print summary failed");
}
#endif // CONFIG_SNIFFER_PCAP_DESTINATION_MEMORY
if (pcap_args.open->count) {
pcap_open(&pcap_cmd_rt);
}
err:
return ret;
}
#endif // CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
void register_pcap_cmd(void)
{
#if !CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
pcap_args.summary = arg_lit0(NULL, "summary", "option to parse and show the summary of .pcap file");
pcap_args.file = arg_str1("f", "file", "<file>",
"name of the file storing the packets in pcap format");
pcap_args.close = arg_lit0(NULL, "close", "close .pcap file");
pcap_args.open = arg_lit0(NULL, "open", "open .pcap file");
pcap_args.end = arg_end(1);
const esp_console_cmd_t pcap_cmd = {
.command = "pcap",
.help = "Save and parse pcap file",
.hint = NULL,
.func = &do_pcap_cmd,
.argtable = &pcap_args
};
ESP_ERROR_CHECK(esp_console_cmd_register(&pcap_cmd));
#endif // #if CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
}

View File

@ -0,0 +1,57 @@
/* cmd_pcap example — declarations of command registration functions.
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#include "pcap.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Capture a pcap package with parameters
*
* @param payload pointer of the captured data
* @param length length of captured data
* @param seconds second of capture time
* @param microseconds microsecond of capture time
* @return esp_err_t
* - ESP_OK on success
* - ESP_FAIL on error
*/
esp_err_t packet_capture(void *payload, uint32_t length, uint32_t seconds, uint32_t microseconds);
/**
* @brief Tell the pcap component to start sniff and write
*
* @param link_type link type of the captured package
* @return esp_err_t
* - ESP_OK on success
* - ESP_FAIL on error
*/
esp_err_t sniff_packet_start(pcap_link_type_t link_type);
/**
* @brief Tell the pcap component to stop sniff
*
* @return esp_err_t
* - ESP_OK on success
* - ESP_FAIL on error
*/
esp_err_t sniff_packet_stop(void);
/**
* @brief Register pcap command
*
*/
void register_pcap_cmd(void);
#ifdef __cplusplus
}
#endif

View File

@ -6,14 +6,12 @@
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <stdlib.h>
#include "argtable3/argtable3.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#ifdef CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
#include "freertos/timers.h"
#endif // CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
#include <sys/unistd.h>
#include <sys/fcntl.h>
#include "esp_log.h"
@ -21,32 +19,19 @@
#include "esp_console.h"
#include "esp_app_trace.h"
#include "cmd_sniffer.h"
#include "pcap.h"
#include "cmd_pcap.h"
#include "esp_check.h"
#include "sdkconfig.h"
#define SNIFFER_DEFAULT_FILE_NAME "esp-sniffer"
#define SNIFFER_FILE_NAME_MAX_LEN CONFIG_SNIFFER_PCAP_FILE_NAME_MAX_LEN
#define SNIFFER_DEFAULT_CHANNEL (1)
#define SNIFFER_PAYLOAD_FCS_LEN (4)
#define SNIFFER_PROCESS_PACKET_TIMEOUT_MS (100)
#define SNIFFER_PROCESS_APPTRACE_TIMEOUT_US (100)
#define SNIFFER_APPTRACE_RETRY (10)
#define SNIFFER_RX_FCS_ERR (0X41)
#define SNIFFER_MAX_ETH_INTFS (3)
#define SNIFFER_DECIMAL_NUM (10)
#define TRACE_TIMER_FLUSH_INT_MS (1000)
static const char *SNIFFER_TAG = "cmd_sniffer";
#define SNIFFER_CHECK(a, str, goto_tag, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(SNIFFER_TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
goto goto_tag; \
} \
} while (0)
typedef struct {
char *filter_name;
@ -59,13 +44,7 @@ typedef struct {
uint32_t interf_num;
uint32_t channel;
uint32_t filter;
#if CONFIG_SNIFFER_PCAP_DESTINATION_SD
char filename[SNIFFER_FILE_NAME_MAX_LEN];
#endif
#ifdef CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
TimerHandle_t trace_flush_timer; /*!< Timer handle for Trace buffer flush */
#endif // CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
pcap_handle_t pcap;
int32_t packets_to_sniff;
TaskHandle_t task;
QueueHandle_t work_queue;
SemaphoreHandle_t sem_task_over;
@ -81,6 +60,7 @@ typedef struct {
static sniffer_runtime_t snf_rt = {0};
static wlan_filter_table_t wifi_filter_hash_table[SNIFFER_WLAN_FILTER_MAX] = {0};
static esp_err_t sniffer_stop(sniffer_runtime_t *sniffer);
static uint32_t hash_func(const char *str, uint32_t max_num)
{
@ -193,41 +173,52 @@ static void sniffer_task(void *parameters)
sniffer_runtime_t *sniffer = (sniffer_runtime_t *)parameters;
while (sniffer->is_running) {
if (sniffer->packets_to_sniff == 0) {
sniffer_stop(sniffer);
break;
}
/* receive packet info from queue */
if (xQueueReceive(sniffer->work_queue, &packet_info, pdMS_TO_TICKS(SNIFFER_PROCESS_PACKET_TIMEOUT_MS)) != pdTRUE) {
continue;
}
if (pcap_capture_packet(sniffer->pcap, packet_info.payload, packet_info.length,
packet_info.seconds, packet_info.microseconds) != ESP_OK) {
if (packet_capture(packet_info.payload, packet_info.length, packet_info.seconds,
packet_info.microseconds) != ESP_OK) {
ESP_LOGW(SNIFFER_TAG, "save captured packet failed");
}
free(packet_info.payload);
if (sniffer->packets_to_sniff > 0) {
sniffer->packets_to_sniff--;
}
}
/* notify that sniffer task is over */
if (sniffer->packets_to_sniff != 0) {
xSemaphoreGive(sniffer->sem_task_over);
}
vTaskDelete(NULL);
}
static esp_err_t sniffer_stop(sniffer_runtime_t *sniffer)
{
bool eth_set_promiscuous;
esp_err_t ret = ESP_OK;
SNIFFER_CHECK(sniffer->is_running, "sniffer is already stopped", err);
ESP_GOTO_ON_FALSE(sniffer->is_running, ESP_ERR_INVALID_STATE, err, SNIFFER_TAG, "sniffer is already stopped");
switch (sniffer->interf) {
case SNIFFER_INTF_WLAN:
/* Disable wifi promiscuous mode */
SNIFFER_CHECK(esp_wifi_set_promiscuous(false) == ESP_OK, "stop wifi promiscuous failed", err);
ESP_GOTO_ON_ERROR(esp_wifi_set_promiscuous(false), err, SNIFFER_TAG, "stop wifi promiscuous failed");
break;
case SNIFFER_INTF_ETH:
/* Disable Ethernet Promiscuous Mode */
eth_set_promiscuous = false;
SNIFFER_CHECK(esp_eth_ioctl(sniffer->eth_handles[sniffer->interf_num], ETH_CMD_S_PROMISCUOUS, &eth_set_promiscuous) == ESP_OK,
"stop Ethernet promiscuous failed", err);
ESP_GOTO_ON_ERROR(esp_eth_ioctl(sniffer->eth_handles[sniffer->interf_num], ETH_CMD_S_PROMISCUOUS, &eth_set_promiscuous),
err, SNIFFER_TAG, "stop Ethernet promiscuous failed");
esp_eth_update_input_path(sniffer->eth_handles[sniffer->interf_num], NULL, NULL);
break;
default:
SNIFFER_CHECK(false, "unsupported interface", err);
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, SNIFFER_TAG, "unsupported interface");
break;
}
ESP_LOGI(SNIFFER_TAG, "stop promiscuous ok");
@ -235,11 +226,15 @@ static esp_err_t sniffer_stop(sniffer_runtime_t *sniffer)
/* stop sniffer local task */
sniffer->is_running = false;
/* wait for task over */
if (sniffer->packets_to_sniff != 0) {
xSemaphoreTake(sniffer->sem_task_over, portMAX_DELAY);
}
vSemaphoreDelete(sniffer->sem_task_over);
sniffer->sem_task_over = NULL;
/* make sure to free all resources in the left items */
UBaseType_t left_items = uxQueueMessagesWaiting(sniffer->work_queue);
sniffer_packet_info_t packet_info;
while (left_items--) {
xQueueReceive(sniffer->work_queue, &packet_info, pdMS_TO_TICKS(SNIFFER_PROCESS_PACKET_TIMEOUT_MS));
@ -248,91 +243,44 @@ static esp_err_t sniffer_stop(sniffer_runtime_t *sniffer)
vQueueDelete(sniffer->work_queue);
sniffer->work_queue = NULL;
#if CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
if (sniffer->trace_flush_timer != NULL) {
xTimerDelete(sniffer->trace_flush_timer, pdMS_TO_TICKS(100));
sniffer->trace_flush_timer = NULL;
}
#endif // CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
/* stop pcap session */
SNIFFER_CHECK(pcap_deinit(sniffer->pcap) == ESP_OK, "stop pcap session failed", err);
return ESP_OK;
sniff_packet_stop();
err:
return ESP_FAIL;
return ret;
}
#if CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
static int trace_writefun(void *cookie, const char *buf, int len)
{
return esp_apptrace_write(ESP_APPTRACE_DEST_TRAX, buf, len, SNIFFER_PROCESS_APPTRACE_TIMEOUT_US) == ESP_OK ? len : -1;
}
static int trace_closefun(void *cookie)
{
return esp_apptrace_flush(ESP_APPTRACE_DEST_TRAX, ESP_APPTRACE_TMO_INFINITE) == ESP_OK ? 0 : -1;
}
void pcap_flush_apptrace_timer_cb(TimerHandle_t pxTimer)
{
esp_apptrace_flush(ESP_APPTRACE_DEST_TRAX, pdMS_TO_TICKS(10));
}
#endif // CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
static esp_err_t sniffer_start(sniffer_runtime_t *sniffer)
{
pcap_config_t pcap_config;
esp_err_t ret = ESP_OK;
pcap_link_type_t link_type;
wifi_promiscuous_filter_t wifi_filter;
bool eth_set_promiscuous;
SNIFFER_CHECK(sniffer->is_running == false, "sniffer is already running", err);
ESP_GOTO_ON_FALSE(!(sniffer->is_running), ESP_ERR_INVALID_STATE, err, SNIFFER_TAG, "sniffer is already running");
switch (sniffer->interf) {
case SNIFFER_INTF_WLAN:
pcap_config.link_type = PCAP_LINK_TYPE_802_11;
link_type = PCAP_LINK_TYPE_802_11;
break;
case SNIFFER_INTF_ETH:
pcap_config.link_type = PCAP_LINK_TYPE_ETHERNET;
link_type = PCAP_LINK_TYPE_ETHERNET;
break;
default:
SNIFFER_CHECK(false, "unsupported interface", err);
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, SNIFFER_TAG, "unsupported interface");
break;
}
/* Create file to write, binary format */
#if CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
pcap_config.fp = funopen("trace", NULL, trace_writefun, NULL, trace_closefun);
/* Ethernet Link layer traffic amount may be much less than on Wi-Fi (no link management msgs.) and trace data is sent to listener
only after filling trace buffer. Hence the trace buffer might not be filled prior listener's timeout. This condition is resolved by
flushing the trace buffer periodically. */
if(pcap_config.link_type == PCAP_LINK_TYPE_ETHERNET) {
int timer_id = 0xFEED;
sniffer->trace_flush_timer = xTimerCreate("flush_apptrace_timer",
pdMS_TO_TICKS(TRACE_TIMER_FLUSH_INT_MS),
pdTRUE, (void *) timer_id,
pcap_flush_apptrace_timer_cb);
SNIFFER_CHECK(sniffer->trace_flush_timer, "pcap xTimerCreate failed", err);
SNIFFER_CHECK(xTimerStart(sniffer->trace_flush_timer, 0) == pdPASS, "pcap xTimerStart failed", err_timer_start);
}
#elif CONFIG_SNIFFER_PCAP_DESTINATION_SD
pcap_config.fp = fopen(sniffer->filename, "wb");
#else
#error "pcap file destination hasn't specified"
#endif
SNIFFER_CHECK(pcap_config.fp, "open file failed", err);
ESP_LOGI(SNIFFER_TAG, "open file successfully");
/* init a pcap session */
SNIFFER_CHECK(pcap_init(&pcap_config, &sniffer->pcap) == ESP_OK, "init pcap session failed", err);
ESP_GOTO_ON_ERROR(sniff_packet_start(link_type), err, SNIFFER_TAG, "init pcap session failed");
sniffer->is_running = true;
sniffer->work_queue = xQueueCreate(CONFIG_SNIFFER_WORK_QUEUE_LEN, sizeof(sniffer_packet_info_t));
SNIFFER_CHECK(sniffer->work_queue, "create work queue failed", err_queue);
ESP_GOTO_ON_FALSE(sniffer->work_queue, ESP_FAIL, err_queue, SNIFFER_TAG, "create work queue failed");
sniffer->sem_task_over = xSemaphoreCreateBinary();
SNIFFER_CHECK(sniffer->sem_task_over, "create sem failed", err_sem);
SNIFFER_CHECK(xTaskCreate(sniffer_task, "snifferT", CONFIG_SNIFFER_TASK_STACK_SIZE,
sniffer, CONFIG_SNIFFER_TASK_PRIORITY, &sniffer->task) == pdTRUE,
"create task failed", err_task);
ESP_GOTO_ON_FALSE(sniffer->sem_task_over, ESP_FAIL, err_sem, SNIFFER_TAG, "create work queue failed");
ESP_GOTO_ON_FALSE(xTaskCreate(sniffer_task, "snifferT", CONFIG_SNIFFER_TASK_STACK_SIZE,
sniffer, CONFIG_SNIFFER_TASK_PRIORITY, &sniffer->task), ESP_FAIL,
err_task, SNIFFER_TAG, "create task failed");
switch (sniffer->interf) {
case SNIFFER_INTF_WLAN:
@ -340,22 +288,22 @@ static esp_err_t sniffer_start(sniffer_runtime_t *sniffer)
wifi_filter.filter_mask = sniffer->filter;
esp_wifi_set_promiscuous_filter(&wifi_filter);
esp_wifi_set_promiscuous_rx_cb(wifi_sniffer_cb);
SNIFFER_CHECK(esp_wifi_set_promiscuous(true) == ESP_OK, "start wifi promiscuous failed", err_start);
ESP_GOTO_ON_ERROR(esp_wifi_set_promiscuous(true), err_start, SNIFFER_TAG, "create work queue failed");
esp_wifi_set_channel(sniffer->channel, WIFI_SECOND_CHAN_NONE);
ESP_LOGI(SNIFFER_TAG, "start WiFi promiscuous ok");
break;
case SNIFFER_INTF_ETH:
/* Start Ethernet Promiscuous Mode */
eth_set_promiscuous = true;
SNIFFER_CHECK(esp_eth_ioctl(sniffer->eth_handles[sniffer->interf_num], ETH_CMD_S_PROMISCUOUS, &eth_set_promiscuous) == ESP_OK,
"start Ethernet promiscuous failed", err_start);
ESP_GOTO_ON_ERROR(esp_eth_ioctl(sniffer->eth_handles[sniffer->interf_num], ETH_CMD_S_PROMISCUOUS, &eth_set_promiscuous),
err_start, SNIFFER_TAG, "start Ethernet promiscuous failed");
esp_eth_update_input_path(sniffer->eth_handles[sniffer->interf_num], eth_sniffer_cb, NULL);
ESP_LOGI(SNIFFER_TAG, "start Ethernet promiscuous ok");
break;
default:
break;
}
return ESP_OK;
return ret;
err_start:
vTaskDelete(sniffer->task);
sniffer->task = NULL;
@ -367,37 +315,31 @@ err_sem:
sniffer->work_queue = NULL;
err_queue:
sniffer->is_running = false;
pcap_deinit(sniffer->pcap);
#ifdef CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
err_timer_start:
xTimerDelete(sniffer->trace_flush_timer, pdMS_TO_TICKS(100));
sniffer->trace_flush_timer = NULL;
#endif // CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
err:
return ESP_FAIL;
return ret;
}
static struct {
struct arg_str *file;
struct arg_str *interface;
struct arg_str *filter;
struct arg_int *channel;
struct arg_lit *stop;
struct arg_int *number;
struct arg_end *end;
} sniffer_args;
esp_err_t sniffer_reg_eth_intf(esp_eth_handle_t eth_handle)
{
esp_err_t ret = ESP_OK;
int32_t i = 0;
while ((snf_rt.eth_handles[i] != NULL) && (i < SNIFFER_MAX_ETH_INTFS)) {
i++;
}
SNIFFER_CHECK(i < SNIFFER_MAX_ETH_INTFS, "maximum num. of eth interfaces registered", err);
ESP_GOTO_ON_FALSE(i < SNIFFER_MAX_ETH_INTFS, ESP_FAIL, err, SNIFFER_TAG, "maximum num. of eth interfaces registered");
snf_rt.eth_handles[i] = eth_handle;
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static int do_sniffer_cmd(int argc, char **argv)
@ -438,8 +380,7 @@ static int do_sniffer_cmd(int argc, char **argv)
ESP_LOGE(SNIFFER_TAG, "unsupported interface %s", sniffer_args.interface->sval[0]);
return 1;
}
}
else {
} else {
snf_rt.interf = SNIFFER_INTF_WLAN;
ESP_LOGW(SNIFFER_TAG, "sniffing interface set to wlan by default");
}
@ -461,30 +402,6 @@ static int do_sniffer_cmd(int argc, char **argv)
break;
}
#if CONFIG_SNIFFER_PCAP_DESTINATION_SD
/* set pcap file name: "-f" option */
int len = snprintf(snf_rt.filename, sizeof(snf_rt.filename), "%s/%s.pcap", CONFIG_SNIFFER_MOUNT_POINT, SNIFFER_DEFAULT_FILE_NAME);
if (sniffer_args.file->count) {
len = snprintf(snf_rt.filename, sizeof(snf_rt.filename), "%s/%s.pcap", CONFIG_SNIFFER_MOUNT_POINT, sniffer_args.file->sval[0]);
}
if (len >= sizeof(snf_rt.filename)) {
ESP_LOGW(SNIFFER_TAG, "pcap file name too long, try to enlarge memory in menuconfig");
}
#endif
#if CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
uint32_t retry = 0;
/* wait until apptrace communication established or timeout */
while (!esp_apptrace_host_is_connected(ESP_APPTRACE_DEST_TRAX) && (retry < SNIFFER_APPTRACE_RETRY)) {
retry++;
ESP_LOGW(SNIFFER_TAG, "waiting for apptrace established");
vTaskDelay(pdMS_TO_TICKS(1000));
}
if (retry >= SNIFFER_APPTRACE_RETRY) {
ESP_LOGE(SNIFFER_TAG, "waiting for apptrace established timeout");
return 1;
}
#endif
/* Check filter setting: "-F" option */
switch (snf_rt.interf) {
case SNIFFER_INTF_WLAN:
@ -509,16 +426,22 @@ static int do_sniffer_cmd(int argc, char **argv)
break;
}
/* Check the number of captured packages: "-n" option */
snf_rt.packets_to_sniff = -1;
if (sniffer_args.number->count) {
snf_rt.packets_to_sniff = sniffer_args.number->ival[0];
ESP_LOGI(SNIFFER_TAG, "%d packages will be captured", snf_rt.packets_to_sniff);
}
/* start sniffer */
sniffer_start(&snf_rt);
return 0;
}
void register_sniffer(void)
void register_sniffer_cmd(void)
{
sniffer_args.file = arg_str0("f", "file", "<file>",
"name of the file storing the packets in pcap format");
sniffer_args.number = arg_int0("n", "number", "<num>",
"the number of the packets to be captured");
sniffer_args.interface = arg_str0("i", "interface", "<wlan|eth0|eth1|...>",
"which interface to capture packet");
sniffer_args.filter = arg_strn("F", "filter", "<mgmt|data|ctrl|misc|mpdu|ampdu|fcsfail>", 0, 7, "filter parameters");

View File

@ -37,7 +37,7 @@ typedef enum {
SNIFFER_WLAN_FILTER_MAX
} sniffer_wlan_filter_t;
void register_sniffer(void);
void register_sniffer_cmd(void);
esp_err_t sniffer_reg_eth_intf(esp_eth_handle_t eth_handle);
#ifdef __cplusplus

View File

@ -25,8 +25,8 @@
#endif
#include "nvs_flash.h"
#include "sdmmc_cmd.h"
#include "cmd_system.h"
#include "cmd_sniffer.h"
#include "cmd_pcap.h"
#if CONFIG_ETH_USE_SPI_ETHERNET
#include "driver/spi_master.h"
#endif // CONFIG_ETH_USE_SPI_ETHERNET
@ -397,18 +397,29 @@ void app_main(void)
register_mount();
register_unmount();
#endif
register_sniffer();
register_system();
register_sniffer_cmd();
register_pcap_cmd();
#if CONFIG_SNIFFER_PCAP_DESTINATION_SD
printf("\n =======================================================\n");
printf(" | Steps to sniffer WiFi packets |\n");
printf(" | Steps to sniff network packets |\n");
printf(" | |\n");
printf(" | 1. Enter 'help' to check all commands usage |\n");
printf(" | 2. Enter 'mount <device>' to mount filesystem |\n");
printf(" | 3. Enter 'sniffer' to start capture packets |\n");
printf(" | 4. Enter 'unmount <device>' to unmount filesystem |\n");
printf(" | 3. Enter 'pcap' to create pcap file |\n");
printf(" | 4. Enter 'sniffer' to start capture packets |\n");
printf(" | 5. Enter 'unmount <device>' to unmount filesystem |\n");
printf(" | |\n");
printf(" =======================================================\n\n");
#else
printf("\n =======================================================\n");
printf(" | Steps to sniff network packets |\n");
printf(" | |\n");
printf(" | 1. Enter 'help' to check all commands' usage |\n");
printf(" | 2. Enter 'pcap' to create pcap file |\n");
printf(" | 3. Enter 'sniffer' to start capture packets |\n");
printf(" | |\n");
printf(" =======================================================\n\n");
#endif
// start console REPL
ESP_ERROR_CHECK(esp_console_start_repl(repl));

View File

@ -0,0 +1 @@
CONFIG_SNIFFER_PCAP_DESTINATION_MEMORY=y