blob: 23f8ba0c379a8f303269503a504278feeff15175 [file] [log] [blame]
// Copyright 2018 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.
#![deny(warnings)]
#[macro_use] extern crate bitfield;
extern crate byteorder;
extern crate failure;
extern crate fuchsia_app as app;
extern crate fuchsia_async as async;
extern crate fuchsia_zircon as zx;
extern crate wlantap_client;
extern crate fidl_fuchsia_wlan_device as wlan_device;
extern crate fidl_fuchsia_wlan_service as fidl_wlan_service;
extern crate fidl_fuchsia_wlan_tap as wlantap;
extern crate futures;
use futures::prelude::*;
use std::sync::{Arc, Mutex};
use wlantap_client::Wlantap;
use zx::prelude::*;
mod mac_frames;
#[cfg(test)]
mod test_utils;
fn create_2_4_ghz_band_info() -> wlan_device::BandInfo {
wlan_device::BandInfo{
description: String::from("2.4 GHz"),
ht_caps: wlan_device::HtCapabilities{
ht_capability_info: 0x01fe,
ampdu_params: 0,
supported_mcs_set: [
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0xff, 0, 0, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0, 0, 0
],
ht_ext_capabilities: 0,
tx_beamforming_capabilities: 0,
asel_capabilities: 0
},
vht_caps: None,
basic_rates: vec![2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108],
supported_channels: wlan_device::ChannelList{
base_freq: 2407,
channels: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
}
}
}
fn create_wlantap_config() -> wlantap::WlantapPhyConfig {
use wlan_device::SupportedPhy;
wlantap::WlantapPhyConfig {
phy_info: wlan_device::PhyInfo{
id: 0,
dev_path: None,
hw_mac_address: [ 0x67, 0x62, 0x6f, 0x6e, 0x69, 0x6b ],
supported_phys: vec![
SupportedPhy::Dsss, SupportedPhy::Cck, SupportedPhy::Ofdm, SupportedPhy::Ht
],
driver_features: vec![],
mac_roles: vec![wlan_device::MacRole::Client],
caps: vec![],
bands: vec![
create_2_4_ghz_band_info()
]
},
name: String::from("wlantap0")
}
}
struct State {
current_channel: wlan_device::Channel,
frame_buf: Vec<u8>,
}
impl State {
fn new() -> Self {
Self {
current_channel: wlan_device::Channel {
primary: 0,
cbw: 0,
secondary80: 0
},
frame_buf: vec![]
}
}
}
fn send_beacon(frame_buf: &mut Vec<u8>, channel: &wlan_device::Channel, bss_id: &[u8; 6],
ssid: &str, proxy: &wlantap::WlantapPhyProxy)
-> Result<(), failure::Error>
{
frame_buf.clear();
mac_frames::MacFrameWriter::<&mut Vec<u8>>::new(frame_buf)
.beacon(
&mac_frames::MgmtHeader{
frame_control: mac_frames::FrameControl(0), // will be filled automatically
duration: 0,
addr1: mac_frames::BROADCAST_ADDR.clone(),
addr2: bss_id.clone(),
addr3: bss_id.clone(),
seq_control: mac_frames::SeqControl {
frag_num: 0,
seq_num: 123
},
ht_control: None
},
&mac_frames::BeaconFields{
timestamp: 0,
beacon_interval: 100,
capability_info: 0,
})?
.ssid(ssid.as_bytes())?
.supported_rates(&[0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24])?
.dsss_parameter_set(channel.primary)?;
let rx_info = &mut wlantap::WlanRxInfo {
rx_flags: 0,
valid_fields: 0,
phy: 0,
data_rate: 0,
chan: wlan_device::Channel { // TODO(FIDL-54): use clone()
primary: channel.primary,
cbw: channel.cbw,
secondary80: channel.secondary80
},
mcs: 0,
rssi_dbm: 0,
rcpi_dbmh: 0,
snr_dbh: 0,
};
proxy.rx(0, &mut frame_buf.iter().cloned(), rx_info)?;
Ok(())
}
fn main() -> Result<(), failure::Error> {
let mut exec = async::Executor::new()?;
let wlantap = Wlantap::open()?;
let state = Arc::new(Mutex::new(State::new()));
let proxy = wlantap.create_phy(create_wlantap_config())?;
let event_listener = {
let state = state.clone();
proxy.take_event_stream().for_each(move |event| {
match event {
wlantap::WlantapPhyEvent::SetChannel{ args } => {
let mut state = state.lock().unwrap();
state.current_channel = args.chan;
println!("setting channel to {:?}", state.current_channel);
},
_ => {}
}
Ok(())
})
.map(|_| ())
.recover(|e| eprintln!("error running wlantap event listener: {:?}", e))
};
let beacon_timer = async::Interval::<zx::Status>::new(102_400_000.nanos())
.for_each(move |_| {
let state = &mut *state.lock().map_err(|e| {
eprintln!("beacon timer callback: Failed to lock mutex: {:?}", e);
zx::Status::INTERNAL
})?;
if state.current_channel.primary == 6 {
eprintln!("sending beacon!");
send_beacon(&mut state.frame_buf, &state.current_channel,
&[0x62, 0x73, 0x73, 0x62, 0x73, 0x73], "fakenet", &proxy).unwrap();
}
Ok(())
})
.map(|_| ())
.recover::<Never, _>(|e| eprintln!("error running beacon timer: {:?}", e));
// Unwrap is OK since the error type is Never, which doesn't work with '?'
exec.run_singlethreaded(event_listener.join(beacon_timer)).unwrap();
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
const BSS_FOO: [u8; 6] = [0x62, 0x73, 0x73, 0x66, 0x6f, 0x6f];
const SSID_FOO: &str = "foo";
const BSS_BAR: [u8; 6] = [0x62, 0x73, 0x73, 0x62, 0x61, 0x72];
const SSID_BAR: &str = "bar";
const BSS_BAZ: [u8; 6] = [0x62, 0x73, 0x73, 0x62, 0x61, 0x7a];
const SSID_BAZ: &str = "baz";
#[test]
fn simulate_scan() {
let mut exec = async::Executor::new().expect("Failed to create an executor");
let mut helper = test_utils::TestHelper::begin_test(&mut exec, create_wlantap_config());
let wlan_service = app::client::connect_to_service::<fidl_wlan_service::WlanMarker>()
.expect("Failed to connect to wlan service");
let proxy = helper.proxy();
let scan_result = scan(&mut exec, &wlan_service, &proxy, &mut helper);
assert_eq!(fidl_wlan_service::ErrCode::Ok, scan_result.error.code,
"The error message was: {}", scan_result.error.description);
let mut aps:Vec<_> = scan_result.aps.expect("Got empty scan results")
.into_iter().map(|ap| (ap.ssid, ap.bssid)).collect();
aps.sort();
let mut expected_aps = [
( SSID_FOO.to_string(), BSS_FOO.to_vec() ),
( SSID_BAR.to_string(), BSS_BAR.to_vec() ),
( SSID_BAZ.to_string(), BSS_BAZ.to_vec() ),
];
expected_aps.sort();
assert_eq!(&expected_aps, &aps[..]);
}
fn scan(exec: &mut async::Executor,
wlan_service: &fidl_wlan_service::WlanProxy,
phy: &wlantap::WlantapPhyProxy,
helper: &mut test_utils::TestHelper) -> fidl_wlan_service::ScanResult {
let mut wlanstack_retry = test_utils::RetryWithBackoff::new(1.seconds());
loop {
let scan_result = helper.run(exec, 10.seconds(), "receive a scan response",
|event| {
match event {
wlantap::WlantapPhyEvent::SetChannel { args } => {
println!("set channel to {:?}", args.chan);
if args.chan.primary == 1 {
send_beacon(&mut vec![], &args.chan, &BSS_FOO, SSID_FOO, &phy)
.unwrap();
} else if args.chan.primary == 6 {
send_beacon(&mut vec![], &args.chan, &BSS_BAR, SSID_BAR, &phy)
.unwrap();
} else if args.chan.primary == 11 {
send_beacon(&mut vec![], &args.chan, &BSS_BAZ, SSID_BAZ, &phy)
.unwrap();
}
},
_ => {}
}
},
wlan_service.scan(&mut fidl_wlan_service::ScanRequest { timeout: 5 })).unwrap();
if scan_result.error.code == fidl_wlan_service::ErrCode::NotFound {
let slept = wlanstack_retry.sleep_unless_timed_out();
assert!(slept, "Wlanstack did not recognize the interface in time");
} else {
return scan_result;
}
}
}
}