--- Makefile.am | 3 +- src/cdma-sms.c | 342 ++++++++++++++++++++++++++++++++++++++ src/cdma-smsutil.c | 467 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/cdma-smsutil.h | 264 +++++++++++++++++++++++++++++ 4 files changed, 1075 insertions(+), 1 deletions(-) create mode 100644 src/cdma-sms.c create mode 100644 src/cdma-smsutil.c create mode 100644 src/cdma-smsutil.h diff --git a/Makefile.am b/Makefile.am index 13cbc37..b7dc5ee 100644 --- a/Makefile.am +++ b/Makefile.am @@ -319,7 +319,8 @@ src_ofonod_SOURCES = $(gdbus_sources) $(builtin_sources) src/ofono.ver \ src/radio-settings.c src/stkutil.h src/stkutil.c \ src/nettime.c src/stkagent.c src/stkagent.h \ src/simfs.c src/simfs.h src/audio-settings.c \ - src/smsagent.c src/smsagent.h src/ctm.c + src/smsagent.c src/smsagent.h src/ctm.c \ + src/cdma-sms.c src/cdma-smsutil.c src_ofonod_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@ @CAPNG_LIBS@ -ldl diff --git a/src/cdma-sms.c b/src/cdma-sms.c new file mode 100644 index 0000000..1271345 --- /dev/null +++ b/src/cdma-sms.c @@ -0,0 +1,342 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2010 Nokia Corporation. All rights reserved. + * + * 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 +#endif + +#include +#include +#include + +#include +#include +#include + +#include "ofono.h" + +#include "cdma-smsutil.h" +#include "cdma-sms.h" + +static GSList *g_drivers; + +struct ofono_cdmasms { + const struct ofono_cdmasms_driver *driver; + void *driver_data; + struct ofono_atom *atom; +}; + +static GDBusMethodTable cdmasms_manager_methods[] = { + /* TODO */ + { } +}; + +static GDBusSignalTable cdmasms_manager_signals[] = { + { "IncomingMessage", "sa{sv}" }, + /* TODO */ + { } +}; + +static void cdma_dispatch_text_message(struct ofono_cdmasms *cdmasms, + const char *message, + const char *oaddr) +{ + const char *path = ofono_cdmasms_get_path(cdmasms); + DBusConnection *conn = ofono_dbus_get_connection(); + DBusMessage *signal; + DBusMessageIter iter; + DBusMessageIter dict; + const char *signal_name; + + /* TODO: Support ImmediateMessage */ + signal_name = "IncomingMessage"; + + signal = dbus_message_new_signal(path, + OFONO_CDMA_MESSAGE_MANAGER_INTERFACE, + signal_name); + if (signal == NULL) + return; + + dbus_message_iter_init_append(signal, &iter); + + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, + &(message)); + + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + OFONO_PROPERTIES_ARRAY_SIGNATURE, &dict); + + ofono_dbus_dict_append(&dict, "Sender", DBUS_TYPE_STRING, + &oaddr); + + /* TODO: Other property not supported yet */ + + dbus_message_iter_close_container(&iter, &dict); + + g_dbus_send_message(conn, signal); + + /*TODO: Add the message to history*/ +} + +static void ofono_cdmasms_process_wmt_deliver(struct ofono_cdmasms *cdmasms, + struct cdma_sms *incoming) +{ + char *message; + char *oaddr; + + message = cdmasms_decode_text(&incoming->p2p_msg.bearer_data.ud); + if (message == NULL) + return; + + oaddr = cdmasms_address_to_string(&incoming->p2p_msg.oaddr); + if (oaddr == NULL) { + g_free(message); + return; + } + + cdma_dispatch_text_message(cdmasms, message, oaddr); + + g_free(message); + g_free(oaddr); +} + +static void ofono_cdmasms_process_wmt(struct ofono_cdmasms *cdmasms, + struct cdma_sms *incoming) +{ + if (!check_bitmap(incoming->p2p_msg.bearer_data.subparam_bitmap, + SMS_SUBPARAM_ID_MESSAGE_ID)) + return; + + /* TODO: Add duplicate detection support */ + + switch (incoming->p2p_msg.bearer_data.id.msg_type) { + case CDMASMS_RESERVED: + break; + case CDMASMS_DELIVER: + ofono_cdmasms_process_wmt_deliver(cdmasms, incoming); + break; + case CDMASMS_SUBMIT: + case CDMASMS_CANCEL: + case CDMASMS_DELIVER_ACK: + case CDMASMS_USER_ACK: + case CDMASMS_READ_ACK: + break; /* TODO */ + } +} + +static void ofono_cdmasms_process_p2p(struct ofono_cdmasms *cdmasms, + struct cdma_sms *incoming) +{ + /* Check validity of incoming message, per Table 3.4.2.1-1 */ + if (!(check_bitmap(incoming->p2p_msg.bearer_data.subparam_bitmap, + SMS_PARAM_ID_TELESERVICE_IDENTIFIER) + && + check_bitmap(incoming->p2p_msg.param_bitmap, + SMS_PARAM_ID_ORIGINATING_ADDRESS) + )) + return; + + switch (incoming->p2p_msg.teleservice_id) { + case TELESERVICE_CMT91: + case TELESERVICE_WPT: + break; /* TODO: Not supported yet */ + case TELESERVICE_WMT: + ofono_cdmasms_process_wmt(cdmasms, incoming); + break; + case TELESERVICE_VMN: + case TELESERVICE_WAP: + case TELESERVICE_WEMT: + case TELESERVICE_SCPT: + case TELESERVICE_CATPT: + break; /* TODO: Not supported yet */ + } +} + +void ofono_cdmasms_deliver_notify(struct ofono_cdmasms *cdmasms, + unsigned char *pdu, int pdu_len) +{ + struct cdma_sms s; + gboolean ret; + + DBG("pdu len %d", pdu_len); + + memset(&s, 0, sizeof(struct cdma_sms)); + + ret = cdmasms_decode(pdu, pdu_len, &s); + if (!ret) + return; + + switch (s.type) { + case CDMASMS_P2P: + ofono_cdmasms_process_p2p(cdmasms, &s); + break; + case CDMASMS_BCAST: + case CDMASMS_ACK: + /* + * TODO: Support SMS Broadcast Message and SMS + * Acknowledge Message. + */ + break; + } +} + +int ofono_cdmasms_driver_register(const struct ofono_cdmasms_driver *d) +{ + DBG("driver: %p, name: %s", d, d->name); + + if (d->probe == NULL) + return -EINVAL; + + g_drivers = g_slist_prepend(g_drivers, (void *)d); + + return 0; +} + +void ofono_cdmasms_driver_unregister(const struct ofono_cdmasms_driver *d) +{ + DBG("driver: %p, name: %s", d, d->name); + + g_drivers = g_slist_remove(g_drivers, (void *)d); +} + +static void cdmasms_unregister(struct ofono_atom *atom) +{ + DBusConnection *conn = ofono_dbus_get_connection(); + struct ofono_modem *modem = __ofono_atom_get_modem(atom); + const char *path = __ofono_atom_get_path(atom); + + g_dbus_unregister_interface(conn, path, + OFONO_CDMA_MESSAGE_MANAGER_INTERFACE); + + ofono_modem_remove_interface(modem, + OFONO_CDMA_MESSAGE_MANAGER_INTERFACE); +} + +static void cdmasms_remove(struct ofono_atom *atom) +{ + struct ofono_cdmasms *cdmasms = __ofono_atom_get_data(atom); + + DBG("atom: %p", atom); + + if (cdmasms == NULL) + return; + + if (cdmasms->driver && cdmasms->driver->remove) + cdmasms->driver->remove(cdmasms); + + g_free(cdmasms); +} + +/* + * Create a CDMA SMS driver + * + * This creates a CDMA SMS driver that is hung off a @modem + * object. However, for the driver to be used by the system, it has to + * be registered with the oFono core using ofono_sms_register(). + * + * This is done once the modem driver determines that SMS is properly + * supported by the hardware. + */ +struct ofono_cdmasms *ofono_cdmasms_create(struct ofono_modem *modem, + unsigned int vendor, + const char *driver, + void *data) +{ + struct ofono_cdmasms *cdmasms; + GSList *l; + + if (driver == NULL) + return NULL; + + cdmasms = g_try_new0(struct ofono_cdmasms, 1); + if (cdmasms == NULL) + return NULL; + + cdmasms->atom = __ofono_modem_add_atom(modem, OFONO_ATOM_TYPE_SMS, + cdmasms_remove, cdmasms); + + for (l = g_drivers; l; l = l->next) { + const struct ofono_cdmasms_driver *drv = l->data; + + if (g_strcmp0(drv->name, driver)) + continue; + + if (drv->probe(cdmasms, vendor, data) < 0) + continue; + + cdmasms->driver = drv; + break; + } + + return cdmasms; +} + +/* + * Indicate oFono that a CDMA SMS driver is ready for operation + * + * This is called after ofono_cdmasms_create() was done and the modem + * driver determined that a modem supports SMS correctly. Once this + * call succeeds, the D-BUS interface for SMS goes live. + */ +void ofono_cdmasms_register(struct ofono_cdmasms *cdmasms) +{ + DBusConnection *conn = ofono_dbus_get_connection(); + struct ofono_modem *modem = __ofono_atom_get_modem(cdmasms->atom); + const char *path = __ofono_atom_get_path(cdmasms->atom); + + if (!g_dbus_register_interface(conn, path, + OFONO_CDMA_MESSAGE_MANAGER_INTERFACE, + cdmasms_manager_methods, + cdmasms_manager_signals, + NULL, cdmasms, NULL)) { + ofono_error("Could not create %s interface", + OFONO_CDMA_MESSAGE_MANAGER_INTERFACE); + return; + } + + ofono_modem_add_interface(modem, OFONO_CDMA_MESSAGE_MANAGER_INTERFACE); + + __ofono_atom_register(cdmasms->atom, cdmasms_unregister); +} + +void ofono_cdmasms_remove(struct ofono_cdmasms *cdmasms) +{ + __ofono_atom_free(cdmasms->atom); +} + +void ofono_cdmasms_set_data(struct ofono_cdmasms *cdmasms, void *data) +{ + cdmasms->driver_data = data; +} + +void *ofono_cdmasms_get_data(struct ofono_cdmasms *cdmasms) +{ + return cdmasms->driver_data; +} + +struct ofono_atom *ofono_cdmasms_get_atom(struct ofono_cdmasms *cdmasms) +{ + return cdmasms->atom; +} + +const char *ofono_cdmasms_get_path(struct ofono_cdmasms *cdmasms) +{ + return __ofono_atom_get_path(cdmasms->atom); +} diff --git a/src/cdma-smsutil.c b/src/cdma-smsutil.c new file mode 100644 index 0000000..e140d60 --- /dev/null +++ b/src/cdma-smsutil.c @@ -0,0 +1,467 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2010 Nokia Corporation. All rights reserved. + * + * 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 +#endif + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include + +#include "cdma-smsutil.h" + +/* + * Mapping from binary DTMF code to the digit it represents. + * As defined in Table 2.7.1.3.2.4-4 of 3GPP2 C.S0005-E v2.0. + * Note, 0 is NOT a valid value and not mapped to + * any valid DTMF digit. + */ +const char cdmasms_dtmf_digits[13] = {0, '1', '2', '3', '4', '5', '6', '7', + '8', '9', '0', '*', '#'}; + + +/* Unpacks the byte stream. */ +static guint32 bit_field_unpack(const guint8 *buf, + guint32 offset, + guint32 nbit) +{ + guint32 val = 0; + guint32 byteIndex; + guint32 remainder; + + if (buf == NULL) + return 0; + + byteIndex = offset >> 3; + remainder = (offset & 0x7); + + if (remainder != 0) { + /* The field to be unpacked does not start at the byte boundary. + * Retrieve those bits first. */ + if (nbit >= (8 - remainder)) { + /* The field at least spans till the end of the byte. */ + val = buf[byteIndex] & ((1 << (8 - remainder)) - 1); + nbit -= (8 - remainder); + byteIndex++; + } else { + val = (buf[byteIndex] & + ((1 << (8 - remainder)) - 1)) >> (8 - remainder - nbit); + return val; + } + } + + /* Unpack rest of the bits in the field in 8-bit chunk. */ + while (nbit >= 8) { + val = (val << 8) | buf[byteIndex]; + nbit -= 8; + byteIndex++; + } + + /* If still some left, unpack the last remaining bits. */ + if (nbit > 0) + val = (val << nbit) | (buf[byteIndex] >> (8 - nbit)); + + return val; +} + +/* Convert CDMA DTMF digits into a string */ +static gboolean cdmasms_dtmf_to_ascii(char *buf, const char *addr, + guint8 num_fields) +{ + guint8 index; + guint8 value; + + if (buf == NULL || addr == NULL) + return FALSE; + + for (index = 0; index < num_fields; index++) { + if ((addr[index] <= 0) || (addr[index] > 12)) + return FALSE; /* Invalid digit in address field */ + + value = (guint8) addr[index]; + buf[index] = cdmasms_dtmf_digits[value]; + } + + buf[index] = 0; /* Make it NULL terminated string */ + + return TRUE; +} + +char *cdmasms_address_to_string(const struct cdmasms_address *addr) +{ + char *buf; + + if (addr == NULL) + return NULL; + + if (addr->digit_mode != DTMF_4_BIT) + return NULL; /* TODO: Only support DTMF_4_BIT currently */ + + buf = g_new(char, addr->num_fields + 1); + if (buf == NULL) + return NULL; + + if (!cdmasms_dtmf_to_ascii(buf, addr->address, addr->num_fields)) { + g_free(buf); + return NULL; + } + + return buf; +} + +/* Decode Address parameter record */ +static gboolean cdmasms_decode_addr(const unsigned char *buf, int len, + struct cdmasms_address *addr) +{ + guint32 bit_offset = 0; + guint8 chari_len; + guint32 total_num_bits = len * 8; + guint8 index; + + if (len <= 0 || buf == NULL || addr == NULL) + return FALSE; + + addr->digit_mode = (enum cdmasms_digit_mode) bit_field_unpack(buf, 0, 1); + bit_offset += 1; + addr->number_mode = (guint8) bit_field_unpack(buf, bit_offset, 1); + bit_offset += 1; + + if (addr->digit_mode == CODE_8_BIT) { + addr->number_type = (guint8) bit_field_unpack(buf, bit_offset, 3); + bit_offset += 3; + + if (addr->number_mode == 0) { + if (bit_offset + 4 > total_num_bits) + return FALSE; + + addr->number_plan = (enum cdmasms_numbering_plan) + bit_field_unpack(buf, bit_offset, 4); + bit_offset += 4; + } + } + + if ((bit_offset + 8) > total_num_bits) + return FALSE; + + addr->num_fields = (guint8) bit_field_unpack(buf, bit_offset, 8); + bit_offset += 8; + + if (addr->digit_mode == DTMF_4_BIT) + chari_len = 4; + else + chari_len = 8; + + if ((bit_offset + (chari_len * addr->num_fields)) > total_num_bits) + return FALSE; + + for (index = 0; index < addr->num_fields; index++) { + addr->address[index] = (char) bit_field_unpack(buf, bit_offset, + chari_len); + bit_offset += chari_len; + } + + return TRUE; +} + +char *cdmasms_decode_text(struct cdmasms_ud *ud) +{ + char *buf; + + if (ud == NULL) + return NULL; + + /* TODO: Only support MSG_ENCODING_7BIT_ASCII currently */ + if (ud->msg_encoding != MSG_ENCODING_7BIT_ASCII) + return NULL; + + buf = g_new(char, ud->num_fields + 1); + if (buf == NULL) + return NULL; + + memcpy(buf, ud->chari, ud->num_fields); + buf[ud->num_fields] = 0; /* Make it NULL terminated string */ + + return buf; +} + +/* Decode User Data */ +static gboolean cdmasms_decode_ud(const unsigned char *buf, + int len, struct cdmasms_ud *ud) +{ + guint32 bit_offset = 0; + guint8 chari_len = 0; + guint32 total_num_bits = len * 8; + guint8 index; + enum cdmasms_message_encoding msg_encoding; + + if (buf == NULL || ud == NULL) + return FALSE; + + if (total_num_bits < 13) + return FALSE; + + msg_encoding = (enum cdmasms_message_encoding) + bit_field_unpack(buf, bit_offset, 5); + ud->msg_encoding = msg_encoding; + bit_offset += 5; + + if (ud->msg_encoding == MSG_ENCODING_EXTENDED_PROTOCOL_MSG || + ud->msg_encoding == MSG_ENCODING_GSM_DATA_CODING) { + /* Skip message type field */ + /* TODO: Add support for message type field */ + bit_offset += 8; + } + + if (bit_offset + 8 > total_num_bits) + return FALSE; + + ud->num_fields = (guint8) bit_field_unpack(buf, bit_offset, 8); + bit_offset += 8; + + switch (msg_encoding) { + case MSG_ENCODING_OCTET: + chari_len = 8; + break; + case MSG_ENCODING_EXTENDED_PROTOCOL_MSG: + return FALSE; /* TODO */ + case MSG_ENCODING_7BIT_ASCII: + case MSG_ENCODING_IA5: + chari_len = 7; + break; + case MSG_ENCODING_UNICODE: + case MSG_ENCODING_SHIFT_JIS: + case MSG_ENCODING_KOREAN: + return FALSE; /* TODO */ + case MSG_ENCODING_LATIN_HEBREW: + case MSG_ENCODING_LATIN: + chari_len = 8; + break; + case MSG_ENCODING_GSM_7BIT: + chari_len = 7; + break; + case MSG_ENCODING_GSM_DATA_CODING: + return FALSE; /* TODO */ + } + + if (chari_len == 0) + return FALSE; + + if (bit_offset + chari_len * ud->num_fields > total_num_bits) + return FALSE; + + for (index = 0; index < ud->num_fields; index++) { + ud->chari[index] = (guint8) bit_field_unpack(buf, bit_offset, + chari_len); + bit_offset += chari_len; + } + + return TRUE; +} + +/* Decode Message Identifier */ +static gboolean cdmasms_decode_message_id(const unsigned char *buf, + int len, + struct cdmasms_identifier *id) +{ + guint32 bit_offset = 0; + + if (buf == NULL || id == NULL) + return FALSE; + + if (len != 3) + return FALSE; + + id->msg_type = (enum cdmasms_msg_type) bit_field_unpack(buf, bit_offset, 4); + bit_offset += 4; + id->msg_id = (guint16) bit_field_unpack(buf, bit_offset, 16); + bit_offset += 16; + id->header_ind = (gboolean) bit_field_unpack(buf, bit_offset, 1); + + return TRUE; +} + +/* Decode Bearer Data */ +static gboolean cdmasms_decode_bearer_data(const unsigned char *buf, int len, + struct cdmasms_bearer_data *bearer_data) +{ + gboolean ret = TRUE; + enum cdmasms_subparam_id subparam_id; + guint8 subparam_len; + + if (buf == NULL || bearer_data == NULL) + return FALSE; + + while (len != 0) { + + if (len < 2) + return FALSE; + + subparam_id = (enum cdmasms_subparam_id) bit_field_unpack(buf, 0, 8); + buf += 1; + subparam_len = (guint8) bit_field_unpack(buf, 0, 8); + buf += 1; + len -= 2; + + if (len < subparam_len) + return FALSE; + + switch (subparam_id) { + case SMS_SUBPARAM_ID_MESSAGE_ID: + ret = cdmasms_decode_message_id(buf, subparam_len, + &bearer_data->id); + set_bitmap(&bearer_data->subparam_bitmap, + SMS_SUBPARAM_ID_MESSAGE_ID); + break; + case SMS_SUBPARAM_ID_USER_DATA: + ret = cdmasms_decode_ud(buf, subparam_len, &bearer_data->ud); + set_bitmap(&bearer_data->subparam_bitmap, + SMS_SUBPARAM_ID_USER_DATA); + break; + case SMS_SUBPARAM_ID_USER_RESPONSE_CODE: + case SMS_SUBPARAM_ID_MC_TIME_STAMP: + case SMS_SUBPARAM_ID_VALIDITY_PERIOD_ABSOLUTE: + case SMS_SUBPARAM_ID_VALIDITY_PERIOD_RELATIVE: + case SMS_SUBPARAM_ID_DEFERRED_DELIVERY_TIME_ABSOLUTE: + case SMS_SUBPARAM_ID_DEFERRED_DELIVERY_TIME_RELATIVE: + case SMS_SUBPARAM_ID_PRIORITY_INDICATOR: + case SMS_SUBPARAM_ID_PRIVACY_INDICATOR: + case SMS_SUBPARAM_ID_REPLY_OPTION: + case SMS_SUBPARAM_ID_NUMBER_OF_MESSAGES: + case SMS_SUBPARAM_ID_ALERT_ON_MESSAGE_DELIVERY: + case SMS_SUBPARAM_ID_LANGUAGE_INDICATOR: + case SMS_SUBPARAM_ID_CALL_BACK_NUMBER: + case SMS_SUBPARAM_ID_MESSAGE_DISPLAY_MODE: + case SMS_SUBPARAM_ID_MULTIPLE_ENCODING_USER_DATA: + case SMS_SUBPARAM_ID_MESSAGE_DEPOSIT_INDEX: + case SMS_SUBPARAM_ID_SERVICE_CATEGORY_PROGRAM_DATA: + case SMS_SUBPARAM_ID_SERVICE_CATEGORY_PROGRAM_RESULT: + case SMS_SUBPARAM_ID_MESSAGE_STATUS: + case SMS_SUBPARAM_ID_TP_FAILURE_CAUSE: + case SMS_SUBPARAM_ID_ENHANCED_VMN: + case SMS_SUBPARAM_ID_ENHANCED_VMN_ACK: + /* TODO */ + /* Ignore any other unsupported/un-recognized parameter */ + break; + } + + if (ret == FALSE) + return FALSE; + + len -= subparam_len; + buf += subparam_len; + } + + return TRUE; +} + +static gboolean cdmasms_p2p_decode(const unsigned char *pdu, int len, + struct cdma_sms *incoming) +{ + gboolean ret = TRUE; + enum cdmasms_param_id rec_id; + guint8 rec_len; + + if (pdu == NULL || incoming == NULL) + return FALSE; + + while (len != 0) { + + if (len <= 2) + return FALSE; + + rec_id = (enum cdmasms_param_id) bit_field_unpack(pdu, 0, 8); + pdu += 1; + rec_len = (guint8) bit_field_unpack(pdu, 0, 8); + pdu += 1; + len -= 2; + + if (len < rec_len) + return FALSE; + + switch (rec_id) { + case SMS_PARAM_ID_TELESERVICE_IDENTIFIER: + incoming->p2p_msg.teleservice_id = (enum cdmasms_teleservice_id) + bit_field_unpack(pdu, 0, 16); + set_bitmap(&incoming->p2p_msg.param_bitmap, + SMS_PARAM_ID_TELESERVICE_IDENTIFIER); + break; + case SMS_PARAM_ID_SERVICE_CATEGORY: + break; /* TODO */ + case SMS_PARAM_ID_ORIGINATING_ADDRESS: + ret = cdmasms_decode_addr(pdu, rec_len, &incoming->p2p_msg.oaddr); + set_bitmap(&incoming->p2p_msg.param_bitmap, + SMS_PARAM_ID_ORIGINATING_ADDRESS); + break; + case SMS_PARAM_ID_ORIGINATING_SUBADDRESS: + case SMS_PARAM_ID_DESTINATION_ADDRESS: + case SMS_PARAM_ID_DESTINATION_SUBADDRESS: + case SMS_PARAM_ID_BEARER_REPLY_OPTION: + case SMS_PARAM_ID_CAUSE_CODE: + break; /* TODO */ + case SMS_PARAM_ID_BEARER_DATA: + ret = cdmasms_decode_bearer_data(pdu, rec_len, + &incoming->p2p_msg.bearer_data); + set_bitmap(&incoming->p2p_msg.param_bitmap, + SMS_PARAM_ID_BEARER_DATA); + break; + } + + if (!ret) + return FALSE; + + len -= rec_len; + pdu += rec_len; + } + + return TRUE; +} + +gboolean cdmasms_decode(const unsigned char *pdu, int len, + struct cdma_sms *incoming) +{ + gboolean ret = FALSE; + + if ((len == 0) || (pdu == NULL) || (incoming == NULL)) + return FALSE; + + incoming->type = (enum cdmasms_tp_msg_type) bit_field_unpack(pdu, 0, 8); + pdu += 1; + len -= 1; + + switch (incoming->type) { + case CDMASMS_P2P: + ret = cdmasms_p2p_decode(pdu, len, incoming); + break; + case CDMASMS_BCAST: + case CDMASMS_ACK: + /* TODO: Not supported yet */ + ret = FALSE; + break; + } + + return ret; +} diff --git a/src/cdma-smsutil.h b/src/cdma-smsutil.h new file mode 100644 index 0000000..5188378 --- /dev/null +++ b/src/cdma-smsutil.h @@ -0,0 +1,264 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2010 Nokia Corporation. All rights reserved. + * + * 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 + * + */ + +/* 3GPP2 C.S0015-B v2.0, Table 3.4-1 */ +enum cdmasms_tp_msg_type { + CDMASMS_P2P = 0, + CDMASMS_BCAST = 1, + CDMASMS_ACK = 2 +}; + +/* 3GPP2 X.S0004-550-E, Section 2.256 */ +enum cdmasms_teleservice_id { + TELESERVICE_CMT91 = 4096, + TELESERVICE_WPT = 4097, + TELESERVICE_WMT = 4098, + TELESERVICE_VMN = 4099, + TELESERVICE_WAP = 4100, + TELESERVICE_WEMT = 4101, + TELESERVICE_SCPT = 4102, + TELESERVICE_CATPT = 4103 +}; + +/* 3GPP2 C.S0005-E v2.0 Table 2.7.1.3.2.4-2 */ +enum cdmasms_digi_number_type { + CDMASMS_NUM_TYPE_UNKNOWN = 0, + CDMASMS_NUM_TYPE_INTERNATIONAL_NUMBER = 1, + CDMASMS_NUM_TYPE_NATIONAL_NUMBER = 2, + CDMASMS_NUM_TYPE_NETWORK_SPECIFIC_NUMBER = 3, + CDMASMS_NUM_TYPE_SUBSCRIBER_NUMBER = 4, + /* Reserved 5 */ + CDMASMS_NUM_TYPE_ABBREVIATED_NUMBER = 6 + /* Reserved 7 */ +}; + +/* 3GPP2 C.S0015-B v2.0 Table 3.4.3.3-1 */ +enum cdmasms_data_network_number_type { + CDMASMS_NETWORK_NUM_TYPE_UNKNOWN = 0, + CDMASMS_NETWORK_TYPE_INTERNET_PROTOCOL = 1, + CDMASMS_NETWORK_TYPE_INTERNET_EMAIL_ADDRESS = 2, + /* All Other Values Reserved */ +}; + +/* 3GPP2 C.S0005-E v2.0 Table 2.7.1.3.2.4-3 */ +enum cdmasms_numbering_plan { + CDMASMS_NUMBERING_PLAN_UNKNOWN = 0, + CDMASMS_NUMBERING_PLAN_ISDN = 1, + CDMASMS_NUMBERING_PLAN_DATA = 3, + CDMASMS_NUMBERING_PLAN_TELEX = 4, + CDMASMS_NUMBERING_PLAN_PRIVATE = 9, + CDMASMS_NUMBERING_PLAN_RESERVED = 15 +}; + +/* 3GPP2 C.S0015-B v2.0 Table 4.5.1-1 */ +enum cdmasms_msg_type { + CDMASMS_RESERVED = 0, + CDMASMS_DELIVER = 1, + CDMASMS_SUBMIT = 2, + CDMASMS_CANCEL = 3, + CDMASMS_DELIVER_ACK = 4, + CDMASMS_USER_ACK = 5, + CDMASMS_READ_ACK = 6, +}; + +/* C.R1001-G_v1.0 Table 9.1-1 */ +enum cdmasms_message_encoding { + MSG_ENCODING_OCTET = 0, + MSG_ENCODING_EXTENDED_PROTOCOL_MSG = 1, + MSG_ENCODING_7BIT_ASCII = 2, + MSG_ENCODING_IA5 = 3, + MSG_ENCODING_UNICODE = 4, + MSG_ENCODING_SHIFT_JIS = 5, + MSG_ENCODING_KOREAN = 6, + MSG_ENCODING_LATIN_HEBREW = 7, + MSG_ENCODING_LATIN = 8, + MSG_ENCODING_GSM_7BIT = 9, + MSG_ENCODING_GSM_DATA_CODING = 10 +}; + +/* 3GPP2 C.S0015-B v2.0 Table 3.4.3-1 */ +enum cdmasms_param_id { + SMS_PARAM_ID_TELESERVICE_IDENTIFIER = 0x00, + SMS_PARAM_ID_SERVICE_CATEGORY = 0x01, + SMS_PARAM_ID_ORIGINATING_ADDRESS = 0x02, + SMS_PARAM_ID_ORIGINATING_SUBADDRESS = 0x03, + SMS_PARAM_ID_DESTINATION_ADDRESS = 0x04, + SMS_PARAM_ID_DESTINATION_SUBADDRESS = 0x05, + SMS_PARAM_ID_BEARER_REPLY_OPTION = 0x06, + SMS_PARAM_ID_CAUSE_CODE = 0x07, + SMS_PARAM_ID_BEARER_DATA = 0x08 +}; + +/* 3GPP2 C.S0015-B v2.0 Table 4.5-1 */ +enum cdmasms_subparam_id { + SMS_SUBPARAM_ID_MESSAGE_ID = 0x00, + SMS_SUBPARAM_ID_USER_DATA = 0x01, + SMS_SUBPARAM_ID_USER_RESPONSE_CODE = 0x02, + SMS_SUBPARAM_ID_MC_TIME_STAMP = 0x03, + SMS_SUBPARAM_ID_VALIDITY_PERIOD_ABSOLUTE = 0x04, + SMS_SUBPARAM_ID_VALIDITY_PERIOD_RELATIVE = 0x05, + SMS_SUBPARAM_ID_DEFERRED_DELIVERY_TIME_ABSOLUTE = 0x06, + SMS_SUBPARAM_ID_DEFERRED_DELIVERY_TIME_RELATIVE = 0x07, + SMS_SUBPARAM_ID_PRIORITY_INDICATOR = 0x08, + SMS_SUBPARAM_ID_PRIVACY_INDICATOR = 0x09, + SMS_SUBPARAM_ID_REPLY_OPTION = 0x0A, + SMS_SUBPARAM_ID_NUMBER_OF_MESSAGES = 0x0B, + SMS_SUBPARAM_ID_ALERT_ON_MESSAGE_DELIVERY = 0x0C, + SMS_SUBPARAM_ID_LANGUAGE_INDICATOR = 0x0D, + SMS_SUBPARAM_ID_CALL_BACK_NUMBER = 0x0E, + SMS_SUBPARAM_ID_MESSAGE_DISPLAY_MODE = 0x0F, + SMS_SUBPARAM_ID_MULTIPLE_ENCODING_USER_DATA = 0x10, + SMS_SUBPARAM_ID_MESSAGE_DEPOSIT_INDEX = 0x11, + SMS_SUBPARAM_ID_SERVICE_CATEGORY_PROGRAM_DATA = 0x12, + SMS_SUBPARAM_ID_SERVICE_CATEGORY_PROGRAM_RESULT = 0x13, + SMS_SUBPARAM_ID_MESSAGE_STATUS = 0x14, + SMS_SUBPARAM_ID_TP_FAILURE_CAUSE = 0x15, + SMS_SUBPARAM_ID_ENHANCED_VMN = 0x16, + SMS_SUBPARAM_ID_ENHANCED_VMN_ACK = 0x17 +}; + +/* 3GPP2 C.R1001-G Table 9.3.1-1 */ +enum cdmasms_service_category { + SERVICE_CAT_EMERGENCY_BROADCAST = 1, + SERVICE_CAT_ADMINISTRATIVE = 2, + SERVICE_CAT_MAINTENANCE = 3, + SERVICE_CAT_GENERALNEWSLOCAL = 4, + SERVICE_CAT_GENERALNEWSREGIONAL = 5, + SERVICE_CAT_GENERALNEWSNATIONAL = 6, + SERVICE_CAT_GENERALNEWSINTERNATIONAL = 7, + SERVICE_CAT_BUSINESSFINALNEWSLOCAL = 8, + SERVICE_CAT_BUSINESSFINALNEWSREGIONAL = 9, + SERVICE_CAT_BUSINESSFINALNEWSNATIONAL = 10, + SERVICE_CAT_BUSINESSFINALNEWSINTNL = 11, + SERVICE_CAT_SPORTSNEWSLOCAL = 12, + SERVICE_CAT_SPORTSNEWSREGIONAL = 13, + SERVICE_CAT_SPORTSNEWSNATIONAL = 14, + SERVICE_CAT_SPORTSNEWSINTERNATIONAL = 15, + SERVICE_CAT_ENTERTAINMENTNEWSLOCAL = 16, + SERVICE_CAT_ENTERTAINMENTNEWSREGIONAL = 17, + SERVICE_CAT_ENTERTAINMENTNEWSNATIONAL = 18, + SERVICE_CAT_ENTERTAINMENTNEWSINTERNATIONAL = 19, + SERVICE_CAT_ENTERTAINMENTNEWSLOCALWEATHER = 20, + SERVICE_CAT_AREATRAFFICREPORTS = 21, + SERVICE_CAT_LOCALAIRTPORTFLIGHTSCHEDULES = 22, + SERVICE_CAT_RESTURANTS = 23, + SERVICE_CAT_LODGINGS = 24, + SERVICE_CAT_RETAILDIRECTORYADVERTISEMENTS = 25, + SERVICE_CAT_ADVERTISEMENTS = 26, + SERVICE_CAT_STOCKQUOTES = 27, + SERVICE_CAT_EMPLOYMENTOPPORTUNITIES = 28, + SERVICE_CAT_MEDICALHEALTHHOSPITALS = 29, + SERVICE_CAT_TECHNOLOGYNEWS = 30, + SERVICE_CAT_MULTICATEGORY = 31, + SERVICE_CAT_CAPT = 32 +}; + +enum cdmasms_digit_mode { + DTMF_4_BIT = 0, + CODE_8_BIT = 1 +}; + +/* 3GPP2 C.S0015-B v2.0 Section 3.4.3.3 */ +struct cdmasms_address { + enum cdmasms_digit_mode digit_mode; + guint8 number_mode; + guint8 number_type; + enum cdmasms_numbering_plan number_plan; + guint8 num_fields; + char address[256]; +}; + +/* 3GPP2 C.S0015-B v2.0 Section 3.4.3.6 */ +struct cdmasms_cause_code { + guint8 reply_seq; + guint8 error_class; + guint8 cause_code; +}; + +/* 3GPP2 C.S0015-B v2.0 Section 4.5.1 */ +struct cdmasms_identifier { + enum cdmasms_msg_type msg_type; + guint16 msg_id; + gboolean header_ind; +}; + +/* 3GPP2 C.S0015-B v2.0 Section 4.5.2 */ +struct cdmasms_ud { + enum cdmasms_message_encoding msg_encoding; + guint8 num_fields; + guint8 chari[512]; +}; + +/* 3GPP2 C.S0015-B v2.0 Section 4.5 */ +struct cdmasms_bearer_data { + guint32 subparam_bitmap; + struct cdmasms_identifier id; + struct cdmasms_ud ud; +}; + +/* 3GPP2 C.S0015-B v2.0 Table 3.4.2.1-1. */ +struct cdmasms_p2p_msg { + guint32 param_bitmap; + enum cdmasms_teleservice_id teleservice_id; + struct cdmasms_address oaddr; + struct cdmasms_bearer_data bearer_data; +}; + +/* 3GPP2 C.S0015-B v2.0 Table 3.4.2.2-1 */ +struct cdmasms_broadcast_msg { + enum cdmasms_service_category service_category; + struct cdmasms_bearer_data bearer_data; +}; + +/* 3GPP2 C.S0015-B v2.0 Table 3.4.2.3-1 */ +struct cdmasms_ack_msg { + struct cdmasms_address daddr; + struct cdmasms_cause_code cause_code; +}; + +/* 3GPP2 C.S0015-B v2.0 Section 3.4.1 */ +struct cdma_sms { + enum cdmasms_tp_msg_type type; + union { + struct cdmasms_p2p_msg p2p_msg; + struct cdmasms_broadcast_msg broadcast_msg; + struct cdmasms_ack_msg ack_msg; + }; +}; + +static inline gboolean check_bitmap(guint32 bitmap, guint32 pos) +{ + guint32 mask = 0x1 << pos; + return bitmap & mask ? TRUE : FALSE; +} + +static inline void set_bitmap(guint32 *bitmap, guint32 pos) +{ + if (bitmap == NULL) + return; + + *bitmap = *bitmap | (1 << pos); +} + +gboolean cdmasms_decode(const unsigned char *pdu, int len, + struct cdma_sms *out); +char *cdmasms_decode_text(struct cdmasms_ud *ud); +char *cdmasms_address_to_string(const struct cdmasms_address *addr); -- 1.7.0.4