refactor: Move sniffer to own module
This commit is contained in:
parent
dc309bc095
commit
93f3cce9e4
3 changed files with 126 additions and 82 deletions
|
|
@ -1 +1,2 @@
|
||||||
stack-size-threshold = 1024
|
stack-size-threshold = 1024
|
||||||
|
doc-valid-idents = ["WiFi", ".."]
|
||||||
|
|
|
||||||
107
src/main.rs
107
src/main.rs
|
|
@ -12,64 +12,14 @@ use embassy_time::{Duration, Timer};
|
||||||
use esp_backtrace as _;
|
use esp_backtrace as _;
|
||||||
use esp_hal::clock::CpuClock;
|
use esp_hal::clock::CpuClock;
|
||||||
use esp_hal::timer::timg::TimerGroup;
|
use esp_hal::timer::timg::TimerGroup;
|
||||||
use log::{debug, error, info, warn};
|
use esp_radio::wifi;
|
||||||
|
use log::{debug, info, warn};
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
const WIFI_CHANNEL: core::ffi::c_int = 180;
|
mod radio;
|
||||||
|
|
||||||
unsafe extern "C" {
|
const WIFI_CHANNEL: radio::Channel = 180;
|
||||||
/// Changes the 802.11 PHY channel
|
|
||||||
///
|
|
||||||
/// C function signature: `void phy_change_channel(int,int,int,int)`
|
|
||||||
///
|
|
||||||
/// Options:
|
|
||||||
/// - `primary`: Channel frequency in MHz
|
|
||||||
/// - `ignored1`: Ignored (set to 1)
|
|
||||||
/// - `ignored2`: Ignored (set to 0)
|
|
||||||
/// - `ht_mode`: Probably HT mode
|
|
||||||
pub unsafe fn phy_change_channel(
|
|
||||||
primary: core::ffi::c_int,
|
|
||||||
ignored1: core::ffi::c_int,
|
|
||||||
ignored2: core::ffi::c_int,
|
|
||||||
ht_mode: core::ffi::c_int,
|
|
||||||
) -> core::ffi::c_int;
|
|
||||||
|
|
||||||
/// Enables 802.11p mode on the ESP32-C5
|
|
||||||
///
|
|
||||||
/// C function signature: `void phy_11p_set(int,int)`
|
|
||||||
///
|
|
||||||
/// Options:
|
|
||||||
/// - `enable`: Boolean option to enable 802.11p mode
|
|
||||||
/// - `zero`: Unknown, but need to be zero
|
|
||||||
pub unsafe fn phy_11p_set(enable: u8, zero: u8);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(u8)]
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
enum EspWifiPromiscuousPktType {
|
|
||||||
/// Management frame, indicates 'buf' argument is wifi_promiscuous_pkt_t
|
|
||||||
MGMT = 0,
|
|
||||||
/// Control frame, indicates 'buf' argument is wifi_promiscuous_pkt_t
|
|
||||||
CTRL = 1,
|
|
||||||
/// Data frame, indicates 'buf' argument is wifi_promiscuous_pkt_t
|
|
||||||
DATA = 2,
|
|
||||||
/// Other type, such as MIMO etc. 'buf' argument is wifi_promiscuous_pkt_t but the payload is zero length.
|
|
||||||
MISC = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EspWifiPromiscuousPktType {
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn as_repr(self) -> u8 {
|
|
||||||
self as u8
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts to underlying type of `wifi_promiscuous_pkt_type_t` (used by `esp_radio::wifi::sniffer::PromiscuousPkt::frame_type`)
|
|
||||||
pub fn as_frame_type(self) -> core::ffi::c_uint {
|
|
||||||
(self as u8) as core::ffi::c_uint
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This creates a default app-descriptor required by the esp-idf bootloader.
|
// This creates a default app-descriptor required by the esp-idf bootloader.
|
||||||
// For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description>
|
// For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description>
|
||||||
|
|
@ -115,34 +65,9 @@ async fn main(spawner: Spawner) -> ! {
|
||||||
.expect("Failed to initialize Wi-Fi controller");
|
.expect("Failed to initialize Wi-Fi controller");
|
||||||
|
|
||||||
let mut sniffer = interfaces.sniffer;
|
let mut sniffer = interfaces.sniffer;
|
||||||
sniffer
|
radio::setup_wifi_sniffer(WIFI_CHANNEL, &mut sniffer, handle_frame)
|
||||||
.set_promiscuous_mode(true)
|
.expect("Fatal error initializing 802.11p sniffer");
|
||||||
.expect("Failed to enable promiscuous mode");
|
|
||||||
|
|
||||||
sniffer.set_receive_cb(|packet| {
|
|
||||||
// Ignore frames with errors and non-data frames
|
|
||||||
if packet.rx_cntl.rx_state != 0 {
|
|
||||||
warn!("Received frame has RX error: {}", packet.rx_cntl.rx_state);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if packet.frame_type != EspWifiPromiscuousPktType::DATA.as_frame_type() {
|
|
||||||
debug!("Received frame is not a DATA frame: {}", packet.frame_type);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: handle 802.11 frame
|
|
||||||
info!("Received frame with {} bytes", packet.len);
|
|
||||||
});
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
phy_11p_set(1, 0);
|
|
||||||
match phy_change_channel(5000 + (WIFI_CHANNEL * 5), 1, 0, 0) {
|
|
||||||
0 => {}
|
|
||||||
ret => {
|
|
||||||
error!("ERROR: Failed to change channel: {ret}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
info!("WiFi promiscuous mode on channel {WIFI_CHANNEL} running");
|
info!("WiFi promiscuous mode on channel {WIFI_CHANNEL} running");
|
||||||
|
|
||||||
// TODO: Spawn some tasks
|
// TODO: Spawn some tasks
|
||||||
|
|
@ -154,3 +79,23 @@ async fn main(spawner: Spawner) -> ! {
|
||||||
Timer::after(Duration::from_secs(1)).await;
|
Timer::after(Duration::from_secs(1)).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(
|
||||||
|
clippy::needless_pass_by_value,
|
||||||
|
reason = "adhering to callback interface"
|
||||||
|
)]
|
||||||
|
fn handle_frame(frame: wifi::sniffer::PromiscuousPkt<'_>) {
|
||||||
|
// Ignore frames with errors and non-data frames
|
||||||
|
if frame.rx_cntl.rx_state != 0 {
|
||||||
|
warn!("Received frame has RX error: {}", frame.rx_cntl.rx_state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !radio::PromiscuousPktType::Data.matches(frame.frame_type) {
|
||||||
|
debug!("Received frame is not a DATA frame: {}", frame.frame_type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: handle 802.11 frame
|
||||||
|
info!("Received frame with {} bytes", frame.len);
|
||||||
|
}
|
||||||
|
|
|
||||||
98
src/radio.rs
Normal file
98
src/radio.rs
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
//! IEEE 802.11p C-ITS Capture with ESP32-C5
|
||||||
|
|
||||||
|
// -----------------------------
|
||||||
|
// missing interface definitions
|
||||||
|
// -----------------------------
|
||||||
|
|
||||||
|
use alloc::format;
|
||||||
|
use alloc::string::String;
|
||||||
|
|
||||||
|
use esp_radio::wifi::sniffer;
|
||||||
|
|
||||||
|
pub type Channel = core::ffi::c_int;
|
||||||
|
|
||||||
|
unsafe extern "C" {
|
||||||
|
/// Changes the 802.11 PHY channel
|
||||||
|
///
|
||||||
|
/// C function signature: `void phy_change_channel(int,int,int,int)`
|
||||||
|
///
|
||||||
|
/// Options:
|
||||||
|
/// - `primary`: Channel frequency in MHz
|
||||||
|
/// - `ignored1`: Ignored (set to 1)
|
||||||
|
/// - `ignored2`: Ignored (set to 0)
|
||||||
|
/// - `ht_mode`: Probably HT mode
|
||||||
|
unsafe fn phy_change_channel(
|
||||||
|
primary: Channel,
|
||||||
|
ignored1: core::ffi::c_int,
|
||||||
|
ignored2: core::ffi::c_int,
|
||||||
|
ht_mode: core::ffi::c_int,
|
||||||
|
) -> core::ffi::c_int;
|
||||||
|
|
||||||
|
/// Enables 802.11p mode on the ESP32-C5
|
||||||
|
///
|
||||||
|
/// C function signature: `void phy_11p_set(int,int)`
|
||||||
|
///
|
||||||
|
/// Options:
|
||||||
|
/// - `enable`: Boolean option to enable 802.11p mode
|
||||||
|
/// - `zero`: Unknown, but need to be zero
|
||||||
|
unsafe fn phy_11p_set(enable: u8, zero: u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enum values for `wifi_promiscuous_pkt_type_t` used in `esp_radio::wifi::sniffer::PromiscuousPkt::frame_type`
|
||||||
|
///
|
||||||
|
/// Original value is actually `core::ffi::c_uint`, but that can't be used in `#[repr()]` attributes,
|
||||||
|
/// so we're using `u8` as the smallest suitable type here that can be casted to a bigger type.
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) enum PromiscuousPktType {
|
||||||
|
/// Management frame, indicates 'buf' argument is `wifi_promiscuous_pkt_t`
|
||||||
|
Mgmt = 0,
|
||||||
|
/// Control frame, indicates 'buf' argument is `wifi_promiscuous_pkt_t`
|
||||||
|
Ctrl = 1,
|
||||||
|
/// Data frame, indicates 'buf' argument is `wifi_promiscuous_pkt_t`
|
||||||
|
Data = 2,
|
||||||
|
/// Other type, such as MIMO etc. 'buf' argument is `wifi_promiscuous_pkt_t` but the payload is zero length.
|
||||||
|
Misc = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PromiscuousPktType {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn as_repr(self) -> u8 {
|
||||||
|
self as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts to underlying type of `wifi_promiscuous_pkt_type_t` (used by `esp_radio::wifi::sniffer::PromiscuousPkt::frame_type`)
|
||||||
|
pub fn as_frame_type(self) -> core::ffi::c_uint {
|
||||||
|
core::ffi::c_uint::from(self.as_repr())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if
|
||||||
|
pub fn matches(self, frame_type: core::ffi::c_uint) -> bool {
|
||||||
|
self.as_frame_type() == frame_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure WiFi Sniffer to a certain 802.11p channel
|
||||||
|
pub fn setup_wifi_sniffer(
|
||||||
|
channel: Channel,
|
||||||
|
sniffer: &mut sniffer::Sniffer,
|
||||||
|
callback: fn(sniffer::PromiscuousPkt<'_>),
|
||||||
|
) -> Result<(), String> {
|
||||||
|
sniffer
|
||||||
|
.set_promiscuous_mode(true)
|
||||||
|
.map_err(|err| format!("Failed to enable promiscuous mode: {err:?}"))?;
|
||||||
|
|
||||||
|
sniffer.set_receive_cb(callback);
|
||||||
|
|
||||||
|
// convert channel number to frequency in MHz
|
||||||
|
let primary = 5000 + (channel * 5);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
phy_11p_set(1, 0);
|
||||||
|
match phy_change_channel(primary, 1, 0, 0) {
|
||||||
|
0 => Ok(()),
|
||||||
|
ret => Err(format!("Failed to change channel: {ret}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue