Add RawHardwareAddress, use it in wire ndisc.
This avoids wire needing to know what medium we're on.
This commit is contained in:
parent
fb2d0029d8
commit
b4764e4973
|
@ -22,7 +22,7 @@ use smoltcp::{
|
||||||
};
|
};
|
||||||
|
|
||||||
macro_rules! send_icmp_ping {
|
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 ) => {{
|
$echo_payload:expr, $socket:expr, $remote_addr:expr ) => {{
|
||||||
let icmp_repr = $repr_type::EchoRequest {
|
let icmp_repr = $repr_type::EchoRequest {
|
||||||
ident: $ident,
|
ident: $ident,
|
||||||
|
@ -35,22 +35,6 @@ macro_rules! send_icmp_ping {
|
||||||
let icmp_packet = $packet_type::new_unchecked(icmp_payload);
|
let icmp_packet = $packet_type::new_unchecked(icmp_payload);
|
||||||
(icmp_repr, icmp_packet)
|
(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 {
|
macro_rules! get_icmp_pong {
|
||||||
|
@ -186,7 +170,6 @@ fn main() {
|
||||||
match remote_addr {
|
match remote_addr {
|
||||||
IpAddress::Ipv4(_) => {
|
IpAddress::Ipv4(_) => {
|
||||||
let (icmp_repr, mut icmp_packet) = send_icmp_ping!(
|
let (icmp_repr, mut icmp_packet) = send_icmp_ping!(
|
||||||
v4,
|
|
||||||
Icmpv4Repr,
|
Icmpv4Repr,
|
||||||
Icmpv4Packet,
|
Icmpv4Packet,
|
||||||
ident,
|
ident,
|
||||||
|
@ -199,7 +182,6 @@ fn main() {
|
||||||
}
|
}
|
||||||
IpAddress::Ipv6(_) => {
|
IpAddress::Ipv6(_) => {
|
||||||
let (icmp_repr, mut icmp_packet) = send_icmp_ping!(
|
let (icmp_repr, mut icmp_packet) = send_icmp_ping!(
|
||||||
v6,
|
|
||||||
Icmpv6Repr,
|
Icmpv6Repr,
|
||||||
Icmpv6Packet,
|
Icmpv6Packet,
|
||||||
ident,
|
ident,
|
||||||
|
@ -213,7 +195,6 @@ fn main() {
|
||||||
&remote_addr,
|
&remote_addr,
|
||||||
&mut icmp_packet,
|
&mut icmp_packet,
|
||||||
&device_caps.checksum,
|
&device_caps.checksum,
|
||||||
&device_caps.medium,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
|
@ -249,7 +230,6 @@ fn main() {
|
||||||
&src_ipv6,
|
&src_ipv6,
|
||||||
&icmp_packet,
|
&icmp_packet,
|
||||||
&device_caps.checksum,
|
&device_caps.checksum,
|
||||||
&device_caps.medium,
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
get_icmp_pong!(
|
get_icmp_pong!(
|
||||||
|
|
|
@ -389,7 +389,6 @@ impl<'a> IpPacket<'a> {
|
||||||
&_ip_repr.dst_addr(),
|
&_ip_repr.dst_addr(),
|
||||||
&mut Icmpv6Packet::new_unchecked(payload),
|
&mut Icmpv6Packet::new_unchecked(payload),
|
||||||
&caps.checksum,
|
&caps.checksum,
|
||||||
&caps.medium,
|
|
||||||
),
|
),
|
||||||
#[cfg(feature = "socket-raw")]
|
#[cfg(feature = "socket-raw")]
|
||||||
IpPacket::Raw((_, raw_packet)) => payload.copy_from_slice(raw_packet),
|
IpPacket::Raw((_, raw_packet)) => payload.copy_from_slice(raw_packet),
|
||||||
|
@ -1198,7 +1197,7 @@ impl<'a> InterfaceInner<'a> {
|
||||||
header: ipv6_repr,
|
header: ipv6_repr,
|
||||||
data: &payload[0..payload_len],
|
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::Unspecified { .. } => Err(Error::Unaddressable),
|
||||||
IpRepr::Sixlowpan(_) => Err(Error::Malformed), // XXX(thvdveld): this is just wrong;
|
IpRepr::Sixlowpan(_) => Err(Error::Malformed), // XXX(thvdveld): this is just wrong;
|
||||||
|
@ -1394,7 +1393,7 @@ impl<'a> InterfaceInner<'a> {
|
||||||
header: ipv6_repr,
|
header: ipv6_repr,
|
||||||
data: &ip_payload[0..payload_len],
|
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(),
|
&ip_repr.dst_addr(),
|
||||||
&icmp_packet,
|
&icmp_packet,
|
||||||
&cx.caps.checksum,
|
&cx.caps.checksum,
|
||||||
&cx.caps.medium,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
#[cfg(feature = "socket-icmp")]
|
#[cfg(feature = "socket-icmp")]
|
||||||
|
@ -1639,7 +1637,7 @@ impl<'a> InterfaceInner<'a> {
|
||||||
seq_no,
|
seq_no,
|
||||||
data,
|
data,
|
||||||
};
|
};
|
||||||
Ok(self.icmpv6_reply(cx, ipv6_repr, icmp_reply_repr))
|
Ok(self.icmpv6_reply(ipv6_repr, icmp_reply_repr))
|
||||||
}
|
}
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
#[cfg(feature = "medium-ieee802154")]
|
||||||
IpRepr::Sixlowpan(sixlowpan_repr) => {
|
IpRepr::Sixlowpan(sixlowpan_repr) => {
|
||||||
|
@ -1649,7 +1647,6 @@ impl<'a> InterfaceInner<'a> {
|
||||||
data,
|
data,
|
||||||
};
|
};
|
||||||
Ok(self.icmpv6_reply(
|
Ok(self.icmpv6_reply(
|
||||||
cx,
|
|
||||||
Ipv6Repr {
|
Ipv6Repr {
|
||||||
src_addr: sixlowpan_repr.src_addr,
|
src_addr: sixlowpan_repr.src_addr,
|
||||||
dst_addr: sixlowpan_repr.dst_addr,
|
dst_addr: sixlowpan_repr.dst_addr,
|
||||||
|
@ -1714,23 +1711,24 @@ impl<'a> InterfaceInner<'a> {
|
||||||
flags,
|
flags,
|
||||||
} => {
|
} => {
|
||||||
let ip_addr = ip_repr.src_addr.into();
|
let ip_addr = ip_repr.src_addr.into();
|
||||||
match lladdr {
|
if let Some(lladdr) = lladdr {
|
||||||
Some(lladdr) if lladdr.is_unicast() && target_addr.is_unicast() => {
|
let lladdr = lladdr.parse(cx.caps.medium)?;
|
||||||
if flags.contains(NdiscNeighborFlags::OVERRIDE)
|
if !lladdr.is_unicast() || !target_addr.is_unicast() {
|
||||||
|| !self
|
return Err(Error::Malformed);
|
||||||
.neighbor_cache
|
}
|
||||||
.as_mut()
|
if flags.contains(NdiscNeighborFlags::OVERRIDE)
|
||||||
.unwrap()
|
|| !self
|
||||||
.lookup(&ip_addr, cx.now)
|
.neighbor_cache
|
||||||
.found()
|
.as_mut()
|
||||||
{
|
.unwrap()
|
||||||
self.neighbor_cache
|
.lookup(&ip_addr, cx.now)
|
||||||
.as_mut()
|
.found()
|
||||||
.unwrap()
|
{
|
||||||
.fill(ip_addr, lladdr, cx.now)
|
self.neighbor_cache
|
||||||
}
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.fill(ip_addr, lladdr, cx.now)
|
||||||
}
|
}
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
@ -1739,27 +1737,31 @@ impl<'a> InterfaceInner<'a> {
|
||||||
lladdr,
|
lladdr,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
match lladdr {
|
if let Some(lladdr) = lladdr {
|
||||||
Some(lladdr) if lladdr.is_unicast() && target_addr.is_unicast() => self
|
let lladdr = lladdr.parse(cx.caps.medium)?;
|
||||||
.neighbor_cache
|
if !lladdr.is_unicast() || !target_addr.is_unicast() {
|
||||||
.as_mut()
|
return Err(Error::Malformed);
|
||||||
.unwrap()
|
}
|
||||||
.fill(ip_repr.src_addr.into(), lladdr, cx.now),
|
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) {
|
if self.has_solicited_node(ip_repr.dst_addr) && self.has_ip_addr(target_addr) {
|
||||||
let advert = Icmpv6Repr::Ndisc(NdiscRepr::NeighborAdvert {
|
let advert = Icmpv6Repr::Ndisc(NdiscRepr::NeighborAdvert {
|
||||||
flags: NdiscNeighborFlags::SOLICITED,
|
flags: NdiscNeighborFlags::SOLICITED,
|
||||||
target_addr,
|
target_addr,
|
||||||
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
#[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 {
|
let ip_repr = Ipv6Repr {
|
||||||
src_addr: target_addr,
|
src_addr: target_addr,
|
||||||
dst_addr: ip_repr.src_addr,
|
dst_addr: ip_repr.src_addr,
|
||||||
next_header: IpProtocol::Icmpv6,
|
next_header: IpProtocol::Icmpv6,
|
||||||
hop_limit: 0xff,
|
hop_limit: 0xff,
|
||||||
payload_len: advert.buffer_len(&cx.caps.medium),
|
payload_len: advert.buffer_len(),
|
||||||
};
|
};
|
||||||
Ok(Some(IpPacket::Icmpv6((ip_repr, advert))))
|
Ok(Some(IpPacket::Icmpv6((ip_repr, advert))))
|
||||||
} else {
|
} else {
|
||||||
|
@ -1917,7 +1919,6 @@ impl<'a> InterfaceInner<'a> {
|
||||||
#[cfg(feature = "proto-ipv6")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
fn icmpv6_reply<'frame, 'icmp: 'frame>(
|
fn icmpv6_reply<'frame, 'icmp: 'frame>(
|
||||||
&self,
|
&self,
|
||||||
cx: &Context,
|
|
||||||
ipv6_repr: Ipv6Repr,
|
ipv6_repr: Ipv6Repr,
|
||||||
icmp_repr: Icmpv6Repr<'icmp>,
|
icmp_repr: Icmpv6Repr<'icmp>,
|
||||||
) -> Option<IpPacket<'frame>> {
|
) -> Option<IpPacket<'frame>> {
|
||||||
|
@ -1926,7 +1927,7 @@ impl<'a> InterfaceInner<'a> {
|
||||||
src_addr: ipv6_repr.dst_addr,
|
src_addr: ipv6_repr.dst_addr,
|
||||||
dst_addr: ipv6_repr.src_addr,
|
dst_addr: ipv6_repr.src_addr,
|
||||||
next_header: IpProtocol::Icmpv6,
|
next_header: IpProtocol::Icmpv6,
|
||||||
payload_len: icmp_repr.buffer_len(&cx.caps.medium),
|
payload_len: icmp_repr.buffer_len(),
|
||||||
hop_limit: 64,
|
hop_limit: 64,
|
||||||
};
|
};
|
||||||
Some(IpPacket::Icmpv6((ipv6_reply_repr, icmp_repr)))
|
Some(IpPacket::Icmpv6((ipv6_reply_repr, icmp_repr)))
|
||||||
|
@ -1989,7 +1990,7 @@ impl<'a> InterfaceInner<'a> {
|
||||||
header: ipv6_repr,
|
header: ipv6_repr,
|
||||||
data: &ip_payload[0..payload_len],
|
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")]
|
#[cfg(feature = "proto-sixlowpan")]
|
||||||
IpRepr::Sixlowpan(sixlowpan_repr) => {
|
IpRepr::Sixlowpan(sixlowpan_repr) => {
|
||||||
|
@ -2011,7 +2012,7 @@ impl<'a> InterfaceInner<'a> {
|
||||||
header: ipv6_repr,
|
header: ipv6_repr,
|
||||||
data: &ip_payload[0..payload_len],
|
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),
|
IpRepr::Unspecified { .. } => Err(Error::Unaddressable),
|
||||||
}
|
}
|
||||||
|
@ -2254,7 +2255,7 @@ impl<'a> InterfaceInner<'a> {
|
||||||
|
|
||||||
let solicit = Icmpv6Repr::Ndisc(NdiscRepr::NeighborSolicit {
|
let solicit = Icmpv6Repr::Ndisc(NdiscRepr::NeighborSolicit {
|
||||||
target_addr: dst_addr,
|
target_addr: dst_addr,
|
||||||
lladdr: self.hardware_addr,
|
lladdr: Some(self.hardware_addr.unwrap().into()),
|
||||||
});
|
});
|
||||||
|
|
||||||
let packet = IpPacket::Icmpv6((
|
let packet = IpPacket::Icmpv6((
|
||||||
|
@ -2262,7 +2263,7 @@ impl<'a> InterfaceInner<'a> {
|
||||||
src_addr,
|
src_addr,
|
||||||
dst_addr: dst_addr.solicited_node(),
|
dst_addr: dst_addr.solicited_node(),
|
||||||
next_header: IpProtocol::Icmpv6,
|
next_header: IpProtocol::Icmpv6,
|
||||||
payload_len: solicit.buffer_len(&cx.caps.medium),
|
payload_len: solicit.buffer_len(),
|
||||||
hop_limit: 0xff,
|
hop_limit: 0xff,
|
||||||
},
|
},
|
||||||
solicit,
|
solicit,
|
||||||
|
@ -2422,7 +2423,7 @@ impl<'a> InterfaceInner<'a> {
|
||||||
tx_len += udp_repr.header_len() + payload.len();
|
tx_len += udp_repr.header_len() + payload.len();
|
||||||
}
|
}
|
||||||
IpPacket::Icmpv6((_, icmp)) => {
|
IpPacket::Icmpv6((_, icmp)) => {
|
||||||
tx_len += icmp.buffer_len(&cx.caps.medium);
|
tx_len += icmp.buffer_len();
|
||||||
}
|
}
|
||||||
_ => return Err(Error::Unrecognized),
|
_ => return Err(Error::Unrecognized),
|
||||||
}
|
}
|
||||||
|
@ -2466,7 +2467,6 @@ impl<'a> InterfaceInner<'a> {
|
||||||
&iphc_repr.dst_addr.into(),
|
&iphc_repr.dst_addr.into(),
|
||||||
&mut icmp_packet,
|
&mut icmp_packet,
|
||||||
&cx.caps.checksum,
|
&cx.caps.checksum,
|
||||||
&cx.caps.medium,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => return Err(Error::Unrecognized),
|
_ => return Err(Error::Unrecognized),
|
||||||
|
@ -3135,7 +3135,7 @@ mod test {
|
||||||
dst_addr: src_addr,
|
dst_addr: src_addr,
|
||||||
next_header: IpProtocol::Icmpv6,
|
next_header: IpProtocol::Icmpv6,
|
||||||
hop_limit: 64,
|
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")))]
|
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
|
||||||
let expected_icmp_repr = Icmpv4Repr::DstUnreachable {
|
let expected_icmp_repr = Icmpv4Repr::DstUnreachable {
|
||||||
|
@ -3157,7 +3157,7 @@ mod test {
|
||||||
// The expected packet does not exceed the IPV4_MIN_MTU
|
// The expected packet does not exceed the IPV4_MIN_MTU
|
||||||
#[cfg(feature = "proto-ipv6")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
assert_eq!(
|
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
|
MIN_MTU
|
||||||
);
|
);
|
||||||
// The expected packet does not exceed the IPV4_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(),
|
dst_addr: local_ip_addr.solicited_node(),
|
||||||
next_header: IpProtocol::Icmpv6,
|
next_header: IpProtocol::Icmpv6,
|
||||||
hop_limit: 0xff,
|
hop_limit: 0xff,
|
||||||
payload_len: solicit.buffer_len(&Medium::Ethernet),
|
payload_len: solicit.buffer_len(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut frame = EthernetFrame::new_unchecked(&mut eth_bytes);
|
let mut frame = EthernetFrame::new_unchecked(&mut eth_bytes);
|
||||||
|
@ -3281,7 +3281,6 @@ mod test {
|
||||||
&local_ip_addr.solicited_node().into(),
|
&local_ip_addr.solicited_node().into(),
|
||||||
&mut Icmpv6Packet::new_unchecked(&mut frame.payload_mut()[ip_repr.buffer_len()..]),
|
&mut Icmpv6Packet::new_unchecked(&mut frame.payload_mut()[ip_repr.buffer_len()..]),
|
||||||
&ChecksumCapabilities::default(),
|
&ChecksumCapabilities::default(),
|
||||||
&iface.device().capabilities().medium,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3296,7 +3295,7 @@ mod test {
|
||||||
dst_addr: remote_ip_addr,
|
dst_addr: remote_ip_addr,
|
||||||
next_header: IpProtocol::Icmpv6,
|
next_header: IpProtocol::Icmpv6,
|
||||||
hop_limit: 0xff,
|
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));
|
let cx = iface.context(Instant::from_secs(0));
|
||||||
|
@ -3530,7 +3529,7 @@ mod test {
|
||||||
src_addr: Ipv6Address::LOOPBACK,
|
src_addr: Ipv6Address::LOOPBACK,
|
||||||
dst_addr: remote_ip_addr,
|
dst_addr: remote_ip_addr,
|
||||||
next_header: IpProtocol::Icmpv6,
|
next_header: IpProtocol::Icmpv6,
|
||||||
payload_len: reply_icmp_repr.buffer_len(&Medium::Ethernet),
|
payload_len: reply_icmp_repr.buffer_len(),
|
||||||
hop_limit: 0x40,
|
hop_limit: 0x40,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -427,19 +427,18 @@ impl<'a> IcmpSocket<'a> {
|
||||||
IcmpRepr::Ipv6(ref icmp_repr) => {
|
IcmpRepr::Ipv6(ref icmp_repr) => {
|
||||||
let packet_buf = self
|
let packet_buf = self
|
||||||
.rx_buffer
|
.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(
|
icmp_repr.emit(
|
||||||
&ip_repr.src_addr(),
|
&ip_repr.src_addr(),
|
||||||
&ip_repr.dst_addr(),
|
&ip_repr.dst_addr(),
|
||||||
&mut Icmpv6Packet::new_unchecked(packet_buf),
|
&mut Icmpv6Packet::new_unchecked(packet_buf),
|
||||||
&ChecksumCapabilities::default(),
|
&ChecksumCapabilities::default(),
|
||||||
&_cx.caps.medium,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
net_trace!(
|
net_trace!(
|
||||||
"{}:{}: receiving {} octets",
|
"{}:{}: receiving {} octets",
|
||||||
self.meta.handle,
|
self.meta.handle,
|
||||||
icmp_repr.buffer_len(&_cx.caps.medium),
|
icmp_repr.buffer_len(),
|
||||||
packet_buf.len()
|
packet_buf.len()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -487,13 +486,12 @@ impl<'a> IcmpSocket<'a> {
|
||||||
&ipv6_addr.into(),
|
&ipv6_addr.into(),
|
||||||
&packet,
|
&packet,
|
||||||
&ChecksumCapabilities::ignored(),
|
&ChecksumCapabilities::ignored(),
|
||||||
&_cx.caps.medium,
|
|
||||||
)?;
|
)?;
|
||||||
let ip_repr = IpRepr::Ipv6(Ipv6Repr {
|
let ip_repr = IpRepr::Ipv6(Ipv6Repr {
|
||||||
src_addr: src_addr,
|
src_addr: src_addr,
|
||||||
dst_addr: ipv6_addr,
|
dst_addr: ipv6_addr,
|
||||||
next_header: IpProtocol::Icmpv6,
|
next_header: IpProtocol::Icmpv6,
|
||||||
payload_len: repr.buffer_len(&_cx.caps.medium),
|
payload_len: repr.buffer_len(),
|
||||||
hop_limit: hop_limit,
|
hop_limit: hop_limit,
|
||||||
});
|
});
|
||||||
emit((ip_repr, IcmpRepr::Ipv6(repr)))
|
emit((ip_repr, IcmpRepr::Ipv6(repr)))
|
||||||
|
@ -868,7 +866,6 @@ mod test_ipv6 {
|
||||||
&REMOTE_IPV6.into(),
|
&REMOTE_IPV6.into(),
|
||||||
&mut packet,
|
&mut packet,
|
||||||
&checksum,
|
&checksum,
|
||||||
&crate::phy::Medium::Ethernet,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -916,7 +913,6 @@ mod test_ipv6 {
|
||||||
&REMOTE_IPV6.into(),
|
&REMOTE_IPV6.into(),
|
||||||
&mut packet,
|
&mut packet,
|
||||||
&checksum,
|
&checksum,
|
||||||
&crate::phy::Medium::Ethernet,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
s.set_hop_limit(Some(0x2a));
|
s.set_hop_limit(Some(0x2a));
|
||||||
|
@ -933,7 +929,7 @@ mod test_ipv6 {
|
||||||
src_addr: Ipv6Address::UNSPECIFIED,
|
src_addr: Ipv6Address::UNSPECIFIED,
|
||||||
dst_addr: REMOTE_IPV6,
|
dst_addr: REMOTE_IPV6,
|
||||||
next_header: IpProtocol::Icmpv6,
|
next_header: IpProtocol::Icmpv6,
|
||||||
payload_len: ECHOV6_REPR.buffer_len(&crate::phy::Medium::Ethernet),
|
payload_len: ECHOV6_REPR.buffer_len(),
|
||||||
hop_limit: 0x2a,
|
hop_limit: 0x2a,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -960,7 +956,6 @@ mod test_ipv6 {
|
||||||
&REMOTE_IPV6.into(),
|
&REMOTE_IPV6.into(),
|
||||||
&mut packet,
|
&mut packet,
|
||||||
&checksum,
|
&checksum,
|
||||||
&crate::phy::Medium::Ethernet,
|
|
||||||
);
|
);
|
||||||
let data = &packet.into_inner()[..];
|
let data = &packet.into_inner()[..];
|
||||||
|
|
||||||
|
@ -999,7 +994,6 @@ mod test_ipv6 {
|
||||||
&REMOTE_IPV6.into(),
|
&REMOTE_IPV6.into(),
|
||||||
&mut packet,
|
&mut packet,
|
||||||
&checksum,
|
&checksum,
|
||||||
&crate::phy::Medium::Ethernet,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Ensure that a packet with an identifier that isn't the bound
|
// Ensure that a packet with an identifier that isn't the bound
|
||||||
|
@ -1042,7 +1036,7 @@ mod test_ipv6 {
|
||||||
src_addr: REMOTE_IPV6.into(),
|
src_addr: REMOTE_IPV6.into(),
|
||||||
dst_addr: LOCAL_IPV6.into(),
|
dst_addr: LOCAL_IPV6.into(),
|
||||||
protocol: IpProtocol::Icmpv6,
|
protocol: IpProtocol::Icmpv6,
|
||||||
payload_len: icmp_repr.buffer_len(&crate::phy::Medium::Ethernet),
|
payload_len: icmp_repr.buffer_len(),
|
||||||
hop_limit: 0x40,
|
hop_limit: 0x40,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1064,7 +1058,6 @@ mod test_ipv6 {
|
||||||
&REMOTE_IPV6.into(),
|
&REMOTE_IPV6.into(),
|
||||||
&mut packet,
|
&mut packet,
|
||||||
&checksum,
|
&checksum,
|
||||||
&crate::phy::Medium::Ethernet,
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
socket.recv(),
|
socket.recv(),
|
||||||
|
|
|
@ -357,15 +357,17 @@ impl fmt::Display for Repr {
|
||||||
source_protocol_addr,
|
source_protocol_addr,
|
||||||
target_hardware_addr,
|
target_hardware_addr,
|
||||||
target_protocol_addr,
|
target_protocol_addr,
|
||||||
} => write!(
|
} => {
|
||||||
f,
|
write!(
|
||||||
"ARP type=Ethernet+IPv4 src={}/{} tgt={}/{} op={:?}",
|
f,
|
||||||
source_hardware_addr,
|
"ARP type=Ethernet+IPv4 src={}/{} tgt={}/{} op={:?}",
|
||||||
source_protocol_addr,
|
source_hardware_addr,
|
||||||
target_hardware_addr,
|
source_protocol_addr,
|
||||||
target_protocol_addr,
|
target_hardware_addr,
|
||||||
operation
|
target_protocol_addr,
|
||||||
),
|
operation
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ use byteorder::{ByteOrder, NetworkEndian};
|
||||||
use core::{cmp, fmt};
|
use core::{cmp, fmt};
|
||||||
|
|
||||||
use crate::phy::ChecksumCapabilities;
|
use crate::phy::ChecksumCapabilities;
|
||||||
use crate::phy::Medium;
|
|
||||||
use crate::wire::ip::checksum;
|
use crate::wire::ip::checksum;
|
||||||
use crate::wire::MldRepr;
|
use crate::wire::MldRepr;
|
||||||
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
||||||
|
@ -546,7 +545,6 @@ impl<'a> Repr<'a> {
|
||||||
dst_addr: &IpAddress,
|
dst_addr: &IpAddress,
|
||||||
packet: &Packet<&'a T>,
|
packet: &Packet<&'a T>,
|
||||||
checksum_caps: &ChecksumCapabilities,
|
checksum_caps: &ChecksumCapabilities,
|
||||||
medium: &Medium,
|
|
||||||
) -> Result<Repr<'a>>
|
) -> Result<Repr<'a>>
|
||||||
where
|
where
|
||||||
T: AsRef<[u8]> + ?Sized,
|
T: AsRef<[u8]> + ?Sized,
|
||||||
|
@ -620,16 +618,14 @@ impl<'a> Repr<'a> {
|
||||||
data: packet.payload(),
|
data: packet.payload(),
|
||||||
}),
|
}),
|
||||||
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
||||||
(msg_type, 0) if msg_type.is_ndisc() => {
|
(msg_type, 0) if msg_type.is_ndisc() => NdiscRepr::parse(packet).map(Repr::Ndisc),
|
||||||
NdiscRepr::parse(packet, medium).map(Repr::Ndisc)
|
|
||||||
}
|
|
||||||
(msg_type, 0) if msg_type.is_mld() => MldRepr::parse(packet).map(Repr::Mld),
|
(msg_type, 0) if msg_type.is_mld() => MldRepr::parse(packet).map(Repr::Mld),
|
||||||
_ => Err(Error::Unrecognized),
|
_ => Err(Error::Unrecognized),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the length of a packet that will be emitted from this high-level representation.
|
/// 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 {
|
match self {
|
||||||
&Repr::DstUnreachable { header, data, .. }
|
&Repr::DstUnreachable { header, data, .. }
|
||||||
| &Repr::PktTooBig { header, data, .. }
|
| &Repr::PktTooBig { header, data, .. }
|
||||||
|
@ -641,7 +637,7 @@ impl<'a> Repr<'a> {
|
||||||
field::ECHO_SEQNO.end + data.len()
|
field::ECHO_SEQNO.end + data.len()
|
||||||
}
|
}
|
||||||
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
#[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(),
|
&Repr::Mld(mld) => mld.buffer_len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -654,7 +650,6 @@ impl<'a> Repr<'a> {
|
||||||
dst_addr: &IpAddress,
|
dst_addr: &IpAddress,
|
||||||
packet: &mut Packet<&mut T>,
|
packet: &mut Packet<&mut T>,
|
||||||
checksum_caps: &ChecksumCapabilities,
|
checksum_caps: &ChecksumCapabilities,
|
||||||
medium: &Medium,
|
|
||||||
) where
|
) where
|
||||||
T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
|
T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
|
||||||
{
|
{
|
||||||
|
@ -736,7 +731,7 @@ impl<'a> Repr<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
#[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),
|
Repr::Mld(mld) => mld.emit(packet),
|
||||||
}
|
}
|
||||||
|
@ -844,7 +839,6 @@ mod test {
|
||||||
&MOCK_IP_ADDR_2,
|
&MOCK_IP_ADDR_2,
|
||||||
&packet,
|
&packet,
|
||||||
&ChecksumCapabilities::default(),
|
&ChecksumCapabilities::default(),
|
||||||
&Medium::Ethernet,
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(repr, echo_packet_repr());
|
assert_eq!(repr, echo_packet_repr());
|
||||||
|
@ -853,14 +847,13 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_echo_emit() {
|
fn test_echo_emit() {
|
||||||
let repr = echo_packet_repr();
|
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);
|
let mut packet = Packet::new_unchecked(&mut bytes);
|
||||||
repr.emit(
|
repr.emit(
|
||||||
&MOCK_IP_ADDR_1,
|
&MOCK_IP_ADDR_1,
|
||||||
&MOCK_IP_ADDR_2,
|
&MOCK_IP_ADDR_2,
|
||||||
&mut packet,
|
&mut packet,
|
||||||
&ChecksumCapabilities::default(),
|
&ChecksumCapabilities::default(),
|
||||||
&Medium::Ethernet,
|
|
||||||
);
|
);
|
||||||
assert_eq!(&packet.into_inner()[..], &ECHO_PACKET_BYTES[..]);
|
assert_eq!(&packet.into_inner()[..], &ECHO_PACKET_BYTES[..]);
|
||||||
}
|
}
|
||||||
|
@ -899,7 +892,6 @@ mod test {
|
||||||
&MOCK_IP_ADDR_2,
|
&MOCK_IP_ADDR_2,
|
||||||
&packet,
|
&packet,
|
||||||
&ChecksumCapabilities::default(),
|
&ChecksumCapabilities::default(),
|
||||||
&Medium::Ethernet,
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(repr, too_big_packet_repr());
|
assert_eq!(repr, too_big_packet_repr());
|
||||||
|
@ -908,14 +900,13 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_too_big_emit() {
|
fn test_too_big_emit() {
|
||||||
let repr = too_big_packet_repr();
|
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);
|
let mut packet = Packet::new_unchecked(&mut bytes);
|
||||||
repr.emit(
|
repr.emit(
|
||||||
&MOCK_IP_ADDR_1,
|
&MOCK_IP_ADDR_1,
|
||||||
&MOCK_IP_ADDR_2,
|
&MOCK_IP_ADDR_2,
|
||||||
&mut packet,
|
&mut packet,
|
||||||
&ChecksumCapabilities::default(),
|
&ChecksumCapabilities::default(),
|
||||||
&Medium::Ethernet,
|
|
||||||
);
|
);
|
||||||
assert_eq!(&packet.into_inner()[..], &PKT_TOO_BIG_BYTES[..]);
|
assert_eq!(&packet.into_inner()[..], &PKT_TOO_BIG_BYTES[..]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -503,15 +503,17 @@ impl<'a> fmt::Display for Repr<'a> {
|
||||||
length,
|
length,
|
||||||
segments_left,
|
segments_left,
|
||||||
home_address,
|
home_address,
|
||||||
} => write!(
|
} => {
|
||||||
f,
|
write!(
|
||||||
"IPv6 Routing next_hdr={} length={} type={} seg_left={} home_address={}",
|
f,
|
||||||
next_header,
|
"IPv6 Routing next_hdr={} length={} type={} seg_left={} home_address={}",
|
||||||
length,
|
next_header,
|
||||||
Type::Type2,
|
length,
|
||||||
segments_left,
|
Type::Type2,
|
||||||
home_address
|
segments_left,
|
||||||
),
|
home_address
|
||||||
|
)
|
||||||
|
}
|
||||||
Repr::Rpl {
|
Repr::Rpl {
|
||||||
next_header,
|
next_header,
|
||||||
length,
|
length,
|
||||||
|
@ -520,17 +522,10 @@ impl<'a> fmt::Display for Repr<'a> {
|
||||||
cmpr_e,
|
cmpr_e,
|
||||||
pad,
|
pad,
|
||||||
..
|
..
|
||||||
} => write!(
|
} => {
|
||||||
f,
|
write!(f, "IPv6 Routing next_hdr={} length={} type={} seg_left={} cmpr_i={} cmpr_e={} pad={}",
|
||||||
"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)
|
||||||
next_header,
|
}
|
||||||
length,
|
|
||||||
Type::Rpl,
|
|
||||||
segments_left,
|
|
||||||
cmpr_i,
|
|
||||||
cmpr_e,
|
|
||||||
pad
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -532,7 +532,6 @@ mod test {
|
||||||
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
|
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
|
||||||
&packet,
|
&packet,
|
||||||
&ChecksumCapabilities::default(),
|
&ChecksumCapabilities::default(),
|
||||||
&crate::phy::Medium::Ethernet,
|
|
||||||
);
|
);
|
||||||
assert_eq!(repr, Ok(create_repr(Message::MldQuery)));
|
assert_eq!(repr, Ok(create_repr(Message::MldQuery)));
|
||||||
}
|
}
|
||||||
|
@ -545,7 +544,6 @@ mod test {
|
||||||
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
|
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
|
||||||
&packet,
|
&packet,
|
||||||
&ChecksumCapabilities::default(),
|
&ChecksumCapabilities::default(),
|
||||||
&crate::phy::Medium::Ethernet,
|
|
||||||
);
|
);
|
||||||
assert_eq!(repr, Ok(create_repr(Message::MldReport)));
|
assert_eq!(repr, Ok(create_repr(Message::MldReport)));
|
||||||
}
|
}
|
||||||
|
@ -560,7 +558,6 @@ mod test {
|
||||||
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
|
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
|
||||||
&mut packet,
|
&mut packet,
|
||||||
&ChecksumCapabilities::default(),
|
&ChecksumCapabilities::default(),
|
||||||
&crate::phy::Medium::Ethernet,
|
|
||||||
);
|
);
|
||||||
assert_eq!(&packet.into_inner()[..], &QUERY_PACKET_BYTES[..]);
|
assert_eq!(&packet.into_inner()[..], &QUERY_PACKET_BYTES[..]);
|
||||||
}
|
}
|
||||||
|
@ -575,7 +572,6 @@ mod test {
|
||||||
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
|
&Ipv6Address::LINK_LOCAL_ALL_ROUTERS.into(),
|
||||||
&mut packet,
|
&mut packet,
|
||||||
&ChecksumCapabilities::default(),
|
&ChecksumCapabilities::default(),
|
||||||
&crate::phy::Medium::Ethernet,
|
|
||||||
);
|
);
|
||||||
assert_eq!(&packet.into_inner()[..], &REPORT_PACKET_BYTES[..]);
|
assert_eq!(&packet.into_inner()[..], &REPORT_PACKET_BYTES[..]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,6 +123,8 @@ mod sixlowpan;
|
||||||
mod tcp;
|
mod tcp;
|
||||||
mod udp;
|
mod udp;
|
||||||
|
|
||||||
|
use crate::{phy::Medium, Error};
|
||||||
|
|
||||||
pub use self::pretty_print::PrettyPrinter;
|
pub use self::pretty_print::PrettyPrinter;
|
||||||
|
|
||||||
#[cfg(feature = "medium-ethernet")]
|
#[cfg(feature = "medium-ethernet")]
|
||||||
|
@ -310,3 +312,94 @@ impl From<Ieee802154Address> for HardwareAddress {
|
||||||
HardwareAddress::Ieee802154(addr)
|
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 bitflags::bitflags;
|
||||||
use byteorder::{ByteOrder, NetworkEndian};
|
use byteorder::{ByteOrder, NetworkEndian};
|
||||||
|
|
||||||
use crate::phy::Medium;
|
|
||||||
use crate::time::Duration;
|
use crate::time::Duration;
|
||||||
use crate::wire::icmpv6::{field, Message, Packet};
|
use crate::wire::icmpv6::{field, Message, Packet};
|
||||||
use crate::wire::HardwareAddress;
|
|
||||||
use crate::wire::Ipv6Address;
|
use crate::wire::Ipv6Address;
|
||||||
|
use crate::wire::RawHardwareAddress;
|
||||||
use crate::wire::{Ipv6Packet, Ipv6Repr};
|
use crate::wire::{Ipv6Packet, Ipv6Repr};
|
||||||
use crate::wire::{NdiscOption, NdiscOptionRepr, NdiscOptionType};
|
use crate::wire::{NdiscOption, NdiscOptionRepr, NdiscOptionType};
|
||||||
use crate::wire::{NdiscPrefixInformation, NdiscRedirectedHeader};
|
use crate::wire::{NdiscPrefixInformation, NdiscRedirectedHeader};
|
||||||
|
@ -195,7 +194,7 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum Repr<'a> {
|
pub enum Repr<'a> {
|
||||||
RouterSolicit {
|
RouterSolicit {
|
||||||
lladdr: Option<HardwareAddress>,
|
lladdr: Option<RawHardwareAddress>,
|
||||||
},
|
},
|
||||||
RouterAdvert {
|
RouterAdvert {
|
||||||
hop_limit: u8,
|
hop_limit: u8,
|
||||||
|
@ -203,23 +202,23 @@ pub enum Repr<'a> {
|
||||||
router_lifetime: Duration,
|
router_lifetime: Duration,
|
||||||
reachable_time: Duration,
|
reachable_time: Duration,
|
||||||
retrans_time: Duration,
|
retrans_time: Duration,
|
||||||
lladdr: Option<HardwareAddress>,
|
lladdr: Option<RawHardwareAddress>,
|
||||||
mtu: Option<u32>,
|
mtu: Option<u32>,
|
||||||
prefix_info: Option<NdiscPrefixInformation>,
|
prefix_info: Option<NdiscPrefixInformation>,
|
||||||
},
|
},
|
||||||
NeighborSolicit {
|
NeighborSolicit {
|
||||||
target_addr: Ipv6Address,
|
target_addr: Ipv6Address,
|
||||||
lladdr: Option<HardwareAddress>,
|
lladdr: Option<RawHardwareAddress>,
|
||||||
},
|
},
|
||||||
NeighborAdvert {
|
NeighborAdvert {
|
||||||
flags: NeighborFlags,
|
flags: NeighborFlags,
|
||||||
target_addr: Ipv6Address,
|
target_addr: Ipv6Address,
|
||||||
lladdr: Option<HardwareAddress>,
|
lladdr: Option<RawHardwareAddress>,
|
||||||
},
|
},
|
||||||
Redirect {
|
Redirect {
|
||||||
target_addr: Ipv6Address,
|
target_addr: Ipv6Address,
|
||||||
dest_addr: Ipv6Address,
|
dest_addr: Ipv6Address,
|
||||||
lladdr: Option<HardwareAddress>,
|
lladdr: Option<RawHardwareAddress>,
|
||||||
redirected_hdr: Option<NdiscRedirectedHeader<'a>>,
|
redirected_hdr: Option<NdiscRedirectedHeader<'a>>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -227,7 +226,7 @@ pub enum Repr<'a> {
|
||||||
impl<'a> Repr<'a> {
|
impl<'a> Repr<'a> {
|
||||||
/// Parse an NDISC packet and return a high-level representation of the
|
/// Parse an NDISC packet and return a high-level representation of the
|
||||||
/// packet.
|
/// 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
|
where
|
||||||
T: AsRef<[u8]> + ?Sized,
|
T: AsRef<[u8]> + ?Sized,
|
||||||
{
|
{
|
||||||
|
@ -236,7 +235,7 @@ impl<'a> Repr<'a> {
|
||||||
let lladdr = if !packet.payload().is_empty() {
|
let lladdr = if !packet.payload().is_empty() {
|
||||||
let opt = NdiscOption::new_checked(packet.payload())?;
|
let opt = NdiscOption::new_checked(packet.payload())?;
|
||||||
match opt.option_type() {
|
match opt.option_type() {
|
||||||
NdiscOptionType::SourceLinkLayerAddr => Some(opt.link_layer_addr(medium)),
|
NdiscOptionType::SourceLinkLayerAddr => Some(opt.link_layer_addr()),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::Unrecognized);
|
return Err(Error::Unrecognized);
|
||||||
}
|
}
|
||||||
|
@ -251,7 +250,7 @@ impl<'a> Repr<'a> {
|
||||||
let (mut lladdr, mut mtu, mut prefix_info) = (None, None, None);
|
let (mut lladdr, mut mtu, mut prefix_info) = (None, None, None);
|
||||||
while packet.payload().len() - offset > 0 {
|
while packet.payload().len() - offset > 0 {
|
||||||
let pkt = NdiscOption::new_checked(&packet.payload()[offset..])?;
|
let pkt = NdiscOption::new_checked(&packet.payload()[offset..])?;
|
||||||
let opt = NdiscOptionRepr::parse(&pkt, medium)?;
|
let opt = NdiscOptionRepr::parse(&pkt)?;
|
||||||
match opt {
|
match opt {
|
||||||
NdiscOptionRepr::SourceLinkLayerAddr(addr) => lladdr = Some(addr),
|
NdiscOptionRepr::SourceLinkLayerAddr(addr) => lladdr = Some(addr),
|
||||||
NdiscOptionRepr::Mtu(val) => mtu = Some(val),
|
NdiscOptionRepr::Mtu(val) => mtu = Some(val),
|
||||||
|
@ -260,7 +259,7 @@ impl<'a> Repr<'a> {
|
||||||
return Err(Error::Unrecognized);
|
return Err(Error::Unrecognized);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
offset += opt.buffer_len(medium);
|
offset += opt.buffer_len();
|
||||||
}
|
}
|
||||||
Ok(Repr::RouterAdvert {
|
Ok(Repr::RouterAdvert {
|
||||||
hop_limit: packet.current_hop_limit(),
|
hop_limit: packet.current_hop_limit(),
|
||||||
|
@ -277,7 +276,7 @@ impl<'a> Repr<'a> {
|
||||||
let lladdr = if !packet.payload().is_empty() {
|
let lladdr = if !packet.payload().is_empty() {
|
||||||
let opt = NdiscOption::new_checked(packet.payload())?;
|
let opt = NdiscOption::new_checked(packet.payload())?;
|
||||||
match opt.option_type() {
|
match opt.option_type() {
|
||||||
NdiscOptionType::SourceLinkLayerAddr => Some(opt.link_layer_addr(medium)),
|
NdiscOptionType::SourceLinkLayerAddr => Some(opt.link_layer_addr()),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::Unrecognized);
|
return Err(Error::Unrecognized);
|
||||||
}
|
}
|
||||||
|
@ -294,7 +293,7 @@ impl<'a> Repr<'a> {
|
||||||
let lladdr = if !packet.payload().is_empty() {
|
let lladdr = if !packet.payload().is_empty() {
|
||||||
let opt = NdiscOption::new_checked(packet.payload())?;
|
let opt = NdiscOption::new_checked(packet.payload())?;
|
||||||
match opt.option_type() {
|
match opt.option_type() {
|
||||||
NdiscOptionType::TargetLinkLayerAddr => Some(opt.link_layer_addr(medium)),
|
NdiscOptionType::TargetLinkLayerAddr => Some(opt.link_layer_addr()),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::Unrecognized);
|
return Err(Error::Unrecognized);
|
||||||
}
|
}
|
||||||
|
@ -315,7 +314,7 @@ impl<'a> Repr<'a> {
|
||||||
let opt = NdiscOption::new_checked(&packet.payload()[offset..])?;
|
let opt = NdiscOption::new_checked(&packet.payload()[offset..])?;
|
||||||
match opt.option_type() {
|
match opt.option_type() {
|
||||||
NdiscOptionType::SourceLinkLayerAddr => {
|
NdiscOptionType::SourceLinkLayerAddr => {
|
||||||
lladdr = Some(opt.link_layer_addr(medium));
|
lladdr = Some(opt.link_layer_addr());
|
||||||
offset += 8;
|
offset += 8;
|
||||||
}
|
}
|
||||||
NdiscOptionType::RedirectedHeader => {
|
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 {
|
match self {
|
||||||
&Repr::RouterSolicit { lladdr } => match lladdr {
|
&Repr::RouterSolicit { lladdr } => match lladdr {
|
||||||
Some(_) => field::UNUSED.end + 8,
|
Some(_) => field::UNUSED.end + 8,
|
||||||
|
@ -374,34 +373,11 @@ impl<'a> Repr<'a> {
|
||||||
field::RETRANS_TM.end + offset
|
field::RETRANS_TM.end + offset
|
||||||
}
|
}
|
||||||
&Repr::NeighborSolicit { lladdr, .. } | &Repr::NeighborAdvert { lladdr, .. } => {
|
&Repr::NeighborSolicit { lladdr, .. } | &Repr::NeighborAdvert { lladdr, .. } => {
|
||||||
match lladdr {
|
let mut offset = field::TARGET_ADDR.end;
|
||||||
Some(_addr) => {
|
if let Some(lladdr) = lladdr {
|
||||||
match medium {
|
offset += NdiscOptionRepr::SourceLinkLayerAddr(lladdr).buffer_len();
|
||||||
#[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,
|
|
||||||
}
|
}
|
||||||
|
offset
|
||||||
}
|
}
|
||||||
&Repr::Redirect {
|
&Repr::Redirect {
|
||||||
lladdr,
|
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
|
where
|
||||||
T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
|
T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
|
||||||
{
|
{
|
||||||
|
@ -431,7 +407,7 @@ impl<'a> Repr<'a> {
|
||||||
packet.clear_reserved();
|
packet.clear_reserved();
|
||||||
if let Some(lladdr) = lladdr {
|
if let Some(lladdr) = lladdr {
|
||||||
let mut opt_pkt = NdiscOption::new_unchecked(packet.payload_mut());
|
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;
|
let mut offset = 0;
|
||||||
if let Some(lladdr) = lladdr {
|
if let Some(lladdr) = lladdr {
|
||||||
let mut opt_pkt = NdiscOption::new_unchecked(packet.payload_mut());
|
let mut opt_pkt = NdiscOption::new_unchecked(packet.payload_mut());
|
||||||
NdiscOptionRepr::SourceLinkLayerAddr(lladdr).emit(&mut opt_pkt, medium);
|
let opt = NdiscOptionRepr::SourceLinkLayerAddr(lladdr);
|
||||||
match medium {
|
opt.emit(&mut opt_pkt);
|
||||||
#[cfg(feature = "medium-ethernet")]
|
offset += opt.buffer_len();
|
||||||
Medium::Ethernet => offset += 6,
|
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
|
||||||
Medium::Ieee802154 => offset += 8,
|
|
||||||
#[cfg(feature = "medium-ip")]
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if let Some(mtu) = mtu {
|
if let Some(mtu) = mtu {
|
||||||
let mut opt_pkt =
|
let mut opt_pkt =
|
||||||
NdiscOption::new_unchecked(&mut packet.payload_mut()[offset..]);
|
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;
|
offset += 8;
|
||||||
}
|
}
|
||||||
if let Some(prefix_info) = prefix_info {
|
if let Some(prefix_info) = prefix_info {
|
||||||
let mut opt_pkt =
|
let mut opt_pkt =
|
||||||
NdiscOption::new_unchecked(&mut packet.payload_mut()[offset..]);
|
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);
|
packet.set_target_addr(target_addr);
|
||||||
if let Some(lladdr) = lladdr {
|
if let Some(lladdr) = lladdr {
|
||||||
let mut opt_pkt = NdiscOption::new_unchecked(packet.payload_mut());
|
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);
|
packet.set_target_addr(target_addr);
|
||||||
if let Some(lladdr) = lladdr {
|
if let Some(lladdr) = lladdr {
|
||||||
let mut opt_pkt = NdiscOption::new_unchecked(packet.payload_mut());
|
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 {
|
let offset = match lladdr {
|
||||||
Some(lladdr) => {
|
Some(lladdr) => {
|
||||||
let mut opt_pkt = NdiscOption::new_unchecked(packet.payload_mut());
|
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
|
8
|
||||||
}
|
}
|
||||||
None => 0,
|
None => 0,
|
||||||
|
@ -530,7 +500,7 @@ impl<'a> Repr<'a> {
|
||||||
if let Some(redirected_hdr) = redirected_hdr {
|
if let Some(redirected_hdr) = redirected_hdr {
|
||||||
let mut opt_pkt =
|
let mut opt_pkt =
|
||||||
NdiscOption::new_unchecked(&mut packet.payload_mut()[offset..]);
|
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::phy::ChecksumCapabilities;
|
||||||
use crate::wire::ip::test::{MOCK_IP_ADDR_1, MOCK_IP_ADDR_2};
|
use crate::wire::ip::test::{MOCK_IP_ADDR_1, MOCK_IP_ADDR_2};
|
||||||
use crate::wire::EthernetAddress;
|
use crate::wire::EthernetAddress;
|
||||||
use crate::wire::HardwareAddress;
|
|
||||||
use crate::wire::Icmpv6Repr;
|
use crate::wire::Icmpv6Repr;
|
||||||
|
|
||||||
static ROUTER_ADVERT_BYTES: [u8; 24] = [
|
static ROUTER_ADVERT_BYTES: [u8; 24] = [
|
||||||
|
@ -559,9 +528,7 @@ mod test {
|
||||||
router_lifetime: Duration::from_secs(900),
|
router_lifetime: Duration::from_secs(900),
|
||||||
reachable_time: Duration::from_millis(900),
|
reachable_time: Duration::from_millis(900),
|
||||||
retrans_time: Duration::from_millis(900),
|
retrans_time: Duration::from_millis(900),
|
||||||
lladdr: Some(HardwareAddress::Ethernet(EthernetAddress([
|
lladdr: Some(EthernetAddress([0x52, 0x54, 0x00, 0x12, 0x34, 0x56]).into()),
|
||||||
0x52, 0x54, 0x00, 0x12, 0x34, 0x56,
|
|
||||||
]))),
|
|
||||||
mtu: None,
|
mtu: None,
|
||||||
prefix_info: None,
|
prefix_info: None,
|
||||||
})
|
})
|
||||||
|
@ -606,8 +573,7 @@ mod test {
|
||||||
&MOCK_IP_ADDR_1,
|
&MOCK_IP_ADDR_1,
|
||||||
&MOCK_IP_ADDR_2,
|
&MOCK_IP_ADDR_2,
|
||||||
&packet,
|
&packet,
|
||||||
&ChecksumCapabilities::default(),
|
&ChecksumCapabilities::default()
|
||||||
&Medium::Ethernet,
|
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
create_repr()
|
create_repr()
|
||||||
|
@ -623,7 +589,6 @@ mod test {
|
||||||
&MOCK_IP_ADDR_2,
|
&MOCK_IP_ADDR_2,
|
||||||
&mut packet,
|
&mut packet,
|
||||||
&ChecksumCapabilities::default(),
|
&ChecksumCapabilities::default(),
|
||||||
&Medium::Ethernet,
|
|
||||||
);
|
);
|
||||||
assert_eq!(&packet.into_inner()[..], &ROUTER_ADVERT_BYTES[..]);
|
assert_eq!(&packet.into_inner()[..], &ROUTER_ADVERT_BYTES[..]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,17 +2,11 @@ use bitflags::bitflags;
|
||||||
use byteorder::{ByteOrder, NetworkEndian};
|
use byteorder::{ByteOrder, NetworkEndian};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
use crate::phy::Medium;
|
|
||||||
use crate::time::Duration;
|
use crate::time::Duration;
|
||||||
use crate::wire::{Ipv6Address, Ipv6Packet, Ipv6Repr};
|
use crate::wire::{Ipv6Address, Ipv6Packet, Ipv6Repr, MAX_HARDWARE_ADDRESS_LEN};
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
|
|
||||||
#[cfg(feature = "medium-ethernet")]
|
use crate::wire::RawHardwareAddress;
|
||||||
use crate::wire::EthernetAddress;
|
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
|
||||||
use crate::wire::Ieee802154Address;
|
|
||||||
|
|
||||||
use crate::wire::HardwareAddress;
|
|
||||||
|
|
||||||
enum_with_unknown! {
|
enum_with_unknown! {
|
||||||
/// NDISC Option Type
|
/// NDISC Option Type
|
||||||
|
@ -90,12 +84,6 @@ mod field {
|
||||||
// | Type | Length | Link-Layer Address ...
|
// | 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.
|
// Prefix Information Option fields.
|
||||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
// | Type | Length | Prefix Length |L|A| Reserved1 |
|
// | Type | Length | Prefix Length |L|A| Reserved1 |
|
||||||
|
@ -225,23 +213,10 @@ impl<T: AsRef<[u8]>> NdiscOption<T> {
|
||||||
impl<T: AsRef<[u8]>> NdiscOption<T> {
|
impl<T: AsRef<[u8]>> NdiscOption<T> {
|
||||||
/// Return the Source/Target Link-layer Address.
|
/// Return the Source/Target Link-layer Address.
|
||||||
#[inline]
|
#[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();
|
let data = self.buffer.as_ref();
|
||||||
|
RawHardwareAddress::from_bytes(&data[2..len + 2])
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,21 +297,9 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> NdiscOption<T> {
|
||||||
impl<T: AsRef<[u8]> + AsMut<[u8]>> NdiscOption<T> {
|
impl<T: AsRef<[u8]> + AsMut<[u8]>> NdiscOption<T> {
|
||||||
/// Set the Source/Target Link-layer Address.
|
/// Set the Source/Target Link-layer Address.
|
||||||
#[inline]
|
#[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();
|
let data = self.buffer.as_mut();
|
||||||
match addr {
|
data[2..2 + addr.len()].copy_from_slice(addr.as_bytes())
|
||||||
#[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!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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> {
|
impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for NdiscOption<&'a T> {
|
||||||
//fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
//// XXX(thvdveld): how do we pass the medium?
|
match Repr::parse(self) {
|
||||||
//match Repr::parse(self, &Medium::Ethernet) {
|
Ok(repr) => write!(f, "{}", repr),
|
||||||
//Ok(repr) => write!(f, "{}", repr),
|
Err(err) => {
|
||||||
//Err(err) => {
|
write!(f, "NDISC Option ({})", err)?;
|
||||||
//write!(f, "NDISC Option ({})", err)?;
|
Ok(())
|
||||||
//Ok(())
|
}
|
||||||
//}
|
}
|
||||||
//}
|
}
|
||||||
//}
|
}
|
||||||
//}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
@ -447,8 +409,8 @@ pub struct RedirectedHeader<'a> {
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum Repr<'a> {
|
pub enum Repr<'a> {
|
||||||
SourceLinkLayerAddr(HardwareAddress),
|
SourceLinkLayerAddr(RawHardwareAddress),
|
||||||
TargetLinkLayerAddr(HardwareAddress),
|
TargetLinkLayerAddr(RawHardwareAddress),
|
||||||
PrefixInformation(PrefixInformation),
|
PrefixInformation(PrefixInformation),
|
||||||
RedirectedHeader(RedirectedHeader<'a>),
|
RedirectedHeader(RedirectedHeader<'a>),
|
||||||
Mtu(u32),
|
Mtu(u32),
|
||||||
|
@ -461,21 +423,21 @@ pub enum Repr<'a> {
|
||||||
|
|
||||||
impl<'a> Repr<'a> {
|
impl<'a> Repr<'a> {
|
||||||
/// Parse an NDISC Option and return a high-level representation.
|
/// 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
|
where
|
||||||
T: AsRef<[u8]> + ?Sized,
|
T: AsRef<[u8]> + ?Sized,
|
||||||
{
|
{
|
||||||
match opt.option_type() {
|
match opt.option_type() {
|
||||||
Type::SourceLinkLayerAddr => {
|
Type::SourceLinkLayerAddr => {
|
||||||
if opt.data_len() == 1 {
|
if opt.data_len() == 1 {
|
||||||
Ok(Repr::SourceLinkLayerAddr(opt.link_layer_addr(medium)))
|
Ok(Repr::SourceLinkLayerAddr(opt.link_layer_addr()))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Malformed)
|
Err(Error::Malformed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::TargetLinkLayerAddr => {
|
Type::TargetLinkLayerAddr => {
|
||||||
if opt.data_len() == 1 {
|
if opt.data_len() == 1 {
|
||||||
Ok(Repr::TargetLinkLayerAddr(opt.link_layer_addr(medium)))
|
Ok(Repr::TargetLinkLayerAddr(opt.link_layer_addr()))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Malformed)
|
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.
|
/// Return the length of a header 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, medium) {
|
match self {
|
||||||
#[cfg(feature = "medium-ethernet")]
|
&Repr::SourceLinkLayerAddr(addr) | &Repr::TargetLinkLayerAddr(addr) => {
|
||||||
(&Repr::SourceLinkLayerAddr(_) | &Repr::TargetLinkLayerAddr(_), Medium::Ethernet) => {
|
let len = 2 + addr.len();
|
||||||
field::LL_ADDR_ETHERNET.end
|
// Round up to next multiple of 8
|
||||||
|
(len + 7) / 8 * 8
|
||||||
}
|
}
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
&Repr::PrefixInformation(_) => field::PREFIX.end,
|
||||||
(&Repr::SourceLinkLayerAddr(_) | &Repr::TargetLinkLayerAddr(_), Medium::Ieee802154) => {
|
&Repr::RedirectedHeader(RedirectedHeader { header, data }) => {
|
||||||
field::LL_ADDR_IEEE802154.end
|
|
||||||
}
|
|
||||||
#[cfg(feature = "medium-ip")]
|
|
||||||
(&Repr::SourceLinkLayerAddr(_) | &Repr::TargetLinkLayerAddr(_), _) => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
(&Repr::PrefixInformation(_), _) => field::PREFIX.end,
|
|
||||||
(&Repr::RedirectedHeader(RedirectedHeader { header, data }), _) => {
|
|
||||||
field::IP_DATA + header.buffer_len() + data.len()
|
field::IP_DATA + header.buffer_len() + data.len()
|
||||||
}
|
}
|
||||||
(&Repr::Mtu(_), _) => field::MTU.end,
|
&Repr::Mtu(_) => field::MTU.end,
|
||||||
(&Repr::Unknown { length, .. }, _) => field::DATA(length).end,
|
&Repr::Unknown { length, .. } => field::DATA(length).end,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit a high-level representation into an NDISC Option.
|
/// 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
|
where
|
||||||
T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
|
T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
|
||||||
{
|
{
|
||||||
match *self {
|
match *self {
|
||||||
Repr::SourceLinkLayerAddr(addr) => {
|
Repr::SourceLinkLayerAddr(addr) => {
|
||||||
opt.set_option_type(Type::SourceLinkLayerAddr);
|
opt.set_option_type(Type::SourceLinkLayerAddr);
|
||||||
match medium {
|
let opt_len = addr.len() + 2;
|
||||||
#[cfg(feature = "medium-ethernet")]
|
opt.set_data_len(((opt_len + 7) / 8) as u8); // round to next multiple of 8.
|
||||||
Medium::Ethernet => opt.set_data_len(1),
|
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
|
||||||
Medium::Ieee802154 => opt.set_data_len(2),
|
|
||||||
#[cfg(feature = "medium-ip")]
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
opt.set_link_layer_addr(addr);
|
opt.set_link_layer_addr(addr);
|
||||||
}
|
}
|
||||||
Repr::TargetLinkLayerAddr(addr) => {
|
Repr::TargetLinkLayerAddr(addr) => {
|
||||||
opt.set_option_type(Type::TargetLinkLayerAddr);
|
opt.set_option_type(Type::TargetLinkLayerAddr);
|
||||||
match medium {
|
let opt_len = addr.len() + 2;
|
||||||
#[cfg(feature = "medium-ethernet")]
|
opt.set_data_len(((opt_len + 7) / 8) as u8); // round to next multiple of 8.
|
||||||
Medium::Ethernet => opt.set_data_len(1),
|
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
|
||||||
Medium::Ieee802154 => opt.set_data_len(2),
|
|
||||||
#[cfg(feature = "medium-ip")]
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
opt.set_link_layer_addr(addr);
|
opt.set_link_layer_addr(addr);
|
||||||
}
|
}
|
||||||
Repr::PrefixInformation(PrefixInformation {
|
Repr::PrefixInformation(PrefixInformation {
|
||||||
|
@ -626,42 +569,51 @@ impl<'a> fmt::Display for Repr<'a> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "NDISC Option: ")?;
|
write!(f, "NDISC Option: ")?;
|
||||||
match *self {
|
match *self {
|
||||||
Repr::SourceLinkLayerAddr(addr) => write!(f, "SourceLinkLayer addr={}", addr),
|
Repr::SourceLinkLayerAddr(addr) => {
|
||||||
Repr::TargetLinkLayerAddr(addr) => write!(f, "TargetLinkLayer addr={}", addr),
|
write!(f, "SourceLinkLayer addr={}", addr)
|
||||||
|
}
|
||||||
|
Repr::TargetLinkLayerAddr(addr) => {
|
||||||
|
write!(f, "TargetLinkLayer addr={}", addr)
|
||||||
|
}
|
||||||
Repr::PrefixInformation(PrefixInformation {
|
Repr::PrefixInformation(PrefixInformation {
|
||||||
prefix, prefix_len, ..
|
prefix, prefix_len, ..
|
||||||
}) => write!(f, "PrefixInformation prefix={}/{}", prefix, prefix_len),
|
}) => {
|
||||||
|
write!(f, "PrefixInformation prefix={}/{}", prefix, prefix_len)
|
||||||
|
}
|
||||||
Repr::RedirectedHeader(RedirectedHeader { header, .. }) => {
|
Repr::RedirectedHeader(RedirectedHeader { header, .. }) => {
|
||||||
write!(f, "RedirectedHeader header={}", header)
|
write!(f, "RedirectedHeader header={}", header)
|
||||||
}
|
}
|
||||||
Repr::Mtu(mtu) => write!(f, "MTU mtu={}", mtu),
|
Repr::Mtu(mtu) => {
|
||||||
|
write!(f, "MTU mtu={}", mtu)
|
||||||
|
}
|
||||||
Repr::Unknown {
|
Repr::Unknown {
|
||||||
type_: id, length, ..
|
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> {
|
impl<T: AsRef<[u8]>> PrettyPrint for NdiscOption<T> {
|
||||||
//fn pretty_print(
|
fn pretty_print(
|
||||||
//buffer: &dyn AsRef<[u8]>,
|
buffer: &dyn AsRef<[u8]>,
|
||||||
//f: &mut fmt::Formatter,
|
f: &mut fmt::Formatter,
|
||||||
//indent: &mut PrettyIndent,
|
indent: &mut PrettyIndent,
|
||||||
//) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
//// TODO(thvdveld): how do we pass the medium?
|
match NdiscOption::new_checked(buffer) {
|
||||||
//match NdiscOption::new_checked(buffer) {
|
Err(err) => return write!(f, "{}({})", indent, err),
|
||||||
//Err(err) => return write!(f, "{}({})", indent, err),
|
Ok(ndisc) => match Repr::parse(&ndisc) {
|
||||||
//Ok(ndisc) => match Repr::parse(&ndisc, &Medium::Ethernet) {
|
Err(_) => Ok(()),
|
||||||
//Err(_) => Ok(()),
|
Ok(repr) => {
|
||||||
//Ok(repr) => {
|
write!(f, "{}{}", indent, repr)
|
||||||
//write!(f, "{}{}", indent, repr)
|
}
|
||||||
//}
|
},
|
||||||
//},
|
}
|
||||||
//}
|
}
|
||||||
//}
|
}
|
||||||
//}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
@ -721,20 +673,14 @@ mod test {
|
||||||
let addr = EthernetAddress([0x54, 0x52, 0x00, 0x12, 0x23, 0x34]);
|
let addr = EthernetAddress([0x54, 0x52, 0x00, 0x12, 0x23, 0x34]);
|
||||||
{
|
{
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Repr::parse(
|
Repr::parse(&NdiscOption::new_unchecked(&bytes)),
|
||||||
&NdiscOption::new_unchecked(&bytes),
|
|
||||||
&crate::phy::Medium::Ethernet
|
|
||||||
),
|
|
||||||
Ok(Repr::SourceLinkLayerAddr(addr.into()))
|
Ok(Repr::SourceLinkLayerAddr(addr.into()))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
bytes[0] = 0x02;
|
bytes[0] = 0x02;
|
||||||
{
|
{
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Repr::parse(
|
Repr::parse(&NdiscOption::new_unchecked(&bytes)),
|
||||||
&NdiscOption::new_unchecked(&bytes),
|
|
||||||
&crate::phy::Medium::Ethernet
|
|
||||||
),
|
|
||||||
Ok(Repr::TargetLinkLayerAddr(addr.into()))
|
Ok(Repr::TargetLinkLayerAddr(addr.into()))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -750,10 +696,7 @@ mod test {
|
||||||
prefix: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1),
|
prefix: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1),
|
||||||
});
|
});
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Repr::parse(
|
Repr::parse(&NdiscOption::new_unchecked(&PREFIX_OPT_BYTES)),
|
||||||
&NdiscOption::new_unchecked(&PREFIX_OPT_BYTES),
|
|
||||||
&crate::phy::Medium::Ethernet
|
|
||||||
),
|
|
||||||
Ok(repr)
|
Ok(repr)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -769,7 +712,7 @@ mod test {
|
||||||
prefix: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1),
|
prefix: Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1),
|
||||||
});
|
});
|
||||||
let mut opt = NdiscOption::new_unchecked(&mut bytes);
|
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[..]);
|
assert_eq!(&opt.into_inner()[..], &PREFIX_OPT_BYTES[..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -777,10 +720,7 @@ mod test {
|
||||||
fn test_repr_parse_mtu() {
|
fn test_repr_parse_mtu() {
|
||||||
let bytes = [0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0xdc];
|
let bytes = [0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0xdc];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Repr::parse(
|
Repr::parse(&NdiscOption::new_unchecked(&bytes)),
|
||||||
&NdiscOption::new_unchecked(&bytes),
|
|
||||||
&crate::phy::Medium::Ethernet
|
|
||||||
),
|
|
||||||
Ok(Repr::Mtu(1500))
|
Ok(Repr::Mtu(1500))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue