From 57e572ca12182007d0dc421e4406a4a0a4695d99 Mon Sep 17 00:00:00 2001 From: Simon Börjesson Date: Mon, 8 Dec 2025 23:41:19 +0100 Subject: Improve cyw43 join handling --- cyw43/src/consts.rs | 4 ++- cyw43/src/control.rs | 73 +++++++++++++++++++++++++++++++++------------------- cyw43/src/lib.rs | 2 +- 3 files changed, 50 insertions(+), 29 deletions(-) (limited to 'cyw43') diff --git a/cyw43/src/consts.rs b/cyw43/src/consts.rs index c3f0dbfd8..e561d4794 100644 --- a/cyw43/src/consts.rs +++ b/cyw43/src/consts.rs @@ -177,9 +177,11 @@ pub(crate) enum Security { } #[allow(non_camel_case_types)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq, num_enum::FromPrimitive)] #[repr(u8)] pub enum EStatus { + #[num_enum(default)] + Unknown = 0xFF, /// operation was successful SUCCESS = 0, /// operation failed diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index 219198d1f..98f456ce4 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -12,11 +12,15 @@ use crate::ioctl::{IoctlState, IoctlType}; use crate::structs::*; use crate::{PowerManagementMode, countries, events}; -/// Control errors. +/// Join errors. #[derive(Debug)] -pub struct Error { - /// Status code. - pub status: u32, +pub enum JoinError { + /// Network not found. + NetworkNotFound, + /// Failure to join network. Contains the status code from the SET_SSID event. + JoinFailure(u8), + /// Authentication failure for a secure network. + AuthenticationFailure, } /// Multicast errors. @@ -296,7 +300,7 @@ impl<'a> Control<'a> { } /// Join a network with the provided SSID using the specified options. - pub async fn join(&mut self, ssid: &str, options: JoinOptions<'_>) -> Result<(), Error> { + pub async fn join(&mut self, ssid: &str, options: JoinOptions<'_>) -> Result<(), JoinError> { self.set_iovar_u32("ampdu_ba_wsize", 8).await; if options.auth == JoinAuth::Open { @@ -367,40 +371,55 @@ impl<'a> Control<'a> { }; i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes()); - self.wait_for_join(i).await + let secure_network = options.auth != JoinAuth::Open; + self.wait_for_join(i, secure_network).await } - async fn wait_for_join(&mut self, i: SsidInfo) -> Result<(), Error> { - self.events.mask.enable(&[Event::SET_SSID, Event::AUTH]); + async fn wait_for_join(&mut self, i: SsidInfo, secure_network: bool) -> Result<(), JoinError> { + self.events.mask.enable(&[Event::SET_SSID, Event::AUTH, Event::PSK_SUP]); let mut subscriber = self.events.queue.subscriber().unwrap(); // the actual join operation starts here // we make sure to enable events before so we don't miss any self.ioctl(IoctlType::Set, Ioctl::SetSsid, 0, &mut i.to_bytes()).await; - // to complete the join, we wait for a SET_SSID event - // we also save the AUTH status for the user, it may be interesting - let mut auth_status = 0; - let status = loop { + // To complete the join on an open network, we wait for a SET_SSID event with status SUCCESS + // For secured networks, we wait for a PSK_SUP event with status 6 "UNSOLICITED" + let result = loop { let msg = subscriber.next_message_pure().await; - if msg.header.event_type == Event::AUTH && msg.header.status != EStatus::SUCCESS { - auth_status = msg.header.status; - } else if msg.header.event_type == Event::SET_SSID { - // join operation ends with SET_SSID event - break msg.header.status; - } + + let status = EStatus::from(msg.header.status as u8); + match (msg.header.event_type, status, secure_network) { + // Join operation ends with SET_SSID event for open networks + (Event::SET_SSID, EStatus::SUCCESS, false) => break Ok(()), + (Event::SET_SSID, EStatus::NO_NETWORKS, _) => break Err(JoinError::NetworkNotFound), + (Event::SET_SSID, status, _) if status != EStatus::SUCCESS => { + break Err(JoinError::JoinFailure(status as u8)); + } + // Ignore PSK_SUP "ABORT" which is sometimes sent before successful join + (Event::PSK_SUP, EStatus::ABORT, true) => {} + // Event PSK_SUP with status 6 "UNSOLICITED" indicates success for secure networks + (Event::PSK_SUP, EStatus::UNSOLICITED, true) => break Ok(()), + // Events indicating authentication failure, possibly due to incorrect password + (Event::PSK_SUP, _, true) | (Event::AUTH, EStatus::FAIL, true) => { + break Err(JoinError::AuthenticationFailure); + } + _ => {} + }; }; self.events.mask.disable_all(); - if status == EStatus::SUCCESS { - // successful join - self.state_ch.set_link_state(LinkState::Up); - debug!("JOINED"); - Ok(()) - } else { - warn!("JOIN failed with status={} auth={}", status, auth_status); - Err(Error { status }) - } + match result { + Ok(()) => { + self.state_ch.set_link_state(LinkState::Up); + debug!("JOINED"); + } + Err(JoinError::JoinFailure(status)) => debug!("JOIN failed: status={}", status), + Err(JoinError::NetworkNotFound) => debug!("JOIN failed: network not found"), + Err(JoinError::AuthenticationFailure) => debug!("JOIN failed: authentication failure"), + }; + + result } /// Set GPIO pin on WiFi chip. diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs index 82c636346..d723037c7 100644 --- a/cyw43/src/lib.rs +++ b/cyw43/src/lib.rs @@ -31,7 +31,7 @@ use ioctl::IoctlState; use crate::bus::Bus; pub use crate::bus::SpiBusCyw43; pub use crate::control::{ - AddMulticastAddressError, Control, Error as ControlError, JoinAuth, JoinOptions, ScanOptions, ScanType, Scanner, + AddMulticastAddressError, Control, JoinError, JoinAuth, JoinOptions, ScanOptions, ScanType, Scanner, }; pub use crate::runner::Runner; pub use crate::structs::BssInfo; -- cgit