diff options
Diffstat (limited to 'gril/grilrequest.c')
-rw-r--r-- | gril/grilrequest.c | 1161 |
1 files changed, 1161 insertions, 0 deletions
diff --git a/gril/grilrequest.c b/gril/grilrequest.c new file mode 100644 index 00000000..3571c6ba --- /dev/null +++ b/gril/grilrequest.c @@ -0,0 +1,1161 @@ +/* + * + * RIL library with GLib integration + * + * Copyright (C) 2008-2011 Intel Corporation. All rights reserved. + * Copyright (C) 2012-2014 Canonical Ltd. + * Copyright (C) 2015 Ratchanan Srirattanamet. + * + * 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 + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> + +#include <glib.h> + +#include <ofono/log.h> +#include <ofono/modem.h> +#include <ofono/gprs-context.h> + +#include "grilrequest.h" +#include "simutil.h" +#include "util.h" +#include "common.h" + +/* DEACTIVATE_DATA_CALL request parameters */ +#define DEACTIVATE_DATA_CALL_NUM_PARAMS 2 + +/* POWER request parameters */ +#define POWER_PARAMS 1 + +/* SETUP_DATA_CALL_PARAMS request parameters */ +#define SETUP_DATA_CALL_PARAMS 7 +#define DATA_PROFILE_DEFAULT_STR "0" +#define DATA_PROFILE_TETHERED_STR "1" +#define DATA_PROFILE_IMS_STR "2" +#define DATA_PROFILE_FOTA_STR "3" +#define DATA_PROFILE_CBS_STR "4" +#define DATA_PROFILE_OEM_BASE_STR "1000" +#define DATA_PROFILE_MTK_MMS_STR "1001" + +/* SETUP_DATA_CALL_PARAMS reply parameters */ +#define MIN_DATA_CALL_REPLY_SIZE 36 + +/* Commands defined for TS 27.007 +CRSM */ +#define CMD_READ_BINARY 176 /* 0xB0 */ +#define CMD_READ_RECORD 178 /* 0xB2 */ +#define CMD_GET_RESPONSE 192 /* 0xC0 */ +#define CMD_UPDATE_BINARY 214 /* 0xD6 */ +#define CMD_UPDATE_RECORD 220 /* 0xDC */ +#define CMD_STATUS 242 /* 0xF2 */ +#define CMD_RETRIEVE_DATA 203 /* 0xCB */ +#define CMD_SET_DATA 219 /* 0xDB */ + +/* FID/path of SIM/USIM root directory */ +#define ROOTMF ((char[]) {'\x3F', '\x00'}) +#define ROOTMF_SZ sizeof(ROOTMF) + +/* RIL_Request* parameter counts */ +#define GET_IMSI_NUM_PARAMS 1 +#define ENTER_SIM_PIN_PARAMS 2 +#define SET_FACILITY_LOCK_PARAMS 5 +#define ENTER_SIM_PUK_PARAMS 3 +#define CHANGE_SIM_PIN_PARAMS 3 + +/* RIL_FACILITY_LOCK parameters */ +#define RIL_FACILITY_UNLOCK "0" +#define RIL_FACILITY_LOCK "1" + +/* Call ID should not really be a big number */ +#define MAX_CID_DIGITS 3 + +#define OFONO_EINVAL(error) do { \ + error->type = OFONO_ERROR_TYPE_FAILURE; \ + error->error = -EINVAL; \ +} while (0) + +#define OFONO_NO_ERROR(error) do { \ + error->type = OFONO_ERROR_TYPE_NO_ERROR; \ + error->error = 0; \ +} while (0) + +/* + * TODO: + * + * A potential future change here is to create a driver + * abstraction for each request/reply/event method, and a + * corresponding method to allow new per-message implementations + * to be registered. This would allow PES to easily add code + * to quirk a particular RIL implementation. + * + * struct g_ril_messages_driver { + * const char *name; + * }; + * + */ + +static gboolean set_path(GRil *ril, guint app_type, + struct parcel *rilp, + const int fileid, const guchar *path, + const guint path_len) +{ + unsigned char db_path[6] = { 0x00 }; + unsigned char *comm_path = db_path; + char *hex_path = NULL; + int len = 0; + + if (path_len > 0 && path_len < 7) { + memcpy(db_path, path, path_len); + len = path_len; + } else if (app_type == RIL_APPTYPE_USIM) { + len = sim_ef_db_get_path_3g(fileid, db_path); + } else if (app_type == RIL_APPTYPE_SIM) { + len = sim_ef_db_get_path_2g(fileid, db_path); + } else { + ofono_error("Unsupported app_type: 0%x", app_type); + return FALSE; + } + + /* + * db_path contains the ID of the MF, but MediaTek modems return an + * error if we do not remove it. Other devices work the other way + * around: they need the MF in the path. In fact MTK behaviour seem to + * be the right one: to have the MF in the file is forbidden following + * ETSI TS 102 221, section 8.4.2 (we are accessing the card in mode + * "select by path from MF", see 3gpp 27.007, +CRSM). + */ + if (g_ril_vendor(ril) == OFONO_RIL_VENDOR_MTK && len >= (int) ROOTMF_SZ + && memcmp(db_path, ROOTMF, ROOTMF_SZ) == 0) { + comm_path = db_path + ROOTMF_SZ; + len -= ROOTMF_SZ; + } + + if (len > 0) { + hex_path = encode_hex(comm_path, len, 0); + parcel_w_string(rilp, hex_path); + + g_ril_append_print_buf(ril, + "%spath=%s,", + print_buf, + hex_path); + + g_free(hex_path); + } else { + /* + * The only known case of this is EFPHASE_FILED (0x6FAE). + * The ef_db table ( see /src/simutil.c ) entry for + * EFPHASE contains a value of 0x0000 for it's + * 'parent3g' member. This causes a NULL path to + * be returned. + * (EF_PHASE does not exist for USIM) + */ + parcel_w_string(rilp, NULL); + + g_ril_append_print_buf(ril, + "%spath=(null),", + print_buf); + } + + return TRUE; +} + +gboolean g_ril_request_deactivate_data_call(GRil *gril, + const struct req_deactivate_data_call *req, + struct parcel *rilp, + struct ofono_error *error) +{ + gchar *cid_str = NULL; + gchar *reason_str = NULL; + + if (req->reason != RIL_DEACTIVATE_DATA_CALL_NO_REASON && + req->reason != RIL_DEACTIVATE_DATA_CALL_RADIO_SHUTDOWN) { + goto error; + } + + parcel_init(rilp); + parcel_w_int32(rilp, DEACTIVATE_DATA_CALL_NUM_PARAMS); + + cid_str = g_strdup_printf("%d", req->cid); + parcel_w_string(rilp, cid_str); + + /* + * TODO: airplane-mode; change reason to '1', + * which means "radio power off". + */ + reason_str = g_strdup_printf("%d", req->reason); + parcel_w_string(rilp, reason_str); + + g_ril_append_print_buf(gril, "(%s,%s)", cid_str, reason_str); + + g_free(cid_str); + g_free(reason_str); + + OFONO_NO_ERROR(error); + return TRUE; + +error: + OFONO_EINVAL(error); + return FALSE; +} + +void g_ril_request_power(GRil *gril, + const gboolean power, + struct parcel *rilp) +{ + DBG(""); + + parcel_init(rilp); + parcel_w_int32(rilp, POWER_PARAMS); + parcel_w_int32(rilp, (int32_t) power); + + g_ril_append_print_buf(gril, "(%d)", power); +} + +void g_ril_request_set_net_select_manual(GRil *gril, + const char *mccmnc, + struct parcel *rilp) +{ + DBG(""); + + parcel_init(rilp); + parcel_w_string(rilp, mccmnc); + + g_ril_append_print_buf(gril, "(%s)", mccmnc); +} + +gboolean g_ril_request_setup_data_call(GRil *gril, + const struct req_setup_data_call *req, + struct parcel *rilp, + struct ofono_error *error) +{ + const gchar *protocol_str; + gchar *tech_str; + gchar *auth_str; + gchar *profile_str; + int num_param = SETUP_DATA_CALL_PARAMS; + + DBG(""); + + if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK) + num_param = SETUP_DATA_CALL_PARAMS + 1; + + /* + * Radio technology to use: 0-CDMA, 1-GSM/UMTS, 2... + * values > 2 are (RADIO_TECH + 2) + */ + if (req->tech < 1 || req->tech > (RADIO_TECH_GSM + 2)) { + ofono_error("%s: Invalid tech value: %d", + __func__, + req->tech); + goto error; + } + + /* + * TODO(OEM): This code doesn't currently support + * OEM data profiles. If a use case exist, then + * this code will need to be modified. + */ + switch (req->data_profile) { + case RIL_DATA_PROFILE_DEFAULT: + profile_str = DATA_PROFILE_DEFAULT_STR; + break; + case RIL_DATA_PROFILE_TETHERED: + profile_str = DATA_PROFILE_TETHERED_STR; + break; + case RIL_DATA_PROFILE_IMS: + profile_str = DATA_PROFILE_IMS_STR; + break; + case RIL_DATA_PROFILE_FOTA: + profile_str = DATA_PROFILE_FOTA_STR; + break; + case RIL_DATA_PROFILE_CBS: + profile_str = DATA_PROFILE_CBS_STR; + break; + case RIL_DATA_PROFILE_MTK_MMS: + if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK) { + profile_str = DATA_PROFILE_MTK_MMS_STR; + break; + } + default: + ofono_error("%s, invalid data_profile value: %d", + __func__, + req->data_profile); + goto error; + } + + if (req->apn == NULL) + goto error; + + if (req->auth_type > RIL_AUTH_BOTH) { + ofono_error("%s: Invalid auth type: %d", + __func__, + req->auth_type); + goto error; + } + + protocol_str = ril_ofono_protocol_to_ril_string(req->protocol); + if (protocol_str == NULL) { + ofono_error("%s: Invalid protocol: %d", + __func__, + req->protocol); + goto error; + } + + parcel_init(rilp); + + parcel_w_int32(rilp, num_param); + + tech_str = g_strdup_printf("%d", req->tech); + parcel_w_string(rilp, tech_str); + parcel_w_string(rilp, profile_str); + parcel_w_string(rilp, req->apn); + parcel_w_string(rilp, req->username); + parcel_w_string(rilp, req->password); + + auth_str = g_strdup_printf("%d", req->auth_type); + parcel_w_string(rilp, auth_str); + parcel_w_string(rilp, protocol_str); + + g_ril_append_print_buf(gril, + "(%s,%s,%s,%s,%s,%s,%s", + tech_str, + profile_str, + req->apn, + req->username, + req->password, + auth_str, + protocol_str); + + if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK) { + /* MTK request_cid parameter */ + char cid_str[MAX_CID_DIGITS + 1]; + + snprintf(cid_str, sizeof(cid_str), "%u", req->req_cid); + parcel_w_string(rilp, cid_str); + g_ril_append_print_buf(gril, "%s,%s", print_buf, cid_str); + } + + g_ril_append_print_buf(gril, "%s)", print_buf); + + g_free(tech_str); + g_free(auth_str); + + OFONO_NO_ERROR(error); + return TRUE; + +error: + OFONO_EINVAL(error); + return FALSE; +} + +gboolean g_ril_request_sim_read_info(GRil *gril, + const struct req_sim_read_info *req, + struct parcel *rilp) +{ + parcel_init(rilp); + + parcel_w_int32(rilp, CMD_GET_RESPONSE); + parcel_w_int32(rilp, req->fileid); + + g_ril_append_print_buf(gril, + "(cmd=0x%.2X,efid=0x%.4X,", + CMD_GET_RESPONSE, + req->fileid); + + if (set_path(gril, req->app_type, rilp, req->fileid, + req->path, req->path_len) == FALSE) + goto error; + + parcel_w_int32(rilp, 0); /* P1 */ + parcel_w_int32(rilp, 0); /* P2 */ + + /* + * TODO: review parameters values used by Android. + * The values of P1-P3 in this code were based on + * values used by the atmodem driver impl. + * + * NOTE: + * GET_RESPONSE_EF_SIZE_BYTES == 15; !255 + */ + parcel_w_int32(rilp, 15); /* P3 - max length */ + parcel_w_string(rilp, NULL); /* data; only req'd for writes */ + parcel_w_string(rilp, NULL); /* pin2; only req'd for writes */ + parcel_w_string(rilp, req->aid_str); /* AID (Application ID) */ + + /* + * sessionId, specific to latest MTK modems (harmless for older ones). + * It looks like this field selects one or another SIM application, but + * we use only one at a time so using zero here seems safe. + */ + if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK) + parcel_w_int32(rilp, 0); + + return TRUE; + +error: + return FALSE; +} + +gboolean g_ril_request_sim_read_binary(GRil *gril, + const struct req_sim_read_binary *req, + struct parcel *rilp) +{ + g_ril_append_print_buf(gril, + "(cmd=0x%.2X,efid=0x%.4X,", + CMD_READ_BINARY, + req->fileid); + + parcel_init(rilp); + parcel_w_int32(rilp, CMD_READ_BINARY); + parcel_w_int32(rilp, req->fileid); + + if (set_path(gril, req->app_type, rilp, req->fileid, + req->path, req->path_len) == FALSE) + goto error; + + parcel_w_int32(rilp, (req->start >> 8)); /* P1 */ + parcel_w_int32(rilp, (req->start & 0xff)); /* P2 */ + parcel_w_int32(rilp, req->length); /* P3 */ + parcel_w_string(rilp, NULL); /* data; only req'd for writes */ + parcel_w_string(rilp, NULL); /* pin2; only req'd for writes */ + parcel_w_string(rilp, req->aid_str); + + /* sessionId, specific to latest MTK modems (harmless for older ones) */ + if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK) + parcel_w_int32(rilp, 0); + + return TRUE; + +error: + return FALSE; +} + +gboolean g_ril_request_sim_read_record(GRil *gril, + const struct req_sim_read_record *req, + struct parcel *rilp) +{ + parcel_init(rilp); + parcel_w_int32(rilp, CMD_READ_RECORD); + parcel_w_int32(rilp, req->fileid); + + g_ril_append_print_buf(gril, + "(cmd=0x%.2X,efid=0x%.4X,", + CMD_READ_RECORD, + req->fileid); + + if (set_path(gril, req->app_type, rilp, req->fileid, + req->path, req->path_len) == FALSE) + goto error; + + parcel_w_int32(rilp, req->record); /* P1 */ + parcel_w_int32(rilp, 4); /* P2 */ + parcel_w_int32(rilp, req->length); /* P3 */ + parcel_w_string(rilp, NULL); /* data; only req'd for writes */ + parcel_w_string(rilp, NULL); /* pin2; only req'd for writes */ + parcel_w_string(rilp, req->aid_str); /* AID (Application ID) */ + + /* sessionId, specific to latest MTK modems (harmless for older ones) */ + if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK) + parcel_w_int32(rilp, 0); + + return TRUE; + +error: + return FALSE; +} + +gboolean g_ril_request_sim_write_binary(GRil *gril, + const struct req_sim_write_binary *req, + struct parcel *rilp) +{ + char *hex_data; + int p1, p2; + + parcel_init(rilp); + parcel_w_int32(rilp, CMD_UPDATE_BINARY); + parcel_w_int32(rilp, req->fileid); + + g_ril_append_print_buf(gril, "(cmd=0x%02X,efid=0x%04X,", + CMD_UPDATE_BINARY, req->fileid); + + if (set_path(gril, req->app_type, rilp, req->fileid, + req->path, req->path_len) == FALSE) + goto error; + + p1 = req->start >> 8; + p2 = req->start & 0xff; + hex_data = encode_hex(req->data, req->length, 0); + + parcel_w_int32(rilp, p1); /* P1 */ + parcel_w_int32(rilp, p2); /* P2 */ + parcel_w_int32(rilp, req->length); /* P3 (Lc) */ + parcel_w_string(rilp, hex_data); /* data */ + parcel_w_string(rilp, NULL); /* pin2; only for FDN/BDN */ + parcel_w_string(rilp, req->aid_str); /* AID (Application ID) */ + + /* sessionId, specific to latest MTK modems (harmless for older ones) */ + if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK) + parcel_w_int32(rilp, 0); + + g_ril_append_print_buf(gril, + "%s%d,%d,%d,%s,pin2=(null),aid=%s)", + print_buf, + p1, + p2, + req->length, + hex_data, + req->aid_str); + + g_free(hex_data); + + return TRUE; + +error: + return FALSE; +} + +static int get_sim_record_access_p2(enum req_record_access_mode mode) +{ + switch (mode) { + case GRIL_REC_ACCESS_MODE_CURRENT: + return 4; + case GRIL_REC_ACCESS_MODE_ABSOLUTE: + return 4; + case GRIL_REC_ACCESS_MODE_NEXT: + return 2; + case GRIL_REC_ACCESS_MODE_PREVIOUS: + return 3; + } + + return -1; +} + +gboolean g_ril_request_sim_write_record(GRil *gril, + const struct req_sim_write_record *req, + struct parcel *rilp) +{ + char *hex_data; + int p2; + + parcel_init(rilp); + parcel_w_int32(rilp, CMD_UPDATE_RECORD); + parcel_w_int32(rilp, req->fileid); + + g_ril_append_print_buf(gril, "(cmd=0x%02X,efid=0x%04X,", + CMD_UPDATE_RECORD, req->fileid); + + if (set_path(gril, req->app_type, rilp, req->fileid, + req->path, req->path_len) == FALSE) + goto error; + + p2 = get_sim_record_access_p2(req->mode); + hex_data = encode_hex(req->data, req->length, 0); + + parcel_w_int32(rilp, req->record); /* P1 */ + parcel_w_int32(rilp, p2); /* P2 (access mode) */ + parcel_w_int32(rilp, req->length); /* P3 (Lc) */ + parcel_w_string(rilp, hex_data); /* data */ + parcel_w_string(rilp, NULL); /* pin2; only for FDN/BDN */ + parcel_w_string(rilp, req->aid_str); /* AID (Application ID) */ + + /* sessionId, specific to latest MTK modems (harmless for older ones) */ + if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK) + parcel_w_int32(rilp, 0); + + g_ril_append_print_buf(gril, + "%s%d,%d,%d,%s,pin2=(null),aid=%s)", + print_buf, + req->record, + p2, + req->length, + hex_data, + req->aid_str); + + g_free(hex_data); + + return TRUE; + +error: + return FALSE; +} + +void g_ril_request_read_imsi(GRil *gril, + const gchar *aid_str, + struct parcel *rilp) +{ + parcel_init(rilp); + parcel_w_int32(rilp, GET_IMSI_NUM_PARAMS); + parcel_w_string(rilp, aid_str); + + g_ril_append_print_buf(gril, "(%d,%s)", GET_IMSI_NUM_PARAMS, aid_str); +} + +void g_ril_request_pin_send(GRil *gril, + const char *passwd, + const gchar *aid_str, + struct parcel *rilp) +{ + parcel_init(rilp); + + parcel_w_int32(rilp, ENTER_SIM_PIN_PARAMS); + parcel_w_string(rilp, passwd); + parcel_w_string(rilp, aid_str); + + g_ril_append_print_buf(gril, "(%s,aid=%s)", passwd, aid_str); +} + +gboolean g_ril_request_pin_change_state(GRil *gril, + const struct req_pin_change_state *req, + struct parcel *rilp) +{ + const char *lock_type; + + /* + * TODO: clean up the use of string literals & + * the multiple g_ril_append_print_buf() calls + * by using a table lookup as does the core sim code + */ + switch (req->passwd_type) { + case OFONO_SIM_PASSWORD_SIM_PIN: + g_ril_append_print_buf(gril, "(SC,"); + lock_type = "SC"; + break; + case OFONO_SIM_PASSWORD_PHSIM_PIN: + g_ril_append_print_buf(gril, "(PS,"); + lock_type = "PS"; + break; + case OFONO_SIM_PASSWORD_PHFSIM_PIN: + g_ril_append_print_buf(gril, "(PF,"); + lock_type = "PF"; + break; + case OFONO_SIM_PASSWORD_SIM_PIN2: + g_ril_append_print_buf(gril, "(P2,"); + lock_type = "P2"; + break; + case OFONO_SIM_PASSWORD_PHNET_PIN: + g_ril_append_print_buf(gril, "(PN,"); + lock_type = "PN"; + break; + case OFONO_SIM_PASSWORD_PHNETSUB_PIN: + g_ril_append_print_buf(gril, "(PU,"); + lock_type = "PU"; + break; + case OFONO_SIM_PASSWORD_PHSP_PIN: + g_ril_append_print_buf(gril, "(PP,"); + lock_type = "PP"; + break; + case OFONO_SIM_PASSWORD_PHCORP_PIN: + g_ril_append_print_buf(gril, "(PC,"); + lock_type = "PC"; + break; + default: + ofono_error("%s: Invalid password type: %d", + __func__, + req->passwd_type); + goto error; + } + + parcel_init(rilp); + parcel_w_int32(rilp, SET_FACILITY_LOCK_PARAMS); + + parcel_w_string(rilp, lock_type); + + if (req->enable) + parcel_w_string(rilp, RIL_FACILITY_LOCK); + else + parcel_w_string(rilp, RIL_FACILITY_UNLOCK); + + parcel_w_string(rilp, req->passwd); + + /* TODO: make this a constant... */ + parcel_w_string(rilp, "0"); /* class */ + + parcel_w_string(rilp, req->aid_str); + + g_ril_append_print_buf(gril, "(%s,%d,%s,0,aid=%s)", + print_buf, + req->enable, + req->passwd, + req->aid_str); + + return TRUE; + +error: + return FALSE; +} + +void g_ril_request_pin_send_puk(GRil *gril, + const char *puk, + const char *passwd, + const gchar *aid_str, + struct parcel *rilp) +{ + parcel_init(rilp); + + parcel_w_int32(rilp, ENTER_SIM_PUK_PARAMS); + parcel_w_string(rilp, puk); + parcel_w_string(rilp, passwd); + parcel_w_string(rilp, aid_str); + + g_ril_append_print_buf(gril, "(puk=%s,pin=%s,aid=%s)", + puk, passwd, aid_str); +} + +void g_ril_request_change_passwd(GRil *gril, + const char *old_passwd, + const char *new_passwd, + const gchar *aid_str, + struct parcel *rilp) +{ + parcel_init(rilp); + + parcel_w_int32(rilp, CHANGE_SIM_PIN_PARAMS); + parcel_w_string(rilp, old_passwd); + parcel_w_string(rilp, new_passwd); + parcel_w_string(rilp, aid_str); + + g_ril_append_print_buf(gril, "(old=%s,new=%s,aid=%s)", + old_passwd, new_passwd, aid_str); +} + +void g_ril_request_sms_cmgs(GRil *gril, + const struct req_sms_cmgs *req, + struct parcel *rilp) +{ + int smsc_len; + char *tpdu; + + parcel_init(rilp); + parcel_w_int32(rilp, 2); /* Number of strings */ + + /* + * SMSC address: + * + * smsc_len == 1, then zero-length SMSC was spec'd + * RILD expects a NULL string in this case instead + * of a zero-length string. + */ + smsc_len = req->pdu_len - req->tpdu_len; + /* TODO: encode SMSC & write to parcel */ + if (smsc_len > 1) + ofono_error("SMSC address specified (smsc_len %d); " + "NOT-IMPLEMENTED", smsc_len); + + parcel_w_string(rilp, NULL); /* SMSC address; NULL == default */ + + /* + * TPDU: + * + * 'pdu' is a raw hexadecimal string + * encode_hex() turns it into an ASCII/hex UTF8 buffer + * parcel_w_string() encodes utf8 -> utf16 + */ + tpdu = encode_hex(req->pdu + smsc_len, req->tpdu_len, 0); + parcel_w_string(rilp, tpdu); + + g_ril_append_print_buf(gril, "(%s)", tpdu); + + g_free(tpdu); +} + +void g_ril_request_sms_acknowledge(GRil *gril, + struct parcel *rilp) +{ + parcel_init(rilp); + parcel_w_int32(rilp, 2); /* Number of int32 values in array */ + parcel_w_int32(rilp, 1); /* Successful receipt */ + parcel_w_int32(rilp, 0); /* error code */ + + g_ril_append_print_buf(gril, "(1,0)"); +} + +void g_ril_request_set_smsc_address(GRil *gril, + const struct ofono_phone_number *sca, + struct parcel *rilp) +{ + char number[OFONO_MAX_PHONE_NUMBER_LENGTH + 4]; + + if (sca->type == OFONO_NUMBER_TYPE_INTERNATIONAL) + snprintf(number, sizeof(number), "\"+%s\"", sca->number); + else + snprintf(number, sizeof(number), "\"%s\"", sca->number); + + parcel_init(rilp); + parcel_w_string(rilp, number); + + g_ril_append_print_buf(gril, "(%s)", number); +} + +void g_ril_request_dial(GRil *gril, + const struct ofono_phone_number *ph, + enum ofono_clir_option clir, + struct parcel *rilp) +{ + parcel_init(rilp); + + /* Number to dial */ + parcel_w_string(rilp, phone_number_to_string(ph)); + /* CLIR mode */ + parcel_w_int32(rilp, clir); + /* USS, empty string */ + /* TODO: Deal with USS properly */ + parcel_w_int32(rilp, 0); + parcel_w_int32(rilp, 0); + + g_ril_append_print_buf(gril, "(%s,%d,0,0)", + phone_number_to_string(ph), + clir); +} + +void g_ril_request_hangup(GRil *gril, + unsigned call_id, + struct parcel *rilp) +{ + parcel_init(rilp); + parcel_w_int32(rilp, 1); /* Always 1 - AT+CHLD=1x */ + parcel_w_int32(rilp, call_id); + + g_ril_append_print_buf(gril, "(%u)", call_id); +} + +void g_ril_request_dtmf(GRil *gril, + char dtmf_char, + struct parcel *rilp) +{ + char ril_dtmf[2]; + + parcel_init(rilp); + /* Ril wants just one character, but we need to send as string */ + ril_dtmf[0] = dtmf_char; + ril_dtmf[1] = '\0'; + parcel_w_string(rilp, ril_dtmf); + + g_ril_append_print_buf(gril, "(%s)", ril_dtmf); +} + +void g_ril_request_separate_conn(GRil *gril, + int call_id, + struct parcel *rilp) +{ + parcel_init(rilp); + + /* Payload is an array that holds just one element */ + parcel_w_int32(rilp, 1); + parcel_w_int32(rilp, call_id); + + g_ril_append_print_buf(gril, "(%d)", call_id); +} + +void g_ril_request_set_supp_svc_notif(GRil *gril, + struct parcel *rilp) +{ + parcel_init(rilp); + parcel_w_int32(rilp, 1); /* size of array */ + parcel_w_int32(rilp, 1); /* notifications enabled */ + + g_ril_append_print_buf(gril, "(1)"); +} + +void g_ril_request_set_mute(GRil *gril, int muted, struct parcel *rilp) +{ + parcel_init(rilp); + + parcel_w_int32(rilp, 1); + parcel_w_int32(rilp, muted); + + g_ril_append_print_buf(gril, "(%d)", muted); +} + +void g_ril_request_send_ussd(GRil *gril, + const char *ussd, + struct parcel *rilp) +{ + parcel_init(rilp); + parcel_w_string(rilp, ussd); + + g_ril_append_print_buf(gril, "(%s)", ussd); +} + +void g_ril_request_set_call_waiting(GRil *gril, + int enabled, int serviceclass, + struct parcel *rilp) +{ + parcel_init(rilp); + + parcel_w_int32(rilp, 2); /* Number of params */ + parcel_w_int32(rilp, enabled); /* on/off */ + + /* + * 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 + * SERVICE_CLASS_VOICE effectively making it the + * default bearer. + */ + if (serviceclass == BEARER_CLASS_DEFAULT) + serviceclass = BEARER_CLASS_VOICE; + + parcel_w_int32(rilp, serviceclass); /* Service class */ + + g_ril_append_print_buf(gril, "(%d, 0x%x)", enabled, serviceclass); +} + +void g_ril_request_query_call_waiting(GRil *gril, + int serviceclass, + struct parcel *rilp) +{ + parcel_init(rilp); + + parcel_w_int32(rilp, 1); /* Number of params */ + /* + * RILD expects service class to be 0 as certain carriers can reject the + * query with specific service class + */ + parcel_w_int32(rilp, 0); + + g_ril_append_print_buf(gril, "(0)"); +} + +void g_ril_request_set_clir(GRil *gril, + int mode, + struct parcel *rilp) +{ + parcel_init(rilp); + + parcel_w_int32(rilp, 1); /* Number of params */ + parcel_w_int32(rilp, mode); + + g_ril_append_print_buf(gril, "(%d)", mode); +} + +void g_ril_request_screen_state(GRil *gril, + int state, + struct parcel *rilp) +{ + parcel_init(rilp); + parcel_w_int32(rilp, 1); /* Number of params */ + parcel_w_int32(rilp, state); + + g_ril_append_print_buf(gril, "(%d)", state); +} + +void g_ril_request_call_fwd(GRil *gril, const struct req_call_fwd *req, + struct parcel *rilp) +{ + parcel_init(rilp); + + parcel_w_int32(rilp, req->action); + parcel_w_int32(rilp, req->type); + parcel_w_int32(rilp, req->cls); + + g_ril_append_print_buf(gril, "(type: %d cls: %d ", req->type, req->cls); + + if (req->number != NULL) { + parcel_w_int32(rilp, req->number->type); + parcel_w_string(rilp, (char *) req->number->number); + + g_ril_append_print_buf(gril, "%s number type: %d number: " + "%s time: %d) ", print_buf, + req->number->type, req->number->number, + req->time); + } else { + /* + * The following values have no real meaning for + * activation/deactivation/erasure actions, but + * apparently rild expects them, so fields need to + * be filled. Otherwise there is no response. + */ + + parcel_w_int32(rilp, 0x81); /* TOA unknown */ + parcel_w_string(rilp, "1234567890"); + g_ril_append_print_buf(gril, "%s number type: %d number: " + "%s time: %d) ", print_buf, + 0x81, "1234567890", + req->time); + + } + + parcel_w_int32(rilp, req->time); +} + +void g_ril_request_set_preferred_network_type(GRil *gril, int net_type, + struct parcel *rilp) +{ + parcel_init(rilp); + + parcel_w_int32(rilp, 1); /* Number of params */ + parcel_w_int32(rilp, net_type); + + g_ril_append_print_buf(gril, "(%d)", net_type); +} + +void g_ril_request_query_facility_lock(GRil *gril, const char *facility, + const char *password, int services, + struct parcel *rilp) +{ + char svcs_str[4]; + + parcel_init(rilp); + + parcel_w_int32(rilp, 4); /* # of strings */ + parcel_w_string(rilp, facility); + parcel_w_string(rilp, password); + snprintf(svcs_str, sizeof(svcs_str), "%d", services); + parcel_w_string(rilp, svcs_str); + parcel_w_string(rilp, NULL); /* AID (for FDN, not yet supported) */ + + g_ril_append_print_buf(gril, "(%s,%s,%s,(null))", + facility, password, svcs_str); +} + +void g_ril_request_set_facility_lock(GRil *gril, const char *facility, + int enable, const char *passwd, + int services, struct parcel *rilp) +{ + char svcs_str[4]; + const char *enable_str; + + parcel_init(rilp); + + parcel_w_int32(rilp, 5); /* # of strings */ + parcel_w_string(rilp, facility); + if (enable) + enable_str = "1"; + else + enable_str = "0"; + parcel_w_string(rilp, enable_str); + parcel_w_string(rilp, passwd); + snprintf(svcs_str, sizeof(svcs_str), "%d", services); + parcel_w_string(rilp, svcs_str); + parcel_w_string(rilp, NULL); /* AID (for FDN, not yet supported) */ + + g_ril_append_print_buf(gril, "(%s,%s,%s,%s,(null))", + facility, enable_str, passwd, svcs_str); +} + +void g_ril_request_change_barring_password(GRil *gril, const char *facility, + const char *old_passwd, + const char *new_passwd, + struct parcel *rilp) +{ + parcel_init(rilp); + + parcel_w_int32(rilp, 3); /* # of strings */ + parcel_w_string(rilp, facility); + parcel_w_string(rilp, old_passwd); + parcel_w_string(rilp, new_passwd); + + g_ril_append_print_buf(gril, "(%s,%s,%s)", + facility, old_passwd, new_passwd); +} + +void g_ril_request_oem_hook_raw(GRil *gril, const void *payload, size_t length, + struct parcel *rilp) +{ + char *hex_dump = NULL; + + parcel_init(rilp); + parcel_w_raw(rilp, payload, length); + + if (payload != NULL) + hex_dump = encode_hex(payload, length, '\0'); + + g_ril_append_print_buf(gril, "(%s)", hex_dump ? hex_dump : "(null)"); + g_free(hex_dump); +} + +void g_ril_request_oem_hook_strings(GRil *gril, const char **strs, int num_str, + struct parcel *rilp) +{ + int i; + + parcel_init(rilp); + parcel_w_int32(rilp, num_str); + + g_ril_append_print_buf(gril, "("); + + for (i = 0; i < num_str; ++i) { + parcel_w_string(rilp, strs[i]); + + if (i == num_str - 1) + g_ril_append_print_buf(gril, "%s%s)", + print_buf, strs[i]); + else + g_ril_append_print_buf(gril, "%s%s, ", + print_buf, strs[i]); + } +} + +void g_ril_request_set_initial_attach_apn(GRil *gril, const char *apn, + int proto, + const char *user, + const char *passwd, + const char *mccmnc, + struct parcel *rilp) +{ + const char *proto_str; + const int auth_type = RIL_AUTH_ANY; + + parcel_init(rilp); + + parcel_w_string(rilp, apn); + + proto_str = ril_ofono_protocol_to_ril_string(proto); + parcel_w_string(rilp, proto_str); + + parcel_w_int32(rilp, auth_type); + parcel_w_string(rilp, user); + parcel_w_string(rilp, passwd); + + g_ril_append_print_buf(gril, "(%s,%s,%s,%s,%s", apn, proto_str, + ril_authtype_to_string(auth_type), + user, passwd); + + if (g_ril_vendor(gril) == OFONO_RIL_VENDOR_MTK) { + parcel_w_string(rilp, mccmnc); + g_ril_append_print_buf(gril, "%s,%s)", print_buf, mccmnc); + } else { + g_ril_append_print_buf(gril, "%s)", print_buf); + } +} + +void g_ril_request_set_uicc_subscription(GRil *gril, int slot_id, + int app_index, + int sub_id, + int sub_status, + struct parcel *rilp) +{ + parcel_init(rilp); + + parcel_w_int32(rilp, slot_id); + parcel_w_int32(rilp, app_index); + parcel_w_int32(rilp, sub_id); + parcel_w_int32(rilp, sub_status); + + g_ril_append_print_buf(gril, "(%d, %d, %d, %d(%s))", + slot_id, + app_index, + sub_id, + sub_status, + sub_status ? "ACTIVATE" : "DEACTIVATE"); +} |