Add RawHardwareAddress, use it in wire ndisc.

This avoids wire needing to know what medium we're on.
master
Dario Nieuwenhuis 2021-10-07 06:56:32 +02:00
parent fb2d0029d8
commit b4764e4973
10 changed files with 282 additions and 328 deletions

View File

@ -22,7 +22,7 @@ use smoltcp::{
};
macro_rules! send_icmp_ping {
(v4, $repr_type:ident, $packet_type:ident, $ident:expr, $seq_no:expr,
( $repr_type:ident, $packet_type:ident, $ident:expr, $seq_no:expr,
$echo_payload:expr, $socket:expr, $remote_addr:expr ) => {{
let icmp_repr = $repr_type::EchoRequest {
ident: $ident,
@ -35,22 +35,6 @@ macro_rules! send_icmp_ping {
let icmp_packet = $packet_type::new_unchecked(icmp_payload);
(icmp_repr, icmp_packet)
}};
(v6, $repr_type:ident, $packet_type:ident, $ident:expr, $seq_no:expr,
$echo_payload:expr, $socket:expr, $remote_addr:expr ) => {{
let icmp_repr = $repr_type::EchoRequest {
ident: $ident,
seq_no: $seq_no,
data: &$echo_payload,
};
let icmp_payload = $socket
.send(icmp_repr.buffer_len(&Medium::Ethernet), $remote_addr)
.unwrap();
let icmp_packet = $packet_type::new_unchecked(icmp_payload);
(icmp_repr, icmp_packet)
}};
}
macro_rules! get_icmp_pong {
@ -186,7 +170,6 @@ fn main() {
match remote_addr {
IpAddress::Ipv4(_) => {
let (icmp_repr, mut icmp_packet) = send_icmp_ping!(
v4,
Icmpv4Repr,
Icmpv4Packet,
ident,
@ -199,7 +182,6 @@ fn main() {
}
IpAddress::Ipv6(_) => {
let (icmp_repr, mut icmp_packet) = send_icmp_ping!(
v6,
Icmpv6Repr,
Icmpv6Packet,
ident,
@ -213,7 +195,6 @@ fn main() {
&remote_addr,
&mut icmp_packet,
&device_caps.checksum,
&device_caps.medium,
);
}
_ => unimplemented!(),
@ -249,7 +230,6 @@ fn main() {
&src_ipv6,
&icmp_packet,
&device_caps.checksum,
&device_caps.medium,
)
.unwrap();
get_icmp_pong!(

View File

@ -389,7 +389,6 @@ impl<'a> IpPacket<'a> {
&_ip_repr.dst_addr(),
&mut Icmpv6Packet::new_unchecked(payload),
&caps.checksum,
&caps.medium,
),
#[cfg(feature = "socket-raw")]
IpPacket::Raw((_, raw_packet)) => payload.copy_from_slice(raw_packet),
@ -1198,7 +1197,7 @@ impl<'a> InterfaceInner<'a> {
header: ipv6_repr,
data: &payload[0..payload_len],
};
Ok(self.icmpv6_reply(cx, ipv6_repr, icmpv6_reply_repr))
Ok(self.icmpv6_reply(ipv6_repr, icmpv6_reply_repr))
}
IpRepr::Unspecified { .. } => Err(Error::Unaddressable),
IpRepr::Sixlowpan(_) => Err(Error::Malformed), // XXX(thvdveld): this is just wrong;
@ -1394,7 +1393,7 @@ impl<'a> InterfaceInner<'a> {
header: ipv6_repr,
data: &ip_payload[0..payload_len],
};
Ok(self.icmpv6_reply(cx, ipv6_repr, icmp_reply_repr))
Ok(self.icmpv6_reply(ipv6_repr, icmp_reply_repr))
}
}
}
@ -1604,7 +1603,6 @@ impl<'a> InterfaceInner<'a> {
&ip_repr.dst_addr(),
&icmp_packet,
&cx.caps.checksum,
&cx.caps.medium,
)?;
#[cfg(feature = "socket-icmp")]
@ -1639,7 +1637,7 @@ impl<'a> InterfaceInner<'a> {
seq_no,
data,
};
Ok(self.icmpv6_reply(cx, ipv6_repr, icmp_reply_repr))
Ok(self.icmpv6_reply(ipv6_repr, icmp_reply_repr))
}
#[cfg(feature = "medium-ieee802154")]
IpRepr::Sixlowpan(sixlowpan_repr) => {
@ -1649,7 +1647,6 @@ impl<'a> InterfaceInner<'a> {
data,
};
Ok(self.icmpv6_reply(
cx,
Ipv6Repr {
src_addr: sixlowpan_repr.src_addr,
dst_addr: sixlowpan_repr.dst_addr,
@ -1714,23 +1711,24 @@ impl<'a> InterfaceInner<'a> {
flags,
} => {
let ip_addr = ip_repr.src_addr.into();
match lladdr {
Some(lladdr) if lladdr.is_unicast() && target_addr.is_unicast() => {
if flags.contains(NdiscNeighborFlags::OVERRIDE)
|| !self
.neighbor_cache
.as_mut()
.unwrap()
.lookup(&ip_addr, cx.now)
.found()
{
self.neighbor_cache
.as_mut()
.unwrap()
.fill(ip_addr, lladdr, cx.now)
}
if let Some(lladdr) = lladdr {
let lladdr = lladdr.parse(cx.caps.medium)?;
if !lladdr.is_unicast() || !target_addr.is_unicast() {
return Err(Error::Malformed);
}
if flags.contains(NdiscNeighborFlags::OVERRIDE)
|| !self
.neighbor_cache
.as_mut()
.unwrap()
.lookup(&ip_addr, cx.now)
.found()
{
self.neighbor_cache
.as_mut()
.unwrap()
.fill(ip_addr, lladdr, cx.now)
}
_ => (),
}
Ok(None)
}
@ -1739,27 +1737,31 @@ impl<'a> InterfaceInner<'a> {
lladdr,
..
} => {
match lladdr {
Some(lladdr) if lladdr.is_unicast() && target_addr.is_unicast() => self
.neighbor_cache
.as_mut()
.unwrap()
.fill(ip_repr.src_addr.into(), lladdr, cx.now),
_ => (),
if let Some(lladdr) = lladdr {
let lladdr = lladdr.parse(cx.caps.medium)?;
if !lladdr.is_unicast() || !target_addr.is_unicast() {
return Err(Error::Malformed);
}
self.neighbor_cache.as_mut().unwrap().fill(
ip_repr.src_addr.into(),
lladdr,
cx.now,
);
}
if self.has_solicited_node(ip_repr.dst_addr) && self.has_ip_addr(target_addr) {
let advert = Icmpv6Repr::Ndisc(NdiscRepr::NeighborAdvert {
flags: NdiscNeighborFlags::SOLICITED,
target_addr,
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
lladdr: Some(self.hardware_addr.unwrap()),
lladdr: Some(self.hardware_addr.unwrap().into()),
});
let ip_repr = Ipv6Repr {
src_addr: target_addr,
dst_addr: ip_repr.src_addr,
next_header: IpProtocol::Icmpv6,
hop_limit: 0xff,
payload_len: advert.buffer_len(&cx.caps.medium),
payload_len: advert.buffer_len(),
};
Ok(Some(IpPacket::Icmpv6((ip_repr, advert))))
} else {
@ -1917,7 +1919,6 @@ impl<'a> InterfaceInner<'a> {
#[cfg(feature = "proto-ipv6")]
fn icmpv6_reply<'frame, 'icmp: 'frame>(
&self,
cx: &Context,
ipv6_repr: Ipv6Repr,
icmp_repr: Icmpv6Repr<'icmp>,
) -> Option<IpPacket<'frame>> {
@ -1926,7 +1927,7 @@ impl<'a> InterfaceInner<'a> {
src_addr: ipv6_repr.dst_addr,
dst_addr: ipv6_repr.src_addr,
next_header: IpProtocol::Icmpv6,
payload_len: icmp_repr.buffer_len(&cx.caps.medium),
payload_len: icmp_repr.buffer_len(),
hop_limit: 64,
};
Some(IpPacket::Icmpv6((ipv6_reply_repr, icmp_repr)))
@ -1989,7 +1990,7 @@ impl<'a> InterfaceInner<'a> {
header: ipv6_repr,
data: &ip_payload[0..payload_len],
};
Ok(self.icmpv6_reply(cx, ipv6_repr, icmpv6_reply_repr))
Ok(self.icmpv6_reply(ipv6_repr, icmpv6_reply_repr))
}
#[cfg(feature = "proto-sixlowpan")]
IpRepr::Sixlowpan(sixlowpan_repr) => {
@ -2011,7 +2012,7 @@ impl<'a> InterfaceInner<'a> {
header: ipv6_repr,
data: &ip_payload[0..payload_len],
};
Ok(self.icmpv6_reply(cx, ipv6_repr, icmpv6_reply_repr))
Ok(self.icmpv6_reply(ipv6_repr, icmpv6_reply_repr))
}
IpRepr::Unspecified { .. } => Err(Error::Unaddressable),
}
@ -2254,7 +2255,7 @@ impl<'a> InterfaceInner<'a> {
let solicit = Icmpv6Repr::Ndisc(NdiscRepr::NeighborSolicit {
target_addr: dst_addr,
lladdr: self.hardware_addr,
lladdr: Some(self.hardware_addr.unwrap().into()),
});
let packet = IpPacket::Icmpv6((
@ -2262,7 +2263,7 @@ impl<'a> InterfaceInner<'a> {
src_addr,
dst_addr: dst_addr.solicited_node(),
next_header: IpProtocol::Icmpv6,
payload_len: solicit.buffer_len(&cx.caps.medium),
payload_len: solicit.buffer_len(),
hop_limit: 0xff,
},
solicit,
@ -2422,7 +2423,7 @@ impl<'a> InterfaceInner<'a> {
tx_len += udp_repr.header_len() + payload.len();
}
IpPacket::Icmpv6((_, icmp)) => {
tx_len += icmp.buffer_len(&cx.caps.medium);
tx_len += icmp.buffer_len();
}
_ => return Err(Error::Unrecognized),
}
@ -2466,7 +2467,6 @@ impl<'a> InterfaceInner<'a> {
&iphc_repr.dst_addr.into(),
&mut icmp_packet,
&cx.caps.checksum,
&cx.caps.medium,
);
}
_ => return Err(Error::Unrecognized),
@ -3135,7 +3135,7 @@ mod test {
dst_addr: src_addr,
next_header: IpProtocol::Icmpv6,
hop_limit: 64,
payload_len: expected_icmp_repr.buffer_len(&Medium::Ethernet),
payload_len: expected_icmp_repr.buffer_len(),
};
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
let expected_icmp_repr = Icmpv4Repr::DstUnreachable {
@ -3157,7 +3157,7 @@ mod test {
// The expected packet does not exceed the IPV4_MIN_MTU
#[cfg(feature = "proto-ipv6")]
assert_eq!(
expected_ip_repr.buffer_len() + expected_icmp_repr.buffer_len(&Medium::Ethernet),
expected_ip_repr.buffer_len() + expected_icmp_repr.buffer_len(),
MIN_MTU
);
// The expected packet does not exceed the IPV4_MIN_MTU
@ -3267,7 +3267,7 @@ mod test {
dst_addr: local_ip_addr.solicited_node(),
next_header: IpProtocol::Icmpv6,
hop_limit: 0xff,
payload_len: solicit.buffer_len(&Medium::Ethernet),
payload_len: solicit.buffer_len(),
});
let mut frame = EthernetFrame::new_unchecked(&mut eth_bytes);
@ -3281,7 +3281,6 @@ mod test {
&local_ip_addr.solicited_node().into(),
&mut Icmpv6Packet::new_unchecked(&mut frame.payload_mut()[ip_repr.buffer_len()..]),
&ChecksumCapabilities::default(),
&iface.device().capabilities().medium,
);
}
@ -3296,7 +3295,7 @@ mod test {
dst_addr: remote_ip_addr,
next_header: IpProtocol::Icmpv6,
hop_limit: 0xff,
payload_len: icmpv6_expected.buffer_len(&Medium::Ethernet),
payload_len: icmpv6_expected.buffer_len(),
};
let cx = iface.context(Instant::from_secs(0));
@ -3530,7 +3529,7 @@ mod test {
src_addr: Ipv6Address::LOOPBACK,
dst_addr: remote_ip_addr,
next_header: IpProtocol::Icmpv6,
payload_len: reply_icmp_repr.buffer_len(&Medium::Ethernet),
payload_len: reply_icmp_repr.buffer_len(),
hop_limit: 0x40,
};

View File

@ -427,19 +427,18 @@ impl<'a> IcmpSocket<'a> {
IcmpRepr::Ipv6(ref icmp_repr) => {
let packet_buf = self
.rx_buffer
.enqueue(icmp_repr.buffer_len(&_cx.caps.medium), ip_repr.src_addr())?;
.enqueue(icmp_repr.buffer_len(), ip_repr.src_addr())?;
icmp_repr.emit(
&ip_repr.src_addr(),
&ip_repr.dst_addr(),
&mut Icmpv6Packet::new_unchecked(packet_buf),
&ChecksumCapabilities::default(),
&_cx.caps.medium,
);
net_trace!(
"{}:{}: receiving {} octets",
self.meta.handle,
icmp_repr.buffer_len(&_cx.caps.medium),
icmp_repr.buffer_len(),
packet_buf.len()
);
}
@ -487,13 +486,12 @@ impl<'a> IcmpSocket<'a> {
&ipv6_addr.into(),
&packet,
&ChecksumCapabilities::ignored(),
&_cx.caps.medium,
)?;
let ip_repr = IpRepr::Ipv6(Ipv6Repr {
src_addr: src_addr,
dst_addr: ipv6_addr,
next_header: IpProtocol::Icmpv6,
payload_len: repr.buffer_len(&_cx.caps.medium),
payload_len: repr.buffer_len(),
hop_limit: hop_limit,
});
emit((ip_repr, IcmpRepr::Ipv6(repr)))
@ -868,7 +866,6 @@ mod test_ipv6 {
&REMOTE_IPV6.into(),
&mut packet,
&checksum,
&crate::phy::Medium::Ethernet,
);
assert_eq!(
@ -916,7 +913,6 @@ mod test_ipv6 {
&REMOTE_IPV6.into(),
&mut packet,
&checksum,
&crate::phy::Medium::Ethernet,
);
s.set_hop_limit(Some(0x2a));
@ -933,7 +929,7 @@ mod test_ipv6 {
src_addr: Ipv6Address::UNSPECIFIED,
dst_addr: REMOTE_IPV6,
next_header: IpProtocol::Icmpv6,
payload_len: ECHOV6_REPR.buffer_len(&crate::phy::Medium::Ethernet),
payload_len: ECHOV6_REPR.buffer_len(),
hop_limit: 0x2a,
})
);
@ -960,7 +956,6 @@ mod test_ipv6 {
&REMOTE_IPV6.into(),
&mut packet,
&checksum,
&crate::phy::Medium::Ethernet,
);
let data = &packet.into_inner()[..];
@ -999,7 +994,6 @@ mod test_ipv6 {
&REMOTE_IPV6.into(),
&mut packet,
&checksum,
&crate::phy::Medium::Ethernet,
);
// Ensure that a packet with an identifier that isn't the bound
@ -1042,7 +1036,7 @@ mod test_ipv6 {
src_addr: REMOTE_IPV6.into(),
dst_addr: LOCAL_IPV6.into(),
protocol: IpProtocol::Icmpv6,
payload_len: icmp_repr.buffer_len(&crate::phy::Medium::Ethernet),
payload_len: icmp_repr.buffer_len(),
hop_limit: 0x40,
};
@ -1064,7 +1058,6 @@ mod test_ipv6 {
&REMOTE_IPV6.into(),
&mut packet,
&checksum,
&crate::phy::Medium::Ethernet,
);
assert_eq!(
socket.recv(),

View File

@ -357,15 +357,17 @@ impl fmt::Display for Repr {
source_protocol_addr,
target_hardware_addr,
target_protocol_addr,
} => write!(
f,
"ARP type=Ethernet+IPv4 src={}/{} tgt={}/{} op={:?}",
source_hardware_addr,
source_protocol_addr,
target_hardware_addr,
target_protocol_addr,
operation
),
} => {
write!(
f,
"ARP type=Ethernet+IPv4 src={}/{} tgt={}/{} op={:?}",
source_hardware_addr,
source_protocol_addr,
target_hardware_addr,
target_protocol_addr,
operation
)
}
}
}
}

View File

@ -2,7 +2,6 @@ use byteorder::{ByteOrder, NetworkEndian};
use core::{cmp, fmt};
use crate::phy::ChecksumCapabilities;
use crate::phy::Medium;
use crate::wire::ip::checksum;
use crate::wire::MldRepr;
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
@ -546,7 +545,6 @@ impl<'a> Repr<'a> {
dst_addr: &IpAddress,
packet: &Packet<&'a T>,
checksum_caps: &ChecksumCapabilities,
medium: &Medium,
) -> Result<Repr<'a>>
where
T: AsRef<[u8]> + ?Sized,
@ -620,16 +618,14 @@ impl<'a> Repr<'a> {
data: packet.payload(),
}),
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
(msg_type, 0) if msg_type.is_ndisc() => {
NdiscRepr::parse(packet, medium).map(Repr::Ndisc)
}
(msg_type, 0) if msg_type.is_ndisc() => NdiscRepr::parse(packet).map(Repr::Ndisc),
(msg_type, 0) if msg_type.is_mld() => MldRepr::parse(packet).map(Repr::Mld),
_ => Err(Error::Unrecognized),
}
}
/// Return the length of a packet that will be emitted from this high-level representation.
pub fn buffer_len(&self, medium: &Medium) -> usize {
pub fn buffer_len(&self) -> usize {
match self {
&Repr::DstUnreachable { header, data, .. }
| &Repr::PktTooBig { header, data, .. }
@ -641,7 +637,7 @@ impl<'a> Repr<'a> {
field::ECHO_SEQNO.end + data.len()
}
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
&Repr::Ndisc(ndisc) => ndisc.buffer_len(medium),
&Repr::Ndisc(ndisc) => ndisc.buffer_len(),
&Repr::Mld(mld) => mld.buffer_len(),
}
}
@ -654,7 +650,6 @@ impl<'a> Repr<'a> {
dst_addr: &IpAddress,
packet: &mut Packet<&mut T>,
checksum_caps: &ChecksumCapabilities,
medium: &Medium,
) where
T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
{
@ -736,7 +731,7 @@ impl<'a> Repr<'a> {
}
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
Repr::Ndisc(ndisc) => ndisc.emit(packet, medium),
Repr::Ndisc(ndisc) => ndisc.emit(packet),
Repr::Mld(mld) => mld.emit(packet),
}
@ -844,7 +839,6 @@ mod test {
&MOCK_IP_ADDR_2,
&packet,
&ChecksumCapabilities::default(),
&Medium::Ethernet,
)
.unwrap();
assert_eq!(repr, echo_packet_repr());
@ -853,14 +847,13 @@ mod test {
#[test]
fn test_echo_emit() {
let repr = echo_packet_repr();
let mut bytes = vec![0xa5; repr.buffer_len(&Medium::Ethernet)];
let mut bytes = vec![0xa5; repr.buffer_len()];
let mut packet = Packet::new_unchecked(&mut bytes);
repr.emit(
&MOCK_IP_ADDR_1,
&MOCK_IP_ADDR_2,
&mut packet,
&ChecksumCapabilities::default(),
&Medium::Ethernet,
);
assert_eq!(&packet.into_inner()[..], &ECHO_PACKET_BYTES[..]);
}
@ -899,7 +892,6 @@ mod test {
&MOCK_IP_ADDR_2,
&packet,
&ChecksumCapabilities::default(),
&Medium::Ethernet,
)
.unwrap();
assert_eq!(repr, too_big_packet_repr());
@ -908,14 +900,13 @@ mod test {
#[test]
fn test_too_big_emit() {
let repr = too_big_packet_repr();
let mut bytes = vec![0xa5; repr.buffer_len(&Medium::Ethernet)];
let mut bytes = vec![0xa5; repr.buffer_len()];
let mut packet = Packet::new_unchecked(&mut bytes);
repr.emit(
&MOCK_IP_ADDR_1,
&MOCK_IP_ADDR_2,
&mut packet,
&ChecksumCapabilities::default(),
&Medium::Ethernet,
);
assert_eq!(&packet.into_inner()[..], &PKT_TOO_BIG_BYTES[..]);
}

View File

@ -503,15 +503,17 @@ impl<'a> fmt::Display for Repr<'a> {
length,
segments_left,
home_address,
} => write!(
f,
"IPv6 Routing next_hdr={} length={} type={} seg_left={} home_address={}",
next_header,
length,
Type::Type2,
segments_left,
home_address
),
} => {
write!(
f,
"IPv6 Routing next_hdr={} length={} type={} seg_left={} home_address={}",
next_header,
length,
Type::Type2,
segments_left,
home_address
)
}
Repr::Rpl {
next_header,
length,
@ -520,17 +522,10 @@ impl<'a> fmt::Display for Repr<'a> {
cmpr_e,
pad,
..
} => write!(
f,
"IPv6 Routing next_hdr={} length={} type={} seg_left={} cmpr_i={} cmpr_e={} pad={}",
next_header,
length,
Type::Rpl,
segments_left,
cmpr_i,
cmpr_e,
pad
),
} => {
write!(f, "IPv6 Routing next_hdr={} length={} type={} seg_left={} cmpr_i={} cmpr_e={} pad={}",
next_header, length, Type::Rpl, segments_left, cmpr_i, cmpr_e, pad)
}
}
}
}

View File

@ -532,7 +532,6 @@ mod test {
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
&packet,
&ChecksumCapabilities::default(),
&crate::phy::Medium::Ethernet,
);
assert_eq!(repr, Ok(create_repr(Message::MldQuery)));
}
@ -545,7 +544,6 @@ mod test {
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
&packet,
&ChecksumCapabilities::default(),
&crate::phy::Medium::Ethernet,
);
assert_eq!(repr, Ok(create_repr(Message::MldReport)));
}
@ -560,7 +558,6 @@ mod test {
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
&mut packet,
&ChecksumCapabilities::default(),
&crate::phy::Medium::Ethernet,
);
assert_eq!(&packet.into_inner()[..], &QUERY_PACKET_BYTES[..]);
}
@ -575,7 +572,6 @@ mod test {
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
&mut packet,
&ChecksumCapabilities::default(),
&crate::phy::Medium::Ethernet,
);
assert_eq!(&packet.into_inner()[..], &REPORT_PACKET_BYTES[..]);
}

View File

@ -123,6 +123,8 @@ mod sixlowpan;
mod tcp;
mod udp;
use crate::{phy::Medium, Error};
pub use self::pretty_print::PrettyPrinter;
#[cfg(feature = "medium-ethernet")]
@ -310,3 +312,94 @@ impl From<Ieee802154Address> for HardwareAddress {
HardwareAddress::Ieee802154(addr)
}
}
#[cfg(not(feature = "medium-ieee802154"))]
pub const MAX_HARDWARE_ADDRESS_LEN: usize = 6;
#[cfg(feature = "medium-ieee802154")]
pub const MAX_HARDWARE_ADDRESS_LEN: usize = 8;
/// Unparsed hardware address.
///
/// Used to make NDISC parsing agnostic of the hardware medium in use.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct RawHardwareAddress {
len: u8,
data: [u8; MAX_HARDWARE_ADDRESS_LEN],
}
impl RawHardwareAddress {
pub fn from_bytes(addr: &[u8]) -> Self {
let mut data = [0u8; MAX_HARDWARE_ADDRESS_LEN];
data[..addr.len()].copy_from_slice(addr);
Self {
len: addr.len() as u8,
data,
}
}
pub fn as_bytes(&self) -> &[u8] {
&self.data[..self.len as usize]
}
pub fn len(&self) -> usize {
self.len as usize
}
pub fn parse(&self, medium: Medium) -> Result<HardwareAddress, Error> {
match medium {
#[cfg(feature = "medium-ethernet")]
Medium::Ethernet => {
if self.len() < 6 {
return Err(Error::Malformed);
}
Ok(HardwareAddress::Ethernet(EthernetAddress::from_bytes(
self.as_bytes(),
)))
}
#[cfg(feature = "medium-ieee802154")]
Medium::Ieee802154 => {
if self.len() < 8 {
return Err(Error::Malformed);
}
Ok(HardwareAddress::Ieee802154(Ieee802154Address::from_bytes(
self.as_bytes(),
)))
}
#[cfg(feature = "medium-ip")]
Medium::Ip => unreachable!(),
}
}
}
impl core::fmt::Display for RawHardwareAddress {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
for (i, &b) in self.as_bytes().iter().enumerate() {
if i != 0 {
write!(f, ":")?;
}
write!(f, "{:02x}", b)?;
}
Ok(())
}
}
#[cfg(feature = "medium-ethernet")]
impl From<EthernetAddress> for RawHardwareAddress {
fn from(addr: EthernetAddress) -> Self {
Self::from_bytes(addr.as_bytes())
}
}
#[cfg(feature = "medium-ieee802154")]
impl From<Ieee802154Address> for RawHardwareAddress {
fn from(addr: Ieee802154Address) -> Self {
Self::from_bytes(addr.as_bytes())
}
}
impl From<HardwareAddress> for RawHardwareAddress {
fn from(addr: HardwareAddress) -> Self {
Self::from_bytes(addr.as_bytes())
}
}

