blob: 68f13bc6f013a252f3ba69f1edd32df99a164419 [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.
//trace_macros!(true);
#![allow(dead_code)]
use byteorder::{LittleEndian, WriteBytesExt};
use std::io;
// IEEE Std 802.11-2016, 9.2.4.1.3 Table 9-1
#[derive(Clone, Copy, Debug)]
pub enum FrameControlType {
Mgmt = 0b00,
}
#[derive(Clone, Copy, Debug)]
pub enum MgmtSubtype {
Beacon = 0b1000,
}
bitfield!{
#[derive(Clone, Copy, Debug)]
pub struct FrameControl(u16);
pub protocol_ver, set_protocol_ver: 1, 0;
pub typ, set_typ: 3, 2;
pub subtype, set_subtype: 7, 4;
pub to_ds, set_to_ds: 8;
pub from_ds, set_from_ds: 9;
pub more_frags, set_more_frags: 10;
pub retry, set_retry: 11;
pub power_mgmt, set_power_mgmt: 12;
pub more_data, set_more_data: 13;
pub protected_frame, set_protected_frame: 14;
pub htc_order, set_htc_order: 15;
}
// IEEE Std 802.11-2016, 9.2.4.4
#[derive(Clone, Copy, Debug)]
pub struct SeqControl {
pub frag_num: u16,
pub seq_num: u16,
}
impl SeqControl {
fn encode(&self) -> u16 {
self.frag_num | (self.seq_num << 4)
}
}
// IEEE Std 802.11-2016, 9.3.3.2
#[derive(Clone, Copy, Debug)]
pub struct MgmtHeader {
pub frame_control: FrameControl,
pub duration: u16,
pub addr1: [u8; 6],
pub addr2: [u8; 6],
pub addr3: [u8; 6],
pub seq_control: SeqControl,
pub ht_control: Option<u32>,
}
// IEEE Std 802.11-2016, 9.3.3.3
#[derive(Clone, Copy, Debug)]
pub struct BeaconFields {
pub timestamp: u64, // IEEE Std 802.11-2016, 9.4.1.10
pub beacon_interval: u16, // IEEE Std 802.11-2016, 9.4.1.3
pub capability_info: u16, // IEEE Std 802.11-2016, 9.4.1.4
}
pub const BROADCAST_ADDR: [u8; 6] = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
// IEEE Std 802.11-2016, 9.4.2.1
enum ElementId {
Ssid = 0,
SupportedRates = 1,
DsssParameterSet = 3,
}
pub struct MacFrameWriter<W: io::Write> {
w: W,
}
impl<W: io::Write> MacFrameWriter<W> {
pub fn new(w: W) -> Self {
MacFrameWriter { w }
}
pub fn beacon(
mut self, header: &MgmtHeader, beacon: &BeaconFields,
) -> io::Result<ElementWriter<W>> {
self.write_mgmt_header(header, MgmtSubtype::Beacon)?;
self.w.write_u64::<LittleEndian>(beacon.timestamp)?;
self.w.write_u16::<LittleEndian>(beacon.beacon_interval)?;
self.w.write_u16::<LittleEndian>(beacon.capability_info)?;
Ok(ElementWriter { w: self.w })
}
fn write_mgmt_header(&mut self, header: &MgmtHeader, subtype: MgmtSubtype) -> io::Result<()> {
let mut frame_control = header.frame_control;
frame_control.set_typ(FrameControlType::Mgmt as u16);
frame_control.set_subtype(subtype as u16);
frame_control.set_htc_order(header.ht_control.is_some());
self.w.write_u16::<LittleEndian>(frame_control.0)?;
self.w.write_u16::<LittleEndian>(header.duration)?;
self.w.write_all(&header.addr1)?;
self.w.write_all(&header.addr2)?;
self.w.write_all(&header.addr3)?;
self.w
.write_u16::<LittleEndian>(header.seq_control.encode())?;
if let Some(ht_control) = header.ht_control {
self.w.write_u32::<LittleEndian>(ht_control)?;
}
Ok(())
}
}
pub struct ElementWriter<W: io::Write> {
w: W,
}
impl<W: io::Write> ElementWriter<W> {
pub fn ssid(mut self, ssid: &[u8]) -> io::Result<Self> {
self.write_header(ElementId::Ssid, ssid.len() as u8)?;
self.w.write_all(ssid)?;
Ok(self)
}
pub fn supported_rates(mut self, rates: &[u8]) -> io::Result<Self> {
self.write_header(ElementId::SupportedRates, rates.len() as u8)?;
self.w.write_all(rates)?;
Ok(self)
}
pub fn dsss_parameter_set(mut self, current_channel: u8) -> io::Result<Self> {
self.write_header(ElementId::DsssParameterSet, 1)?;
self.w.write_u8(current_channel)?;
Ok(self)
}
pub fn into_writer(self) -> W {
self.w
}
fn write_header(&mut self, element_id: ElementId, length: u8) -> io::Result<()> {
self.w.write_u8(element_id as u8)?;
self.w.write_u8(length)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn simple_beacon() {
let frame = MacFrameWriter::new(vec![])
.beacon(
&MgmtHeader {
frame_control: FrameControl(0),
duration: 0x9765,
addr1: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06],
addr2: [0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C],
addr3: [0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12],
seq_control: SeqControl {
frag_num: 5,
seq_num: 0xABC,
},
ht_control: None,
},
&BeaconFields {
timestamp: 0x1122334455667788u64,
beacon_interval: 0xBEAC,
capability_info: 0xCAFE,
},
)
.unwrap()
.ssid(&[0xAA, 0xBB, 0xCC, 0xDD, 0xEE])
.unwrap()
.into_writer();
#[cfg_attr(rustfmt, rustfmt_skip)]
let expected_frame: &[u8] = &[
// Framectl Duration Address 1
0x80, 0x00, 0x65, 0x97, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
// Address 2 Address 3
0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
// Seq ctl Timestamp
0xC5, 0xAB, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11,
// Interval Cap info SSID element
0xAC, 0xBE, 0xFE, 0xCA, 0x00, 0x05, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE
];
assert_eq!(expected_frame, &frame[..]);
}
}