use std::ops::RangeInclusive;
use rand::distr::{Distribution, StandardUniform};
use rand::{Rng, RngExt};
use silizium::zigbee::security::man::Key;
use crate::ember::{Eui64, PanId};
const EUI64_LENGTH: usize = 8;
const LOCAL_BIT: u8 = 0x02;
const MULTICAST_BIT: u8 = 0x01;
const VALID_PAN_IDS: RangeInclusive<u16> = 0x0000..=0xFFFE;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct NetworkCredentials {
pub(crate) extended_pan_id: Eui64,
pub(crate) pan_id: PanId,
pub(crate) trust_center_eui64: Eui64,
pub(crate) network_key: Key,
}
impl NetworkCredentials {
#[must_use]
pub const fn new(
extended_pan_id: Eui64,
pan_id: PanId,
trust_center_eui64: Eui64,
network_key: Key,
) -> Self {
Self {
extended_pan_id,
pan_id,
trust_center_eui64,
network_key,
}
}
}
impl Distribution<NetworkCredentials> for StandardUniform {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> NetworkCredentials {
NetworkCredentials {
extended_pan_id: random_mac_addr8(rng),
pan_id: rng.random_range(VALID_PAN_IDS),
trust_center_eui64: random_mac_addr8(rng),
network_key: rng.random(),
}
}
}
fn random_mac_addr8<T>(rng: &mut T) -> Eui64
where
T: Rng + ?Sized,
{
loop {
let mut bytes = [0u8; EUI64_LENGTH];
rng.fill(&mut bytes);
bytes[0] = (bytes[0] & !MULTICAST_BIT) | LOCAL_BIT;
if bytes != [0; EUI64_LENGTH] && bytes != [u8::MAX; EUI64_LENGTH] {
return Eui64::from(bytes);
}
}
}