Add RawHardwareAddress, use it in wire ndisc.
This avoids wire needing to know what medium we're on.master
parent
fb2d0029d8
commit
b4764e4973
|
@ -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!(
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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[..]);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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[..]);
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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[..]);
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue