Re-land "[shill] Add hardware address to Device objects."

Forgot some headers...

BUG=chromium-os:17744
TEST=unit

This reverts commit 0fda552b0fec3498403336acb9e89dd7799cac74.

Change-Id: I1cd05e47d29bc7ea2a065cabf1d81dd37f74c0f8
Reviewed-on: http://gerrit.chromium.org/gerrit/6270
Reviewed-by: Chris Masone <cmasone@chromium.org>
Tested-by: Chris Masone <cmasone@chromium.org>
diff --git a/cellular.cc b/cellular.cc
index 4618c06..548ac54 100644
--- a/cellular.cc
+++ b/cellular.cc
@@ -102,6 +102,7 @@
                    EventDispatcher *dispatcher,
                    Manager *manager,
                    const string &link_name,
+                   const std::string &address,
                    int interface_index,
                    Type type,
                    const string &owner,
@@ -110,6 +111,7 @@
              dispatcher,
              manager,
              link_name,
+             address,
              interface_index),
       type_(type),
       state_(kStateDisabled),
diff --git a/cellular.h b/cellular.h
index a273d8a..54f1aaa 100644
--- a/cellular.h
+++ b/cellular.h
@@ -119,6 +119,7 @@
            EventDispatcher *dispatcher,
            Manager *manager,
            const std::string &link_name,
+           const std::string &address,
            int interface_index,
            Type type,
            const std::string &owner,
diff --git a/cellular_unittest.cc b/cellular_unittest.cc
index 982430a..df29dba 100644
--- a/cellular_unittest.cc
+++ b/cellular_unittest.cc
@@ -46,6 +46,7 @@
                              NULL,
                              NULL,
                              "usb0",
+                             "00:01:02:03:04:05",
                              3,
                              Cellular::kTypeGSM,
                              "",
@@ -121,6 +122,7 @@
                              &dispatcher_,
                              &manager_,
                              kTestDeviceName,
+                             kTestDeviceAddress,
                              3,
                              Cellular::kTypeGSM,
                              kDBusOwner,
@@ -169,6 +171,7 @@
   };
 
   static const char kTestDeviceName[];
+  static const char kTestDeviceAddress[];
   static const int kTestSocket;
   static const char kDBusOwner[];
   static const char kDBusPath[];
@@ -194,6 +197,7 @@
 };
 
 const char CellularTest::kTestDeviceName[] = "usb0";
+const char CellularTest::kTestDeviceAddress[] = "00:01:02:03:04:05";
 const int CellularTest::kTestSocket = 123;
 const char CellularTest::kDBusOwner[] = ":1.19";
 const char CellularTest::kDBusPath[] = "/org/chromium/ModemManager/Gobi/0";
diff --git a/dbus_adaptor_unittest.cc b/dbus_adaptor_unittest.cc
index 082d9b9..9c14ab0 100644
--- a/dbus_adaptor_unittest.cc
+++ b/dbus_adaptor_unittest.cc
@@ -55,6 +55,7 @@
                                &dispatcher_,
                                &manager_,
                                "mock",
+                               "addr0",
                                0)),
         service_(new MockService(&control_interface_,
                                  &dispatcher_,
diff --git a/device.cc b/device.cc
index 851c922..838f311 100644
--- a/device.cc
+++ b/device.cc
@@ -45,9 +45,11 @@
                EventDispatcher *dispatcher,
                Manager *manager,
                const string &link_name,
+               const string &address,
                int interface_index)
     : powered_(true),
       reconnect_(true),
+      hardware_address_(address),
       interface_index_(interface_index),
       running_(false),
       link_name_(link_name),
@@ -136,6 +138,9 @@
 string Device::GetStorageIdentifier() {
   string id = GetRpcIdentifier();
   ControlInterface::RpcIdToStorageId(&id);
+  size_t needle = id.find('_');
+  LOG_IF(ERROR, needle == string::npos) << "No _ in storage id?!?!";
+  id.replace(id.begin() + needle + 1, id.end(), hardware_address_);
   return id;
 }
 
diff --git a/device.h b/device.h
index 27fee74..7f9fbfb 100644
--- a/device.h
+++ b/device.h
@@ -23,7 +23,6 @@
 class ControlInterface;
 class DHCPProvider;
 class DeviceAdaptorInterface;
-class DeviceInfo;
 class Endpoint;
 class Error;
 class EventDispatcher;
@@ -47,6 +46,7 @@
          EventDispatcher *dispatcher,
          Manager *manager,
          const std::string &link_name,
+         const std::string &address,
          int interface_index);
   virtual ~Device();
 
