blob: bd619a127f47b9f84893ac9b4bf3d46eefe22a76 [file] [log] [blame]
// 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 std::collections::HashMap;
type MacAddr = [u8; 6];
const MAC_ADDR_LEN: usize = 6;
const SEQ_START_NUM: SequenceNum = 0;
type SnsEntryHash = u64;
type SequenceNum = u32;
/// IEEE Std 802.11-2016, 10.3.2.11.2, 10.3.2.11.3
/// A specific Sequence Number Space such as SNS1, SNS2, etc.
/// A STA owns multiple of such SNS maps, each of which holds
/// sequence numbers for its peers.
struct SnsMap {
inner: HashMap<SnsEntryHash, SequenceNum>,
modulo_divisor: SequenceNum,
}
impl SnsMap {
pub fn new(modulo_divisor: SequenceNum) -> Self {
Self { inner: HashMap::new(), modulo_divisor }
}
pub fn next(&mut self, entry: &SnsEntryHash) -> SequenceNum {
match self.inner.get_mut(entry) {
None => {
self.inner.insert(*entry, SEQ_START_NUM);
SEQ_START_NUM
}
Some(seq) => {
*seq = (*seq + 1) % self.modulo_divisor;
*seq
}
}
}
}
/// Manages all SNS for a STA.
pub struct SequenceManager {
sns_map1024: SnsMap,
sns_map4096: SnsMap,
}
impl SequenceManager {
pub fn new() -> Self {
Self { sns_map1024: SnsMap::new(1024), sns_map4096: SnsMap::new(4096) }
}
pub fn next_sns1(&mut self, sta_addr: &MacAddr) -> SequenceNum {
self.sns_map4096.next(&hash_mac_addr(sta_addr))
}
pub fn next_sns2(&mut self, sta_addr: &MacAddr, tid: u16) -> SequenceNum {
// IEEE Std 802.11-2016, 9.2.4.5.2
// TID is 4 bit long.
// Insert 0x10 to generate a unique hash.
let hash = hash_mac_addr(sta_addr) + ((0x10 | tid as SnsEntryHash) << MAC_ADDR_LEN);
self.sns_map4096.next(&hash)
}
// Sns3 optional
pub fn next_sns4(&mut self, sta_addr: &MacAddr, aci: u8) -> SequenceNum {
// IEEE Std 802.11-2016, 9.2.4.4.2
// ACI subfield is 2 bit long.
// Insert 0x20 to generate a unique hash.
let hash = hash_mac_addr(sta_addr) + ((0x20 | aci as SnsEntryHash) << MAC_ADDR_LEN);
self.sns_map1024.next(&hash)
}
pub fn next_sns5(&mut self) -> SequenceNum {
// Arbitrary value by spec. Increment to assist debugging.
const HASH: SnsEntryHash = 0x01 << (MAC_ADDR_LEN + 1);
self.sns_map4096.next(&HASH)
}
}
fn hash_mac_addr(mac_addr: &MacAddr) -> SnsEntryHash {
return mac_addr.iter().fold(0, |acc, x| (acc << 8) | (*x as u64));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sns1_next() {
let mut seq_mgr = SequenceManager::new();
for i in 0..4095 {
let seq_num = seq_mgr.next_sns1(&[1; 6]);
assert_eq!(i, seq_num);
}
let seq_num = seq_mgr.next_sns1(&[1; 6]);
assert_eq!(4095, seq_num);
let seq_num = seq_mgr.next_sns1(&[1; 6]);
assert_eq!(0, seq_num);
}
#[test]
fn sns1_next_multiple_peers() {
const FIRST_PEER: [u8; 6] = [1; 6];
const SECOND_PEER: [u8; 6] = [2; 6];
let mut seq_mgr = SequenceManager::new();
seq_mgr.next_sns1(&FIRST_PEER);
seq_mgr.next_sns1(&FIRST_PEER);
let seq_num = seq_mgr.next_sns1(&FIRST_PEER);
assert_eq!(2, seq_num);
seq_mgr.next_sns1(&SECOND_PEER);
let seq_num = seq_mgr.next_sns1(&SECOND_PEER);
assert_eq!(1, seq_num);
let seq_num = seq_mgr.next_sns1(&FIRST_PEER);
assert_eq!(3, seq_num);
}
#[test]
fn sns2_next_multiple_tids() {
let mut seq_mgr = SequenceManager::new();
seq_mgr.next_sns2(&[1; 6], 0);
seq_mgr.next_sns2(&[1; 6], 0);
let seq_num = seq_mgr.next_sns2(&[1; 6], 0);
assert_eq!(2, seq_num);
seq_mgr.next_sns2(&[1; 6], 1);
let seq_num = seq_mgr.next_sns2(&[1; 6], 1);
assert_eq!(1, seq_num);
let seq_num = seq_mgr.next_sns2(&[1; 6], 0);
assert_eq!(3, seq_num);
}
#[test]
fn sns4_next_multiple_acis() {
let mut seq_mgr = SequenceManager::new();
seq_mgr.next_sns4(&[1; 6], 0);
seq_mgr.next_sns4(&[1; 6], 0);
let seq_num = seq_mgr.next_sns4(&[1; 6], 0);
assert_eq!(2, seq_num);
seq_mgr.next_sns4(&[1; 6], 1);
let seq_num = seq_mgr.next_sns4(&[1; 6], 1);
assert_eq!(1, seq_num);
let seq_num = seq_mgr.next_sns4(&[1; 6], 0);
assert_eq!(3, seq_num);
}
#[test]
fn mixed_sns_next() {
let mut seq_mgr = SequenceManager::new();
seq_mgr.next_sns1(&[1; 6]);
seq_mgr.next_sns1(&[1; 6]);
let seq_num = seq_mgr.next_sns1(&[1; 6]);
assert_eq!(2, seq_num);
seq_mgr.next_sns2(&[1; 6], 0);
let seq_num = seq_mgr.next_sns2(&[1; 6], 0);
assert_eq!(1, seq_num);
let seq_num = seq_mgr.next_sns4(&[1; 6], 3);
assert_eq!(0, seq_num);
}
}