[net-types] Introduce `Witness` trait

- Introduce the `Witness` trait; `Witness<A>` is implemented by
  any witness type (`SpecifiedAddr<A>`, `UnicastAddr<A>`, etc) which
  is a witness to some property about the address `A`
- Introduce the `IpAddrWitness: Witness<IpAddr>` trait, which
  provides useful associated types
- Modify `AddrSubnet` and `AddrSubnetEither` to be generic over
  which witness type is used as opposed to only supporting
  `SpecifiedAddr`

Test: Very little behavior change, although added one test case to
      make sure that `AddrSubnet::new` properly rejects addresses
      based on the witness type which is used
Change-Id: I12ea1f7b5f0892e7fa625864a454e4585b92701f
diff --git a/src/connectivity/lib/net-types/src/ethernet.rs b/src/connectivity/lib/net-types/src/ethernet.rs
index 90a6e0a..bb2920d 100644
--- a/src/connectivity/lib/net-types/src/ethernet.rs
+++ b/src/connectivity/lib/net-types/src/ethernet.rs
@@ -9,7 +9,9 @@
 use zerocopy::{AsBytes, FromBytes, Unaligned};
 
 use crate::ip::{IpAddress, Ipv6Addr};
-use crate::{BroadcastAddress, LinkLocalAddr, MulticastAddr, MulticastAddress, UnicastAddress};
+use crate::{
+    BroadcastAddress, LinkLocalAddr, MulticastAddr, MulticastAddress, UnicastAddress, Witness,
+};
 
 /// A media access control (MAC) address.
 ///
diff --git a/src/connectivity/lib/net-types/src/ip.rs b/src/connectivity/lib/net-types/src/ip.rs
index 1f95fa79..d6dda51 100644
--- a/src/connectivity/lib/net-types/src/ip.rs
+++ b/src/connectivity/lib/net-types/src/ip.rs
@@ -59,7 +59,7 @@
 
 use crate::{
     sealed, LinkLocalAddr, LinkLocalAddress, MulticastAddr, MulticastAddress, SpecifiedAddr,
-    SpecifiedAddress, UnicastAddress,
+    SpecifiedAddress, UnicastAddress, Witness,
 };
 
 // NOTE on passing by reference vs by value: Clippy advises us to pass IPv4
@@ -1002,70 +1002,105 @@
 ///
 /// An `AddrSubnet` is a pair of an address and a subnet which maintains the
 /// invariant that the address is guaranteed to be a unicast address in the
-/// subnet.
+/// subnet. `S` is the type of address ([`Ipv4Addr`] or [`Ipv6Addr`]), and `A`
+/// is the type of the address in the subnet, which is always a witness wrapper
+/// around `S`. By default, it is `SpecifiedAddr<S>`.
 #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
