[PATCH 2/4] Handle EF-CBSMID contents.

Andrzej Zaborowski andrew.zaborowski at intel.com
Tue Dec 15 18:06:04 PST 2009


This lets operators download contents to the sim over the air.
---
 drivers/atmodem/sim.c |   81 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/sim.h         |    6 ++++
 src/cbs.c             |   27 +++++++++++-----
 src/sim.c             |   33 ++++++++++++++++++++
 4 files changed, 138 insertions(+), 9 deletions(-)

diff --git a/drivers/atmodem/sim.c b/drivers/atmodem/sim.c
index 92ae575..fca6f0f 100644
--- a/drivers/atmodem/sim.c
+++ b/drivers/atmodem/sim.c
@@ -704,6 +704,86 @@ error:
 	CALLBACK_WITH_FAILURE(cb, -1, data);
 }
 
+static void at_csim_envelope_cb(gboolean ok, GAtResult *result,
+		gpointer user_data)
+{
+	struct cb_data *cbd = user_data;
+	GAtResultIter iter;
+	ofono_sim_read_cb_t cb = cbd->cb;
+	struct ofono_error error;
+	const guint8 *response;
+	gint rlen, len;
+
+	dump_response("at_csim_envelope_cb", ok, result);
+	decode_at_error(&error, g_at_result_final_response(result));
+
+	if (!ok) {
+		CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
+		return;
+	}
+
+	g_at_result_iter_init(&iter, result);
+
+	if (!g_at_result_iter_next(&iter, "+CSIM:")) {
+		CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
+		return;
+	}
+
+	if (!g_at_result_iter_next_number(&iter, &rlen)) {
+		CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
+		return;
+	}
+
+	if (!g_at_result_iter_next_hexstring(&iter, &response, &len)) {
+		CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
+		return;
+	}
+
+	if (rlen != len * 2 || len < 2 ||
+			response[len - 2] != 0x90 || response[len - 1] != 0) {
+		CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
+		return;
+	}
+
+	ofono_debug("csim_envelope_cb: %i", len);
+
+	cb(&error, response, len - 2, cbd->data);
+}
+
+static void at_sim_envelope(struct ofono_sim *sim, int length,
+				const guint8 *command,
+				ofono_sim_read_cb_t cb, void *data)
+{
+	struct sim_data *sd = ofono_sim_get_data(sim);
+	struct cb_data *cbd = cb_data_new(cb, data);
+	char *buf = g_try_new(char, 64 + length * 2);
+	int len, ret;
+
+	if (!cbd || !buf)
+		goto error;
+
+	len = sprintf(buf, "AT+CSIM=%i,a0c20000%02hhx",
+			12 + length * 2, length);
+
+	for (; length; length--)
+		len += sprintf(buf + len, "%02hhx", *command++);
+	sprintf(buf + len, "00");
+
+	ret = g_at_chat_send(sd->chat, buf, crsm_prefix,
+				at_csim_envelope_cb, cbd, g_free);
+
+	g_free(buf);
+
+	if (ret > 0)
+		return;
+
+error:
+	if (cbd)
+		g_free(cbd);
+
+	CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
+}
+
 static gboolean at_sim_register(gpointer user)
 {
 	struct ofono_sim *sim = user;
@@ -756,6 +836,7 @@ static struct ofono_sim_driver driver = {
 	.lock			= at_pin_enable,
 	.change_passwd		= at_change_passwd,
 	.query_locked		= at_pin_query_enabled,
+	.envelope		= at_sim_envelope,
 };
 
 void at_sim_init()
diff --git a/include/sim.h b/include/sim.h
index f76f9d1..8df7ec3 100644
--- a/include/sim.h
+++ b/include/sim.h
@@ -135,6 +135,9 @@ struct ofono_sim_driver {
 	void (*query_locked)(struct ofono_sim *sim,
 			enum ofono_sim_password_type type,
 			ofono_sim_locked_cb_t cb, void *data);
+	void (*envelope)(struct ofono_sim *sim, int length,
+				const guint8 *command,
+				ofono_sim_read_cb_t cb, void *data);
 };
 
 int ofono_sim_driver_register(const struct ofono_sim_driver *d);
@@ -176,6 +179,9 @@ int ofono_sim_write(struct ofono_sim *sim, int id,
 			ofono_sim_file_write_cb_t cb,
 			enum ofono_sim_file_structure structure, int record,
 			const unsigned char *data, int length, void *userdata);
+
+void ofono_cbs_download(struct ofono_sim *sim, const guint8 *pdu, int pdu_len);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/cbs.c b/src/cbs.c
index 42594c7..c378f2a 100644
--- a/src/cbs.c
+++ b/src/cbs.c
@@ -184,6 +184,11 @@ void ofono_cbs_notify(struct ofono_cbs *cbs, const unsigned char *pdu,
 		return;
 	}
 
+	if (cbs_topic_in_range(c.message_identifier, cbs->efcbmid_contents)) {
+		ofono_cbs_download(cbs->sim, pdu, pdu_len);
+		return;
+	}
+
 	if (!cbs_dcs_decode(c.dcs, &udhi, &cls, &charset, &comp, NULL, NULL)) {
 		ofono_error("Unknown / Reserved DCS.  Ignoring");
 		return;
@@ -437,6 +442,13 @@ static void cbs_unregister(struct ofono_atom *atom)
 		cbs->new_topics = NULL;
 	}
 
+	if (cbs->efcbmid_length) {
+		cbs->efcbmid_length = 0;
+		g_slist_foreach(cbs->efcbmid_contents, (GFunc)g_free, NULL);
+		g_slist_free(cbs->efcbmid_contents);
+		cbs->efcbmid_contents = NULL;
+	}
+
 	cbs->sim = NULL;
 
 	if (cbs->reset_source) {
@@ -627,6 +639,7 @@ static void sim_cbmid_read_cb(int ok, int length, int record,
 	unsigned short mi;
 	int i;
 	char *str;
+	GSList *contents = NULL;
 
 	if (!ok)
 		return;
@@ -648,23 +661,19 @@ static void sim_cbmid_read_cb(int ok, int length, int record,
 		range->min = mi;
 		range->max = mi;
 
-		cbs->efcbmid_contents = g_slist_prepend(cbs->efcbmid_contents,
-							range);
+		contents = g_slist_prepend(contents, range);
 	}
 
-	if (cbs->efcbmid_contents == NULL)
+	if (contents == NULL)
 		return;
 
-	cbs->efcbmid_contents = g_slist_reverse(cbs->efcbmid_contents);
+	cbs->efcbmid_contents = cbs_optimize_ranges(contents);
+	g_slist_foreach(contents, (GFunc) g_free, NULL);
+	g_slist_free(contents);
 
 	str = cbs_topic_ranges_to_string(cbs->efcbmid_contents);
 	ofono_debug("Got cbmid: %s", str);
 	g_free(str);
-
-	cbs->efcbmid_length = 0;
-	g_slist_foreach(cbs->efcbmid_contents, (GFunc)g_free, NULL);
-	g_slist_free(cbs->efcbmid_contents);
-	cbs->efcbmid_contents = NULL;
 }
 
 static void cbs_got_imsi(struct ofono_cbs *cbs)
diff --git a/src/sim.c b/src/sim.c
index 907e4ce..4689886 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -1720,6 +1720,39 @@ void ofono_sim_set_ready(struct ofono_sim *sim)
 	}
 }
 
