@@ -1,7 +1,7 @@
/*
* oFono - Open Source Telephony - RIL-based devices
*
- * Copyright (C) 2015 Jolla Ltd.
+ * Copyright (C) 2015-2016 Jolla Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -25,14 +25,16 @@
guint timer_id;
};
-enum ril_call_forward_cmd {
+enum ril_call_forward_action {
CF_ACTION_DISABLE,
CF_ACTION_ENABLE,
- CF_ACTION_UNUSED,
+ CF_ACTION_INTERROGATE,
CF_ACTION_REGISTRATION,
CF_ACTION_ERASURE
};
+#define CF_TIME_DEFAULT (0)
+
struct ril_call_forward_cbd {
struct ril_call_forward *fd;
union _ofono_call_forward_cb {
@@ -43,35 +45,57 @@
gpointer data;
};
-#define ril_call_forward_cbd_free g_free
-
static inline struct ril_call_forward *ril_call_forward_get_data(
struct ofono_call_forwarding *cf)
{
return ofono_call_forwarding_get_data(cf);
}
+static void ril_call_forward_cbd_free(gpointer cbd)
+{
+ g_slice_free(struct ril_call_forward_cbd, cbd);
+}
+
static struct ril_call_forward_cbd *ril_call_forward_cbd_new(void *cb,
void *data)
{
struct ril_call_forward_cbd *cbd;
- cbd = g_new0(struct ril_call_forward_cbd, 1);
+ cbd = g_slice_new0(struct ril_call_forward_cbd);
cbd->cb.ptr = cb;
cbd->data = data;
return cbd;
}
-static inline void ril_call_forward_submit_request(struct ril_call_forward *fd,
- GRilIoRequest* req, guint code, GRilIoChannelResponseFunc response,
- void *cb, void *data)
+static GRilIoRequest *ril_call_forward_req(enum ril_call_forward_action action,
+ int type, int cls, const struct ofono_phone_number *number, int time)
{
- grilio_queue_send_request_full(fd->q, req, code, response,
- ril_call_forward_cbd_free,
- ril_call_forward_cbd_new(cb, data));
+ GRilIoRequest *req = grilio_request_new();
+
+ /*
+ * Modem seems to respond with error to all requests
+ * made with bearer class BEARER_CLASS_DEFAULT.
+ */
+ if (cls == BEARER_CLASS_DEFAULT) {
+ cls = SERVICE_CLASS_NONE;
+ }
+
+ grilio_request_append_int32(req, action);
+ grilio_request_append_int32(req, type);
+ grilio_request_append_int32(req, cls); /* Service class */
+ if (number) {
+ grilio_request_append_int32(req, number->type);
+ grilio_request_append_utf8(req, number->number);
+ } else {
+ grilio_request_append_int32(req, 0x81); /* TOA unknown */
+ grilio_request_append_utf8(req, NULL); /* No number */
+ }
+ grilio_request_append_int32(req, time);
+
+ return req;
}
-static void ril_forward_set_cb(GRilIoChannel *io, int status,
+static void ril_call_forward_set_cb(GRilIoChannel *io, int status,
const void *data, guint len, void *user_data)
{
struct ofono_error error;
@@ -86,93 +110,51 @@
}
}
-static void ril_call_forward_registration(struct ofono_call_forwarding *cf,
- int type, int cls, const struct ofono_phone_number *number,
- int time, ofono_call_forwarding_set_cb_t cb, void *data)
+static void ril_call_forward_set(struct ofono_call_forwarding *cf,
+ enum ril_call_forward_action cmd, int type, int cls,
+ const struct ofono_phone_number *number, int time,
+ ofono_call_forwarding_set_cb_t cb, void *data)
{
struct ril_call_forward *fd = ril_call_forward_get_data(cf);
- GRilIoRequest *req = grilio_request_new();
-
- ofono_info("cf registration");
- grilio_request_append_int32(req, CF_ACTION_REGISTRATION);
- grilio_request_append_int32(req, type);
-
- /*
- * Modem seems to respond with error to all queries
- * or settings made with bearer class
- * BEARER_CLASS_DEFAULT. Design decision: If given
- * class is BEARER_CLASS_DEFAULT let's map it to
- * BEARER_CLASS_VOICE as per RIL design.
- */
- if (cls == BEARER_CLASS_DEFAULT) {
- cls = BEARER_CLASS_VOICE;
- }
+ GRilIoRequest *req = ril_call_forward_req(cmd, type, cls, number, time);
- grilio_request_append_int32(req, cls);
- grilio_request_append_int32(req, number->type);
- grilio_request_append_utf8(req, number->number);
- grilio_request_append_int32(req, time);
-
- ril_call_forward_submit_request(fd, req, RIL_REQUEST_SET_CALL_FORWARD,
- ril_forward_set_cb, cb, data);
+ grilio_queue_send_request_full(fd->q, req, RIL_REQUEST_SET_CALL_FORWARD,
+ ril_call_forward_set_cb, ril_call_forward_cbd_free,
+ ril_call_forward_cbd_new(cb, data));
grilio_request_unref(req);
}
-static void ril_call_forward_send_cmd(struct ofono_call_forwarding *cf,
- int type, int cls, ofono_call_forwarding_set_cb_t cb,
- void *data, int action)
+static void ril_call_forward_registration(struct ofono_call_forwarding *cf,
+ int type, int cls, const struct ofono_phone_number *number,
+ int time, ofono_call_forwarding_set_cb_t cb, void *data)
{
- struct ril_call_forward *fd = ril_call_forward_get_data(cf);
- GRilIoRequest *req = grilio_request_new();
-
- grilio_request_append_int32(req, action);
- grilio_request_append_int32(req, type);
-
- /*
- * Modem seems to respond with error to all queries
- * or settings made with bearer class
- * BEARER_CLASS_DEFAULT. Design decision: If given
- * class is BEARER_CLASS_DEFAULT let's map it to
- * BEARER_CLASS_VOICE as per RIL design.
- */
- if (cls == BEARER_CLASS_DEFAULT) {
- cls = BEARER_CLASS_VOICE;
- }
-
- grilio_request_append_int32(req, cls); /* Service class */
-
- /* Following 3 values have no real meaning in erasure
- * but apparently RIL expects them so fields need to
- * be filled. Otherwise there is no response
- */
- grilio_request_append_int32(req, 0x81); /* TOA unknown */
- grilio_request_append_utf8(req, "1234567890");
- grilio_request_append_int32(req, 60);
-
- ril_call_forward_submit_request(fd, req, RIL_REQUEST_SET_CALL_FORWARD,
- ril_forward_set_cb, cb, data);
- grilio_request_unref(req);
+ ofono_info("cf registration");
+ ril_call_forward_set(cf, CF_ACTION_REGISTRATION, type, cls,
+ number, time, cb, data);
}
static void ril_call_forward_erasure(struct ofono_call_forwarding *cf,
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
{
- ofono_info("CF_ACTION_ERASURE");
- ril_call_forward_send_cmd(cf, type, cls, cb, data, CF_ACTION_ERASURE);
+ ofono_info("cf erasure");
+ ril_call_forward_set(cf, CF_ACTION_ERASURE, type, cls,
+ NULL, CF_TIME_DEFAULT, cb, data);
}
static void ril_call_forward_deactivate(struct ofono_call_forwarding *cf,
int type, int cls, ofono_call_forwarding_set_cb_t cb, void *data)
{
- ofono_info("CF_ACTION_DISABLE");
- ril_call_forward_send_cmd(cf, type, cls, cb, data, CF_ACTION_DISABLE);
+ ofono_info("cf disable");
+ ril_call_forward_set(cf, CF_ACTION_DISABLE, type, cls,
+ NULL, CF_TIME_DEFAULT, cb, data);
|
@@ -24,12 +24,6 @@
#define SIM_STATE_CHANGE_TIMEOUT_SECS (5)
-/*
- * TODO:
- * 1. Define constants for hex literals
- * 2. Document P1-P3 usage (+CSRM)
- */
-
#define EF_STATUS_INVALIDATED 0
#define EF_STATUS_VALID 1
@@ -53,6 +47,13 @@
#define ENTER_SIM_PUK_PARAMS 3
#define CHANGE_SIM_PIN_PARAMS 3
+/* P2 coding (modes) for READ RECORD and UPDATE RECORD (see TS 102.221) */
+#define MODE_SELECTED (0x00) /* Currently selected EF */
+#define MODE_CURRENT (0x04) /* P1='00' denotes the current record */
+#define MODE_ABSOLUTE (0x04) /* The record number is given in P1 */
+#define MODE_NEXT (0x02) /* Next record */
+#define MODE_PREVIOUS (0x03) /* Previous record */
+
/*
* TODO: CDMA/IMS
*
@@ -86,11 +87,18 @@
guint query_passwd_state_timeout_id;
};
+struct ril_sim_io_response {
+ guint sw1, sw2;
+ guchar* data;
+ guint data_len;
+};
+
struct ril_sim_cbd {
struct ril_sim *sd;
union _ofono_sim_cb {
ofono_sim_file_info_cb_t file_info;
ofono_sim_read_cb_t read;
+ ofono_sim_write_cb_t write;
ofono_sim_imsi_cb_t imsi;
ofono_sim_pin_retries_cb_t retries;
ofono_query_facility_lock_cb_t query_facility_lock;
@@ -252,41 +260,112 @@
}
}
-static guchar *ril_sim_parse_io_response(const void *data, guint len,
- int *sw1, int *sw2, int *hex_len)
+static struct ril_sim_io_response *ril_sim_parse_io_response(const void *data,
+ guint len)
{
+ struct ril_sim_io_response *res = NULL;
GRilIoParser rilp;
- char *response = NULL;
- guchar *hex_response = NULL;
+ int sw1, sw2;
- /* Minimum length of SIM_IO_Response is 12:
- * sw1 (int32)
- * sw2 (int32)
- * simResponse (string)
- */
- if (len < 12) {
- ofono_error("SIM IO reply too small (< 12): %d", len);
- return NULL;
+ grilio_parser_init(&rilp, data, len);
+
+ if (grilio_parser_get_int32(&rilp, &sw1) &&
+ grilio_parser_get_int32(&rilp, &sw2)) {
+ char *hex_data = grilio_parser_get_utf8(&rilp);
+
+ DBG("sw1=0x%02X,sw2=0x%02X,%s", sw1, sw2, hex_data);
+ res = g_slice_new0(struct ril_sim_io_response);
+ res->sw1 = sw1;
+ res->sw2 = sw2;
+ if (hex_data) {
+ long num_bytes = 0;
+ res->data = decode_hex(hex_data, -1, &num_bytes, 0);
+ res->data_len = num_bytes;
+ g_free(hex_data);
+ }
}
- DBG("length is: %d", len);
- grilio_parser_init(&rilp, data, len);
- grilio_parser_get_int32(&rilp, sw1);
- grilio_parser_get_int32(&rilp, sw2);
+ return res;
+}
+
+static gboolean ril_sim_io_response_ok(const struct ril_sim_io_response *res)
+{
+ if (res) {
+ static const struct ril_sim_io_error {
+ int sw;
+ const char* msg;
+ } errmsg [] = {
+ /* TS 102.221 */
+ { 0x6a80, "Incorrect parameters in the data field" },
+ { 0x6a81, "Function not supported" },
+ { 0x6a82, "File not found" },
+ { 0x6a83, "Record not found" },
+ { 0x6a84, "Not enough memory space" },
+ { 0x6a86, "Incorrect parameters P1 to P2" },
+ { 0x6a87, "Lc inconsistent with P1 to P2" },
+ { 0x6a88, "Referenced data not found" },
+ /* TS 51.011 */
+ { 0x9240, "Memory problem" },
+ { 0x9400, "No EF selected" },
+ { 0x9402, "Out of range (invalid address)" },
+ { 0x9404, "File id/pattern not found" },
+ { 0x9408, "File is inconsistent with the command" }
+ };
+
+ int low, high, sw;
+
+ switch (res->sw1) {
+ case 0x90:
+ /* '90 00' is the normal completion */
+ if (res->sw2 != 0x00) {
+ break;
+ }
+ /* fall through */
+ case 0x91:
+ case 0x9e:
+ case 0x9f:
+ return TRUE;
+ case 0x92:
+ if (res->sw2 != 0x40) {
+ /* '92 40' is "memory problem" */
+ return TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Find the error message */
+ low = 0;
+ high = G_N_ELEMENTS(errmsg)-1;
+ sw = (res->sw1 << 8) | res->sw2;
+
+ while (low <= high) {
+ const int mid = (low + high)/2;
+ const int val = errmsg[mid].sw;
+ if (val < sw) {
+ low = mid + 1;
+ } else if (val > sw) {
+ high = mid - 1;
+ } else {
+ /* Message found */
+ DBG("error: %s", errmsg[mid].msg);
+ return FALSE;
+ }
+ }
- response = grilio_parser_get_utf8(&rilp);
- if (response) {
- long items_written = 0;
- const long response_len = strlen(response);
- DBG("response is set; len is: %ld", response_len);
- hex_response = decode_hex(response, response_len,
- &items_written, -1);
- *hex_len = items_written;
- }
-
- DBG("sw1=0x%.2X,sw2=0x%.2X,%s", *sw1, *sw2, response);
- g_free(response);
- return hex_response;
+ /* No message */
+ DBG("error %02x %02x", res->sw1, res->sw2);
+ }
+ return FALSE;
+}
+
+static void ril_sim_io_response_free(struct ril_sim_io_response *res)
+{
+ if (res) {
+ g_free(res->data);
+ g_slice_free(struct ril_sim_io_response, res);
+ }
}
static void ril_sim_file_info_cb(GRilIoChannel *io, int status,
@@ -295,17 +374,14 @@
struct ril_sim_cbd *cbd = user_data;
ofono_sim_file_info_cb_t cb = cbd->cb.file_info;
struct ril_sim *sd = cbd->sd;
+ struct ril_sim_io_response *res = NULL;
struct ofono_error error;
- gboolean ok = FALSE;
- int sw1 = 0, sw2 = 0, response_len = 0;
- int flen = 0, rlen = 0, str = 0;
- guchar *response = NULL;
- guchar access[3] = { 0x00, 0x00, 0x00 };
- guchar file_status = EF_STATUS_VALID;
|