Implement Sniffer API (#1935)
* Implemented queue_msg_waiting. * Fmt. * Adjusted changelog. * Fixed CI. * Fixed pointer mutability. * Implemented experimental sniffer api. * Fixed CI.. * Added safety comment. * Featured gated, PromiscuousPkt * Format. * Adjusted imports. * Added injection example. * Made RxControlInfo::from_raw public. * Format. * Added sniffer example.
This commit is contained in:
parent
59728c523f
commit
d1acacb757
@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Implement `embedded_io::{ReadReady, WriteReady}` traits for `WifiStack` (#1882)
|
||||
- Implement `queue_msg_waiting` on the os_adapter (#1925)
|
||||
- Added API for promiscuous mode (#1935)
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
@ -133,6 +133,7 @@ dhcpv4 = ["wifi", "utils", "smoltcp?/proto-dhcpv4", "smoltcp?/socket-dhcpv4"]
|
||||
wifi-default = ["ipv4", "tcp", "udp", "icmp", "igmp", "dns", "dhcpv4"]
|
||||
defmt = ["dep:defmt", "smoltcp?/defmt", "esp-hal/defmt"]
|
||||
log = ["dep:log", "esp-hal/log"]
|
||||
sniffer = ["wifi"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = [
|
||||
|
||||
@ -19,7 +19,7 @@ use crate::{
|
||||
binary::include::*,
|
||||
compat::queue::SimpleQueue,
|
||||
hal::peripheral::{Peripheral, PeripheralRef},
|
||||
wifi::Protocol,
|
||||
wifi::{Protocol, RxControlInfo},
|
||||
EspWifiInitialization,
|
||||
};
|
||||
|
||||
@ -179,57 +179,6 @@ pub struct PeerInfo {
|
||||
// we always use STA for now
|
||||
}
|
||||
|
||||
#[cfg(not(any(esp32c6)))]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct RxControlInfo {
|
||||
pub rssi: i32,
|
||||
pub rate: u32,
|
||||
pub sig_mode: u32,
|
||||
pub mcs: u32,
|
||||
pub cwb: u32,
|
||||
pub smoothing: u32,
|
||||
pub not_sounding: u32,
|
||||
pub aggregation: u32,
|
||||
pub stbc: u32,
|
||||
pub fec_coding: u32,
|
||||
pub sgi: u32,
|
||||
pub ampdu_cnt: u32,
|
||||
pub channel: u32,
|
||||
pub secondary_channel: u32,
|
||||
pub timestamp: u32,
|
||||
pub noise_floor: i32,
|
||||
pub ant: u32,
|
||||
pub sig_len: u32,
|
||||
pub rx_state: u32,
|
||||
}
|
||||
|
||||
#[cfg(esp32c6)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct RxControlInfo {
|
||||
pub rssi: i32,
|
||||
pub rate: u32,
|
||||
pub sig_len: u32,
|
||||
pub rx_state: u32,
|
||||
pub dump_len: u32,
|
||||
pub he_sigb_len: u32,
|
||||
pub cur_single_mpdu: u32,
|
||||
pub cur_bb_format: u32,
|
||||
pub rx_channel_estimate_info_vld: u32,
|
||||
pub rx_channel_estimate_len: u32,
|
||||
pub second: u32,
|
||||
pub channel: u32,
|
||||
pub data_rssi: i32,
|
||||
pub noise_floor: u32,
|
||||
pub is_group: u32,
|
||||
pub rxend_state: u32,
|
||||
pub rxmatch3: u32,
|
||||
pub rxmatch2: u32,
|
||||
pub rxmatch1: u32,
|
||||
pub rxmatch0: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct ReceiveInfo {
|
||||
@ -813,52 +762,7 @@ unsafe extern "C" fn rcv_cb(
|
||||
];
|
||||
|
||||
let rx_cntl = (*esp_now_info).rx_ctrl;
|
||||
#[cfg(not(any(esp32c6)))]
|
||||
let rx_control = RxControlInfo {
|
||||
rssi: (*rx_cntl).rssi(),
|
||||
rate: (*rx_cntl).rate(),
|
||||
sig_mode: (*rx_cntl).sig_mode(),
|
||||
mcs: (*rx_cntl).mcs(),
|
||||
cwb: (*rx_cntl).cwb(),
|
||||
smoothing: (*rx_cntl).smoothing(),
|
||||
not_sounding: (*rx_cntl).not_sounding(),
|
||||
aggregation: (*rx_cntl).aggregation(),
|
||||
stbc: (*rx_cntl).stbc(),
|
||||
fec_coding: (*rx_cntl).fec_coding(),
|
||||
sgi: (*rx_cntl).sgi(),
|
||||
ampdu_cnt: (*rx_cntl).ampdu_cnt(),
|
||||
channel: (*rx_cntl).channel(),
|
||||
secondary_channel: (*rx_cntl).secondary_channel(),
|
||||
timestamp: (*rx_cntl).timestamp(),
|
||||
noise_floor: (*rx_cntl).noise_floor(),
|
||||
ant: (*rx_cntl).ant(),
|
||||
sig_len: (*rx_cntl).sig_len(),
|
||||
rx_state: (*rx_cntl).rx_state(),
|
||||
};
|
||||
|
||||
#[cfg(esp32c6)]
|
||||
let rx_control = RxControlInfo {
|
||||
rssi: (*rx_cntl).rssi(),
|
||||
rate: (*rx_cntl).rate(),
|
||||
sig_len: (*rx_cntl).sig_len(),
|
||||
rx_state: (*rx_cntl).rx_state(),
|
||||
dump_len: (*rx_cntl).dump_len(),
|
||||
he_sigb_len: (*rx_cntl).he_sigb_len(),
|
||||
cur_single_mpdu: (*rx_cntl).cur_single_mpdu(),
|
||||
cur_bb_format: (*rx_cntl).cur_bb_format(),
|
||||
rx_channel_estimate_info_vld: (*rx_cntl).rx_channel_estimate_info_vld(),
|
||||
rx_channel_estimate_len: (*rx_cntl).rx_channel_estimate_len(),
|
||||
second: (*rx_cntl).second(),
|
||||
channel: (*rx_cntl).channel(),
|
||||
data_rssi: (*rx_cntl).data_rssi(),
|
||||
noise_floor: (*rx_cntl).noise_floor(),
|
||||
is_group: (*rx_cntl).is_group(),
|
||||
rxend_state: (*rx_cntl).rxend_state(),
|
||||
rxmatch3: (*rx_cntl).rxmatch3(),
|
||||
rxmatch2: (*rx_cntl).rxmatch2(),
|
||||
rxmatch1: (*rx_cntl).rxmatch1(),
|
||||
rxmatch0: (*rx_cntl).rxmatch0(),
|
||||
};
|
||||
let rx_control = RxControlInfo::from_raw(rx_cntl);
|
||||
|
||||
let info = ReceiveInfo {
|
||||
src_address: src,
|
||||
|
||||
@ -6,15 +6,23 @@ pub(crate) mod state;
|
||||
use core::{
|
||||
cell::{RefCell, RefMut},
|
||||
fmt::Debug,
|
||||
mem,
|
||||
mem::MaybeUninit,
|
||||
mem::{self, MaybeUninit},
|
||||
ptr::addr_of,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use critical_section::{CriticalSection, Mutex};
|
||||
use enumset::{EnumSet, EnumSetType};
|
||||
#[cfg(feature = "sniffer")]
|
||||
use esp_wifi_sys::include::{
|
||||
esp_wifi_80211_tx,
|
||||
esp_wifi_set_promiscuous,
|
||||
esp_wifi_set_promiscuous_rx_cb,
|
||||
wifi_promiscuous_pkt_t,
|
||||
wifi_promiscuous_pkt_type_t,
|
||||
};
|
||||
use esp_wifi_sys::include::{
|
||||
wifi_pkt_rx_ctrl_t,
|
||||
WIFI_PROTOCOL_11AX,
|
||||
WIFI_PROTOCOL_11B,
|
||||
WIFI_PROTOCOL_11G,
|
||||
@ -25,6 +33,8 @@ use num_derive::FromPrimitive;
|
||||
use num_traits::FromPrimitive;
|
||||
#[doc(hidden)]
|
||||
pub(crate) use os_adapter::*;
|
||||
#[cfg(feature = "sniffer")]
|
||||
use portable_atomic::AtomicBool;
|
||||
use portable_atomic::{AtomicUsize, Ordering};
|
||||
#[cfg(feature = "smoltcp")]
|
||||
use smoltcp::phy::{Device, DeviceCapabilities, RxToken, TxToken};
|
||||
@ -1770,10 +1780,208 @@ fn convert_ap_info(record: &include::wifi_ap_record_t) -> AccessPointInfo {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(esp32c6)))]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct RxControlInfo {
|
||||
pub rssi: i32,
|
||||
pub rate: u32,
|
||||
pub sig_mode: u32,
|
||||
pub mcs: u32,
|
||||
pub cwb: u32,
|
||||
pub smoothing: u32,
|
||||
pub not_sounding: u32,
|
||||
pub aggregation: u32,
|
||||
pub stbc: u32,
|
||||
pub fec_coding: u32,
|
||||
pub sgi: u32,
|
||||
pub ampdu_cnt: u32,
|
||||
pub channel: u32,
|
||||
pub secondary_channel: u32,
|
||||
pub timestamp: u32,
|
||||
pub noise_floor: i32,
|
||||
pub ant: u32,
|
||||
pub sig_len: u32,
|
||||
pub rx_state: u32,
|
||||
}
|
||||
|
||||
#[cfg(esp32c6)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct RxControlInfo {
|
||||
pub rssi: i32,
|
||||
pub rate: u32,
|
||||
pub sig_len: u32,
|
||||
pub rx_state: u32,
|
||||
pub dump_len: u32,
|
||||
pub he_sigb_len: u32,
|
||||
pub cur_single_mpdu: u32,
|
||||
pub cur_bb_format: u32,
|
||||
pub rx_channel_estimate_info_vld: u32,
|
||||
pub rx_channel_estimate_len: u32,
|
||||
pub second: u32,
|
||||
pub channel: u32,
|
||||
pub data_rssi: i32,
|
||||
pub noise_floor: u32,
|
||||
pub is_group: u32,
|
||||
pub rxend_state: u32,
|
||||
pub rxmatch3: u32,
|
||||
pub rxmatch2: u32,
|
||||
pub rxmatch1: u32,
|
||||
pub rxmatch0: u32,
|
||||
}
|
||||
impl RxControlInfo {
|
||||
/// Create an instance from a raw pointer to [wifi_pkt_rx_ctrl_t].
|
||||
///
|
||||
/// # Safety
|
||||
/// When calling this, you must ensure, that `rx_cntl` points to a valid
|
||||
/// instance of [wifi_pkt_rx_ctrl_t].
|
||||
pub unsafe fn from_raw(rx_cntl: *const wifi_pkt_rx_ctrl_t) -> Self {
|
||||
#[cfg(not(esp32c6))]
|
||||
let rx_control_info = RxControlInfo {
|
||||
rssi: (*rx_cntl).rssi(),
|
||||
rate: (*rx_cntl).rate(),
|
||||
sig_mode: (*rx_cntl).sig_mode(),
|
||||
mcs: (*rx_cntl).mcs(),
|
||||
cwb: (*rx_cntl).cwb(),
|
||||
smoothing: (*rx_cntl).smoothing(),
|
||||
not_sounding: (*rx_cntl).not_sounding(),
|
||||
aggregation: (*rx_cntl).aggregation(),
|
||||
stbc: (*rx_cntl).stbc(),
|
||||
fec_coding: (*rx_cntl).fec_coding(),
|
||||
sgi: (*rx_cntl).sgi(),
|
||||
ampdu_cnt: (*rx_cntl).ampdu_cnt(),
|
||||
channel: (*rx_cntl).channel(),
|
||||
secondary_channel: (*rx_cntl).secondary_channel(),
|
||||
timestamp: (*rx_cntl).timestamp(),
|
||||
noise_floor: (*rx_cntl).noise_floor(),
|
||||
ant: (*rx_cntl).ant(),
|
||||
sig_len: (*rx_cntl).sig_len(),
|
||||
rx_state: (*rx_cntl).rx_state(),
|
||||
};
|
||||
#[cfg(esp32c6)]
|
||||
let rx_control_info = RxControlInfo {
|
||||
rssi: (*rx_cntl).rssi(),
|
||||
rate: (*rx_cntl).rate(),
|
||||
sig_len: (*rx_cntl).sig_len(),
|
||||
rx_state: (*rx_cntl).rx_state(),
|
||||
dump_len: (*rx_cntl).dump_len(),
|
||||
he_sigb_len: (*rx_cntl).he_sigb_len(),
|
||||
cur_single_mpdu: (*rx_cntl).cur_single_mpdu(),
|
||||
cur_bb_format: (*rx_cntl).cur_bb_format(),
|
||||
rx_channel_estimate_info_vld: (*rx_cntl).rx_channel_estimate_info_vld(),
|
||||
rx_channel_estimate_len: (*rx_cntl).rx_channel_estimate_len(),
|
||||
second: (*rx_cntl).second(),
|
||||
channel: (*rx_cntl).channel(),
|
||||
data_rssi: (*rx_cntl).data_rssi(),
|
||||
noise_floor: (*rx_cntl).noise_floor(),
|
||||
is_group: (*rx_cntl).is_group(),
|
||||
rxend_state: (*rx_cntl).rxend_state(),
|
||||
rxmatch3: (*rx_cntl).rxmatch3(),
|
||||
rxmatch2: (*rx_cntl).rxmatch2(),
|
||||
rxmatch1: (*rx_cntl).rxmatch1(),
|
||||
rxmatch0: (*rx_cntl).rxmatch0(),
|
||||
};
|
||||
rx_control_info
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "sniffer")]
|
||||
pub struct PromiscuousPkt<'a> {
|
||||
pub rx_cntl: RxControlInfo,
|
||||
pub frame_type: wifi_promiscuous_pkt_type_t,
|
||||
pub len: usize,
|
||||
pub data: &'a [u8],
|
||||
}
|
||||
#[cfg(feature = "sniffer")]
|
||||
impl PromiscuousPkt<'_> {
|
||||
/// # Safety
|
||||
/// When calling this, you have to ensure, that `buf` points to a valid
|
||||
/// [wifi_promiscuous_pkt_t].
|
||||
pub(crate) unsafe fn from_raw(
|
||||
buf: *const wifi_promiscuous_pkt_t,
|
||||
frame_type: wifi_promiscuous_pkt_type_t,
|
||||
) -> Self {
|
||||
let rx_cntl = RxControlInfo::from_raw(&(*buf).rx_ctrl);
|
||||
let len = rx_cntl.sig_len as usize;
|
||||
PromiscuousPkt {
|
||||
rx_cntl,
|
||||
frame_type,
|
||||
len,
|
||||
data: core::slice::from_raw_parts(
|
||||
(buf as *const u8).add(size_of::<wifi_pkt_rx_ctrl_t>()),
|
||||
len,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "sniffer")]
|
||||
static SNIFFER_CB: Mutex<RefCell<Option<fn(PromiscuousPkt)>>> = Mutex::new(RefCell::new(None));
|
||||
|
||||
#[cfg(feature = "sniffer")]
|
||||
unsafe extern "C" fn promiscuous_rx_cb(buf: *mut core::ffi::c_void, frame_type: u32) {
|
||||
critical_section::with(|cs| {
|
||||
let Some(sniffer_callback) = *SNIFFER_CB.borrow_ref(cs) else {
|
||||
return;
|
||||
};
|
||||
let promiscuous_pkt = PromiscuousPkt::from_raw(buf as *const _, frame_type);
|
||||
sniffer_callback(promiscuous_pkt);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "sniffer")]
|
||||
/// A wifi sniffer.
|
||||
pub struct Sniffer {
|
||||
promiscuous_mode_enabled: AtomicBool,
|
||||
}
|
||||
#[cfg(feature = "sniffer")]
|
||||
impl Sniffer {
|
||||
pub(crate) fn new() -> Self {
|
||||
// This shouldn't fail, since the way this is created, means that wifi will
|
||||
// always be initialized.
|
||||
esp_wifi_result!(unsafe { esp_wifi_set_promiscuous_rx_cb(Some(promiscuous_rx_cb)) })
|
||||
.unwrap();
|
||||
Self {
|
||||
promiscuous_mode_enabled: AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
/// Set promiscuous mode enabled or disabled.
|
||||
pub fn set_promiscuous_mode(&self, enabled: bool) -> Result<(), WifiError> {
|
||||
esp_wifi_result!(unsafe { esp_wifi_set_promiscuous(enabled) })?;
|
||||
self.promiscuous_mode_enabled
|
||||
.store(enabled, Ordering::Relaxed);
|
||||
Ok(())
|
||||
}
|
||||
/// Transmit a raw frame.
|
||||
pub fn send_raw_frame(
|
||||
&mut self,
|
||||
use_sta_interface: bool,
|
||||
buffer: &[u8],
|
||||
use_internal_seq_num: bool,
|
||||
) -> Result<(), WifiError> {
|
||||
esp_wifi_result!(unsafe {
|
||||
esp_wifi_80211_tx(
|
||||
if use_sta_interface { 0 } else { 1 } as wifi_interface_t,
|
||||
buffer.as_ptr() as *const _,
|
||||
buffer.len() as i32,
|
||||
use_internal_seq_num,
|
||||
)
|
||||
})
|
||||
}
|
||||
/// Set the callback for receiving a packet.
|
||||
pub fn set_receive_cb(&mut self, cb: fn(PromiscuousPkt)) {
|
||||
critical_section::with(|cs| {
|
||||
*SNIFFER_CB.borrow_ref_mut(cs) = Some(cb);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// A wifi controller
|
||||
pub struct WifiController<'d> {
|
||||
_device: PeripheralRef<'d, crate::hal::peripherals::WIFI>,
|
||||
config: Configuration,
|
||||
#[cfg(feature = "sniffer")]
|
||||
sniffer_taken: AtomicBool,
|
||||
}
|
||||
|
||||
impl<'d> WifiController<'d> {
|
||||
@ -1792,6 +2000,8 @@ impl<'d> WifiController<'d> {
|
||||
let mut this = Self {
|
||||
_device,
|
||||
config: Default::default(),
|
||||
#[cfg(feature = "sniffer")]
|
||||
sniffer_taken: AtomicBool::new(false),
|
||||
};
|
||||
|
||||
let mode = WifiMode::try_from(&config)?;
|
||||
@ -1801,6 +2011,18 @@ impl<'d> WifiController<'d> {
|
||||
this.set_configuration(&config)?;
|
||||
Ok(this)
|
||||
}
|
||||
#[cfg(feature = "sniffer")]
|
||||
pub fn take_sniffer(&self) -> Option<Sniffer> {
|
||||
if self
|
||||
.sniffer_taken
|
||||
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
|
||||
== Ok(false)
|
||||
{
|
||||
Some(Sniffer::new())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the wifi protocol.
|
||||
///
|
||||
|
||||
@ -42,6 +42,7 @@ fugit = "0.3.7"
|
||||
heapless = "0.8.0"
|
||||
hex-literal = "0.4.1"
|
||||
hmac = { version = "0.12.1", default-features = false }
|
||||
ieee80211 = { version = "0.4.0", default-features = false }
|
||||
ieee802154 = "0.6.1"
|
||||
lis3dh-async = "0.9.3"
|
||||
log = "0.4.22"
|
||||
|
||||
123
examples/src/bin/wifi_80211_tx.rs
Normal file
123
examples/src/bin/wifi_80211_tx.rs
Normal file
@ -0,0 +1,123 @@
|
||||
//! WiFi frame injection example
|
||||
//!
|
||||
//! Periodically transmits a beacon frame.
|
||||
|
||||
//% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/sniffer
|
||||
//% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use esp_backtrace as _;
|
||||
use esp_hal::{
|
||||
clock::ClockControl,
|
||||
delay::Delay,
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
rng::Rng,
|
||||
system::SystemControl,
|
||||
timer::{timg::TimerGroup, ErasedTimer, PeriodicTimer},
|
||||
};
|
||||
use esp_wifi::{initialize, wifi, EspWifiInitFor};
|
||||
use ieee80211::{
|
||||
common::{CapabilitiesInformation, FCFFlags},
|
||||
element_chain,
|
||||
elements::{DSSSParameterSetElement, RawIEEE80211Element, SSIDElement},
|
||||
mgmt_frame::{body::BeaconBody, header::ManagementFrameHeader, BeaconFrame},
|
||||
scroll::Pwrite,
|
||||
supported_rates,
|
||||
};
|
||||
|
||||
const SSID: &str = "esp-wifi 802.11 injection";
|
||||
/// This is an arbitrary MAC address, used for the fake beacon frames.
|
||||
const MAC_ADDRESS: [u8; 6] = [0x00, 0x80, 0x41, 0x13, 0x37, 0x42];
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
esp_println::logger::init_logger_from_env();
|
||||
|
||||
let peripherals = Peripherals::take();
|
||||
|
||||
let system = SystemControl::new(peripherals.SYSTEM);
|
||||
let clocks = ClockControl::max(system.clock_control).freeze();
|
||||
|
||||
let delay = Delay::new(&clocks);
|
||||
|
||||
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
|
||||
let timer0: ErasedTimer = timg0.timer0.into();
|
||||
let timer = PeriodicTimer::new(timer0);
|
||||
|
||||
let init = initialize(
|
||||
EspWifiInitFor::Wifi,
|
||||
timer,
|
||||
Rng::new(peripherals.RNG),
|
||||
peripherals.RADIO_CLK,
|
||||
&clocks,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let wifi = peripherals.WIFI;
|
||||
|
||||
// We must initialize some kind of interface and start it.
|
||||
let (_, mut controller) = wifi::new_with_mode(&init, wifi, wifi::WifiApDevice).unwrap();
|
||||
controller.start().unwrap();
|
||||
|
||||
let mut sniffer = controller.take_sniffer().unwrap();
|
||||
|
||||
// Create a buffer, which can hold the enitre serialized beacon frame.
|
||||
let mut beacon = [0u8; 300];
|
||||
let length = beacon
|
||||
.pwrite(
|
||||
BeaconFrame {
|
||||
header: ManagementFrameHeader {
|
||||
fcf_flags: FCFFlags::new(),
|
||||
duration: 0,
|
||||
receiver_address: [0xff; 6].into(),
|
||||
transmitter_address: MAC_ADDRESS.into(),
|
||||
bssid: MAC_ADDRESS.into(),
|
||||
..Default::default()
|
||||
},
|
||||
body: BeaconBody {
|
||||
timestamp: 0,
|
||||
// We transmit a beacon every 100 ms/TUs
|
||||
beacon_interval: 100,
|
||||
capabilities_info: CapabilitiesInformation::new().with_is_ess(true),
|
||||
elements: element_chain! {
|
||||
SSIDElement::new(SSID).unwrap(),
|
||||
// These are known good values.
|
||||
supported_rates![
|
||||
1 B,
|
||||
2 B,
|
||||
5.5 B,
|
||||
11 B,
|
||||
6,
|
||||
9,
|
||||
12,
|
||||
18
|
||||
],
|
||||
DSSSParameterSetElement {
|
||||
current_channel: 1,
|
||||
},
|
||||
// This contains the Traffic Indication Map(TIM), for which `ieee80211-rs` currently lacks support.
|
||||
RawIEEE80211Element {
|
||||
tlv_type: 5,
|
||||
slice: [0x01, 0x02, 0x00, 0x00].as_slice(),
|
||||
_phantom: PhantomData
|
||||
}
|
||||
},
|
||||
_phantom: PhantomData,
|
||||
},
|
||||
},
|
||||
0,
|
||||
)
|
||||
.unwrap();
|
||||
// Only use the actually written bytes.
|
||||
let beacon = &beacon[..length];
|
||||
|
||||
loop {
|
||||
sniffer.send_raw_frame(false, beacon, false).unwrap();
|
||||
delay.delay(100.millis());
|
||||
}
|
||||
}
|
||||
85
examples/src/bin/wifi_sniffer.rs
Normal file
85
examples/src/bin/wifi_sniffer.rs
Normal file
@ -0,0 +1,85 @@
|
||||
//! WiFi sniffer example
|
||||
//!
|
||||
//! Sniffs for beacon frames.
|
||||
|
||||
//% FEATURES: esp-wifi esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/sniffer
|
||||
//% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::{
|
||||
collections::btree_set::BTreeSet,
|
||||
string::{String, ToString},
|
||||
};
|
||||
use core::cell::RefCell;
|
||||
|
||||
use critical_section::Mutex;
|
||||
use esp_alloc::heap_allocator;
|
||||
use esp_backtrace as _;
|
||||
use esp_hal::{
|
||||
clock::ClockControl,
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
rng::Rng,
|
||||
system::SystemControl,
|
||||
timer::{timg::TimerGroup, ErasedTimer, PeriodicTimer},
|
||||
};
|
||||
use esp_println::println;
|
||||
use esp_wifi::{initialize, wifi, EspWifiInitFor};
|
||||
use ieee80211::{match_frames, mgmt_frame::BeaconFrame};
|
||||
|
||||
static KNOWN_SSIDS: Mutex<RefCell<BTreeSet<String>>> = Mutex::new(RefCell::new(BTreeSet::new()));
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
esp_println::logger::init_logger_from_env();
|
||||
|
||||
let peripherals = Peripherals::take();
|
||||
// Create a heap allocator, with 32kB of space.
|
||||
heap_allocator!(32_168);
|
||||
|
||||
let system = SystemControl::new(peripherals.SYSTEM);
|
||||
let clocks = ClockControl::max(system.clock_control).freeze();
|
||||
|
||||
let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
|
||||
let timer0: ErasedTimer = timg0.timer0.into();
|
||||
let timer = PeriodicTimer::new(timer0);
|
||||
|
||||
let init = initialize(
|
||||
EspWifiInitFor::Wifi,
|
||||
timer,
|
||||
Rng::new(peripherals.RNG),
|
||||
peripherals.RADIO_CLK,
|
||||
&clocks,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let wifi = peripherals.WIFI;
|
||||
|
||||
// We must initialize some kind of interface and start it.
|
||||
let (_, mut controller) = wifi::new_with_mode(&init, wifi, wifi::WifiApDevice).unwrap();
|
||||
controller.start().unwrap();
|
||||
|
||||
let mut sniffer = controller.take_sniffer().unwrap();
|
||||
sniffer.set_promiscuous_mode(true).unwrap();
|
||||
sniffer.set_receive_cb(|packet| {
|
||||
let _ = match_frames! {
|
||||
packet.data,
|
||||
beacon = BeaconFrame => {
|
||||
let Some(ssid) = beacon.ssid() else {
|
||||
return;
|
||||
};
|
||||
if critical_section::with(|cs| {
|
||||
KNOWN_SSIDS.borrow_ref_mut(cs).insert(ssid.to_string())
|
||||
}) {
|
||||
println!("Found new AP with SSID: {ssid}");
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
loop {}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user