use alloc::string::String;
use core::fmt::Write as _;
use core::net::IpAddr;
use crate::ast::Protocol;
use crate::reverse::{ProtocolDissection, be_u32, ipv4_at, ipv6_at, push_if};
use super::ok_dissect;
pub(crate) fn dissect_sflow(payload: &[u8], sp: u16, dp: u16) -> Option<ProtocolDissection> {
if payload.len() < 28
|| be_u32(payload, 0) != 5
|| !(sp == 6343 || dp == 6343 || sp == 16343 || dp == 16343)
{
return None;
}
let (agent_ip, hdr_end) = match be_u32(payload, 4) {
1 => (IpAddr::V4(ipv4_at(payload, 8)), 28usize),
2 if payload.len() >= 40 => (IpAddr::V6(ipv6_at(payload, 8)), 40usize),
_ => return None,
};
let base = hdr_end - 16;
let residual_start = if payload.len() >= hdr_end + 40 {
hdr_end + 40
} else {
hdr_end
};
let mut tokens = String::from("sflow");
let _ = write!(tokens, " agent_ip {agent_ip}");
push_if(&mut tokens, "sub_agent_id", be_u32(payload, base), 0);
push_if(&mut tokens, "seq", be_u32(payload, base + 4), 1);
push_if(&mut tokens, "uptime", be_u32(payload, base + 8), 1000);
push_if(&mut tokens, "samples", be_u32(payload, base + 12), 1);
ok_dissect(Protocol::Sflow, tokens, payload[residual_start..].to_vec())
}