use alloc::string::String;
use alloc::vec::Vec;
use core::fmt::Write as _;
use crate::ast::Protocol;
use crate::reverse::{ProtocolDissection, be_u16, be_u32, be_u64, push_hex, push_if, sd};
pub(crate) fn dissect_openflow(b: &[u8]) -> Option<ProtocolDissection> {
if b.len() < 8 || !matches!(b[0], 1..=6) {
return None;
}
let (body, mut t, mut res) = (&b[8..], String::from("openflow"), Vec::new());
push_if(&mut t, "version", b[0], 4);
match b[1] {
0 | 2 | 3 | 5 | 13 => {
t.push_str(match b[1] {
0 => " hello",
2 => " echo_req",
3 => " echo_reply",
5 => " features_req",
_ => " packet_out",
});
res.extend_from_slice(body);
}
6 if body.len() >= 24 => {
t.push_str(" features_reply");
push_hex(&mut t, "dpid", be_u64(body, 0), 1, 1);
push_if(&mut t, "table_id", body[12], 254);
push_if(&mut t, "priority", be_u32(body, 20) as u16, 0);
res.extend_from_slice(&body[24..]);
}
10 => {
t.push_str(" packet_in");
if body.len() == 1 {
let _ = write!(t, " table_id {}", body[0]);
} else {
res.extend_from_slice(body);
}
}
14 if body.len() >= 48 => {
t.push_str(" flow_mod");
push_hex(&mut t, "dpid", be_u64(body, 0), 0, 1);
push_if(&mut t, "table_id", body[16], 0);
push_if(&mut t, "priority", be_u16(body, 22), 100);
res.extend_from_slice(&body[48..]);
}
_ => return None,
}
push_if(&mut t, "xid", be_u32(b, 4), 1);
Some(sd(Protocol::Openflow, t, res))
}