From b4764e4973349e1b5a041f197351f1e0198604e3 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 7 Oct 2021 06:56:32 +0200 Subject: [PATCH] Add RawHardwareAddress, use it in wire ndisc. This avoids wire needing to know what medium we're on. --- examples/ping.rs | 22 +---- src/iface/interface.rs | 89 +++++++++-------- src/socket/icmp.rs | 17 +--- src/wire/arp.rs | 20 ++-- src/wire/icmpv6.rs | 21 ++-- src/wire/ipv6routing.rs | 35 +++---- src/wire/mld.rs | 4 - src/wire/mod.rs | 93 ++++++++++++++++++ src/wire/ndisc.rs | 97 ++++++------------ src/wire/ndiscoption.rs | 212 ++++++++++++++-------------------------- 10 files changed, 282 insertions(+), 328 deletions(-) diff --git a/examples/ping.rs b/examples/ping.rs index 45bd63d..530b72f 100644 --- a/examples/ping.rs +++ b/examples/ping.rs @@ -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!( diff --git a/src/iface/interface.rs b/src/iface/interface.rs index 12427e3..1435edc 100644 --- a/src/iface/interface.rs +++ b/src/iface/interface.rs @@ -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> { @@ -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, }; diff --git a/src/socket/icmp.rs b/src/socket/icmp.rs index b2b231d..acdee12 100644 --- a/src/socket/icmp.rs +++ b/src/socket/icmp.rs @@ -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(), diff --git a/src/wire/arp.rs b/src/wire/arp.rs index a56c17d..48d64ca 100644 --- a/src/wire/arp.rs +++ b/src/wire/arp.rs @@ -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 + ) + } } } } diff --git a/src/wire/icmpv6.rs b/src/wire/icmpv6.rs index 0873ea3..4afa37d 100644 --- a/src/wire/icmpv6.rs +++ b/src/wire/icmpv6.rs @@ -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> 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[..]); } diff --git a/src/wire/ipv6routing.rs b/src/wire/ipv6routing.rs index 84e5540..fdb155a 100644 --- a/src/wire/ipv6routing.rs +++ b/src/wire/ipv6routing.rs @@ -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) + } } } } diff --git a/src/wire/mld.rs b/src/wire/mld.rs index cf3b5f4..c77e1da 100644 --- a/src/wire/mld.rs +++ b/src/wire/mld.rs @@ -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[..]); } diff --git a/src/wire/mod.rs b/src/wire/mod.rs index 321a67f..c891a1b 100644 --- a/src/wire/mod.rs +++ b/src/wire/mod.rs @@ -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 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 { + 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 for RawHardwareAddress { + fn from(addr: EthernetAddress) -> Self { + Self::from_bytes(addr.as_bytes()) + } +} + +#[cfg(feature = "medium-ieee802154")] +impl From for RawHardwareAddress { + fn from(addr: Ieee802154Address) -> Self { + Self::from_bytes(addr.as_bytes()) + } +} + +impl From for RawHardwareAddress { + fn from(addr: HardwareAddress) -> Self { + Self::from_bytes(addr.as_bytes()) + } +} diff --git a/src/wire/ndisc.rs b/src/wire/ndisc.rs index 1d96909..32a2163 100644 --- a/src/wire/ndisc.rs +++ b/src/wire/ndisc.rs @@ -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 + AsMut<[u8]>> Packet { #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Repr<'a> { RouterSolicit { - lladdr: Option, + lladdr: Option, }, RouterAdvert { hop_limit: u8, @@ -203,23 +202,23 @@ pub enum Repr<'a> { router_lifetime: Duration, reachable_time: Duration, retrans_time: Duration, - lladdr: Option, + lladdr: Option, mtu: Option, prefix_info: Option, }, NeighborSolicit { target_addr: Ipv6Address, - lladdr: Option, + lladdr: Option, }, NeighborAdvert { flags: NeighborFlags, target_addr: Ipv6Address, - lladdr: Option, + lladdr: Option, }, Redirect { target_addr: Ipv6Address, dest_addr: Ipv6Address, - lladdr: Option, + lladdr: Option, redirected_hdr: Option>, }, } @@ -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(packet: &Packet<&'a T>, medium: &Medium) -> Result> + pub fn parse(packet: &Packet<&'a T>) -> Result> 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(&self, packet: &mut Packet<&mut T>, medium: &Medium) + pub fn emit(&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[..]); } diff --git a/src/wire/ndiscoption.rs b/src/wire/ndiscoption.rs index 59e212b..5c598b3 100644 --- a/src/wire/ndiscoption.rs +++ b/src/wire/ndiscoption.rs @@ -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> NdiscOption { impl> NdiscOption { /// 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 + AsMut<[u8]>> NdiscOption { impl + AsMut<[u8]>> NdiscOption { /// 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(opt: &'a NdiscOption<&'a T>, medium: &Medium) -> Result> + pub fn parse(opt: &'a NdiscOption<&'a T>) -> Result> 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(&self, opt: &mut NdiscOption<&'a mut T>, medium: &Medium) + pub fn emit(&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> PrettyPrint for NdiscOption { -//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> PrettyPrint for NdiscOption { + 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)) ); }