use crate::ast::*;
use crate::builders::WireContext;
use crate::packet::internet_checksum;
use alloc::vec::Vec;
use core::net::IpAddr;
pub fn build_ospf_payload(ctx: &WireContext, spec: &OspfSpec, payload: &[u8]) -> (Vec<u8>, IpAddr, u8) {
let router_id = match spec.router_id {
Some(IpAddr::V4(r)) => r.octets(),
_ => match ctx.src_ip {
IpAddr::V4(s) => s.octets(),
_ => [10, 0, 0, 1],
},
};
let ospf_type = spec.ospf_type.unwrap_or(OspfType::Hello);
let type_code = match ospf_type {
OspfType::Hello => 1_u8,
OspfType::Dbd => 2_u8,
OspfType::Lsr => 3_u8,
OspfType::Lsu => 4_u8,
OspfType::LsAck => 5_u8,
};
let mut ospf = Vec::with_capacity(44 + payload.len());
ospf.push(2); ospf.push(type_code);
ospf.extend_from_slice(&0_u16.to_be_bytes()); ospf.extend_from_slice(&router_id);
ospf.extend_from_slice(&spec.area_id.unwrap_or(0).to_be_bytes());
ospf.extend_from_slice(&[0, 0]); ospf.extend_from_slice(&0_u16.to_be_bytes()); ospf.extend_from_slice(&[0u8; 8]);
match ospf_type {
OspfType::Hello => {
ospf.extend_from_slice(&[255, 255, 255, 0]); ospf.extend_from_slice(&spec.hello_interval.unwrap_or(10).to_be_bytes());
ospf.push(0x02); ospf.push(spec.priority.unwrap_or(1));
ospf.extend_from_slice(&spec.dead_interval.unwrap_or(40).to_be_bytes());
ospf.extend_from_slice(&[0u8; 4]); ospf.extend_from_slice(&[0u8; 4]); }
OspfType::Dbd => {
ospf.extend_from_slice(&1500_u16.to_be_bytes()); ospf.push(0x02); ospf.push(0x07); ospf.extend_from_slice(&spec.dead_interval.unwrap_or(1).to_be_bytes()); }
OspfType::Lsr => {
ospf.extend_from_slice(&1_u32.to_be_bytes()); ospf.extend_from_slice(&router_id); ospf.extend_from_slice(&router_id); }
OspfType::Lsu => {
ospf.extend_from_slice(&0_u32.to_be_bytes());
}
OspfType::LsAck => {
ospf.extend_from_slice(&spec.hello_interval.unwrap_or(1).to_be_bytes()); ospf.push(0x02); ospf.push(1); ospf.extend_from_slice(&router_id);
ospf.extend_from_slice(&router_id);
ospf.extend_from_slice(&0x8000_0001_u32.to_be_bytes()); ospf.extend_from_slice(&0_u16.to_be_bytes()); ospf.extend_from_slice(&20_u16.to_be_bytes()); }
}
ospf.extend_from_slice(payload);
let total_len = ospf.len() as u16;
ospf[2..4].copy_from_slice(&total_len.to_be_bytes());
let cksum = internet_checksum(&[&ospf[..]]);
ospf[12..14].copy_from_slice(&cksum.to_be_bytes());
let dst_ip = match ctx.dst_ip {
IpAddr::V6(_) => IpAddr::V6(core::net::Ipv6Addr::new(0xff02, 0, 0, 0, 0, 0, 0, 5)),
_ => IpAddr::V4(core::net::Ipv4Addr::new(224, 0, 0, 5)),
};
(ospf, dst_ip, 89)
}