Prechádzať zdrojové kódy

Add RawHardwareAddress, use it in wire ndisc.

This avoids wire needing to know what medium we're on.
Dario Nieuwenhuis 3 rokov pred
rodič
commit
68e25a29c3

+ 1 - 21
examples/ping.rs

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

+ 44 - 45
src/iface/interface.rs

@@ -389,7 +389,6 @@ impl<'a> IpPacket<'a> {
                 &_ip_repr.dst_addr(),
                 &mut Icmpv6Packet::new_unchecked(payload),
                 &caps.checksum,
-                &caps.medium,
             ),
             #[cfg(feature = "socket-raw")]
             IpPacket::Raw((_, raw_packet)) => payload.copy_from_slice(raw_packet),
@@ -1198,7 +1197,7 @@ impl<'a> InterfaceInner<'a> {
                                     header: ipv6_repr,
                                     data: &payload[0..payload_len],
                                 };
-                                Ok(self.icmpv6_reply(cx, ipv6_repr, icmpv6_reply_repr))
+                                Ok(self.icmpv6_reply(ipv6_repr, icmpv6_reply_repr))
                             }
                             IpRepr::Unspecified { .. } => Err(Error::Unaddressable),
                             IpRepr::Sixlowpan(_) => Err(Error::Malformed), // XXX(thvdveld): this is just wrong;
@@ -1394,7 +1393,7 @@ impl<'a> InterfaceInner<'a> {
                     header: ipv6_repr,
                     data: &ip_payload[0..payload_len],
                 };
-                Ok(self.icmpv6_reply(cx, ipv6_repr, icmp_reply_repr))
+                Ok(self.icmpv6_reply(ipv6_repr, icmp_reply_repr))
             }
         }
     }
@@ -1604,7 +1603,6 @@ impl<'a> InterfaceInner<'a> {
             &ip_repr.dst_addr(),
             &icmp_packet,
             &cx.caps.checksum,
-            &cx.caps.medium,
         )?;
 
         #[cfg(feature = "socket-icmp")]
@@ -1639,7 +1637,7 @@ impl<'a> InterfaceInner<'a> {
                         seq_no,
                         data,
                     };
