shill: Add IP Address tracking to DeviceInfo

Subscribe to IP Address messages in DeviceInfo, and create a
per-device list of assigned IP Addresses.  Provide a method
to flush all globally scoped addresses from a device.

As a result, we can now flush assigned IP addresses when a
Connection is terminated.  There is also some incidental cleanup
in RTNLHandler to remove some vestiges of hand-baked RTNL
message encoding.

BUG=chromium-os:19744
TEST=Run new unit tests.  Test using ethernet on a netbook to make sure
addresses are added and removed correctly.

Change-Id: I63fd09088e71c43cb1f11a89a8ef15e11074976c
Reviewed-on: http://gerrit.chromium.org/gerrit/7180
Reviewed-by: Darin Petkov <petkov@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
diff --git a/connection.cc b/connection.cc
index d788020..847ac4d 100644
--- a/connection.cc
+++ b/connection.cc
@@ -4,6 +4,10 @@
 
 #include "shill/connection.h"
 
+#include <arpa/inet.h>
+#include <linux/rtnetlink.h>
+
+#include "shill/device_info.h"
 #include "shill/resolver.h"
 #include "shill/routing_table.h"
 #include "shill/rtnl_handler.h"
@@ -17,10 +21,13 @@
 // static
 const uint32 Connection::kNonDefaultMetric = 10;
 
-Connection::Connection(int interface_index, const std::string& interface_name)
+Connection::Connection(int interface_index,
+                       const std::string& interface_name,
+                       const DeviceInfo *device_info)
     : is_default_(false),
       interface_index_(interface_index),
       interface_name_(interface_name),
+      device_info_(device_info),
       resolver_(Resolver::GetInstance()),
       routing_table_(RoutingTable::GetInstance()),
       rtnl_handler_(RTNLHandler::GetInstance()) {
@@ -28,18 +35,31 @@
 }
 
 Connection::~Connection() {
-  routing_table_->FlushRoutes(interface_index_);
-  // TODO(pstew): Also flush all addresses when DeviceInfo starts tracking them
   VLOG(2) << __func__;
+
+  routing_table_->FlushRoutes(interface_index_);
+  device_info_->FlushAddresses(interface_index_);
 }
 
 void Connection::UpdateFromIPConfig(const IPConfigRefPtr &config) {
   VLOG(2) << __func__;
 
-  // TODO(pstew): Create a centralized resource (perhaps in DeviceInfo?) to
-  // keep apply and keep track of addresses associated with an interface.
-  // Use this instead of directly setting the address over RTNL.
-  rtnl_handler_->AddInterfaceAddress(interface_index_, *config);
+  const IPConfig::Properties &properties = config->properties();
+  IPAddress local(properties.address_family);
+  if (!local.SetAddressFromString(properties.address)) {
+    LOG(ERROR) << "Local address " << properties.address << " is invalid";
+    return;
+  }
+  local.set_prefix(properties.subnet_cidr);
+
+  IPAddress broadcast(properties.address_family);
+  if (!broadcast.SetAddressFromString(properties.broadcast_address)) {
+    LOG(ERROR) << "Broadcast address " << properties.broadcast_address
+               << " is invalid";
+    return;
+  }
+
+  rtnl_handler_->AddInterfaceAddress(interface_index_, local, broadcast);
 
   uint32 metric = is_default_ ? kDefaultMetric : kNonDefaultMetric;
   routing_table_->SetDefaultRoute(interface_index_, config, metric);