[lowpan][lowpan-spinel-driver] Add support for getting credential.

Test: fx test lowpan-tests
Change-Id: I2deea49df2a255d11ec872341f7eecc2078dd684
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/430346
Commit-Queue: Robert Quattlebaum <rquattle@google.com>
Reviewed-by: Jiaming (Charlie) Wang <jiamingw@google.com>
Testability-Review: Jiaming (Charlie) Wang <jiamingw@google.com>
diff --git a/src/connectivity/lowpan/drivers/lowpan-spinel-driver/src/driver/api.rs b/src/connectivity/lowpan/drivers/lowpan-spinel-driver/src/driver/api.rs
index fd79bf9..6ad8676 100644
--- a/src/connectivity/lowpan/drivers/lowpan-spinel-driver/src/driver/api.rs
+++ b/src/connectivity/lowpan/drivers/lowpan-spinel-driver/src/driver/api.rs
@@ -185,6 +185,15 @@
                     .await?;
             }
 
+            // Set the credential, if we have one.
+            if let Some(fidl_fuchsia_lowpan::Credential::MasterKey(key)) =
+                params.credential.map(|x| *x)
+            {
+                self.frame_handler
+                    .send_request(CmdPropValueSet(PropNet::MasterKey.into(), key).verify())
+                    .await?;
+            }
+
             if self.driver_state.lock().has_cap(Cap::NetSave) {
                 // If we have the NetSave capability, go ahead and send the
                 // net save command.
@@ -424,7 +433,24 @@
     }
 
     async fn get_credential(&self) -> ZxResult<Option<fidl_fuchsia_lowpan::Credential>> {
-        Err(ZxStatus::NOT_SUPPORTED)
+        fx_log_info!("Got get credential command");
+
+        // Wait until we are ready.
+        self.wait_for_state(DriverState::is_initialized).await;
+
+        if self.driver_state.lock().is_ready() {
+            self.get_property_simple::<Vec<u8>, _>(PropNet::MasterKey)
+                .and_then(|key| {
+                    futures::future::ready(if key.is_empty() {
+                        Ok(None)
+                    } else {
+                        Ok(Some(fidl_fuchsia_lowpan::Credential::MasterKey(key)))
+                    })
+                })
+                .await
+        } else {
+            Ok(None)
+        }
     }
 
     fn start_energy_scan(
diff --git a/src/connectivity/lowpan/drivers/lowpan-spinel-driver/src/driver/tests.rs b/src/connectivity/lowpan/drivers/lowpan-spinel-driver/src/driver/tests.rs
index c8b36c3..1c3bf07 100644
--- a/src/connectivity/lowpan/drivers/lowpan-spinel-driver/src/driver/tests.rs
+++ b/src/connectivity/lowpan/drivers/lowpan-spinel-driver/src/driver/tests.rs
@@ -9,7 +9,7 @@
 use mock::*;
 
 use crate::spinel::mock::PROP_DEBUG_LOGGING_TEST;
-use fidl_fuchsia_lowpan::{Identity, ProvisioningParams, NET_TYPE_THREAD_1_X};
+use fidl_fuchsia_lowpan::{Credential, Identity, ProvisioningParams, NET_TYPE_THREAD_1_X};
 use lowpan_driver_common::Driver as _;
 
 impl<DS> SpinelDriver<DS> {
@@ -115,7 +115,9 @@
                             channel: Some(11),
                             panid: Some(0x1234),
                         },
-                        credential: None
+                        credential: Some(Box::new(Credential::MasterKey(vec![
+                            0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+                        ]))),
                     })
                     .await,
                 Ok(())
@@ -135,6 +137,15 @@
                 ConnectivityState::Ready
             );
 
+            traceln!("app_task: Checking credential...");
+            assert_eq!(
+                driver.get_credential().await,
+                Ok(Some(Credential::MasterKey(vec![
+                    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+                ])))
+            );
+            traceln!("app_task: Credential is correct!");
+
             traceln!("app_task: Leaving network...");
             assert_eq!(driver.leave_network().await, Ok(()));
             traceln!("app_task: Did leave!");