-pub struct AddrSubnet<A: IpAddress> {
+pub struct AddrSubnet<S: IpAddress, A: Witness<S> = SpecifiedAddr<S>> {
     // TODO(joshlf): Would it be more performant to store these as just an
     // address and subnet mask? It would make the object smaller and so cheaper
     // to pass around, but it would make certain operations more expensive.
-    addr: SpecifiedAddr<A>,
-    subnet: Subnet<A>,
+    addr: A,
+    subnet: Subnet<S>,
 }
 
-impl<A: IpAddress> AddrSubnet<A> {
+impl<S: IpAddress, A: Witness<S>> AddrSubnet<S, A> {
     /// Creates a new `AddrSubnet`.
     ///
     /// `new` creates a new `AddrSubnet` with the given address and prefix
     /// length. The network address of the subnet is taken to be the first
     /// `prefix` bits of the address. It returns `None` if `prefix` is longer
     /// than the number of bits in this type of IP address (32 for IPv4 and 128
-    /// for IPv6) or if `addr` is not a unicast address in the resulting subnet
-    /// (see [`IpAddress::is_unicast_in_subnet`]).
+    /// for IPv6), if `addr` is not a unicast address in the resulting subnet
+    /// (see [`IpAddress::is_unicast_in_subnet`]), or if `addr` does not satisfy
+    /// the requirements of the witness type `A`.
     #[inline]
-    pub fn new(addr: A, prefix: u8) -> Option<AddrSubnet<A>> {
-        if prefix > A::BYTES * 8 {
+    pub fn new(addr: S, prefix: u8) -> Option<AddrSubnet<S, A>> {
+        if prefix > S::BYTES * 8 {
             return None;
         }
         let subnet = Subnet { network: addr.mask(prefix), prefix };
         if !addr.is_unicast_in_subnet(&subnet) {
             return None;
         }
-        let addr = SpecifiedAddr::new(addr)?;
+        let addr = A::new(addr)?;
         Some(AddrSubnet { addr, subnet })
     }
 
-    /// Gets the address.
-    #[inline]
-    pub fn addr(&self) -> SpecifiedAddr<A> {
-        self.addr
-    }
-
     /// Gets the subnet.
     #[inline]
-    pub fn subnet(&self) -> Subnet<A> {
+    pub fn subnet(&self) -> Subnet<S> {
         self.subnet
     }
 
     /// Consumes the `AddrSubnet` and returns the address.
     #[inline]
-    pub fn into_addr(self) -> SpecifiedAddr<A> {
+    pub fn into_addr(self) -> A {
         self.addr
     }
 
     /// Consumes the `AddrSubnet` and returns the subnet.
     #[inline]
-    pub fn into_subnet(self) -> Subnet<A> {
+    pub fn into_subnet(self) -> Subnet<S> {
         self.subnet
     }
 
     /// Consumes the `AddrSubnet` and returns the address and subnet
     /// individually.
     #[inline]
-    pub fn into_addr_subnet(self) -> (SpecifiedAddr<A>, Subnet<A>) {
+    pub fn into_addr_subnet(self) -> (A, Subnet<S>) {
         (self.addr, self.subnet)
     }
 }
 
+impl<S: IpAddress, A: Witness<S> + Copy> AddrSubnet<S, A> {
+    /// Gets the address.
+    #[inline]
+    pub fn addr(&self) -> A {
+        self.addr
+    }
+}
+
+/// A type which is a witness to some property about an `IpAddress`.
+///
+/// `IpAddrWitness` extends [`Witness`] by adding associated types for the IPv4-
+/// and IPv6-specific versions of the same witness type. For example, the
+/// following implementation is provided for `SpecifiedAddr<IpAddr>`:
+///
+/// ```rust,ignore
+/// impl IpAddrWitness for SpecifiedAddr<IpAddr> {
+///     type V4 = SpecifiedAddr<Ipv4Addr>;
+///     type V6 = SpecifiedAddr<Ipv6Addr>;
+/// }
+/// ```
+pub trait IpAddrWitness: Witness<IpAddr> {
+    type V4: Witness<Ipv4Addr> + Into<Self>;
+    type V6: Witness<Ipv6Addr> + Into<Self>;
+}
+
+macro_rules! impl_ip_addr_witness {
+    ($witness:ident) => {
+        impl IpAddrWitness for $witness<IpAddr> {
+            type V4 = $witness<Ipv4Addr>;
+            type V6 = $witness<Ipv6Addr>;
+        }
+    };
+}
+
+impl_ip_addr_witness!(SpecifiedAddr);
+impl_ip_addr_witness!(MulticastAddr);
+impl_ip_addr_witness!(LinkLocalAddr);
+
 /// An address and that address' subnet, either IPv4 or IPv6.
 ///
 /// `AddrSubnetEither` is an enum of [`AddrSubnet<Ipv4Addr>`] and
@@ -1074,21 +1109,19 @@
 /// [`AddrSubnet<Ipv4Addr>`]: crate::ip::AddrSubnet
 #[allow(missing_docs)]
 #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
-pub enum AddrSubnetEither {
-    V4(AddrSubnet<Ipv4Addr>),
-    V6(AddrSubnet<Ipv6Addr>),
+pub enum AddrSubnetEither<A: IpAddrWitness = SpecifiedAddr<IpAddr>> {
+    V4(AddrSubnet<Ipv4Addr, A::V4>),
+    V6(AddrSubnet<Ipv6Addr, A::V6>),
 }
 
-impl AddrSubnetEither {
+impl<A: IpAddrWitness> AddrSubnetEither<A> {
     /// Creates a new `AddrSubnetEither`.
     ///
     /// `new` creates a new `AddrSubnetEither` with the given address and prefix
-    /// length. The network address of the subnet is taken to be the first
-    /// `prefix` bits of the address. It returns `None` if `prefix` is longer
-    /// than the number of bits in this type of IP address (32 for IPv4 and 128
-    /// for IPv6).
+    /// length. It returns `None` under the same conditions as
+    /// [`AddrSubnet::new`].
     #[inline]
-    pub fn new(addr: IpAddr, prefix: u8) -> Option<AddrSubnetEither> {
+    pub fn new(addr: IpAddr, prefix: u8) -> Option<AddrSubnetEither<A>> {
         Some(match addr {
             IpAddr::V4(addr) => AddrSubnetEither::V4(AddrSubnet::new(addr, prefix)?),
             IpAddr::V6(addr) => AddrSubnetEither::V6(AddrSubnet::new(addr, prefix)?),
@@ -1097,7 +1130,7 @@
 
     /// Gets the contained IP address and prefix in this `AddrSubnetEither`.
     #[inline]
-    pub fn into_addr_prefix(self) -> (SpecifiedAddr<IpAddr>, u8) {
+    pub fn into_addr_prefix(self) -> (A, u8) {
         match self {
             AddrSubnetEither::V4(v4) => (v4.addr.into(), v4.subnet.prefix),
             AddrSubnetEither::V6(v6) => (v6.addr.into(), v6.subnet.prefix),
@@ -1106,7 +1139,7 @@
 
     /// Gets the IP address and subnet in this `AddrSubnetEither`.
     #[inline]
-    pub fn into_addr_subnet(self) -> (SpecifiedAddr<IpAddr>, SubnetEither) {
+    pub fn into_addr_subnet(self) -> (A, SubnetEither) {
         match self {
             AddrSubnetEither::V4(v4) => (v4.addr.into(), SubnetEither::V4(v4.subnet)),
             AddrSubnetEither::V6(v6) => (v6.addr.into(), SubnetEither::V6(v6.subnet)),
@@ -1179,30 +1212,42 @@
         // Network address has more than top 8 bits set
         assert_eq!(Subnet::new(Ipv4Addr::new([255, 255, 0, 0]), 8), None);
 
-        AddrSubnet::new(Ipv4Addr::new([1, 2, 3, 4]), 32).unwrap();
+        AddrSubnet::<_, SpecifiedAddr<_>>::new(Ipv4Addr::new([1, 2, 3, 4]), 32).unwrap();
         // The unspecified address is not considered to be a unicast address in
         // any subnet (use assert, not assert_eq, because AddrSubnet doesn't
         // impl Debug)
-        assert!(AddrSubnet::new(Ipv4::UNSPECIFIED_ADDRESS, 16) == None);
-        assert!(AddrSubnet::new(Ipv6::UNSPECIFIED_ADDRESS, 64) == None);
+        assert!(AddrSubnet::<_, SpecifiedAddr<_>>::new(Ipv4::UNSPECIFIED_ADDRESS, 16) == None);
+        assert!(AddrSubnet::<_, SpecifiedAddr<_>>::new(Ipv6::UNSPECIFIED_ADDRESS, 64) == None);
         // Prefix exceeds 32/128 bits
-        assert!(AddrSubnet::new(Ipv4Addr::new([1, 2, 3, 4]), 33) == None);
+        assert!(AddrSubnet::<_, SpecifiedAddr<_>>::new(Ipv4Addr::new([1, 2, 3, 4]), 33) == None);
         assert!(
-            AddrSubnet::new(
+            AddrSubnet::<_, SpecifiedAddr<_>>::new(
                 Ipv6Addr::new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
                 129
             ) == None
         );
         // Global broadcast
-        assert!(AddrSubnet::new(Ipv4::GLOBAL_BROADCAST_ADDRESS.into_addr(), 16) == None);
-        // Subnet broadcast
-        assert!(AddrSubnet::new(Ipv4Addr::new([192, 168, 255, 255]), 16) == None);
-        // Multicast
-        assert!(AddrSubnet::new(Ipv4Addr::new([224, 0, 0, 1]), 16) == None);
         assert!(
-            AddrSubnet::new(Ipv6Addr::new([0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]), 64)
+            AddrSubnet::<_, SpecifiedAddr<_>>::new(Ipv4::GLOBAL_BROADCAST_ADDRESS.into_addr(), 16)
                 == None
         );
+        // Subnet broadcast
+        assert!(
+            AddrSubnet::<_, SpecifiedAddr<_>>::new(Ipv4Addr::new([192, 168, 255, 255]), 16) == None
+        );
+        // Multicast
+        assert!(AddrSubnet::<_, SpecifiedAddr<_>>::new(Ipv4Addr::new([224, 0, 0, 1]), 16) == None);
+        assert!(
+            AddrSubnet::<_, SpecifiedAddr<_>>::new(
+                Ipv6Addr::new([0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]),
+                64
+            ) == None
+        );
+
+        // If we use the `LinkLocalAddr` witness type, then non link-local
+        // addresses are rejected. Note that this address was accepted above
+        // when `SpecifiedAddr` was used.
+        assert!(AddrSubnet::<_, LinkLocalAddr<_>>::new(Ipv4Addr::new([1, 2, 3, 4]), 32) == None);
     }
 
     #[test]
diff --git a/src/connectivity/lib/net-types/src/lib.rs b/src/connectivity/lib/net-types/src/lib.rs
index 2529784..b19c798 100644
--- a/src/connectivity/lib/net-types/src/lib.rs
+++ b/src/connectivity/lib/net-types/src/lib.rs
@@ -25,6 +25,28 @@
     pub trait Sealed {}
 }
 
+/// A type which is a witness to some property about an address.
+///
+/// A type which implements `Witness<A>` wraps an address of type `A` and
+/// guarantees some property about the wrapped address. It is implemented by
+/// [`SpecifiedAddr`], [`UnicastAddr`], [`MulticastAddr`], and
+/// [`LinkLocalAddr`].
+pub trait Witness<A>: Deref<Target = A> + sealed::Sealed + Sized {
+    /// Constructs a new witness type..
+    ///
+    /// `new` returns `None` if `addr` does not satisfy the property guaranteed
+    /// by `Self`.
+    fn new(addr: A) -> Option<Self>;
+
+    /// Get a clone of the address.
+    fn get(&self) -> A
+    where
+        A: Clone;
+
+    /// Consumes this witness and returns the contained `A`.
+    fn into_addr(self) -> A;
+}
+
 // NOTE: The "witness" types UnicastAddr, MulticastAddr, and LinkLocalAddr -
 // which provide the invariant that the value they contain is a unicast,
 // multicast, or link-local address, respectively - cannot actually guarantee
@@ -172,6 +194,30 @@
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
 pub struct SpecifiedAddr<A>(A);
 
+impl<A: SpecifiedAddress> sealed::Sealed for SpecifiedAddr<A> {}
+impl<A: SpecifiedAddress> Witness<A> for SpecifiedAddr<A> {
+    #[inline]
+    fn new(addr: A) -> Option<SpecifiedAddr<A>> {
+        if !addr.is_specified() {
+            return None;
+        }
+        Some(SpecifiedAddr(addr))
+    }
+
+    #[inline]
+    fn get(&self) -> A
+    where
+        A: Clone,
+    {
+        self.0.clone()
+    }
+
+    #[inline]
+    fn into_addr(self) -> A {
+        self.0
+    }
+}
+
 impl<A> SpecifiedAddr<A> {
     /// Constructs a new `SpecifiedAddr` without checking to see if `addr` is
     /// actually a specified address.
@@ -185,34 +231,6 @@
     pub const unsafe fn new_unchecked(addr: A) -> SpecifiedAddr<A> {
         SpecifiedAddr(addr)
     }
-
-    /// Consumes this `SpecifiedAddr` and returns the contained `A`.
-    #[inline]
-    pub fn into_addr(self) -> A {
-        self.0
-    }
-}
-
-impl<A: SpecifiedAddress> SpecifiedAddr<A> {
-    /// Constructs a new `SpecifiedAddr`.
-    ///
-    /// `new` returns `None` if `addr` is not a specified address according to
-    /// [`SpecifiedAddress::is_specified`].
-    #[inline]
-    pub fn new(addr: A) -> Option<SpecifiedAddr<A>> {
-        if !addr.is_specified() {
-            return None;
-        }
-        Some(SpecifiedAddr(addr))
-    }
-}
-
-impl<A: Clone> SpecifiedAddr<A> {
-    /// Get a clone of the address.
-    #[inline]
-    pub fn get(&self) -> A {
-        self.0.clone()
-    }
 }
 
 impl<A: SpecifiedAddress> Deref for SpecifiedAddr<A> {
@@ -240,6 +258,30 @@
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
 pub struct UnicastAddr<A>(A);
 
+impl<A: UnicastAddress> sealed::Sealed for UnicastAddr<A> {}
+impl<A: UnicastAddress> Witness<A> for UnicastAddr<A> {
+    #[inline]
+    fn new(addr: A) -> Option<UnicastAddr<A>> {
+        if !addr.is_unicast() {
+            return None;
+        }
+        Some(UnicastAddr(addr))
+    }
+
+    #[inline]
+    fn get(&self) -> A
+    where
+        A: Clone,
+    {
+        self.0.clone()
+    }
+
+    #[inline]
+    fn into_addr(self) -> A {
+        self.0
+    }
+}
+
 impl<A> UnicastAddr<A> {
     /// Constructs a new `UnicastAddr` without checking to see if `addr` is
     /// actually a unicast address.
@@ -253,34 +295,6 @@
     pub const unsafe fn new_unchecked(addr: A) -> UnicastAddr<A> {
         UnicastAddr(addr)
     }
-
-    /// Consumes this `UnicastAddr` and returns the contained `A`.
-    #[inline]
-    pub fn into_addr(self) -> A {
-        self.0
-    }
-}
-
-impl<A: UnicastAddress> UnicastAddr<A> {
-    /// Constructs a new `UnicastAddr`.
-    ///
-    /// `new` returns `None` if `addr` is not a unicast address according to
-    /// [`UnicastAddress::is_unicast`].
-    #[inline]
-    pub fn new(addr: A) -> Option<UnicastAddr<A>> {
-        if !addr.is_unicast() {
-            return None;
-        }
-        Some(UnicastAddr(addr))
-    }
-}
-
-impl<A: Clone> UnicastAddr<A> {
-    /// Get a clone of the address.
-    #[inline]
-    pub fn get(&self) -> A {
-        self.0.clone()
-    }
 }
 
 impl<A: UnicastAddress> Deref for UnicastAddr<A> {
@@ -308,6 +322,30 @@
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
 pub struct MulticastAddr<A>(A);
 
+impl<A: MulticastAddress> sealed::Sealed for MulticastAddr<A> {}
+impl<A: MulticastAddress> Witness<A> for MulticastAddr<A> {
+    #[inline]
+    fn new(addr: A) -> Option<MulticastAddr<A>> {
+        if !addr.is_multicast() {
+            return None;
+        }
+        Some(MulticastAddr(addr))
+    }
+
+    #[inline]
+    fn get(&self) -> A
+    where
+        A: Clone,
+    {
+        self.0.clone()
+    }
+
+    #[inline]
+    fn into_addr(self) -> A {
+        self.0
+    }
+}
+
 impl<A> MulticastAddr<A> {
     /// Construct a new `MulticastAddr` without checking to see if `addr` is
     /// actually a multicast address.
@@ -321,12 +359,6 @@
     pub const unsafe fn new_unchecked(addr: A) -> MulticastAddr<A> {
         MulticastAddr(addr)
     }
-
-    /// Consumes this `MulticastAddr` and returns the contained `A`.
-    #[inline]
-    pub fn into_addr(self) -> A {
-        self.0
-    }
 }
 
 impl<A: SpecifiedAddress> MulticastAddr<A> {
@@ -341,28 +373,6 @@
     }
 }
 
-impl<A: MulticastAddress> MulticastAddr<A> {
-    /// Constructs a new `MulticastAddr`.
-    ///
-    /// `new` returns `None` if `addr` is not a multicast address according to
-    /// [`MulticastAddress::is_multicast`].
-    #[inline]
-    pub fn new(addr: A) -> Option<MulticastAddr<A>> {
-        if !addr.is_multicast() {
-            return None;
-        }
-        Some(MulticastAddr(addr))
-    }
-}
-
-impl<A: Clone> MulticastAddr<A> {
-    /// Get a clone of the address.
-    #[inline]
-    pub fn get(&self) -> A {
-        self.0.clone()
-    }
-}
-
 impl<A: MulticastAddress> Deref for MulticastAddr<A> {
     type Target = A;
 
@@ -394,6 +404,30 @@
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
 pub struct LinkLocalAddr<A>(A);
 
+impl<A: LinkLocalAddress> sealed::Sealed for LinkLocalAddr<A> {}
+impl<A: LinkLocalAddress> Witness<A> for LinkLocalAddr<A> {
+    #[inline]
+    fn new(addr: A) -> Option<LinkLocalAddr<A>> {
+        if !addr.is_linklocal() {
+            return None;
+        }
+        Some(LinkLocalAddr(addr))
+    }
+
+    #[inline]
+    fn get(&self) -> A
+    where
+        A: Clone,
+    {
+        self.0.clone()
+    }
+
+    #[inline]
+    fn into_addr(self) -> A {
+        self.0
+    }
+}
+
 impl<A> LinkLocalAddr<A> {
     /// Construct a new `LinkLocalAddr` without checking to see if `addr` is
     /// actually a link-local address.
@@ -407,12 +441,6 @@
     pub const unsafe fn new_unchecked(addr: A) -> LinkLocalAddr<A> {
         LinkLocalAddr(addr)
     }
-
-    /// Consumes this `LinkLocalAddr` and returns the contained `A`.
-    #[inline]
-    pub fn into_addr(self) -> A {
-        self.0
-    }
 }
 
 impl<A: SpecifiedAddress> LinkLocalAddr<A> {
@@ -427,28 +455,6 @@
     }
 }
 
-impl<A: LinkLocalAddress> LinkLocalAddr<A> {
-    /// Constructs a new `LinkLocalAddr`.
-    ///
-    /// `new` returns `None` if `addr` is not a link-local address according to
-    /// [`LinkLocalAddress::is_linklocal`].
-    #[inline]
-    pub fn new(addr: A) -> Option<LinkLocalAddr<A>> {
-        if !addr.is_linklocal() {
-            return None;
-        }
-        Some(LinkLocalAddr(addr))
-    }
-}
-
-impl<A: Clone> LinkLocalAddr<A> {
-    /// Get a clone of the address.
-    #[inline]
-    pub fn get(&self) -> A {
-        self.0.clone()
-    }
-}
-
 impl<A: LinkLocalAddress> Deref for LinkLocalAddr<A> {
     type Target = A;
 
diff --git a/src/connectivity/network/netstack3/core/src/device/ethernet.rs b/src/connectivity/network/netstack3/core/src/device/ethernet.rs
index 958b244..aca86b0 100644
--- a/src/connectivity/network/netstack3/core/src/device/ethernet.rs
+++ b/src/connectivity/network/netstack3/core/src/device/ethernet.rs
@@ -13,7 +13,8 @@
 use net_types::ethernet::Mac;
 use net_types::ip::{AddrSubnet, Ip, IpAddr, IpAddress, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
 use net_types::{
-    BroadcastAddress, LinkLocalAddr, MulticastAddr, MulticastAddress, SpecifiedAddr, UnicastAddress,
+    BroadcastAddress, LinkLocalAddr, MulticastAddr, MulticastAddress, SpecifiedAddr,
+    UnicastAddress, Witness,
 };
 use packet::{Buf, BufferMut, EmptyBuf, Nested, Serializer};
 use specialize_ip_macro::{specialize_ip, specialize_ip_address};
diff --git a/src/connectivity/network/netstack3/core/src/device/mod.rs b/src/connectivity/network/netstack3/core/src/device/mod.rs
index cb3bc68..5667f7e 100644
--- a/src/connectivity/network/netstack3/core/src/device/mod.rs
+++ b/src/connectivity/network/netstack3/core/src/device/mod.rs
@@ -14,7 +14,7 @@
 use log::{debug, trace};
 use net_types::ethernet::Mac;
 use net_types::ip::{AddrSubnet, Ip, IpAddress, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
-use net_types::{LinkLocalAddr, MulticastAddr, SpecifiedAddr};
+use net_types::{LinkLocalAddr, MulticastAddr, SpecifiedAddr, Witness};
 use packet::{BufferMut, Serializer};
 use specialize_ip_macro::specialize_ip;
 
diff --git a/src/connectivity/network/netstack3/core/src/device/ndp.rs b/src/connectivity/network/netstack3/core/src/device/ndp.rs
index f59d752b..6de1ee0 100644
--- a/src/connectivity/network/netstack3/core/src/device/ndp.rs
+++ b/src/connectivity/network/netstack3/core/src/device/ndp.rs
@@ -29,7 +29,7 @@
 use net_types::ip::{AddrSubnet, Ip, Ipv6, Ipv6Addr};
 use net_types::{
     LinkLocalAddr, LinkLocalAddress, MulticastAddr, MulticastAddress, SpecifiedAddr,
-    SpecifiedAddress,
+    SpecifiedAddress, Witness,
 };
 use packet::{EmptyBuf, InnerPacketBuilder, Serializer};
 use rand::{thread_rng, Rng};
diff --git a/src/connectivity/network/netstack3/core/src/ip/icmp.rs b/src/connectivity/network/netstack3/core/src/ip/icmp.rs
index 8c92cc1..a1907d4 100644
--- a/src/connectivity/network/netstack3/core/src/ip/icmp.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/icmp.rs
@@ -7,7 +7,7 @@
 use byteorder::{ByteOrder, NetworkEndian};
 use log::{debug, trace};
 use net_types::ip::{Ip, IpAddress, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
-use net_types::{MulticastAddress, SpecifiedAddr};
+use net_types::{MulticastAddress, SpecifiedAddr, Witness};
 use packet::{BufferMut, Serializer, TruncateDirection, TruncatingSerializer};
 use specialize_ip_macro::specialize_ip_address;
 
diff --git a/src/connectivity/network/netstack3/core/src/ip/igmp.rs b/src/connectivity/network/netstack3/core/src/ip/igmp.rs
index f82390c..2ee5c5c 100644
--- a/src/connectivity/network/netstack3/core/src/ip/igmp.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/igmp.rs
@@ -14,7 +14,7 @@
 use failure::Fail;
 use log::{debug, error};
 use net_types::ip::{AddrSubnet, Ipv4Addr};
-use net_types::{MulticastAddr, SpecifiedAddr, SpecifiedAddress};
+use net_types::{MulticastAddr, SpecifiedAddr, SpecifiedAddress, Witness};
 use packet::{BufferMut, EmptyBuf, InnerPacketBuilder};
 use rand::Rng;
 use rand_xorshift::XorShiftRng;
diff --git a/src/connectivity/network/netstack3/core/src/ip/mld.rs b/src/connectivity/network/netstack3/core/src/ip/mld.rs
index 39f8801..adf7db0 100644
--- a/src/connectivity/network/netstack3/core/src/ip/mld.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/mld.rs
@@ -14,7 +14,7 @@
 use failure::Fail;
 use log::{debug, error};
 use net_types::ip::{Ip, Ipv6, Ipv6Addr};
-use net_types::{LinkLocalAddr, MulticastAddr, SpecifiedAddr, SpecifiedAddress};
+use net_types::{LinkLocalAddr, MulticastAddr, SpecifiedAddr, SpecifiedAddress, Witness};
 use packet::serialize::Serializer;
 use packet::{EmptyBuf, InnerPacketBuilder};
 use rand::Rng;
diff --git a/src/connectivity/network/netstack3/core/src/ip/mod.rs b/src/connectivity/network/netstack3/core/src/ip/mod.rs
index 22ffec3..82f8539 100644
--- a/src/connectivity/network/netstack3/core/src/ip/mod.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/mod.rs
@@ -24,7 +24,7 @@
 
 use log::{debug, trace};
 use net_types::ip::{AddrSubnet, Ip, IpAddress, IpVersion, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Subnet};
-use net_types::{LinkLocalAddr, MulticastAddr, SpecifiedAddr};
+use net_types::{LinkLocalAddr, MulticastAddr, SpecifiedAddr, Witness};
 use packet::{Buf, BufferMut, Either, EmptyBuf, ParseMetadata, Serializer};
 use specialize_ip_macro::{specialize_ip, specialize_ip_address};
 
diff --git a/src/connectivity/network/netstack3/core/src/ip/path_mtu.rs b/src/connectivity/network/netstack3/core/src/ip/path_mtu.rs
index fdddf4f..1b4de6d 100644
--- a/src/connectivity/network/netstack3/core/src/ip/path_mtu.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/path_mtu.rs
@@ -406,7 +406,7 @@
     use super::*;
 
     use net_types::ip::{Ipv4, Ipv6};
-    use net_types::SpecifiedAddr;
+    use net_types::{SpecifiedAddr, Witness};
     use specialize_ip_macro::specialize_ip_address;
 
     use crate::testutil::{
diff --git a/src/connectivity/network/netstack3/core/src/ip/reassembly.rs b/src/connectivity/network/netstack3/core/src/ip/reassembly.rs
index 2e765ed..c561f84 100644
--- a/src/connectivity/network/netstack3/core/src/ip/reassembly.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/reassembly.rs
@@ -722,6 +722,7 @@
 #[cfg(test)]
 mod tests {
     use net_types::ip::{IpAddress, Ipv4, Ipv6};
+    use net_types::Witness;
     use packet::{Buf, ParseBuffer, Serializer};
     use specialize_ip_macro::specialize_ip;
 
diff --git a/src/connectivity/network/netstack3/core/src/ip/types.rs b/src/connectivity/network/netstack3/core/src/ip/types.rs
index a89cb94..d416f7f 100644
--- a/src/connectivity/network/netstack3/core/src/ip/types.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/types.rs
@@ -367,6 +367,8 @@
 
 #[cfg(test)]
 mod tests {
+    use net_types::Witness;
+
     use super::*;
 
     #[test]
diff --git a/src/connectivity/network/netstack3/core/src/testutil.rs b/src/connectivity/network/netstack3/core/src/testutil.rs
index 4632cda..46b69c95 100644
--- a/src/connectivity/network/netstack3/core/src/testutil.rs
+++ b/src/connectivity/network/netstack3/core/src/testutil.rs
@@ -16,7 +16,7 @@
 use log::{debug, trace};
 use net_types::ethernet::Mac;
 use net_types::ip::{AddrSubnet, Ip, IpAddr, IpAddress, Ipv4Addr, Ipv6Addr, Subnet, SubnetEither};
-use net_types::SpecifiedAddr;
+use net_types::{SpecifiedAddr, Witness};
 use packet::{Buf, BufferMut, ParsablePacket, ParseBuffer, Serializer};
 use rand::{self, CryptoRng, RngCore, SeedableRng};
 use rand_xorshift::XorShiftRng;
diff --git a/src/connectivity/network/netstack3/core/src/transport/udp.rs b/src/connectivity/network/netstack3/core/src/transport/udp.rs
index 0491c25..2be5b30 100644
--- a/src/connectivity/network/netstack3/core/src/transport/udp.rs
+++ b/src/connectivity/network/netstack3/core/src/transport/udp.rs
@@ -7,7 +7,7 @@
 use std::num::NonZeroU16;
 
 use net_types::ip::{Ip, IpAddress};
-use net_types::SpecifiedAddr;
+use net_types::{SpecifiedAddr, Witness};
 use packet::{BufferMut, ParsablePacket, Serializer};
 use specialize_ip_macro::specialize_ip;
 use zerocopy::ByteSlice;
diff --git a/src/connectivity/network/netstack3/core/src/wire/icmp/mld.rs b/src/connectivity/network/netstack3/core/src/wire/icmp/mld.rs
index 00274c6..a63bf6f 100644
--- a/src/connectivity/network/netstack3/core/src/wire/icmp/mld.rs
+++ b/src/connectivity/network/netstack3/core/src/wire/icmp/mld.rs
@@ -240,6 +240,7 @@
 
 #[cfg(test)]
 mod tests {
+    use net_types::Witness;
     use packet::{InnerPacketBuilder, ParseBuffer, Serializer};
     use std::convert::TryInto;
     use std::fmt::Debug;
diff --git a/src/connectivity/network/netstack3/src/eventloop/integration_tests.rs b/src/connectivity/network/netstack3/src/eventloop/integration_tests.rs
index c54c255..8415886 100644
--- a/src/connectivity/network/netstack3/src/eventloop/integration_tests.rs
+++ b/src/connectivity/network/netstack3/src/eventloop/integration_tests.rs
@@ -11,7 +11,7 @@
 use fuchsia_component::client;
 use futures::{future, Future, FutureExt, StreamExt};
 use net_types::ip::{AddrSubnetEither, IpAddr, Ipv4, Ipv4Addr};
-use net_types::SpecifiedAddr;
+use net_types::{SpecifiedAddr, Witness};
 use netstack3_core::icmp::{self as core_icmp, IcmpConnId};
 use packet::Buf;
 use pin_utils::pin_mut;
diff --git a/src/connectivity/network/netstack3/src/eventloop/util.rs b/src/connectivity/network/netstack3/src/eventloop/util.rs
index a21b388..3891ad0 100644
--- a/src/connectivity/network/netstack3/src/eventloop/util.rs
+++ b/src/connectivity/network/netstack3/src/eventloop/util.rs
@@ -5,7 +5,7 @@
 use fidl_fuchsia_net as fidl_net;
 use fidl_fuchsia_net_stack as fidl_net_stack;
 use net_types::ip::{AddrSubnetEither, IpAddr, Ipv4Addr, Ipv6Addr, SubnetEither};
-use net_types::SpecifiedAddr;
+use net_types::{SpecifiedAddr, Witness};
 use netstack3_core::{Context, DeviceId, EntryDest, EntryDestEither, EntryEither};
 use never::Never;
 use std::convert::TryFrom;