aboutsummaryrefslogtreecommitdiff
path: root/cyw43/src/control.rs
diff options
context:
space:
mode:
authorSimon Börjesson <[email protected]>2025-12-08 23:41:19 +0100
committerSimon Börjesson <[email protected]>2025-12-08 23:41:19 +0100
commit57e572ca12182007d0dc421e4406a4a0a4695d99 (patch)
tree37bfee25078595bdac922d5f9ecb20d950e06e07 /cyw43/src/control.rs
parent95fd1f46a2c44f961e27f48920d87468d39a3793 (diff)
Improve cyw43 join handling
Diffstat (limited to 'cyw43/src/control.rs')
-rw-r--r--cyw43/src/control.rs73
1 files changed, 46 insertions, 27 deletions
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};
12use crate::structs::*; 12use crate::structs::*;
13use crate::{PowerManagementMode, countries, events}; 13use crate::{PowerManagementMode, countries, events};
14 14
15/// Control errors. 15/// Join errors.
16#[derive(Debug)] 16#[derive(Debug)]
17pub struct Error { 17pub enum JoinError {
18 /// Status code. 18 /// Network not found.
19 pub status: u32, 19 NetworkNotFound,
20 /// Failure to join network. Contains the status code from the SET_SSID event.
21 JoinFailure(u8),
22 /// Authentication failure for a secure network.
23 AuthenticationFailure,
20} 24}
21 25
22/// Multicast errors. 26/// Multicast errors.
@@ -296,7 +300,7 @@ impl<'a> Control<'a> {
296 } 300 }
297 301
298 /// Join a network with the provided SSID using the specified options. 302 /// Join a network with the provided SSID using the specified options.
299 pub async fn join(&mut self, ssid: &str, options: JoinOptions<'_>) -> Result<(), Error> { 303 pub async fn join(&mut self, ssid: &str, options: JoinOptions<'_>) -> Result<(), JoinError> {
300 self.set_iovar_u32("ampdu_ba_wsize", 8).await; 304 self.set_iovar_u32("ampdu_ba_wsize", 8).await;
301 305
302 if options.auth == JoinAuth::Open { 306 if options.auth == JoinAuth::Open {
@@ -367,40 +371,55 @@ impl<'a> Control<'a> {
367 }; 371 };
368 i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes()); 372 i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes());
369 373
370 self.wait_for_join(i).await 374 let secure_network = options.auth != JoinAuth::Open;
375 self.wait_for_join(i, secure_network).await
371 } 376 }
372 377
373 async fn wait_for_join(&mut self, i: SsidInfo) -> Result<(), Error> { 378 async fn wait_for_join(&mut self, i: SsidInfo, secure_network: bool) -> Result<(), JoinError> {
374 self.events.mask.enable(&[Event::SET_SSID, Event::AUTH]); 379 self.events.mask.enable(&[Event::SET_SSID, Event::AUTH, Event::PSK_SUP]);
375 let mut subscriber = self.events.queue.subscriber().unwrap(); 380 let mut subscriber = self.events.queue.subscriber().unwrap();
376 // the actual join operation starts here 381 // the actual join operation starts here
377 // we make sure to enable events before so we don't miss any 382 // we make sure to enable events before so we don't miss any
378 383
379 self.ioctl(IoctlType::Set, Ioctl::SetSsid, 0, &mut i.to_bytes()).await; 384 self.ioctl(IoctlType::Set, Ioctl::SetSsid, 0, &mut i.to_bytes()).await;
380 385
381 // to complete the join, we wait for a SET_SSID event 386 // 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 387 // For secured networks, we wait for a PSK_SUP event with status 6 "UNSOLICITED"
383 let mut auth_status = 0; 388 let result = loop {
384 let status = loop {
385 let msg = subscriber.next_message_pure().await; 389 let msg = subscriber.next_message_pure().await;
386 if msg.header.event_type == Event::AUTH && msg.header.status != EStatus::SUCCESS { 390
387 auth_status = msg.header.status; 391 let status = EStatus::from(msg.header.status as u8);
388 } else if msg.header.event_type == Event::SET_SSID { 392 match (msg.header.event_type, status, secure_network) {
389 // join operation ends with SET_SSID event 393 // Join operation ends with SET_SSID event for open networks
390 break msg.header.status; 394 (Event::SET_SSID, EStatus::SUCCESS, false) => break Ok(()),
391 } 395 (Event::SET_SSID, EStatus::NO_NETWORKS, _) => break Err(JoinError::NetworkNotFound),
396 (Event::SET_SSID, status, _) if status != EStatus::SUCCESS => {
397 break Err(JoinError::JoinFailure(status as u8));
398 }
399 // Ignore PSK_SUP "ABORT" which is sometimes sent before successful join
400 (Event::PSK_SUP, EStatus::ABORT, true) => {}
401 // Event PSK_SUP with status 6 "UNSOLICITED" indicates success for secure networks
402 (Event::PSK_SUP, EStatus::UNSOLICITED, true) => break Ok(()),
403 // Events indicating authentication failure, possibly due to incorrect password
404 (Event::PSK_SUP, _, true) | (Event::AUTH, EStatus::FAIL, true) => {
405 break Err(JoinError::AuthenticationFailure);
406 }
407 _ => {}
408 };
392 }; 409 };
393 410
394 self.events.mask.disable_all(); 411 self.events.mask.disable_all();
395 if status == EStatus::SUCCESS { 412 match result {
396 // successful join 413 Ok(()) => {
397 self.state_ch.set_link_state(LinkState::Up); 414 self.state_ch.set_link_state(LinkState::Up);
398 debug!("JOINED"); 415 debug!("JOINED");
399 Ok(()) 416 }
400 } else { 417 Err(JoinError::JoinFailure(status)) => debug!("JOIN failed: status={}", status),
401 warn!("JOIN failed with status={} auth={}", status, auth_status); 418 Err(JoinError::NetworkNotFound) => debug!("JOIN failed: network not found"),
402 Err(Error { status }) 419 Err(JoinError::AuthenticationFailure) => debug!("JOIN failed: authentication failure"),
403 } 420 };
421
422 result
404 } 423 }
405 424
406 /// Set GPIO pin on WiFi chip. 425 /// Set GPIO pin on WiFi chip.