@@ -109,9 +109,9 @@
                                   bool(Device::*set)(const Strings&));
 
   // Properties
-  std::string hardware_address_;
   bool powered_;  // TODO(pstew): Is this what |running_| is for?
   bool reconnect_;
+  const std::string hardware_address_;
 
   PropertyStore store_;
 
diff --git a/device_info.cc b/device_info.cc
index c6ba786..c7afe61 100644
--- a/device_info.cc
+++ b/device_info.cc
@@ -153,6 +153,9 @@
       infos_[dev_index].address = msg.GetAttribute(IFLA_ADDRESS);
       VLOG(2) << "link index " << dev_index << " address "
               << infos_[dev_index].address.HexEncode();
+    } else {
+      LOG(ERROR) << "Add Link message does not have IFLA_ADDRESS!";
+      return;
     }
     if (!msg.HasAttribute(IFLA_IFNAME)) {
       LOG(ERROR) << "Add Link message does not have IFLA_IFNAME!";
@@ -169,7 +172,7 @@
         technology = GetDeviceTechnology(link_name);
       }
     }
-
+    string address = infos_[dev_index].address.HexEncode();
     switch (technology) {
       case Device::kCellular:
         // Cellular devices are managed by ModemInfo.
@@ -178,15 +181,15 @@
         return;
       case Device::kEthernet:
         device = new Ethernet(control_interface_, dispatcher_, manager_,
-                              link_name, dev_index);
+                              link_name, address, dev_index);
         break;
       case Device::kWifi:
         device = new WiFi(control_interface_, dispatcher_, manager_,
-                          link_name, dev_index);
+                          link_name, address, dev_index);
         break;
       default:
         device = new DeviceStub(control_interface_, dispatcher_, manager_,
-                                link_name, dev_index, technology);
+                                link_name, address, dev_index, technology);
         break;
     }
     RegisterDevice(device);
diff --git a/device_info.h b/device_info.h
index f749669..09271c6 100644
--- a/device_info.h
+++ b/device_info.h
@@ -39,8 +39,8 @@
   void RegisterDevice(const DeviceRefPtr &device);
 
   DeviceRefPtr GetDevice(int interface_index) const;
-  bool GetAddress(int interface_index, ByteString *address) const;
-  bool GetFlags(int interface_index, unsigned int *flags) const;
+  virtual bool GetAddress(int interface_index, ByteString *address) const;
+  virtual bool GetFlags(int interface_index, unsigned int *flags) const;
 
  private:
   friend class DeviceInfoTest;
diff --git a/device_info_unittest.cc b/device_info_unittest.cc
index 3e76418..2001c56 100644
--- a/device_info_unittest.cc
+++ b/device_info_unittest.cc
@@ -76,6 +76,8 @@
                                          IPAddress::kAddressFamilyIPv4);
   message->SetAttribute(static_cast<uint16>(IFLA_IFNAME),
                         ByteString(kTestDeviceName, true));
+  ByteString test_address(kTestAddress, sizeof(kTestAddress));
+  message->SetAttribute(IFLA_ADDRESS, test_address);
   return message;
 }
 
@@ -89,8 +91,6 @@
   scoped_ptr<RTNLMessage> message(BuildMessage(RTNLMessage::kMessageTypeLink,
                                                RTNLMessage::kMessageModeAdd));
   message->set_link_status(RTNLMessage::LinkStatus(0, IFF_LOWER_UP, 0));
-  ByteString test_address(kTestAddress, sizeof(kTestAddress));
-  message->SetAttribute(IFLA_ADDRESS, test_address);
   EXPECT_FALSE(device_info_.GetDevice(kTestDeviceIndex).get());
   SendMessageToDeviceInfo(*message);
   EXPECT_TRUE(device_info_.GetDevice(kTestDeviceIndex).get());
@@ -100,7 +100,7 @@
   ByteString address;
   EXPECT_TRUE(device_info_.GetAddress(kTestDeviceIndex, &address));
   EXPECT_FALSE(address.IsEmpty());
-  EXPECT_TRUE(test_address.Equals(address));
+  EXPECT_TRUE(address.Equals(ByteString(kTestAddress, sizeof(kTestAddress))));
 
   message.reset(BuildMessage(RTNLMessage::kMessageTypeLink,
                              RTNLMessage::kMessageModeAdd));
