---
 src/network.c |  121 ++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 95 insertions(+), 26 deletions(-)

diff --git a/src/network.c b/src/network.c
index bf61472..ef0b37f 100644
--- a/src/network.c
+++ b/src/network.c
@@ -42,7 +42,8 @@
 
 enum network_registration_mode {
        NETWORK_REGISTRATION_MODE_AUTO =        0,
-       NETWORK_REGISTRATION_MODE_MANUAL =      1,
+       NETWORK_REGISTRATION_MODE_AUTO_ONLY =   1,
+       NETWORK_REGISTRATION_MODE_MANUAL =      2,
 };
 
 #define SETTINGS_STORE "netreg"
@@ -98,6 +99,8 @@ static const char *registration_mode_to_string(int mode)
        switch (mode) {
        case NETWORK_REGISTRATION_MODE_AUTO:
                return "auto";
+       case NETWORK_REGISTRATION_MODE_AUTO_ONLY:
+               return "auto-only";
        case NETWORK_REGISTRATION_MODE_MANUAL:
                return "manual";
        }
@@ -143,6 +146,42 @@ static char **network_operator_technologies(struct 
network_operator_data *opd)
        return techs;
 }
 
+static void registration_status_callback(const struct ofono_error *error,
+                                       int status, int lac, int ci, int tech,
+                                       void *data)
+{
+       struct ofono_netreg *netreg = data;
+
+       if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+               DBG("Error during registration status query");
+               return;
+       }
+
+       ofono_netreg_status_notify(netreg, status, lac, ci, tech);
+}
+
+static void init_register(const struct ofono_error *error, void *data)
+{
+       struct ofono_netreg *netreg = data;
+
+       if (netreg->driver->registration_status == NULL)
+               return;
+
+       netreg->driver->registration_status(netreg,
+                                       registration_status_callback, netreg);
+}
+
+static void enforce_auto_only(struct ofono_netreg *netreg)
+{
+       if (netreg->mode != NETWORK_REGISTRATION_MODE_MANUAL)
+               return;
+
+       if (netreg->driver->register_auto == NULL)
+               return;
+
+       netreg->driver->register_auto(netreg, init_register, netreg);
+}
+
 static void set_registration_mode(struct ofono_netreg *netreg, int mode)
 {
        DBusConnection *conn;
@@ -152,6 +191,9 @@ static void set_registration_mode(struct ofono_netreg 
*netreg, int mode)
        if (netreg->mode == mode)
                return;
 
+       if (mode == NETWORK_REGISTRATION_MODE_AUTO_ONLY)
+               enforce_auto_only(netreg);
+
        netreg->mode = mode;
 
        if (netreg->settings) {
@@ -170,20 +212,6 @@ static void set_registration_mode(struct ofono_netreg 
*netreg, int mode)
                                        "Mode", DBUS_TYPE_STRING, &strmode);
 }
 
-static void registration_status_callback(const struct ofono_error *error,
-                                       int status, int lac, int ci, int tech,
-                                       void *data)
-{
-       struct ofono_netreg *netreg = data;
-
-       if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
-               DBG("Error during registration status query");
-               return;
-       }
-
-       ofono_netreg_status_notify(netreg, status, lac, ci, tech);
-}
-
 static void register_callback(const struct ofono_error *error, void *data)
 {
        struct ofono_netreg *netreg = data;
@@ -211,15 +239,6 @@ out:
                                        registration_status_callback, netreg);
 }
 
