shill: don't run dhcpcd and pppd simultaneously, for the same Cellular

Some Cellular dongles expose both a network device (e.g. wwan0),
and a serial interface for ppp. Despite the presence of the network
device, they really want to be used as PPP devices.

Normally, we run dhcpcd on every network device, and terminate the
link if we are unable to acquire a DHCP lease. In the case of PPP
dongles, that causes us to tear down a totally functional link
after about 30 seconds. (The IP address is acquired using PPP
IPCP, and applied to the ppp0, or similar, interface.)

Avoid this problem, by a) not starting dhcpcd if pppd is already
running for the Cellular device, and b) stopping dhcpcd for the
Cellular device (if running), when we start pppd.

BUG=chromium:252516
TEST=new unit tests

Change-Id: I506413655ce44d36b3db0bd8e436340e5f5c20a9
Reviewed-on: https://gerrit.chromium.org/gerrit/60328
Reviewed-by: Ben Chan <benchan@chromium.org>
Commit-Queue: mukesh agrawal <quiche@chromium.org>
Tested-by: mukesh agrawal <quiche@chromium.org>
diff --git a/cellular.cc b/cellular.cc
index 3f31e30..678f75b 100644
--- a/cellular.cc
+++ b/cellular.cc
@@ -640,6 +640,11 @@
 
 void Cellular::LinkEvent(unsigned int flags, unsigned int change) {
   Device::LinkEvent(flags, change);
+  if (ppp_task_) {
+    LOG(INFO) << "Ignoring LinkEvent on device with PPP interface.";
+    return;
+  }
+
   if ((flags & IFF_UP) != 0 && state_ == kStateConnected) {
     LOG(INFO) << link_name() << " is up.";
     SetState(kStateLinked);
@@ -763,6 +768,13 @@
 }
 
 void Cellular::StartPPP(const string &serial_device) {
+  // Some PPP dongles also expose an Ethernet-like network device,
+  // using either cdc_ether, or cdc_ncm. dhcpcd may be running on that
+  // interface. If so, it will eventually time out, and cause us
+  // terminate the cellular connection. Avoid terminating the connection,
+  // by cancelling any such DHCP process.
+  DestroyIPConfig();
+
   base::Callback<void(pid_t, int)> death_callback(
       Bind(&Cellular::OnPPPDied, weak_ptr_factory_.GetWeakPtr()));
   vector<string> args;