diff --git a/device_stub.h b/device_stub.h
index 9e45fa0..4775097 100644
--- a/device_stub.h
+++ b/device_stub.h
@@ -29,10 +29,11 @@
   DeviceStub(ControlInterface *control_interface,
              EventDispatcher *dispatcher,
              Manager *manager,
-             const std::string& link_name,
+             const std::string &link_name,
+             const std::string &address,
              int interface_index,
              Technology technology)
-      : Device(control_interface, dispatcher, manager, link_name,
+      : Device(control_interface, dispatcher, manager, link_name, address,
                interface_index),
         technology_(technology) {}
   void Start() {}
diff --git a/device_unittest.cc b/device_unittest.cc
index 8142277..604607e 100644
--- a/device_unittest.cc
+++ b/device_unittest.cc
@@ -35,25 +35,32 @@
 
 namespace shill {
 
-namespace {
-const char kDeviceName[] = "testdevice";
-}  // namespace {}
-
 class DeviceTest : public PropertyStoreTest {
  public:
   DeviceTest()
-      : device_(new Device(&control_interface_, NULL, NULL, kDeviceName, 0)) {
+      : device_(new Device(&control_interface_,
+                           NULL,
+                           NULL,
+                           kDeviceName,
+                           kDeviceAddress,
+                           0)) {
     DHCPProvider::GetInstance()->glib_ = &glib_;
     DHCPProvider::GetInstance()->control_interface_ = &control_interface_;
   }
   virtual ~DeviceTest() {}
 
  protected:
+  static const char kDeviceName[];
+  static const char kDeviceAddress[];
+
   MockGLib glib_;
   MockControl control_interface_;
   DeviceRefPtr device_;
 };
 
+const char DeviceTest::kDeviceName[] = "testdevice";
+const char DeviceTest::kDeviceAddress[] = "address";
+
 TEST_F(DeviceTest, Contains) {
   EXPECT_TRUE(device_->store()->Contains(flimflam::kNameProperty));
   EXPECT_FALSE(device_->store()->Contains(""));
diff --git a/ethernet.cc b/ethernet.cc
index 4cdedc9..9b0b3f4 100644
--- a/ethernet.cc
+++ b/ethernet.cc
@@ -30,11 +30,13 @@
                    EventDispatcher *dispatcher,
                    Manager *manager,
                    const string &link_name,
+                   const std::string &address,
                    int interface_index)
     : Device(control_interface,
              dispatcher,
              manager,
              link_name,
+             address,
              interface_index),
       service_registered_(false),
       service_(new EthernetService(control_interface,
diff --git a/ethernet.h b/ethernet.h
index 9967e1c..c0ea433 100644
--- a/ethernet.h
+++ b/ethernet.h
@@ -19,6 +19,7 @@
            EventDispatcher *dispatcher,
            Manager *manager,
            const std::string& link_name,
+           const std::string &address,
            int interface_index);
   ~Ethernet();
 
diff --git a/manager.h b/manager.h
index 5f6f925..9a4aa47 100644
--- a/manager.h
+++ b/manager.h
@@ -65,8 +65,8 @@
   ServiceRefPtr FindService(const std::string& name);
   std::vector<std::string> EnumerateAvailableServices();
 
-  DeviceInfo *device_info() { return &device_info_; }
-  PropertyStore *store() { return &store_; }
+  virtual DeviceInfo *device_info() { return &device_info_; }
+  virtual PropertyStore *store() { return &store_; }
 
  private:
   friend class ManagerAdaptorInterface;
diff --git a/manager_unittest.cc b/manager_unittest.cc
index 9cc7d5f..2450c86 100644
--- a/manager_unittest.cc
+++ b/manager_unittest.cc
@@ -39,16 +39,19 @@
                                               &dispatcher_,
                                               &manager_,
                                               "null0",
+                                              "addr0",
                                               0)),
         mock_device2_(new NiceMock<MockDevice>(&control_interface_,
                                                &dispatcher_,
                                                &manager_,
                                                "null2",
+                                               "addr2",
                                                2)),
         mock_device3_(new NiceMock<MockDevice>(&control_interface_,
                                                &dispatcher_,
                                                &manager_,
                                                "null3",
+                                               "addr3",
                                                3)) {
   }
   virtual ~ManagerTest() {}
diff --git a/mock_device.cc b/mock_device.cc
index bc69e94..4e5187a 100644
--- a/mock_device.cc
+++ b/mock_device.cc
@@ -23,11 +23,13 @@
                        EventDispatcher *dispatcher,
                        Manager *manager,
                        const std::string &link_name,
+                       const std::string &address,
                        int interface_index)
     : Device(control_interface,
              dispatcher,
              manager,
              link_name,
+             address,
              interface_index) {
   ON_CALL(*this, TechnologyIs(_)).WillByDefault(Return(false));
 }
diff --git a/mock_device.h b/mock_device.h
index 2147bbc..f1205cf 100644
--- a/mock_device.h
+++ b/mock_device.h
@@ -23,6 +23,7 @@
              EventDispatcher *dispatcher,
              Manager *manager,
              const std::string &link_name,
+             const std::string &address,
              int interface_index);
   virtual ~MockDevice();
 
