shill: ArpClient: Support Request Reception

Refactor the code (specifically the part that sets up BPF filters)
to be able to receive and parse ARP requests.  In doing so, we
will now be able to start an ARP client to monitor the amount of
ambient broadcast ARP traffic on the network.  We can use this to
back down the rate of LinkMonitor requests to reduce loads on
networks with large numbers of Chromebooks.

BUG=chromium:422159
TEST=Unit tests + manual: ff_debug +link; ff_debug --level -4
Make sure ARP responses continue to be received correctly

Change-Id: I4c29919a09537b8be39f414647dd3a4fccc3800b
Reviewed-on: https://chromium-review.googlesource.com/222704
Reviewed-by: Peter Qiu <zqiu@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
Commit-Queue: Paul Stewart <pstew@chromium.org>
diff --git a/arp_packet.cc b/arp_packet.cc
index cf0c129..ae14ac6 100644
--- a/arp_packet.cc
+++ b/arp_packet.cc
@@ -16,7 +16,8 @@
 const size_t ArpPacket::kMinPayloadSize = ETH_ZLEN - ETH_HLEN;
 
 ArpPacket::ArpPacket()
-    : local_ip_address_(IPAddress::kFamilyUnknown),
+    : operation_(0),
+      local_ip_address_(IPAddress::kFamilyUnknown),
       remote_ip_address_(IPAddress::kFamilyUnknown) {}
 
 ArpPacket::ArpPacket(
@@ -49,7 +50,7 @@
 // +-----------------------------------------------------------------------+
 // | Target IP Address (of length "Protocol Length")...                    |
 // +-----------------------------------------------------------------------+
-bool ArpPacket::ParseReply(const ByteString &packet) {
+bool ArpPacket::Parse(const ByteString &packet) {
   arphdr header;
   if (packet.GetLength() < sizeof(header)) {
     LOG(ERROR) << "Packet size " << packet.GetLength()
@@ -89,8 +90,8 @@
     return false;
   }
   const uint16_t operation = ntohs(header.ar_op);
-  if (operation != ARPOP_REPLY) {
-    NOTIMPLEMENTED() << "Packet is not an ARP reply but of type "
+  if (operation != ARPOP_REPLY && operation != ARPOP_REQUEST) {
+    NOTIMPLEMENTED() << "Packet is not an ARP reply or request but of type "
                      << operation;
     return false;
   }
@@ -104,6 +105,7 @@
                      << min_packet_size;
     return false;
   }
+  operation_ = operation;
   local_mac_address_ = packet.GetSubstring(sizeof(header), ETH_ALEN);
   local_ip_address_ = IPAddress(family, packet.GetSubstring(
       sizeof(header) + ETH_ALEN, ip_address_length));
@@ -166,4 +168,8 @@
   return true;
 }
 
+bool ArpPacket::IsReply() const {
+  return operation_ == ARPOP_REPLY;
+}
+
 }  // namespace shill