All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Read EF-SPDI and use it for SPN display.
@ 2009-06-21  1:40 Andrzej Zaborowski
  2009-06-22 18:23 ` Denis Kenzior
  0 siblings, 1 reply; 3+ messages in thread
From: Andrzej Zaborowski @ 2009-06-21  1:40 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 7709 bytes --]

When the operator is one of those listed in EF-SPDI then we need to
treat it like a HPLMN in deciding whether the SPN or PLMN name should
be displayed.
---
I was also going to try implementing the semantics described in EF-PNN /
EF-OPL but I have not found evidence that it's not already handled by the
modem in the responses to +COPN (i.e. it may already be taking care to
substitute the network names?  is this specified somewhere or would this
be very unlikely?)

Regards
---
 src/network.c |    7 ++-
 src/sim.c     |  167 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/sim.h     |    3 +
 3 files changed, 176 insertions(+), 1 deletions(-)

diff --git a/src/network.c b/src/network.c
index a437f0d..43fa2ab 100644
--- a/src/network.c
+++ b/src/network.c
@@ -328,6 +328,7 @@ static char *get_operator_display_name(struct ofono_modem *modem)
 	const char *plmn;
 	char *name = netreg->display_name;
 	int len = sizeof(netreg->display_name);
+	int home_or_spdi;
 
 	/* The name displayed to user depends on whether we're in a home
 	 * PLMN or roaming and on configuration bits from the SIM, all
@@ -345,7 +346,11 @@ static char *get_operator_display_name(struct ofono_modem *modem)
 
 	plmn = netreg->current_operator->name;
 
-	if (netreg->status == NETWORK_REGISTRATION_STATUS_REGISTERED)
+	home_or_spdi =
+		(netreg->status == NETWORK_REGISTRATION_STATUS_REGISTERED) ||
+		ofono_operator_in_spdi(modem, netreg->current_operator);
+
+	if (home_or_spdi)
 		if (netreg->flags & NETWORK_REGISTRATION_FLAG_HOME_SHOW_PLMN)
 			/* Case 1 */
 			snprintf(name, len, "%s (%s)", netreg->spname, plmn);
diff --git a/src/sim.c b/src/sim.c
index a8b7d5f..572f6a8 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -53,6 +53,8 @@ struct sim_manager_data {
 
 	GSList *update_spn_notify;
 
+	GSList *spdi;
+
 	int own_numbers_num;
 	int own_numbers_size;
 	int own_numbers_current;
@@ -80,6 +82,44 @@ static char **get_own_numbers(GSList *own_numbers)
 	return ret;
 }
 
+/* Parse ASN.1 Basic Encoding Rules TLVs per ISO/IEC 7816 */
+static const guint8 *ber_tlv_find_by_tag(const guint8 *pdu, guint8 in_tag,
+						int in_len, int *out_len)
+{
+	guint8 tag;
+	int len;
+	const guint8 *end = pdu + in_len;
+
+	do {
+		while (pdu < end && (*pdu == 0x00 || *pdu == 0xff))
+			pdu ++;
+		if (pdu == end)
+			break;
+
+		tag = *pdu ++;
+		if (!(0x1f & ~tag))
+			while (pdu < end && (*pdu ++ & 0x80));
+		if (pdu == end)
+			break;
+
+		for (len = 0; pdu + 1 < end && (*pdu & 0x80);
+				len = (len | (*pdu ++ & 0x7f)) << 7);
+		if (*pdu & 0x80)
+			break;
+		len |= *pdu ++;
+
+		if (tag == in_tag && pdu + len <= end) {
+			if (out_len)
+				*out_len = len;
+			return pdu;
+		}
+
+		pdu += len;
+	} while (pdu < end);
+
+	return NULL;
+}
+
 static struct sim_manager_data *sim_manager_create()
 {
 	return g_try_new0(struct sim_manager_data, 1);
@@ -105,6 +145,12 @@ static void sim_manager_destroy(gpointer userdata)
 		g_free(data->spn);
 		data->spn = NULL;
 	}
+
+	if (data->spdi) {
+		g_slist_foreach(data->spdi, (GFunc)g_free, NULL);
+		g_slist_free(data->spdi);
+		data->spdi = NULL;
+	}
 }
 
 static DBusMessage *sim_get_properties(DBusConnection *conn,
@@ -156,6 +202,7 @@ static GDBusSignalTable sim_manager_signals[] = { { } };
 enum sim_fileids {
 	SIM_EFMSISDN_FILEID = 0x6f40,
 	SIM_EFSPN_FILEID = 0x6f46,
+	SIM_EFSPDI_FILEID = 0x6fcd,
 };
 
 #define SIM_EFSPN_DC_HOME_PLMN_BIT 0x1
@@ -338,6 +385,123 @@ static gboolean sim_retrieve_own_number(void *user_data)
 	return FALSE;
 }
 
+struct spdi_operator {
+	char mcc[OFONO_MAX_MCC_LENGTH + 1];
+	char mnc[OFONO_MAX_MNC_LENGTH + 1];
+};
+
+static struct spdi_operator *spdi_operator_alloc(const guint8 *bcd)
+{
+	struct spdi_operator *spdi = g_new0(struct spdi_operator, 1);
+	char *mcc = spdi->mcc;
+	char *mnc = spdi->mnc;
+	guint8 digit;
+
+	digit = (bcd[0] >> 0) & 0xf;
+	if (digit != 0xf)
+		*mcc ++ = '0' + digit;
+	digit = (bcd[0] >> 4) & 0xf;
+	if (digit != 0xf)
+		*mcc ++ = '0' + digit;
+	digit = (bcd[1] >> 0) & 0xf;
+	if (digit != 0xf)
+		*mcc ++ = '0' + digit;
+	digit = (bcd[2] >> 0) & 0xf;
+	if (digit != 0xf)
+		*mnc ++ = '0' + digit;
+	digit = (bcd[2] >> 4) & 0xf;
+	if (digit != 0xf)
+		*mnc ++ = '0' + digit;
+	digit = (bcd[1] >> 4) & 0xf;
+	if (digit != 0xf)
+		*mnc ++ = '0' + digit;
+
+	return spdi;
+}
+
+static gint spdi_operator_compare(gconstpointer a, gconstpointer b)
+{
+	const struct spdi_operator *opa = a;
+	const struct spdi_operator *opb = b;
+
+	return strcmp(opa->mcc, opb->mcc) ?: strcmp(opa->mnc, opb->mnc);
+}
+
+int ofono_operator_in_spdi(struct ofono_modem *modem,
+				const struct ofono_network_operator *op)
+{
+	struct sim_manager_data *sim = modem->sim_manager;
+	struct spdi_operator spdi_op;
+
+	if (!sim)
+		return FALSE;
+
+	g_strlcpy(spdi_op.mcc, op->mcc, sizeof(spdi_op.mcc));
+	g_strlcpy(spdi_op.mnc, op->mnc, sizeof(spdi_op.mnc));
+
+	return !!g_slist_find_custom(sim->spdi,
+			&spdi_op, spdi_operator_compare);
+}
+
+static void sim_spdi_read_cb(const struct ofono_error *error,
+				const unsigned char *spdidata,
+				int length, void *data)
+{
+	struct ofono_modem *modem = data;
+	struct sim_manager_data *sim = modem->sim_manager;
+	const guint8 *plmn_list;
+	struct spdi_operator *spdi;
+	GSList *l;
+
+	if (error->type != OFONO_ERROR_TYPE_NO_ERROR || length <= 5)
+		return;
+
+	plmn_list = ber_tlv_find_by_tag(spdidata, 0x80, length, &length);
+	if (!plmn_list) {
+		ofono_debug("Couldn't parse the EF-SPDI contents as a TLV");
+		return;
+	}
+
+	for (length /= 3; length --; plmn_list += 3) {
+		if ((plmn_list[0] & plmn_list[1] & plmn_list[2]) == 0xff)
+			continue;
+
+		sim->spdi = g_slist_insert_sorted(sim->spdi,
+				spdi_operator_alloc(plmn_list),
+				spdi_operator_compare);
+	}
+
+	if (sim->spdi)
+		for (l = sim->update_spn_notify; l; l = l->next)
+			sim_spn_notify(modem, l->data);
+}
+
+static void sim_spdi_info_cb(const struct ofono_error *error, int length,
+				enum ofono_sim_file_structure structure,
+				int dummy, void *data)
+{
+	struct ofono_modem *modem = data;
+	struct sim_manager_data *sim = modem->sim_manager;
+
+	if (error->type != OFONO_ERROR_TYPE_NO_ERROR || length <= 5 ||
+			structure != OFONO_SIM_FILE_STRUCTURE_TRANSPARENT)
+		return;
+
+	sim->ops->read_file_transparent(modem, SIM_EFSPDI_FILEID, 0, length,
+					sim_spdi_read_cb, modem);
+}
+
+static gboolean sim_retrieve_spdi(void *user_data)
+{
+	struct ofono_modem *modem = user_data;
+	struct sim_manager_data *sim = modem->sim_manager;
+
+	sim->ops->read_file_info(modem, SIM_EFSPDI_FILEID,
+					sim_spdi_info_cb, modem);
+
+	return FALSE;
+}
+
 static void initialize_sim_manager(struct ofono_modem *modem)
 {
 	DBusConnection *conn = dbus_gsm_connection();
@@ -367,6 +531,9 @@ static void initialize_sim_manager(struct ofono_modem *modem)
 
 	if (modem->sim_manager->ops->read_file_linear)
 		g_timeout_add(0, sim_retrieve_own_number, modem);
+
+	if (modem->sim_manager->ops->read_file_transparent)
+		g_timeout_add(0, sim_retrieve_spdi, modem);
 }
 
 int ofono_sim_manager_register(struct ofono_modem *modem,
diff --git a/src/sim.h b/src/sim.h
index e0b471d..9456934 100644
--- a/src/sim.h
+++ b/src/sim.h
@@ -28,3 +28,6 @@ int ofono_spn_update_notify_register(struct ofono_modem *modem,
 		update_spn_cb cb);
 int ofono_spn_update_notify_unregister(struct ofono_modem *modem,
 		update_spn_cb cb);
+
+int ofono_operator_in_spdi(struct ofono_modem *modem,
+				const struct ofono_network_operator *op);
-- 
1.6.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] Read EF-SPDI and use it for SPN display.
  2009-06-21  1:40 [PATCH] Read EF-SPDI and use it for SPN display Andrzej Zaborowski
@ 2009-06-22 18:23 ` Denis Kenzior
  2009-06-22 18:30   ` Aki Niemi
  0 siblings, 1 reply; 3+ messages in thread
From: Denis Kenzior @ 2009-06-22 18:23 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 1467 bytes --]

Hi,

>When the operator is one of those listed in EF-SPDI then we need to
>treat it like a HPLMN in deciding whether the SPN or PLMN name should
>be displayed.

Patch has been applied.  I fixed a couple minor style issues.  Thanks.

>---
>I was also going to try implementing the semantics described in EF-PNN /
>EF-OPL but I have not found evidence that it's not already handled by the
>modem in the responses to +COPN (i.e. it may already be taking care to
>substitute the network names?  is this specified somewhere or would this
>be very unlikely?)

Unfortunately +COPN is based on the operator list stored in the modem itself.  
This generally means this list is pretty much garbage after a few years.  
Check 22.101 Appending A, Section A.3.  Basically the +COPS=? lists the 
operator names stored in the ME, +COPS? is likely to report the NITZ name once 
it arrives.  The SIM EFpnn and EFopl is not queried unless you use vendor 
extensions.

For us the strategy should probably be:
- If EFpnn / EFopl exists on the SIM, read and cache
- If EFpnn / EFopl exists on the SIM and cache already exists, delay updating 
cache until later
- If EFpnn / EFopl cache name exists, use that name
- Otherwise use COPS name.

There's also the possibility of including our own database of mcc/mnc 
identifiers along with operator name and operator country.  This would probably 
have higher precedence over the COPS name.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] Read EF-SPDI and use it for SPN display.
  2009-06-22 18:23 ` Denis Kenzior
@ 2009-06-22 18:30   ` Aki Niemi
  0 siblings, 0 replies; 3+ messages in thread
From: Aki Niemi @ 2009-06-22 18:30 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 438 bytes --]


On Mon, 22 Jun 2009 13:23:07 -0500, Denis Kenzior <denkenz@gmail.com>
wrote:
> There's also the possibility of including our own database of mcc/mnc 
> identifiers along with operator name and operator country.  This would
> probably have higher precedence over the COPS name.

This would be my preference. I suspect modem vendors would be more than
happy to let the that list live somewhere else in the future.

Cheers,
Aki

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2009-06-22 18:30 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-21  1:40 [PATCH] Read EF-SPDI and use it for SPN display Andrzej Zaborowski
2009-06-22 18:23 ` Denis Kenzior
2009-06-22 18:30   ` Aki Niemi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.