use alloc::{boxed::Box, sync::Arc, vec::Vec};
use core::{sync::atomic::Ordering, task::Poll};
use crate::fdrv::{
core::bus::{BusState, WifiBus},
protocol::{send_me_sta_add_req, send_set_control_port_req},
thread::tx::enqueue_mgmt_frame,
};
pub fn start(bus: Arc<WifiBus>) {
log::debug!("[wifi-ap] worker thread starting");
crate::runtime::runtime().spawn_poll_task(
"wifi-ap",
Box::new(move |cx| {
if *bus.state.lock() == BusState::Down {
return Poll::Ready(());
}
loop {
let assoc_req = bus.ap.assoc_queue.lock().pop_front();
match assoc_req {
Some(mpdu) => handle_assoc_req(&bus, &mpdu),
None => break,
}
}
bus.ap.assoc_pollset.register(cx.waker());
if !bus.ap.assoc_queue.lock().is_empty() {
cx.waker().wake_by_ref();
}
Poll::Pending
}),
);
}
fn handle_assoc_req(bus: &Arc<WifiBus>, mpdu: &[u8]) {
if mpdu.len() < 28 {
return;
}
let mut sta_mac = [0u8; 6];
sta_mac.copy_from_slice(&mpdu[10..16]);
let vif_idx = bus.conn.vif_idx.load(Ordering::Acquire);
let aid: u16 = 1;
let rates = parse_supported_rates(&mpdu[28..]);
let sta_idx = match send_me_sta_add_req(bus, &sta_mac, &rates, aid, vif_idx, 0) {
Ok(idx) => idx,
Err(e) => {
log::warn!("[wifi-ap] ME_STA_ADD failed: {:?}", e);
return;
}
};
bus.conn.sta_idx.store(sta_idx, Ordering::Release);
log::info!(
"[wifi-ap] STA {:02x?} registered: sta_idx={}, aid={}",
sta_mac,
sta_idx,
aid
);
let ap_mac = match *bus.conn.sta_mac.lock() {
Some(m) => m,
None => {
log::warn!("[wifi-ap] no AP mac, cannot send Assoc Response");
return;
}
};
let frame = build_assoc_response(&sta_mac, &ap_mac, aid, &rates);
match enqueue_mgmt_frame(bus, frame) {
Ok(()) => log::info!("[wifi-ap] Assoc Response queued -> {:02x?}", sta_mac),
Err(e) => log::warn!("[wifi-ap] Assoc Response enqueue failed: {:?}", e),
}
match send_set_control_port_req(bus, sta_idx, true, 0) {
Ok(_) => log::info!("[wifi-ap] control port OPENED for sta_idx={}", sta_idx),
Err(e) => log::warn!("[wifi-ap] open control port failed: {:?}", e),
}
}
fn parse_supported_rates(ies: &[u8]) -> Vec<u8> {
let mut i = 0;
while i + 2 <= ies.len() {
let eid = ies[i];
let len = ies[i + 1] as usize;
if i + 2 + len > ies.len() {
break;
}
if eid == 1 {
return ies[i + 2..i + 2 + len].to_vec();
}
i += 2 + len;
}
Vec::from([0x82, 0x84, 0x8b, 0x96])
}
fn build_assoc_response(dst: &[u8; 6], ap_mac: &[u8; 6], aid: u16, rates: &[u8]) -> Vec<u8> {
let mut f = Vec::with_capacity(40);
f.extend_from_slice(&[0x10, 0x00]); f.extend_from_slice(&[0x00, 0x00]); f.extend_from_slice(dst); f.extend_from_slice(ap_mac); f.extend_from_slice(ap_mac); f.extend_from_slice(&[0x00, 0x00]);
f.extend_from_slice(&0x0021u16.to_le_bytes());
f.extend_from_slice(&0u16.to_le_bytes());
f.extend_from_slice(&(aid | 0xC000).to_le_bytes());
let n = rates.len().min(8);
f.push(1);
f.push(n as u8);
f.extend_from_slice(&rates[..n]);
f
}