use crate::icmpv6::ndp::{NdpOptionPacket, NdpOptionTypes, NeighborSolicitPacket};
use crate::icmpv6::{self, Icmpv6Header, Icmpv6Packet, Icmpv6Type, checksum};
use crate::packet::Packet;
use bytes::Bytes;
use nex_core::mac::MacAddr;
use std::net::Ipv6Addr;
fn octets_len(len: usize) -> u8 {
((len + 7) / 8) as u8
}
#[derive(Clone, Debug)]
pub struct NdpPacketBuilder {
pub src_mac: MacAddr,
pub dst_mac: MacAddr,
pub src_ip: Ipv6Addr,
pub dst_ip: Ipv6Addr,
}
impl NdpPacketBuilder {
pub fn new(src_mac: MacAddr, src_ip: Ipv6Addr, dst_ip: Ipv6Addr) -> Self {
Self {
src_mac,
dst_mac: MacAddr::broadcast(),
src_ip,
dst_ip,
}
}
pub fn dst_mac(mut self, dst_mac: MacAddr) -> Self {
self.dst_mac = dst_mac;
self
}
pub fn build(&self) -> Icmpv6Packet {
let mac_bytes = self.src_mac.octets();
let opt_payload = Bytes::copy_from_slice(&mac_bytes);
let opt_len = octets_len(mac_bytes.len());
let options = vec![NdpOptionPacket {
option_type: NdpOptionTypes::SourceLLAddr,
length: opt_len,
payload: opt_payload,
}];
let packet = NeighborSolicitPacket {
header: Icmpv6Header {
icmpv6_type: Icmpv6Type::NeighborSolicitation,
icmpv6_code: icmpv6::ndp::Icmpv6Codes::NoCode,
checksum: 0,
},
reserved: 0,
target_addr: self.dst_ip,
options,
payload: Bytes::new(),
};
let mut icmp_packet = Icmpv6Packet::from_bytes(packet.to_bytes())
.expect("Failed to create Icmpv6Packet from NeighborSolicitPacket");
icmp_packet.header.checksum = checksum(&icmp_packet, &self.src_ip, &self.dst_ip);
icmp_packet
}
pub fn to_bytes(&self) -> Bytes {
self.build().to_bytes()
}
}