View File

@ -1,11 +1,10 @@
use bitflags::bitflags;
use byteorder::{ByteOrder, NetworkEndian};
use crate::phy::Medium;
use crate::time::Duration;
use crate::wire::icmpv6::{field, Message, Packet};
use crate::wire::HardwareAddress;
use crate::wire::Ipv6Address;
use crate::wire::RawHardwareAddress;
use crate::wire::{Ipv6Packet, Ipv6Repr};
use crate::wire::{NdiscOption, NdiscOptionRepr, NdiscOptionType};
use crate::wire::{NdiscPrefixInformation, NdiscRedirectedHeader};
@ -195,7 +194,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Repr<'a> {
RouterSolicit {
lladdr: Option<HardwareAddress>,
lladdr: Option<RawHardwareAddress>,
},
RouterAdvert {
hop_limit: u8,
@ -203,23 +202,23 @@ pub enum Repr<'a> {
router_lifetime: Duration,
reachable_time: Duration,
retrans_time: Duration,
lladdr: Option<HardwareAddress>,
lladdr: Option<RawHardwareAddress>,
mtu: Option<u32>,
prefix_info: Option<NdiscPrefixInformation>,
},
NeighborSolicit {
target_addr: Ipv6Address,
lladdr: Option<HardwareAddress>,
lladdr: Option<RawHardwareAddress>,
},
NeighborAdvert {
flags: NeighborFlags,
target_addr: Ipv6Address,
lladdr: Option<HardwareAddress>,
lladdr: Option<RawHardwareAddress>,
},
Redirect {
target_addr: Ipv6Address,
dest_addr: Ipv6Address,
lladdr: Option<HardwareAddress>,
lladdr: Option<RawHardwareAddress>,
redirected_hdr: Option<NdiscRedirectedHeader<'a>>,
},
}
@ -227,7 +226,7 @@ pub enum Repr<'a> {
impl<'a> Repr<'a> {
/// Parse an NDISC packet and return a high-level representation of the
/// packet.
pub fn parse<T>(packet: &Packet<&'a T>, medium: &Medium) -> Result<Repr<'a>>
pub fn parse<T>(packet: &Packet<&'a T>) -> Result<Repr<'a>>
where
T: AsRef<[u8]> + ?Sized,
{
@ -236,7 +235,7 @@ impl<'a> Repr<'a> {
let lladdr = if !packet.payload().is_empty() {
let opt = NdiscOption::new_checked(packet.payload())?;
match opt.option_type() {
NdiscOptionType::SourceLinkLayerAddr => Some(opt.link_layer_addr(medium)),
NdiscOptionType::SourceLinkLayerAddr => Some(opt.link_layer_addr()),
_ => {
return Err(Error::Unrecognized);
}
@ -251,7 +250,7 @@ impl<'a> Repr<'a> {
let (mut lladdr, mut mtu, mut prefix_info) = (None, None, None);
while packet.payload().len() - offset > 0 {
let pkt = NdiscOption::new_checked(&packet.payload()[offset..])?;
let opt = NdiscOptionRepr::parse(&pkt, medium)?;
let opt = NdiscOptionRepr::parse(&pkt)?;
match opt {
NdiscOptionRepr::SourceLinkLayerAddr(addr) => lladdr = Some(addr),
NdiscOptionRepr::Mtu(val) => mtu = Some(val),
@ -260,7 +259,7 @@ impl<'a> Repr<'a> {
return Err(Error::Unrecognized);
}
}
offset += opt.buffer_len(medium);
offset += opt.buffer_len();
}
Ok(Repr::RouterAdvert {
hop_limit: packet.current_hop_limit(),
@ -277,7 +276,7 @@ impl<'a> Repr<'a> {
let lladdr = if !packet.payload().is_empty() {
let opt = NdiscOption::new_checked(packet.payload())?;
match opt.option_type() {
NdiscOptionType::SourceLinkLayerAddr => Some(opt.link_layer_addr(medium)),
NdiscOptionType::SourceLinkLayerAddr => Some(opt.link_layer_addr()),
_ => {
return Err(Error::Unrecognized);
}
@ -294,7 +293,7 @@ impl<'a> Repr<'a> {
let lladdr = if !packet.payload().is_empty() {
let opt = NdiscOption::new_checked(packet.payload())?;
match opt.option_type() {
NdiscOptionType::TargetLinkLayerAddr => Some(opt.link_layer_addr(medium)),
NdiscOptionType::TargetLinkLayerAddr => Some(opt.link_layer_addr()),
_ => {
return Err(Error::Unrecognized);
}
@ -315,7 +314,7 @@ impl<'a> Repr<'a> {
let opt = NdiscOption::new_checked(&packet.payload()[offset..])?;
match opt.option_type() {
NdiscOptionType::SourceLinkLayerAddr => {
lladdr = Some(opt.link_layer_addr(medium));
lladdr = Some(opt.link_layer_addr());
offset += 8;
}
NdiscOptionType::RedirectedHeader => {
@ -349,7 +348,7 @@ impl<'a> Repr<'a> {
}
}
pub fn buffer_len(&self, medium: &Medium) -> usize {
pub fn buffer_len(&self) -> usize {
match self {
&Repr::RouterSolicit { lladdr } => match lladdr {
Some(_) => field::UNUSED.end + 8,
@ -374,34 +373,11 @@ impl<'a> Repr<'a> {
field::RETRANS_TM.end + offset
}
&Repr::NeighborSolicit { lladdr, .. } | &Repr::NeighborAdvert { lladdr, .. } => {
match lladdr {
Some(_addr) => {
match medium {
#[cfg(feature = "medium-ethernet")]
Medium::Ethernet => field::TARGET_ADDR.end + 8,
#[cfg(feature = "medium-ieee802154")]
Medium::Ieee802154 => {
// XXX: This is for 6LoWPAN
let mut len = field::TARGET_ADDR.end;
len += 2;
len += _addr.as_bytes().len();
// A packet of len == 30 is a packet with an Ethernet address
if len > 30 {
// TODO(thvdveld): find out why this padding is +4 and not +6
// WireShark wants a padding of +6, however, then the packet is not accepted when using ping
// When a padding of +4 is used, then WireShark complains and says that the packet is malformed,
// however, ping accepts this packet.
len += 4; // Padding
}
len
}
#[cfg(feature = "medium-ip")]
Medium::Ip => unreachable!(),
}
}
None => field::TARGET_ADDR.end,
let mut offset = field::TARGET_ADDR.end;
if let Some(lladdr) = lladdr {
offset += NdiscOptionRepr::SourceLinkLayerAddr(lladdr).buffer_len();
}
offset
}
&Repr::Redirect {
lladdr,
@ -420,7 +396,7 @@ impl<'a> Repr<'a> {
}
}
pub fn emit<T>(&self, packet: &mut Packet<&mut T>, medium: &Medium)
pub fn emit<T>(&self, packet: &mut Packet<&mut T>)
where
T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
{
@ -431,7 +407,7 @@ impl<'a> Repr<'a> {
packet.clear_reserved();
if let Some(lladdr) = lladdr {
let mut opt_pkt = NdiscOption::new_unchecked(packet.payload_mut());
NdiscOptionRepr::SourceLinkLayerAddr(lladdr).emit(&mut opt_pkt, medium);
NdiscOptionRepr::SourceLinkLayerAddr(lladdr).emit(&mut opt_pkt);
}
}
@ -455,26 +431,20 @@ impl<'a> Repr<'a> {
let mut offset = 0;
if let Some(lladdr) = lladdr {
let mut opt_pkt = NdiscOption::new_unchecked(packet.payload_mut());
NdiscOptionRepr::SourceLinkLayerAddr(lladdr).emit(&mut opt_pkt, medium);
match medium {
#[cfg(feature = "medium-ethernet")]
Medium::Ethernet => offset += 6,
#[cfg(feature = "medium-ieee802154")]
Medium::Ieee802154 => offset += 8,
#[cfg(feature = "medium-ip")]
_ => unreachable!(),
}
let opt = NdiscOptionRepr::SourceLinkLayerAddr(lladdr);
opt.emit(&mut opt_pkt);
offset += opt.buffer_len();
}
if let Some(mtu) = mtu {
let mut opt_pkt =
NdiscOption::new_unchecked(&mut packet.payload_mut()[offset..]);
NdiscOptionRepr::Mtu(mtu).emit(&mut opt_pkt, medium);
NdiscOptionRepr::Mtu(mtu).emit(&mut opt_pkt);
offset += 8;
}
if let Some(prefix_info) = prefix_info {
let mut opt_pkt =
NdiscOption::new_unchecked(&mut packet.payload_mut()[offset..]);
NdiscOptionRepr::PrefixInformation(prefix_info).emit(&mut opt_pkt, medium)
NdiscOptionRepr::PrefixInformation(prefix_info).emit(&mut opt_pkt)
}
}
@ -488,7 +458,7 @@ impl<'a> Repr<'a> {
packet.set_target_addr(target_addr);
if let Some(lladdr) = lladdr {
let mut opt_pkt = NdiscOption::new_unchecked(packet.payload_mut());
NdiscOptionRepr::SourceLinkLayerAddr(lladdr).emit(&mut opt_pkt, medium);
NdiscOptionRepr::SourceLinkLayerAddr(lladdr).emit(&mut opt_pkt);
}
}
@ -504,7 +474,7 @@ impl<'a> Repr<'a> {
packet.set_target_addr(target_addr);
if let Some(lladdr) = lladdr {
let mut opt_pkt = NdiscOption::new_unchecked(packet.payload_mut());
NdiscOptionRepr::TargetLinkLayerAddr(lladdr).emit(&mut opt_pkt, medium);
NdiscOptionRepr::TargetLinkLayerAddr(lladdr).emit(&mut opt_pkt);
}
}
@ -522,7 +492,7 @@ impl<'a> Repr<'a> {
let offset = match lladdr {
Some(lladdr) => {
let mut opt_pkt = NdiscOption::new_unchecked(packet.payload_mut());
NdiscOptionRepr::TargetLinkLayerAddr(lladdr).emit(&mut opt_pkt, medium);
NdiscOptionRepr::TargetLinkLayerAddr(lladdr).emit(&mut opt_pkt);
8
}
None => 0,
@ -530,7 +500,7 @@ impl<'a> Repr<'a> {
if let Some(redirected_hdr) = redirected_hdr {
let mut opt_pkt =
NdiscOption::new_unchecked(&mut packet.payload_mut()[offset..]);
NdiscOptionRepr::RedirectedHeader(redirected_hdr).emit(&mut opt_pkt, medium);
NdiscOptionRepr::RedirectedHeader(redirected_hdr).emit(&mut opt_pkt);
}
}
}
@ -543,7 +513,6 @@ mod test {
use crate::phy::ChecksumCapabilities;
use crate::wire::ip::test::{MOCK_IP_ADDR_1, MOCK_IP_ADDR_2};
use crate::wire::EthernetAddress;
use crate::wire::HardwareAddress;
use crate::wire::Icmpv6Repr;
static ROUTER_ADVERT_BYTES: [u8; 24] = [
@ -559,9 +528,7 @@ mod test {
router_lifetime: Duration::from_secs(900),
reachable_time: Duration::from_millis(900),
retrans_time: Duration::from_millis(900),
lladdr: Some(HardwareAddress::Ethernet(EthernetAddress([
0x52, 0x54, 0x00, 0x12, 0x34, 0x56,
]))),
lladdr: Some(EthernetAddress([0x52, 0x54, 0x00, 0x12, 0x34, 0x56]).into()),
mtu: None,
prefix_info: None,
})
@ -606,8 +573,7 @@ mod test {
&MOCK_IP_ADDR_1,
&MOCK_IP_ADDR_2,
&packet,
&ChecksumCapabilities::default(),
&Medium::Ethernet,
&ChecksumCapabilities::default()
)
.unwrap(),
create_repr()
@ -623,7 +589,6 @@ mod test {
&MOCK_IP_ADDR_2,
&mut packet,
&ChecksumCapabilities::default(),
&Medium::Ethernet,
);
assert_eq!(&packet.into_inner()[..], &ROUTER_ADVERT_BYTES[..]);
}

View File

@ -2,17 +2,11 @@ use bitflags::bitflags;
use byteorder::{ByteOrder, NetworkEndian};
use core::fmt;
use crate::phy::Medium;
use crate::time::Duration;
use crate::wire::{Ipv6Address, Ipv6Packet, Ipv6Repr};
use crate::wire::{Ipv6Address, Ipv6Packet, Ipv6Repr, MAX_HARDWARE_ADDRESS_LEN};
use crate::{Error, Result};
#[cfg(feature = "medium-ethernet")]
use crate::wire::EthernetAddress;
#[cfg(feature = "medium-ieee802154")]
use crate::wire::Ieee802154Address;
use crate::wire::HardwareAddress;
use crate::wire::RawHardwareAddress;
enum_with_unknown! {
/// NDISC Option Type
@ -90,12 +84,6 @@ mod field {
// | Type | Length | Link-Layer Address ...
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Link-Layer Address
#[cfg(feature = "medium-ethernet")]
pub const LL_ADDR_ETHERNET: Field = 2..8;
#[cfg(feature = "medium-ieee802154")]
pub const LL_ADDR_IEEE802154: Field = 2..10;
// Prefix Information Option fields.
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type | Length | Prefix Length |L|A| Reserved1 |
@ -225,23 +213,10 @@ impl<T: AsRef<[u8]>> NdiscOption<T> {
impl<T: AsRef<[u8]>> NdiscOption<T> {
/// Return the Source/Target Link-layer Address.
#[inline]
pub fn link_layer_addr(&self, medium: &Medium) -> HardwareAddress {
pub fn link_layer_addr(&self) -> RawHardwareAddress {
let len = MAX_HARDWARE_ADDRESS_LEN.min(self.data_len() as usize * 8 - 2);
let data = self.buffer.as_ref();
match medium {
#[cfg(feature = "medium-ethernet")]
Medium::Ethernet => {
let addr = &data[field::LL_ADDR_ETHERNET];
HardwareAddress::Ethernet(EthernetAddress::from_bytes(addr))
}
#[cfg(feature = "medium-ieee802154")]
Medium::Ieee802154 => {
let addr = &data[field::LL_ADDR_IEEE802154];
HardwareAddress::Ieee802154(Ieee802154Address::from_bytes(addr))
}
#[cfg(feature = "medium-ip")]
_ => todo!(), // TODO(thvdveld)
}
RawHardwareAddress::from_bytes(&data[2..len + 2])
}
}
@ -322,21 +297,9 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> NdiscOption<T> {
impl<T: AsRef<[u8]> + AsMut<[u8]>> NdiscOption<T> {
/// Set the Source/Target Link-layer Address.
#[inline]
pub fn set_link_layer_addr(&mut self, addr: HardwareAddress) {
pub fn set_link_layer_addr(&mut self, addr: RawHardwareAddress) {
let data = self.buffer.as_mut();
match addr {
#[cfg(feature = "medium-ethernet")]
HardwareAddress::Ethernet(addr) => {
let data = &mut data[field::LL_ADDR_ETHERNET];
data.copy_from_slice(addr.as_bytes());
}
#[cfg(feature = "medium-ieee802154")]
HardwareAddress::Ieee802154(addr) => {
let data = &mut data[field::LL_ADDR_IEEE802154];
data.copy_from_slice(addr.as_bytes());
}
_ => todo!(),
}
data[2..2 + addr.len()].copy_from_slice(addr.as_bytes())
}
}
@ -413,18 +376,17 @@ impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> NdiscOption<&'a mut T> {
}
}
//impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for NdiscOption<&'a T> {
//fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
//// XXX(thvdveld): how do we pass the medium?
//match Repr::parse(self, &Medium::Ethernet) {
//Ok(repr) => write!(f, "{}", repr),
//Err(err) => {
//write!(f, "NDISC Option ({})", err)?;
//Ok(())
//}
//}
//}
//}
impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for NdiscOption<&'a T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match Repr::parse(self) {
Ok(repr) => write!(f, "{}", repr),
Err(err) => {
write!(f, "NDISC Option ({})", err)?;
Ok(())
}
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -447,8 +409,8 @@ pub struct RedirectedHeader<'a> {
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Repr<'a> {
SourceLinkLayerAddr(HardwareAddress),
TargetLinkLayerAddr(HardwareAddress),
SourceLinkLayerAddr(RawHardwareAddress),
TargetLinkLayerAddr(RawHardwareAddress),
PrefixInformation(PrefixInformation),
RedirectedHeader(RedirectedHeader<'a>),
Mtu(u32),
@ -461,21 +423,21 @@ pub enum Repr<'a> {
impl<'a> Repr<'a> {
/// Parse an NDISC Option and return a high-level representation.
pub fn parse<T>(opt: &'a NdiscOption<&'a T>, medium: &Medium) -> Result<Repr<'a>>
pub fn parse<T>(opt: &'a NdiscOption<&'a T>) -> Result<Repr<'a>>
where
T: AsRef<[u8]> + ?Sized,
{
match opt.option_type() {
Type::SourceLinkLayerAddr => {
if opt.data_len() == 1 {
Ok(Repr::SourceLinkLayerAddr(opt.link_layer_addr(medium)))
Ok(Repr::SourceLinkLayerAddr(opt.link_layer_addr()))
} else {
Err(Error::Malformed)
}
}
Type::TargetLinkLayerAddr => {
if opt.data_len() == 1 {
Ok(Repr::TargetLinkLayerAddr(opt.link_layer_addr(medium)))
Ok(Repr::TargetLinkLayerAddr(opt.link_layer_addr()))
} else {
Err(Error::Malformed)
}
@ -524,57 +486,38 @@ impl<'a> Repr<'a> {
}
/// Return the length of a header that will be emitted from this high-level representation.
pub fn buffer_len(&self, medium: &Medium) -> usize {
match (self, medium) {
#[cfg(feature = "medium-ethernet")]
(&Repr::SourceLinkLayerAddr(_) | &Repr::TargetLinkLayerAddr(_), Medium::Ethernet) => {
field::LL_ADDR_ETHERNET.end
pub fn buffer_len(&self) -> usize {
match self {
&Repr::SourceLinkLayerAddr(addr) | &Repr::TargetLinkLayerAddr(addr) => {
let len = 2 + addr.len();
// Round up to next multiple of 8
(len + 7) / 8 * 8
}
#[cfg(feature = "medium-ieee802154")]
(&Repr::SourceLinkLayerAddr(_) | &Repr::TargetLinkLayerAddr(_), Medium::Ieee802154) => {
field::LL_ADDR_IEEE802154.end
}
#[cfg(feature = "medium-ip")]
(&Repr::SourceLinkLayerAddr(_) | &Repr::TargetLinkLayerAddr(_), _) => {
unreachable!()
}
(&Repr::PrefixInformation(_), _) => field::PREFIX.end,
(&Repr::RedirectedHeader(RedirectedHeader { header, data }), _) => {
&Repr::PrefixInformation(_) => field::PREFIX.end,
&Repr::RedirectedHeader(RedirectedHeader { header, data }) => {
field::IP_DATA + header.buffer_len() + data.len()
}
(&Repr::Mtu(_), _) => field::MTU.end,
(&Repr::Unknown { length, .. }, _) => field::DATA(length).end,
&Repr::Mtu(_) => field::MTU.end,
&Repr::Unknown { length, .. } => field::DATA(length).end,
}
}
/// Emit a high-level representation into an NDISC Option.
pub fn emit<T>(&self, opt: &mut NdiscOption<&'a mut T>, medium: &Medium)
pub fn emit<T>(&self, opt: &mut NdiscOption<&'a mut T>)
where
T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
{
match *self {
Repr::SourceLinkLayerAddr(addr) => {
opt.set_option_type(Type::SourceLinkLayerAddr);
match medium {
#[cfg(feature = "medium-ethernet")]
Medium::Ethernet => opt.set_data_len(1),
#[cfg(feature = "medium-ieee802154")]
Medium::Ieee802154 => opt.set_data_len(2),
#[cfg(feature = "medium-ip")]
_ => unreachable!(),
}
let opt_len = addr.len() + 2;
opt.set_data_len(((opt_len + 7) / 8) as u8); // round to next multiple of 8.
opt.set_link_layer_addr(addr);
}
Repr::TargetLinkLayerAddr(addr) => {
opt.set_option_type(Type::TargetLinkLayerAddr);
match medium {
#[cfg(feature = "medium-ethernet")]
Medium::Ethernet => opt.set_data_len(1),
#[cfg(feature = "medium-ieee802154")]
Medium::Ieee802154 => opt.set_data_len(2),
#[cfg(feature = "medium-ip")]
_ => unreachable!(),
}
let opt_len = addr.len() + 2;
opt.set_data_len(((opt_len + 7) / 8) as u8); // round to next multiple of 8.
opt.set_link_layer_addr(addr);
}
Repr::PrefixInformation(PrefixInformation {
@ -626,42 +569,51 @@ impl<'a> fmt::Display for Repr<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "NDISC Option: ")?;
match *self {
Repr::SourceLinkLayerAddr(addr) => write!(f, "SourceLinkLayer addr={}", addr),
Repr::TargetLinkLayerAddr(addr) => write!(f, "TargetLinkLayer addr={}", addr),
Repr::SourceLinkLayerAddr(addr) => {
write!(f, "SourceLinkLayer addr={}", addr)
}
Repr::TargetLinkLayerAddr(addr) => {
write!(f, "TargetLinkLayer addr={}", addr)
}
Repr::PrefixInformation(PrefixInformation {
prefix, prefix_len, ..
}) => write!(f, "PrefixInformation prefix={}/{}", prefix, prefix_len),
}) => {
write!(f, "PrefixInformation prefix={}/{}", prefix, prefix_len)
}
Repr::RedirectedHeader(RedirectedHeader { header, .. }) => {
write!(f, "RedirectedHeader header={}", header)
}
Repr::Mtu(mtu) => write!(f, "MTU mtu={}", mtu),
Repr::Mtu(mtu) => {
write!(f, "MTU mtu={}", mtu)
}
Repr::Unknown {
type_: id, length, ..
} => write!(f, "Unknown({}) length={}", id, length),
} => {
write!(f, "Unknown({}) length={}", id, length)
}
}
}
}
//use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
//impl<T: AsRef<[u8]>> PrettyPrint for NdiscOption<T> {
//fn pretty_print(
//buffer: &dyn AsRef<[u8]>,
//f: &mut fmt::Formatter,
//indent: &mut PrettyIndent,
//) -> fmt::Result {
//// TODO(thvdveld): how do we pass the medium?
//match NdiscOption::new_checked(buffer) {
//Err(err) => return write!(f, "{}({})", indent, err),
//Ok(ndisc) => match Repr::parse(&ndisc, &Medium::Ethernet) {
//Err(_) => Ok(()),
//Ok(repr) => {
//write!(f, "{}{}", indent, repr)
//}
//},
//}
//}
//}
impl<T: AsRef<[u8]>> PrettyPrint for NdiscOption<T> {
fn pretty_print(
buffer: &dyn AsRef<[u8]>,
f: &mut fmt::Formatter,
indent: &mut PrettyIndent,
) -> fmt::Result {
match NdiscOption::new_checked(buffer) {
Err(err) => return write!(f, "{}({})", indent, err),
Ok(ndisc) => match Repr::parse(&ndisc) {
Err(_) => Ok(()),
Ok(repr) => {
write!(f, "{}{}", indent, repr)
}
},
}
}
}
#[cfg(test)]
mod test {
@ -721,20 +673,14 @@ mod test {
let addr = EthernetAddress([0x54, 0x52, 0x00, 0x12, 0x23, 0x34]);
{
assert_eq!(
Repr::parse(
&NdiscOption::new_unchecked(&bytes),
&crate::phy::Medium::Ethernet
),
Repr::parse(&NdiscOption::new_unchecked(&bytes)),
Ok(Repr::SourceLinkLayerAddr(addr.into()))
);
}
bytes[0] = 0x02;
{
assert_eq!(
Repr::parse(
&NdiscOption::new_unchecked(&bytes),
&crate::phy::Medium::Ethernet
),
Repr::parse(&NdiscOption::new_unchecked(&bytes)),
Ok(Repr::TargetLinkLayerAddr(addr.into()))
);
}
@ -750,10 +696,7 @@ mod test {
prefix: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1),
});
assert_eq!(
Repr::parse(
&NdiscOption::new_unchecked(&PREFIX_OPT_BYTES),
&crate::phy::Medium::Ethernet
),
Repr::parse(&NdiscOption::new_unchecked(&PREFIX_OPT_BYTES)),
Ok(repr)
);
}
@ -769,7 +712,7 @@ mod test {
prefix: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1),
});
let mut opt = NdiscOption::new_unchecked(&mut bytes);
repr.emit(&mut opt, &crate::phy::Medium::Ethernet);
repr.emit(&mut opt);
assert_eq!(&opt.into_inner()[..], &PREFIX_OPT_BYTES[..]);
}
@ -777,10 +720,7 @@ mod test {
fn test_repr_parse_mtu() {
let bytes = [0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0xdc];
assert_eq!(
Repr::parse(
&NdiscOption::new_unchecked(&bytes),
&crate::phy::Medium::Ethernet
),
Repr::parse(&NdiscOption::new_unchecked(&bytes)),
Ok(Repr::Mtu(1500))
);
}