summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2017-05-28 04:14:34 +0200
committerWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2017-05-28 04:14:34 +0200
commit3ba458b87c1974f26e9b50835c3c8e3cabb60a25 (patch)
tree8966230d99ca523aff61827c94ef7eb6b7ce5210
parent20bb9a83a8a6a1e8457194511620743727eed44b (diff)
downloadhardware_ril_samsung-ril-3ba458b87c1974f26e9b50835c3c8e3cabb60a25.zip
hardware_ril_samsung-ril-3ba458b87c1974f26e9b50835c3c8e3cabb60a25.tar.gz
hardware_ril_samsung-ril-3ba458b87c1974f26e9b50835c3c8e3cabb60a25.tar.bz2
first version
-rw-r--r--Android.mk1
-rw-r--r--samsung-ril.c14
-rw-r--r--samsung-ril.h8
-rw-r--r--ss.c284
-rw-r--r--utils.c155
-rw-r--r--utils.h11
6 files changed, 473 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
index 888d890..a7f53c6 100644
--- a/Android.mk
+++ b/Android.mk
@@ -33,6 +33,7 @@ LOCAL_SRC_FILES := \
network.c \
sound.c \
misc.c \
+ ss.c \
oem.c \
data.c \
rfs.c \
diff --git a/samsung-ril.c b/samsung-ril.c
index bcfb7ff..9f13b86 100644
--- a/samsung-ril.c
+++ b/samsung-ril.c
@@ -170,6 +170,11 @@ struct ipc_dispatch_handler ipc_fmt_dispatch_handlers[] = {
.command = IPC_MISC_TIME_INFO,
.handler = ipc_misc_time_info,
},
+ /* SS */
+ {
+ .command = IPC_SS_USSD,
+ .handler = ipc_ss_ussd,
+ },
/* OEM */
{
.command = IPC_SVC_DISPLAY_SCREEN,
@@ -440,6 +445,15 @@ struct ril_request_handler ril_request_handlers[] = {
.request = RIL_REQUEST_SCREEN_STATE,
.handler = ril_request_screen_state,
},
+ /* SS */
+ {
+ .request = RIL_REQUEST_SEND_USSD,
+ .handler = ril_request_send_ussd,
+ },
+ {
+ .request = RIL_REQUEST_CANCEL_USSD,
+ .handler = ril_request_cancel_ussd,
+ },
/* OEM */
{
.request = RIL_REQUEST_OEM_HOOK_RAW,
diff --git a/samsung-ril.h b/samsung-ril.h
index 497e72c..28a731f 100644
--- a/samsung-ril.h
+++ b/samsung-ril.h
@@ -366,6 +366,14 @@ int ipc_misc_time_info(struct ipc_message *message);
int ril_request_screen_state(void *data, size_t size, RIL_Token token);
/*
+ * SS
+ */
+
+int ipc_ss_ussd(struct ipc_message *message);
+int ril_request_send_ussd(void *data, size_t size, RIL_Token token);
+int ril_request_cancel_ussd(void *data, size_t size, RIL_Token token);
+
+/*
* OEM
*/
diff --git a/ss.c b/ss.c
new file mode 100644
index 0000000..45fc48d
--- /dev/null
+++ b/ss.c
@@ -0,0 +1,284 @@
+/*
+ * This file is part of Samsung-RIL.
+ *
+ * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr>
+ * Copyright (C) 2017 Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>
+ *
+ * Samsung-RIL is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Samsung-RIL 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 Samsung-RIL. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define LOG_TAG "RIL-SS"
+#include <utils/Log.h>
+
+#include <samsung-ril.h>
+#include <utils.h>
+
+unsigned char global_ussd_state;
+
+int ipc_ss_ussd_callback(struct ipc_message *message)
+{
+ struct ipc_gen_phone_res_data *data;
+ int rc;
+
+ if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_gen_phone_res_data))
+ return -1;
+
+ data = (struct ipc_gen_phone_res_data *) message->data;
+
+ rc = ipc_gen_phone_res_check(data);
+ if (rc < 0) {
+ RIL_LOGE("There was an error, aborting USSD request");
+ goto error;
+ }
+
+ ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, NULL, 0);
+ global_ussd_state = 0;
+ goto complete;
+
+error:
+ ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
+
+complete:
+ return 0;
+}
+
+int ril_request_send_ussd(void *data, size_t size, RIL_Token token)
+{
+ char *data_enc = NULL;
+ int data_enc_len = 0;
+ char *message =NULL;
+ struct ipc_ss_ussd_header *ussd = NULL;
+ int message_size = 0xc0;
+ int rc;
+
+ if (data == NULL || size < sizeof(char *))
+ goto error;
+
+ rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
+ if (rc < 0)
+ return RIL_REQUEST_UNHANDLED;
+
+ switch (global_ussd_state) {
+ case 0:
+ case IPC_SS_USSD_NO_ACTION_REQUIRE:
+ case IPC_SS_USSD_TERMINATED_BY_NET:
+ case IPC_SS_USSD_OTHER_CLIENT:
+ case IPC_SS_USSD_NOT_SUPPORT:
+ case IPC_SS_USSD_TIME_OUT:
+ RIL_LOGD("USSD Tx encoding is GSM7");
+
+ data_enc_len = ascii2gsm7_ussd(data, (unsigned char**)&data_enc, (int) size);
+ if (data_enc_len > message_size) {
+ RIL_LOGE("USSD message size is too long, aborting");
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+ free(data_enc);
+
+ return RIL_REQUEST_COMPLETED;
+ }
+
+ message = malloc(message_size);
+ memset(message, 0, message_size);
+
+ ussd = (struct ipc_ss_ussd_header *) message;
+ ussd->state = IPC_SS_USSD_NO_ACTION_REQUIRE;
+ ussd->dcs = 0x0f; // GSM7 in that case
+ ussd->length = data_enc_len;
+
+ memcpy((void *) (message + sizeof(struct ipc_ss_ussd_header)), data_enc, data_enc_len);
+
+ free(data_enc);
+
+ break;
+ case IPC_SS_USSD_ACTION_REQUIRE:
+ default:
+ RIL_LOGD("USSD Tx encoding is ASCII");
+
+ data_enc_len = asprintf(&data_enc, "%s", (char*)data);
+
+ if (data_enc_len > message_size) {
+ RIL_LOGE("USSD message size is too long, aborting");
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+ free(data_enc);
+
+ return RIL_REQUEST_COMPLETED;
+ }
+
+ message = malloc(message_size);
+ memset(message, 0, message_size);
+
+ ussd = (struct ipc_ss_ussd_header *) message;
+ ussd->state = IPC_SS_USSD_ACTION_REQUIRE;
+ ussd->dcs = 0x0f; // ASCII in that case
+ ussd->length = data_enc_len;
+
+ memcpy((void *) (message + sizeof(struct ipc_ss_ussd_header)), data_enc, data_enc_len);
+
+ free(data_enc);
+
+ break;
+ }
+
+ if (message == NULL) {
+ RIL_LOGE("USSD message is empty, aborting");
+
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+ return RIL_REQUEST_COMPLETED;
+ }
+
+ ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SS_USSD,
+ ipc_ss_ussd_callback);
+
+ rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SS_USSD, IPC_TYPE_EXEC, (void *) message, message_size);
+ if (rc < 0)
+ goto error;
+
+ rc = RIL_REQUEST_HANDLED;
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+ return RIL_REQUEST_COMPLETED;
+complete:
+ return rc;
+}
+
+int ril_request_cancel_ussd(void *data, size_t size, RIL_Token token)
+{
+ struct ipc_ss_ussd_header ussd;
+ int rc;
+
+ rc = ril_radio_state_check(RADIO_STATE_SIM_READY);
+ if (rc < 0)
+ return RIL_REQUEST_UNHANDLED;
+
+ memset(&ussd, 0, sizeof(ussd));
+
+ ussd.state = IPC_SS_USSD_TERMINATED_BY_NET;
+ global_ussd_state = IPC_SS_USSD_TERMINATED_BY_NET;
+
+ rc = ipc_gen_phone_res_expect_complete(ipc_fmt_request_seq(token), IPC_SS_USSD);
+ if (rc < 0)
+ goto error;
+
+ rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SS_USSD, IPC_TYPE_EXEC, (void *) &ussd, sizeof(ussd));
+ if (rc < 0)
+ goto error;
+
+ rc = RIL_REQUEST_HANDLED;
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+ rc = RIL_REQUEST_COMPLETED;
+
+complete:
+ return rc;
+}
+
+void ipc2ril_ussd_state(struct ipc_ss_ussd_header *ussd, char *message[2])
+{
+ if (ussd == NULL || message == NULL)
+ return;
+
+ switch (ussd->state) {
+ case IPC_SS_USSD_NO_ACTION_REQUIRE:
+ asprintf(&message[0], "%d", 0);
+ break;
+ case IPC_SS_USSD_ACTION_REQUIRE:
+ asprintf(&message[0], "%d", 1);
+ break;
+ case IPC_SS_USSD_TERMINATED_BY_NET:
+ asprintf(&message[0], "%d", 2);
+ break;
+ case IPC_SS_USSD_OTHER_CLIENT:
+ asprintf(&message[0], "%d", 3);
+ break;
+ case IPC_SS_USSD_NOT_SUPPORT:
+ asprintf(&message[0], "%d", 4);
+ break;
+ case IPC_SS_USSD_TIME_OUT:
+ asprintf(&message[0], "%d", 5);
+ break;
+ }
+}
+
+int ipc_ss_ussd(struct ipc_message *message)
+{
+ char *data_dec = NULL;
+ int data_dec_len = 0;
+ sms_coding_scheme coding_scheme;
+
+ char *ussd_message[2];
+
+ struct ipc_ss_ussd_header *ussd = NULL;
+ unsigned char state;
+
+ if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_ss_ussd_header))
+ goto error;
+
+ memset(ussd_message, 0, sizeof(ussd_message));
+
+ ussd = (struct ipc_ss_ussd_header *) message->data;
+
+ ipc2ril_ussd_state(ussd, ussd_message);
+
+ global_ussd_state = ussd->state;
+
+ if (ussd->length > 0 && message->size > 0 && message->data != NULL) {
+ coding_scheme = sms_get_coding_scheme(ussd->dcs);
+ switch (coding_scheme) {
+ case SMS_CODING_SCHEME_GSM7:
+ RIL_LOGD("USSD Rx encoding is GSM7");
+
+ data_dec_len = gsm72ascii((unsigned char *) message->data
+ + sizeof(struct ipc_ss_ussd_header), &data_dec, message->size - sizeof(struct ipc_ss_ussd_header));
+ asprintf(&ussd_message[1], "%s", data_dec);
+ ussd_message[1][data_dec_len] = '\0';
+
+ break;
+ case SMS_CODING_SCHEME_UCS2:
+ RIL_LOGD("USSD Rx encoding %x is UCS2", ussd->dcs);
+
+ data_dec_len = message->size - sizeof(struct ipc_ss_ussd_header);
+ ussd_message[1] = malloc(data_dec_len * 4 + 1);
+
+ int i, result = 0;
+ char *ucs2 = (char*)message->data + sizeof(struct ipc_ss_ussd_header);
+ for (i = 0; i < data_dec_len; i += 2) {
+ int c = (ucs2[i] << 8) | ucs2[1 + i];
+ result += utf8_write(ussd_message[1], result, c);
+ }
+ ussd_message[1][result] = '\0';
+ break;
+ default:
+ RIL_LOGD("USSD Rx encoding %x is unknown, assuming ASCII",
+ ussd->dcs);
+
+ data_dec_len = message->size - sizeof(struct ipc_ss_ussd_header);
+ asprintf(&ussd_message[1], "%s", (unsigned char *) message->data + sizeof(struct ipc_ss_ussd_header));
+ ussd_message[1][data_dec_len] = '\0';
+ break;
+ }
+ }
+
+ ril_request_unsolicited(RIL_UNSOL_ON_USSD, ussd_message, sizeof(ussd_message));
+
+ return 0;
+
+error:
+ ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
+ return 0;
+}
diff --git a/utils.c b/utils.c
index 164812e..80b95e7 100644
--- a/utils.c
+++ b/utils.c
@@ -61,6 +61,161 @@ void list_head_free(struct list_head *list)
free(list);
}
+/*
+ * Converts GSM7 (8 bits) data to ASCII (7 bits)
+ */
+int gsm72ascii(unsigned char *data, char **data_dec, int length)
+{
+ int t, u, d, o = 0;
+ int i;
+
+ int dec_length;
+ char *dec;
+
+ dec_length = ((length * 8) - ((length * 8) % 7) ) / 7;
+ dec = malloc(dec_length);
+
+ memset(dec, 0, dec_length);
+
+ for (i = 0 ; i < length ; i++)
+ {
+ d = 7 - i % 7;
+ if (d == 7 && i != 0)
+ o++;
+
+ t = (data[i] - (((data[i] >> d) & 0xff) << d));
+ u = (data[i] >> d) & 0xff;
+
+ dec[i+o]+=t << (i + o) % 8;
+
+ if (u)
+ dec[i+1+o]+=u;
+ }
+
+ *data_dec = dec;
+
+ return dec_length;
+}
+
+/*
+ * Converts ASCII (7 bits) data to GSM7 (8 bits)
+ */
+int ascii2gsm7_ussd(char *data, unsigned char **data_enc, int length)
+{
+ int d_off, d_pos, a_off, a_pos = 0;
+ int i;
+
+ int enc_length;
+ unsigned char *enc;
+
+ enc_length = ((length * 7) - (length * 7) % 8) / 8;
+ enc_length += (length * 7) % 8 > 0 ? 1 : 0;
+
+ //FIXME: why does samsung does that?
+ enc_length++;
+
+ enc = malloc(enc_length);
+ memset(enc, 0, enc_length);
+
+ for (i = 0 ; i < length ; i++)
+ {
+ // offset from the right of data to keep
+ d_off = i % 8;
+
+ // position of the data we keep
+ d_pos = ((i * 7) - (i * 7) % 8) / 8;
+ d_pos += (i * 7) % 8 > 0 ? 1 : 0;
+
+ // adding the data with correct offset
+ enc[d_pos] |= data[i] >> d_off;
+
+ // numbers of bits to omit to get data to add another place
+ a_off = 8 - d_off;
+ // position (on the encoded feed) of the data to add
+ a_pos = d_pos - 1;
+
+ // adding the data to add at the correct position
+ enc[a_pos] |= data[i] << a_off;
+ }
+
+ *data_enc = enc;
+
+ //FIXME: what is going on here?
+ enc[enc_length - 2] |= 0x30;
+ enc[enc_length - 1] = 0x02;
+
+ return enc_length;
+}
+
+/* writes the utf8 character encoded in v
+ * to the buffer utf8 at the specified offset
+ */
+int utf8_write(char *utf8, int offset, int v)
+{
+
+ int result;
+
+ if (v < 0x80) {
+ result = 1;
+ if (utf8)
+ utf8[offset] = (char)v;
+ } else if (v < 0x800) {
+ result = 2;
+ if (utf8) {
+ utf8[offset + 0] = (char)(0xc0 | (v >> 6));
+ utf8[offset + 1] = (char)(0x80 | (v & 0x3f));
+ }
+ } else if (v < 0x10000) {
+ result = 3;
+ if (utf8) {
+ utf8[offset + 0] = (char)(0xe0 | (v >> 12));
+ utf8[offset + 1] = (char)(0x80 | ((v >> 6) & 0x3f));
+ utf8[offset + 2] = (char)(0x80 | (v & 0x3f));
+ }
+ } else {
+ result = 4;
+ if (utf8) {
+ utf8[offset + 0] = (char)(0xf0 | ((v >> 18) & 0x7));
+ utf8[offset + 1] = (char)(0x80 | ((v >> 12) & 0x3f));
+ utf8[offset + 2] = (char)(0x80 | ((v >> 6) & 0x3f));
+ utf8[offset + 3] = (char)(0x80 | (v & 0x3f));
+ }
+ }
+ return result;
+}
+
+sms_coding_scheme sms_get_coding_scheme(int data_encoding)
+{
+ switch (data_encoding >> 4) {
+ case 0x00:
+ case 0x02:
+ case 0x03:
+ return SMS_CODING_SCHEME_GSM7;
+ case 0x01:
+ if (data_encoding == 0x10)
+ return SMS_CODING_SCHEME_GSM7;
+ if (data_encoding == 0x11)
+ return SMS_CODING_SCHEME_UCS2;
+ break;
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ if (data_encoding & 0x20)
+ return SMS_CODING_SCHEME_UNKNOWN;
+ if (((data_encoding >> 2) & 3) == 0)
+ return SMS_CODING_SCHEME_GSM7;
+ if (((data_encoding >> 2) & 3) == 2)
+ return SMS_CODING_SCHEME_UCS2;
+ break;
+ case 0xF:
+ if (!(data_encoding & 4))
+ return SMS_CODING_SCHEME_GSM7;
+ break;
+ }
+ return SMS_CODING_SCHEME_UNKNOWN;
+}
+
int data_dump(const void *data, size_t size)
{
unsigned int cols = 8;
diff --git a/utils.h b/utils.h
index f651d35..21a8add 100644
--- a/utils.h
+++ b/utils.h
@@ -33,10 +33,21 @@ struct list_head {
struct list_head *list_head_alloc(struct list_head *prev, struct list_head *next,
const void *data);
void list_head_free(struct list_head *list);
+int gsm72ascii(unsigned char *data, char **data_dec, int length);
+int ascii2gsm7_ussd(char *data, unsigned char **data_enc, int length);
+int utf8_write(char *utf8, int offset, int v);
int data_dump(const void *data, size_t size);
int strings_array_free(char **array, size_t size);
int eventfd_flush(int fd);
int eventfd_recv(int fd, eventfd_t *event);
int eventfd_send(int fd, eventfd_t event);
+typedef enum {
+ SMS_CODING_SCHEME_UNKNOWN = 0,
+ SMS_CODING_SCHEME_GSM7,
+ SMS_CODING_SCHEME_UCS2
+} sms_coding_scheme;
+
+sms_coding_scheme sms_get_coding_scheme(int data_encoding);
+
#endif