blob: 34e6239bb55fbad7237496a72dec8ab29512ee17 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO(fxbug.dev/74991): This test should be implemented using the Policy API (instead of directly
// interacting with SME). However, Policy cannot yet manage multiple client
// interfaces. Parts of the test pause so that Policy can detect the SME
// clients and request startup disconnects before the test continues to
// manipulate their state. When the Policy API can be used, reimplement this
// test with it (and remove the pauses).
use {
anyhow::format_err,
fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_common_security as fidl_security,
fidl_fuchsia_wlan_device_service::DeviceServiceMarker,
fidl_fuchsia_wlan_ieee80211 as fidl_ieee80211,
fidl_fuchsia_wlan_sme::{self as fidl_sme, ClientSmeProxy, ConnectRequest},
fuchsia_async as fasync,
fuchsia_component::client::connect_to_protocol,
fuchsia_zircon::DurationNum,
futures::{
channel::oneshot, future, join, stream::TryStreamExt, FutureExt, StreamExt, TryFutureExt,
},
pin_utils::pin_mut,
std::{panic, thread, time},
wlan_common::{bss::Protection::Open, fake_fidl_bss_description, TimeUnit},
wlan_hw_sim::*,
};
pub const CLIENT1_MAC_ADDR: [u8; 6] = [0x68, 0x62, 0x6f, 0x6e, 0x69, 0x6c];
pub const CLIENT2_MAC_ADDR: [u8; 6] = [0x68, 0x62, 0x6f, 0x6e, 0x69, 0x6d];
async fn connect(
client_sme: &ClientSmeProxy,
req: &mut ConnectRequest,
) -> Result<(), anyhow::Error> {
let (local, remote) = fidl::endpoints::create_proxy()?;
client_sme.connect(req, Some(remote))?;
let mut stream = local.take_event_stream();
if let Some(event) = stream.try_next().await? {
match event {
fidl_sme::ConnectTransactionEvent::OnConnectResult { result } => {
if result.code == fidl_ieee80211::StatusCode::Success {
return Ok(());
}
return Err(format_err!("connect failed with error code: {:?}", result.code));
}
other => {
return Err(format_err!(
"Expected ConnectTransactionEvent::OnConnectResult event, got {:?}",
other
))
}
}
}
Err(format_err!("Server closed the ConnectTransaction channel before sending a response"))
}
// TODO(fxbug.dev/91118) - Added to help investigate hw-sim test. Remove later
async fn canary(mut finish_receiver: oneshot::Receiver<()>) {
let mut interval_stream = fasync::Interval::new(fasync::Duration::from_seconds(1));
loop {
futures::select! {
_ = interval_stream.next() => {
log::info!("1 second canary");
}
_ = finish_receiver => {
return;
}
}
}
}
/// Spawn two client and one AP wlantap devices. Verify that both clients connect to the AP by
/// sending ethernet frames.
#[fuchsia_async::run_singlethreaded(test)]
async fn multiple_clients_ap() {
init_syslog();
let wlanstack_svc =
connect_to_protocol::<DeviceServiceMarker>().expect("connecting to wlanstack service");
let network_config = NetworkConfigBuilder::open().ssid(&AP_SSID);
let mut dc = CreateDeviceHelper::new(&wlanstack_svc);
let (mut ap_helper, _) = dc
.create_device(default_wlantap_config_ap(), Some(network_config))
.await
.expect("create ap");
let ap_proxy = ap_helper.proxy();
let (mut client1_helper, client1_iface_id) = dc
.create_device(wlantap_config_client(format!("wlantap-client-1"), CLIENT1_MAC_ADDR), None)
.await
.expect("create client1");
let client1_proxy = client1_helper.proxy();
let client1_sme = get_client_sme(&wlanstack_svc, client1_iface_id).await;
let (client1_confirm_sender, client1_confirm_receiver) = oneshot::channel();
let (mut client2_helper, client2_iface_id) = dc
.create_device(wlantap_config_client(format!("wlantap-client-2"), CLIENT2_MAC_ADDR), None)
.await
.expect("create client2");
let client2_proxy = client2_helper.proxy();
let client2_sme = get_client_sme(&wlanstack_svc, client2_iface_id).await;
let (client2_confirm_sender, client2_confirm_receiver) = oneshot::channel();
let (finish_sender, finish_receiver) = oneshot::channel();
let ap_fut = ap_helper
.run_until_complete_or_timeout(
std::i64::MAX.nanos(),
"serving as an AP",
EventHandlerBuilder::new()
.on_debug_name("ap")
.on_tx(
Sequence::start()
.then(Rx::send(&client1_proxy, WLANCFG_DEFAULT_AP_CHANNEL))
.then(Rx::send(&client2_proxy, WLANCFG_DEFAULT_AP_CHANNEL)),
)
.build(),
future::join(client1_confirm_receiver, client2_confirm_receiver).then(|_| {
finish_sender.send(()).expect("sending finish notification");
future::ok(())
}),
)
.unwrap_or_else(|oneshot::Canceled| panic!("waiting for connect confirmation"));
// Start client 1
let mut client1_connect_req = ConnectRequest {
ssid: AP_SSID.to_vec(),
bss_description: fake_fidl_bss_description!(
Open,
ssid: AP_SSID.clone(),
bssid: AP_MAC_ADDR.0,
// Unrealistically long beacon period so that connect doesn't timeout on slow bots.
beacon_period: TimeUnit::DEFAULT_BEACON_INTERVAL.0 * 20u16,
channel: WLANCFG_DEFAULT_AP_CHANNEL.into(),
),
authentication: fidl_security::Authentication {
protocol: fidl_security::Protocol::Open,
credentials: None,
},
deprecated_scan_type: fidl_common::ScanType::Passive,
multiple_bss_candidates: false, // only used for metrics, select arbitrary value
};
let client1_connect_fut = connect(&client1_sme, &mut client1_connect_req);
pin_mut!(client1_connect_fut);
thread::sleep(time::Duration::from_secs(3)); // Wait for the policy layer. See fxbug.dev/74991.
let client1_fut = client1_helper
.run_until_complete_or_timeout(
std::i64::MAX.nanos(),
"connecting to AP",
EventHandlerBuilder::new()
.on_debug_name("client1")
.on_set_channel(
Beacon::send_on_primary_channel(
WLANCFG_DEFAULT_AP_CHANNEL.primary,
&client1_proxy,
)
.bssid(AP_MAC_ADDR)
.ssid(&AP_SSID)
.protection(Open),
)
.on_tx(Rx::send(&ap_proxy, WLANCFG_DEFAULT_AP_CHANNEL))
.build(),
client1_connect_fut.and_then(|()| {
client1_confirm_sender.send(()).expect("sending confirmation");
future::ok(())
}),
)
.unwrap_or_else(|e| panic!("waiting for connect confirmation: {:?}", e));
// Start client 2
let mut client2_connect_req = ConnectRequest {
ssid: AP_SSID.to_vec(),
bss_description: fake_fidl_bss_description!(
Open,
ssid: AP_SSID.clone(),
bssid: AP_MAC_ADDR.0,
// Unrealistically long beacon period so that connect doesn't timeout on slow bots.
beacon_period: TimeUnit::DEFAULT_BEACON_INTERVAL.0 * 20u16,
channel: WLANCFG_DEFAULT_AP_CHANNEL.into(),
),
authentication: fidl_security::Authentication {
protocol: fidl_security::Protocol::Open,
credentials: None,
},
deprecated_scan_type: fidl_common::ScanType::Passive,
multiple_bss_candidates: false, // only used for metrics, select arbitrary value
};
let client2_connect_fut = connect(&client2_sme, &mut client2_connect_req);
pin_mut!(client2_connect_fut);
thread::sleep(time::Duration::from_secs(3)); // Wait for the policy layer. See fxbug.dev/74991.
let client2_fut = client2_helper
.run_until_complete_or_timeout(
std::i64::MAX.nanos(),
"connecting to AP",
EventHandlerBuilder::new()
.on_debug_name("client2")
.on_set_channel(
Beacon::send_on_primary_channel(
WLANCFG_DEFAULT_AP_CHANNEL.primary,
&client2_proxy,
)
.bssid(AP_MAC_ADDR)
.ssid(&AP_SSID)
.protection(Open),
)
.on_tx(Rx::send(&ap_proxy, WLANCFG_DEFAULT_AP_CHANNEL))
.build(),
client2_connect_fut.and_then(|()| {
client2_confirm_sender.send(()).expect("sending confirmation");
future::ok(())
}),
)
.unwrap_or_else(|e| panic!("waiting for connect confirmation: {:?}", e));
join!(ap_fut, client1_fut, client2_fut, canary(finish_receiver));
client1_helper.stop().await;
client2_helper.stop().await;
ap_helper.stop().await;
}