blob: d02becfa098a7f764246eb95c274cdd3110d1e9f [file] [log] [blame]
// Copyright 2018 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 akm;
use bytes::Bytes;
use cipher;
use pmkid;
use suite_selector;
use nom::{le_u16, le_u8, IResult};
macro_rules! if_remaining (
($i:expr, $f:expr) => ( cond!($i, $i.len() !=0, call!($f)); );
);
pub const ID: u8 = 48;
// IEEE 802.11-2016, 9.4.2.25.1
#[derive(Default, Debug)]
pub struct Rsne {
pub element_id: u8,
pub length: u8,
pub version: u16,
pub group_data_cipher_suite: Option<cipher::Cipher>,
pub pairwise_cipher_suites: Vec<cipher::Cipher>,
pub akm_suites: Vec<akm::Akm>,
pub rsn_capabilities: u16,
pub pmkids: Vec<pmkid::Pmkid>,
pub group_mgmt_cipher_suite: Option<cipher::Cipher>,
}
fn read_suite_selector<'a, T>(input: &'a [u8]) -> IResult<&'a [u8], T>
where
T: suite_selector::Factory<Suite = T>,
{
let (i1, bytes) = try_parse!(input, take!(4));
let oui = Bytes::from(&bytes[0..3]);
let (i2, ctor_result) = try_parse!(i1, expr_res!(T::new(oui, bytes[3])));
return IResult::Done(i2, ctor_result);
}
fn read_pmkid<'a>(input: &'a [u8]) -> IResult<&'a [u8], pmkid::Pmkid> {
let (i1, bytes) = try_parse!(input, take!(16));
let pmkid_data = Bytes::from(bytes);
let (i2, result) = try_parse!(i1, expr_res!(pmkid::new(pmkid_data)));
return IResult::Done(i2, result);
}
named!(akm<&[u8], akm::Akm>, call!(read_suite_selector::<akm::Akm>));
named!(cipher<&[u8], cipher::Cipher>, call!(read_suite_selector::<cipher::Cipher>));
named!(pub from_bytes<&[u8], Rsne>,
do_parse!(
element_id: le_u8 >>
length: le_u8 >>
version: le_u16 >>
group_cipher: if_remaining!(cipher) >>
pairwise_count: if_remaining!(le_u16) >>
pairwise_list: count!(cipher, pairwise_count.unwrap_or(0) as usize) >>
akm_count: if_remaining!(le_u16) >>
akm_list: count!(akm, akm_count.unwrap_or(0) as usize) >>
rsn_capabilities: if_remaining!(le_u16) >>
pmkid_count: if_remaining!(le_u16) >>
pmkid_list: count!(read_pmkid, pmkid_count.unwrap_or(0) as usize) >>
group_mgmt_cipher_suite: if_remaining!(cipher) >>
eof!() >>
(Rsne{
element_id: element_id,
length: length,
version: version,
group_data_cipher_suite: group_cipher,
pairwise_cipher_suites: pairwise_list,
akm_suites: akm_list,
rsn_capabilities: rsn_capabilities.unwrap_or(0),
pmkids: pmkid_list,
group_mgmt_cipher_suite: group_mgmt_cipher_suite
})
)
);
#[cfg(test)]
mod tests {
use super::*;
use test::Bencher;
#[bench]
fn bench_parse_with_nom(b: &mut Bencher) {
let frame: Vec<u8> = vec![
0x30, 0x14, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04, 0x01, 0x00, 0x00, 0x0f, 0xac, 0x04,
0x01, 0x00, 0x00, 0x0f, 0xac, 0x02, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x00, 0x0f,
0xac, 0x04,
];
b.iter(|| from_bytes(&frame));
}
// TODO(hahnr): Add tests.
}