net/addr/ether: Add basic queries

Change-Id: Ib7028d7a32905b7dec79f4db4251bafb98a862f7
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/include/stdplus/net/addr/ether.hpp b/include/stdplus/net/addr/ether.hpp
index ef29889..1fc3638 100644
--- a/include/stdplus/net/addr/ether.hpp
+++ b/include/stdplus/net/addr/ether.hpp
@@ -32,6 +32,21 @@
     {
         return *this == static_cast<ether_addr&>(rhs);
     }
+
+    constexpr bool isEmpty() const noexcept
+    {
+        return *this == EtherAddr{};
+    }
+
+    constexpr bool isMulticast() const noexcept
+    {
+        return ether_addr_octet[0] & 1;
+    }
+
+    constexpr bool isUnicast() const noexcept
+    {
+        return !(isEmpty() || isMulticast());
+    }
 };
 
 template <>
diff --git a/test/net/addr/ether.cpp b/test/net/addr/ether.cpp
index 8005906..bf5ec2b 100644
--- a/test/net/addr/ether.cpp
+++ b/test/net/addr/ether.cpp
@@ -15,6 +15,30 @@
     std::hash<EtherAddr>{}(EtherAddr{});
 }
 
+TEST(Query, IsEmpty)
+{
+    EXPECT_TRUE((EtherAddr{}.isEmpty()));
+    EXPECT_FALSE((EtherAddr{1}.isEmpty()));
+    EXPECT_FALSE((EtherAddr{0, 0, 0, 1}.isEmpty()));
+}
+
+TEST(Query, IsMulticast)
+{
+    EXPECT_TRUE((EtherAddr{255, 255, 255, 255, 255, 255}.isMulticast()));
+    EXPECT_TRUE((EtherAddr{1}.isMulticast()));
+    EXPECT_FALSE((EtherAddr{0, 1, 2, 3, 4, 5}.isMulticast()));
+    EXPECT_FALSE((EtherAddr{0xfe, 255, 255, 255, 255, 255}.isMulticast()));
+}
+
+TEST(Query, IsUnicast)
+{
+    EXPECT_TRUE((EtherAddr{0, 1, 2, 3, 4, 5}.isUnicast()));
+    EXPECT_TRUE((EtherAddr{0xfe, 255, 255, 255, 255, 255}.isUnicast()));
+    EXPECT_FALSE((EtherAddr{}.isUnicast()));
+    EXPECT_FALSE((EtherAddr{1}.isUnicast()));
+    EXPECT_FALSE((EtherAddr{255, 255, 255, 255, 255, 255}.isUnicast()));
+}
+
 TEST(ToStr, EthAddr)
 {
     ToStrHandle<ToStr<EtherAddr>> tsh;