shill: Support SIM lock status updates and MmPropertiesChanged.

BUG=chromium-os:19898,19855
TEST=unit tests, tested on device

Change-Id: I8de5c6a1593d394143cc978e99d49e56d0719ee6
Reviewed-on: http://gerrit.chromium.org/gerrit/7781
Tested-by: Darin Petkov <petkov@chromium.org>
Reviewed-by: Eric Shienbrood <ers@chromium.org>
diff --git a/cellular.cc b/cellular.cc
index 8d357eb..6ed7617 100644
--- a/cellular.cc
+++ b/cellular.cc
@@ -965,6 +965,14 @@
   return to_return;
 }
 
+void Cellular::SetGSMAccessTechnology(uint32 access_technology) {
+  CHECK_EQ(kTypeGSM, type_);
+  gsm_.access_technology = access_technology;
+  if (service_.get()) {
+    service_->set_network_tech(GetNetworkTechnologyString());
+  }
+}
+
 StrIntPair Cellular::SimLockStatusToProperty() {
   return StrIntPair(make_pair(flimflam::kSIMLockTypeProperty,
                               sim_lock_status_.lock_type),
diff --git a/cellular.h b/cellular.h
index 2341dc9..900536e 100644
--- a/cellular.h
+++ b/cellular.h
@@ -122,6 +122,9 @@
   struct SimLockStatus {
    public:
     SimLockStatus() : retries_left(0) {}
+    SimLockStatus(const std::string &in_lock_type, uint32 in_retries_left)
+        : lock_type(in_lock_type),
+          retries_left(in_retries_left) {}
 
     std::string lock_type;
     uint32 retries_left;
@@ -154,6 +157,11 @@
   void set_modem_state(ModemState state) { modem_state_ = state; }
   ModemState modem_state() const { return modem_state_; }
 
+  const SimLockStatus &sim_lock_status() const { return sim_lock_status_; }
+  void set_sim_lock_status(const SimLockStatus &s) { sim_lock_status_ = s; }
+
+  void SetGSMAccessTechnology(uint32 access_technology);
+
   // Inherited from Device.
   virtual void Start();
   virtual void Stop();
@@ -199,6 +207,7 @@
   FRIEND_TEST(CellularTest, RegisterOnNetworkError);
   FRIEND_TEST(CellularTest, RequirePIN);
   FRIEND_TEST(CellularTest, RequirePINError);
+  FRIEND_TEST(CellularTest, SetGSMAccessTechnology);
   FRIEND_TEST(CellularTest, StartConnected);
   FRIEND_TEST(CellularTest, StartCDMARegister);
   FRIEND_TEST(CellularTest, StartGSMRegister);
@@ -245,8 +254,9 @@
   // to the network-connected state and bring the network interface up.
   void EstablishLink();
 
-  Stringmaps EnumerateNetworks();
   StrIntPair SimLockStatusToProperty();
+
+  Stringmaps EnumerateNetworks();
   void HelpRegisterDerivedStringmaps(const std::string &name,
                                      Stringmaps(Cellular::*get)(void),
                                      bool(Cellular::*set)(const Stringmaps&));
diff --git a/cellular_unittest.cc b/cellular_unittest.cc
index 18b7f8b..e6ea342 100644
--- a/cellular_unittest.cc
+++ b/cellular_unittest.cc
@@ -863,4 +863,17 @@
             device_->service_->error());
 }
 
+TEST_F(CellularTest, SetGSMAccessTechnology) {
+  device_->type_ = Cellular::kTypeGSM;
+  device_->SetGSMAccessTechnology(MM_MODEM_GSM_ACCESS_TECH_GSM);
+  EXPECT_EQ(MM_MODEM_GSM_ACCESS_TECH_GSM, device_->gsm_.access_technology);
+  device_->service_ = new CellularService(
+      &control_interface_, &dispatcher_, &manager_, device_);
+  device_->gsm_.registration_state = MM_MODEM_GSM_NETWORK_REG_STATUS_HOME;
+  device_->SetGSMAccessTechnology(MM_MODEM_GSM_ACCESS_TECH_GPRS);
+  EXPECT_EQ(MM_MODEM_GSM_ACCESS_TECH_GPRS, device_->gsm_.access_technology);
+  EXPECT_EQ(flimflam::kNetworkTechnologyGprs,
+            device_->service_->network_tech());
+}
+
 }  // namespace shill
diff --git a/modem.cc b/modem.cc
index 50aa67c..0d8c45d 100644
--- a/modem.cc
+++ b/modem.cc
@@ -18,6 +18,7 @@
 namespace shill {
 
 // TODO(petkov): Consider generating these in mm/mm-modem.h.
+const char Modem::kPropertyAccessTechnology[] = "AccessTechnology";
 const char Modem::kPropertyLinkName[] = "Device";
 const char Modem::kPropertyIPMethod[] = "IpMethod";
 const char Modem::kPropertyState[] = "State";
@@ -131,7 +132,8 @@
     DBusProperties::GetUint32(properties,
                               kPropertyUnlockRetries,
                               &unlock_retries);
-    // TODO(petkov): Set these properties on the device instance.
+    device_->set_sim_lock_status(
+        Cellular::SimLockStatus(unlock_required, unlock_retries));
   }
 
   manager_->device_info()->RegisterDevice(device_);
@@ -147,8 +149,23 @@
 void Modem::OnModemManagerPropertiesChanged(
     const string &interface,
     const DBusPropertiesMap &properties) {
-  // TODO(petkov): Implement this.
-  NOTIMPLEMENTED();
+  if (!device_.get()) {
+    return;
+  }
+  Cellular::SimLockStatus lock_status = device_->sim_lock_status();
+  if (DBusProperties::GetString(
+          properties, kPropertyUnlockRequired, &lock_status.lock_type) ||
+      DBusProperties::GetUint32(properties,
+                                kPropertyUnlockRetries,
+                                &lock_status.retries_left)) {
+    device_->set_sim_lock_status(lock_status);
+  }
+  uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
+  if (DBusProperties::GetUint32(properties,
+                                kPropertyAccessTechnology,
+                                &access_technology)) {
+    device_->SetGSMAccessTechnology(access_technology);
+  }
 }
 
 }  // namespace shill
diff --git a/modem.h b/modem.h
index 71af22c..ea5c20d 100644
--- a/modem.h
+++ b/modem.h
@@ -47,6 +47,7 @@
   FRIEND_TEST(ModemTest, CreateCellularDevice);
   FRIEND_TEST(ModemTest, Init);
 
+  static const char kPropertyAccessTechnology[];
   static const char kPropertyLinkName[];
   static const char kPropertyIPMethod[];
   static const char kPropertyState[];