[MM][PATCH] modem: add support for 3GPP Vendor PCO info

ori inbar ori.inbar.altair.semi.com at gmail.com
Mon Jul 1 22:27:12 PDT 2013


From: ori inbar <ori.inbar at altair-semi.com>

Change-Id: I139802238868e9743390906c1cfc77fef9179599
---
 ...g.freedesktop.ModemManager1.Modem.Modem3gpp.xml |  17 +++
 libmm-glib/mm-simple-status.c                      |  26 +++-
 libmm-glib/mm-simple-status.h                      |   1 +
 src/mm-broadband-bearer.c                          |  10 ++
 src/mm-iface-modem-3gpp.c                          | 145 +++++++++++++++++++--
 src/mm-iface-modem-3gpp.h                          |  18 +++
 6 files changed, 206 insertions(+), 11 deletions(-)

diff --git a/introspection/org.freedesktop.ModemManager1.Modem.Modem3gpp.xml b/introspection/org.freedesktop.ModemManager1.Modem.Modem3gpp.xml
index 83e1499..14b5e02 100644
--- a/introspection/org.freedesktop.ModemManager1.Modem.Modem3gpp.xml
+++ b/introspection/org.freedesktop.ModemManager1.Modem.Modem3gpp.xml
@@ -136,5 +136,22 @@
     -->
     <property name="EnabledFacilityLocks" type="u" access="read" />
 
+    <!--
+        VendorPcoInfo
+
+        Vendor-specific protocol configuration option (PCO) info received from the LTE
+        mobile network to which the mobile is currently registered (see 3GPP TS 24.008
+        Section 10.5.6.3).
+
+        Returned in the format <literal>"PCOIdPCOPayload"</literal>, where
+        <literal>PCOId</literal> is the 4-digit hex-encoded string of PCO ID and
+        <literal>PCOPayload</literal> is the hex-encoded string of the PCO payload data,
+        e.g. <literal>"FF003114800"</literal>.
+
+        If the <literal>PCOId</literal> and <literal>PCOPayload</literal> are not known
+        or the mobile is not registered to a mobile network, this property will
+        be a zero-length (blank) string.
+    -->
+    <property name="VendorPcoInfo" type="s" access="read" />
   </interface>
 </node>
