shill: Device: Release lease if using static IP

If we are using a statically configured IP address instead
of a leased IP address, release any acquired lease so it may
be used by others.  This allows us to merge other non-leased
parameters (like DNS) when they're available from a DHCP server
and not overridden by static parameters, but at the same time
we avoid taking up a dynamic IP address the DHCP server could
assign to someone else who might actually use it.

The only downside to this approach is that we will no longer
perform lease renewals via the DHCP client, so if other parameters
of the lease (default gateway, DNS servers) change while we are
connected, they will not automatically refresh at the client.

BUG=chromium:249399
TEST=Unit tests + network_DhcpNegotiationSuccess autotest + manual:
tcpdump eth0 while connecting to a network with a static IP address.
Ensure lease is acquired, then released, and the device is using the
statically-configured address.  Without a static IP configuration,
ensure that the lease is retained and the host uses the DHCP supplied
address.

Change-Id: Ifdc1a1b9f2e55bead3bc2ed6e58b0fcac91bcbcd
Reviewed-on: https://gerrit.chromium.org/gerrit/58592
Commit-Queue: Paul Stewart <pstew@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
Reviewed-by: Christopher Wiley <wiley@chromium.org>
diff --git a/dhcp_config_unittest.cc b/dhcp_config_unittest.cc
index ec9dafd..4b45138 100644
--- a/dhcp_config_unittest.cc
+++ b/dhcp_config_unittest.cc
@@ -445,7 +445,7 @@
   config_->arp_gateway_ = false;
   EXPECT_CALL(*proxy_, Release(kDeviceName)).Times(1);
   config_->proxy_.reset(proxy_.release());
-  EXPECT_TRUE(config_->ReleaseIP());
+  EXPECT_TRUE(config_->ReleaseIP(IPConfig::kReleaseReasonDisconnect));
   config_->pid_ = 0;
 }
 
@@ -454,7 +454,31 @@
   config_->arp_gateway_ = true;
   EXPECT_CALL(*proxy_, Release(kDeviceName)).Times(0);
   config_->proxy_.reset(proxy_.release());
-  EXPECT_TRUE(config_->ReleaseIP());
+  EXPECT_TRUE(config_->ReleaseIP(IPConfig::kReleaseReasonDisconnect));
+  config_->pid_ = 0;
+}
+
+TEST_F(DHCPConfigTest, ReleaseIPStaticIPWithLease) {
+  config_->pid_ = 1 << 18;  // Ensure unknown positive PID.
+  config_->arp_gateway_ = true;
+  config_->is_lease_active_ = true;
+  EXPECT_CALL(*proxy_, Release(kDeviceName));
+  config_->proxy_.reset(proxy_.release());
+  EXPECT_TRUE(config_->ReleaseIP(IPConfig::kReleaseReasonStaticIP));
+  EXPECT_EQ(NULL, config_->proxy_.get());
+  config_->pid_ = 0;
+}
+
+TEST_F(DHCPConfigTest, ReleaseIPStaticIPWithoutLease) {
+  config_->pid_ = 1 << 18;  // Ensure unknown positive PID.
+  config_->arp_gateway_ = true;
+  config_->is_lease_active_ = false;
+  EXPECT_CALL(*proxy_, Release(kDeviceName)).Times(0);
+  MockDHCPProxy *proxy_pointer = proxy_.get();
+  config_->proxy_.reset(proxy_.release());
+  EXPECT_TRUE(config_->ReleaseIP(IPConfig::kReleaseReasonStaticIP));
+  // Expect that proxy has not been released.
+  EXPECT_EQ(proxy_pointer, config_->proxy_.get());
   config_->pid_ = 0;
 }