esp_radio/wifi/
sniffer.rs1use esp_sync::NonReentrantMutex;
4
5use super::{RxControlInfo, SNIFFER_BIT, WifiRefGuard, release, try_acquire};
6use crate::{
7 WifiError,
8 sys::include::{
9 esp_wifi_80211_tx,
10 esp_wifi_set_promiscuous,
11 esp_wifi_set_promiscuous_rx_cb,
12 wifi_interface_t,
13 wifi_interface_t_WIFI_IF_AP,
14 wifi_interface_t_WIFI_IF_STA,
15 wifi_pkt_rx_ctrl_t,
16 wifi_promiscuous_pkt_t,
17 wifi_promiscuous_pkt_type_t,
18 },
19 wifi::esp_wifi_result,
20};
21
22#[derive(Debug)]
24#[cfg_attr(feature = "defmt", derive(defmt::Format))]
25#[instability::unstable]
26pub struct PromiscuousPkt<'a> {
27 pub rx_cntl: RxControlInfo,
29 pub frame_type: wifi_promiscuous_pkt_type_t,
31 pub len: usize,
33 pub data: &'a [u8],
35}
36
37#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
38impl PromiscuousPkt<'_> {
39 pub(crate) unsafe fn from_raw(
44 buf: *const wifi_promiscuous_pkt_t,
45 frame_type: wifi_promiscuous_pkt_type_t,
46 ) -> Self {
47 let rx_cntl = unsafe { RxControlInfo::from_raw(&(*buf).rx_ctrl) };
48 let len = rx_cntl.sig_len as usize;
49 PromiscuousPkt {
50 rx_cntl,
51 frame_type,
52 len,
53 data: unsafe {
54 core::slice::from_raw_parts(
55 (buf as *const u8).add(core::mem::size_of::<wifi_pkt_rx_ctrl_t>()),
56 len,
57 )
58 },
59 }
60 }
61}
62
63static SNIFFER_CB: NonReentrantMutex<Option<fn(PromiscuousPkt<'_>)>> = NonReentrantMutex::new(None);
64
65unsafe extern "C" fn promiscuous_rx_cb(buf: *mut core::ffi::c_void, frame_type: u32) {
66 unsafe {
67 if let Some(sniffer_callback) = SNIFFER_CB.with(|callback| *callback) {
68 let promiscuous_pkt = PromiscuousPkt::from_raw(buf as *const _, frame_type);
69 sniffer_callback(promiscuous_pkt);
70 }
71 }
72}
73
74#[derive(Debug)]
76#[cfg_attr(feature = "defmt", derive(defmt::Format))]
77#[instability::unstable]
78#[non_exhaustive]
79pub struct Sniffer {
80 _wifi_guard: WifiRefGuard,
81}
82
83impl Sniffer {
84 pub(crate) fn new(guard: WifiRefGuard) -> Self {
85 assert!(try_acquire(SNIFFER_BIT), "sniffer already in use");
86
87 let res =
90 esp_wifi_result!(unsafe { esp_wifi_set_promiscuous_rx_cb(Some(promiscuous_rx_cb)) });
91 if res.is_err() {
92 release(SNIFFER_BIT);
93 unwrap!(res);
94 }
95
96 Self { _wifi_guard: guard }
97 }
98
99 #[instability::unstable]
101 pub fn set_promiscuous_mode(&self, enabled: bool) -> Result<(), WifiError> {
102 esp_wifi_result!(unsafe { esp_wifi_set_promiscuous(enabled) })?;
103 Ok(())
104 }
105
106 #[instability::unstable]
108 pub fn send_raw_frame(
109 &mut self,
110 use_sta_interface: bool,
111 buffer: &[u8],
112 use_internal_seq_num: bool,
113 ) -> Result<(), WifiError> {
114 esp_wifi_result!(unsafe {
115 esp_wifi_80211_tx(
116 if use_sta_interface {
117 wifi_interface_t_WIFI_IF_STA
118 } else {
119 wifi_interface_t_WIFI_IF_AP
120 } as wifi_interface_t,
121 buffer.as_ptr() as *const _,
122 buffer.len() as i32,
123 use_internal_seq_num,
124 )
125 })
126 }
127
128 #[instability::unstable]
130 pub fn set_receive_cb(&mut self, cb: fn(PromiscuousPkt<'_>)) {
131 SNIFFER_CB.with(|callback| *callback = Some(cb));
132 }
133}
134
135impl Drop for Sniffer {
136 fn drop(&mut self) {
137 SNIFFER_CB.with(|callback| *callback = None);
140 if let Err(e) = esp_wifi_result!(unsafe { esp_wifi_set_promiscuous(false) }) {
143 warn!(
144 "Failed to disable promiscuous mode on sniffer drop: {:?}",
145 e
146 );
147 }
148 if let Err(e) = esp_wifi_result!(unsafe { esp_wifi_set_promiscuous_rx_cb(None) }) {
149 warn!(
150 "Failed to unregister promiscuous rx cb on sniffer drop: {:?}",
151 e
152 );
153 }
154 release(SNIFFER_BIT);
155 }
156}