esp_radio/wifi/
sniffer.rs1use core::marker::PhantomData;
4
5use esp_sync::NonReentrantMutex;
6
7use super::RxControlInfo;
8use crate::{
9 WifiError,
10 sys::include::{
11 esp_wifi_80211_tx,
12 esp_wifi_set_promiscuous,
13 esp_wifi_set_promiscuous_rx_cb,
14 wifi_interface_t,
15 wifi_interface_t_WIFI_IF_AP,
16 wifi_interface_t_WIFI_IF_STA,
17 wifi_pkt_rx_ctrl_t,
18 wifi_promiscuous_pkt_t,
19 wifi_promiscuous_pkt_type_t,
20 },
21 wifi::esp_wifi_result,
22};
23
24#[derive(Debug)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
27#[instability::unstable]
28pub struct PromiscuousPkt<'a> {
29 pub rx_cntl: RxControlInfo,
31 pub frame_type: wifi_promiscuous_pkt_type_t,
33 pub len: usize,
35 pub data: &'a [u8],
37}
38
39#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
40impl PromiscuousPkt<'_> {
41 pub(crate) unsafe fn from_raw(
46 buf: *const wifi_promiscuous_pkt_t,
47 frame_type: wifi_promiscuous_pkt_type_t,
48 ) -> Self {
49 let rx_cntl = unsafe { RxControlInfo::from_raw(&(*buf).rx_ctrl) };
50 let len = rx_cntl.sig_len as usize;
51 PromiscuousPkt {
52 rx_cntl,
53 frame_type,
54 len,
55 data: unsafe {
56 core::slice::from_raw_parts(
57 (buf as *const u8).add(core::mem::size_of::<wifi_pkt_rx_ctrl_t>()),
58 len,
59 )
60 },
61 }
62 }
63}
64
65static SNIFFER_CB: NonReentrantMutex<Option<fn(PromiscuousPkt<'_>)>> = NonReentrantMutex::new(None);
66
67unsafe extern "C" fn promiscuous_rx_cb(buf: *mut core::ffi::c_void, frame_type: u32) {
68 unsafe {
69 if let Some(sniffer_callback) = SNIFFER_CB.with(|callback| *callback) {
70 let promiscuous_pkt = PromiscuousPkt::from_raw(buf as *const _, frame_type);
71 sniffer_callback(promiscuous_pkt);
72 }
73 }
74}
75
76#[derive(Debug)]
78#[cfg_attr(feature = "defmt", derive(defmt::Format))]
79#[instability::unstable]
80#[non_exhaustive]
81pub struct Sniffer<'d> {
82 _phantom: PhantomData<&'d ()>,
83}
84
85impl Sniffer<'_> {
86 pub(crate) fn new() -> Self {
87 unwrap!(esp_wifi_result!(unsafe {
90 esp_wifi_set_promiscuous_rx_cb(Some(promiscuous_rx_cb))
91 }));
92
93 Self {
94 _phantom: PhantomData,
95 }
96 }
97
98 #[instability::unstable]
100 pub fn set_promiscuous_mode(&self, enabled: bool) -> Result<(), WifiError> {
101 esp_wifi_result!(unsafe { esp_wifi_set_promiscuous(enabled) })?;
102 Ok(())
103 }
104
105 #[instability::unstable]
107 pub fn send_raw_frame(
108 &mut self,
109 use_sta_interface: bool,
110 buffer: &[u8],
111 use_internal_seq_num: bool,
112 ) -> Result<(), WifiError> {
113 esp_wifi_result!(unsafe {
114 esp_wifi_80211_tx(
115 if use_sta_interface {
116 wifi_interface_t_WIFI_IF_STA
117 } else {
118 wifi_interface_t_WIFI_IF_AP
119 } as wifi_interface_t,
120 buffer.as_ptr() as *const _,
121 buffer.len() as i32,
122 use_internal_seq_num,
123 )
124 })
125 }
126
127 #[instability::unstable]
129 pub fn set_receive_cb(&mut self, cb: fn(PromiscuousPkt<'_>)) {
130 SNIFFER_CB.with(|callback| *callback = Some(cb));
131 }
132}