---
src/network.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 72 insertions(+), 3 deletions(-)
diff --git a/src/network.c b/src/network.c
index b5450ee..64734d0 100644
--- a/src/network.c
+++ b/src/network.c
@@ -64,6 +64,7 @@ struct ofono_netreg {
int cellid;
int technology;
int mode;
+ gboolean forced_auto;
char *base_station;
struct network_operator_data *current_operator;
GSList *operator_list;
@@ -93,8 +94,11 @@ struct network_operator_data {
struct ofono_netreg *netreg;
};
-static const char *registration_mode_to_string(int mode)
+static const char *registration_mode_to_string(int mode, gboolean forced_auto)
{
+ if (forced_auto)
+ return "auto-only";
+
switch (mode) {
case NETWORK_REGISTRATION_MODE_AUTO:
return "auto";
@@ -160,7 +164,28 @@ static void set_registration_mode(struct ofono_netreg *netreg, int
mode)
storage_sync(netreg->imsi, SETTINGS_STORE, netreg->settings);
}
- strmode = registration_mode_to_string(mode);
+ strmode = registration_mode_to_string(mode, netreg->forced_auto);
+
+ conn = ofono_dbus_get_connection();
+ path = __ofono_atom_get_path(netreg->atom);
+
+ ofono_dbus_signal_property_changed(conn, path,
+ OFONO_NETWORK_REGISTRATION_INTERFACE,
+ "Mode", DBUS_TYPE_STRING, &strmode);
+}
+
+static void set_registration_forced_auto(struct ofono_netreg *netreg, gboolean value)
+{
+ DBusConnection *conn;
+ const char *strmode;
+ const char *path;
+
+ if (netreg->forced_auto == value)
+ return;
+
+ netreg->forced_auto = value;
+
+ strmode = registration_mode_to_string(netreg->mode, value);
conn = ofono_dbus_get_connection();
path = __ofono_atom_get_path(netreg->atom);
@@ -584,6 +609,9 @@ static DBusMessage *network_operator_register(DBusConnection *conn,
struct network_operator_data *opd = data;
struct ofono_netreg *netreg = opd->netreg;
+ if (netreg->forced_auto)
+ return __ofono_error_access_denied(msg);
+
if (netreg->pending)
return __ofono_error_busy(msg);
@@ -753,7 +781,8 @@ static DBusMessage *network_get_properties(DBusConnection *conn,
const char *status = registration_status_to_string(netreg->status);
const char *operator;
- const char *mode = registration_mode_to_string(netreg->mode);
+ const char *mode = registration_mode_to_string(netreg->mode,
+ netreg->forced_auto);
reply = dbus_message_new_method_return(msg);
if (reply == NULL)
@@ -1572,6 +1601,43 @@ 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++) {
+ gboolean forced_auto;
+
+ if (data[i * 2] != SIM_CSP_ENTRY_VALUE_ADDED_SERVICES)
+ continue;
+
+ forced_auto = (data[i * 2 + 1] & 0x80) == 0;
+
+ set_registration_forced_auto(netreg, forced_auto);
+ }
+}
+
int ofono_netreg_get_location(struct ofono_netreg *netreg)
{
if (netreg == NULL)
@@ -1819,6 +1885,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