1use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
14#[repr(u8)]
15pub enum AssociationFailureCause {
16 Unknown = 0,
18 Associationfailed = 1,
20 Authenticationfailed = 2,
22 Ssidnotfound = 3,
24}
25
26impl AssociationFailureCause {
27 pub fn from_u8(value: u8) -> Option<Self> {
29 match value {
30 0 => Some(AssociationFailureCause::Unknown),
31 1 => Some(AssociationFailureCause::Associationfailed),
32 2 => Some(AssociationFailureCause::Authenticationfailed),
33 3 => Some(AssociationFailureCause::Ssidnotfound),
34 _ => None,
35 }
36 }
37
38 pub fn to_u8(self) -> u8 {
40 self as u8
41 }
42}
43
44impl From<AssociationFailureCause> for u8 {
45 fn from(val: AssociationFailureCause) -> Self {
46 val as u8
47 }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
51#[repr(u8)]
52pub enum ConnectionStatus {
53 Connected = 0,
55 Notconnected = 1,
57}
58
59impl ConnectionStatus {
60 pub fn from_u8(value: u8) -> Option<Self> {
62 match value {
63 0 => Some(ConnectionStatus::Connected),
64 1 => Some(ConnectionStatus::Notconnected),
65 _ => None,
66 }
67 }
68
69 pub fn to_u8(self) -> u8 {
71 self as u8
72 }
73}
74
75impl From<ConnectionStatus> for u8 {
76 fn from(val: ConnectionStatus) -> Self {
77 val as u8
78 }
79}
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
82#[repr(u8)]
83pub enum SecurityType {
84 Unspecified = 0,
86 None = 1,
88 Wep = 2,
90 Wpa = 3,
92 Wpa2 = 4,
94 Wpa3 = 5,
96}
97
98impl SecurityType {
99 pub fn from_u8(value: u8) -> Option<Self> {
101 match value {
102 0 => Some(SecurityType::Unspecified),
103 1 => Some(SecurityType::None),
104 2 => Some(SecurityType::Wep),
105 3 => Some(SecurityType::Wpa),
106 4 => Some(SecurityType::Wpa2),
107 5 => Some(SecurityType::Wpa3),
108 _ => None,
109 }
110 }
111
112 pub fn to_u8(self) -> u8 {
114 self as u8
115 }
116}
117
118impl From<SecurityType> for u8 {
119 fn from(val: SecurityType) -> Self {
120 val as u8
121 }
122}
123
124#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
125#[repr(u8)]
126pub enum WiFiVersion {
127 A = 0,
129 B = 1,
131 G = 2,
133 N = 3,
135 Ac = 4,
137 Ax = 5,
139 Ah = 6,
141}
142
143impl WiFiVersion {
144 pub fn from_u8(value: u8) -> Option<Self> {
146 match value {
147 0 => Some(WiFiVersion::A),
148 1 => Some(WiFiVersion::B),
149 2 => Some(WiFiVersion::G),
150 3 => Some(WiFiVersion::N),
151 4 => Some(WiFiVersion::Ac),
152 5 => Some(WiFiVersion::Ax),
153 6 => Some(WiFiVersion::Ah),
154 _ => None,
155 }
156 }
157
158 pub fn to_u8(self) -> u8 {
160 self as u8
161 }
162}
163
164impl From<WiFiVersion> for u8 {
165 fn from(val: WiFiVersion) -> Self {
166 val as u8
167 }
168}
169
170pub fn decode_bssid(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<Vec<u8>>> {
176 if let tlv::TlvItemValue::OctetString(v) = inp {
177 Ok(Some(v.clone()))
178 } else {
179 Ok(None)
180 }
181}
182
183pub fn decode_security_type(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<SecurityType>> {
185 if let tlv::TlvItemValue::Int(v) = inp {
186 Ok(SecurityType::from_u8(*v as u8))
187 } else {
188 Ok(None)
189 }
190}
191
192pub fn decode_wifi_version(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<WiFiVersion>> {
194 if let tlv::TlvItemValue::Int(v) = inp {
195 Ok(WiFiVersion::from_u8(*v as u8))
196 } else {
197 Ok(None)
198 }
199}
200
201pub fn decode_channel_number(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
203 if let tlv::TlvItemValue::Int(v) = inp {
204 Ok(Some(*v as u16))
205 } else {
206 Ok(None)
207 }
208}
209
210pub fn decode_rssi(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i8>> {
212 if let tlv::TlvItemValue::Int(v) = inp {
213 Ok(Some(*v as i8))
214 } else {
215 Ok(None)
216 }
217}
218
219pub fn decode_beacon_lost_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
221 if let tlv::TlvItemValue::Int(v) = inp {
222 Ok(Some(*v as u32))
223 } else {
224 Ok(None)
225 }
226}
227
228pub fn decode_beacon_rx_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
230 if let tlv::TlvItemValue::Int(v) = inp {
231 Ok(Some(*v as u32))
232 } else {
233 Ok(None)
234 }
235}
236
237pub fn decode_packet_multicast_rx_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
239 if let tlv::TlvItemValue::Int(v) = inp {
240 Ok(Some(*v as u32))
241 } else {
242 Ok(None)
243 }
244}
245
246pub fn decode_packet_multicast_tx_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
248 if let tlv::TlvItemValue::Int(v) = inp {
249 Ok(Some(*v as u32))
250 } else {
251 Ok(None)
252 }
253}
254
255pub fn decode_packet_unicast_rx_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
257 if let tlv::TlvItemValue::Int(v) = inp {
258 Ok(Some(*v as u32))
259 } else {
260 Ok(None)
261 }
262}
263
264pub fn decode_packet_unicast_tx_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
266 if let tlv::TlvItemValue::Int(v) = inp {
267 Ok(Some(*v as u32))
268 } else {
269 Ok(None)
270 }
271}
272
273pub fn decode_current_max_rate(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u64>> {
275 if let tlv::TlvItemValue::Int(v) = inp {
276 Ok(Some(*v))
277 } else {
278 Ok(None)
279 }
280}
281
282pub fn decode_overrun_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u64>> {
284 if let tlv::TlvItemValue::Int(v) = inp {
285 Ok(Some(*v))
286 } else {
287 Ok(None)
288 }
289}
290
291
292pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
304 if cluster_id != 0x0036 {
306 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0036, got {}\"}}", cluster_id);
307 }
308
309 match attribute_id {
310 0x0000 => {
311 match decode_bssid(tlv_value) {
312 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
313 Err(e) => format!("{{\"error\": \"{}\"}}", e),
314 }
315 }
316 0x0001 => {
317 match decode_security_type(tlv_value) {
318 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
319 Err(e) => format!("{{\"error\": \"{}\"}}", e),
320 }
321 }
322 0x0002 => {
323 match decode_wifi_version(tlv_value) {
324 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
325 Err(e) => format!("{{\"error\": \"{}\"}}", e),
326 }
327 }
328 0x0003 => {
329 match decode_channel_number(tlv_value) {
330 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
331 Err(e) => format!("{{\"error\": \"{}\"}}", e),
332 }
333 }
334 0x0004 => {
335 match decode_rssi(tlv_value) {
336 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
337 Err(e) => format!("{{\"error\": \"{}\"}}", e),
338 }
339 }
340 0x0005 => {
341 match decode_beacon_lost_count(tlv_value) {
342 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
343 Err(e) => format!("{{\"error\": \"{}\"}}", e),
344 }
345 }
346 0x0006 => {
347 match decode_beacon_rx_count(tlv_value) {
348 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
349 Err(e) => format!("{{\"error\": \"{}\"}}", e),
350 }
351 }
352 0x0007 => {
353 match decode_packet_multicast_rx_count(tlv_value) {
354 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
355 Err(e) => format!("{{\"error\": \"{}\"}}", e),
356 }
357 }
358 0x0008 => {
359 match decode_packet_multicast_tx_count(tlv_value) {
360 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
361 Err(e) => format!("{{\"error\": \"{}\"}}", e),
362 }
363 }
364 0x0009 => {
365 match decode_packet_unicast_rx_count(tlv_value) {
366 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
367 Err(e) => format!("{{\"error\": \"{}\"}}", e),
368 }
369 }
370 0x000A => {
371 match decode_packet_unicast_tx_count(tlv_value) {
372 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
373 Err(e) => format!("{{\"error\": \"{}\"}}", e),
374 }
375 }
376 0x000B => {
377 match decode_current_max_rate(tlv_value) {
378 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
379 Err(e) => format!("{{\"error\": \"{}\"}}", e),
380 }
381 }
382 0x000C => {
383 match decode_overrun_count(tlv_value) {
384 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
385 Err(e) => format!("{{\"error\": \"{}\"}}", e),
386 }
387 }
388 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
389 }
390}
391
392pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
397 vec![
398 (0x0000, "BSSID"),
399 (0x0001, "SecurityType"),
400 (0x0002, "WiFiVersion"),
401 (0x0003, "ChannelNumber"),
402 (0x0004, "RSSI"),
403 (0x0005, "BeaconLostCount"),
404 (0x0006, "BeaconRxCount"),
405 (0x0007, "PacketMulticastRxCount"),
406 (0x0008, "PacketMulticastTxCount"),
407 (0x0009, "PacketUnicastRxCount"),
408 (0x000A, "PacketUnicastTxCount"),
409 (0x000B, "CurrentMaxRate"),
410 (0x000C, "OverrunCount"),
411 ]
412}
413
414#[derive(Debug, serde::Serialize)]
415pub struct DisconnectionEvent {
416 pub reason_code: Option<u16>,
417}
418
419#[derive(Debug, serde::Serialize)]
420pub struct AssociationFailureEvent {
421 pub association_failure_cause: Option<AssociationFailureCause>,
422 pub status: Option<u16>,
423}
424
425#[derive(Debug, serde::Serialize)]
426pub struct ConnectionStatusEvent {
427 pub connection_status: Option<ConnectionStatus>,
428}
429
430pub fn decode_disconnection_event(inp: &tlv::TlvItemValue) -> anyhow::Result<DisconnectionEvent> {
434 if let tlv::TlvItemValue::List(_fields) = inp {
435 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
436 Ok(DisconnectionEvent {
437 reason_code: item.get_int(&[0]).map(|v| v as u16),
438 })
439 } else {
440 Err(anyhow::anyhow!("Expected struct fields"))
441 }
442}
443
444pub fn decode_association_failure_event(inp: &tlv::TlvItemValue) -> anyhow::Result<AssociationFailureEvent> {
446 if let tlv::TlvItemValue::List(_fields) = inp {
447 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
448 Ok(AssociationFailureEvent {
449 association_failure_cause: item.get_int(&[0]).and_then(|v| AssociationFailureCause::from_u8(v as u8)),
450 status: item.get_int(&[1]).map(|v| v as u16),
451 })
452 } else {
453 Err(anyhow::anyhow!("Expected struct fields"))
454 }
455}
456
457pub fn decode_connection_status_event(inp: &tlv::TlvItemValue) -> anyhow::Result<ConnectionStatusEvent> {
459 if let tlv::TlvItemValue::List(_fields) = inp {
460 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
461 Ok(ConnectionStatusEvent {
462 connection_status: item.get_int(&[0]).and_then(|v| ConnectionStatus::from_u8(v as u8)),
463 })
464 } else {
465 Err(anyhow::anyhow!("Expected struct fields"))
466 }
467}
468