[rust][ethernet] Distinguish tx_echo from rx

If listen_tx is enabled for the client, it is impossible to tell whether
a Receive event is caused by tx echo or a packet that is received. So
include the flags as part of the Receive event.

Test: Verified behavior with eth-rs

Change-Id: Ice7c2353f5b634bea30ee181eb8113b345940377
diff --git a/bin/recovery_netstack/src/eventloop.rs b/bin/recovery_netstack/src/eventloop.rs
index dfe749b..285f6f8 100644
--- a/bin/recovery_netstack/src/eventloop.rs
+++ b/bin/recovery_netstack/src/eventloop.rs
@@ -95,7 +95,7 @@
                     let status = await!(ctx.dispatcher().eth_client.get_status())?;
                     println!("ethernet status: {:?}", status);
                 }
-                eth::Event::Receive(rx) => {
+                eth::Event::Receive(rx, _flags) => {
                     let len = rx.read(&mut buf);
                     receive_frame(&mut event_loop.ctx.lock().unwrap(), eth_id, &mut buf[..len]);
                 }
diff --git a/bin/wlan/wlan-hw-sim/BUILD.gn b/bin/wlan/wlan-hw-sim/BUILD.gn
index 0ba1b0f..a3e8652 100644
--- a/bin/wlan/wlan-hw-sim/BUILD.gn
+++ b/bin/wlan/wlan-hw-sim/BUILD.gn
@@ -13,6 +13,7 @@
 
   deps = [
     "//garnet/lib/rust/ethernet",
+    "//garnet/lib/rust/fidl_zircon_ethernet_ext",
     "//garnet/lib/rust/wlantap-client",
     "//garnet/lib/wlan/fidl:fidl-rustc",
     "//garnet/lib/wlan/fidl:wlantap-rustc",
diff --git a/bin/wlan/wlan-hw-sim/src/main.rs b/bin/wlan/wlan-hw-sim/src/main.rs
index f00d01b..be30d5e 100644
--- a/bin/wlan/wlan-hw-sim/src/main.rs
+++ b/bin/wlan/wlan-hw-sim/src/main.rs
@@ -342,7 +342,7 @@
     use super::*;
     use {
         fidl_fuchsia_wlan_service as fidl_wlan_service,
-        failure::format_err,
+        failure::{ensure, format_err},
         fuchsia_app as app,
         fuchsia_zircon as zx,
         futures::{channel::mpsc, poll, select},
@@ -805,6 +805,7 @@
 
     async fn send_and_receive<'a>(client: &'a mut ethernet::Client, buf: &'a Vec<u8>)
         -> Result<(eth_frames::EthHeader, Vec<u8>), failure::Error> {
+        use fidl_zircon_ethernet_ext::EthernetQueueFlags;
         let mut client_stream = client.get_stream();
         client.send(&buf);
         loop {
@@ -814,7 +815,8 @@
                 ethernet::Event::StatusChanged => {
                     await!(client.get_status()).expect("getting status");
                 },
-                ethernet::Event::Receive(buffer) => {
+                ethernet::Event::Receive(buffer, flags) => {
+                    ensure!(flags.intersects(EthernetQueueFlags::RX_OK), "RX_OK not set");
                     let mut eth_frame = vec![0u8; buffer.len()];
                     buffer.read(&mut eth_frame);
                     let mut cursor = io::Cursor::new(&eth_frame);
diff --git a/examples/rust/eth-rs/BUILD.gn b/examples/rust/eth-rs/BUILD.gn
index 88d2df4..6c6c6e3 100644
--- a/examples/rust/eth-rs/BUILD.gn
+++ b/examples/rust/eth-rs/BUILD.gn
@@ -9,6 +9,7 @@
   name = "eth_rs"
   edition = "2018"
   deps = [
+    "//garnet/lib/rust/fidl_zircon_ethernet_ext",
     "//garnet/lib/rust/ethernet",
     "//garnet/public/rust/fuchsia-async",
     "//garnet/public/rust/fuchsia-zircon",
diff --git a/examples/rust/eth-rs/src/main.rs b/examples/rust/eth-rs/src/main.rs
index 3ca62f0..33e8662 100644
--- a/examples/rust/eth-rs/src/main.rs
+++ b/examples/rust/eth-rs/src/main.rs
@@ -5,6 +5,7 @@
 #![feature(async_await, await_macro)]
 
 use failure::{Error, ResultExt};
+use fidl_zircon_ethernet_ext::EthernetQueueFlags;
 use fuchsia_async as fasync;
 use fuchsia_zircon as zx;
 use futures::prelude::*;
@@ -36,10 +37,12 @@
 
         let mut events = client.get_stream();
         while let Some(evt) = await!(events.try_next())? {
-            if let ethernet::Event::Receive(rx) = evt {
+            if let ethernet::Event::Receive(rx, flags) = evt {
                 let mut buf = [0; 64];
                 let r = rx.read(&mut buf);
-                println!("first {} bytes: {:02x?}", r, &buf[0..r]);
+                let is_tx_echo = flags.intersects(EthernetQueueFlags::TX_ECHO);
+                println!("{} first {} bytes:\n{:02x?}", if is_tx_echo {"TX_ECHO"} else {"RX     "},
+                         r, &buf[0..r]);
             }
         }
         Ok(())
diff --git a/lib/rust/ethernet/src/lib.rs b/lib/rust/ethernet/src/lib.rs
index dd7eaaf..8a79ac7 100644
--- a/lib/rust/ethernet/src/lib.rs
+++ b/lib/rust/ethernet/src/lib.rs
@@ -171,7 +171,8 @@
     }
 
     /// Poll the Ethernet client to receive a packet from the Ethernet device.
-    pub fn poll_complete_rx(&self, cx: &LocalWaker) -> Poll<Result<buffer::RxBuffer, zx::Status>> {
+    pub fn poll_complete_rx(&self, cx: &LocalWaker)
+        -> Poll<Result<(buffer::RxBuffer, EthernetQueueFlags), zx::Status>> {
         self.inner.poll_complete_rx(cx)
     }
 }
@@ -191,7 +192,7 @@
     /// The `get_status` method may be used to retrieve the current status.
     StatusChanged,
     /// A RxBuffer was received from the Ethernet device.
-    Receive(buffer::RxBuffer),
+    Receive(buffer::RxBuffer, EthernetQueueFlags),
 }
 
 impl Stream for EventStream {
@@ -229,8 +230,8 @@
                 progress = true;
             }
 
-            if let Poll::Ready(buf) = self.inner.poll_complete_rx(lw)? {
-                return Poll::Ready(Ok(Event::Receive(buf)));
+            if let Poll::Ready((buf, flags)) = self.inner.poll_complete_rx(lw)? {
+                return Poll::Ready(Ok(Event::Receive(buf, flags)));
             }
 
             if !progress {
@@ -338,12 +339,13 @@
     }
 
     /// Receive a buffer from the Ethernet device representing a packet from the network.
-    fn poll_complete_rx(&self, lw: &LocalWaker) -> Poll<Result<buffer::RxBuffer, zx::Status>> {
+    fn poll_complete_rx(&self, lw: &LocalWaker)
+        -> Poll<Result<(buffer::RxBuffer, EthernetQueueFlags), zx::Status>> {
         Poll::Ready(match try_ready!(self.rx_fifo.try_read(lw)) {
             Some(entry) => {
                 let mut pool_guard = self.pool.lock().unwrap();
                 let buf = pool_guard.map_rx_buffer(entry.offset as usize, entry.length as usize);
-                Ok(buf)
+                Ok((buf, EthernetQueueFlags::from_bits_truncate(entry.flags)))
             }
             None => Err(zx::Status::PEER_CLOSED),
         })