use alloc::format;
use alloc::vec::Vec;
use crate::ast::{L2Modifiers, MplsSpec, Protocol};
use crate::reverse::{ProtocolDissection, be_u32, push_if, sd};
pub(crate) fn peel_mpls(
b: &[u8],
dst_mac: [u8; 6],
et: &mut u16,
off: &mut usize,
l2: &mut L2Modifiers,
) {
if matches!(*et, 0x8847 | 0x8848) && *off + 4 <= b.len() {
let shim = be_u32(b, *off);
let (exp, bos, mttl) = (
((shim >> 9) & 0x07) as u8,
((shim >> 8) & 0x01) as u8,
(shim & 0xFF) as u8,
);
l2.mpls = Some(MplsSpec {
label: shim >> 12,
exp: (exp != 0).then_some(exp),
bos: (bos != 1).then_some(bos),
ttl: (mttl != 64).then_some(mttl),
});
*off += 4;
if *off + 28 <= b.len()
&& b[*off..*off + 6] == [0x00, 0x01, 0x08, 0x00, 0x06, 0x04]
&& matches!(b[*off + 6..*off + 8], [0x00, 0x01 | 0x02])
{
*et = 0x0806;
} else if dst_mac == [0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e] && *off + 2 <= b.len() {
*et = 0x88CC;
} else if *off + 38 <= b.len() && b[*off..*off + 3] == [0x42, 0x42, 0x03] {
*et = (b.len() - *off) as u16;
} else if *off + 110 <= b.len() && b[*off..*off + 2] == [0x01, 0x01] {
*et = 0x8809;
} else if dst_mac == [0x01, 0x80, 0xc2, 0x00, 0x00, 0x03] && *off + 4 <= b.len() {
*et = 0x888E;
} else if let Some(&nib) = b.get(*off) {
match nib >> 4 {
4 if *off + 20 <= b.len() && (nib & 0x0f) >= 5 => *et = 0x0800,
6 if *off + 40 <= b.len() => *et = 0x86DD,
_ => {}
}
}
}
}
pub(crate) fn dissect_mpls(m: &MplsSpec, res: Vec<u8>) -> ProtocolDissection {
let mut t = format!("mpls {}", m.label);
push_if(&mut t, "exp", m.exp.unwrap_or(0), 0);
push_if(&mut t, "bos", m.bos.unwrap_or(1), 1);
push_if(&mut t, "mpls_ttl", m.ttl.unwrap_or(64), 64);
sd(Protocol::Mpls, t, res)
}