-static void init_register(const struct ofono_error *error, void *data)
-{
-       struct ofono_netreg *netreg = data;
-
-       if (netreg->driver->registration_status)
-               netreg->driver->registration_status(netreg,
-                                       registration_status_callback, netreg);
-}
-
 static struct network_operator_data *
        network_operator_create(const struct ofono_network_operator *op)
 {
@@ -586,6 +605,9 @@ static DBusMessage 
*network_operator_register(DBusConnection *conn,
        struct network_operator_data *opd = data;
        struct ofono_netreg *netreg = opd->netreg;
 
+       if (netreg->mode == NETWORK_REGISTRATION_MODE_AUTO_ONLY)
+               return __ofono_error_access_denied(msg);
+
        if (netreg->pending)
                return __ofono_error_busy(msg);
 
@@ -838,6 +860,9 @@ static DBusMessage *network_register(DBusConnection *conn,
 
        netreg->driver->register_auto(netreg, register_callback, netreg);
 
+       if (netreg->mode == NETWORK_REGISTRATION_MODE_AUTO_ONLY)
+               return NULL;
+
        set_registration_mode(netreg, NETWORK_REGISTRATION_MODE_AUTO);
 
        return NULL;
@@ -947,6 +972,9 @@ static DBusMessage *network_scan(DBusConnection *conn,
 {
        struct ofono_netreg *netreg = data;
 
+       if (netreg->mode == NETWORK_REGISTRATION_MODE_AUTO_ONLY)
+               return __ofono_error_access_denied(msg);
+
        if (netreg->pending)
                return __ofono_error_busy(msg);
 
@@ -1364,7 +1392,7 @@ static void init_registration_status(const struct 
ofono_error *error,
                                        signal_strength_callback, netreg);
        }
 
-       if (netreg->mode == NETWORK_REGISTRATION_MODE_AUTO &&
+       if (netreg->mode != NETWORK_REGISTRATION_MODE_MANUAL &&
                (status == NETWORK_REGISTRATION_STATUS_NOT_REGISTERED ||
                        status == NETWORK_REGISTRATION_STATUS_DENIED ||
                        status == NETWORK_REGISTRATION_STATUS_UNKNOWN)) {
@@ -1574,6 +1602,44 @@ static void sim_spn_read_cb(int ok, int length, int 
record,
        }
 }
 
+static void sim_csp_read_cb(int ok, int length, int record,
+                               const unsigned char *data,
+                               int record_length, void *user_data)
+{
+       struct ofono_netreg *netreg = user_data;
+       int i;
+
+       if (!ok)
+               return;
+
+       if (length < 18 || record_length < 18 || length < record_length)
+               return;
+
+       /*
+        * According to CPHS 4.2, EFcsp is an array of two-byte service
+        * entries, each consisting of a one byte service group
+        * identifier followed by 8 bits; each bit is indicating
+        * availability of a specific service or feature.
+        *
+        * The PLMN mode bit, if present, indicates whether manual
+        * operator selection should be disabled or enabled. When
+        * unset, the device is forced to automatic mode; when set,
+        * manual selection is to be enabled. The latter is also the
+        * default.
+        */
+       for (i = 0; i < record_length / 2; i++) {
+
+               if (data[i * 2] != SIM_CSP_ENTRY_VALUE_ADDED_SERVICES)
+                       continue;
+
+               if ((data[i * 2 + 1] & 0x80) != 0)
+                       return;
+
+               set_registration_mode(netreg,
+                                       NETWORK_REGISTRATION_MODE_AUTO_ONLY);
+       }
+}
+
 int ofono_netreg_get_location(struct ofono_netreg *netreg)
 {
        if (netreg == NULL)
@@ -1769,7 +1835,7 @@ static void netreg_load_settings(struct ofono_netreg 
*netreg)
        mode = g_key_file_get_integer(netreg->settings, SETTINGS_GROUP,
                                        "Mode", NULL);
 
-       if (mode >= 0 && mode <= 1)
+       if (mode != NETWORK_REGISTRATION_MODE_AUTO_ONLY)
                netreg->mode = mode;
 
        g_key_file_set_integer(netreg->settings, SETTINGS_GROUP,
@@ -1816,6 +1882,9 @@ void ofono_netreg_register(struct ofono_netreg *netreg)
                ofono_sim_read(netreg->sim, SIM_EFSPN_FILEID,
                                OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
                                sim_spn_read_cb, netreg);
+               ofono_sim_read(netreg->sim, SIM_EF_CPHS_CSP_FILEID,
+                               OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+                               sim_csp_read_cb, netreg);
        }
 
        __ofono_atom_register(netreg->atom, netreg_unregister);
-- 
1.7.1

_______________________________________________
ofono mailing list
ofono@ofono.org
http://lists.ofono.org/listinfo/ofono

Reply via email to