[wlan][mlme] Add Keep Alive frame construction
Test=Included
Change-Id: Iaf60ee93c20fc4b9073dc850d61a041a10757aaa
diff --git a/lib/rust/wlan-common/src/buffer_writer.rs b/lib/rust/wlan-common/src/buffer_writer.rs
index 11bde35..6163984 100644
--- a/lib/rust/wlan-common/src/buffer_writer.rs
+++ b/lib/rust/wlan-common/src/buffer_writer.rs
@@ -4,9 +4,11 @@
use {
failure::{Error, ensure, format_err},
- zerocopy::{ByteSliceMut, LayoutVerified, Unaligned},
+ zerocopy::{self, LayoutVerified, Unaligned},
};
+pub use zerocopy::ByteSliceMut as ByteSliceMut;
+
pub struct BufferWriter<B: ByteSliceMut> {
buf: B,
written_bytes: usize,
diff --git a/lib/rust/wlan-common/src/mac.rs b/lib/rust/wlan-common/src/mac.rs
index 461b8c5..8a1b0a1 100644
--- a/lib/rust/wlan-common/src/mac.rs
+++ b/lib/rust/wlan-common/src/mac.rs
@@ -15,17 +15,19 @@
// IEEE Std 802.11-2016, 9.2.4.1.3
// Frame types:
-const FRAME_TYPE_MGMT: u16 = 0;
-const FRAME_TYPE_DATA: u16 = 2;
+pub const FRAME_TYPE_MGMT: u16 = 0;
+pub const FRAME_TYPE_DATA: u16 = 2;
// Management subtypes:
-const MGMT_SUBTYPE_ASSOC_RESP: u16 = 0x01;
-const MGMT_SUBTYPE_BEACON: u16 = 0x08;
-const MGMT_SUBTYPE_AUTH: u16 = 0x0B;
+pub const MGMT_SUBTYPE_ASSOC_RESP: u16 = 0x01;
+pub const MGMT_SUBTYPE_BEACON: u16 = 0x08;
+pub const MGMT_SUBTYPE_AUTH: u16 = 0x0B;
// Data subtypes:
-const DATA_SUBTYPE_DATA: u16 = 0x00;
-const DATA_SUBTYPE_QOS_DATA: u16 = 0x08;
+pub const DATA_SUBTYPE_DATA: u16 = 0x00;
+pub const DATA_SUBTYPE_NULL_DATA: u16 = 0x04;
+pub const DATA_SUBTYPE_QOS_DATA: u16 = 0x08;
// IEEE Std 802.11-2016, 9.2.4.1.3, Table 9-1
+const BITMASK_NULL: u16 = 1 << 2;
const BITMASK_QOS: u16 = 1 << 3;
// IEEE Std 802.11-2016, 9.2.4.1.1
@@ -166,6 +168,18 @@
LittleEndian::read_u16(&self.seq_ctrl)
}
+ pub fn set_frame_ctrl(&mut self, val: u16) {
+ LittleEndian::write_u16(&mut self.frame_ctrl, val)
+ }
+
+ pub fn set_duration(&mut self, val: u16) {
+ LittleEndian::write_u16(&mut self.duration, val)
+ }
+
+ pub fn set_seq_ctrl(&mut self, val: u16) {
+ LittleEndian::write_u16(&mut self.seq_ctrl, val)
+ }
+
/// Returns the length in bytes of a mgmt header including all its fixed and optional
/// fields (if they are present).
pub fn len(has_ht_ctrl: bool) -> usize {
@@ -201,6 +215,18 @@
LittleEndian::read_u16(&self.seq_ctrl)
}
+ pub fn set_frame_ctrl(&mut self, val: u16) {
+ LittleEndian::write_u16(&mut self.frame_ctrl, val)
+ }
+
+ pub fn set_duration(&mut self, val: u16) {
+ LittleEndian::write_u16(&mut self.duration, val)
+ }
+
+ pub fn set_seq_ctrl(&mut self, val: u16) {
+ LittleEndian::write_u16(&mut self.seq_ctrl, val)
+ }
+
/// Returns the length in bytes of a data header including all its fixed and optional
/// fields (if they are present).
pub fn len(has_addr4: bool, has_qos_ctrl: bool, has_ht_ctrl: bool) -> usize {
diff --git a/lib/rust/wlan-mlme/src/client.rs b/lib/rust/wlan-mlme/src/client.rs
new file mode 100644
index 0000000..4af031a
--- /dev/null
+++ b/lib/rust/wlan-mlme/src/client.rs
@@ -0,0 +1,51 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use {
+ failure::Error,
+ wlan_common::{mac, buffer_writer::{BufferWriter, ByteSliceMut}},
+};
+
+type MacAddr = [u8; 6];
+
+/// Fills a given buffer with a null-data frame which will be send from a client to an AP.
+/// Fails if the given buffer is too short.
+/// Returns the amount of bytes written to the buffer.
+pub fn write_keep_alive_resp_frame<B: ByteSliceMut>(buf: B, bssid: MacAddr,
+ client_addr: MacAddr, seq_ctrl: u16)
+ -> Result<usize, Error>
+{
+ let (mut data_hdr, w) = BufferWriter::new(buf).reserve_zeroed::<mac::DataHdr>()?;
+ let mut fc = mac::FrameControl(0);
+ fc.set_frame_type(mac::FRAME_TYPE_DATA);
+ fc.set_frame_subtype(mac::DATA_SUBTYPE_NULL_DATA);
+ fc.set_to_ds(true);
+ data_hdr.set_frame_ctrl(fc.value());
+ data_hdr.addr1 = bssid;
+ data_hdr.addr2 = client_addr;
+ data_hdr.addr3 = bssid;
+ data_hdr.set_seq_ctrl(seq_ctrl);
+ Ok(w.written_bytes())
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn keep_alive_resp_frame() {
+ let mut buf = [3u8; 25];
+ let written_bytes = write_keep_alive_resp_frame(&mut buf[..], [1; 6], [2; 6], 42)
+ .expect("failed writing frame");
+ assert_eq!(24, written_bytes);
+ assert_eq!([0b01001000, 0b1, // Frame Control
+ 0, 0, // Duration
+ 1, 1, 1, 1, 1, 1, // addr1
+ 2, 2, 2, 2, 2, 2, // addr2
+ 1, 1, 1, 1, 1, 1, // addr3
+ 42, 0, // Sequence Control
+ 3 // Trailing bytes
+ ], buf);
+ }
+}
\ No newline at end of file
diff --git a/lib/rust/wlan-mlme/src/lib.rs b/lib/rust/wlan-mlme/src/lib.rs
index 83c17e4..0a146e6 100644
--- a/lib/rust/wlan-mlme/src/lib.rs
+++ b/lib/rust/wlan-mlme/src/lib.rs
@@ -7,4 +7,5 @@
pub use wlan_common as common;
-pub mod auth;
\ No newline at end of file
+pub mod auth;
+pub mod client;
\ No newline at end of file