shill: Make cellular Connect work for GSM networks.

Add the APN to the properties map passed to Connect.
Set up the list of APNs to try, and step through it when
a connect attempt fails with the InvalidApn error. The
order in which APNs are tried is

  - APN which most recently resulted in a successful
    connection on the current network
  - a user-specified APN, specified by setting the Cellular.APN
    property on the service
  - the list of APNs found for the home network provider in the
    mobile broadband provider database
  - if all those fail, a null APN

BUG=chromium-os:23259
TEST=manual testing, some of which involved modifying the
mobile provider DB to create invalid APN entries. Created
two new unit tests as well, and ran all unit tests.

Change-Id: I38c869228fe1aaf7421de8a826c54e7b62c209b2
Reviewed-on: https://gerrit.chromium.org/gerrit/19122
Tested-by: Eric Shienbrood <ers@chromium.org>
Reviewed-by: Jason Glasgow <jglasgow@chromium.org>
Commit-Ready: Eric Shienbrood <ers@chromium.org>
diff --git a/cellular_service.h b/cellular_service.h
index 8e2a3a1..a502f8a 100644
--- a/cellular_service.h
+++ b/cellular_service.h
@@ -24,6 +24,9 @@
 
 class CellularService : public Service {
  public:
+  static const char kStorageAPN[];
+  static const char kStorageLastGoodAPN[];
+
   // Online payment portal.
   class OLP {
    public:
@@ -88,12 +91,50 @@
   void SetRoamingState(const std::string &state);
   const std::string &roaming_state() const { return roaming_state_; }
 
+  // Overrride Load and Save from parent Service class.  We will call
+  // the parent method.
+  virtual bool Load(StoreInterface *storage);
+  virtual bool Save(StoreInterface *storage);
+
+  Stringmap *GetUserSpecifiedApn();
+  Stringmap *GetLastGoodApn();
+  void SetLastGoodApn(const Stringmap &apn_info);
+  void ClearLastGoodApn();
+
  private:
   friend class CellularServiceTest;
+  FRIEND_TEST(CellularCapabilityGSMTest, SetupApnTryList);
+  FRIEND_TEST(CellularCapabilityTest, TryApns);
   FRIEND_TEST(CellularTest, Connect);
 
+  void HelpRegisterDerivedStringmap(
+      const std::string &name,
+      Stringmap(CellularService::*get)(Error *error),
+      void(CellularService::*set)(const Stringmap &value, Error *error));
+
   virtual std::string GetDeviceRpcId(Error *error);
 
+  Stringmap GetApn(Error *error);
+  void SetApn(const Stringmap &value, Error *error);
+  static void SaveApn(StoreInterface *storage,
+                      const std::string &storage_group,
+                      const Stringmap *apn_info,
+                      const std::string &keytag);
+  static void SaveApnField(StoreInterface *storage,
+                           const std::string &storage_group,
+                           const Stringmap *apn_info,
+                           const std::string &keytag,
+                           const std::string &apntag);
+  static void LoadApn(StoreInterface *storage,
+                      const std::string &storage_group,
+                      const std::string &keytag,
+                      Stringmap *apn_info);
+  static bool LoadApnField(StoreInterface *storage,
+                           const std::string &storage_group,
+                           const std::string &keytag,
+                           const std::string &apntag,
+                           Stringmap *apn_info);
+
   // Properties
   std::string activation_state_;
   Cellular::Operator serving_operator_;
@@ -102,8 +143,8 @@
   OLP olp_;
   std::string usage_url_;
 
-  std::map<std::string, std::string> apn_info_;
-  std::map<std::string, std::string> last_good_apn_info_;
+  Stringmap apn_info_;
+  Stringmap last_good_apn_info_;
 
   std::string storage_identifier_;