shill: modem: unregister the cellular device when deleting a modem

Unregister the cellular device so that the chain of refences to the
device are all dropped when the modem disappears.  The references are
from DeviceInfo, Manager, Modem and Service.  Calling deregister
remove the device info reference, and will cause the manager to stop
the device, which will in turn clean up the service.  Deleting the
modem will drop the last reference.

BUG=chromium-os:26796, chromium-os:26300
TEST=run shill, list-devices, stop cromo, list-devices, start cromo,
     /opt/Qualcomm/bin/powercycle-all-gobis

Change-Id: Ia10932cc3c644bbf5accd69e02b85c75dc783b11
Reviewed-on: https://gerrit.chromium.org/gerrit/16546
Commit-Ready: Jason Glasgow <jglasgow@chromium.org>
Reviewed-by: Jason Glasgow <jglasgow@chromium.org>
Tested-by: Jason Glasgow <jglasgow@chromium.org>
diff --git a/device_info.cc b/device_info.cc
index 1f8bd08..3419146 100644
--- a/device_info.cc
+++ b/device_info.cc
@@ -107,6 +107,24 @@
   }
 }
 
+void DeviceInfo::DeregisterDevice(const DeviceRefPtr &device) {
+  int interface_index = device->interface_index();
+
+  VLOG(2) << __func__ << "(" << device->link_name() << ", "
+          << interface_index << ")";
+  CHECK(device->TechnologyIs(Technology::kCellular));
+
+  // Release reference to the device
+  map<int, Info>::iterator iter = infos_.find(interface_index);
+  if (iter != infos_.end()) {
+    VLOG(2) << "Removing device from info for index: " << interface_index;
+    manager_->DeregisterDevice(device);
+    // Release the reference to the device, but maintain the mapping
+    // for the index.  That will be cleaned up by an RTNL message.
+    iter->second.device = NULL;
+  }
+}
+
 Technology::Identifier DeviceInfo::GetDeviceTechnology(
     const string &iface_name) {
   FilePath uevent_file(StringPrintf(kInterfaceUevent, iface_name.c_str()));