shill: Device: Support same-net multi-homing

When two interfaces are connected to the same subnet, two
components of ChromeOS system behavior conspire to produce
surprising results.  First, the default Linux network behavior
induces the "ARP Flux" effect where the system replies to
ARPs interchangably for both interfaces.  Secondly, reverse-
path filtering (setup by default in shill) causes only one
network interface to be able to receive packets for a given
subnet at a time.

This CL adds code to recognize situations where more than
one interface is connected to the same subnet.  In such
situtations reverse-path filtering is disabled and ARP
filtering is enabled.  This requires the driver to keep
track of the requested reverse-path filtering state.

BUG=chromium:430041
TEST=Unit tests + manual:

 (1) Attach both WiFi and Ethernet, but to _different_ IP
     networks (subnet addresses should be different).  Run
     "sysctl -a | egrep '(rp_filter|arp_announce|arp_ignore)'".
     Output should be something like:

	net.ipv4.conf.all.arp_announce = 0
	net.ipv4.conf.all.arp_filter = 0
	net.ipv4.conf.all.arp_ignore = 0
	net.ipv4.conf.all.rp_filter = 1
	net.ipv4.conf.default.arp_announce = 0
	net.ipv4.conf.default.arp_filter = 0
	net.ipv4.conf.default.arp_ignore = 0
	net.ipv4.conf.default.rp_filter = 1
	net.ipv4.conf.eth0.arp_announce = 0
	net.ipv4.conf.eth0.arp_filter = 0
	net.ipv4.conf.eth0.arp_ignore = 0
	net.ipv4.conf.eth0.rp_filter = 1
	net.ipv4.conf.lo.arp_announce = 0
	net.ipv4.conf.lo.arp_filter = 0
	net.ipv4.conf.lo.arp_ignore = 0
	net.ipv4.conf.lo.rp_filter = 1
	net.ipv4.conf.wlan0.arp_announce = 0
	net.ipv4.conf.wlan0.arp_filter = 0
	net.ipv4.conf.wlan0.arp_ignore = 0
	net.ipv4.conf.wlan0.rp_filter = 1

     In other words, rp_filter is enabled on all interfaces,
     and arp_filter / arp_ignore are left as default.

 (2) Attach both WiFi and Ethernet to the same router.  Run
     "sysctl -a | egrep '(rp_filter|arp_announce|arp_ignore)'".
     Output should be something like:

	net.ipv4.conf.all.arp_announce = 0
	net.ipv4.conf.all.arp_filter = 0
	net.ipv4.conf.all.arp_ignore = 0
	net.ipv4.conf.all.rp_filter = 1
	net.ipv4.conf.default.arp_announce = 0
	net.ipv4.conf.default.arp_filter = 0
	net.ipv4.conf.default.arp_ignore = 0
	net.ipv4.conf.default.rp_filter = 1
	net.ipv4.conf.eth0.arp_announce = 2
	net.ipv4.conf.eth0.arp_filter = 0
	net.ipv4.conf.eth0.arp_ignore = 1
	net.ipv4.conf.eth0.rp_filter = 2
	net.ipv4.conf.lo.arp_announce = 0
	net.ipv4.conf.lo.arp_filter = 0
	net.ipv4.conf.lo.arp_ignore = 0
	net.ipv4.conf.lo.rp_filter = 1
	net.ipv4.conf.wlan0.arp_announce = 2
	net.ipv4.conf.wlan0.arp_filter = 0
	net.ipv4.conf.wlan0.arp_ignore = 1
	net.ipv4.conf.wlan0.rp_filter = 2

     In other words, rp_filter is set to "loose mode" on WiFi
     and Ethernet.  arp_filter and arp_ignore are also enabled
     on those interfaces.

Change-Id: Id19e5b7101ba70f94aaa51b3ad6cc163a4bc0005
Reviewed-on: https://chromium-review.googlesource.com/229696
Reviewed-by: Will Drewry <wad@chromium.org>
Commit-Queue: Paul Stewart <pstew@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
diff --git a/manager.h b/manager.h
index 49a506f..87818c9 100644
--- a/manager.h
+++ b/manager.h
@@ -426,6 +426,7 @@
   FRIEND_TEST(ManagerTest, ConnectToBestServices);
   FRIEND_TEST(ManagerTest, CreateConnectivityReport);
   FRIEND_TEST(ManagerTest, DefaultTechnology);
+  FRIEND_TEST(ManagerTest, DetectMultiHomedDevices);
   FRIEND_TEST(ManagerTest, DevicePresenceStatusCheck);
   FRIEND_TEST(ManagerTest, DeviceRegistrationAndStart);
   FRIEND_TEST(ManagerTest, DisableTechnology);
@@ -486,6 +487,10 @@
   bool SetDisableWiFiVHT(const bool &disable_wifi_vht, Error *error);
   bool GetDisableWiFiVHT(Error *error);
 
+  // For every device instance that is sharing the same connectivity with
+  // another device, enable the multi-home flag.
+  void DetectMultiHomedDevices();
+
   // Unload a service while iterating through |services_|.  Returns true if
   // service was erased (which means the caller loop should not increment
   // |service_iterator|), false otherwise (meaning the caller should