diff --git a/mock_device_info.h b/mock_device_info.h
new file mode 100644
index 0000000..0c36154
--- /dev/null
+++ b/mock_device_info.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHILL_MOCK_DEVICE_INFO_
+#define SHILL_MOCK_DEVICE_INFO_
+
+#include <base/memory/ref_counted.h>
+#include <gmock/gmock.h>
+
+#include "shill/device_info.h"
+
+namespace shill {
+
+class ByteString;
+class ControlInterface;
+class EventDispatcher;
+class Manager;
+
+class MockDeviceInfo : public DeviceInfo {
+ public:
+  MockDeviceInfo(ControlInterface *control_interface,
+                 EventDispatcher *dispatcher,
+                 Manager *manager)
+      : DeviceInfo(control_interface, dispatcher, manager) {
+  }
+  ~MockDeviceInfo() {}
+
+  MOCK_CONST_METHOD2(GetAddress, bool(int, ByteString*));
+  MOCK_CONST_METHOD2(GetFlags, bool(int, unsigned int*));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockDeviceInfo);
+};
+
+}  // namespace shill
+
+#endif  // SHILL_MOCK_DEVICE_INFO_
diff --git a/mock_manager.h b/mock_manager.h
new file mode 100644
index 0000000..6ebe043
--- /dev/null
+++ b/mock_manager.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHILL_MOCK_MANAGER_
+#define SHILL_MOCK_MANAGER_
+
+#include <base/memory/ref_counted.h>
+#include <gmock/gmock.h>
+
+#include "shill/manager.h"
+
+namespace shill {
+
+class ControlInterface;
+class DeviceInfo;
+class EventDispatcher;
+class GLib;
+class PropertyStore;
+
+class MockManager : public Manager {
+ public:
+  MockManager(ControlInterface *control_interface,
+              EventDispatcher *dispatcher,
+              GLib *glib)
+      : Manager(control_interface, dispatcher, glib) {
+  }
+  ~MockManager() {}
+
+  MOCK_METHOD0(device_info, DeviceInfo*(void));
+  MOCK_METHOD0(store, PropertyStore*(void));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockManager);
+};
+
+}  // namespace shill
+
+#endif  // SHILL_MOCK_MANAGER_
diff --git a/modem.cc b/modem.cc
index 58cab52..4f38518 100644
--- a/modem.cc
+++ b/modem.cc
@@ -84,6 +84,14 @@
     return;
   }
 
+  ByteString address_bytes;
+  if (!manager_->device_info()->GetAddress(interface_index, &address_bytes)) {
+    // TODO(petkov): ensure that DeviceInfo has heard about this device before
+    //               we go ahead and try to add it.
+    LOG(ERROR) << "Unable to create cellular device without a hardware addr.";
+    return;
+  }
+
   uint32 mm_type = kuint32max;
   Cellular::Type type;
   DBusProperties::GetUint32(properties, kPropertyType, &mm_type);
@@ -105,6 +113,7 @@
                          dispatcher_,
                          manager_,
                          link_name,
+                         address_bytes.HexEncode(),
                          interface_index,
                          type,
                          owner_,
diff --git a/modem_unittest.cc b/modem_unittest.cc
index fb0b217..781c052 100644
--- a/modem_unittest.cc
+++ b/modem_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <vector>
 
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <mm/mm-modem.h>
 #include <net/if.h>
@@ -12,8 +13,10 @@
 #include "shill/cellular.h"
 #include "shill/manager.h"
 #include "shill/mock_control.h"
+#include "shill/mock_device_info.h"
 #include "shill/mock_dbus_properties_proxy.h"
 #include "shill/mock_glib.h"
+#include "shill/mock_manager.h"
 #include "shill/mock_sockets.h"
 #include "shill/modem.h"
 #include "shill/proxy_factory.h"
