[wlan-hw-sim] Add Ethernet rx test
Test: Test-only change.
WLAN-350 #progress
Change-Id: I96b927c5b7eb347fed6d0b139eb3c1f748759966
diff --git a/bin/wlan/wlan-hw-sim/src/eth_frames.rs b/bin/wlan/wlan-hw-sim/src/eth_frames.rs
index 2010fe9..d8db6bb 100644
--- a/bin/wlan/wlan-hw-sim/src/eth_frames.rs
+++ b/bin/wlan/wlan-hw-sim/src/eth_frames.rs
@@ -3,7 +3,7 @@
// found in the LICENSE file.
use {
- byteorder::{LittleEndian, WriteBytesExt},
+ byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt},
std::io,
};
@@ -19,6 +19,18 @@
pub src: [u8; 6],
pub eth_type: u16,
}
+
+impl EthHeader {
+ pub fn from_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
+ let mut dst = [0u8; 6];
+ reader.read(&mut dst)?;
+ let mut src = [0u8; 6];
+ reader.read(&mut src)?;
+ let eth_type = reader.read_u16::<LittleEndian>()?;
+ Ok(Self { dst, src, eth_type})
+ }
+}
+
pub fn write_eth_header<W: io::Write>(w: &mut W, header: &EthHeader) -> io::Result<()> {
w.write_all(&header.dst)?;
w.write_all(&header.src)?;
@@ -31,7 +43,7 @@
use super::*;
#[test]
- fn simple_eth() {
+ fn simple_eth_header() {
let mut buf = vec![];
write_eth_header(&mut buf, &EthHeader{
dst: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06],
@@ -49,4 +61,17 @@
];
assert_eq!(expected_frame, &buf[..]);
}
+
+ #[test]
+ fn parse_eth_header() {
+ let mut bytes = &[
+ 0x01u8, 0x02, 0x03, 0x04, 0x05, 0x06, // dst
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // src
+ 0x00, 0x08, // ether_type
+ ] as &[u8];
+ let eth_header = EthHeader::from_reader(&mut bytes).expect("reading eth_header");
+ assert_eq!(eth_header.dst, [0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
+ assert_eq!(eth_header.src, [0x11, 0x12, 0x13, 0x14, 0x15, 0x16]);
+ assert_eq!(eth_header.eth_type, EtherType::Ipv4 as u16);
+ }
}
diff --git a/bin/wlan/wlan-hw-sim/src/mac_frames.rs b/bin/wlan/wlan-hw-sim/src/mac_frames.rs
index 5ff2440..f2e0921 100644
--- a/bin/wlan/wlan-hw-sim/src/mac_frames.rs
+++ b/bin/wlan/wlan-hw-sim/src/mac_frames.rs
@@ -156,11 +156,11 @@
// IETF RFC 1042
#[derive(Clone, Copy, Debug)]
pub struct LlcHeader {
- dsap: u8,
- ssap: u8,
- control: u8,
- oui: [u8; 3],
- protocol_id: u16,
+ pub dsap: u8,
+ pub ssap: u8,
+ pub control: u8,
+ pub oui: [u8; 3],
+ pub protocol_id: u16,
}
#[cfg(test)]
@@ -284,6 +284,52 @@
}
Ok(())
}
+
+ #[cfg(test)]
+ pub fn data(mut self, data_header: &DataHeader, llc_header: &LlcHeader, payload: &[u8])
+ -> io::Result<Self> {
+ self.write_data_header(data_header, DataSubtype::Data)?;
+ self.write_llc_header(llc_header)?;
+ self.w.write_all(payload)?;
+ Ok(self)
+ }
+
+ #[cfg(test)]
+ fn write_data_header(&mut self, header: &DataHeader, subtype: DataSubtype) -> io::Result<()> {
+ let mut frame_control = header.frame_control;
+ frame_control.set_typ(FrameControlType::Data as u16);
+ frame_control.set_subtype(subtype as u16);
+ frame_control.set_htc_order(header.ht_control.is_some());
+ self.w.write_u16::<LittleEndian>(frame_control.0)?;
+ self.w.write_u16::<LittleEndian>(header.duration)?;
+ self.w.write_all(&header.addr1)?;
+ self.w.write_all(&header.addr2)?;
+ self.w.write_all(&header.addr3)?;
+ self.w.write_u16::<LittleEndian>(header.seq_control.encode())?;
+ if let Some(addr4) = header.addr4 { self.w.write_all(&addr4)?; }
+ if let Some(qos_control) = header.qos_control{
+ self.w.write_u16::<LittleEndian>(qos_control)?;
+ };
+ if let Some(ht_control) = header.ht_control {
+ self.w.write_u32::<LittleEndian>(ht_control)?;
+ };
+ Ok(())
+ }
+
+ #[cfg(test)]
+ fn write_llc_header(&mut self, header: &LlcHeader) -> io::Result<()> {
+ self.w.write_u8(header.dsap)?;
+ self.w.write_u8(header.ssap)?;
+ self.w.write_u8(header.control)?;
+ self.w.write_all(&header.oui)?;
+ self.w.write_u16::<LittleEndian>(header.protocol_id)?;
+ Ok(())
+ }
+
+ #[cfg(test)]
+ pub fn into_writer(self) -> W {
+ self.w
+ }
}
pub struct ElementWriter<W: io::Write> {
@@ -473,4 +519,50 @@
assert_eq!(bytes_read, 15);
assert_eq!(&payload[..], &[1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
}
+
+ #[test]
+ fn simple_data() {
+ let frame = MacFrameWriter::new(vec![])
+ .data(
+ &DataHeader {
+ frame_control: FrameControl(0), // will be overwritten
+ duration: 0x8765,
+ addr1: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06],
+ addr2: [0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C],
+ addr3: [0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12],
+ seq_control: SeqControl {
+ frag_num: 6,
+ seq_num: 0xDEF,
+ },
+ addr4: None,
+ qos_control: None,
+ ht_control: None,
+ },
+ &LlcHeader {
+ dsap: 123,
+ ssap: 234,
+ control: 111,
+ oui: [0xff, 0xfe, 0xfd],
+ protocol_id: 0x3456,
+ },
+ &[11, 12, 13, 14, 15, 16, 17]
+ ).unwrap()
+ .into_writer();
+ #[cfg_attr(rustfmt, rustfmt_skip)]
+ let expected_frame: &[u8] = &[
+ 8u8, 0, // FrameControl (overwritten)
+ 0x65, 0x87, // Duration
+ 1, 2, 3, 4, 5, 6, // Addr1
+ 7, 8, 9, 10, 11, 12, // Addr2
+ 13, 14, 15, 16, 17, 18, // Addr3
+ 0xf6, 0xde, // SeqControl
+ // LLC Header
+ 123, 234, 111, // dsap, ssap and control
+ 0xff, 0xfe, 0xfd, // OUI
+ 0x56, 0x34, // protocol ID
+ // payload
+ 11, 12, 13, 14, 15, 16, 17,
+ ];
+ assert_eq!(expected_frame, &frame[..]);
+ }
}
diff --git a/bin/wlan/wlan-hw-sim/src/main.rs b/bin/wlan/wlan-hw-sim/src/main.rs
index efab16b..f00d01b 100644
--- a/bin/wlan/wlan-hw-sim/src/main.rs
+++ b/bin/wlan/wlan-hw-sim/src/main.rs
@@ -368,7 +368,7 @@
// Temporary workaround to run tests synchronously. This is because wlan service only works with
// one PHY, so having tests with multiple PHYs running in parallel make them flaky.
#[test]
- fn ethernet_and_scan_and_minstrel() {
+ fn ethernet_then_scan_then_txrx_then_minstrel() {
let mut ok = true;
ok = run_test("verify_ethernet", verify_ethernet) && ok;
ok = run_test("simulate_scan", simulate_scan) && ok;
@@ -776,11 +776,10 @@
.expect("cannot create ethernet client")
.expect(&format!("ethernet client not found {:?}", &HW_MAC_ADDR));
- verify_tx(&mut client, &mut exec, &mut helper);
- // TODO(eyw): verify_rx(...)
+ verify_tx_and_rx(&mut client, &mut exec, &mut helper);
}
- fn verify_tx(client: &mut ethernet::Client, exec: &mut fasync::Executor,
+ fn verify_tx_and_rx(client: &mut ethernet::Client, exec: &mut fasync::Executor,
helper: &mut test_utils::TestHelper) {
let mut buf: Vec<u8> = Vec::new();
eth_frames::write_eth_header(&mut buf, ð_frames::EthHeader{
@@ -789,39 +788,46 @@
eth_type : eth_frames::EtherType::Ipv4 as u16,
}).expect("Error creating fake ethernet frame");
buf.extend_from_slice(PAYLOAD);
- println!("{:?}", buf);
- let (sender, receiver) = mpsc::channel(1);
- let eth_tx_fut = test_eth_tx(client, &buf, receiver);
- pin_mut!(eth_tx_fut);
+ let eth_tx_rx_fut = send_and_receive(client, &buf);
+ pin_mut!(eth_tx_rx_fut);
+ let phy = helper.proxy();
let mut actual = Vec::new();
- helper.run(exec, 5.seconds(), "verify ethernet_tx is working",
- |event| { handle_eth_tx(event, &mut actual, sender.clone()); },
- eth_tx_fut).expect("running main future");
+ let (header, payload) = helper.run(exec, 5.seconds(), "verify ethernet_tx_rx",
+ |event| { handle_eth_tx(event, &mut actual, &phy); },
+ eth_tx_rx_fut).expect("send and receive eth");
assert_eq!(&actual[..], PAYLOAD);
+ assert_eq!(header.dst, HW_MAC_ADDR);
+ assert_eq!(header.src, BSSID);
+ assert_eq!(&payload[..], PAYLOAD);
}
- async fn test_eth_tx<'a>(client: &'a mut ethernet::Client, buf: &'a[u8],
- mut receiver: mpsc::Receiver<()>) -> Result<(), failure::Error> {
+ async fn send_and_receive<'a>(client: &'a mut ethernet::Client, buf: &'a Vec<u8>)
+ -> Result<(eth_frames::EthHeader, Vec<u8>), failure::Error> {
let mut client_stream = client.get_stream();
- println!("Sending");
client.send(&buf);
loop {
- let polled = poll!(client_stream.next());
- match polled {
- futures::Poll::Ready(Some(Ok(ethernet::Event::StatusChanged))) => {
+ let event = await!(client_stream.next())
+ .expect("receiving ethernet event")?;
+ match event {
+ ethernet::Event::StatusChanged => {
await!(client.get_status()).expect("getting status");
},
- _ => { break; }
+ ethernet::Event::Receive(buffer) => {
+ let mut eth_frame = vec![0u8; buffer.len()];
+ buffer.read(&mut eth_frame);
+ let mut cursor = io::Cursor::new(ð_frame);
+ let header = eth_frames::EthHeader::from_reader(&mut cursor)?;
+ let payload = eth_frame.split_off(cursor.position() as usize);
+ return Ok((header, payload));
+ }
}
}
- await!(receiver.next());
- Ok(())
}
fn handle_eth_tx(event: wlantap::WlantapPhyEvent, actual: &mut Vec<u8>,
- mut sender: mpsc::Sender<()>) {
+ phy: &wlantap::WlantapPhyProxy) {
if let wlantap::WlantapPhyEvent::Tx{args} = event {
let frame_ctrl = get_frame_ctrl(&args.packet.data);
if frame_ctrl.typ() == mac_frames::FrameControlType::Data as u16 {
@@ -833,13 +839,47 @@
&& data_header.addr3 == BSSID {
mac_frames::LlcHeader::from_reader(&mut cursor).expect("skipping llc header");
io::Read::read_to_end(&mut cursor, actual).expect("reading payload");
- sender.try_send(()).expect("sending result");
+ rx_wlan_data_frame(&HW_MAC_ADDR, &BSS_ETHNET, &BSSID, &PAYLOAD, phy)
+ .expect("sending wlan data frame");
}
}
}
}
- fn run_test<F>(name: &str, f: F) -> bool
+ fn rx_wlan_data_frame(addr1: &[u8; 6], addr2: &[u8; 6], addr3: &[u8; 6], payload: &[u8],
+ phy: &wlantap::WlantapPhyProxy) -> Result<(), failure::Error> {
+ let mut buf: Vec<u8> = vec![];
+ mac_frames::MacFrameWriter::<&mut Vec<u8>>::new(&mut buf).data(
+ &mac_frames::DataHeader {
+ frame_control: mac_frames::FrameControl(0), // will be filled automatically
+ duration: 0,
+ addr1: addr1.clone(),
+ addr2: addr2.clone(),
+ addr3: addr3.clone(),
+ seq_control: mac_frames::SeqControl {
+ frag_num: 0,
+ seq_num: 3,
+ },
+ addr4: None,
+ qos_control: None,
+ ht_control: None,
+ },
+ &mac_frames::LlcHeader {
+ dsap: 170,
+ ssap: 170,
+ control: 3,
+ oui: [0; 3],
+ protocol_id: eth_frames::EtherType::Ipv4 as u16,
+ },
+ payload
+ )?;
+
+ let rx_info = &mut create_rx_info(&CHANNEL);
+ phy.rx(0, &mut buf.iter().cloned(), rx_info)?;
+ Ok(())
+ }
+
+ fn run_test<F>(name: &str, f: F) -> bool
where F: FnOnce() + panic::UnwindSafe
{
println!("\nTest `{}` started\n", name);