use num_enum::{FromPrimitive, IntoPrimitive};
use super::option_fsm::{Protocol, Verdict};
use crate::wire::ProtocolType;
#[derive(FromPrimitive, IntoPrimitive, Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[repr(u8)]
enum Option {
#[num_enum(default)]
Unknown = 0,
Asyncmap = 2,
Auth = 3,
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum AuthType {
None = 0,
PAP = 0xc023,
}
pub(crate) struct LCP {
pub auth: AuthType,
pub asyncmap_remote: u32,
pub asyncmap: u32,
pub asyncmap_rej: bool,
}
impl LCP {
pub fn new() -> Self {
Self {
auth: AuthType::None,
asyncmap_remote: 0xFFFFFFFF,
asyncmap: 0x00000000,
asyncmap_rej: false,
}
}
}
impl Protocol for LCP {
fn protocol(&self) -> ProtocolType {
ProtocolType::LCP
}
fn peer_options_start(&mut self) {
self.auth = AuthType::None;
}
fn peer_option_received(&mut self, code: u8, data: &[u8]) -> Verdict {
let opt = Option::from(code);
trace!("LCP: rx option {:?} {:?} {:?}", code, opt, data);
match opt {
Option::Unknown => Verdict::Rej,
Option::Asyncmap => {
if data.len() == 4 {
self.asyncmap_remote = u32::from_be_bytes(data.try_into().unwrap());
Verdict::Ack
} else {
Verdict::Rej
}
}
Option::Auth => {
if data == &[0xc0, 0x23] {
self.auth = AuthType::PAP;
Verdict::Ack
} else {
Verdict::Nack(&[0xc0, 0x23])
}
}
}
}
fn own_options(&mut self, mut f: impl FnMut(u8, &[u8])) {
if !self.asyncmap_rej {
f(Option::Asyncmap.into(), &self.asyncmap.to_be_bytes());
}
}
fn own_option_nacked(&mut self, code: u8, data: &[u8], is_rej: bool) {
let opt = Option::from(code);
trace!("LCP nak {:?} {:?} {:?} {:?}", code, opt, data, is_rej);
match opt {
Option::Asyncmap => {
if !is_rej && data.len() == 4 {
self.asyncmap = u32::from_be_bytes(data.try_into().unwrap())
} else {
self.asyncmap_rej = true
}
}
_ => {}
}
}
}