diff options
Diffstat (limited to 'cyw43/src/control.rs')
| -rw-r--r-- | cyw43/src/control.rs | 89 |
1 files changed, 59 insertions, 30 deletions
diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index fd0d4d532..240c0e728 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs | |||
| @@ -10,13 +10,18 @@ use crate::events::{Event, EventSubscriber, Events}; | |||
| 10 | use crate::fmt::Bytes; | 10 | use crate::fmt::Bytes; |
| 11 | use crate::ioctl::{IoctlState, IoctlType}; | 11 | use crate::ioctl::{IoctlState, IoctlType}; |
| 12 | use crate::structs::*; | 12 | use crate::structs::*; |
| 13 | use crate::{countries, events, PowerManagementMode}; | 13 | use crate::{PowerManagementMode, countries, events}; |
| 14 | 14 | ||
| 15 | /// Control errors. | 15 | /// Join errors. |
| 16 | #[derive(Debug)] | 16 | #[derive(Debug)] |
| 17 | pub struct Error { | 17 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 18 | /// Status code. | 18 | pub enum JoinError { |
| 19 | pub status: u32, | 19 | /// Network not found. |
| 20 | NetworkNotFound, | ||
| 21 | /// Failure to join network. Contains the status code from the SET_SSID event. | ||
| 22 | JoinFailure(u8), | ||
| 23 | /// Authentication failure for a secure network. | ||
| 24 | AuthenticationFailure, | ||
| 20 | } | 25 | } |
| 21 | 26 | ||
| 22 | /// Multicast errors. | 27 | /// Multicast errors. |
| @@ -296,7 +301,7 @@ impl<'a> Control<'a> { | |||
| 296 | } | 301 | } |
| 297 | 302 | ||
| 298 | /// Join a network with the provided SSID using the specified options. | 303 | /// Join a network with the provided SSID using the specified options. |
| 299 | pub async fn join(&mut self, ssid: &str, options: JoinOptions<'_>) -> Result<(), Error> { | 304 | pub async fn join(&mut self, ssid: &str, options: JoinOptions<'_>) -> Result<(), JoinError> { |
| 300 | self.set_iovar_u32("ampdu_ba_wsize", 8).await; | 305 | self.set_iovar_u32("ampdu_ba_wsize", 8).await; |
| 301 | 306 | ||
| 302 | if options.auth == JoinAuth::Open { | 307 | if options.auth == JoinAuth::Open { |
| @@ -367,40 +372,55 @@ impl<'a> Control<'a> { | |||
| 367 | }; | 372 | }; |
| 368 | i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes()); | 373 | i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes()); |
| 369 | 374 | ||
| 370 | self.wait_for_join(i).await | 375 | let secure_network = options.auth != JoinAuth::Open; |
| 376 | self.wait_for_join(i, secure_network).await | ||
| 371 | } | 377 | } |
| 372 | 378 | ||
| 373 | async fn wait_for_join(&mut self, i: SsidInfo) -> Result<(), Error> { | 379 | async fn wait_for_join(&mut self, i: SsidInfo, secure_network: bool) -> Result<(), JoinError> { |
| 374 | self.events.mask.enable(&[Event::SET_SSID, Event::AUTH]); | 380 | self.events.mask.enable(&[Event::SET_SSID, Event::AUTH, Event::PSK_SUP]); |
| 375 | let mut subscriber = self.events.queue.subscriber().unwrap(); | 381 | let mut subscriber = self.events.queue.subscriber().unwrap(); |
| 376 | // the actual join operation starts here | 382 | // the actual join operation starts here |
| 377 | // we make sure to enable events before so we don't miss any | 383 | // we make sure to enable events before so we don't miss any |
| 378 | 384 | ||
| 379 | self.ioctl(IoctlType::Set, Ioctl::SetSsid, 0, &mut i.to_bytes()).await; | 385 | self.ioctl(IoctlType::Set, Ioctl::SetSsid, 0, &mut i.to_bytes()).await; |
| 380 | 386 | ||
| 381 | // to complete the join, we wait for a SET_SSID event | 387 | // To complete the join on an open network, we wait for a SET_SSID event with status SUCCESS |
| 382 | // we also save the AUTH status for the user, it may be interesting | 388 | // For secured networks, we wait for a PSK_SUP event with status 6 "UNSOLICITED" |
| 383 | let mut auth_status = 0; | 389 | let result = loop { |
| 384 | let status = loop { | ||
| 385 | let msg = subscriber.next_message_pure().await; | 390 | let msg = subscriber.next_message_pure().await; |
| 386 | if msg.header.event_type == Event::AUTH && msg.header.status != EStatus::SUCCESS { | 391 | |
| 387 | auth_status = msg.header.status; | 392 | let status = EStatus::from(msg.header.status as u8); |
| 388 | } else if msg.header.event_type == Event::SET_SSID { | 393 | match (msg.header.event_type, status, secure_network) { |
| 389 | // join operation ends with SET_SSID event | 394 | // Join operation ends with SET_SSID event for open networks |
| 390 | break msg.header.status; | 395 | (Event::SET_SSID, EStatus::SUCCESS, false) => break Ok(()), |
| 391 | } | 396 | (Event::SET_SSID, EStatus::NO_NETWORKS, _) => break Err(JoinError::NetworkNotFound), |
| 397 | (Event::SET_SSID, status, _) if status != EStatus::SUCCESS => { | ||
| 398 | break Err(JoinError::JoinFailure(status as u8)); | ||
| 399 | } | ||
| 400 | // Ignore PSK_SUP "ABORT" which is sometimes sent before successful join | ||
| 401 | (Event::PSK_SUP, EStatus::ABORT, true) => {} | ||
| 402 | // Event PSK_SUP with status 6 "UNSOLICITED" indicates success for secure networks | ||
| 403 | (Event::PSK_SUP, EStatus::UNSOLICITED, true) => break Ok(()), | ||
| 404 | // Events indicating authentication failure, possibly due to incorrect password | ||
| 405 | (Event::PSK_SUP, _, true) | (Event::AUTH, EStatus::FAIL, true) => { | ||
| 406 | break Err(JoinError::AuthenticationFailure); | ||
| 407 | } | ||
| 408 | _ => {} | ||
| 409 | }; | ||
| 392 | }; | 410 | }; |
| 393 | 411 | ||
| 394 | self.events.mask.disable_all(); | 412 | self.events.mask.disable_all(); |
| 395 | if status == EStatus::SUCCESS { | 413 | match result { |
| 396 | // successful join | 414 | Ok(()) => { |
| 397 | self.state_ch.set_link_state(LinkState::Up); | 415 | self.state_ch.set_link_state(LinkState::Up); |
| 398 | debug!("JOINED"); | 416 | debug!("JOINED"); |
| 399 | Ok(()) | 417 | } |
| 400 | } else { | 418 | Err(JoinError::JoinFailure(status)) => debug!("JOIN failed: status={}", status), |
| 401 | warn!("JOIN failed with status={} auth={}", status, auth_status); | 419 | Err(JoinError::NetworkNotFound) => debug!("JOIN failed: network not found"), |
| 402 | Err(Error { status }) | 420 | Err(JoinError::AuthenticationFailure) => debug!("JOIN failed: authentication failure"), |
| 403 | } | 421 | }; |
| 422 | |||
| 423 | result | ||
| 404 | } | 424 | } |
| 405 | 425 | ||
| 406 | /// Set GPIO pin on WiFi chip. | 426 | /// Set GPIO pin on WiFi chip. |
| @@ -436,6 +456,9 @@ impl<'a> Control<'a> { | |||
| 436 | // Set wifi up again | 456 | // Set wifi up again |
| 437 | self.up().await; | 457 | self.up().await; |
| 438 | 458 | ||
| 459 | // Disable authentication | ||
| 460 | self.ioctl_set_u32(Ioctl::SetAuth, 0, AUTH_OPEN).await; | ||
| 461 | |||
| 439 | // Turn on AP mode | 462 | // Turn on AP mode |
| 440 | self.ioctl_set_u32(Ioctl::SetAp, 0, 1).await; | 463 | self.ioctl_set_u32(Ioctl::SetAp, 0, 1).await; |
| 441 | 464 | ||
| @@ -470,8 +493,6 @@ impl<'a> Control<'a> { | |||
| 470 | pfi.passphrase[..passphrase.as_bytes().len()].copy_from_slice(passphrase.as_bytes()); | 493 | pfi.passphrase[..passphrase.as_bytes().len()].copy_from_slice(passphrase.as_bytes()); |
| 471 | self.ioctl(IoctlType::Set, Ioctl::SetWsecPmk, 0, &mut pfi.to_bytes()) | 494 | self.ioctl(IoctlType::Set, Ioctl::SetWsecPmk, 0, &mut pfi.to_bytes()) |
| 472 | .await; | 495 | .await; |
| 473 | } else { | ||
| 474 | self.ioctl_set_u32(Ioctl::SetAuth, 0, 0).await; | ||
| 475 | } | 496 | } |
| 476 | 497 | ||
| 477 | // Change mutlicast rate from 1 Mbps to 11 Mbps | 498 | // Change mutlicast rate from 1 Mbps to 11 Mbps |
| @@ -547,6 +568,14 @@ impl<'a> Control<'a> { | |||
| 547 | n | 568 | n |
| 548 | } | 569 | } |
| 549 | 570 | ||
| 571 | /// Retrieve the latest RSSI value | ||
| 572 | pub async fn get_rssi(&mut self) -> i32 { | ||
| 573 | let mut rssi_buf = [0u8; 4]; | ||
| 574 | let n = self.ioctl(IoctlType::Get, Ioctl::GetRssi, 0, &mut rssi_buf).await; | ||
| 575 | assert_eq!(n, 4); | ||
| 576 | i32::from_ne_bytes(rssi_buf) | ||
| 577 | } | ||
| 578 | |||
| 550 | async fn set_iovar_u32x2(&mut self, name: &str, val1: u32, val2: u32) { | 579 | async fn set_iovar_u32x2(&mut self, name: &str, val1: u32, val2: u32) { |
| 551 | let mut buf = [0; 8]; | 580 | let mut buf = [0; 8]; |
| 552 | buf[0..4].copy_from_slice(&val1.to_le_bytes()); | 581 | buf[0..4].copy_from_slice(&val1.to_le_bytes()); |
