use crate::ast::*;
use crate::builders::WireContext;
use alloc::vec::Vec;
use core::net::IpAddr;
pub fn build_dhcp_payload(
ctx: &WireContext,
spec: &DhcpSpec,
payload_bytes: &[u8],
) -> (Vec<u8>, u16, u16) {
if ctx.src_ip.is_ipv4() {
let is_server_msg = spec.is_offer || spec.is_ack;
let op = if is_server_msg { 2u8 } else { 1u8 };
let xid = spec.xid.unwrap_or(0x12345678);
let mut pkt = Vec::with_capacity(300);
pkt.push(op); pkt.push(1); pkt.push(6); pkt.push(0); pkt.extend_from_slice(&xid.to_be_bytes());
pkt.extend_from_slice(&0u16.to_be_bytes()); let flags = if spec.is_discover { 0x8000u16 } else { 0u16 };
pkt.extend_from_slice(&flags.to_be_bytes());
if let Some(IpAddr::V4(v4)) = spec.ciaddr {
pkt.extend_from_slice(&v4.octets());
} else {
pkt.extend_from_slice(&[0, 0, 0, 0]);
}
if let Some(IpAddr::V4(v4)) = spec.yiaddr {
pkt.extend_from_slice(&v4.octets());
} else {
pkt.extend_from_slice(&[0, 0, 0, 0]);
}
if let Some(IpAddr::V4(v4)) = spec.siaddr {
pkt.extend_from_slice(&v4.octets());
} else {
pkt.extend_from_slice(&[0, 0, 0, 0]);
}
pkt.extend_from_slice(&[0, 0, 0, 0]);
let chaddr = spec.chaddr.unwrap_or(ctx.src_mac);
pkt.extend_from_slice(&chaddr);
pkt.extend_from_slice(&[0u8; 10]);
pkt.extend_from_slice(&[0u8; 64]);
pkt.extend_from_slice(&[0u8; 128]);
pkt.extend_from_slice(&[99, 130, 83, 99]);
let msg_type = if spec.is_discover {
1u8 } else if spec.is_offer {
2u8 } else if spec.is_request {
3u8 } else if spec.is_ack {
5u8 } else if spec.is_release {
7u8 } else {
1u8 };
pkt.extend_from_slice(&[53, 1, msg_type]);
if let Some(IpAddr::V4(v4)) = spec.subnet_mask {
pkt.extend_from_slice(&[1, 4]);
pkt.extend_from_slice(&v4.octets());
}
if let Some(IpAddr::V4(v4)) = spec.router {
pkt.extend_from_slice(&[3, 4]);
pkt.extend_from_slice(&v4.octets());
}
if let Some(IpAddr::V4(v4)) = spec.dns_server {
pkt.extend_from_slice(&[6, 4]);
pkt.extend_from_slice(&v4.octets());
}
if let Some(hostname) = spec.hostname {
let bytes = hostname.as_bytes();
pkt.push(12);
pkt.push(bytes.len() as u8);
pkt.extend_from_slice(bytes);
}
if let Some(lease) = spec.lease_time {
pkt.extend_from_slice(&[51, 4]);
pkt.extend_from_slice(&lease.to_be_bytes());
}
if !payload_bytes.is_empty() {
pkt.extend_from_slice(payload_bytes);
}
pkt.push(255);
let (sport, dport) = if is_server_msg { (67, 68) } else { (68, 67) };
(pkt, sport, dport)
} else {
let msg_type = if spec.is_solicit || spec.is_discover {
1u8 } else if spec.is_advertise || spec.is_offer {
2u8 } else if spec.is_request {
3u8 } else if spec.is_reply || spec.is_ack {
7u8 } else if spec.is_release {
8u8 } else {
1u8 };
let xid = spec.xid.unwrap_or(0x123456);
let mut pkt = alloc::vec![
msg_type,
(xid >> 16) as u8,
(xid >> 8) as u8,
xid as u8,
];
pkt.extend_from_slice(&[0, 1, 0, 10]); pkt.extend_from_slice(&[0, 3, 0, 1]); pkt.extend_from_slice(&ctx.src_mac);
if !payload_bytes.is_empty() {
pkt.extend_from_slice(payload_bytes);
}
let (sport, dport) = if spec.is_advertise || spec.is_reply || spec.is_ack {
(547, 546)
} else {
(546, 547)
};
(pkt, sport, dport)
}
}