[wlan][wpa1] WPA1 support for write_frame!

Add support for writing WPA1 IE to write_frame! macro.

Bug: 43987
Test: Included
Change-Id: I1420d7858764a80d47e62c1ace32e0a9f03df15c
diff --git a/src/connectivity/wlan/lib/frame_writer/macro/src/ie.rs b/src/connectivity/wlan/lib/frame_writer/macro/src/ie.rs
index a5eeb81..4b23894 100644
--- a/src/connectivity/wlan/lib/frame_writer/macro/src/ie.rs
+++ b/src/connectivity/wlan/lib/frame_writer/macro/src/ie.rs
@@ -19,6 +19,7 @@
 const IE_RSNE: &str = "rsne";
 const IE_BSS_MAX_IDLE_PERIOD: &str = "bss_max_idle_period";
 const IE_DSSS_PARAM_SET: &str = "dsss_param_set";
+const IE_WPA1: &str = "wpa1";
 
 /// Field carrying necessary meta information to generate relevant tokens.
 #[derive(Hash, Eq, Ord, PartialEq, PartialOrd, Clone, Copy)]
@@ -35,6 +36,7 @@
     Rsne,
     BssMaxIdlePeriod,
     DsssParamSet,
+    Wpa1,
 }
 
 pub struct IeDefinition {
@@ -164,6 +166,10 @@
             Ie::DsssParamSet => {
                 frame_len!(bss_max_idle_period, IE_PREFIX_LEN + size_of::<ie::DsssParamSet>())
             }
+            Ie::Wpa1 => {
+                // IE + Vendor OUI + Vendor specific type + WPA1 body
+                frame_len!(wpa1, self.optional, IE_PREFIX_LEN + 4 + wpa1.len())
+            }
         })
     }
 
@@ -213,6 +219,7 @@
             Ie::DsssParamSet => {
                 apply_on!(dsss, &self.value, ie::write_dsss_param_set(&mut w, &dsss)?)
             }
+            Ie::Wpa1 => apply_on!(wpa1, &self.value, ie::write_wpa1_ie(&mut w, &wpa1)?),
         })
     }
 
@@ -226,6 +233,7 @@
             Ie::Rsne => declare_var!(rsne, self.optional, &self.value),
             Ie::BssMaxIdlePeriod => declare_var!(bss_max_idle_period, self.optional, &self.value),
             Ie::DsssParamSet => declare_var!(dsss, &self.value),
+            Ie::Wpa1 => declare_var!(wpa1, &self.value),
         })
     }
 }
@@ -296,6 +304,7 @@
             }
             IE_RSNE => Ie::Rsne,
             IE_BSS_MAX_IDLE_PERIOD => Ie::BssMaxIdlePeriod,
+            IE_WPA1 => Ie::Wpa1,
             unknown => return Err(Error::new(name.span(), format!("unknown IE: '{}'", unknown))),
         };
         Ok(IeDefinition { name, value, type_, optional })
diff --git a/src/connectivity/wlan/lib/frame_writer/src/lib.rs b/src/connectivity/wlan/lib/frame_writer/src/lib.rs
index 81487da..b283f80 100644
--- a/src/connectivity/wlan/lib/frame_writer/src/lib.rs
+++ b/src/connectivity/wlan/lib/frame_writer/src/lib.rs
@@ -22,11 +22,13 @@
                 self,
                 rsn::{
                     akm::{Akm, PSK},
-                    cipher::{Cipher, CCMP_128},
+                    cipher::{Cipher, CCMP_128, TKIP},
                     rsne,
                 },
+                wpa,
             },
             mac::*,
+            organization::Oui,
         },
     };
 
@@ -251,6 +253,33 @@
     }
 
     #[test]
+    fn write_wpa1() {
+        let wpa_ie = wpa::WpaIe {
+            multicast_cipher: Cipher { oui: Oui::MSFT, suite_type: TKIP },
+            unicast_cipher_list: vec![Cipher { oui: Oui::MSFT, suite_type: TKIP }],
+            akm_list: vec![Akm { oui: Oui::MSFT, suite_type: PSK }],
+        };
+
+        let buffer_provider = BufferProvider;
+        let (buf, bytes_written) = write_frame!(buffer_provider, {
+            ies: { wpa1: &wpa_ie, }
+        })
+        .expect("frame construction failed");
+        assert_eq!(bytes_written, 24);
+        assert_eq!(
+            &[
+                0xdd, 0x16, // Vendor IE header
+                0x00, 0x50, 0xf2, // MSFT OUI
+                0x01, 0x01, 0x00, // WPA IE header
+                0x00, 0x50, 0xf2, 0x02, // multicast cipher: AKM
+                0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 unicast cipher: TKIP
+                0x01, 0x00, 0x00, 0x50, 0xf2, 0x02, // 1 AKM: PSK
+            ][..],
+            &buf[..]
+        );
+    }
+
+    #[test]
     fn write_ht_caps() {
         let buffer_provider = BufferProvider;
         let (buf, bytes_written) = write_frame!(buffer_provider, {