+static void sim_cb_download_cb(const struct ofono_error *error,
+				const unsigned char *data, int len, void *user)
+{
+	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+		ofono_error("CellBroadcast download to UICC failed");
+		return;
+	}
+
+	ofono_debug("CellBroadcast download to UICC reported no error");
+}
+
+void ofono_cbs_download(struct ofono_sim *sim, const guint8 *pdu, int pdu_len)
+{
+	guint8 tlv[pdu_len + 8];
+
+	if (sim->ready != TRUE)
+		return;
+	if (!sim->driver->envelope)
+		return;
+
+	tlv[0] = 0xd2; /* Cell Broadcast Download */
+	tlv[1] = 6 + pdu_len;
+	tlv[2] = 0x82; /* Device Identities */
+	tlv[3] = 0x02; /* Device Identities length */
+	tlv[4] = 0x83; /* Network */
+	tlv[5] = 0x81; /* UICC */
+	tlv[6] = 0x8c; /* Cell Broadcast page */
+	tlv[7] = pdu_len;
+	memcpy(tlv + 8, pdu, pdu_len);
+
+	sim->driver->envelope(sim, pdu_len + 8, tlv, sim_cb_download_cb, sim);
+}
+
 int ofono_sim_driver_register(const struct ofono_sim_driver *d)
 {
 	DBG("driver: %p, name: %s", d, d->name);
-- 
1.6.1



More information about the ofono mailing list