diff --git a/libmm-glib/mm-simple-status.c b/libmm-glib/mm-simple-status.c
index 10dfee3..0560a34 100644
--- a/libmm-glib/mm-simple-status.c
+++ b/libmm-glib/mm-simple-status.c
@@ -44,6 +44,7 @@ enum {
     PROP_3GPP_REGISTRATION_STATE,
     PROP_3GPP_OPERATOR_CODE,
     PROP_3GPP_OPERATOR_NAME,
+    PROP_3GPP_VENDOR_PCO_INFO,
     PROP_CDMA_CDMA1X_REGISTRATION_STATE,
     PROP_CDMA_EVDO_REGISTRATION_STATE,
     PROP_CDMA_SID,
@@ -72,6 +73,8 @@ struct _MMSimpleStatusPrivate {
     gchar *modem_3gpp_operator_code;
     /* 3GPP operator name, given only when registered, signature 's' */
     gchar *modem_3gpp_operator_name;
+    /* 3GPP LTE vendor PCO info, given only when registered, signature 's' */
+    gchar *modem_3gpp_vendor_pco_info;
 
     /* <--- From the Modem CDMA interface ---> */
     /* CDMA/CDMA1x registration state, signature 'u' */
@@ -350,6 +353,11 @@ mm_simple_status_get_dictionary (MMSimpleStatus *self)
                                    "{sv}",
                                    MM_SIMPLE_PROPERTY_3GPP_OPERATOR_NAME,
                                    g_variant_new_string (self->priv->modem_3gpp_operator_name));
+        if (self->priv->modem_3gpp_vendor_pco_info)
+            g_variant_builder_add (&builder,
+                                   "{sv}",
+                                   MM_SIMPLE_PROPERTY_3GPP_VENDOR_PCO_INFO,
+                                   g_variant_new_string (self->priv->modem_3gpp_vendor_pco_info));
 
         if (self->priv->modem_cdma_cdma1x_registration_state != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) {
             g_variant_builder_add (&builder,
@@ -423,7 +431,8 @@ mm_simple_status_new_from_dictionary (GVariant *dictionary,
                           key, g_variant_get_uint32 (value),
                           NULL);
         } else if (g_str_equal (key, MM_SIMPLE_PROPERTY_3GPP_OPERATOR_CODE) ||
-                   g_str_equal (key, MM_SIMPLE_PROPERTY_3GPP_OPERATOR_NAME)) {
+                   g_str_equal (key, MM_SIMPLE_PROPERTY_3GPP_OPERATOR_NAME) ||
+                   g_str_equal (key, MM_SIMPLE_PROPERTY_3GPP_VENDOR_PCO_INFO)) {
             /* string properties */
             g_object_set (properties,
                           key, g_variant_get_string (value, NULL),
@@ -501,6 +510,10 @@ set_property (GObject *object,
         g_free (self->priv->modem_3gpp_operator_code);
         self->priv->modem_3gpp_operator_code = g_value_dup_string (value);
         break;
+    case PROP_3GPP_VENDOR_PCO_INFO:
+        g_free (self->priv->modem_3gpp_vendor_pco_info);
+        self->priv->modem_3gpp_vendor_pco_info = g_value_dup_string (value);
+        break;
     case PROP_3GPP_OPERATOR_NAME:
         g_free (self->priv->modem_3gpp_operator_name);
         self->priv->modem_3gpp_operator_name = g_value_dup_string (value);
@@ -553,6 +566,9 @@ get_property (GObject *object,
     case PROP_3GPP_OPERATOR_NAME:
         g_value_set_string (value, self->priv->modem_3gpp_operator_name);
         break;
+    case PROP_3GPP_VENDOR_PCO_INFO:
+        g_value_set_string (value, self->priv->modem_3gpp_vendor_pco_info);
+        break;
     case PROP_CDMA_CDMA1X_REGISTRATION_STATE:
         g_value_set_enum (value, self->priv->modem_cdma_cdma1x_registration_state);
         break;
@@ -678,6 +694,14 @@ mm_simple_status_class_init (MMSimpleStatusClass *klass)
                              G_PARAM_READWRITE);
     g_object_class_install_property (object_class, PROP_3GPP_OPERATOR_NAME, properties[PROP_3GPP_OPERATOR_NAME]);
 
+    properties[PROP_3GPP_VENDOR_PCO_INFO] =
+        g_param_spec_string (MM_SIMPLE_PROPERTY_3GPP_VENDOR_PCO_INFO,
+                             "3GPP LTE vendor PCO info",
+                             "Hex-encoded string of the current vendor PCO info",
+                             NULL,
+                             G_PARAM_READWRITE);
+    g_object_class_install_property (object_class, PROP_3GPP_VENDOR_PCO_INFO, properties[PROP_3GPP_VENDOR_PCO_INFO]);
+
     properties[PROP_CDMA_CDMA1X_REGISTRATION_STATE] =
         g_param_spec_enum (MM_SIMPLE_PROPERTY_CDMA_CDMA1X_REGISTRATION_STATE,
                            "CDMA1x registration state",
diff --git a/libmm-glib/mm-simple-status.h b/libmm-glib/mm-simple-status.h
index 8292fdb..be4f7f6 100644
--- a/libmm-glib/mm-simple-status.h
+++ b/libmm-glib/mm-simple-status.h
@@ -88,6 +88,7 @@ guint                        mm_simple_status_get_cdma_nid
 #define MM_SIMPLE_PROPERTY_3GPP_REGISTRATION_STATE "m3gpp-registration-state"
 #define MM_SIMPLE_PROPERTY_3GPP_OPERATOR_CODE      "m3gpp-operator-code"
 #define MM_SIMPLE_PROPERTY_3GPP_OPERATOR_NAME      "m3gpp-operator-name"
+#define MM_SIMPLE_PROPERTY_3GPP_VENDOR_PCO_INFO    "m3gpp-vendor-pco-info"
 
 #define MM_SIMPLE_PROPERTY_CDMA_CDMA1X_REGISTRATION_STATE "cdma-cdma1x-registration-state"
 #define MM_SIMPLE_PROPERTY_CDMA_EVDO_REGISTRATION_STATE   "cdma-evdo-registration-state"
diff --git a/src/mm-broadband-bearer.c b/src/mm-broadband-bearer.c
index f8f449d..90fd33f 100644
--- a/src/mm-broadband-bearer.c
+++ b/src/mm-broadband-bearer.c
@@ -1100,6 +1100,7 @@ connect_3gpp_ready (MMBroadbandBearer *self,
                     ConnectContext *ctx)
 {
     MMBearerConnectResult *result;
+    MMBaseModem *modem = NULL;
     GError *error = NULL;
 
     result = MM_BROADBAND_BEARER_GET_CLASS (self)->connect_3gpp_finish (self, res, &error);
@@ -1109,6 +1110,15 @@ connect_3gpp_ready (MMBroadbandBearer *self,
         return;
     }
 
+    /* Get the owner modem object */
+    g_object_get (self,
+                  MM_BEARER_MODEM, &modem,
+                  NULL);
+    g_assert (modem != NULL);
+
+    /* In case of 3GPP LTE, there is a need to refresh the vendor PCO info at this stage. */
+    mm_iface_modem_3gpp_reload_current_vendor_pco_info (MM_IFACE_MODEM_3GPP (modem), NULL, NULL);
+
     /* take result */
     connect_succeeded (ctx, CONNECTION_TYPE_3GPP, result);
 }
diff --git a/src/mm-iface-modem-3gpp.c b/src/mm-iface-modem-3gpp.c
index 53399d5..7fdce03 100644
--- a/src/mm-iface-modem-3gpp.c
+++ b/src/mm-iface-modem-3gpp.c
@@ -64,6 +64,10 @@ mm_iface_modem_3gpp_bind_simple_status (MMIfaceModem3gpp *self,
                             status, MM_SIMPLE_PROPERTY_3GPP_OPERATOR_NAME,
                             G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
 
+    g_object_bind_property (skeleton, "vendor-pco-info",
+                            status, MM_SIMPLE_PROPERTY_3GPP_VENDOR_PCO_INFO,
+                            G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
+
     g_object_unref (skeleton);
 }
 
@@ -75,7 +79,7 @@ typedef struct {
     MMModem3gppRegistrationState eps;
     gboolean manual_registration;
     GCancellable *pending_registration_cancellable;
-    gboolean reloading_operator;
+    gboolean reloading_registration_info;
 } RegistrationStateContext;
 
 static void
@@ -951,6 +955,114 @@ mm_iface_modem_3gpp_clear_current_operator (MMIfaceModem3gpp *self)
 
 /*****************************************************************************/
 
+typedef struct {
+    MMIfaceModem3gpp *self;
+    MmGdbusModem3gpp *skeleton;
+    GSimpleAsyncResult *result;
+} ReloadCurrentVendorPcoInfoContext;
+
+static void
+reload_current_vendor_pco_info_context_complete_and_free (ReloadCurrentVendorPcoInfoContext *ctx)
+{
+    g_simple_async_result_complete_in_idle (ctx->result);
+    g_object_unref (ctx->result);
+    if (ctx->skeleton)
+        g_object_unref (ctx->skeleton);
+    g_object_unref (ctx->self);
+    g_slice_free (ReloadCurrentVendorPcoInfoContext, ctx);
+}
+
+gboolean
+mm_iface_modem_3gpp_reload_current_vendor_pco_info_finish (MMIfaceModem3gpp *self,
+                                                           GAsyncResult *res,
+                                                           GError **error)
+{
+    return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
+}
+
+static void
+load_vendor_pco_info_ready (MMIfaceModem3gpp *self,
+                            GAsyncResult *res,
+                            ReloadCurrentVendorPcoInfoContext *ctx)
+{
+    GError *error = NULL;
+    gchar *str;
+
+    str = MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->load_vendor_pco_info_finish (self, res, &error);
+    if (error) {
+        mm_warn ("Couldn't load Vendor PCO Info: '%s'", error->message);
+        g_error_free (error);
+    }
+
+    if (ctx->skeleton)
+        mm_gdbus_modem3gpp_set_vendor_pco_info (ctx->skeleton, str);
+
+    g_free (str);
+
+    g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
+    reload_current_vendor_pco_info_context_complete_and_free (ctx);
+}
+
+void
+mm_iface_modem_3gpp_reload_current_vendor_pco_info (MMIfaceModem3gpp *self,
+                                                    GAsyncReadyCallback callback,
+                                                    gpointer user_data)
+{
+    ReloadCurrentVendorPcoInfoContext *ctx;
+
+    ctx = g_slice_new0 (ReloadCurrentVendorPcoInfoContext);
+    ctx->self = g_object_ref (self);
+    ctx->result = g_simple_async_result_new (G_OBJECT (self),
+                                             callback,
+                                             user_data,
+                                             mm_iface_modem_3gpp_reload_current_vendor_pco_info);
+
+    g_object_get (self,
+                  MM_IFACE_MODEM_3GPP_DBUS_SKELETON, &ctx->skeleton,
+                  NULL);
+
+    if (!ctx->skeleton) {
+        g_simple_async_result_set_error (ctx->result,
+                                         MM_CORE_ERROR,
+                                         MM_CORE_ERROR_FAILED,
+                                         "Couldn't get interface skeleton");
+        reload_current_vendor_pco_info_context_complete_and_free (ctx);
+        return;
+    }
+
+    if (!MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->load_vendor_pco_info ||
+        !MM_IFACE_MODEM_3GPP_GET_INTERFACE (self)->load_vendor_pco_info_finish) {
+
+        mm_gdbus_modem3gpp_set_vendor_pco_info (ctx->skeleton, NULL);
+
+        g_simple_async_result_set_op_res_gboolean(ctx->result, TRUE);
+        reload_current_vendor_pco_info_context_complete_and_free(ctx);
+        return;
+    }
+
+    /* Launch vendor PCO info update */
+    MM_IFACE_MODEM_3GPP_GET_INTERFACE (ctx->self)->load_vendor_pco_info (
+        ctx->self,
+        (GAsyncReadyCallback)load_vendor_pco_info_ready,
+        ctx);
+}
+
+void
+mm_iface_modem_3gpp_clear_current_vendor_pco_info (MMIfaceModem3gpp *self)
+{
+    MmGdbusModem3gpp *skeleton = NULL;
+
+    g_object_get (self,
+                  MM_IFACE_MODEM_3GPP_DBUS_SKELETON, &skeleton,
+                  NULL);
+    if (!skeleton)
+        return;
+
+    mm_gdbus_modem3gpp_set_vendor_pco_info (skeleton, NULL);
+}
+/*****************************************************************************/
+
+
 void
 mm_iface_modem_3gpp_update_access_technologies (MMIfaceModem3gpp *self,
                                                 MMModemAccessTechnology access_tech)
@@ -969,7 +1081,7 @@ mm_iface_modem_3gpp_update_access_technologies (MMIfaceModem3gpp *self,
      * but only if something valid to report */
     if (state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
         state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING ||
-        ctx->reloading_operator) {
+        ctx->reloading_registration_info) {
         if (access_tech != MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN)
             mm_iface_modem_update_access_technologies (MM_IFACE_MODEM (self),
                                                        access_tech,
@@ -1034,7 +1146,19 @@ update_registration_reload_current_operator_ready (MMIfaceModem3gpp *self,
                                            MM_MODEM_STATE_CHANGE_REASON_UNKNOWN);
 
     ctx = get_registration_state_context (self);
-    ctx->reloading_operator = FALSE;
+    ctx->reloading_registration_info = FALSE;
+}
+
+static void
+update_registration_reload_current_vendor_pco_info_ready (MMIfaceModem3gpp *self,
+                                                          GAsyncResult *res,
+                                                          gpointer user_data)
+{
+    mm_iface_modem_3gpp_reload_current_operator (
+        self,
+        (GAsyncReadyCallback)update_registration_reload_current_operator_ready,
+        user_data);
+
 }
 
 static void
@@ -1044,6 +1168,7 @@ update_non_registered_state (MMIfaceModem3gpp *self,
 {
     /* Not registered neither in home nor roaming network */
     mm_iface_modem_3gpp_clear_current_operator (self);
+    mm_iface_modem_3gpp_clear_current_vendor_pco_info(self);
 
     /* The property in the interface is bound to the property
      * in the skeleton, so just updating here is enough */
@@ -1081,20 +1206,20 @@ update_registration_state (MMIfaceModem3gpp *self,
 
     if (new_state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
         new_state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
-        /* If already reloading operator, skip it */
-        if (ctx->reloading_operator)
+        /* If already reloading registration info, skip it */
+        if (ctx->reloading_registration_info)
             return;
 
         mm_info ("Modem %s: 3GPP Registration state changed (%s -> registering)",
                  g_dbus_object_get_object_path (G_DBUS_OBJECT (self)),
                  mm_modem_3gpp_registration_state_get_string (old_state));
 
-        /* Reload current operator. ONLY update the state to REGISTERED after
-         * having loaded operator code/name */
-        ctx->reloading_operator = TRUE;
-        mm_iface_modem_3gpp_reload_current_operator (
+        /* Reload current registration info - vendor PCO info and operator.
+         * ONLY update the state to REGISTERED after having loaded operator code/name */
+        ctx->reloading_registration_info = TRUE;
+        mm_iface_modem_3gpp_reload_current_vendor_pco_info (
             self,
-            (GAsyncReadyCallback)update_registration_reload_current_operator_ready,
+            (GAsyncReadyCallback)update_registration_reload_current_vendor_pco_info_ready,
             GUINT_TO_POINTER (new_state));
         return;
     }
diff --git a/src/mm-iface-modem-3gpp.h b/src/mm-iface-modem-3gpp.h
index f4014c4..79342e6 100644
--- a/src/mm-iface-modem-3gpp.h
+++ b/src/mm-iface-modem-3gpp.h
@@ -34,6 +34,7 @@
 #define MM_IFACE_MODEM_3GPP_PS_NETWORK_SUPPORTED    "iface-modem-3gpp-ps-network-supported"
 #define MM_IFACE_MODEM_3GPP_EPS_NETWORK_SUPPORTED   "iface-modem-3gpp-eps-network-supported"
 #define MM_IFACE_MODEM_3GPP_IGNORED_FACILITY_LOCKS  "iface-modem-3gpp-ignored-facility-locks"
+#define MM_IFACE_MODEM_3GPP_VENDOR_PCO_INFO         "iface-modem-3gpp-vendor-pco-info"
 
 #define MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK    \
     (MM_MODEM_ACCESS_TECHNOLOGY_GSM |                       \
@@ -176,6 +177,14 @@ struct _MMIfaceModem3gpp {
                                           GAsyncResult *res,
                                           GError **error);
 
+    /* Loading of the Vendor PCO Info property */
+    void (*load_vendor_pco_info) (MMIfaceModem3gpp *self,
+                                  GAsyncReadyCallback callback,
+                                  gpointer user_data);
+    gchar * (*load_vendor_pco_info_finish) (MMIfaceModem3gpp *self,
+                                            GAsyncResult *res,
+                                            GError **error);
+
     /* Scan current networks, expect a GList of MMModem3gppNetworkInfo */
     void (* scan_networks) (MMIfaceModem3gpp *self,
                             GAsyncReadyCallback callback,
@@ -249,6 +258,15 @@ gboolean mm_iface_modem_3gpp_reload_current_operator_finish (MMIfaceModem3gpp *s
                                                              GError **error);
 void     mm_iface_modem_3gpp_clear_current_operator         (MMIfaceModem3gpp *self);
 
+/* Request to reload vendor PCO info */
+void     mm_iface_modem_3gpp_reload_current_vendor_pco_info        (MMIfaceModem3gpp *self,
+                                                                    GAsyncReadyCallback callback,
+                                                                    gpointer user_data);
+gboolean mm_iface_modem_3gpp_reload_current_vendor_pco_info_finish (MMIfaceModem3gpp *self,
+                                                                    GAsyncResult *res,
+                                                                    GError **error);
+void     mm_iface_modem_3gpp_clear_current_vendor_pco_info         (MMIfaceModem3gpp *self);
+
 /* Allow registering in the network */
 gboolean mm_iface_modem_3gpp_register_in_network_finish (MMIfaceModem3gpp *self,
                                                          GAsyncResult *res,
-- 
1.7.12.4



More information about the ModemManager-devel mailing list