@@ -25,6 +28,7 @@
 using testing::_;
 using testing::DoAll;
 using testing::Return;
+using testing::SetArgumentPointee;
 using testing::StrictMock;
 using testing::Test;
 
@@ -79,7 +83,7 @@
   MockGLib glib_;
   MockControl control_interface_;
   EventDispatcher dispatcher_;
-  Manager manager_;
+  MockManager manager_;
   scoped_ptr<MockDBusPropertiesProxy> proxy_;
   TestProxyFactory proxy_factory_;
   Modem modem_;
@@ -133,6 +137,7 @@
   EXPECT_FALSE(modem_.device_.get());
 
   static const char kLinkName[] = "usb0";
+  static const unsigned char kAddress[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
   const int kTestSocket = 10;
   props[Modem::kPropertyLinkName].writer().append_string(kLinkName);
   EXPECT_CALL(sockets_, Socket(PF_INET, SOCK_DGRAM, 0))
@@ -142,6 +147,14 @@
       .WillRepeatedly(DoAll(SetInterfaceIndex(), Return(0)));
   EXPECT_CALL(sockets_, Close(kTestSocket))
       .WillRepeatedly(Return(0));
+
+  ByteString expected_address(kAddress, arraysize(kAddress));
+  MockDeviceInfo info_(&control_interface_, &dispatcher_, &manager_);
+  EXPECT_CALL(info_, GetAddress(kTestInterfaceIndex, _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(expected_address), Return(true)))
+      .WillOnce(DoAll(SetArgumentPointee<1>(expected_address), Return(true)));
+  EXPECT_CALL(manager_, device_info()).WillRepeatedly(Return(&info_));
+
   modem_.CreateCellularDevice(props);
   EXPECT_FALSE(modem_.device_.get());
 
diff --git a/wifi.cc b/wifi.cc
index 6db73ab..ca88281 100644
--- a/wifi.cc
+++ b/wifi.cc
@@ -44,11 +44,13 @@
            EventDispatcher *dispatcher,
            Manager *manager,
            const string& link,
+           const std::string &address,
            int interface_index)
     : Device(control_interface,
              dispatcher,
              manager,
              link,
+             address,
              interface_index),
       task_factory_(this),
       bgscan_short_interval_(0),
diff --git a/wifi.h b/wifi.h
index 86969da..8a35e95 100644
--- a/wifi.h
+++ b/wifi.h
@@ -27,7 +27,8 @@
   WiFi(ControlInterface *control_interface,
        EventDispatcher *dispatcher,
        Manager *manager,
-       const std::string& link,
+       const std::string &link,
+       const std::string &address,
        int interface_index);
   virtual ~WiFi();
   virtual void Start();
diff --git a/wifi_unittest.cc b/wifi_unittest.cc
index 18039e5..78a49cc 100644
--- a/wifi_unittest.cc
+++ b/wifi_unittest.cc
@@ -44,7 +44,7 @@
 class WiFiPropertyTest : public PropertyStoreTest {
  public:
   WiFiPropertyTest()
-      : device_(new WiFi(&control_interface_, NULL, NULL, "wifi", 0)) {
+      : device_(new WiFi(&control_interface_, NULL, NULL, "wifi", "", 0)) {
   }
   virtual ~WiFiPropertyTest() {}
 
@@ -95,7 +95,12 @@
  public:
   WiFiMainTest()
       : manager_(&control_interface_, NULL, NULL),
-        wifi_(new WiFi(&control_interface_, NULL, &manager_, kDeviceName, 0)),
+        wifi_(new WiFi(&control_interface_,
+                       NULL,
+                       &manager_,
+                       kDeviceName,
+                       kDeviceAddress,
+                       0)),
         supplicant_process_proxy_(new NiceMock<MockSupplicantProcessProxy>()),
         supplicant_interface_proxy_(
             new NiceMock<MockSupplicantInterfaceProxy>(wifi_)),
@@ -173,6 +178,7 @@
   // initialization order
  protected:
   static const char kDeviceName[];
+  static const char kDeviceAddress[];
   static const char kNetworkModeAdHoc[];
   static const char kNetworkModeInfrastructure[];
 
@@ -185,6 +191,7 @@
 };
 
 const char WiFiMainTest::kDeviceName[] = "wlan0";
+const char WiFiMainTest::kDeviceAddress[] = "00:01:02:03:04:05";
 const char WiFiMainTest::kNetworkModeAdHoc[] = "ad-hoc";
 const char WiFiMainTest::kNetworkModeInfrastructure[] = "infrastructure";