[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, &eth_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(&eth_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);