-                    Ok(self.icmpv6_reply(cx, ipv6_repr, icmp_reply_repr))
+                    Ok(self.icmpv6_reply(ipv6_repr, icmp_reply_repr))
                 }
                 #[cfg(feature = "medium-ieee802154")]
                 IpRepr::Sixlowpan(sixlowpan_repr) => {
@@ -1649,7 +1647,6 @@ impl<'a> InterfaceInner<'a> {
                         data,
                     };
                     Ok(self.icmpv6_reply(
-                        cx,
                         Ipv6Repr {
                             src_addr: sixlowpan_repr.src_addr,
                             dst_addr: sixlowpan_repr.dst_addr,
@@ -1714,23 +1711,24 @@ impl<'a> InterfaceInner<'a> {
                 flags,
             } => {
                 let ip_addr = ip_repr.src_addr.into();
-                match lladdr {
-                    Some(lladdr) if lladdr.is_unicast() && target_addr.is_unicast() => {
-                        if flags.contains(NdiscNeighborFlags::OVERRIDE)
-                            || !self
-                                .neighbor_cache
-                                .as_mut()
-                                .unwrap()
-                                .lookup(&ip_addr, cx.now)
-                                .found()
-                        {
-                            self.neighbor_cache
-                                .as_mut()
-                                .unwrap()
-                                .fill(ip_addr, lladdr, cx.now)
-                        }
+                if let Some(lladdr) = lladdr {
+                    let lladdr = lladdr.parse(cx.caps.medium)?;
+                    if !lladdr.is_unicast() || !target_addr.is_unicast() {
+                        return Err(Error::Malformed);
+                    }
+                    if flags.contains(NdiscNeighborFlags::OVERRIDE)
+                        || !self
+                            .neighbor_cache
+                            .as_mut()
+                            .unwrap()
+                            .lookup(&ip_addr, cx.now)
+                            .found()
+                    {
+                        self.neighbor_cache
+                            .as_mut()
+                            .unwrap()
+                            .fill(ip_addr, lladdr, cx.now)
                     }
-                    _ => (),
                 }
                 Ok(None)
             }
@@ -1739,27 +1737,31 @@ impl<'a> InterfaceInner<'a> {
                 lladdr,
                 ..
             } => {
-                match lladdr {
-                    Some(lladdr) if lladdr.is_unicast() && target_addr.is_unicast() => self
-                        .neighbor_cache
-                        .as_mut()
-                        .unwrap()
-                        .fill(ip_repr.src_addr.into(), lladdr, cx.now),
-                    _ => (),
+                if let Some(lladdr) = lladdr {
+                    let lladdr = lladdr.parse(cx.caps.medium)?;
+                    if !lladdr.is_unicast() || !target_addr.is_unicast() {
+                        return Err(Error::Malformed);
+                    }
+                    self.neighbor_cache.as_mut().unwrap().fill(
+                        ip_repr.src_addr.into(),
+                        lladdr,
+                        cx.now,
+                    );
                 }
+
                 if self.has_solicited_node(ip_repr.dst_addr) && self.has_ip_addr(target_addr) {
                     let advert = Icmpv6Repr::Ndisc(NdiscRepr::NeighborAdvert {
                         flags: NdiscNeighborFlags::SOLICITED,
                         target_addr,
                         #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
-                        lladdr: Some(self.hardware_addr.unwrap()),
+                        lladdr: Some(self.hardware_addr.unwrap().into()),
                     });
                     let ip_repr = Ipv6Repr {
                         src_addr: target_addr,
                         dst_addr: ip_repr.src_addr,
                         next_header: IpProtocol::Icmpv6,
                         hop_limit: 0xff,
-                        payload_len: advert.buffer_len(&cx.caps.medium),
+                        payload_len: advert.buffer_len(),
                     };
                     Ok(Some(IpPacket::Icmpv6((ip_repr, advert))))
                 } else {
@@ -1917,7 +1919,6 @@ impl<'a> InterfaceInner<'a> {
     #[cfg(feature = "proto-ipv6")]
     fn icmpv6_reply<'frame, 'icmp: 'frame>(
         &self,
-        cx: &Context,
         ipv6_repr: Ipv6Repr,
         icmp_repr: Icmpv6Repr<'icmp>,
     ) -> Option<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,
         };
 

+ 5 - 12
src/socket/icmp.rs

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

+ 11 - 9
src/wire/arp.rs

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

+ 6 - 15
src/wire/icmpv6.rs

@@ -2,7 +2,6 @@ use byteorder::{ByteOrder, NetworkEndian};
 use core::{cmp, fmt};
 
 use crate::phy::ChecksumCapabilities;
-use crate::phy::Medium;
 use crate::wire::ip::checksum;
 use crate::wire::MldRepr;
 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
@@ -546,7 +545,6 @@ impl<'a> Repr<'a> {
         dst_addr: &IpAddress,
         packet: &Packet<&'a T>,
         checksum_caps: &ChecksumCapabilities,
-        medium: &Medium,
     ) -> Result<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[..]);
     }

+ 15 - 20
src/wire/ipv6routing.rs

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

+ 0 - 4
src/wire/mld.rs

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

+ 93 - 0
src/wire/mod.rs

@@ -123,6 +123,8 @@ mod sixlowpan;
 mod tcp;
 mod udp;
 
+use crate::{phy::Medium, Error};
+
 pub use self::pretty_print::PrettyPrinter;
 
 #[cfg(feature = "medium-ethernet")]
@@ -310,3 +312,94 @@ impl From<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())
+    }
+}

+ 31 - 66
src/wire/ndisc.rs

@@ -1,11 +1,10 @@
 use bitflags::bitflags;
 use byteorder::{ByteOrder, NetworkEndian};
 
-use crate::phy::Medium;
 use crate::time::Duration;
 use crate::wire::icmpv6::{field, Message, Packet};
-use crate::wire::HardwareAddress;
 use crate::wire::Ipv6Address;
+use crate::wire::RawHardwareAddress;
 use crate::wire::{Ipv6Packet, Ipv6Repr};
 use crate::wire::{NdiscOption, NdiscOptionRepr, NdiscOptionType};
 use crate::wire::{NdiscPrefixInformation, NdiscRedirectedHeader};
@@ -195,7 +194,7 @@ impl<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[..]);
     }

+ 77 - 137
src/wire/ndiscoption.rs

@@ -2,17 +2,11 @@ use bitflags::bitflags;
 use byteorder::{ByteOrder, NetworkEndian};
 use core::fmt;
 
-use crate::phy::Medium;
 use crate::time::Duration;
-use crate::wire::{Ipv6Address, Ipv6Packet, Ipv6Repr};
+use crate::wire::{Ipv6Address, Ipv6Packet, Ipv6Repr, MAX_HARDWARE_ADDRESS_LEN};
 use crate::{Error, Result};
 
-#[cfg(feature = "medium-ethernet")]
-use crate::wire::EthernetAddress;
-#[cfg(feature = "medium-ieee802154")]
-use crate::wire::Ieee802154Address;
-
-use crate::wire::HardwareAddress;
+use crate::wire::RawHardwareAddress;
 
 enum_with_unknown! {
     /// NDISC Option Type
@@ -90,12 +84,6 @@ mod field {
     // |     Type      |    Length     |    Link-Layer Address ...
     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
-    // Link-Layer Address
-    #[cfg(feature = "medium-ethernet")]
-    pub const LL_ADDR_ETHERNET: Field = 2..8;
-    #[cfg(feature = "medium-ieee802154")]
-    pub const LL_ADDR_IEEE802154: Field = 2..10;
-
     // Prefix Information Option fields.
     //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     //  |     Type      |    Length     | Prefix Length |L|A| Reserved1 |
@@ -225,23 +213,10 @@ impl<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
-            }
-            #[cfg(feature = "medium-ieee802154")]
-            (&Repr::SourceLinkLayerAddr(_) | &Repr::TargetLinkLayerAddr(_), Medium::Ieee802154) => {
-                field::LL_ADDR_IEEE802154.end
-            }
-            #[cfg(feature = "medium-ip")]
-            (&Repr::SourceLinkLayerAddr(_) | &Repr::TargetLinkLayerAddr(_), _) => {
-                unreachable!()
+    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
             }
-            (&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};
-
-//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)
-//}
-//},
-//}
-//}
-//}
+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 {
+        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))
         );
     }