mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
sniffer: capture packets to host via JTAG
Based on app-trace component, it's able to send sniffer packets to host via JTAG interface.
This commit is contained in:
parent
a8b2e982e1
commit
ae6d19b4fb
@ -4,26 +4,32 @@
|
||||
|
||||
## Overview
|
||||
|
||||
This example demonstrates basic usage of wifi sniffer mode by saving packets into SD card with pcap format. Go to wikipedia for more information about [pcap](https://en.wikipedia.org/wiki/Pcap).
|
||||
This example demonstrates basic usage of WiFi sniffer mode by saving packets into SD card with pcap format. We can send pcap file to host via JTAG interface as well.
|
||||
|
||||
This example is based on esp-idf's console component. For more information about console you should read this [guide](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/console.html).
|
||||
For more information about pcap, please go to [wikipedia](https://en.wikipedia.org/wiki/Pcap).
|
||||
|
||||
This example is based on console component. For more information about console, please refer to [console guide](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/console.html).
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
To run this example, you should have one ESP32 dev board integrated with a SD card slot (e.g ESP32-WROVER Kit) or just connect ESP32-DevKitC to a SD card breakout board.
|
||||
To run this example, you should have one ESP32 dev board integrated with a SD card slot (e.g [ESP-WROVER-KIT](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/modules-and-boards.html#esp-wrover-kit-v4-1)) or just connect [ESP32-DevKitC](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/modules-and-boards.html#esp32-devkitc-v4) to a SD card breakout board.
|
||||
If you want to send packets to host, make sure to connect ESP32 to some kind of [JTAG adapter](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/index.html#jtag-debugging-selecting-jtag-adapter).
|
||||
|
||||
### Configure the project
|
||||
|
||||
Enter `make menuconfig` if you are using GNU Make based build system or enter `idf.py menuconfig` if you are using CMake based build system. Then go into `Example Configuration` menu.
|
||||
|
||||
- Check `Store command history in flash` if you want to save command history into flash (recommend).
|
||||
- Set the mount point in your filesystem, for example, `/sdcard` if you want to store pcap file into SD card.
|
||||
- Set the length of sniffer work queue.
|
||||
- Set the stack size of the sniffer task.
|
||||
- Set the priority of the sniffer task.
|
||||
- Set the max number of packets to store in a single pcap file. The number of packets usually will be very large, so we just truncate them into multiple files. You should set a threshold value here.
|
||||
- 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.
|
||||
- `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).
|
||||
- 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.
|
||||
- Set the stack size of the sniffer task in `Stack size of sniffer task` menu item.
|
||||
- Set the priority of the sniffer task `Length of sniffer work queue` menu item.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
@ -86,21 +92,17 @@ Size: 14832MB
|
||||
|
||||
```bash
|
||||
esp32> sniffer -f sniffer-example -i wlan -c 2
|
||||
I (36200) cmd_sniffer: Start WiFi Promicuous Mode
|
||||
I (36270) phy: phy_version: 4000, b6198fa, Sep 3 2018, 15:11:06, 0, 0
|
||||
I (36270) wifi: ic_enable_sniffer
|
||||
I (36290) pcap: Store packets to file: /sdcard/sniffer-example0.pcap
|
||||
I (103810) pcap: Close Pcap file OK
|
||||
I (103830) pcap: Store packets to file: /sdcard/sniffer-example1.pcap
|
||||
I (177300) pcap: Close Pcap file OK
|
||||
I (177320) pcap: Store packets to file: /sdcard/sniffer-example2.pcap
|
||||
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
|
||||
esp32> sniffer --stop
|
||||
I (212250) wifi: ic_disable_sniffer
|
||||
I (212250) wifi: flush txq
|
||||
I (212250) wifi: stop sw txq
|
||||
I (212260) wifi: lmac stop hw txq
|
||||
I (212340) pcap: Close Pcap file OK
|
||||
I (212340) cmd_sniffer: Sniffer Stopped
|
||||
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
|
||||
```
|
||||
|
||||
### Unmount SD Card
|
||||
@ -110,15 +112,25 @@ esp32> unmount sd
|
||||
I (248800) example: Card unmounted
|
||||
```
|
||||
|
||||
### Steps for sending packets to host via JTAG interface
|
||||
1. Select `JTAG (App Trace)` as the destination of pcap files.
|
||||
2. Build & Flash with `idf.py build flash` or `make 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).
|
||||
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-example0-pcap.png)
|
||||
![sniffer-example0.pcap](sniffer-esp32-pcap.png)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- Make sure you have pluged in your SD card and mount it into filesystem before doing sniffer work or you will get error message like “Create file /sdcard/sniffer0.pcap failed”.
|
||||
- To protect the SD card, we recommand you to execute command `unmount sd` before you plug out your SD card.
|
||||
- Make sure to run `esp32 apptrace` command before or immediately after a new sniffer task started when you try this example with JTAG. Otherwise the console will issue warning message `waiting for apptrace established` every 1 second. If the apptrace communication doesn't be established within 10 seconds (can be altered by macro `SNIFFER_APPTRACE_RETRY`), this sniffer command will failed with an error message `waiting for apptrace established timeout`.
|
||||
|
||||
|
||||
|
||||
(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.)
|
||||
(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.)
|
||||
|
@ -1,10 +1,16 @@
|
||||
/* pcap encoder.
|
||||
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.
|
||||
*/
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -15,19 +21,19 @@
|
||||
#include "esp_log.h"
|
||||
#include "pcap.h"
|
||||
|
||||
static const char *TAG = "pcap";
|
||||
#define PCAP_CHECK(a, str, ret_val, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (!(a)) \
|
||||
{ \
|
||||
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
return (ret_val); \
|
||||
} \
|
||||
static const char *PCAP_TAG = "pcap";
|
||||
#define PCAP_CHECK(a, str, goto_tag, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (!(a)) \
|
||||
{ \
|
||||
ESP_LOGE(PCAP_TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
goto goto_tag; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @brief Pcap File Header Type Definition
|
||||
* @brief Pcap File Header
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
@ -41,23 +47,29 @@ typedef struct {
|
||||
} pcap_file_header_t;
|
||||
|
||||
/**
|
||||
* @brief Pcap Packet Header Type Definition
|
||||
* @brief Pcap Packet Header
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t seconds; /*!< Number of seconds since January 1st, 1970, 00:00:00 GMT */
|
||||
uint32_t microseconds; /*!< Number of microseconds when the packet was captured(offset from seconds) */
|
||||
uint32_t capture_length; /*!< Number of bytes of captured data, not longer than packet_length */
|
||||
uint32_t microseconds; /*!< Number of microseconds when the packet was captured (offset from seconds) */
|
||||
uint32_t capture_length; /*!< Number of bytes of captured data, no longer than packet_length */
|
||||
uint32_t packet_length; /*!< Actual length of current packet */
|
||||
} pcap_packet_header_t;
|
||||
|
||||
static FILE *file = NULL;
|
||||
/**
|
||||
* @brief Pcap Runtime Handle
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
FILE *file; /*!< File handle */
|
||||
} pcap_runtime_t;
|
||||
|
||||
esp_err_t pcap_capture_packet(void *payload, uint32_t length, uint32_t seconds, uint32_t microseconds)
|
||||
esp_err_t pcap_capture_packet(pcap_handle_t handle, void *payload, uint32_t length, uint32_t seconds, uint32_t microseconds)
|
||||
{
|
||||
if (!file) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
PCAP_CHECK(handle, "pcap handle is NULL", err);
|
||||
pcap_runtime_t *pcap_rt = (pcap_runtime_t *)handle;
|
||||
PCAP_CHECK(pcap_rt->file, "pcap file is NULL", err);
|
||||
size_t real_write = 0;
|
||||
pcap_packet_header_t header = {
|
||||
.seconds = seconds,
|
||||
@ -65,33 +77,39 @@ esp_err_t pcap_capture_packet(void *payload, uint32_t length, uint32_t seconds,
|
||||
.capture_length = length,
|
||||
.packet_length = length
|
||||
};
|
||||
real_write = fwrite(&header, sizeof(header), 1, file);
|
||||
PCAP_CHECK(real_write == 1, "Write packet header error", ESP_FAIL);
|
||||
real_write = fwrite(payload, sizeof(uint8_t), length, file);
|
||||
PCAP_CHECK(real_write == length, "Write packet payload error", ESP_FAIL);
|
||||
real_write = fwrite(&header, sizeof(header), 1, pcap_rt->file);
|
||||
PCAP_CHECK(real_write == 1, "write packet header error", err);
|
||||
real_write = fwrite(payload, sizeof(uint8_t), length, pcap_rt->file);
|
||||
PCAP_CHECK(real_write == length, "write packet payload error", err);
|
||||
/* Flush content in the buffer into device */
|
||||
fflush(file);
|
||||
fflush(pcap_rt->file);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t pcap_close(void)
|
||||
esp_err_t pcap_deinit(pcap_handle_t handle)
|
||||
{
|
||||
if (!file) {
|
||||
return ESP_OK;
|
||||
}
|
||||
if (fclose(file)) {
|
||||
ESP_LOGE(TAG, "Close pcap file failed");
|
||||
file = NULL;
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGI(TAG, "Close Pcap file OK");
|
||||
file = NULL;
|
||||
PCAP_CHECK(handle, "pcap handle is NULL", err);
|
||||
pcap_runtime_t *pcap_rt = (pcap_runtime_t *)handle;
|
||||
PCAP_CHECK(pcap_rt->file, "pcap file is NULL", err);
|
||||
PCAP_CHECK(fclose(pcap_rt->file) == 0, "close pcap file failed", err);
|
||||
pcap_rt->file = NULL;
|
||||
free(pcap_rt);
|
||||
ESP_LOGD(PCAP_TAG, "pcap deinit OK");
|
||||
return ESP_OK;
|
||||
err:
|
||||
ESP_LOGW(PCAP_TAG, "pcap deinit failed");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t pcap_new(pcap_config_t *config)
|
||||
esp_err_t pcap_init(pcap_config_t *config, pcap_handle_t *handle)
|
||||
{
|
||||
file = config->fp;
|
||||
PCAP_CHECK(config, "config is NULL", err);
|
||||
PCAP_CHECK(handle, "pcap handle is NULL", err);
|
||||
pcap_runtime_t *pcap_rt = calloc(sizeof(pcap_runtime_t), 1);
|
||||
PCAP_CHECK(pcap_rt, "calloc pcap runtime failed", err);
|
||||
pcap_rt->file = config->fp;
|
||||
/* Write Pcap File header */
|
||||
pcap_file_header_t header = {
|
||||
.magic = PCAP_MAGIC_BIG_ENDIAN,
|
||||
@ -102,17 +120,19 @@ esp_err_t pcap_new(pcap_config_t *config)
|
||||
.snaplen = 0x40000,
|
||||
.link_type = config->link_type
|
||||
};
|
||||
size_t real_write = fwrite(&header, sizeof(header), 1, file);
|
||||
if (real_write != 1) {
|
||||
ESP_LOGE(TAG, "Write Pcap file header error");
|
||||
goto err_write;
|
||||
}
|
||||
size_t real_write = fwrite(&header, sizeof(header), 1, pcap_rt->file);
|
||||
PCAP_CHECK(real_write == 1, "write pcap file header failed", err_write);
|
||||
/* Flush content in the buffer into device */
|
||||
fflush(file);
|
||||
fflush(pcap_rt->file);
|
||||
*handle = (pcap_handle_t)pcap_rt;
|
||||
ESP_LOGD(PCAP_TAG, "pcap init OK");
|
||||
return ESP_OK;
|
||||
|
||||
/* Error Handling */
|
||||
err_write:
|
||||
fclose(file);
|
||||
fclose(pcap_rt->file);
|
||||
pcap_rt->file = NULL;
|
||||
free(pcap_rt);
|
||||
err:
|
||||
ESP_LOGW(PCAP_TAG, "pcap init failed");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
@ -1,10 +1,16 @@
|
||||
/* pcap encoder.
|
||||
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.
|
||||
*/
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -12,6 +18,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
#define PCAP_MAGIC_BIG_ENDIAN 0xA1B2C3D4 /*!< Big-Endian */
|
||||
#define PCAP_MAGIC_LITTLE_ENDIAN 0xD4C3B2A1 /*!< Little-Endian */
|
||||
@ -21,8 +28,6 @@ extern "C" {
|
||||
|
||||
#define PCAP_TIME_ZONE_GMT 0x00 /*!< Time Zone */
|
||||
|
||||
#define PCAP_FILE_NAME_MAX_LEN 32 /*!< Max Name Length of Pcap File */
|
||||
|
||||
/**
|
||||
* @brief Link layer Type Definition, used for Pcap reader to decode payload
|
||||
*
|
||||
@ -55,30 +60,45 @@ typedef struct {
|
||||
} pcap_config_t;
|
||||
|
||||
/**
|
||||
* @brief Create a pcap object
|
||||
* @brief Pcap Handle Type Definition
|
||||
*
|
||||
*/
|
||||
typedef void *pcap_handle_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize a pcap session
|
||||
*
|
||||
* @param config configuration of creating pcap object
|
||||
* @return esp_err_t ESP_OK on success, ESP_FAIL on IO error
|
||||
* @param handle pcap handle
|
||||
* @return esp_err_t
|
||||
* - ESP_OK on success
|
||||
* - ESP_FAIL on error
|
||||
*/
|
||||
esp_err_t pcap_new(pcap_config_t *config);
|
||||
esp_err_t pcap_init(pcap_config_t *config, pcap_handle_t *handle);
|
||||
|
||||
/**
|
||||
* @brief Close pcap file and recyle related resources
|
||||
* @brief De-initialize a pcap session
|
||||
*
|
||||
* @return esp_err_t ESP_OK on success, ESP_FAIL on error
|
||||
* @param handle pcap handle
|
||||
* @return esp_err_t
|
||||
* - ESP_OK on success
|
||||
* - ESP_FAIL on error
|
||||
*/
|
||||
esp_err_t pcap_close(void);
|
||||
esp_err_t pcap_deinit(pcap_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Capture one packet into file in pcap format
|
||||
* @brief Capture one packet into pcap file
|
||||
*
|
||||
* @param payload pointer to the captured data
|
||||
* @param handle pcap handle
|
||||
* @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 IO error
|
||||
* @return esp_err_t
|
||||
* - ESP_OK on success
|
||||
* - ESP_FAIL on error
|
||||
*/
|
||||
esp_err_t pcap_capture_packet(void *payload, uint32_t length, uint32_t seconds, uint32_t microseconds);
|
||||
esp_err_t pcap_capture_packet(pcap_handle_t handle, void *payload, uint32_t length, uint32_t seconds, uint32_t microseconds);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -1,20 +1,43 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config STORE_HISTORY
|
||||
bool "Store command history in flash"
|
||||
bool "Store command history into flash"
|
||||
default y
|
||||
help
|
||||
Linenoise line editing library provides functions to save and load
|
||||
command history. If this option is enabled, initalizes a FAT filesystem
|
||||
and uses it to store command history.
|
||||
Linenoise line editing library provides functions to save and load command history.
|
||||
If this option is enabled, initalizes a FAT filesystem and uses it to store command history.
|
||||
|
||||
config SNIFFER_MOUNT_POINT
|
||||
string "Mount Point in your filesystem to store pcap files"
|
||||
default "/sdcard"
|
||||
choice SNIFFER_PCAP_DESTINATION
|
||||
prompt "Select destination to store pcap file"
|
||||
default SNIFFER_PCAP_DESTINATION_SD
|
||||
help
|
||||
Here you need to specify the mount point in the VFS (Virtual File System) where the pcap would be saved.
|
||||
Select where to store the pcap file.
|
||||
Currently support storing files to SD card or to host via JTAG interface.
|
||||
config SNIFFER_PCAP_DESTINATION_SD
|
||||
bool "SD Card"
|
||||
help
|
||||
Store pcap file to SD card.
|
||||
config SNIFFER_PCAP_DESTINATION_JTAG
|
||||
bool "JTAG (App Trace)"
|
||||
help
|
||||
Store pcap file to host via JTAG interface.
|
||||
endchoice
|
||||
|
||||
config SNIFFER_WORK_QUEUE_LENGTH
|
||||
if SNIFFER_PCAP_DESTINATION_SD
|
||||
config SNIFFER_MOUNT_POINT
|
||||
string "SD card mount point in the filesystem"
|
||||
default "/sdcard"
|
||||
help
|
||||
Specify the mount point in the VFS (Virtual File System) for SD card.
|
||||
|
||||
config PCAP_FILE_NAME_MAX_LEN
|
||||
int "Max name length of pcap file"
|
||||
default 32
|
||||
help
|
||||
Specify maximum name length of pcap file.
|
||||
endif
|
||||
|
||||
config SNIFFER_WORK_QUEUE_LEN
|
||||
int "Length of sniffer work queue"
|
||||
default 128
|
||||
help
|
||||
@ -24,9 +47,9 @@ menu "Example Configuration"
|
||||
|
||||
config SNIFFER_TASK_STACK_SIZE
|
||||
int "Stack size of sniffer task"
|
||||
default 2560
|
||||
default 4096
|
||||
help
|
||||
The stack size of sniffer task.
|
||||
Stack size of sniffer task.
|
||||
|
||||
config SNIFFER_TASK_PRIORITY
|
||||
int "Priority of sniffer task"
|
||||
@ -34,11 +57,4 @@ menu "Example Configuration"
|
||||
help
|
||||
Priority of sniffer task.
|
||||
|
||||
config PCAP_FILE_MAX_PACKETS
|
||||
int "Max packets in a pcap file"
|
||||
default 2000
|
||||
help
|
||||
To avoid the pcap file being very large, we should save packets into multiple fiiles.
|
||||
Here you should specify the max number of packets that should be save in one pcap file.
|
||||
|
||||
endmenu
|
||||
|
@ -16,48 +16,58 @@
|
||||
#include "esp_log.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_console.h"
|
||||
#include "esp_app_trace.h"
|
||||
#include "cmd_sniffer.h"
|
||||
#include "pcap.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define SNIFFER_DEFAULT_FILE_NAME "sniffer"
|
||||
#define SNIFFER_DEFAULT_CHANNEL 1
|
||||
#define SNIFFER_DEFAULT_FILE_NAME "esp-sniffer"
|
||||
#define SNIFFER_FILE_NAME_MAX_LEN CONFIG_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)
|
||||
|
||||
static const char *TAG = "cmd_sniffer";
|
||||
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)
|
||||
|
||||
static bool sniffer_running = false;
|
||||
static pcap_config_t pcap_config;
|
||||
static QueueHandle_t sniffer_work_queue = NULL;
|
||||
static SemaphoreHandle_t sem_task_over = NULL;
|
||||
typedef struct {
|
||||
char *filter_name;
|
||||
uint32_t filter_val;
|
||||
} wlan_filter_table_t;
|
||||
|
||||
static wlan_filter_table_t wifi_filter_hash_table[SNIFFER_WLAN_FILTER_MAX] = {0};
|
||||
static char packet_filepath[PCAP_FILE_NAME_MAX_LEN];
|
||||
typedef struct {
|
||||
bool is_running;
|
||||
sniffer_intf_t interf;
|
||||
uint32_t channel;
|
||||
uint32_t filter;
|
||||
#if CONFIG_SNIFFER_PCAP_DESTINATION_SD
|
||||
char filename[SNIFFER_FILE_NAME_MAX_LEN];
|
||||
#endif
|
||||
pcap_handle_t pcap;
|
||||
TaskHandle_t task;
|
||||
QueueHandle_t work_queue;
|
||||
SemaphoreHandle_t sem_task_over;
|
||||
} sniffer_runtime_t;
|
||||
|
||||
typedef struct {
|
||||
void *payload;
|
||||
uint32_t length;
|
||||
uint32_t seconds;
|
||||
uint32_t microseconds;
|
||||
} sniffer_packet_into_t;
|
||||
} sniffer_packet_info_t;
|
||||
|
||||
static esp_err_t create_packet_file(void)
|
||||
{
|
||||
uint32_t file_no = 0;
|
||||
char filename[PCAP_FILE_NAME_MAX_LEN + 15];
|
||||
do {
|
||||
snprintf(filename, sizeof(filename), "%s%d.pcap", packet_filepath, file_no);
|
||||
file_no++;
|
||||
} while (0 == access(filename, F_OK));
|
||||
/* Create file to write, binary format */
|
||||
pcap_config.fp = fopen(filename, "wb");
|
||||
if (!pcap_config.fp) {
|
||||
ESP_LOGE(TAG, "Create file %s failed", filename);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGI(TAG, "Store packets to file: %s", filename);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
static sniffer_runtime_t snf_rt = {0};
|
||||
static wlan_filter_table_t wifi_filter_hash_table[SNIFFER_WLAN_FILTER_MAX] = {0};
|
||||
|
||||
static uint32_t hash_func(const char *str, uint32_t max_num)
|
||||
{
|
||||
@ -73,10 +83,10 @@ static uint32_t hash_func(const char *str, uint32_t max_num)
|
||||
static void create_wifi_filter_hashtable()
|
||||
{
|
||||
char *wifi_filter_keys[SNIFFER_WLAN_FILTER_MAX] = {"mgmt", "data", "ctrl", "misc", "mpdu", "ampdu"};
|
||||
uint32_t wifi_filter_values[SNIFFER_WLAN_FILTER_MAX] = {WIFI_PROMIS_FILTER_MASK_MGMT, WIFI_PROMIS_FILTER_MASK_DATA,
|
||||
WIFI_PROMIS_FILTER_MASK_CTRL, WIFI_PROMIS_FILTER_MASK_MISC,
|
||||
WIFI_PROMIS_FILTER_MASK_DATA_MPDU, WIFI_PROMIS_FILTER_MASK_DATA_AMPDU
|
||||
};
|
||||
uint32_t wifi_filter_values[SNIFFER_WLAN_FILTER_MAX] = {WIFI_PROMIS_FILTER_MASK_MGMT, WIFI_PROMIS_FILTER_MASK_DATA,
|
||||
WIFI_PROMIS_FILTER_MASK_CTRL, WIFI_PROMIS_FILTER_MASK_MISC,
|
||||
WIFI_PROMIS_FILTER_MASK_DATA_MPDU, WIFI_PROMIS_FILTER_MASK_DATA_AMPDU
|
||||
};
|
||||
for (int i = 0; i < SNIFFER_WLAN_FILTER_MAX; i++) {
|
||||
uint32_t idx = hash_func(wifi_filter_keys[i], SNIFFER_WLAN_FILTER_MAX);
|
||||
while (wifi_filter_hash_table[idx].filter_name) {
|
||||
@ -110,123 +120,166 @@ static uint32_t search_wifi_filter_hashtable(const char *key)
|
||||
|
||||
static void wifi_sniffer_cb(void *recv_buf, wifi_promiscuous_pkt_type_t type)
|
||||
{
|
||||
if (sniffer_running) {
|
||||
sniffer_packet_into_t packet_info;
|
||||
wifi_promiscuous_pkt_t *sniffer = (wifi_promiscuous_pkt_t *)recv_buf;
|
||||
/* prepare packet_info */
|
||||
packet_info.seconds = sniffer->rx_ctrl.timestamp / 1000000U;
|
||||
packet_info.microseconds = sniffer->rx_ctrl.timestamp % 1000000U;
|
||||
packet_info.length = sniffer->rx_ctrl.sig_len;
|
||||
wifi_promiscuous_pkt_t *backup = malloc(sniffer->rx_ctrl.sig_len);
|
||||
sniffer_packet_info_t packet_info;
|
||||
wifi_promiscuous_pkt_t *sniffer = (wifi_promiscuous_pkt_t *)recv_buf;
|
||||
/* prepare packet_info */
|
||||
packet_info.seconds = sniffer->rx_ctrl.timestamp / 1000000U;
|
||||
packet_info.microseconds = sniffer->rx_ctrl.timestamp % 1000000U;
|
||||
packet_info.length = sniffer->rx_ctrl.sig_len;
|
||||
/* For now, the sniffer only dumps the length of the MISC type frame */
|
||||
if (type != WIFI_PKT_MISC && !sniffer->rx_ctrl.rx_state) {
|
||||
packet_info.length -= SNIFFER_PAYLOAD_FCS_LEN;
|
||||
void *backup = malloc(packet_info.length);
|
||||
if (backup) {
|
||||
memcpy(backup, sniffer->payload, sniffer->rx_ctrl.sig_len);
|
||||
memcpy(backup, sniffer->payload, packet_info.length);
|
||||
packet_info.payload = backup;
|
||||
if (sniffer_work_queue) {
|
||||
if (snf_rt.work_queue) {
|
||||
/* send packet_info */
|
||||
if (xQueueSend(sniffer_work_queue, &packet_info, 100 / portTICK_PERIOD_MS) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "sniffer work queue full");
|
||||
if (xQueueSend(snf_rt.work_queue, &packet_info, pdMS_TO_TICKS(SNIFFER_PROCESS_PACKET_TIMEOUT_MS)) != pdTRUE) {
|
||||
ESP_LOGE(SNIFFER_TAG, "sniffer work queue full");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "No enough memory for promiscuous packet");
|
||||
ESP_LOGE(SNIFFER_TAG, "No enough memory for promiscuous packet");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sniffer_task(void *parameters)
|
||||
{
|
||||
static uint32_t count = 0;
|
||||
sniffer_packet_into_t packet_info;
|
||||
BaseType_t ret = 0;
|
||||
sniffer_packet_info_t packet_info;
|
||||
sniffer_runtime_t *sniffer = (sniffer_runtime_t *)parameters;
|
||||
|
||||
while (sniffer_running) {
|
||||
while (sniffer->is_running) {
|
||||
/* receive paclet info from queue */
|
||||
ret = xQueueReceive(sniffer_work_queue, &packet_info, 100 / portTICK_PERIOD_MS);
|
||||
if (ret != pdTRUE) {
|
||||
if (xQueueReceive(sniffer->work_queue, &packet_info, pdMS_TO_TICKS(SNIFFER_PROCESS_PACKET_TIMEOUT_MS)) != pdTRUE) {
|
||||
continue;
|
||||
}
|
||||
if (pcap_capture_packet(packet_info.payload, packet_info.length,
|
||||
packet_info.seconds, packet_info.microseconds) == ESP_OK) {
|
||||
count++;
|
||||
/* truncate, create another file */
|
||||
if (count >= CONFIG_PCAP_FILE_MAX_PACKETS) {
|
||||
pcap_close();
|
||||
if (create_packet_file() != ESP_OK || pcap_new(&pcap_config) != ESP_OK) {
|
||||
sniffer_running = false;
|
||||
} else {
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
if (pcap_capture_packet(sniffer->pcap, 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);
|
||||
}
|
||||
/* notify that sniffer task is over */
|
||||
xSemaphoreGive(sem_task_over);
|
||||
xSemaphoreGive(sniffer->sem_task_over);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static esp_err_t snifer_stop(sniffer_config_t *sniffer)
|
||||
static esp_err_t sniffer_stop(sniffer_runtime_t *sniffer)
|
||||
{
|
||||
/* Do interface specific work here */
|
||||
SNIFFER_CHECK(sniffer->is_running, "sniffer is already stopped", err);
|
||||
|
||||
switch (sniffer->interf) {
|
||||
case SNIFFER_INTF_WLAN:
|
||||
/* Disable wifi promiscuous mode */
|
||||
esp_wifi_set_promiscuous(false);
|
||||
SNIFFER_CHECK(esp_wifi_set_promiscuous(false) == ESP_OK, "stop wifi promiscuous failed", err);
|
||||
break;
|
||||
default:
|
||||
SNIFFER_CHECK(false, "unsupported interface", err);
|
||||
break;
|
||||
}
|
||||
ESP_LOGI(SNIFFER_TAG, "stop WiFi promiscuous ok");
|
||||
|
||||
/* stop sniffer local task */
|
||||
sniffer_running = false;
|
||||
sniffer->is_running = false;
|
||||
/* wait for task over */
|
||||
xSemaphoreTake(sem_task_over, portMAX_DELAY);
|
||||
vSemaphoreDelete(sem_task_over);
|
||||
sem_task_over = NULL;
|
||||
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_into_t packet_info;
|
||||
UBaseType_t left_items = uxQueueMessagesWaiting(sniffer->work_queue);
|
||||
sniffer_packet_info_t packet_info;
|
||||
while (left_items--) {
|
||||
xQueueReceive(sniffer_work_queue, &packet_info, 100 / portTICK_PERIOD_MS);
|
||||
xQueueReceive(sniffer->work_queue, &packet_info, pdMS_TO_TICKS(SNIFFER_PROCESS_PACKET_TIMEOUT_MS));
|
||||
free(packet_info.payload);
|
||||
}
|
||||
/* delete queue */
|
||||
vQueueDelete(sniffer_work_queue);
|
||||
sniffer_work_queue = NULL;
|
||||
/* Close the pcap file */
|
||||
pcap_close();
|
||||
|
||||
ESP_LOGI(TAG, "Sniffer Stopped");
|
||||
vQueueDelete(sniffer->work_queue);
|
||||
sniffer->work_queue = NULL;
|
||||
/* stop pcap session */
|
||||
SNIFFER_CHECK(pcap_deinit(sniffer->pcap) == ESP_OK, "stop pcap session failed", err);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
static esp_err_t sniffer_start(sniffer_config_t *sniffer)
|
||||
#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;
|
||||
}
|
||||
#endif
|
||||
|
||||
static esp_err_t sniffer_start(sniffer_runtime_t *sniffer)
|
||||
{
|
||||
pcap_config_t pcap_config;
|
||||
wifi_promiscuous_filter_t wifi_filter;
|
||||
/* set sniffer running status before it starts to run */
|
||||
sniffer_running = true;
|
||||
sniffer_work_queue = xQueueCreate(CONFIG_SNIFFER_WORK_QUEUE_LENGTH, sizeof(sniffer_packet_into_t));
|
||||
sem_task_over = xSemaphoreCreateBinary();
|
||||
/* sniffer task going to run*/
|
||||
xTaskCreate(sniffer_task, "sniffer", CONFIG_SNIFFER_TASK_STACK_SIZE, NULL, CONFIG_SNIFFER_TASK_PRIORITY, NULL);
|
||||
|
||||
switch (sniffer->interf) {
|
||||
case SNIFFER_INTF_WLAN:
|
||||
/* Set Promicuous Mode */
|
||||
pcap_config.link_type = PCAP_LINK_TYPE_802_11;
|
||||
break;
|
||||
default:
|
||||
SNIFFER_CHECK(false, "unsupported interface", err);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Create file to write, binary format */
|
||||
#if CONFIG_SNIFFER_PCAP_DESTINATION_JTAG
|
||||
pcap_config.fp = funopen("trace", NULL, trace_writefun, NULL, trace_closefun);
|
||||
#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);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
switch (sniffer->interf) {
|
||||
case SNIFFER_INTF_WLAN:
|
||||
/* Start WiFi Promicuous Mode */
|
||||
wifi_filter.filter_mask = sniffer->filter;
|
||||
esp_wifi_set_promiscuous_filter(&wifi_filter);
|
||||
esp_wifi_set_promiscuous_rx_cb(wifi_sniffer_cb);
|
||||
ESP_LOGI(TAG, "Start WiFi Promicuous Mode");
|
||||
ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true));
|
||||
/* Specify the channel */
|
||||
SNIFFER_CHECK(esp_wifi_set_promiscuous(true) == ESP_OK, "start wifi promiscuous failed", err_start);
|
||||
esp_wifi_set_channel(sniffer->channel, WIFI_SECOND_CHAN_NONE);
|
||||
/* Create a new pcap object */
|
||||
pcap_config.link_type = PCAP_LINK_TYPE_802_11;
|
||||
pcap_new(&pcap_config);
|
||||
ESP_LOGI(SNIFFER_TAG, "start WiFi promiscuous ok");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
err_start:
|
||||
vTaskDelete(sniffer->task);
|
||||
sniffer->task = NULL;
|
||||
err_task:
|
||||
vSemaphoreDelete(sniffer->sem_task_over);
|
||||
sniffer->sem_task_over = NULL;
|
||||
err_sem:
|
||||
vQueueDelete(sniffer->work_queue);
|
||||
sniffer->work_queue = NULL;
|
||||
err_queue:
|
||||
sniffer->is_running = false;
|
||||
pcap_deinit(sniffer->pcap);
|
||||
err:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
static struct {
|
||||
@ -240,67 +293,73 @@ static struct {
|
||||
|
||||
static int do_sniffer_cmd(int argc, char **argv)
|
||||
{
|
||||
sniffer_config_t sniffer;
|
||||
|
||||
int nerrors = arg_parse(argc, argv, (void **)&sniffer_args);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, sniffer_args.end, argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&sniffer, 0, sizeof(sniffer));
|
||||
|
||||
/* Check interface: "-i" option */
|
||||
if (sniffer_args.interface->count) {
|
||||
if (!strncmp(sniffer_args.interface->sval[0], "wlan", 4)) {
|
||||
sniffer.interf = SNIFFER_INTF_WLAN;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Do not support interface %s", sniffer_args.interface->sval[0]);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
sniffer.interf = SNIFFER_INTF_WLAN;
|
||||
}
|
||||
/* Check whether or not to stop sniffer: "--stop" option */
|
||||
if (sniffer_args.stop->count) {
|
||||
/* stop sniffer */
|
||||
snifer_stop(&sniffer);
|
||||
sniffer_stop(&snf_rt);
|
||||
return 0;
|
||||
}
|
||||
/* Check channel: "-c" option */
|
||||
sniffer.channel = 0;
|
||||
if (sniffer_args.channel->count) {
|
||||
sniffer.channel = sniffer_args.channel->ival[0];
|
||||
} else {
|
||||
sniffer.channel = SNIFFER_DEFAULT_CHANNEL;
|
||||
|
||||
/* Check interface: "-i" option */
|
||||
snf_rt.interf = SNIFFER_INTF_WLAN;
|
||||
if (sniffer_args.interface->count) {
|
||||
if (!strncmp(sniffer_args.interface->sval[0], "wlan", 4)) {
|
||||
snf_rt.interf = SNIFFER_INTF_WLAN;
|
||||
} else {
|
||||
ESP_LOGE(SNIFFER_TAG, "unsupported interface %s", sniffer_args.interface->sval[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* set pcap file name: "-f" option */
|
||||
if (sniffer_args.file->count) {
|
||||
snprintf(packet_filepath, PCAP_FILE_NAME_MAX_LEN, "%s/%s",
|
||||
CONFIG_SNIFFER_MOUNT_POINT, sniffer_args.file->sval[0]);
|
||||
} else {
|
||||
snprintf(packet_filepath, PCAP_FILE_NAME_MAX_LEN, "%s/%s",
|
||||
CONFIG_SNIFFER_MOUNT_POINT, SNIFFER_DEFAULT_FILE_NAME);
|
||||
/* Check channel: "-c" option */
|
||||
snf_rt.channel = SNIFFER_DEFAULT_CHANNEL;
|
||||
if (sniffer_args.channel->count) {
|
||||
snf_rt.channel = sniffer_args.channel->ival[0];
|
||||
}
|
||||
/* Determin file name */
|
||||
if (create_packet_file() != ESP_OK) {
|
||||
|
||||
#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 (sniffer.interf) {
|
||||
switch (snf_rt.interf) {
|
||||
case SNIFFER_INTF_WLAN:
|
||||
if (sniffer_args.filter->count) {
|
||||
for (int i = 0; i < sniffer_args.filter->count; i++) {
|
||||
sniffer.filter += search_wifi_filter_hashtable(sniffer_args.filter->sval[i]);
|
||||
snf_rt.filter += search_wifi_filter_hashtable(sniffer_args.filter->sval[i]);
|
||||
}
|
||||
/* When filter conditions are all wrong */
|
||||
if (sniffer.filter == 0) {
|
||||
sniffer.filter = WIFI_PROMIS_FILTER_MASK_ALL;
|
||||
if (snf_rt.filter == 0) {
|
||||
snf_rt.filter = WIFI_PROMIS_FILTER_MASK_ALL;
|
||||
}
|
||||
} else {
|
||||
sniffer.filter = WIFI_PROMIS_FILTER_MASK_ALL;
|
||||
snf_rt.filter = WIFI_PROMIS_FILTER_MASK_ALL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -308,7 +367,7 @@ static int do_sniffer_cmd(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* start sniffer */
|
||||
sniffer_start(&sniffer);
|
||||
sniffer_start(&snf_rt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -323,14 +382,14 @@ void register_sniffer()
|
||||
sniffer_args.channel = arg_int0("c", "channel", "<channel>", "communication channel to use");
|
||||
sniffer_args.stop = arg_lit0(NULL, "stop", "stop running sniffer");
|
||||
sniffer_args.end = arg_end(1);
|
||||
const esp_console_cmd_t iperf_cmd = {
|
||||
const esp_console_cmd_t sniffer_cmd = {
|
||||
.command = "sniffer",
|
||||
.help = "Capture specific packet and store in pcap format",
|
||||
.hint = NULL,
|
||||
.func = &do_sniffer_cmd,
|
||||
.argtable = &sniffer_args
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&iperf_cmd));
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&sniffer_cmd));
|
||||
|
||||
create_wifi_filter_hashtable();
|
||||
}
|
||||
|
@ -12,32 +12,28 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Supported Sniffer Interface
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
SNIFFER_INTF_WLAN = 0,
|
||||
SNIFFER_INTF_WLAN = 0, /*!< WLAN interface */
|
||||
} sniffer_intf_t;
|
||||
|
||||
/**
|
||||
* @brief WLAN Sniffer Filter
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
SNIFFER_WLAN_FILTER_MGMT = 0,
|
||||
SNIFFER_WLAN_FILTER_CTRL,
|
||||
SNIFFER_WLAN_FILTER_DATA,
|
||||
SNIFFER_WLAN_FILTER_MISC,
|
||||
SNIFFER_WLAN_FILTER_MPDU,
|
||||
SNIFFER_WLAN_FILTER_AMPDU,
|
||||
SNIFFER_WLAN_FILTER_MGMT = 0, /*!< MGMT */
|
||||
SNIFFER_WLAN_FILTER_CTRL, /*!< CTRL */
|
||||
SNIFFER_WLAN_FILTER_DATA, /*!< DATA */
|
||||
SNIFFER_WLAN_FILTER_MISC, /*!< MISC */
|
||||
SNIFFER_WLAN_FILTER_MPDU, /*!< MPDU */
|
||||
SNIFFER_WLAN_FILTER_AMPDU, /*!< AMPDU */
|
||||
SNIFFER_WLAN_FILTER_MAX
|
||||
} sniffer_wlan_filter_t;
|
||||
|
||||
typedef struct {
|
||||
char *filter_name;
|
||||
uint32_t filter_val;
|
||||
} wlan_filter_table_t;
|
||||
|
||||
typedef struct {
|
||||
sniffer_intf_t interf;
|
||||
uint32_t channel;
|
||||
uint32_t duration;
|
||||
uint32_t filter;
|
||||
} sniffer_config_t;
|
||||
|
||||
void register_sniffer();
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -120,6 +120,7 @@ static void initialize_console()
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_SNIFFER_PCAP_DESTINATION_SD
|
||||
static struct {
|
||||
struct arg_str *device;
|
||||
struct arg_end *end;
|
||||
@ -155,7 +156,6 @@ static int mount(int argc, char **argv)
|
||||
// initialize SD card and mount FAT filesystem.
|
||||
sdmmc_card_t *card;
|
||||
esp_err_t ret = esp_vfs_fat_sdmmc_mount(CONFIG_SNIFFER_MOUNT_POINT, &host, &slot_config, &mount_config, &card);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
if (ret == ESP_FAIL) {
|
||||
ESP_LOGE(TAG, "Failed to mount filesystem. "
|
||||
@ -194,7 +194,7 @@ static int unmount(int argc, char **argv)
|
||||
arg_print_errors(stderr, mount_args.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
/* mount sd card */
|
||||
/* unmount sd card */
|
||||
if (!strncmp(mount_args.device->sval[0], "sd", 2)) {
|
||||
if (esp_vfs_fat_sdmmc_unmount() != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Card unmount failed");
|
||||
@ -218,6 +218,7 @@ static void register_unmount()
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
|
||||
}
|
||||
#endif // CONFIG_SNIFFER_PCAP_DESTINATION_SD
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
@ -234,8 +235,10 @@ void app_main(void)
|
||||
|
||||
/* Register commands */
|
||||
esp_console_register_help_command();
|
||||
#if CONFIG_SNIFFER_PCAP_DESTINATION_SD
|
||||
register_mount();
|
||||
register_unmount();
|
||||
#endif
|
||||
register_sniffer();
|
||||
register_system();
|
||||
|
||||
|
@ -20,3 +20,7 @@ CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_FATFS_LFN_HEAP=y
|
||||
CONFIG_FATFS_MAX_LFN=31
|
||||
|
||||
# App trace
|
||||
CONFIG_ESP32_APPTRACE_DEST_TRAX=y
|
||||
CONFIG_ESP32_APPTRACE_ENABLE=y
|
||||
|
||||
|
BIN
examples/wifi/simple_sniffer/sniffer-esp32-pcap.png
Normal file
BIN
examples/wifi/simple_sniffer/sniffer-esp32-pcap.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 293 KiB |
Binary file not shown.
Before Width: | Height: | Size: 504 KiB |
Loading…
x
Reference in New Issue
Block a user